diff options
Diffstat (limited to 'protocols/Weather')
30 files changed, 2275 insertions, 9578 deletions
diff --git a/protocols/Weather/docs/history.txt b/protocols/Weather/docs/history.txt deleted file mode 100644 index bf3351da1d..0000000000 --- a/protocols/Weather/docs/history.txt +++ /dev/null @@ -1,930 +0,0 @@ -Weather Protocol - Version History -================================== -Version 0.3.8.19 2011/09/03 - - Fixed Brief window update on weather station update - - Fixed No ini window no show - -Version 0.3.8.18 2010/08/20 - - Specialized translations for all weather conditions - - Fixed possible crashes - -Version 0.3.8.17 2010/05/29 - - Added possibility to add specialized translations for weather conditions - format: #condition Weather - - Added 32x32 icon support - - 32x32 icon is used in a frame in a frame if no avatar present - - Added support for Miranda 0.9 persistent http trasactions - - Changed Breif dialog appearence - - Fixed translation issues - - Fixed keyborad navigation in UserInfo dialog - - Requires Miranda 0.8 or higher - -Version 0.3.8.16 2009/08/09 - - Increased allowed size of station id - - Removed built-in support for HTTP compression (compression not supported with pre 0.8 Miranda any longer) - - Fixed crash with no ini files - - x64 port - -Version 0.3.8.15 2009/03/22 - - Added support for gif avatars - - Added support for 4 urls per ini - - Added supoort for html metadata (utf8) - - Fixed rounding with fractional reading display - - Added more http redirection support - - Allow to draw forced avatar in frame - -Version 0.3.8.14 2009/01/10 - - Fixed Set Data failures - - Fixed crashes with http - - Fixed http errors processing - - Added support for temperature in format -<space><number> - -Version 0.3.8.13 2008/12/25 - - Changed search UI to have more descriptive labels - - Documentation updates - -Version 0.3.8.12 2008/12/22 - - Added support for cookies (cakes and ice cream) - -Version 0.3.8.10 2008/12/07 - - Fixed temperature display - -Version 0.3.8.9 2008/12/06 - - Added support for deflate compressed http streams - - Fixes for weather crashes - - Added option to round all values to nearest integer - -Version 0.3.8.8 2008/11/22 - - Improved formatting for numerical values - - Fixed crashes due to compressed http stream - - Added support for gzip encoded http stream - -Version 0.3.8.7 2008/08/02 - - Fixed crash for people measuring speed in km/h - -Version 0.3.8.6 2008/08/01 - - Added display fraction of temperature and wind speed when available - - Added handling of UTF8 pages (needed for GisMeteo) - -Version 0.3.8.5 2008/07/27 - - Fixed option dialog layout - - Fixed ini version display - - Fixed memory leak with multiurl ini - - Fixed plugin version number - -Version 0.3.8.3 2008/07/24 - - Fixed url tag - - Added headers to variable view - - Fixed options dialog layout - -Version 0.3.8.2 2008/06/08 - - Fixed ini version display in User Info - - Fixes for wind in Weather Underground ini to work correctly - -Version 0.3.8.1 2008/05/25 - - Added ability to parse upto 3 URL per ini file for weather data - - Fixed break data and parameters with units - - Added ability to skin weather frame with clist_modern ("Main,ID=WeatherFrame") - - Added display "nickname" in the first line of the frame - - Added avatar display in the weather frame - -Version 0.3.7.2 2008/01/19 - - Fixed updates in normal mode - - Fixed option dialog layout - -Version 0.3.7.1 2007/12/22 - - Partial workaround for core HTTP problem - - Tabbed option dialog - -Version 0.3.7.0 2007/12/21 - - Added icolib support - - Added frames support - - New icons by Angeli-Ka - - Compatible with Miranda 0.7 and later - -Version 0.3.6.5 2007/08/17 - - Workaround for tray icon - -Version 0.3.6.4 2007/07/27 - - Fixed caching problems - -Version 0.3.6.3 2007/07/08 - - Fixed error message at stratup (with updater) - - Increased possible weather variable size - - More generic couldy definition - -Version 0.3.6.2 2007/06/02 - - More sensible autoupdate Enable/Disable operation - -Version 0.3.6.1 2007/06/01 - - Fixed popup click action - - Fixed translation - -Version 0.3.6.0 2007/05/18 - - New icons by Angeli-Ka - - Protocol icons split into separate dll - - Option dialog and menus redesign - - Instant avatar update - - Ini file display name now used as client ID (MirVer) - - Moved ini file list into View/Change My Details - - Support for new plugin interface - - Fixed few parsing issues - -Version 0.3.5.19 2007/01/27 - - Fixed translation - -Version 0.3.5.18 2007/01/26 - - Fixed translation - - Fixed resource leaks - - Fixed crash - - Partial unicode support - -Version 0.3.5.17 2007/01/20 - - Reduced GDI resource utilization - - Fixed memory leak with old ini files - - Fixed search function for stations with special characters - -Version 0.3.5.16 2006/11/27 - - Fixed units conversion - - Fixed memory corruption - - Added ability to show clickable links in Brief window - -Version 0.3.5.15 2006/11/16 - - Fixed web page parsing (Wind Speed in Yahoo) - - Fixed "No wind" condition handling - - Performance improvments for HTTP transfers - - Fixed memory corruption - -Version 0.3.5.14 2006/10/31 - - Fixed status message operation - -Version 0.3.5.13 2006/10/29 - - Fixed non english alphabets operation - - Fixed Weather condition update issues - - Added option to keep station status from reflecting weather condition - (should resolve avatar overlay problems with clist modern) - - Moved Weather main menu entry into the protocol group - - Improvements for forecast window sizing - -Version 0.3.5.12 2006/07/23 - - Fixed non english alphabets operation - -Version 0.3.5.11 2006/07/22 - - Fixed text corruption - - Added ability to display avatars for each weather condition - - Fixed Win95 operation - -Version 0.3.5.10 2006/07/16 - - Changed Current Date/Time display (%d) according to locale - - Changed handling of HTTP redirect requests - -Version 0.3.5.9 2006/04/08 - - Fixed misplaced buttons on forecast view window - - Fixed weather history incorrect source - - Fixed incorrect PopUp notification text in the menu - -Version 0.3.5.8 2005/09/20 - - Fixed automatic set of deafult station logic failure and as a result crash at power-up - - Fixed INI info dialog layout and ini version information - - Fixed rare crash on exit - - Fixed resource leak - - Fixed few memory leaks - - Fixed crash at power-up with corrupted ini file - - A lot of code robustness updates - -Version 0.3.5.7 2005/09/18 - - Fixed few resource leaks - - Fixed gloabal status - - Fixed weather alert format - - Fixed very rare crash on exit - -Version 0.3.5.6 2005/09/14 - - Fixed few crashes on exit and - - A lot of code robustness updates - - Updater compatibility - - Fixed resource leaks - -Version 0.3.5.5 2005/09/11 - - Fixed crash on exit - - Support for custom "Status Messages" - -Version 0.3.5.4 2005/09/08 - - Fixed crash in my User details - - Fixed endless "updating user info ..." - - Fixed search function regression - -Version 0.3.5.3 2005/09/07 - - Fixed crash at Powerup - - Fixed crash on Miranda exit - - Fixed numerous other crashes - - Fixed numerous memory leaks - - Fixed memory corruption - - Fixed resource leak - -Version 0.3.5.2 2005/09/07 - - Fixed crash on Miranda exit - - Fixed numerous other crashes - - Fixed numerous memory leaks - - Fixed memory corruption - - Fixed resource leak - -Version 0.3.5.0 2005/03/21 - - New Option: Disable update on startup - - New Option: Enable/Disable popups by type: update, alert, error - - INI Option: Support breaking string - - INI Option: Support hidden fields - - INI Option: Support icon assignment from ini - - Updated sample_ini.ini and translation - - Some other minor changes that I can't remember - -Version 0.3.4.4 2004/12/28 - - Load window list correctly, fix problem with brief info and edit dlg not showing - - Some internal changes with new service functions - -Version 0.3.4.3 2004/12/26 - - Minor change in INI loading - -Version 0.3.4.2 Beta 2004/12/16 - - Bug fix: Miranda cannot quit after forkthread is used - - Bug fix: The unit % does not work anymore - - Bug fix: No longer crash when the link settings is not set - - Update the weather ini download link to the new location - -Version 0.3.4.1 Beta 2004/12/09 - - ESC now works in weather dialogs - - More changes to forkthread - - Document updated: weather-translation, sample_ini - -Version 0.3.4.0 Beta 2004/11/21 - - Change the threading to forkthread - - New option: Custom status when condition is unavailable - - New option: Convert day/month string into 2 char or 3 char format - - Some internal changes - - Minor change in ini format - -Version 0.3.3.17 2004/11/19 - - Condition translated correctly when writing into database - - Correctly restore the windows position for edit setting dialog - -Version 0.3.3.16 2004/11/10 - -Version 0.3.3.15 2004/10/21 - - Remember the window position for edit settings dialog - - Minor change in dialog (I still can't get the close on ESC to work...) - -Version 0.3.3.14 Beta 2004/10/20 - - Fix the crash in option page bug (hopefully) - - Fix the support for \n in text input - - Minor change in dialog - -Version 0.3.3.13 2004/10/16 - - Another fix for default station - - Some changes to reduce database read/write for default station changes - - Now the plugin is correctly registered in known module list for DBEditor++ - - Save the setting for popup and update enable/disable directly after menu click - - Some update in readme, more changes in translation (thanks smyle again) - -Version 0.3.3.12 2004/10/16 - - Fix 2 possible crashes regarding default station - -Version 0.3.3.11 2004/10/15 - - Fix a bug with global status - - Updated translation list (thanks smyle) - -Version 0.3.3.10 2004/10/14 - - Changes in default station handling, hopefully will fix a crash in option page - - Add new sound event: Weather alert - - Add new menu item: Add new weather station (call up the find/add dialog) - - Document updated: weather_translation.txt - -Version 0.3.3.9 2004/09/26 - - Some changes in code. - -Version 0.3.3.8 2004/09/24 - - Now uses default system text for brief info and setup dialog. - -Version 0.3.3.7 (Beta) - - Test releases for crash in option page - -Version 0.3.3.6 2004/09/24 - - Add a sound event when weather condition is updated - - Use the default system color for brief info and setup dialog - - Minor change in unit conversion - - Fix in brief info when there is no data for current conditions - - Add entry to Database Editor++ known module - -Version 0.3.3.5 2004/08/14 - - Fix apply button in option pages - - Fix "Humidity" in default settings - - Ignore the sample ini file if it is placed in plugin\weather dir - - Minor changes in update timer and option dialog - -Version 0.3.3.4 (Beta) 2004/07/23 - - Fix some bug in text option - - Take proto_weather.dll icon into account when auto-assigning icon - - Option to disable automatic icon assignment - - Few minor changes - - Document updated: weather_translation.txt - -Version 0.3.3.3 2004/07/21 - - Automatically set to default weather icon if no custom one is set - - Add a ini setup information dialog to help setup weather protocol - - Update in brief info now retrieve new data from the internet - - Few minor changes - - Document updated: weather_translation.txt - -Version 0.3.3.2 (Beta) 2004/07/14 - - Show error detail on update errors - - Includes simple set of 16-colors weather icons in the dll file - - Option to disable italic display for station with alert issued - - Option to disable warning dialog if ini is not found at startup - - Attempt to fix the black bar bug in brief info - - Fix the bug that shows connecting as weather status - - Document updated: weather_translation.txt - -Version 0.3.3.1 2004/06/19 - - Minor change in the brief info dialog - - More info items are now translatable - - Case conversion in condition to make them translatable (use unit: Cond) - - Save window size for the brief info dialog - - Fix crash when invalid ID or ini file for the station is not found - - Few minor changes - - Document updated: sample_ini - -Version 0.3.3.0 (Beta) 2004/06/12 - - A new feature that erase old data while updating for new data - - A change in the brief information dialog (thanks micron-x for last seen plugin) - - Double click a contact shows brief info dialog (thanks Matrix and JdGordon) - - Add brief info title setting - - Change in the weather, text, and popup options dialogs - - Add reset to default and preview for all display text field - - Change the way the plugin handles protocol status - - Enable/disable auto-update from the main menu - - Reconizes dust conditions and assign a fog icon (thanks Klenje) - - Support the units "%" and "Deg" - - Fix a crash if miranda32.exe is renamed - - Fix crashes in between updating of 2 stations (thanks Targaff) - - Update links in the readme and DLL to the new weather category (thanks lynlimz) - - Other bug fixes and minor changes - - Document updated: weather-translation, langpack_defweather, sample_ini - -Version 0.3.2.16 2004/05/27 - - Reconizes condition in lower case - - Few changes. - -Version 0.3.2.15 2004/05/24 - - Now reconizes the condition string "T-storm" - - No longer skip hidden weather contact while updating - - Bug fix when previewing weather popups - - Bug fix in parsing the HTML content (in cases where "&" exists) - - Few other minor fixes and changes. - -Version 0.3.2.14 2004/05/12 - - Popup preview include a preview of popup text settings (use default station) - - Fix memory leaks in various places. - -Version 0.3.2.13 2004/05/08 - - Changed some linker options to prevent plugin not loading - -Version 0.3.2.12 2004/05/08 - - Assign fog icon to the sand conditions - -Version 0.3.2.11 2004/05/07 - - Really ignore the "Ignore" item in the ini file - - Fix crash when unloading ini's (at reload or shutdown) - - Change in weather alert popup - - Few minor changes - -Version 0.3.2.10 2004/05/02 - - Rebuild using Visual C++ - -Version 0.3.2.9 2004/04/29 - - Attempt to fix crash when searching for cities by name - - Display a list of custom variables - - Fix memory leak when reloading strings from ini files - - Changes in the code for parsing weather info and loading ini files - - Other minor changes - -Version 0.3.2.8 2004/04/28 - - Fix on loading ini strings, support for v1.1a again - - Fix in weather station search - - Fix crash when not connected to the internet - - Add a new debug function (need DB Editor) - - A few other minor fixes and changes - -Version 0.3.2.7 2004/04/19 - - Fixing the crash on startup bug one more time :( - -Version 0.3.2.6 2004/04/19 - - Attempt to fix an crash on startup bug again. - - Temporary remove support for v1.1a of the INI file. :( - -Version 0.3.2.5 2004/04/19 - - Attempt to fix an crash on startup bug. - -Version 0.3.2.4 2004/04/19 - - Fix some error while loading weather ini file. - - Obtain station name from the net in edit dialog. - - Display N/A when temperature is unavail. and the string retrieved is not "N/A" - - Some minor changes. - -Version 0.3.2.3 2004/04/18 - - Automatically suppress online notification for all weather contact when upgrade. - - Fixed crash when adding new contact. - - Fixed crash when importing contact using mContacts. - - Some minor changes. - -Version 0.3.2.2 2004/04/18 - - Change the way weather handles status, now properly display NA for def stn. - - Protocol status can be changed freely if "Do not display weather conditions - as protocol status" is enabled. - - More memory leak fixes and crash fixes. - -Version 0.3.2.1 2004/04/17 - - Reduce memory use by more than 60% and fixed some memory leaks - - Support a revision of v1.1 ini file (the length string now can be unlimited) - - Incrase the maximun text length to 4k (but try keep it as short as possible) - - A few minor fixes and changes - - Updated readme file. - -Version 0.3.2.0 2004/04/12 - - Support new variable %% (same as \%) and %[..] (see readme) - - Now with the complete support of weather INI v1.1 - - Very basic support of weather alert notifications (if the INI supports it) - - Add browse, view webpage, and reset to default buttons edit settings dialog - - Interface changes and fixed tab order for all dialogs - - Display information for the weather INI files - - Some other monor changes and fixes - - Updates Read Me, and now it is in HTML format. - -Version 0.3.1.8 2004/04/09 - - "My Notes" text are copied to "Current\WeatherInfo" (might be useful for some plugins) - - Increase the length of display texts from 512b to 4k - - Bug Fix: when temperature is N/A, display N/A - - Bug Fix: rounding in unit conversion, err... - - Bug Fix: crash with new ini setting "Set Data=" - -Version 0.3.1.7 2004/04/08 - - Now correctly support the new ini files. - -Version 0.3.1.6 2004/04/04 - - Support escape characters "\%" for displaying % - - Changes in warning popups - -Version 0.3.1.5 2004/04/02 - - New option: Consider weather info updated only when cond and temp are changed - - Support v1.1 of weather ini files - only support loading, but not the new features ;) - - Rounding is used when converting units - - Attempt to fix the crash on exit and reload weather data bug - - The default update time is changed to 20 min - - Other minor fixes and changes that I don't remember - -Version 0.3.1.1 2004/03/27 - - Fix the crash when opening brief info dialog - - The default for "Support online notification" is on when adding new station - -Version 0.3.1.0 2004/03/25 - - Change the way popup is handled, no longer need to enable the threading option - - Manually add station without searching by entering "#" in the ID field - - Always provide a search result if the weather service has no ID search available. - - Some error handling and popups to prevent crashes. - - New hookable event: ME_WEATHER_UPDATED - - Bug fix: Translation of retrieved data - - Bug fix: Search don't work for city that has more than 1 word - - Bug fix: Speed conversion is wrong - - Bug fix: weatherch.ini: Crash if adding/updating a station in US Eastern timezone - - Updated: weatherch.ini, Read Me, Translation, Sample INI, m_weather.h - -Version 0.3.0.1 (Beta) 2004/03/23 - - Do not update contacts that are hidden from list (see it as "disabled" contacts) - - Give error message box when selecting more info and weather map before setting the URL - - Bug fix: Find and search contacts (no result found + crashes) - - Bug fix: Issue with StartupStatus, now weather will update at least once on startup - regardless of what's the setting there. - - Bug fix: Visibility unit conversion - - Bug fix: Weather contacts appear offline if langpack is installed - - Bug fix: Some spelling error - - Bug fix: Feel-like temperature can't be displayed by mToolTip - - Bug fix: WU: Find and search for station that doesn't have current condition - - Updated: All 4 INI files, Read Me, Translation - -Version 0.3.0.0 (Beta) 2004/03/22 - - Combine the weather dll's into one - - Using external file for getting update (in plugins\weather directory) - - Added user detail page for weather contacts - - New and improved option pages - - Proxy support (now uses netlib) - - Unit conversion for pressure, visibility, and wind - - Optimization in the edit setting dialog - Allow multiple window - - Changes in brief info dialog - able to open multiple brief info - - Reduce the number of DB access for getting settings - - Add more variables such as feel-like temperature, pressure - - Add menu item for enable/disable popup - - Support weather icon determination for site in other languages using langpack - - Support for plugin uninstaller - - Optimization in weather update - now update using a queue and minimize DB access - - Optimizaiton in add/search - now don't do unnecessary searches - - Other code optimization and reduce file size - - Reload weather update data file from the main menu - - Some other major and minor UI change - - Remove some useless features - - Bug fix: temperature conversion (thanks to sirius) - - Bug fix: crash on adding new station - - Some minor changes and fixes in webpage downloading. - - Includes documentation for INI update data file and icon selection translation. - - Major changes in translation strings. - - Some update in the readme documentation. - - Included in this version: - Weather Channel, Weather Underground (both US and International), Yahoo Weather. - -Version 0.2.5.2 - -Version 0.2.5.1 2003/07/19 - - Minor bug fixes - -Version 0.2.5.0 2003/06/09 - - New feature: short weather information as status message and/or note. - - New option: display weather options inside plugin options. - - Create a seperate page for text and display options. - - Other minor changes and bug fixes - -Version 0.2.4.5 2003/06/12 - - Bug fix: Backup/restore protocol icon (including rebuild icon) if status is hidden. - - Bug fix: Popup only condition changes. - -Version 0.2.4.4 2003/06/08 - - Fixed typo in option - - Weather underground: Retrieve data for high/low temperature even if - current info is unavailable - - Minor code change. - -Version 0.2.4.3 2003/06/07 - - Fix weather underground searching station - -Version 0.2.4.2 2003/06/06 - - Fixed weather underground station name display problem. - - Changes to make compatible with earlier version in case of downgrading - - Reorganize language pack strings. - -Version 0.2.4.1 (Beta) 2003/05/28 - - New preview using the selected timeout value. - - Modified timeout warning message box. - -Version 0.2.4.0 (Beta) 2003/05/28 - - Added advanced option page - - New option: Popup timeout - - Restore the hide icons in status / task bar option - - Use old weather information if new data is unavailable - - Add the debug setting in advanced option page - - Major internal / weather update / DB settings change - -Version 0.2.3.13 2003/05/30 - - Fixed searching weather underground station - - Few minor changes - -Version 0.2.3.12 2003/05/28 - -Version 0.2.3.11 (Beta) 2003/05/27 - - Fixed Weather Channel for the FOURTH time - -Version 0.2.3.10 2003/05/27 - - Third fix for Weather Channel. - - Note: If v0.2.3.9 works, there is no need to upgrade - -Version 0.2.3.9 2003/05/26 - - Fixed download from Weather Channel - - Few minor changes and updates - -Version 0.2.3.8 2003/05/25 - - Removed some unnecessary popup that causes crash and/or confusion - - Minor code change in weather update. - -Version 0.2.3.7 (Beta) 2003/05/08 - - Now compile using latest Miranda source code - -Version 0.2.3.6 (Beta) 2003/04/15 - -Version 0.2.3.5 2003/03/16 - - Fix in "Do not display weather condition as protocol status" option - - Fix in maximun temperature for weather channel plugin. - -Version 0.2.3.4 2003/03/16 - -Version 0.2.3.3 (Beta) 2003/03/10 - - Remove features that are incompatiable with latest version of Miranda - - Bug fix on retrieving weather (again!) - -Version 0.2.3.2 (Beta) 2003/02/28 - - Few minor bug fixes - -Version 0.2.3.1 (Beta) 2003/02/17 - - Bug fix in retrieving high and low temperature. - - Other minor fixes. - -Version 0.2.3.0 2003/02/05 - - New option: Do not display default condition as protocol status - - Support Miranda Installer - - Other minor code changes. - -Version 0.2.2.11 2003/01/31 - - Fixed some weather info parsing problems - -Version 0.2.2.10 2003/01/26 - - Fix some minor errors in weather update - -Version 0.2.2.9 2003/01/25 - - Add some warning messages. - -Version 0.2.2.8 (Beta) 2003/01/25 - - Fixed on popup display. - - More infinite loop prevention. - -Version 0.2.2.7 2003/01/24 - - Forget to update version number in last release - -Version 0.2.2.6 2003/01/24 - - Popup only when condition changes now work properly. - - Minor bug fix in logging - - Smaller file size. - - Other minor changes. - -Version 0.2.2.5 (Beta) 2003/01/23 - - Fixed weatherch.dll for new website format. - -Version 0.2.2.4 (Beta) 2003/01/18 - - Minor code change - -Version 0.2.2.3 2003/01/16 - -Version 0.2.2.2 2003/01/15 - - Show popup action selection when menu is opened. - - Bug fix: Modified weather station now can update normally. - -Version 0.2.2.1 (Beta) 2003/01/12 - - Bug fix: Opening menu when click on PopUp. - - Added link in main menu to the homepage of weathe source. - - New protocol icon. - -Version 0.2.2.0 (Beta) 2003/01/11 - - Move pop-up related options to popup option page. - - New option: Set popup title - - New option: Specify command for popups when mouse is clicked. - - Added variable information popup. - - Some UI changes. - - Added version info. - - Some translation string added / changed. - -Version 0.2.1.6 (Beta) 2003/01/09 - - Shorten code in some functions. - -Version 0.2.1.5 2003/01/08 - - Updated weatherch.dll for data retrieval. - - Bug fix: Searching new weather station. - - Bug fix: Loading default settings. - - Few other minor changes. - -Version 0.2.1.3 (Beta) 2003/01/07 - - Minor bug fix. - -Version 0.2.1.2 2003/01/04 - - New option: Overwrite File upon Update. - - Update in translation doc. - -Version 0.2.1.1 2003/01/03 - - Better support for multiline popups. - - Minor change in codes and readme document. - -Version 0.2.1.0 2002/12/31 - - New option: Override default URL settings for each contact - - Display text are no longer case sensitive. - - Prevent opening two dialogs at the same time. - -Version 0.2.0.5 2002/12/18 - - Few minor changes and bug fixes - -Version 0.2.0.4 (Beta) 2002/12/15 - - Bug fix: changing status and popups. - - Minor change in weather update. - -Version 0.2.0.3 (Beta) 2002/12/14 - - Bug fix: disable popup st startup. - - Other minor changes. - -Version 0.2.0.2 (Beta) 2002/12/12 - - Try to make string compatible between each weather source (not tested) - - Bug fix: crash when not connected (not tested) - - New weather condition in translation string. - - Various other minor bug fixes and changes. - -Version 0.2.0.1 (Beta) 2002/12/11 - - Fix in updating weather information in wunderground.dll - - Various other minor bug fixes and changes. - -Version 0.2.0.0 (Beta) 2002/12/10 - - Completed wunderground.dll - - Bug fix: Update all weather. - - Bug fix: Weather update in weatherch.dll - - Various other bug fixes and improvements. - -Version 0.1.9.5 (Preview) 2002/12/10 - - Completed weatherch.dll - - Weather Underground (wunderground.dll) included - not complete yet. - - Bug fix: Default weather station and weather status. - - Bug fix: Crash when edit weather station. - - Bug fix: Crash when adding new weather station. - - Bug fix: Searching for weather station when no contact found. - - Various other changes and bug fixes. - -Version 0.1.9.0 (Preview) 2002/12/09 - - Split code into different files for easier modification. - - Support for multiple weather protocols (required minimal change + new build) - - Minor changes and bug fixes - -Version 0.1.5.2 2002/12/09 - - Bug fix: crash when "Show multiple icons only when statuses differ" enabled - - Bug fix: some options not saved properly. - - Bug fix: bug fix when adding the first station. - -Version 0.1.5.1 2002/12/07 - - Bug fix in showing notifying messages. - -Version 0.1.5.0 2002/12/06 - - Error detections. - - New option: Show errors on popups. - - Display default station weather condition as status icon. - - Enable / Disable weather update through status. - - New weather conditions. - - Slight change in adding new weather station. - - Fixed tab orders. - -Version 0.1.4.9 2002/12/06 - -Version 0.1.2.0 2002/11/29 - - Add links to weather maps. - - Add option to change Popup text, Log text, and URL links. - - New variables: %d, %s, %S - - New option: open webpage in new window. - - Internal code changes and bug fixes. - -Version 0.1.1.1 2002/11/25 - - Bug fix: Translations - - Minor code change and translation updates. - -Version 0.1.1.0 2002/11/24 - - Brief Information template now translable. - - Add set to default button for Brief Information display. - - UI change in Brief Information dialog. - - Add some control over looping. - - Set default weather station (currently has no use, but it maybe useful later or by - other plugins) - - Bug fix: Searching for station using city names. - - Bug fix: Assigning icon to weather conditions. - - Fixed tab order. - - Other minor UI and code changes (hope this will fix some bugs). - -Version 0.1.0.0 2002/11/23 - - Now add weather station via Find/Add Contact dialog. - - Able to search for station using city name. - - Customize string for showing brief information. - - New option: Log weather station in history. - - New option: Disable popup for specific weather station. - - Bug fix: Update after editing weather station. - - Bug fix: Now correctly update using the new webpage format. - - Updated translation string (both dll and weather condition). - - Updated debug output method. - - Smaller file size. - - Re-organized readme and language files. - - Various other minor bug fixes and improvement. - -Version 0.0.8.5 2002/11/22 - - Bug fix: Hiding icon in task bar. - - New weather condition added (both dll and langpack). - -Version 0.0.8.4 2002/11/22 - - Bug fix: Update issues. - - Updated translation string. - -Version 0.0.8.3 2002/11/21 - - Interface change in option screen. - - Prevent displaying invalid data. - - Minor code change for update weather condition. - - Added missing translation string. - -Version 0.0.8.2 2002/11/20 - - Bug fix: Translation of weather condition on contact list - - Bug fix: Temperature conversion. - - Minor change in option screens and edit setting screen. - -Version 0.0.8.1 2002/11/19 - - Bug fix: Fixed temperature display. - - Fixed tab orders. - -Version 0.0.8.0 (Beta) 2002/11/19 - - Retrieve high and low temperature forecast for the current day. - - Search and display temperature from alternative source when it is unknown. - (For the people who have N/A display beside their city, this ver should work now) - - More customizable contact list name display. - - Bug fix: C and F conversion when temperature < 0 degree C. - - Bug fix: Some update problems. - - Language pack updated: more weather conditions. - -Version 0.0.7.5 (Beta) 2002/11/18 - - Right click -> Update Weather will no longer freeze Miranda. - - New option: Disable popup if condition doesn't change. - - Bug fix: prevent manual update when auto-update is in progress. - - Added missing translation string. - -Version 0.0.7.0 (Beta) 2002/11/17 - - Updating weather will no longer freeze up miranda. - - Add option to disable popup. - - Bug fix: Now saves the degree sign in option. - - Bug fix: Logging weather condition and view log command. - - Bug fix: Update weather condition after modifying weather station. - - Added missing translation string. - - Various other improvements. - -Version 0.0.6.1 (Beta) 2002/11/16 - - Bug fix: Update after modifying weather station. - - Bug fix: No cache (slower but more accurate info). - -Version 0.0.6.0 (Beta) 2002/11/16 - - The plugin has it's own popup (not using NewStatusNotify's anymore) - - Add option to hide icon in status bar and status menu (expreimental release). - - Various minor changes. - -Version 0.0.5.1 (Alpha) 2002/11/16 - -Version 0.0.5.0 (Alpha) 2002/11/15 - -Version 0.0.4.3 (Beta) 2002/11/15 - - Added option to disable main menu item. - - Various minor improvements. - -Version 0.0.4.2 (Beta) 2002/11/15 - - Bug fix: translation strings. - - Bug fix: no longer open miranda directory when no log is found. - -Version 0.0.4.1 (Beta) 2002/11/15 - - Bug fix on retrieving weather information. - - Removed debug string that was accidentally built in the last release. (see above) - -Version 0.0.4.0 (Beta) 2002/11/14 - - Retrieve weather information no longer require temp files. - - Able to modify weather station settings. - - Add link to log file in contact menu. - - Add an option for degree sign (I can't think of a better way to do this). - - Relocate main menu item. - - Bug fix: DB: Attempt to get wrong type of value, word. - - Various other minor bug fixes. - -Version 0.0.3.7 (Beta) 2002/11/14 - - Bug fix: degree signs (sorry for the copy-and-paste error). - - Move the temporary file to miranda directory. - -Version 0.0.3.6 (Beta) 2002/11/14 - - Bug fix: degree signs (changable using language pack) - - Bug fix: DB: Attempt to get wrong type of value, word. - - More weather condition are now able to display with correct icon. - -Version 0.0.3.5 (Beta) 2002/11/13 - - Initial public beta release. - -Version 0.0.3.1 (Beta) 2002/11/13 - -Version 0.0.3.0 (Beta) 2002/11/12 - - Disable auto update option. - - Logging weather condition. - - New option for displaying weather conditions on contact list. - - Bug fix: some tarnslation strings. - - Bug fix: switching between English and metric units. - - Bug fix: time of update. - -Version 0.0.2.1 (Preview) 2002/11/12 - - Bug fix: F to C conversion. - - Bug fix: Display complete forcast page in correct unit system. - -Version 0.0.2.0 (Preview) 2002/11/12 - - Display temperature on contact list. - - Translable strings. - - Display brief weather information as message box. - - Faster information download. - - Various other fixes. - -Version 0.0.1.2 (Pre-Alpha) 2002/11/12 - -Version 0.0.1.1 (Pre-Alpha) 2002/11/11 - - Faster and more reliable download. - - Various bug fixes. - -Version 0.0.1.0 (Pre-Alpha) 2002/11/11 - - Retrieve temperature and update time. - -Version 0.0.0.3 (Pre-Alpha) 2002/11/11 - - Bug fix in weather condition and icons. - - Various other bug fixes. - -Version 0.0.0.2 (Pre-Alpha) 2002/11/11 - - Set the name for city, retrieve weather condition. - -Version 0.0.0.1 (Pre-Alpha) 2002/11/10 - - Initial build diff --git a/protocols/Weather/docs/license.txt b/protocols/Weather/docs/license.txt deleted file mode 100644 index 5b6e7c66c2..0000000000 --- a/protocols/Weather/docs/license.txt +++ /dev/null @@ -1,340 +0,0 @@ - GNU GENERAL PUBLIC LICENSE - Version 2, June 1991 - - Copyright (C) 1989, 1991 Free Software Foundation, Inc. - 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - Everyone is permitted to copy and distribute verbatim copies - of this license document, but changing it is not allowed. - - Preamble - - The licenses for most software are designed to take away your -freedom to share and change it. By contrast, the GNU General Public -License is intended to guarantee your freedom to share and change free -software--to make sure the software is free for all its users. This -General Public License applies to most of the Free Software -Foundation's software and to any other program whose authors commit to -using it. (Some other Free Software Foundation software is covered by -the GNU Library General Public License instead.) You can apply it to -your programs, too. - - When we speak of free software, we are referring to freedom, not -price. Our General Public Licenses are designed to make sure that you -have the freedom to distribute copies of free software (and charge for -this service if you wish), that you receive source code or can get it -if you want it, that you can change the software or use pieces of it -in new free programs; and that you know you can do these things. - - To protect your rights, we need to make restrictions that forbid -anyone to deny you these rights or to ask you to surrender the rights. -These restrictions translate to certain responsibilities for you if you -distribute copies of the software, or if you modify it. - - For example, if you distribute copies of such a program, whether -gratis or for a fee, you must give the recipients all the rights that -you have. You must make sure that they, too, receive or can get the -source code. And you must show them these terms so they know their -rights. - - We protect your rights with two steps: (1) copyright the software, and -(2) offer you this license which gives you legal permission to copy, -distribute and/or modify the software. - - Also, for each author's protection and ours, we want to make certain -that everyone understands that there is no warranty for this free -software. If the software is modified by someone else and passed on, we -want its recipients to know that what they have is not the original, so -that any problems introduced by others will not reflect on the original -authors' reputations. - - Finally, any free program is threatened constantly by software -patents. We wish to avoid the danger that redistributors of a free -program will individually obtain patent licenses, in effect making the -program proprietary. To prevent this, we have made it clear that any -patent must be licensed for everyone's free use or not licensed at all. - - The precise terms and conditions for copying, distribution and -modification follow. - - GNU GENERAL PUBLIC LICENSE - TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION - - 0. This License applies to any program or other work which contains -a notice placed by the copyright holder saying it may be distributed -under the terms of this General Public License. The "Program", below, -refers to any such program or work, and a "work based on the Program" -means either the Program or any derivative work under copyright law: -that is to say, a work containing the Program or a portion of it, -either verbatim or with modifications and/or translated into another -language. (Hereinafter, translation is included without limitation in -the term "modification".) Each licensee is addressed as "you". - -Activities other than copying, distribution and modification are not -covered by this License; they are outside its scope. The act of -running the Program is not restricted, and the output from the Program -is covered only if its contents constitute a work based on the -Program (independent of having been made by running the Program). -Whether that is true depends on what the Program does. - - 1. You may copy and distribute verbatim copies of the Program's -source code as you receive it, in any medium, provided that you -conspicuously and appropriately publish on each copy an appropriate -copyright notice and disclaimer of warranty; keep intact all the -notices that refer to this License and to the absence of any warranty; -and give any other recipients of the Program a copy of this License -along with the Program. - -You may charge a fee for the physical act of transferring a copy, and -you may at your option offer warranty protection in exchange for a fee. - - 2. You may modify your copy or copies of the Program or any portion -of it, thus forming a work based on the Program, and copy and -distribute such modifications or work under the terms of Section 1 -above, provided that you also meet all of these conditions: - - a) You must cause the modified files to carry prominent notices - stating that you changed the files and the date of any change. - - b) You must cause any work that you distribute or publish, that in - whole or in part contains or is derived from the Program or any - part thereof, to be licensed as a whole at no charge to all third - parties under the terms of this License. - - c) If the modified program normally reads commands interactively - when run, you must cause it, when started running for such - interactive use in the most ordinary way, to print or display an - announcement including an appropriate copyright notice and a - notice that there is no warranty (or else, saying that you provide - a warranty) and that users may redistribute the program under - these conditions, and telling the user how to view a copy of this - License. (Exception: if the Program itself is interactive but - does not normally print such an announcement, your work based on - the Program is not required to print an announcement.) - -These requirements apply to the modified work as a whole. If -identifiable sections of that work are not derived from the Program, -and can be reasonably considered independent and separate works in -themselves, then this License, and its terms, do not apply to those -sections when you distribute them as separate works. But when you -distribute the same sections as part of a whole which is a work based -on the Program, the distribution of the whole must be on the terms of -this License, whose permissions for other licensees extend to the -entire whole, and thus to each and every part regardless of who wrote it. - -Thus, it is not the intent of this section to claim rights or contest -your rights to work written entirely by you; rather, the intent is to -exercise the right to control the distribution of derivative or -collective works based on the Program. - -In addition, mere aggregation of another work not based on the Program -with the Program (or with a work based on the Program) on a volume of -a storage or distribution medium does not bring the other work under -the scope of this License. - - 3. You may copy and distribute the Program (or a work based on it, -under Section 2) in object code or executable form under the terms of -Sections 1 and 2 above provided that you also do one of the following: - - a) Accompany it with the complete corresponding machine-readable - source code, which must be distributed under the terms of Sections - 1 and 2 above on a medium customarily used for software interchange; or, - - b) Accompany it with a written offer, valid for at least three - years, to give any third party, for a charge no more than your - cost of physically performing source distribution, a complete - machine-readable copy of the corresponding source code, to be - distributed under the terms of Sections 1 and 2 above on a medium - customarily used for software interchange; or, - - c) Accompany it with the information you received as to the offer - to distribute corresponding source code. (This alternative is - allowed only for noncommercial distribution and only if you - received the program in object code or executable form with such - an offer, in accord with Subsection b above.) - -The source code for a work means the preferred form of the work for -making modifications to it. For an executable work, complete source -code means all the source code for all modules it contains, plus any -associated interface definition files, plus the scripts used to -control compilation and installation of the executable. However, as a -special exception, the source code distributed need not include -anything that is normally distributed (in either source or binary -form) with the major components (compiler, kernel, and so on) of the -operating system on which the executable runs, unless that component -itself accompanies the executable. - -If distribution of executable or object code is made by offering -access to copy from a designated place, then offering equivalent -access to copy the source code from the same place counts as -distribution of the source code, even though third parties are not -compelled to copy the source along with the object code. - - 4. You may not copy, modify, sublicense, or distribute the Program -except as expressly provided under this License. Any attempt -otherwise to copy, modify, sublicense or distribute the Program is -void, and will automatically terminate your rights under this License. -However, parties who have received copies, or rights, from you under -this License will not have their licenses terminated so long as such -parties remain in full compliance. - - 5. You are not required to accept this License, since you have not -signed it. However, nothing else grants you permission to modify or -distribute the Program or its derivative works. These actions are -prohibited by law if you do not accept this License. Therefore, by -modifying or distributing the Program (or any work based on the -Program), you indicate your acceptance of this License to do so, and -all its terms and conditions for copying, distributing or modifying -the Program or works based on it. - - 6. Each time you redistribute the Program (or any work based on the -Program), the recipient automatically receives a license from the -original licensor to copy, distribute or modify the Program subject to -these terms and conditions. You may not impose any further -restrictions on the recipients' exercise of the rights granted herein. -You are not responsible for enforcing compliance by third parties to -this License. - - 7. If, as a consequence of a court judgment or allegation of patent -infringement or for any other reason (not limited to patent issues), -conditions are imposed on you (whether by court order, agreement or -otherwise) that contradict the conditions of this License, they do not -excuse you from the conditions of this License. If you cannot -distribute so as to satisfy simultaneously your obligations under this -License and any other pertinent obligations, then as a consequence you -may not distribute the Program at all. For example, if a patent -license would not permit royalty-free redistribution of the Program by -all those who receive copies directly or indirectly through you, then -the only way you could satisfy both it and this License would be to -refrain entirely from distribution of the Program. - -If any portion of this section is held invalid or unenforceable under -any particular circumstance, the balance of the section is intended to -apply and the section as a whole is intended to apply in other -circumstances. - -It is not the purpose of this section to induce you to infringe any -patents or other property right claims or to contest validity of any -such claims; this section has the sole purpose of protecting the -integrity of the free software distribution system, which is -implemented by public license practices. Many people have made -generous contributions to the wide range of software distributed -through that system in reliance on consistent application of that -system; it is up to the author/donor to decide if he or she is willing -to distribute software through any other system and a licensee cannot -impose that choice. - -This section is intended to make thoroughly clear what is believed to -be a consequence of the rest of this License. - - 8. If the distribution and/or use of the Program is restricted in -certain countries either by patents or by copyrighted interfaces, the -original copyright holder who places the Program under this License -may add an explicit geographical distribution limitation excluding -those countries, so that distribution is permitted only in or among -countries not thus excluded. In such case, this License incorporates -the limitation as if written in the body of this License. - - 9. The Free Software Foundation may publish revised and/or new versions -of the General Public License from time to time. Such new versions will -be similar in spirit to the present version, but may differ in detail to -address new problems or concerns. - -Each version is given a distinguishing version number. If the Program -specifies a version number of this License which applies to it and "any -later version", you have the option of following the terms and conditions -either of that version or of any later version published by the Free -Software Foundation. If the Program does not specify a version number of -this License, you may choose any version ever published by the Free Software -Foundation. - - 10. If you wish to incorporate parts of the Program into other free -programs whose distribution conditions are different, write to the author -to ask for permission. For software which is copyrighted by the Free -Software Foundation, write to the Free Software Foundation; we sometimes -make exceptions for this. Our decision will be guided by the two goals -of preserving the free status of all derivatives of our free software and -of promoting the sharing and reuse of software generally. - - NO WARRANTY - - 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY -FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN -OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES -PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED -OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS -TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE -PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, -REPAIR OR CORRECTION. - - 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING -WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR -REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, -INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING -OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED -TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY -YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER -PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE -POSSIBILITY OF SUCH DAMAGES. - - END OF TERMS AND CONDITIONS - - How to Apply These Terms to Your New Programs - - If you develop a new program, and you want it to be of the greatest -possible use to the public, the best way to achieve this is to make it -free software which everyone can redistribute and change under these terms. - - To do so, attach the following notices to the program. It is safest -to attach them to the start of each source file to most effectively -convey the exclusion of warranty; and each file should have at least -the "copyright" line and a pointer to where the full notice is found. - - <one line to give the program's name and a brief idea of what it does.> - Copyright (C) <year> <name of author> - - 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; either version 2 of the License, or - (at your option) any later version. - - 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, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - - -Also add information on how to contact you by electronic and paper mail. - -If the program is interactive, make it output a short notice like this -when it starts in an interactive mode: - - Gnomovision version 69, Copyright (C) year name of author - Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. - This is free software, and you are welcome to redistribute it - under certain conditions; type `show c' for details. - -The hypothetical commands `show w' and `show c' should show the appropriate -parts of the General Public License. Of course, the commands you use may -be called something other than `show w' and `show c'; they could even be -mouse-clicks or menu items--whatever suits your program. - -You should also get your employer (if you work as a programmer) or your -school, if any, to sign a "copyright disclaimer" for the program, if -necessary. Here is a sample; alter the names: - - Yoyodyne, Inc., hereby disclaims all copyright interest in the program - `Gnomovision' (which makes passes at compilers) written by James Hacker. - - <signature of Ty Coon>, 1 April 1989 - Ty Coon, President of Vice - -This General Public License does not permit incorporating your program into -proprietary programs. If your program is a subroutine library, you may -consider it more useful to permit linking proprietary applications with the -library. If this is what you want to do, use the GNU Library General -Public License instead of this License. diff --git a/protocols/Weather/docs/readme.html b/protocols/Weather/docs/readme.html deleted file mode 100644 index 0f3e8d80c8..0000000000 --- a/protocols/Weather/docs/readme.html +++ /dev/null @@ -1,230 +0,0 @@ -<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> -<html> - <head> - <title>Read Me for Weather Protocol</title> - <script language="javascript" type="text/javascript"> -function link(num){document.location="http://addons.miranda-im.org/details.php?action=viewfile&id="+num;} - </script> - </head> - <body> - <h2>Read Me for Weather Protocol</h2> - <hr/> - <pre> -<a name="top"><font color="red"> -<b>*** IMPORTANT NOTICE ***</b> -Be cautious when choosing the "special status" selection for selecting the status -assign to contact whose current condition is unavailable. This feature is not -officially support by Miranda and may cause a lot of plugins to crash. Be sure to -backup your profile before you try this feature.</font> - -</a> -</pre> -<hr/> -<pre> - -<b><u>File Content</u></b> - -<a href="#fea">Features</a> -<a href="#fi">Files Included</a> -<a href="#sr">System Requirement</a> -<a href="#ins">Installation</a> -<a href="#faq">Frequently Asked Questions</a> -<a href="#lic">License</a> - -</pre> -<hr/> -<pre> - -<a name="fea"><b><u>Features</u></b> - - - Retrieve weather information and display them on your Miranda contact list. - - Provide a contact information page for viewing the current weather conditions. - - Display PopUp when information is retrieved. - - Log weather conditions to a file or in history. - - Quick links for viewing complete forecast and weather maps. - - -</a><a name="fi"><b><u>Files Included</u></b> - - - plugins\weather.dll - The core to the weather plugin. Required component - - </a><a href="langpack_defweather.txt">langpack_defweather.txt</a> (stored in the documentation folder by default) - Langpack for weather icon assignment, containing documentation for how to use - - <a href="weather-readme.html">plugins\weather-doc\weather-readme.html</a> - Documentation and FAQ for Weather Protocol (this file). - - <a href="sample_ini.ini">plugins\weather-doc\sample_ini.ini</a> - Documentation of the format of the weather INI file. - - <a href="weather-translation.txt">plugins\weather-doc\weather-translation.txt</a> - A file that contains a translation of hopefully all string used in Weather Protocol. - - -<a name="sr"><b><u>System Requirement</u></b> - - - </a><a href= -"http://www.miranda-im.org">Miranda IM</a> (v0.7.3.0 or later) - - <a href="http://addons.miranda-im.org/index.php?action=display&id=78">Weather INI file</a> - - Weather icons (Optional) - Numerous choices available in <a href= -"http://addons.miranda-im.org/index.php?action=display&id=35">icon downloads</a>. - - <a href= -"javascript:link(2759)">YAPP plugin</a> by sje or <a href= -"javascript:link(3400)">PopUp Plus plugin</a> by nullbie (Optional) - - -<a name="ins"><b><u>Installation</u></b> - For installation of weather protocol, it is recommended for installing it using Miranda - Installer. For manual installation, please following these steps: - - 1. Copy weather.dll into plugins directory. - 2. Get the ini's from file listing and place them into plugin\weather directory. - 3. If you want external file for status icon selection, copy the content of - langpack_defweather.txt into your language pack and (optionally) enable - "Disable internal icon selection" from the option page. - 4. In icon option, customize the weather icon or use the default one in the dll - - IMPORTANT UPGRADE NOTICE - Due to the changes made in this version, Weather 0.3.x is not compatible with older - releases (v0.2.x). Therefore, you should delete your weather contacts before - upgrading to this new version. - - -</a><a name="faq"><b><u>Frequently Asked Question</u></b> - -<i><u>Setting Up Weather Protocol</u></i> -For installation, follow the steps describe in the </a><a href= -"#ins">installation</a> section of the readme. - -<b>Q1-1. Weather Protocol does not do anything after I installed it, and it - cannot go online.</b> -A. You need to add a new station before you can go online. - -<b>Q1-2. How do I add new stations?</b> -A. Use the find/add dialog box. You can either search for station ID (see the readme - for the ini file to see how it can be obtained) or search by city name by entering - the name in either one of the Nickname, Firstname, or Lastname field. - -<b>Q1-3. I can't find my station! Any help?</b> -A. Make sure you have installed the plugin and ini file correctly. At least one INI - file must exist in the plugins\weather directory in order for the plugin to funciton - properly. For more information, click <a href= -"#ins">here</a>. - -<b>Q1-4. I have installed the plugin properly, and it still doesn't work. I have - noticed that there is no traffic generated by the plugin.</b> -A. Check you proxy setting, some proxy does not work properly under Miranda IM 0.3.3.0. - If your proxy is having problem connecting, you need to upgrade to Miranda IM 0.3.3.1 - or try the <a href="http://www.miranda-im.org/development/">nightly builds</a> - (Note: They are experimental builds!) - Also, if you are using <a href="javascript:link(844)">traffic counter</a> plugin, - please make sure that you are using the latest version. The old version stops Weather - and some other plugin from working. - -<i><u>INI and Development Related Questions</u></i> - -<b>Q2-1. What are those INI files for?</b> -A. The INI files contain information for downloading and parsing weather information - from a particular weather site. At least one INI file must exist in order for the - plugin to work. For a list of available INI's, click <a href="#top">here</a>. - -<b>Q2-2. Can I install or modify the INI files without restarting Miranda?</b> -A. Yes, choose: M (main menu) -> Weather -> Reload Weather Data - -<b>Q2-3. I want to retrieve weather information from a different source than those - that are currently available. How can this be done?</b> -A. You can write your own INI file. For more information, click <a href="sample_ini.ini">here</a>. - -<b>Q2-4. I wrote/downloaded an ini file that retrieve weather condition in a - language that weather protocol doesn't seems to reconize and always - display N/A. What should I do?</b> -A. You can use translation string for assigning icons. For more information, click <a href="langpack_defweather.txt">here</a>. - -<b>Q2-5. How does weather assign status icons for each status?</b> -A. Online = Sunny - Away = Partly Cloudy - NA = Cloudy - Occupied = Rain - DND = Rain Shower - Free for Chat = Snow / Wintery Conditions - Invisible = Lightning / Thunderstorm - On the Phone = Snow Shower - Out to Lunch = Fog / Haze - Offline = No Data Available - -<u><i>Obtaining Weather Data</i></u> - -<b>Q3-1. Does weather protocol retreve weather forecasts?</b> -A. Support of this feature depend on the ini file you use. If it is supported, the most - likely variable you use for it is %[Forecast Day #] or %[FD#] where # is the day you - want the forecast for. See the readme supplied in the INI file package for more - information. - -<b>Q3-2. How long should the time between update be?</b> -A. This depend on the update interval on the website. Generally, this field should set - to a value between 10 to 30 minutes. If the value is too small, a lot of traffics - will be generated by the protocol. - -<b>Q3-3. How can I temporary disable weather procotol?</b> -A. Switch the weather status to OFFLINE, but this will not work if you have "Do not - display weather condition as protocol status" option enabled. To enable the - protocol again, switch it to a status other than OFFLINE. Automatic update of - weather condition can be disabled through menu and option page. - -<b>Q3-4. Why are the name of some weather contacts italic on my contact?</b> -A. There are weather alerts issued for those cities. To see the alert title, use the - %[Alert] variable. You can disable this function in option page. - -<b>Q3-5. There are some status that the weather plugin doesn't seems to - reconize and always shows as N/A on the contact list. What can I do?</b> -A. If the source of weather info is in a language other than English, please check the - INI package for instruction of how to install language pack. If the source is in - English, notify me. - -<u><i>Customizing the Weather Protocol</i></u> - -<b>Q4-1. Can I hide Weather from status bar and protocol menu?</b> -A. Go to Options->Plugins->Weather, enable "Hide Weather in status bar and status menu". - -<b>Q4-2. I can't find Weather in the icon option drop-down list. How can I change - weather icons?</b> -A. Weather icon cannot be changed if "Hide Weather in status bar and status menu" is - enabled. To change icons, disable the option (see Q4-1), make your change, then re- - enable it. - -<b>Q4-3. I can't find the options for changing display text.</b> -A. Go to Options->Plugins->Weather, then click on the icon beside "Change display texts" - -<b>Q4-4. How can I change the display name of my city?</b> -A. Right-click on the city and select "Edit Settings". Change the field "City name" - to the new display name. - -<b>Q4-5. How can I change the default station?</b> -A. Use the Edit Settings dialog (See A4-4). Note that only 1 station can be default. - -<b>Q4-6. What is the %[..] variable for?</b> -A. They are the custom variables. Replace the ".." with a setting name that can be - found in \Weather in the database. For more information about the availability of - the settings, use <a href= -"javascript:link(2957)">Database Editor</a> or refer to the readme of the ini file. - -<b>Q4-7. What are the "Extra Text" for?</b> -A. The field has no use internally. However, it can be useful for some other plugin - to obtain a weather information string that is already parsed. - -<b>Q4-8. I want weather protocol to have the same status as the other protocols. - Is such option available?</b> -A. -Disable the option "Use weather condition as protocol status", then you will be - able to change the status freely. - -<b>Q4-9. How do I create avatars for each weather condition?</b> -A. Put the following files into the Miranda\Plugins\Weather folder: - Light.png, Fog.png, SShower.png, Snow.png, RShower.png, Rain.png - PCloudy.png, Cloudy.png, Sunny.png, NA.png - - -<a name="lic">License - -This plugin is released under </a><a href="http://www.gnu.org/licenses/gpl.txt">GPL</a>. -</pre> - </body> -</html> diff --git a/protocols/Weather/docs/sample_ini.ini b/protocols/Weather/docs/sample_ini.ini deleted file mode 100644 index 9a045e1a3c..0000000000 --- a/protocols/Weather/docs/sample_ini.ini +++ /dev/null @@ -1,428 +0,0 @@ -[Weather 0.3.x Update Data 1.5] - -; This file contains the information required for the weather protocol to obtain update. -; For the plugin to function properly, at least one of these file must be present. -; The proper location of these files is: plugins\weather - -; Note that for the entire file, DO NOT put spaces before or after the "=". The groups -; and setting names (for example, [Header] and Name) are not case sensitive; however, -; the values set for each settings ARE case sensitive. - -; Also note that the first line of this file must be either one of the following: -; [Weather 0.3.x Update Data] (min. req. v0.3.0.0) -; [Weather 0.3.x Update Data 1.1] (min. req. v0.3.1.8) -; [Weather 0.3.x Update Data 1.1a] (min. req. v0.3.2.8) -; [Weather 0.3.x Update Data 1.2] (min. req. v0.3.5.0) -; [Weather 0.3.x Update Data 1.3] (min. req. v0.3.8.0) -; [Weather 0.3.x Update Data 1.4] (min. req. v0.3.8.12) -; [Weather 0.3.x Update Data 1.5] (min. req. v0.4.0.2) - -; Minimun version for not crashing Miranda (Set to this version to prevent the ini from -; loading in an old version of weather plugin and crash Miranda) -; 1.1a String longer than 256 characters. -; 1.1 More than 16 data items in the ini -; Not using [/...] footer at the end of the list -; 1.0 All other features - -; Minimun version for using the new features (Set to this version to prevent invalid data -; for user with old version of weather plugin. However, the other features still works) -; 1.5 Using "UserAgent=" -; 1.4 Using "Cookie=" -; 1.3 Using "Update Url2=" & "Update Url3=" -; 1.2 Using the operation "Break Data=" -; Using the setting "Hidden=" for each data item -; Assign weather icons from ini -; 1.1a Support for the units: Day, Month, %, Deg, Cond -; 1.1 Using the operation "Set Data=" -; 1.0 All other features - -; Revision history: -; 1.5 (Updated in v0.4.0.2) -; New "UserAgent=" -; 1.4 (Updated in v0.3.8.12) -; New "Cookie=" -; 1.3 (Updated in v0.3.8.0) -; New "Update Url2=" & "Update Url3=" -; 1.2 (Updated in v0.3.5.0; minimun req. v0.3.5.0) -; New operation "Break Data=" -; New setting "Hidden=" that hide the data item from the mor data list -; Weather icon assignment from the ini -; 1.1a (Updated in v0.3.4.0; minimun req. v0.3.2.8) -; Support for Day, Month units -; 1.1a (Updated in v0.3.3.0; minimun req. v0.3.2.8) -; Support the %, Deg, Cond units -; 1.1a (For v0.3.2.8; minimun req. v0.3.2.8) -; Now the string can be unlimited long (at least when it's within 4096 characters) -; 1.1 (For v0.3.2.0; minimun req. v0.3.1.8) -; No more need to use [/...] headers (now it just like a normal INI file) -; Support more weather data, and the number of data is no longer limited to 16 -; New operation "Set Data=" that assign data items without download the info -; 1.0 (For v0.3.0.0; minimun req. v0.3.0.0) -; Initial version. - -; ====================================================================================== - -; INI Headers - -[Header] -; The name field contains the string that will appear to the user. Please be unique. -; (for example, "Yahoo Weather") -Name= - -; The internal name is the string that will be used to set the weather ID, and are used -; internally to obtain the weather update information. This string should be short and -; unique. -; (for example, "yw" for "Yahoo Weather") -Internal Name= - -; The following 3 fields are used in the plugin for INI information only, but it also -; gives user some information about the file. -Description= -Author= -Version= - -; For the following three default fields, %s is used for station ID (the one with the -; internal name taken away, for example, CAXX0001) -[Default] -; The default URL for getting more weather information from contact menu or brief info -; dialog. This setting is the default one assigned to the weather contact when it is -; added, but can be changed by user in the Edit Settings dialog. -Default URL= - -; The default URL for getting weather map from contact menu. Same as above. -Default Map= - -; The URL for retrieving weather updates. -Update URL= -Update URL2= -Update URL3= -Update URL4= - -; Set cookie(s) when retrieving weather updates. -Cookie= - -; Set user agent for http requests. -UserAgent= - -; ====================================================================================== - -; Weather Data Fields - -; The following section list the data fields that are used to assign the data to be stored -; in the database. These fields should be placed in the order of appearance in the -; download information. For each item searched, the string before the item are discarded -; so if the order is wrong, no information can be obtained from the latter item. - -; Format (not all settings are necessary): -; [Field Name] -; Start= -; End= -; Set Data= -; Break Data= -; Source= -; Unit= -; Hidden= - -; Default Fields: -; [Condition] Current condition, to assign condition icon -; [Update] For display of the update time of the weather data -; [Temperature] Current temperature -; [Feel] Feel-like temperature -; [High] Today's high -; [Low] Today's low -; [Sunrise] Sun rise time -; [Sunset] Sun set time -; [Wind Direction] Wind direction (not including speed) -; Be careful to consider the no wind situation (ie. calm) -; [Wind Speed] The speed of the wind -; [Pressure] Barometer pressure -; [Visibility] Visibility, if the value is 0 or non-numerical value, then unit conversion -; for this will not run and original string is retained -; [Humidity] Humidity, without a % sign. - -; Special Fields: -; [Alert] -; Special item for weather alert. -; If the data retrieved for this field is non-empty, then a special alert popup will -; display and the city on the contact list will be in a special state (using the -; setting for "Contact to whom you have a different visibility". -; This will be reset to normal once the alert field becomes empty. -; [Ignore] -; Special item for the plugin to ignore what the value it gets and all errors when -; getting it. The value obtained for this field will not be written into the -; database, and no popup and notification will be raised. This is useful to skip -; some specific text or end the download script. Multiple placement of this field -; is allowed. -; Note: For prevent the popup of error message, v0.3.2.11 is required - -; Custom Fields: -; [%name%] -; Where %name% can be any string you want. - - -; Settings: -; Settings for obtaining data: "Start=", "End=", "Set Data=", "Break Data=", "Source=" - -; There are 3 ways for the plugin to obtain the information string: -; 1. Parse directly from the webpage by specifying start and end strings. Note that these -; strings are case sensitive. - -; When parsing the information, the following items are removed: -; HTML tags example: <b> </b> -; symbols example: -; linefeed and tabs -; multiple spaces, spaces at the beginning and at the end of the string -; Also, if the start field is blank, that means the information starts immediately -; after the string from the last "End=" field. If the end field is blank, that means -; the information ends at the first space the plugin encounters (even if it is inside -; a HTML tag). - -; An example, for parsing -; "<sth before>Partly <!-- something in middle --> Cloudy<sth after> -; The code to give "Partly Cloudy" (without quotation): -; [Condition] -; Start=<sth before> -; End=<sth after> - -; 2. Concatenate strings, using "Set Data=", can merge various string together by placing -; them around the operator " & " (without the quotation mark but with the 2 spaces). -; For the variable strings (ie. the data item retrieved previously), use [] -; For constant strings, use "" - -; For example, merging two condition strings "Condition 1" and "Condition 2": -; [Condition] -; Set Data=[Condition 1] & " and " & [Condition 2] - -; Another example, copy the content of "Condition -; [Copy of Condition] -; Set Data=[Condition] - -; 3. Break a string into 2, using "Break Data=", by specifying the string in between the -; two substrings. The first half will store into the name specify by the header, and -; the second half will be specified by "End=" - -; An example, to reverse what we did in Example 2 (the two condition strings): -; [Condition 1] -; Break Data= and -; Source=Condition -; End=Condition 2 - -; Other Settings: -; Unit= -; Specify the unit for the data, for use in unit conversion. The conversion to use -; depends on the value assigned. -; For temperature conversion: C, F, K -; For speed conversion: km/h, m/s, mph, knots -; For pressure conversion: hPa, kPa, mb, torr, mm, in -; For distance conversion: km, miles -; For adding a percent sign at the end: % -; For adding a degree sign at the end: Deg -; Convert condition str to proper case: Cond -; For weekday string length: Day -; For month string length: Month - -; Hidden= -; Acceptable values: true, false -; Using this on any field will prevent it from being displayed in the "More Info" -; list, but its value will still be stored in the database. - -; Url= -; Acceptable values: 1, 2, 3 -; Specifies the url on where to look for data item -; If parameter is not specified item is searched on all urls, the last found will be used - -; Here's an example: -[Condition] -Start= -End= -Unit=Cond - -[Temperature] -Start= -End= -Unit=C - -[Humidity TEMP] -Start= -End= -Hidden=true - -[Humidity] -Set Data=[Humidity TEMP] & "%" - -; - or - - -[Humidity] -Start= -End= -Unit=% - - -; ====================================================================================== - -; The setting for find and add contacts. - -; ID search is used when the user type in the ID in the "Station ID" field and pressed -; "Search" -[ID Search] - -; This can be "true" or "false" (without quotation, not case sensitive) -; If this is set to "false", all the following strings are ignored and the ID are NOT -; going to search for this weather service. -; If this field is set to FALSE, no matter what the user type for station ID, the -; plugin will always return a result with station name empty and ID the same as what -; the user has typed. -Available= - -; The URL for ID search. Note that %s is used for placing the ID. -Search URL= - -; The string appeared in the downloaded information when there is no match -; (ie. "Document not found") -; If this string is found while searching, the search process quit and return no result. -Not Found Str= - -; Similar to weather information retrival above. This is the string preceeding the -; station name obtained from searching. Note that the parsing is the same as above, and -; spaces can be used. -Name Start= - -; This is what's after the station name. -Name End= - -; END ID SEARCH - -; Name search is used when the user type in any of the name field (Nick, First, Last) and -; click on the "search" button. -[Name Search] - -; This can be "true" or "false" (without quotation, not case sensitive) -; If this is set to "false", then the plugin igmore the information stated in the Single -; fields (ie. from "Single Name Start" to "Single ID End") -Single Result= - -; This can be "true" or "false" (without quotation, not case sensitive) -; If this is set to "false", then the plugin igmore the information stated in the Multiple -; fields (ie. from Multiple Name Start" to Multiple ID End") -; Note that if both single and multiple are disabled, the Name search are disabled for -; this weather service. -Multiple Result= - -; The URL for doing the name search. %s will be replaced by the station name input from -; the user. -Search URL= - -; The string appeared in the downloaded information when there is no match -; (ie. "Document not found") -; If this string is found while searching, the search process quit and return no result. -Not Found Str= - -; This field determines whether the search will return a single result or multiple result -; If the string stated in this field is found and Single Result is enabled from above, the -; settings for single result will be used. Otherwise, the settings in multiple result -; will be used. -Single Result Str= - -; These fields are for the single result - -; Determine which item is the first to appear in the download search result file -; This field can be ID or Name (not case sensitive). -; For example, if ID is used here, it means that station ID appears before the station -; name in the downloaded document. -Single First= - -; The start and end string for station name. Parsing using the same way as discribed -; above for weather information. -; Note that if both fields are empty, then whatever the user type into the search field -; will be used for the station name. -Single Name Start= -Single Name End= - -; The start and end string for station name. Parsing using the same way as discribed -; above for weather information. -Single ID Start= -Single ID End= - -; The multiple result is similar to the single result as described above. -; For this search, the plugin will loop until no more Name's and ID's can be founded -; in the downloaded file. -Mult First= -Mult Name Start= -Mult Name End= -Mult ID Start= -Mult ID End= - -; END NAME SEARCH - -; For a workaround of URL forwarding issue: -; If the page retrieved contains URL forward (ie. the 302 code), the download content -; will appears as: -; Moved/Location: <forwarded URL> -; This might be useful for writing the start/end string settings for the single result -; Name Search. -; A typical use of this is: -; Single Result Str=Moved/Location: -; Single First=ID (this isn't really matter) -; Single Name Start= -; Single Name End= (this will use whatever user type in as stn name) -; Single ID Start=/newpages/ (what's before the station ID in the URL) -; Single ID End=.html (what's after the station ID) - -; ====================================================================================== - -; INI Defined Icon Assignments (new in v1.2) - -; These assignment will take the highest priority (before the internal and the langpack -; defined assignment) when matching the condition (icon) to the current condition. -; These settings are INI specific, which means that the setting in one INI will not affect -; the stations that are associated to another INI. - -; Format: -; {icon name}={string to search} - -; The "icon name" is the icon to assigned with the condition string containing the string -; specified in "string to search" is found. - -; Available icon names are (in order of assigning priority): -; Lightning, Fog, Snow Shower, Snow, Rain Shower, Rain, Partly Cloudy, Cloudy, Sunny, N/A - -; For examples, mimicking what internal icon selection and langpack_defweather do (of -; course, putting these in an actual INI is not needed and is waste of space and memory). - -[Icons] -Sunny=Sunny -Sunny=Clear -Sunny=Fair - -Partly Cloudy=Mainly Sunny -Partly Cloudy=Mainly Clear -Partly Cloudy=Partly -Partly Cloudy=Mostly -Partly Cloudy=Clouds - -Cloudy=Cloudy -Cloudy=Overcast - -Rain=Drizzle -Rain=Rain - -Rain Shower=Rain Shower -Rain Shower=Shower - -Snow=Snow -Snow=Ice -Snow=Freezing -Snow=Wintery - -Snow Shower=Snow Shower -Snow Shower=Flurries - -Ligntning=Thunder -Ligntning=T-storm - -Fog=Fog -Fog=Mist -Fog=Smoke -Fog=Haze -Fog=Sand -Fog=Dust diff --git a/protocols/Weather/docs/weather/gismeteo_com.ini b/protocols/Weather/docs/weather/gismeteo_com.ini deleted file mode 100644 index 2d7a4a48dc..0000000000 --- a/protocols/Weather/docs/weather/gismeteo_com.ini +++ /dev/null @@ -1,1254 +0,0 @@ -[Weather 0.3.x Update Data 1.5]
-
-;*********************************************************
-;
-; Прогноз для gismeteo.com.
-;
-; Поиск по названию города добавлен.
-; Можно искать по ID города, который предварительно выясняем на сайте Gismeteo.
-;
-; Перед использованием желательно удалить старые контакты
-; с погодой и найти нужные города по новой. Первый раз обновиться
-; из меню (правый клик на контакте) через "Удалить данные и обновить" .
-;
-; Чтобы все было красиво и понятно видно в миранде идем в
-; Параметры->Модули->Погода->Показывать и поле "Кратко" (остальные поля по вкусу)
-; полностью заменяем на:
-
-; Состояние погоды в %[CityName] на %u
-; ----------------------------------------------------------------
-; Условия: %c
-; Температура: %t
-; Давление: %p
-; Влажность: %m
-; Ветер: %i %w
-; Температура воды: %[TW]
-; Восход: %r, Закат: %y, Продолжительность дня: %[Day Length], Фаза Луны: %[Moon phase]
-;
-; Прогноз (Дата, Температура [Комфорт], Условия, Ветер, Давление, Влажность)
-; -------------------------------------------------------------------------------------------------------
-; %[Forecast Day 1]
-; %[Forecast Day 2]
-; %[Forecast Day 3]
-; %[Forecast Day 4]
-; %[Forecast Day 5]
-; %[Forecast Day 6]
-; %[Forecast Day 7]
-; %[Forecast Day 8]
-; %[Forecast Day 9]
-
-[Header]
-Name=GisMeteo.com
-Internal Name=gm_com
-Description=Weather information from Gismeteo.com
-Author=Dimtr
-Version=2023.05.24
-Utf8=true
-
-[Default]
-Default URL=https://www.gismeteo.com/weather-%s/
-Default Map=https://www.gismeteo.com/nowcast-%s/?utm_campaign=radar&utm_source=gismeteo&utm_medium=radar_teaser
-Update URL=https://www.gismeteo.com/weather-%s/now/
-Update URL2=https://www.gismeteo.com/weather-%s/
-Update URL3=https://www.gismeteo.com/weather-%s/10-days/
-
-;-----------------------------------------------------
-
-;[Condition]
-;Start=data-text="
-;Start="description":["
-;End="]
-;End=">
-;Unit=Cond
-;Url=2
-
-;[TempNow]
-;Start="temperatureAir":[
-;End=]
-;Url=2
-;Hidden=true
-
-;[TempWater]
-;Start="temperatureWater":[
-;End=]
-;Url=2
-;Hidden=true
-
-;[Visibility]
-;Start="visibility":[
-;End=]
-;Url=2
-
-;[Humidity]
-;Start="humidity":[
-;End=]
-;Unit=%
-;Url=2
-
-;[Pressure]
-;Start="pressure":[
-;End=]
-;Unit=mm
-;Url=2
-
-;[WS]
-;Start="windSpeed":[
-;End=]
-;Unit=m/s
-;Url=2
-;Hidden=true
-
-[Condition]
-Start=data-text="
-End="
-Unit=Cond
-Url=1
-
-[Update]
-Start=data-pattern="G:i">
-End=</div>
-Url=1
-
-[TempNow]
-Start=<span class="sign">
-End=<span class="unit
-Url=1
-Hidden=true
-
-[Temperature]
-Set Data=[TempNow] & " °C"
-
-[TempFeel]
-Start=<span class="sign">
-End=<span class="unit
-Url=1
-Hidden=true
-
-[Feel]
-Set Data=[TempFeel] & " °C"
-
-[Low]
-Start=<span class="unit unit_temperature_c">
-End=</span>
-Unit=C
-Url=1
-
-[High]
-Start=<span class="unit unit_temperature_c">
-End=</span>
-Unit=C
-Url=1
-
-[WS]
-Start=<div class="unit unit_wind_m_s">
-End=<div
-;Unit=m/s
-Url=1
-Hidden=true
-
-[Wind speed]
-Set Data=[WS] & " " & "m/s"
-
-;[Visibility]
-;Set Data=[Condition]
-;[/Visibility]
-
-[Wind direction]
-Start=</div><div>
-End=</div>
-Url=1
-
-[Pressure]
-Start=<div class="unit unit_pressure_mm_hg_atm">
-End=<div
-Unit=mm
-Url=1
-
-[Humidity]
-Start=<div class="item-value">
-End=</div>
-Unit=%
-Url=1
-
-[TempWater]
-Start=<span class="sign">
-End=<span class="unit
-Url=1
-Hidden=true
-
-[TW]
-Set Data=[TempWater] & " °C"
-
-[Day Length]
-Start=<div class="astro-progress">
-End=</div>
-Url=2
-
-[Sunrise]
-Start=<div>
-End=</div>
-Url=2
-
-[Sunset]
-Start=<div>
-End=</div>
-Url=2
-
-[Moon phase]
-Start=<div class="astro-progress">
-End=</div>
-Url=2
-
-[Moonrise]
-Start=<div>
-End=</div>
-Url=2
-
-[Moonset]
-Start=<div>
-End=</div>
-Url=2
-
-; DATE: T - time, D - day, M - month, W - weekday
-
-[FD0DW]
-Start=<div class="day">
-End=</div>
-Url=3
-Hidden=true
-
-[FD0DDM]
-Start=<div class="date">
-End=</div>
-Url=3
-Hidden=true
-
-[FD1DW]
-Start=/tomorrow/"><div class="day">
-End=</div>
-Url=3
-Hidden=true
-
-[FD1DDM]
-Start=<div class="date">
-End=</div>
-Url=3
-Hidden=true
-
-[FD2DW]
-Start=<div class="day">
-End=</div>
-Url=3
-Hidden=true
-
-[FD2DDM]
-Start=<div class="date">
-End=</div>
-Url=3
-Hidden=true
-
-[FD3DW]
-Start=<div class="day">
-End=</div>
-Url=3
-Hidden=true
-
-[FD3DDM]
-Start=<div class="date">
-End=</div>
-Url=3
-Hidden=true
-
-[FD4DW]
-Start=<div class="day">
-End=</div>
-Url=3
-Hidden=true
-
-[FD4DDM]
-Start=<div class="date">
-End=</div>
-Url=3
-Hidden=true
-
-[FD5DW]
-Start=<div class="day">
-End=</div>
-Url=3
-Hidden=true
-
-[FD5DDM]
-Start=<div class="date">
-End=</div>
-Url=3
-Hidden=true
-
-[FD6DW]
-Start=<div class="day">
-End=</div>
-Url=3
-Hidden=true
-
-[FD6DDM]
-Start=<div class="date">
-End=</div>
-Url=3
-Hidden=true
-
-[FD7DW]
-Start=<div class="day">
-End=</div>
-Url=3
-Hidden=true
-
-[FD7DDM]
-Start=<div class="date">
-End=</div>
-Url=3
-Hidden=true
-
-[FD8DW]
-Start=<div class="day">
-End=</div>
-Url=3
-Hidden=true
-
-[FD8DDM]
-Start=<div class="date">
-End=</div>
-Url=3
-Hidden=true
-
-[FD9DW]
-Start=<div class="day">
-End=</div>
-Url=3
-Hidden=true
-
-[FD9DDM]
-Start=<div class="date">
-End=</div>
-Url=3
-Hidden=true
-
-;---------------//////////////////////////
-;------1--------//////////////////////////
-;---------------//////////////////////////
-;---------1-234--------------
-
-[FD0D]
-Set Data=[FD0DW] & " " & [FD0DDM]
-Hidden=true
-
-[FD1D]
-Set Data=[FD1DW] & " " & [FD1DDM]
-Hidden=true
-
-[FD2D]
-Set Data=[FD2DW] & " " & [FD2DDM]
-Hidden=true
-
-[FD3D]
-Set Data=[FD3DW] & " " & [FD3DDM]
-Hidden=true
-
-[FD4D]
-Set Data=[FD4DW] & " " & [FD4DDM]
-Hidden=true
-
-[FD5D]
-Set Data=[FD5DW] & " " & [FD5DDM]
-Hidden=true
-
-[FD6D]
-Set Data=[FD6DW] & " " & [FD6DDM]
-Hidden=true
-
-[FD7D]
-Set Data=[FD7DW] & " " & [FD7DDM]
-Hidden=true
-
-[FD8D]
-Set Data=[FD8DW] & " " & [FD8DDM]
-Hidden=true
-
-[FD9D]
-Set Data=[FD9DW] & " " & [FD9DDM]
-Hidden=true
-
-; CONDITION
-
-[FD0C]
-Start=data-text="
-End="
-Unit=Cond
-Url=3
-Hidden=true
-
-[FD1C]
-Start=data-text="
-End="
-Unit=Cond
-Url=3
-Hidden=true
-
-[FD2C]
-Start=data-text="
-End="
-Unit=Cond
-Url=3
-Hidden=true
-
-[FD3C]
-Start=data-text="
-End="
-Unit=Cond
-Url=3
-Hidden=true
-
-[FD4C]
-Start=data-text="
-End="
-Unit=Cond
-Url=3
-Hidden=true
-
-[FD5C]
-Start=data-text="
-End="
-Unit=Cond
-Url=3
-Hidden=true
-
-[FD6C]
-Start=data-text="
-End="
-Unit=Cond
-Url=3
-Hidden=true
-
-[FD7C]
-Start=data-text="
-End="
-Unit=Cond
-Url=3
-Hidden=true
-
-[FD8C]
-Start=data-text="
-End="
-Unit=Cond
-Url=3
-Hidden=true
-
-[FD9C]
-Start=data-text="
-End="
-Unit=Cond
-Url=3
-Hidden=true
-
-;temperature
-
-[FD0TH]
-Start=<div class="maxt"><span class="unit unit_temperature_c">
-End=</span>
-Unit=C
-Url=3
-Hidden=true
-
-[FD0L]
-Start=<span class="unit unit_temperature_c">
-End=</span>
-Unit=C
-Url=3
-Hidden=true
-
-[FD1TH]
-Start=<span class="unit unit_temperature_c">
-End=</span>
-Unit=C
-Url=3
-Hidden=true
-
-[FD1L]
-Start=<span class="unit unit_temperature_c">
-End=</span>
-Unit=C
-Url=3
-Hidden=true
-
-[FD2TH]
-Start=<span class="unit unit_temperature_c">
-End=</span>
-Unit=C
-Url=3
-Hidden=true
-
-[FD2L]
-Start=<span class="unit unit_temperature_c">
-End=</span>
-Unit=C
-Url=3
-Hidden=true
-
-[FD3TH]
-Start=<span class="unit unit_temperature_c">
-End=</span>
-Unit=C
-Url=3
-Hidden=true
-
-[FD3L]
-Start=<span class="unit unit_temperature_c">
-End=</span>
-Unit=C
-Url=3
-Hidden=true
-
-[FD4TH]
-Start=<span class="unit unit_temperature_c">
-End=</span>
-Unit=C
-Url=3
-Hidden=true
-
-[FD4L]
-Start=<span class="unit unit_temperature_c">
-End=</span>
-Unit=C
-Url=3
-Hidden=true
-
-[FD5TH]
-Start=<span class="unit unit_temperature_c">
-End=</span>
-Unit=C
-Url=3
-Hidden=true
-
-[FD5L]
-Start=<span class="unit unit_temperature_c">
-End=</span>
-Unit=C
-Url=3
-Hidden=true
-
-[FD6TH]
-Start=<span class="unit unit_temperature_c">
-End=</span>
-Unit=C
-Url=3
-Hidden=true
-
-[FD6L]
-Start=<span class="unit unit_temperature_c">
-End=</span>
-Unit=C
-Url=3
-Hidden=true
-
-[FD7TH]
-Start=<span class="unit unit_temperature_c">
-End=</span>
-Unit=C
-Url=3
-Hidden=true
-
-[FD7L]
-Start=<span class="unit unit_temperature_c">
-End=</span>
-Unit=C
-Url=3
-Hidden=true
-
-[FD8TH]
-Start=<span class="unit unit_temperature_c">
-End=</span>
-Unit=C
-Url=3
-Hidden=true
-
-[FD8L]
-Start=<span class="unit unit_temperature_c">
-End=</span>
-Unit=C
-Url=3
-Hidden=true
-
-[FD9TH]
-Start=<span class="unit unit_temperature_c">
-End=</span>
-Unit=C
-Url=3
-Hidden=true
-
-[FD9L]
-Start=<span class="unit unit_temperature_c">
-End=</span>
-Unit=C
-Url=3
-Hidden=true
-
-; WIND: H - Hidden data D - direction, S - Speed
-
-[FD0WS]
-Start=<span class="wind-unit unit unit_wind_m_s">
-End=</span>
-Unit=m/s
-Url=3
-Hidden=true
-
-[FD1WS]
-Start=<span class="wind-unit unit unit_wind_m_s">
-End=</span>
-Unit=m/s
-Url=3
-Hidden=true
-
-[FD2WS]
-Start=<span class="wind-unit unit unit_wind_m_s">
-End=</span>
-Unit=m/s
-Url=3
-Hidden=true
-
-[FD3WS]
-Start=<span class="wind-unit unit unit_wind_m_s">
-End=</span>
-Unit=m/s
-Url=3
-Hidden=true
-
-[FD4WS]
-Start=<span class="wind-unit unit unit_wind_m_s">
-End=</span>
-Unit=m/s
-Url=3
-Hidden=true
-
-[FD5WS]
-Start=<span class="wind-unit unit unit_wind_m_s">
-End=</span>
-Unit=m/s
-Url=3
-Hidden=true
-
-[FD6WS]
-Start=<span class="wind-unit unit unit_wind_m_s">
-End=</span>
-Unit=m/s
-Url=3
-Hidden=true
-
-[FD7WS]
-Start=<span class="wind-unit unit unit_wind_m_s">
-End=</span>
-Unit=m/s
-Url=3
-Hidden=true
-
-[FD8WS]
-Start=<span class="wind-unit unit unit_wind_m_s">
-End=</span>
-Unit=m/s
-Url=3
-Hidden=true
-
-[FD9WS]
-Start=<span class="wind-unit unit unit_wind_m_s">
-End=</span>
-Unit=m/s
-Url=3
-Hidden=true
-
-[FD0WD]
-Start=<div class="direction">
-End=</div>
-Url=3
-Hidden=true
-
-[FD1WD]
-Start=<div class="direction">
-End=</div>
-Url=3
-Hidden=true
-
-[FD2WD]
-Start=<div class="direction">
-End=</div>
-Url=3
-Hidden=true
-
-[FD3WD]
-Start=<div class="direction">
-End=</div>
-Url=3
-Hidden=true
-
-[FD4WD]
-Start=<div class="direction">
-End=</div>
-Url=3
-Hidden=true
-
-[FD5WD]
-Start=<div class="direction">
-End=</div>
-Url=3
-Hidden=true
-
-[FD6WD]
-Start=<div class="direction">
-End=</div>
-Url=3
-Hidden=true
-
-[FD7WD]
-Start=<div class="direction">
-End=</div>
-Url=3
-Hidden=true
-
-[FD8WD]
-Start=<div class="direction">
-End=</div>
-Url=3
-Hidden=true
-
-[FD9WD]
-Start=<div class="direction">
-End=</div>
-Url=3
-Hidden=true
-
-[FD0W]
-Set Data=[FD0WD] & " " & [FD0WS]
-Hidden=true
-
-[FD1W]
-Set Data=[FD1WD] & " " & [FD1WS]
-Hidden=true
-
-[FD2W]
-Set Data=[FD2WD] & " " & [FD2WS]
-Hidden=true
-
-[FD3W]
-Set Data=[FD3WD] & " " & [FD3WS]
-Hidden=true
-
-[FD4W]
-Set Data=[FD4WD] & " " & [FD4WS]
-Hidden=true
-
-[FD5W]
-Set Data=[FD5WD] & " " & [FD5WS]
-Hidden=true
-
-[FD6W]
-Set Data=[FD6WD] & " " & [FD6WS]
-Hidden=true
-
-[FD7W]
-Set Data=[FD7WD] & " " & [FD7WS]
-Hidden=true
-
-[FD8W]
-Set Data=[FD8WD] & " " & [FD8WS]
-Hidden=true
-
-[FD9W]
-Set Data=[FD9WD] & " " & [FD9WS]
-Hidden=true
-
-;Precipitation
-
-[Ignore]
-Start=<div class="item-unit
-End=">
-Url=3
-
-[Prec]
-Start=
-End=</div>
-Url=3
-Hidden=true
-
-[Precipitation]
-Set Data=[Prec] & " " & "mm"
-
-[Ignore]
-Start=<div class="item-unit
-End=">
-Url=3
-
-[FD1PR]
-Start=
-End=</div>
-Url=3
-Hidden=true
-
-[Ignore]
-Start=<div class="item-unit
-End=">
-Url=3
-
-[FD2PR]
-Start=
-End=</div>
-Url=3
-Hidden=true
-
-[Ignore]
-Start=<div class="item-unit
-End=">
-Url=3
-
-[FD3PR]
-Start=
-End=</div>
-Url=3
-Hidden=true
-
-[Ignore]
-Start=<div class="item-unit
-End=">
-Url=3
-
-[FD4PR]
-Start=
-End=</div>
-Url=3
-Hidden=true
-
-[Ignore]
-Start=<div class="item-unit
-End=">
-Url=3
-
-[FD5PR]
-Start=
-End=</div>
-Url=3
-Hidden=true
-
-[Ignore]
-Start=<div class="item-unit
-End=">
-Url=3
-
-[FD6PR]
-Start=
-End=</div>
-Url=3
-Hidden=true
-
-[Ignore]
-Start=<div class="item-unit
-End=">
-Url=3
-
-[FD7PR]
-Start=
-End=</div>
-Url=3
-Hidden=true
-
-[Ignore]
-Start=<div class="item-unit
-End=">
-Url=3
-
-[FD8PR]
-Start=
-End=</div>
-Url=3
-Hidden=true
-
-[Ignore]
-Start=<div class="item-unit
-End=">
-Url=3
-
-[FD9PR]
-Start=
-End=</div>
-Url=3
-Hidden=true
-
-; PRESSURE
-[FD0P]
-Start=<div class="maxt"><span class="unit unit_pressure_mm_hg_atm">
-End=</span>
-Unit=mm
-Url=3
-Hidden=true
-
-[FD1P]
-Start=<div class="maxt"><span class="unit unit_pressure_mm_hg_atm">
-End=</span>
-Unit=mm
-Url=3
-Hidden=true
-
-[FD2P]
-Start=<div class="maxt"><span class="unit unit_pressure_mm_hg_atm">
-End=</span>
-Unit=mm
-Url=3
-Hidden=true
-
-[FD3P]
-Start=<div class="maxt"><span class="unit unit_pressure_mm_hg_atm">
-End=</span>
-Unit=mm
-Url=3
-Hidden=true
-
-[FD4P]
-Start=<div class="maxt"><span class="unit unit_pressure_mm_hg_atm">
-End=</span>
-Unit=mm
-Url=3
-Hidden=true
-
-[FD5P]
-Start=<div class="maxt"><span class="unit unit_pressure_mm_hg_atm">
-End=</span>
-Unit=mm
-Url=3
-Hidden=true
-
-[FD6P]
-Start=<div class="maxt"><span class="unit unit_pressure_mm_hg_atm">
-End=</span>
-Unit=mm
-Url=3
-Hidden=true
-
-[FD7P]
-Start=<div class="maxt"><span class="unit unit_pressure_mm_hg_atm">
-End=</span>
-Unit=mm
-Url=3
-Hidden=true
-
-[FD8P]
-Start=<div class="maxt"><span class="unit unit_pressure_mm_hg_atm">
-End=</span>
-Unit=mm
-Url=3
-Hidden=true
-
-[FD9P]
-Start=<div class="maxt"><span class="unit unit_pressure_mm_hg_atm">
-End=</span>
-Unit=mm
-Url=3
-Hidden=true
-
-; Humidity
-
-[Ignore]
-Start=<div class="row-item
-End=">
-Url=3
-
-[FD0H]
-Start=
-End=</div>
-Unit=%
-Url=3
-Hidden=true
-
-[Ignore]
-Start=<div class="row-item
-End=">
-Url=3
-
-[FD1H]
-Start=
-End=</div>
-Unit=%
-Url=3
-Hidden=true
-
-[Ignore]
-Start=<div class="row-item
-End=">
-Url=3
-
-[FD2H]
-Start=
-End=</div>
-Unit=%
-Url=3
-Hidden=true
-
-[Ignore]
-Start=<div class="row-item
-End=">
-Url=3
-
-[FD3H]
-Start=
-End=</div>
-Unit=%
-Url=3
-Hidden=true
-
-[Ignore]
-Start=<div class="row-item
-End=">
-Url=3
-
-[FD4H]
-Start=
-End=</div>
-Unit=%
-Url=3
-Hidden=true
-
-[Ignore]
-Start=<div class="row-item
-End=">
-Url=3
-
-[FD5H]
-Start=
-End=</div>
-Unit=%
-Url=3
-Hidden=true
-
-[Ignore]
-Start=<div class="row-item
-End=">
-Url=3
-
-[FD6H]
-Start=
-End=</div>
-Unit=%
-Url=3
-Hidden=true
-
-[Ignore]
-Start=<div class="row-item
-End=">
-Url=3
-
-[FD7H]
-Start=
-End=</div>
-Unit=%
-Url=3
-Hidden=true
-
-[Ignore]
-Start=<div class="row-item
-End=">
-Url=3
-
-[FD8H]
-Start=
-End=</div>
-Unit=%
-Url=3
-Hidden=true
-
-[Ignore]
-Start=<div class="row-item
-End=">
-Url=3
-
-[FD9H]
-Start=
-End=</div>
-Unit=%
-Url=3
-Hidden=true
-
-; UV Index
-
-[Ignore]
-Start=<div class="row-item
-End=">
-Url=3
-
-[UV Index]
-Start=
-End=</div>
-Url=3
-
-[Ignore]
-Start=<div class="row-item
-End=">
-Url=3
-
-[FD1UV]
-Start=
-End=</div>
-Url=3
-Hidden=true
-
-[Ignore]
-Start=<div class="row-item
-End=">
-Url=3
-
-[FD2UV]
-Start=
-End=</div>
-Url=3
-Hidden=true
-
-[Ignore]
-Start=<div class="row-item
-End=">
-Url=3
-
-[FD3UV]
-Start=
-End=</div>
-Url=3
-Hidden=true
-
-[Ignore]
-Start=<div class="row-item
-End=">
-Url=3
-
-[FD4UV]
-Start=
-End=</div>
-Url=3
-Hidden=true
-
-[Ignore]
-Start=<div class="row-item
-End=">
-Url=3
-
-[FD5UV]
-Start=
-End=</div>
-Url=3
-Hidden=true
-
-[Ignore]
-Start=<div class="row-item
-End=">
-Url=3
-
-[FD6UV]
-Start=
-End=</div>
-Url=3
-Hidden=true
-
-[Ignore]
-Start=<div class="row-item
-End=">
-Url=3
-
-[FD7UV]
-Start=
-End=</div>
-Url=3
-Hidden=true
-
-[Ignore]
-Start=<div class="row-item
-End=">
-Url=3
-
-[FD8UV]
-Start=
-End=</div>
-Url=3
-Hidden=true
-
-[Ignore]
-Start=<div class="row-item
-End=">
-Url=3
-
-[FD9UV]
-Start=
-End=</div>
-Url=3
-Hidden=true
-
-;================================================
-;====================3===========================
-;================================================
-
-[Forecast Day 0]
-Set Data=[FD0D] & ": (" & [FD0TH] & "/" & [FD0L] & ")" & ", " & [FD0C] & ", " & "Precipitation" & ": " & [Prec] & " " & "mm" & ", \n" & "Wind" & ": " & [FD0W] & ", " & "Pressure" & ": " & [FD0P] & ", " & "Humidity" & ": " & [FD0H] & ", " & "UV Index" & ": " & [UV Index]
-
-[Forecast Day 1]
-Set Data=[FD1D] & ": (" & [FD1TH] & "/" & [FD1L] & ")" & ", " & [FD1C] & ", " & "Precipitation" & ": " & [FD1PR] & " " & "mm" & ", \n" & "Wind" & ": " & [FD1W] & ", " & "Pressure" & ": " & [FD1P] & ", " & "Humidity" & ": " & [FD1H] & ", " & "UV Index" & ": " & [FD1UV]
-
-[Forecast Day 2]
-Set Data=[FD2D] & ": (" & [FD2TH] & "/" & [FD2L] & ")" & ", " & [FD2C] & ", " & "Precipitation" & ": " & [FD2PR] & " " & "mm" & ", \n" & "Wind" & ": " & [FD2W] & ", " & "Pressure" & ": " & [FD2P] & ", " & "Humidity" & ": " & [FD2H] & ", " & "UV Index" & ": " & [FD2UV]
-
-[Forecast Day 3]
-Set Data=[FD3D] & ": (" & [FD3TH] & "/" & [FD3L] & ")" & ", " & [FD3C] & ", " & "Precipitation" & ": " & [FD3PR] & " " & "mm" & ", \n" & "Wind" & ": " & [FD3W] & ", " & "Pressure" & ": " & [FD3P] & ", " & "Humidity" & ": " & [FD3H] & ", " & "UV Index" & ": " & [FD3UV]
-
-[Forecast Day 4]
-Set Data=[FD4D] & ": (" & [FD4TH] & "/" & [FD4L] & ")" & ", " & [FD4C] & ", " & "Precipitation" & ": " & [FD4PR] & " " & "mm" & ", \n" & "Wind" & ": " & [FD4W] & ", " & "Pressure" & ": " & [FD4P] & ", " & "Humidity" & ": " & [FD4H] & ", " & "UV Index" & ": " & [FD4UV]
-
-[Forecast Day 5]
-Set Data=[FD5D] & ": (" & [FD5TH] & "/" & [FD5L] & ")" & ", " & [FD5C] & ", " & "Precipitation" & ": " & [FD5PR] & " " & "mm" & ", \n" & "Wind" & ": " & [FD5W] & ", " & "Pressure" & ": " & [FD5P] & ", " & "Humidity" & ": " & [FD5H] & ", " & "UV Index" & ": " & [FD5UV]
-
-[Forecast Day 6]
-Set Data=[FD6D] & ": (" & [FD6TH] & "/" & [FD6L] & ")" & ", " & [FD6C] & ", " & "Precipitation" & ": " & [FD6PR] & " " & "mm" & ", \n" & "Wind" & ": " & [FD6W] & ", " & "Pressure" & ": " & [FD6P] & ", " & "Humidity" & ": " & [FD6H] & ", " & "UV Index" & ": " & [FD6UV]
-
-[Forecast Day 7]
-Set Data=[FD7D] & ": (" & [FD7TH] & "/" & [FD7L] & ")" & ", " & [FD7C] & ", " & "Precipitation" & ": " & [FD7PR] & " " & "mm" & ", \n" & "Wind" & ": " & [FD7W] & ", " & "Pressure" & ": " & [FD7P] & ", " & "Humidity" & ": " & [FD7H] & ", " & "UV Index" & ": " & [FD7UV]
-
-[Forecast Day 8]
-Set Data=[FD8D] & ": (" & [FD8TH] & "/" & [FD8L] & ")" & ", " & [FD8C] & ", " & "Precipitation" & ": " & [FD8PR] & " " & "mm" & ", \n" & "Wind" & ": " & [FD8W] & ", " & "Pressure" & ": " & [FD8P] & ", " & "Humidity" & ": " & [FD8H] & ", " & "UV Index" & ": " & [FD8UV]
-
-[Forecast Day 9]
-Set Data=[FD9D] & ": (" & [FD9TH] & "/" & [FD9L] & ")" & ", " & [FD9C] & ", " & "Precipitation" & ": " & [FD9PR] & " " & "mm" & ", \n" & "Wind" & ": " & [FD9W] & ", " & "Pressure" & ": " & [FD9P] & ", " & "Humidity" & ": " & [FD9H] & ", " & "UV Index" & ": " & [FD9UV]
-
-;--------------------------------------------
-
-[Icons]
-Sunny=ясно
-Sunny=штиль
-Partly Cloudy=малооблачно
-Cloudy=облачно
-Cloudy=пасмурно
-Rain=небольшой дождь
-Rain Shower=дождь
-Rain Shower=ливень
-Snow=снег
-Snow=небольшой снег
-Snow=слабый снег хлопьями
-Snow Shower=снегопад
-Snow Shower=шквал
-Lightning=Storm
-Fog=туман
-
-[ID Search]
-Available=TRUE
-Search URL=https://www.gismeteo.com/search/%s/
-Not Found Str=Not Found
-Name Start=
-Name End=
-
-[Name Search]
-Single Result=false
-Multiple Result=true
-Search URL=https://www.gismeteo.com/search/%s/
-Not Found Str=Not found
-
-Mult First=ID
-Mult ID Start=<a href="/weather-
-Mult ID End=/"
-Mult Name Start=</i>
-Mult Name End=</a>
\ No newline at end of file diff --git a/protocols/Weather/docs/weather/gismeteo_ru.ini b/protocols/Weather/docs/weather/gismeteo_ru.ini deleted file mode 100644 index 43a8886c74..0000000000 --- a/protocols/Weather/docs/weather/gismeteo_ru.ini +++ /dev/null @@ -1,1331 +0,0 @@ -[Weather 0.3.x Update Data 1.5]
-
-;*********************************************************
-;
-; Прогноз для gismeteo.ru.
-;
-; Поиск по названию города добавлен.
-; Можно искать по ID города, который предварительно выясняем на сайте Gismeteo.
-;
-; Перед использованием желательно удалить старые контакты
-; с погодой и найти нужные города по новой. Первый раз обновиться
-; из меню (правый клик на контакте) через "Удалить данные и обновить" .
-;
-; Чтобы все было красиво и понятно видно в миранде идем в
-; Параметры->Модули->Погода->Показывать и поле "Кратко" (остальные поля по вкусу)
-; полностью заменяем на:
-
-; Состояние погоды в %[CityName] на %u
-; ----------------------------------------------------------------
-; Условия: %c
-; Температура: %t
-; Давление: %p
-; Влажность: %m
-; Ветер: %i %w
-; Температура воды: %[TW]
-; Восход: %r, Закат: %y, Продолжительность дня: %[Day Length], Фаза Луны: %[Moon phase]
-;
-; Прогноз (Дата, Температура [Комфорт], Условия, Ветер, Давление, Влажность)
-; -------------------------------------------------------------------------------------------------------
-; %[Forecast Day 1]
-; %[Forecast Day 2]
-; %[Forecast Day 3]
-; %[Forecast Day 4]
-; %[Forecast Day 5]
-; %[Forecast Day 6]
-; %[Forecast Day 7]
-; %[Forecast Day 8]
-; %[Forecast Day 9]
-
-[Header]
-Name=GisMeteo.ru
-Internal Name=gm_ru
-Description=Weather information from Gismeteo.ru
-Author=Dimtr
-Version=2023.05.24
-Utf8=true
-
-[Default]
-Default URL=https://www.gismeteo.ru/weather-%s/
-Default Map=https://www.gismeteo.ru/nowcast-%s/?utm_campaign=radar&utm_source=gismeteo&utm_medium=radar_teaser
-Update URL=https://www.gismeteo.ru/weather-%s/now/
-Update URL2=https://www.gismeteo.ru/weather-%s/
-Update URL3=https://www.gismeteo.ru/weather-%s/10-days/
-
-;-----------------------------------------------------
-
-[Condition]
-Start=<div class="weathertab is-active" data-tooltip="
-End="
-Unit=Cond
-Url=1
-
-[Update]
-Start=data-pattern="G:i">
-End=</div>
-Url=1
-
-[TempNow]
-Start=<temperature-value value="
-End="
-Url=1
-Hidden=true
-
-[Temperature]
-Set Data=[TempNow] & " °C"
-
-[TempFeel]
-Start=<temperature-value value="
-End="
-Url=1
-Hidden=true
-
-[Feel]
-Set Data=[TempFeel] & " °C"
-
-[Low]
-Start=<temperature-value value="
-End="
-Unit=C
-Url=1
-
-[High]
-Start=<temperature-value value="
-End="
-Unit=C
-Url=1
-
-[WS]
-Start=<speed-value value="
-End="
-;Unit=m/s
-Url=1
-Hidden=true
-
-[Wind speed]
-Set Data=[WS] & " " & "m/s"
-
-;[Visibility]
-;Set Data=[Condition]
-;[/Visibility]
-
-[Ignore]
-Start=<speed-value reactive show-units></speed-value>
-End=>
-Url=1
-
-[Wind direction]
-Start=
-End=</div>
-Url=1
-
-[Pressure]
-Start=<pressure-value value="
-End="
-Unit=mm
-Url=1
-
-[Humidity]
-Start=<div class="item-value">
-End=</div>
-Unit=%
-Url=1
-
-[Geo]
-Start=<div class="item-value">
-End=</div>
-Url=1
-
-[TempWater]
-Start=<temperature-value value="
-End="
-Url=1
-Hidden=true
-
-[TW]
-Set Data=[TempWater] & " °C"
-
-[Day Length]
-Start=<div class="astro-progress">
-End=</div>
-Url=2
-
-[Sunrise]
-Start=<div>
-End=</div>
-Url=2
-
-[Sunset]
-Start=<div>
-End=</div>
-Url=2
-
-[Moon phase]
-Start=<div class="astro-progress">
-End=</div>
-Url=2
-
-[Moonrise]
-Start=<div>
-End=</div>
-Url=2
-
-[Moonset]
-Start=<div>
-End=</div>
-Url=2
-
-; DATE: T - time, D - day, M - month, W - weekday
-
-[FD0DW]
-Start=<div class="day">
-End=</div>
-Url=3
-Hidden=true
-
-[FD0DDM]
-Start=<div class="date">
-End=</div>
-Url=3
-Hidden=true
-
-[FD1DW]
-Start=/tomorrow/"><div class="day">
-End=</div>
-Url=3
-Hidden=true
-
-[FD1DDM]
-Start=<div class="date">
-End=</div>
-Url=3
-Hidden=true
-
-[FD2DW]
-Start=<div class="day">
-End=</div>
-Url=3
-Hidden=true
-
-[FD2DDM]
-Start=<div class="date">
-End=</div>
-Url=3
-Hidden=true
-
-[FD3DW]
-Start=<div class="day">
-End=</div>
-Url=3
-Hidden=true
-
-[FD3DDM]
-Start=<div class="date">
-End=</div>
-Url=3
-Hidden=true
-
-[FD4DW]
-Start=<div class="day">
-End=</div>
-Url=3
-Hidden=true
-
-[FD4DDM]
-Start=<div class="date">
-End=</div>
-Url=3
-Hidden=true
-
-[FD5DW]
-Start=<div class="day">
-End=</div>
-Url=3
-Hidden=true
-
-[FD5DDM]
-Start=<div class="date">
-End=</div>
-Url=3
-Hidden=true
-
-[FD6DW]
-Start=<div class="day">
-End=</div>
-Url=3
-Hidden=true
-
-[FD6DDM]
-Start=<div class="date">
-End=</div>
-Url=3
-Hidden=true
-
-[FD7DW]
-Start=<div class="day">
-End=</div>
-Url=3
-Hidden=true
-
-[FD7DDM]
-Start=<div class="date">
-End=</div>
-Url=3
-Hidden=true
-
-[FD8DW]
-Start=<div class="day">
-End=</div>
-Url=3
-Hidden=true
-
-[FD8DDM]
-Start=<div class="date">
-End=</div>
-Url=3
-Hidden=true
-
-[FD9DW]
-Start=<div class="day">
-End=</div>
-Url=3
-Hidden=true
-
-[FD9DDM]
-Start=<div class="date">
-End=</div>
-Url=3
-Hidden=true
-
-;---------------//////////////////////////
-;------1--------//////////////////////////
-;---------------//////////////////////////
-;---------1-234--------------
-
-[FD0D]
-Set Data=[FD0DW] & " " & [FD0DDM]
-Hidden=true
-
-[FD1D]
-Set Data=[FD1DW] & " " & [FD1DDM]
-Hidden=true
-
-[FD2D]
-Set Data=[FD2DW] & " " & [FD2DDM]
-Hidden=true
-
-[FD3D]
-Set Data=[FD3DW] & " " & [FD3DDM]
-Hidden=true
-
-[FD4D]
-Set Data=[FD4DW] & " " & [FD4DDM]
-Hidden=true
-
-[FD5D]
-Set Data=[FD5DW] & " " & [FD5DDM]
-Hidden=true
-
-[FD6D]
-Set Data=[FD6DW] & " " & [FD6DDM]
-Hidden=true
-
-[FD7D]
-Set Data=[FD7DW] & " " & [FD7DDM]
-Hidden=true
-
-[FD8D]
-Set Data=[FD8DW] & " " & [FD8DDM]
-Hidden=true
-
-[FD9D]
-Set Data=[FD9DW] & " " & [FD9DDM]
-Hidden=true
-
-; CONDITION
-
-[FD0C]
-Start=data-tooltip="
-End="
-Unit=Cond
-Url=3
-Hidden=true
-
-[FD1C]
-Start=data-tooltip="
-End="
-Unit=Cond
-Url=3
-Hidden=true
-
-[FD2C]
-Start=data-tooltip="
-End="
-Unit=Cond
-Url=3
-Hidden=true
-
-[FD3C]
-Start=data-tooltip="
-End="
-Unit=Cond
-Url=3
-Hidden=true
-
-[FD4C]
-Start=data-tooltip="
-End="
-Unit=Cond
-Url=3
-Hidden=true
-
-[FD5C]
-Start=data-tooltip="
-End="
-Unit=Cond
-Url=3
-Hidden=true
-
-[FD6C]
-Start=data-tooltip="
-End="
-Unit=Cond
-Url=3
-Hidden=true
-
-[FD7C]
-Start=data-tooltip="
-End="
-Unit=Cond
-Url=3
-Hidden=true
-
-[FD8C]
-Start=data-tooltip="
-End="
-Unit=Cond
-Url=3
-Hidden=true
-
-[FD9C]
-Start=data-tooltip="
-End="
-Unit=Cond
-Url=3
-Hidden=true
-
-;temperature
-
-[FD0TH]
-Start=<div class="maxt"><temperature-value value="
-End="
-Unit=C
-Url=3
-Hidden=true
-
-[FD0L]
-Start=<temperature-value value="
-End="
-Unit=C
-Url=3
-Hidden=true
-
-[FD1TH]
-Start=<temperature-value value="
-End="
-Unit=C
-Url=3
-Hidden=true
-
-[FD1L]
-Start=<temperature-value value="
-End="
-Unit=C
-Url=3
-Hidden=true
-
-[FD2TH]
-Start=<temperature-value value="
-End="
-Unit=C
-Url=3
-Hidden=true
-
-[FD2L]
-Start=<temperature-value value="
-End="
-Unit=C
-Url=3
-Hidden=true
-
-[FD3TH]
-Start=<temperature-value value="
-End="
-Unit=C
-Url=3
-Hidden=true
-
-[FD3L]
-Start=<temperature-value value="
-End="
-Unit=C
-Url=3
-Hidden=true
-
-[FD4TH]
-Start=<temperature-value value="
-End="
-Unit=C
-Url=3
-Hidden=true
-
-[FD4L]
-Start=<temperature-value value="
-End="
-Unit=C
-Url=3
-Hidden=true
-
-[FD5TH]
-Start=<temperature-value value="
-End="
-Unit=C
-Url=3
-Hidden=true
-
-[FD5L]
-Start=<temperature-value value="
-End="
-Unit=C
-Url=3
-Hidden=true
-
-[FD6TH]
-Start=<temperature-value value="
-End="
-Unit=C
-Url=3
-Hidden=true
-
-[FD6L]
-Start=<temperature-value value="
-End="
-Unit=C
-Url=3
-Hidden=true
-
-[FD7TH]
-Start=<temperature-value value="
-End="
-Unit=C
-Url=3
-Hidden=true
-
-[FD7L]
-Start=<temperature-value value="
-End="
-Unit=C
-Url=3
-Hidden=true
-
-[FD8TH]
-Start=<temperature-value value="
-End="
-Unit=C
-Url=3
-Hidden=true
-
-[FD8L]
-Start=<temperature-value value="
-End="
-Unit=C
-Url=3
-Hidden=true
-
-[FD9TH]
-Start=<temperature-value value="
-End="
-Unit=C
-Url=3
-Hidden=true
-
-[FD9L]
-Start=<temperature-value value="
-End="
-Unit=C
-Url=3
-Hidden=true
-
-; WIND: H - Hidden data D - direction, S - Speed
-
-[FD0WS]
-Start=<speed-value value="
-End="
-Unit=m/s
-Url=3
-Hidden=true
-
-[FD1WS]
-Start=<speed-value value="
-End="
-Unit=m/s
-Url=3
-Hidden=true
-
-[FD2WS]
-Start=<speed-value value="
-End="
-Unit=m/s
-Url=3
-Hidden=true
-
-[FD3WS]
-Start=<speed-value value="
-End="
-Unit=m/s
-Url=3
-Hidden=true
-
-[FD4WS]
-Start=<speed-value value="
-End="
-Unit=m/s
-Url=3
-Hidden=true
-
-[FD5WS]
-Start=<speed-value value="
-End="
-Unit=m/s
-Url=3
-Hidden=true
-
-[FD6WS]
-Start=<speed-value value="
-End="
-Unit=m/s
-Url=3
-Hidden=true
-
-[FD7WS]
-Start=<speed-value value="
-End="
-Unit=m/s
-Url=3
-Hidden=true
-
-[FD8WS]
-Start=<speed-value value="
-End="
-Unit=m/s
-Url=3
-Hidden=true
-
-[FD9WS]
-Start=<speed-value value="
-End="
-Unit=m/s
-Url=3
-Hidden=true
-
-[FD0WD]
-Start=<div class="direction">
-End=</div>
-Url=3
-Hidden=true
-
-[FD1WD]
-Start=<div class="direction">
-End=</div>
-Url=3
-Hidden=true
-
-[FD2WD]
-Start=<div class="direction">
-End=</div>
-Url=3
-Hidden=true
-
-[FD3WD]
-Start=<div class="direction">
-End=</div>
-Url=3
-Hidden=true
-
-[FD4WD]
-Start=<div class="direction">
-End=</div>
-Url=3
-Hidden=true
-
-[FD5WD]
-Start=<div class="direction">
-End=</div>
-Url=3
-Hidden=true
-
-[FD6WD]
-Start=<div class="direction">
-End=</div>
-Url=3
-Hidden=true
-
-[FD7WD]
-Start=<div class="direction">
-End=</div>
-Url=3
-Hidden=true
-
-[FD8WD]
-Start=<div class="direction">
-End=</div>
-Url=3
-Hidden=true
-
-[FD9WD]
-Start=<div class="direction">
-End=</div>
-Url=3
-Hidden=true
-
-[FD0W]
-Set Data=[FD0WD] & " " & [FD0WS]
-Hidden=true
-
-[FD1W]
-Set Data=[FD1WD] & " " & [FD1WS]
-Hidden=true
-
-[FD2W]
-Set Data=[FD2WD] & " " & [FD2WS]
-Hidden=true
-
-[FD3W]
-Set Data=[FD3WD] & " " & [FD3WS]
-Hidden=true
-
-[FD4W]
-Set Data=[FD4WD] & " " & [FD4WS]
-Hidden=true
-
-[FD5W]
-Set Data=[FD5WD] & " " & [FD5WS]
-Hidden=true
-
-[FD6W]
-Set Data=[FD6WD] & " " & [FD6WS]
-Hidden=true
-
-[FD7W]
-Set Data=[FD7WD] & " " & [FD7WS]
-Hidden=true
-
-[FD8W]
-Set Data=[FD8WD] & " " & [FD8WS]
-Hidden=true
-
-[FD9W]
-Set Data=[FD9WD] & " " & [FD9WS]
-Hidden=true
-
-;Precipitation
-
-[Ignore]
-Start=<div class="item-unit
-End=">
-Url=3
-
-[Prec]
-Start=
-End=</div>
-Url=3
-Hidden=true
-
-[Precipitation]
-Set Data=[Prec] & " " & "mm"
-
-[Ignore]
-Start=<div class="item-unit
-End=">
-Url=3
-
-[FD1PR]
-Start=
-End=</div>
-Url=3
-Hidden=true
-
-[Ignore]
-Start=<div class="item-unit
-End=">
-Url=3
-
-[FD2PR]
-Start=
-End=</div>
-Url=3
-Hidden=true
-
-[Ignore]
-Start=<div class="item-unit
-End=">
-Url=3
-
-[FD3PR]
-Start=
-End=</div>
-Url=3
-Hidden=true
-
-[Ignore]
-Start=<div class="item-unit
-End=">
-Url=3
-
-[FD4PR]
-Start=
-End=</div>
-Url=3
-Hidden=true
-
-[Ignore]
-Start=<div class="item-unit
-End=">
-Url=3
-
-[FD5PR]
-Start=
-End=</div>
-Url=3
-Hidden=true
-
-[Ignore]
-Start=<div class="item-unit
-End=">
-Url=3
-
-[FD6PR]
-Start=
-End=</div>
-Url=3
-Hidden=true
-
-[Ignore]
-Start=<div class="item-unit
-End=">
-Url=3
-
-[FD7PR]
-Start=
-End=</div>
-Url=3
-Hidden=true
-
-[Ignore]
-Start=<div class="item-unit
-End=">
-Url=3
-
-[FD8PR]
-Start=
-End=</div>
-Url=3
-Hidden=true
-
-[Ignore]
-Start=<div class="item-unit
-End=">
-Url=3
-
-[FD9PR]
-Start=
-End=</div>
-Url=3
-Hidden=true
-
-; PRESSURE
-[FD0P]
-Start=<div class="maxt"><pressure-value value="
-End="
-Unit=mm
-Url=3
-Hidden=true
-
-[FD1P]
-Start=<div class="maxt"><pressure-value value="
-End="
-Unit=mm
-Url=3
-Hidden=true
-
-[FD2P]
-Start=<div class="maxt"><pressure-value value="
-End="
-Unit=mm
-Url=3
-Hidden=true
-
-[FD3P]
-Start=<div class="maxt"><pressure-value value="
-End="
-Unit=mm
-Url=3
-Hidden=true
-
-[FD4P]
-Start=<div class="maxt"><pressure-value value="
-End="
-Unit=mm
-Url=3
-Hidden=true
-
-[FD5P]
-Start=<div class="maxt"><pressure-value value="
-End="
-Unit=mm
-Url=3
-Hidden=true
-
-[FD6P]
-Start=<div class="maxt"><pressure-value value="
-End="
-Unit=mm
-Url=3
-Hidden=true
-
-[FD7P]
-Start=<div class="maxt"><pressure-value value="
-End="
-Unit=mm
-Url=3
-Hidden=true
-
-[FD8P]
-Start=<div class="maxt"><pressure-value value="
-End="
-Unit=mm
-Url=3
-Hidden=true
-
-[FD9P]
-Start=<div class="maxt"><pressure-value value="
-End="
-Unit=mm
-Url=3
-Hidden=true
-
-; Humidity
-
-[Ignore]
-Start=<div class="row-item
-End=">
-Url=3
-
-[FD0H]
-Start=
-End=</div>
-Unit=%
-Url=3
-Hidden=true
-
-[Ignore]
-Start=<div class="row-item
-End=">
-Url=3
-
-[FD1H]
-Start=
-End=</div>
-Unit=%
-Url=3
-Hidden=true
-
-[Ignore]
-Start=<div class="row-item
-End=">
-Url=3
-
-[FD2H]
-Start=
-End=</div>
-Unit=%
-Url=3
-Hidden=true
-
-[Ignore]
-Start=<div class="row-item
-End=">
-Url=3
-
-[FD3H]
-Start=
-End=</div>
-Unit=%
-Url=3
-Hidden=true
-
-[Ignore]
-Start=<div class="row-item
-End=">
-Url=3
-
-[FD4H]
-Start=
-End=</div>
-Unit=%
-Url=3
-Hidden=true
-
-[Ignore]
-Start=<div class="row-item
-End=">
-Url=3
-
-[FD5H]
-Start=
-End=</div>
-Unit=%
-Url=3
-Hidden=true
-
-[Ignore]
-Start=<div class="row-item
-End=">
-Url=3
-
-[FD6H]
-Start=
-End=</div>
-Unit=%
-Url=3
-Hidden=true
-
-[Ignore]
-Start=<div class="row-item
-End=">
-Url=3
-
-[FD7H]
-Start=
-End=</div>
-Unit=%
-Url=3
-Hidden=true
-
-[Ignore]
-Start=<div class="row-item
-End=">
-Url=3
-
-[FD8H]
-Start=
-End=</div>
-Unit=%
-Url=3
-Hidden=true
-
-[Ignore]
-Start=<div class="row-item
-End=">
-Url=3
-
-[FD9H]
-Start=
-End=</div>
-Unit=%
-Url=3
-Hidden=true
-
-; UV Index
-
-[Ignore]
-Start=<div class="row-item
-End=">
-Url=3
-
-[UV Index]
-Start=
-End=</div>
-Url=3
-
-[Ignore]
-Start=<div class="row-item
-End=">
-Url=3
-
-[FD1UV]
-Start=
-End=</div>
-Url=3
-Hidden=true
-
-[Ignore]
-Start=<div class="row-item
-End=">
-Url=3
-
-[FD2UV]
-Start=
-End=</div>
-Url=3
-Hidden=true
-
-[Ignore]
-Start=<div class="row-item
-End=">
-Url=3
-
-[FD3UV]
-Start=
-End=</div>
-Url=3
-Hidden=true
-
-[Ignore]
-Start=<div class="row-item
-End=">
-Url=3
-
-[FD4UV]
-Start=
-End=</div>
-Url=3
-Hidden=true
-
-[Ignore]
-Start=<div class="row-item
-End=">
-Url=3
-
-[FD5UV]
-Start=
-End=</div>
-Url=3
-Hidden=true
-
-[Ignore]
-Start=<div class="row-item
-End=">
-Url=3
-
-[FD6UV]
-Start=
-End=</div>
-Url=3
-Hidden=true
-
-[Ignore]
-Start=<div class="row-item
-End=">
-Url=3
-
-[FD7UV]
-Start=
-End=</div>
-Url=3
-Hidden=true
-
-[Ignore]
-Start=<div class="row-item
-End=">
-Url=3
-
-[FD8UV]
-Start=
-End=</div>
-Url=3
-Hidden=true
-
-[Ignore]
-Start=<div class="row-item
-End=">
-Url=3
-
-[FD9UV]
-Start=
-End=</div>
-Url=3
-Hidden=true
-
-; Geo Magnetism
-
-[Ignore]
-Start=<div class="row-item
-End=">
-Url=3
-
-[FD0GM]
-Start=
-End=</div>
-Url=3
-
-[Ignore]
-Start=<div class="row-item
-End=">
-Url=3
-
-[FD1GM]
-Start=
-End=</div>
-Url=3
-Hidden=true
-
-[Ignore]
-Start=<div class="row-item
-End=">
-Url=3
-
-[FD2GM]
-Start=
-End=</div>
-Url=3
-Hidden=true
-
-[Ignore]
-Start=<div class="row-item
-End=">
-Url=3
-
-[FD3GM]
-Start=
-End=</div>
-Url=3
-Hidden=true
-
-[Ignore]
-Start=<div class="row-item
-End=">
-Url=3
-
-[FD4GM]
-Start=
-End=</div>
-Url=3
-Hidden=true
-
-[Ignore]
-Start=<div class="row-item
-End=">
-Url=3
-
-[FD5GM]
-Start=
-End=</div>
-Url=3
-Hidden=true
-
-[Ignore]
-Start=<div class="row-item
-End=">
-Url=3
-
-[FD6GM]
-Start=
-End=</div>
-Url=3
-Hidden=true
-
-[Ignore]
-Start=<div class="row-item
-End=">
-Url=3
-
-[FD7GM]
-Start=
-End=</div>
-Url=3
-Hidden=true
-
-[Ignore]
-Start=<div class="row-item
-End=">
-Url=3
-
-[FD8GM]
-Start=
-End=</div>
-Url=3
-Hidden=true
-
-[Ignore]
-Start=<div class="row-item
-End=">
-Url=3
-
-[FD9GM]
-Start=
-End=</div>
-Url=3
-Hidden=true
-
-;================================================
-;====================3===========================
-;================================================
-
-[Forecast Day 0]
-Set Data=[FD0D] & ": (" & [FD0TH] & "/" & [FD0L] & ")" & ", " & [FD0C] & ", " & "Precipitation" & ": " & [Prec] & " " & "mm" & ", \n" & "Wind" & ": " & [FD0W] & ", " & "Pressure" & ": " & [FD0P] & ", " & "Humidity" & ": " & [FD0H] & ", " & "UV Index" & ": " & [UV Index] & ", " & "G/M" & ": " & [FD0GM]
-
-[Forecast Day 1]
-Set Data=[FD1D] & ": (" & [FD1TH] & "/" & [FD1L] & ")" & ", " & [FD1C] & ", " & "Precipitation" & ": " & [FD1PR] & " " & "mm" & ", \n" & "Wind" & ": " & [FD1W] & ", " & "Pressure" & ": " & [FD1P] & ", " & "Humidity" & ": " & [FD1H] & ", " & "UV Index" & ": " & [FD1UV] & ", " & "G/M" & ": " & [FD1GM]
-
-[Forecast Day 2]
-Set Data=[FD2D] & ": (" & [FD2TH] & "/" & [FD2L] & ")" & ", " & [FD2C] & ", " & "Precipitation" & ": " & [FD2PR] & " " & "mm" & ", \n" & "Wind" & ": " & [FD2W] & ", " & "Pressure" & ": " & [FD2P] & ", " & "Humidity" & ": " & [FD2H] & ", " & "UV Index" & ": " & [FD2UV] & ", " & "G/M" & ": " & [FD2GM]
-
-[Forecast Day 3]
-Set Data=[FD3D] & ": (" & [FD3TH] & "/" & [FD3L] & ")" & ", " & [FD3C] & ", " & "Precipitation" & ": " & [FD3PR] & " " & "mm" & ", \n" & "Wind" & ": " & [FD3W] & ", " & "Pressure" & ": " & [FD3P] & ", " & "Humidity" & ": " & [FD3H] & ", " & "UV Index" & ": " & [FD3UV] & ", " & "G/M" & ": " & [FD3GM]
-
-[Forecast Day 4]
-Set Data=[FD4D] & ": (" & [FD4TH] & "/" & [FD4L] & ")" & ", " & [FD4C] & ", " & "Precipitation" & ": " & [FD4PR] & " " & "mm" & ", \n" & "Wind" & ": " & [FD4W] & ", " & "Pressure" & ": " & [FD4P] & ", " & "Humidity" & ": " & [FD4H] & ", " & "UV Index" & ": " & [FD4UV] & ", " & "G/M" & ": " & [FD4GM]
-
-[Forecast Day 5]
-Set Data=[FD5D] & ": (" & [FD5TH] & "/" & [FD5L] & ")" & ", " & [FD5C] & ", " & "Precipitation" & ": " & [FD5PR] & " " & "mm" & ", \n" & "Wind" & ": " & [FD5W] & ", " & "Pressure" & ": " & [FD5P] & ", " & "Humidity" & ": " & [FD5H] & ", " & "UV Index" & ": " & [FD5UV] & ", " & "G/M" & ": " & [FD5GM]
-
-[Forecast Day 6]
-Set Data=[FD6D] & ": (" & [FD6TH] & "/" & [FD6L] & ")" & ", " & [FD6C] & ", " & "Precipitation" & ": " & [FD6PR] & " " & "mm" & ", \n" & "Wind" & ": " & [FD6W] & ", " & "Pressure" & ": " & [FD6P] & ", " & "Humidity" & ": " & [FD6H] & ", " & "UV Index" & ": " & [FD6UV] & ", " & "G/M" & ": " & [FD6GM]
-
-[Forecast Day 7]
-Set Data=[FD7D] & ": (" & [FD7TH] & "/" & [FD7L] & ")" & ", " & [FD7C] & ", " & "Precipitation" & ": " & [FD7PR] & " " & "mm" & ", \n" & "Wind" & ": " & [FD7W] & ", " & "Pressure" & ": " & [FD7P] & ", " & "Humidity" & ": " & [FD7H] & ", " & "UV Index" & ": " & [FD7UV] & ", " & "G/M" & ": " & [FD7GM]
-
-[Forecast Day 8]
-Set Data=[FD8D] & ": (" & [FD8TH] & "/" & [FD8L] & ")" & ", " & [FD8C] & ", " & "Precipitation" & ": " & [FD8PR] & " " & "mm" & ", \n" & "Wind" & ": " & [FD8W] & ", " & "Pressure" & ": " & [FD8P] & ", " & "Humidity" & ": " & [FD8H] & ", " & "UV Index" & ": " & [FD8UV] & ", " & "G/M" & ": " & [FD8GM]
-
-[Forecast Day 9]
-Set Data=[FD9D] & ": (" & [FD9TH] & "/" & [FD9L] & ")" & ", " & [FD9C] & ", " & "Precipitation" & ": " & [FD9PR] & " " & "mm" & ", \n" & "Wind" & ": " & [FD9W] & ", " & "Pressure" & ": " & [FD9P] & ", " & "Humidity" & ": " & [FD9H] & ", " & "UV Index" & ": " & [FD9UV] & ", " & "G/M" & ": " & [FD9GM]
-
-;--------------------------------------------
-
-[Icons]
-Sunny=ясно
-Sunny=штиль
-Partly Cloudy=малооблачно
-Cloudy=облачно
-Cloudy=пасмурно
-Rain=небольшой дождь
-Rain Shower=дождь
-Rain Shower=ливень
-Snow=снег
-Snow=небольшой снег
-Snow=слабый снег хлопьями
-Snow Shower=снегопад
-Snow Shower=шквал
-Lightning=гроза
-Fog=туман
-
-[ID Search]
-Available=TRUE
-Search URL=https://www.gismeteo.ru/search/%s/
-Not Found Str=Not Found
-Name Start=
-Name End=
-
-[Name Search]
-Single Result=false
-Multiple Result=true
-Search URL=https://www.gismeteo.ru/search/%s/
-Not Found Str=Not found
-
-Mult First=ID
-Mult ID Start=<a href="/weather-
-Mult ID End=/"
-Mult Name Start=</i>
-Mult Name End=</a>
\ No newline at end of file diff --git a/protocols/Weather/docs/weather/msn.ini b/protocols/Weather/docs/weather/msn.ini deleted file mode 100644 index 7075c4c9b8..0000000000 --- a/protocols/Weather/docs/weather/msn.ini +++ /dev/null @@ -1,1057 +0,0 @@ -[Weather 0.3.x Update Data 1.5] -[Header] -Name=MSN Weather (New Layout) -Internal Name=msn2021 -Description=Get Weather from www.msn.com/en-us/weather -Author=HostedDinner updated by pranza -Version=2021-04-21 -Utf8=true - -;Id of the station is lat,long as for example New York: "40.78,-73.83" - -[Default] -Default URL=https://www.msn.com/en-us/weather/today/x/we-city?q=%s -Default Map=https://www.msn.com/en-us/weather/maps/x/we-city?q=%s -Update URL=https://www.msn.com/en-us/weather/today/x/we-city?q=%s&weadegreetype=C -UserAgent=Mozilla/5.0 (Windows NT 6.3; WOW64; rv:33.0) Gecko/20100101 Firefox/33.0 - -[Update] -Start=xdmap: -End=; -Url=1 - -;current Weather -[Ignore] -Start=<div class="current-info"> -End="> - -[Temperature] -Start= -End=</span> -Unit=C -Url=1 - -[Condition] -Start=<span> -End=</span> -Url=1 -Unit=Cond - -[Feel] -Start=Feels Like</span> -End=° -Unit=C -Url=1 - -[Wind direction] -Start=title=" -End=" -Url=1 - -[Wind speed] -Start=</div> -End=km/h -Url=1 -Unit=km/h - -[Pressure] -Start=<span>Barometer</span> -End=</li> -Url=1 -Unit=mb - -[Visibility] -Start=<span>Visibility</span> -End=km -Url=1 -Unit=km - -[Humidity] -Start=<span>Humidity</span> -End=% -Url=1 -Unit=% - -[Dew point] -Start=<span>Dew Point</span> -End=° -Url=1 -unit=C - -;First entry is still today -[Sunrise] -Start="sunrise":" -End=" -Url=1 - -[Sunset] -Start="sunset":" -End=" -Url=1 - -[Moonrise] -Start="moonrise":" -End=" -Url=1 - -[Moonset] -Start="moonset":" -End=" -Url=1 - -[Moon phase] -Start="moon":" -End=" -Url=1 - -[UV Index] -Start="uvindex":" -End=" -Url=1 - -[Ignore] -Start=class="precipicn -End=> -Url=1 - -[Precipitation] -Start=> -End=%</span> -Url=1 -Unit=% - -[High] -Start=<p> -End=° -Url=1 -Unit=C - -[Low] -Start=<p class="transparent"> -End=° -Url=1 -Unit=C - -;Forecast - -;[Forecast Day 1 Sunrise] -;Start="sunrise":" -;End=" -;Url=1 -;Hidden=true - -;[Forecast Day 1 Sunset] -;Start="sunset":" -;End=" -;Url=1 -;Hidden=true - -;[Forecast Day 1 Moonrise] -;Start="moonrise":" -;End=" -;Url=1 -;Hidden=true - -;[Forecast Day 1 Moonset] -;Start="moonset":" -;End=" -;Url=1 -;Hidden=true - -;[Forecast Day 1 Moonphase] -;Start="moon":" -;End=" -;Url=1 -;Hidden=true - -[Forecast Day 1 Humidity] -Start="humidity":" -End=%" -Url=1 -Unit=% -Hidden=true - -[Forecast Day 1 UV Index] -Start="uvindex":" -End=" -Url=1 -Hidden=true - -;[Ignore] -;Start=class="dt" -;End=> -;Url=1 - -[Forecast Day 1 WeekDay] -Start=<span> -End=</span> -Url=1 -Unit=Day -Hidden=true - -[Forecast Day 1 Day] -Start=<span> -End=</span> -Url=1 -Hidden=true - -[Forecast Day 1 Condition] -Start=title=" -End=" -Url=1 -Unit=Cond -Hidden=true - -[Ignore] -Start=class="precipicn -End=> -Url=1 - -[Forecast Day 1 Precipitation] -Start=> -End=%</span> -Url=1 -Unit=% -Hidden=true - -[Forecast Day 1 High] -Start=<p> -End=° -Url=1 -Unit=C -Hidden=true - -[Forecast Day 1 Low] -Start=<p class="transparent"> -End=° -Url=1 -Unit=C -Hidden=true - -;[Forecast Day 2 Sunrise] -;Start="sunrise":" -;End=" -;Url=1 -;Hidden=true - -;[Forecast Day 2 Sunset] -;Start="sunset":" -;End=" -;Url=1 -;Hidden=true - -;[Forecast Day 2 Moonrise] -;Start="moonrise":" -;End=" -;Url=1 -;Hidden=true - -;[Forecast Day 2 Moonset] -;Start="moonset":" -;End=" -;Url=1 -;Hidden=true - -;[Forecast Day 2 Moonphase] -;Start="moon":" -;End=" -;Url=1 -;Hidden=true - -[Forecast Day 2 Humidity] -Start="humidity":" -End=%" -Url=1 -Unit=% -Hidden=true - -[Forecast Day 2 UV Index] -Start="uvindex":" -End=" -Url=1 -Hidden=true - -;[Ignore] -;Start=class="dt" -;End=> -;Url=1 - -[Forecast Day 2 WeekDay] -Start=<span> -End=</span> -Url=1 -Unit=Day -Hidden=true - -[Forecast Day 2 Day] -Start=<span> -End=</span> -Url=1 -Hidden=true - -[Forecast Day 2 Condition] -Start=title=" -End=" -Url=1 -Unit=Cond -Hidden=true - -[Ignore] -Start=class="precipicn -End=> -Url=1 - -[Forecast Day 2 Precipitation] -Start=> -End=%</span> -Url=1 -Unit=% -Hidden=true - -[Forecast Day 2 High] -Start=<p> -End=° -Url=1 -Unit=C -Hidden=true - -[Forecast Day 2 Low] -Start=<p class="transparent"> -End=° -Url=1 -Unit=C -Hidden=true - -;[Forecast Day 3 Sunrise] -;Start="sunrise":" -;End=" -;Url=1 -;Hidden=true - -;[Forecast Day 3 Sunset] -;Start="sunset":" -;End=" -;Url=1 -;Hidden=true - -;[Forecast Day 3 Moonrise] -;Start="moonrise":" -;End=" -;Url=1 -;Hidden=true - -;[Forecast Day 3 Moonset] -;Start="moonset":" -;End=" -;Url=1 -;Hidden=true - -;[Forecast Day 3 Moonphase] -;Start="moon":" -;End=" -;Url=1 -;Hidden=true - -[Forecast Day 3 Humidity] -Start="humidity":" -End=%" -Url=1 -Unit=% -Hidden=true - -[Forecast Day 3 UV Index] -Start="uvindex":" -End=" -Url=1 -Hidden=true - -;[Ignore] -;Start=class="dt" -;End=> -;Url=1 - -[Forecast Day 3 WeekDay] -Start=<span> -End=</span> -Url=1 -Unit=Day -Hidden=true - -[Forecast Day 3 Day] -Start=<span> -End=</span> -Url=1 -Hidden=true - -[Forecast Day 3 Condition] -Start=title=" -End=" -Url=1 -Unit=Cond -Hidden=true - -[Ignore] -Start=class="precipicn -End=> -Url=1 - -[Forecast Day 3 Precipitation] -Start=> -End=%</span> -Url=1 -Unit=% -Hidden=true - -[Forecast Day 3 High] -Start=<p> -End=° -Url=1 -Unit=C -Hidden=true - -[Forecast Day 3 Low] -Start=<p class="transparent"> -End=° -Url=1 -Unit=C -Hidden=true - -;[Forecast Day 4 Sunrise] -;Start="sunrise":" -;End=" -;Url=1 -;Hidden=true - -;[Forecast Day 4 Sunset] -;Start="sunset":" -;End=" -;Url=1 -;Hidden=true - -;[Forecast Day 4 Moonrise] -;Start="moonrise":" -;End=" -;Url=1 -;Hidden=true - -;[Forecast Day 4 Moonset] -;Start="moonset":" -;End=" -;Url=1 -;Hidden=true - -;[Forecast Day 4 Moonphase] -;Start="moon":" -;End=" -;Url=1 -;Hidden=true - -[Forecast Day 4 Humidity] -Start="humidity":" -End=%" -Url=1 -Unit=% -Hidden=true - -[Forecast Day 4 UV Index] -Start="uvindex":" -End=" -Url=1 -Hidden=true - -;[Ignore] -;Start=class="dt" -;End=> -;Url=1 - -[Forecast Day 4 WeekDay] -Start=<span> -End=</span> -Url=1 -Unit=Day -Hidden=true - -[Forecast Day 4 Day] -Start=<span> -End=</span> -Url=1 -Hidden=true - -[Forecast Day 4 Condition] -Start=title=" -End=" -Url=1 -Unit=Cond -Hidden=true - -[Ignore] -Start=class="precipicn -End=> -Url=1 - -[Forecast Day 4 Precipitation] -Start=> -End=%</span> -Url=1 -Unit=% -Hidden=true - -[Forecast Day 4 High] -Start=<p> -End=° -Url=1 -Unit=C -Hidden=true - -[Forecast Day 4 Low] -Start=<p class="transparent"> -End=° -Url=1 -Unit=C -Hidden=true - -;[Forecast Day 5 Sunrise] -;Start="sunrise":" -;End=" -;Url=1 -;Hidden=true - -;[Forecast Day 5 Sunset] -;Start="sunset":" -;End=" -;Url=1 -;Hidden=true - -;[Forecast Day 5 Moonrise] -;Start="moonrise":" -;End=" -;Url=1 -;Hidden=true - -;[Forecast Day 5 Moonset] -;Start="moonset":" -;End=" -;Url=1 -;Hidden=true - -;[Forecast Day 5 Moonphase] -;Start="moon":" -;End=" -;Url=1 -;Hidden=true - -[Forecast Day 5 Humidity] -Start="humidity":" -End=%" -Url=1 -Unit=% -Hidden=true - -[Forecast Day 5 UV Index] -Start="uvindex":" -End=" -Url=1 -Hidden=true - -;[Ignore] -;Start=class="dt" -;End=> -;Url=1 - -[Forecast Day 5 WeekDay] -Start=<span> -End=</span> -Url=1 -Unit=Day -Hidden=true - -[Forecast Day 5 Day] -Start=<span> -End=</span> -Url=1 -Hidden=true - -[Forecast Day 5 Condition] -Start=title=" -End=" -Url=1 -Unit=Cond -Hidden=true - -[Ignore] -Start=class="precipicn -End=> -Url=1 - -[Forecast Day 5 Precipitation] -Start=> -End=%</span> -Url=1 -Unit=% -Hidden=true - -[Forecast Day 5 High] -Start=<p> -End=° -Url=1 -Unit=C -Hidden=true - -[Forecast Day 5 Low] -Start=<p class="transparent"> -End=° -Url=1 -Unit=C -Hidden=true - -;[Forecast Day 6 Sunrise] -;Start="sunrise":" -;End=" -;Url=1 -;Hidden=true - -;[Forecast Day 6 Sunset] -;Start="sunset":" -;End=" -;Url=1 -;Hidden=true - -;[Forecast Day 6 Moonrise] -;Start="moonrise":" -;End=" -;Url=1 -;Hidden=true - -;[Forecast Day 6 Moonset] -;Start="moonset":" -;End=" -;Url=1 -;Hidden=true - -;[Forecast Day 6 Moonphase] -;Start="moon":" -;End=" -;Url=1 -;Hidden=true - -[Forecast Day 6 Humidity] -Start="humidity":" -End=%" -Url=1 -Unit=% -Hidden=true - -[Forecast Day 6 UV Index] -Start="uvindex":" -End=" -Url=1 -Hidden=true - -;[Ignore] -;Start=class="dt" -;End=> -;Url=1 - -[Forecast Day 6 WeekDay] -Start=<span> -End=</span> -Url=1 -Unit=Day -Hidden=true - -[Forecast Day 6 Day] -Start=<span> -End=</span> -Url=1 -Hidden=true - -[Forecast Day 6 Condition] -Start=title=" -End=" -Url=1 -Unit=Cond -Hidden=true - -[Ignore] -Start=class="precipicn -End=> -Url=1 - -[Forecast Day 6 Precipitation] -Start=> -End=%</span> -Url=1 -Unit=% -Hidden=true - -[Forecast Day 6 High] -Start=<p> -End=° -Url=1 -Unit=C -Hidden=true - -[Forecast Day 6 Low] -Start=<p class="transparent"> -End=° -Url=1 -Unit=C -Hidden=true - -;[Forecast Day 7 Sunrise] -;Start="sunrise":" -;End=" -;Url=1 -;Hidden=true - -;[Forecast Day 7 Sunset] -;Start="sunset":" -;End=" -;Url=1 -;Hidden=true - -;[Forecast Day 7 Moonrise] -;Start="moonrise":" -;End=" -;Url=1 -;Hidden=true - -;[Forecast Day 7 Moonset] -;Start="moonset":" -;End=" -;Url=1 -;Hidden=true - -;[Forecast Day 7 Moonphase] -;Start="moon":" -;End=" -;Url=1 -;Hidden=true - -[Forecast Day 7 Humidity] -Start="humidity":" -End=%" -Url=1 -Unit=% -Hidden=true - -[Forecast Day 7 UV Index] -Start="uvindex":" -End=" -Url=1 -Hidden=true - -;[Ignore] -;Start=class="dt" -;End=> -;Url=1 - -[Forecast Day 7 WeekDay] -Start=<span> -End=</span> -Url=1 -Unit=Day -Hidden=true - -[Forecast Day 7 Day] -Start=<span> -End=</span> -Url=1 -Hidden=true - -[Forecast Day 7 Condition] -Start=title=" -End=" -Url=1 -Unit=Cond -Hidden=true - -[Ignore] -Start=class="precipicn -End=> -Url=1 - -[Forecast Day 7 Precipitation] -Start=> -End=%</span> -Url=1 -Unit=% -Hidden=true - -[Forecast Day 7 High] -Start=<p> -End=° -Url=1 -Unit=C -Hidden=true - -[Forecast Day 7 Low] -Start=<p class="transparent"> -End=° -Url=1 -Unit=C -Hidden=true - -;[Forecast Day 8 Sunrise] -;Start="sunrise":" -;End=" -;Url=1 -;Hidden=true - -;[Forecast Day 8 Sunset] -;Start="sunset":" -;End=" -;Url=1 -;Hidden=true - -;[Forecast Day 8 Moonrise] -;Start="moonrise":" -;End=" -;Url=1 -;Hidden=true - -;[Forecast Day 8 Moonset] -;Start="moonset":" -;End=" -;Url=1 -;Hidden=true - -;[Forecast Day 8 Moonphase] -;Start="moon":" -;End=" -;Url=1 -;Hidden=true - -[Forecast Day 8 Humidity] -Start="humidity":" -End=%" -Url=1 -Unit=% -Hidden=true - -[Forecast Day 8 UV Index] -Start="uvindex":" -End=" -Url=1 -Hidden=true - -;[Ignore] -;Start=class="dt" -;End=> -;Url=1 - -[Forecast Day 8 WeekDay] -Start=<span> -End=</span> -Url=1 -Unit=Day -Hidden=true - -[Forecast Day 8 Day] -Start=<span> -End=</span> -Url=1 -Hidden=true - -[Forecast Day 8 Condition] -Start=title=" -End=" -Url=1 -Unit=Cond -Hidden=true - -[Ignore] -Start=class="precipicn -End=> -Url=1 - -[Forecast Day 8 Precipitation] -Start=> -End=%</span> -Url=1 -Unit=% -Hidden=true - -[Forecast Day 8 High] -Start=<p> -End=° -Url=1 -Unit=C -Hidden=true - -[Forecast Day 8 Low] -Start=<p class="transparent"> -End=° -Url=1 -Unit=C -Hidden=true - -;[Forecast Day 9 Sunrise] -;Start="sunrise":" -;End=" -;Url=1 -;Hidden=true - -;[Forecast Day 9 Sunset] -;Start="sunset":" -;End=" -;Url=1 -;Hidden=true - -;[Forecast Day 9 Moonrise] -;Start="moonrise":" -;End=" -;Url=1 -;Hidden=true - -;[Forecast Day 9 Moonset] -;Start="moonset":" -;End=" -;Url=1 -;Hidden=true - -;[Forecast Day 9 Moonphase] -;Start="moon":" -;End=" -;Url=1 -;Hidden=true - -[Forecast Day 9 Humidity] -Start="humidity":" -End=%" -Url=1 -Unit=% -Hidden=true - -[Forecast Day 9 UV Index] -Start="uvindex":" -End=" -Url=1 -Hidden=true - -;[Ignore] -;Start=class="dt" -;End=> -;Url=1 - -[Forecast Day 9 WeekDay] -Start=<span> -End=</span> -Url=1 -Unit=Day -Hidden=true - -[Forecast Day 9 Day] -Start=<span> -End=</span> -Url=1 -Hidden=true - -[Forecast Day 9 Condition] -Start=title=" -End=" -Url=1 -Unit=Cond -Hidden=true - -[Ignore] -Start=class="precipicn -End=> -Url=1 - -[Forecast Day 9 Precipitation] -Start=> -End=%</span> -Url=1 -Unit=% -Hidden=true - -[Forecast Day 9 High] -Start=<p> -End=° -Url=1 -Unit=C -Hidden=true - -[Forecast Day 9 Low] -Start=<p class="transparent"> -End=° -Url=1 -Unit=C -Hidden=true - - - - - - - -[Forecast Day 1] -Set Data=[Forecast Day 1 WeekDay] & ", " & [Forecast Day 1 Day] & ": " & [Forecast Day 1 Condition] & " (" & [Forecast Day 1 Low] & "/" & [Forecast Day 1 High] & "), " & [Forecast Day 1 Precipitation] & " " & "Rain" & ", " & "UV" & ": " & [Forecast Day 1 UV Index] & ", " & "Humidity" & ": " & [Forecast Day 1 Humidity] - -[Forecast Day 2] -Set Data=[Forecast Day 2 WeekDay] & ", " & [Forecast Day 2 Day] & ": " & [Forecast Day 2 Condition] & " (" & [Forecast Day 2 Low] & "/" & [Forecast Day 2 High] & "), " & [Forecast Day 2 Precipitation] & " " & "Rain" & ", " & "UV" & ": " & [Forecast Day 2 UV Index] & ", " & "Humidity" & ": " & [Forecast Day 2 Humidity] - -[Forecast Day 3] -Set Data=[Forecast Day 3 WeekDay] & ", " & [Forecast Day 3 Day] & ": " & [Forecast Day 3 Condition] & " (" & [Forecast Day 3 Low] & "/" & [Forecast Day 3 High] & "), " & [Forecast Day 3 Precipitation] & " " & "Rain" & ", " & "UV" & ": " & [Forecast Day 3 UV Index] & ", " & "Humidity" & ": " & [Forecast Day 3 Humidity] - -[Forecast Day 4] -Set Data=[Forecast Day 4 WeekDay] & ", " & [Forecast Day 4 Day] & ": " & [Forecast Day 4 Condition] & " (" & [Forecast Day 4 Low] & "/" & [Forecast Day 4 High] & "), " & [Forecast Day 4 Precipitation] & " " & "Rain" & ", " & "UV" & ": " & [Forecast Day 4 UV Index] & ", " & "Humidity" & ": " & [Forecast Day 4 Humidity] - -[Forecast Day 5] -Set Data=[Forecast Day 5 WeekDay] & ", " & [Forecast Day 5 Day] & ": " & [Forecast Day 5 Condition] & " (" & [Forecast Day 5 Low] & "/" & [Forecast Day 5 High] & "), " & [Forecast Day 5 Precipitation] & " " & "Rain" & ", " & "UV" & ": " & [Forecast Day 5 UV Index] & ", " & "Humidity" & ": " & [Forecast Day 5 Humidity] - -[Forecast Day 6] -Set Data=[Forecast Day 6 WeekDay] & ", " & [Forecast Day 6 Day] & ": " & [Forecast Day 6 Condition] & " (" & [Forecast Day 6 Low] & "/" & [Forecast Day 6 High] & "), " & [Forecast Day 6 Precipitation] & " " & "Rain" & ", " & "UV" & ": " & [Forecast Day 6 UV Index] & ", " & "Humidity" & ": " & [Forecast Day 6 Humidity] - -[Forecast Day 7] -Set Data=[Forecast Day 7 WeekDay] & ", " & [Forecast Day 7 Day] & ": " & [Forecast Day 7 Condition] & " (" & [Forecast Day 7 Low] & "/" & [Forecast Day 7 High] & "), " & [Forecast Day 7 Precipitation] & " " & "Rain" & ", " & "UV" & ": " & [Forecast Day 7 UV Index] & ", " & "Humidity" & ": " & [Forecast Day 7 Humidity] - -[Forecast Day 8] -Set Data=[Forecast Day 8 WeekDay] & ", " & [Forecast Day 8 Day] & ": " & [Forecast Day 8 Condition] & " (" & [Forecast Day 8 Low] & "/" & [Forecast Day 8 High] & "), " & [Forecast Day 8 Precipitation] & " " & "Rain" & ", " & "UV" & ": " & [Forecast Day 8 UV Index] & ", " & "Humidity" & ": " & [Forecast Day 8 Humidity] - -[Forecast Day 9] -Set Data=[Forecast Day 9 WeekDay] & ", " & [Forecast Day 9 Day] & ": " & [Forecast Day 9 Condition] & " (" & [Forecast Day 9 Low] & "/" & [Forecast Day 9 High] & "), " & [Forecast Day 9 Precipitation] & " " & "Rain" & ", " & "UV" & ": " & [Forecast Day 9 UV Index] & ", " & "Humidity" & ": " & [Forecast Day 9 Humidity] - - - -[ID Search] -Available=false - -[Name Search] -Single Result=false -Multiple Result=false - -;It's impossible to parse that... -;the id is the lat/long of the town seperated with comma... -;Search URL=http://api.bing.com/qsonhs.aspx?ds=w8weather&mkt=en-us&q=%s - -[Icons] -;Sunny=Sunny -Sunny=Clear -Sunny=Fair -Sunny=Sunny (Clear) - -;Partly Cloudy=Partly Cloudy -Partly Cloudy=Mostly Cloudy - -;Cloudy=Cloudy - -;Rain=Rain - -;Rain Shower=Rain Shower -Rain Shower=Sprinkles -;To fix this one: -Rain Shower=Sleet - -;Snow=Snow - -;Snow Shower=Snow Shower - -;Ligntning=Ligntning -Ligntning=T-storms -Ligntning=Scattered Thunderstorms -Ligntning=Isolated Thunderstorms - -;Fog=Fog - diff --git a/protocols/Weather/res/resource.rc b/protocols/Weather/res/resource.rc index 34e5f32c83..8c6e6227d8 100644 --- a/protocols/Weather/res/resource.rc +++ b/protocols/Weather/res/resource.rc @@ -43,40 +43,36 @@ STYLE DS_SETFONT | DS_FIXEDSYS | WS_CHILD EXSTYLE WS_EX_CONTROLPARENT FONT 8, "MS Shell Dlg", 0, 0, 0x1 BEGIN - GROUPBOX "Options",IDC_STATIC,3,0,299,70,WS_GROUP - CONTROL "Update weather information on startup",IDC_STARTUPUPD, - "Button",BS_AUTOCHECKBOX | WS_TABSTOP,8,12,286,8 - CONTROL "Update weather information every",IDC_UPDATE,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,8,23,206,8 - EDITTEXT IDC_UPDATETIME,223,21,33,12,ES_AUTOHSCROLL | ES_NUMBER | NOT WS_BORDER,WS_EX_CLIENTEDGE | WS_EX_STATICEDGE - LTEXT "minutes",IDC_STATIC,260,23,39,8 + GROUPBOX "Options",IDC_STATIC,3,0,299,69,WS_GROUP + CONTROL "Update weather information every",IDC_UPDATE,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,8,13,206,8 + EDITTEXT IDC_UPDATETIME,223,11,33,12,ES_AUTOHSCROLL | ES_NUMBER | NOT WS_BORDER,WS_EX_CLIENTEDGE | WS_EX_STATICEDGE + LTEXT "minutes",IDC_STATIC,260,13,39,8 CONTROL "Consider weather info updated only when condition and temperature are changed",IDC_UPDCONDCHG, - "Button",BS_AUTOCHECKBOX | WS_TABSTOP,8,34,286,8 - CONTROL "Remove old data when updating",IDC_REMOVEOLD,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,8,45,286,8 + "Button",BS_AUTOCHECKBOX | WS_TABSTOP,8,27,286,8 + CONTROL "Remove old data when updating",IDC_REMOVEOLD,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,8,41,286,8 CONTROL "Make the contact italic when weather alert is issued",IDC_MAKEI, - "Button",BS_AUTOCHECKBOX | WS_TABSTOP,8,56,286,8 - GROUPBOX "Modes",IDC_STATIC,3,70,300,37 - CONTROL "Use weather condition as protocol status",IDC_PROTOCOND, - "Button",BS_AUTOCHECKBOX | WS_TABSTOP,8,81,278,8 - CONTROL "Avatar only mode",IDC_DISCONDICON,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,8,91,278,8 - GROUPBOX "Units",IDC_STATIC,3,107,299,80,WS_GROUP - LTEXT "Temperature",IDC_STATIC,8,116,53,8 - CONTROL "Celsius",IDC_T1,"Button",BS_AUTORADIOBUTTON,65,116,40,8 - CONTROL "Fahrenheit",IDC_T2,"Button",BS_AUTORADIOBUTTON,120,116,47,8 - RTEXT "Degree sign:",IDC_STATIC,194,116,85,8 - EDITTEXT IDC_DEGREE,283,116,13,12,ES_AUTOHSCROLL | NOT WS_BORDER,WS_EX_CLIENTEDGE | WS_EX_STATICEDGE - LTEXT "Wind",IDC_STATIC,8,125,53,8 - CONTROL "km/h",IDC_W1,"Button",BS_AUTORADIOBUTTON,65,125,34,8 - CONTROL "m/s",IDC_W2,"Button",BS_AUTORADIOBUTTON,120,125,34,8 - CONTROL "mph",IDC_W3,"Button",BS_AUTORADIOBUTTON,176,125,34,8 - CONTROL "knots",IDC_W4,"Button",BS_AUTORADIOBUTTON,232,125,49,8 - LTEXT "Visibility",IDC_STATIC,8,134,53,8 - CONTROL "km",IDC_V1,"Button",BS_AUTORADIOBUTTON,65,134,34,8 - CONTROL "miles",IDC_V2,"Button",BS_AUTORADIOBUTTON,120,134,34,8 - LTEXT "Pressure",IDC_STATIC,8,143,53,8 - CONTROL "kPa",IDC_P1,"Button",BS_AUTORADIOBUTTON,65,143,38,8 - CONTROL "mb (hPa)",IDC_P2,"Button",BS_AUTORADIOBUTTON,120,143,56,8 - CONTROL "inches",IDC_P3,"Button",BS_AUTORADIOBUTTON,176,143,38,8 - CONTROL "mm Hg (torr)",IDC_P4,"Button",BS_AUTORADIOBUTTON,232,143,62,8 + "Button",BS_AUTOCHECKBOX | WS_TABSTOP,8,55,286,8 + GROUPBOX "Modes",IDC_STATIC,3,70,300,27 + CONTROL "Avatar only mode",IDC_DISCONDICON,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,8,81,278,8 + GROUPBOX "Units",IDC_STATIC,3,99,299,87,WS_GROUP + LTEXT "Temperature",IDC_STATIC,8,111,53,8 + CONTROL "Celsius",IDC_T1,"Button",BS_AUTORADIOBUTTON,65,111,40,8 + CONTROL "Fahrenheit",IDC_T2,"Button",BS_AUTORADIOBUTTON,120,111,47,8 + RTEXT "Degree sign:",IDC_STATIC,194,111,85,8 + EDITTEXT IDC_DEGREE,283,111,13,12,ES_AUTOHSCROLL | NOT WS_BORDER,WS_EX_CLIENTEDGE | WS_EX_STATICEDGE + LTEXT "Wind",IDC_STATIC,8,121,53,8 + CONTROL "km/h",IDC_W1,"Button",BS_AUTORADIOBUTTON,65,121,34,8 + CONTROL "m/s",IDC_W2,"Button",BS_AUTORADIOBUTTON,120,121,34,8 + CONTROL "mph",IDC_W3,"Button",BS_AUTORADIOBUTTON,176,121,34,8 + CONTROL "knots",IDC_W4,"Button",BS_AUTORADIOBUTTON,232,121,49,8 + LTEXT "Visibility",IDC_STATIC,8,131,53,8 + CONTROL "km",IDC_V1,"Button",BS_AUTORADIOBUTTON,65,131,34,8 + CONTROL "miles",IDC_V2,"Button",BS_AUTORADIOBUTTON,120,131,34,8 + LTEXT "Pressure",IDC_STATIC,8,142,53,8 + CONTROL "kPa",IDC_P1,"Button",BS_AUTORADIOBUTTON,65,142,38,8 + CONTROL "mb (hPa)",IDC_P2,"Button",BS_AUTORADIOBUTTON,120,142,56,8 + CONTROL "inches",IDC_P3,"Button",BS_AUTORADIOBUTTON,176,142,38,8 + CONTROL "mm Hg (torr)",IDC_P4,"Button",BS_AUTORADIOBUTTON,232,142,62,8 LTEXT "Day/Month",IDC_STATIC,8,153,53,8 CONTROL "No change",IDC_D1,"Button",BS_AUTORADIOBUTTON,65,153,52,8 CONTROL "2 chars",IDC_D2,"Button",BS_AUTORADIOBUTTON,120,153,56,8 @@ -92,7 +88,7 @@ BEGIN LTEXT "Avatar size",IDC_STATIC,60,200,95,9 END -IDD_EDIT DIALOGEX 0, 0, 241, 226 +IDD_EDIT DIALOGEX 0, 0, 241, 175 STYLE DS_SETFONT | DS_MODALFRAME | DS_SETFOREGROUND | DS_3DLOOK | DS_FIXEDSYS | DS_CENTER | WS_POPUP | WS_VISIBLE | WS_CAPTION | WS_SYSMENU EXSTYLE WS_EX_CONTROLPARENT CAPTION "Edit Weather Station" @@ -100,9 +96,9 @@ FONT 8, "MS Shell Dlg", 0, 0, 0x1 BEGIN GROUPBOX "Weather Station",IDC_STATIC,5,7,231,46 LTEXT "City name",IDC_STATIC,12,21,57,8,SS_CENTERIMAGE - EDITTEXT IDC_NAME,69,19,146,12,ES_AUTOHSCROLL + EDITTEXT IDC_NAME,69,19,162,12,ES_AUTOHSCROLL LTEXT "ID",IDC_STATIC,12,37,57,8,SS_CENTERIMAGE - EDITTEXT IDC_ID,69,35,146,12,ES_AUTOHSCROLL + EDITTEXT IDC_ID,69,35,162,12,ES_AUTOHSCROLL | WS_DISABLED GROUPBOX "Log Information",IDC_STATIC,5,55,231,53 CONTROL "Use internal history",IDC_Internal,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,12,68,218,8 CONTROL "Use external file",IDC_External,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,12,80,98,8 @@ -110,24 +106,13 @@ BEGIN LTEXT "Path:",IDC_STATIC,25,93,37,8,SS_CENTERIMAGE EDITTEXT IDC_LOG,69,91,146,12,ES_AUTOHSCROLL | ES_READONLY CONTROL "6",IDC_BROWSE,"MButtonClass",WS_TABSTOP,217,91,13,12,WS_EX_NOACTIVATE | 0x10000000L - GROUPBOX "Link Settings",IDC_STATIC,5,110,231,44 - LTEXT "More Info URL",IDC_STATIC,12,123,57,8 - EDITTEXT IDC_IURL,69,121,131,12,ES_AUTOHSCROLL - CONTROL "6",IDC_VIEW1,"MButtonClass",WS_TABSTOP,202,121,13,12,WS_EX_NOACTIVATE | 0x10000000L - CONTROL "6",IDC_RESET1,"MButtonClass",WS_TABSTOP,217,121,13,12,WS_EX_NOACTIVATE | 0x10000000L - LTEXT "Weather Map",IDC_STATIC,12,138,57,8 - EDITTEXT IDC_MURL,69,137,131,12,ES_AUTOHSCROLL - CONTROL "6",IDC_VIEW2,"MButtonClass",WS_TABSTOP,202,137,13,12,WS_EX_NOACTIVATE | 0x10000000L - CONTROL "6",IDC_RESET2,"MButtonClass",WS_TABSTOP,217,137,13,12,WS_EX_NOACTIVATE | 0x10000000L - GROUPBOX "Other Options",IDC_STATIC,5,157,231,46 - CONTROL "Set as default station",IDC_DEFA,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,12,168,218,8 + GROUPBOX "Other Options",IDC_STATIC,5,108,231,46 + CONTROL "Set as default station",IDC_DEFA,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,12,119,218,8 CONTROL "Disable automatic update for this station",IDC_DAutoUpdate, - "Button",BS_AUTOCHECKBOX | WS_TABSTOP,12,179,218,8 - CONTROL "Disable Popup for this station",IDC_DPop,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,12,190,218,8 - PUSHBUTTON "Change",IDC_CHANGE,57,207,46,14 - DEFPUSHBUTTON "Cancel",IDCANCEL,136,207,46,14 - CONTROL "",IDC_SVCINFO,"MButtonClass",WS_TABSTOP,217,35,13,12,WS_EX_NOACTIVATE | 0x10000000L - CONTROL "",IDC_GETNAME,"MButtonClass",WS_TABSTOP,217,19,13,12,WS_EX_NOACTIVATE | 0x10000000L + "Button",BS_AUTOCHECKBOX | WS_TABSTOP,12,130,218,8 + CONTROL "Disable Popup for this station",IDC_DPop,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,12,141,218,8 + PUSHBUTTON "Change",IDC_CHANGE,57,158,46,14 + DEFPUSHBUTTON "Cancel",IDCANCEL,136,158,46,14 END IDD_POPUP DIALOGEX 0, 0, 312, 236 @@ -136,7 +121,6 @@ EXSTYLE WS_EX_CONTROLPARENT FONT 8, "MS Shell Dlg", 0, 0, 0x1 BEGIN GROUPBOX "Popup Options",IDC_STATIC,4,5,158,54 - CONTROL "Enable popups",IDC_E,"Button",BS_AUTOCHECKBOX | BS_NOTIFY | WS_TABSTOP,15,15,143,9 CONTROL "Popup only when condition changes",IDC_CH,"Button",BS_AUTOCHECKBOX | BS_NOTIFY | WS_TABSTOP,15,44,140,10 GROUPBOX "Colors",IDC_STATIC,168,5,139,54 CONTROL "",IDC_BGCOLOUR,"ColourPicker",WS_TABSTOP,177,16,39,11 @@ -163,9 +147,19 @@ BEGIN CONTROL "Variables",IDC_VAR3,"MButtonClass",WS_TABSTOP,7,153,62,12,WS_EX_NOACTIVATE | 0x10000000L CONTROL "Default",IDC_PDEF,"MButtonClass",WS_TABSTOP,7,175,62,12,WS_EX_NOACTIVATE | 0x10000000L CONTROL "Preview",IDC_PREVIEW,"MButtonClass",WS_TABSTOP,7,197,61,12,WS_EX_NOACTIVATE | 0x10000000L - CONTROL "Updates",IDC_POP1,"Button",BS_AUTOCHECKBOX | BS_NOTIFY | WS_TABSTOP,29,24,64,9 - CONTROL "Alerts",IDC_POP2,"Button",BS_AUTOCHECKBOX | BS_NOTIFY | WS_TABSTOP,29,34,64,9 - CONTROL "Errors",IDC_W,"Button",BS_AUTOCHECKBOX | BS_NOTIFY | WS_TABSTOP,97,24,54,9 + CONTROL "Updates",IDC_POP1,"Button",BS_AUTOCHECKBOX | BS_NOTIFY | WS_TABSTOP,14,18,64,9 + CONTROL "Alerts",IDC_POP2,"Button",BS_AUTOCHECKBOX | BS_NOTIFY | WS_TABSTOP,14,31,64,9 + CONTROL "Errors",IDC_W,"Button",BS_AUTOCHECKBOX | BS_NOTIFY | WS_TABSTOP,82,18,54,9 +END + +IDD_ACCOUNT_OPT DIALOGEX 0, 0, 309, 233 +STYLE DS_SETFONT | DS_FIXEDSYS | WS_CHILD +EXSTYLE WS_EX_CONTROLPARENT +FONT 8, "MS Shell Dlg", 0, 0, 0x1 +BEGIN + LTEXT "Enter your personal API key from Visual Crossing Weather site",IDC_STATIC,8,7,294,8 + EDITTEXT IDC_KEY,8,19,294,14,ES_AUTOHSCROLL + PUSHBUTTON "Obtain key",IDC_OBTAIN,172,38,130,14 END IDD_TEXTOPT DIALOGEX 0, 0, 309, 233 @@ -188,7 +182,7 @@ BEGIN CONTROL "History Log",IDC_TM7,"MButtonClass",WS_TABSTOP,2,221,77,9,WS_EX_WINDOWEDGE | WS_EX_NOACTIVATE | 0x10000000L EDITTEXT IDC_HTEXT,80,219,183,12,ES_AUTOHSCROLL GROUPBOX "Variable List",IDC_STATIC,207,14,99,191 - LTEXT "",IDC_VARLIST,213,25,86,157 + CONTROL "",IDC_VARLIST,"Static",SS_LEFTNOWORDWRAP | WS_GROUP,213,25,86,157 CONTROL "More Variables",IDC_MORE,"MButtonClass",WS_TABSTOP,216,187,81,15,WS_EX_WINDOWEDGE | WS_EX_NOACTIVATE | 0x10000000L CONTROL "Reset",IDC_RESET,"MButtonClass",WS_TABSTOP,266,208,40,21,WS_EX_WINDOWEDGE | WS_EX_NOACTIVATE | 0x10000000L EDITTEXT IDC_BTITLE2,80,28,125,12,ES_AUTOHSCROLL @@ -229,40 +223,6 @@ BEGIN CONTROL "More...",IDC_MOREDETAIL,"MButtonClass",WS_TABSTOP,129,104,61,12,WS_EX_WINDOWEDGE | WS_EX_NOACTIVATE | 0x10000000L END -IDD_SETUP DIALOGEX 0, 0, 259, 142 -STYLE DS_SETFONT | DS_SETFOREGROUND | DS_3DLOOK | DS_FIXEDSYS | DS_CENTER | WS_MINIMIZEBOX | WS_POPUP | WS_VISIBLE | WS_CAPTION | WS_SYSMENU -EXSTYLE WS_EX_CONTROLPARENT -CAPTION "Weather Protocol INI Setup" -FONT 8, "MS Shell Dlg", 0, 0, 0x1 -BEGIN - CONTROL "Install and load your weather ini file here",IDC_HEADERBAR, - "MHeaderbarCtrl",0x0,0,0,259,28 - CTEXT "Weather Protocol cannot find any weather INI file stored in your computer. To setup weather INI and add weather stations, please follow the steps:",IDC_STATIC,11,32,222,26 - CONTROL "Click here to download a weather ini file from Miranda file listing",IDC_STEP1, - "MButtonClass",WS_TABSTOP,5,62,249,12,WS_EX_WINDOWEDGE | 0x800000L - CONTROL "Extract the weather ini file from archive to this directory",IDC_STEP2, - "MButtonClass",WS_TABSTOP,5,74,249,12,WS_EX_WINDOWEDGE | 0x800000L - CONTROL "Click here to load the data from the new ini file into memory",IDC_STEP3, - "MButtonClass",WS_TABSTOP,5,86,249,13,WS_EX_WINDOWEDGE | 0x800000L - CONTROL "Add new weather station and close this dialog",IDC_STEP4, - "MButtonClass",WS_TABSTOP,5,99,249,12,WS_EX_WINDOWEDGE | 0x800000L - PUSHBUTTON "Close",IDCANCEL,107,122,48,13 - CONTROL "",IDC_MFRAME,"Static",SS_ETCHEDHORZ,0,117,259,1 -END - -IDD_INFO DIALOGEX 0, 0, 225, 155 -STYLE DS_SETFONT | DS_FIXEDSYS | DS_CONTROL | WS_CHILD | WS_SYSMENU -EXSTYLE WS_EX_CONTROLPARENT -FONT 8, "MS Shell Dlg", 400, 0, 0x1 -BEGIN - CONTROL "",IDC_INFOLIST,"SysListView32",LVS_REPORT | LVS_SINGLESEL | LVS_ALIGNLEFT | WS_BORDER | WS_TABSTOP,7,7,210,115 - LTEXT "Total INI files",IDC_STATIC,7,125,95,8 - LTEXT "Total memory used",IDC_STATIC,7,138,92,8 - LTEXT "",IDC_INICOUNT,104,125,30,10,SS_SUNKEN - LTEXT "",IDC_MEMUSED,104,138,29,10,SS_SUNKEN - PUSHBUTTON "Reload INI",IDC_RELOADINI,145,128,64,18 -END - IDD_SEARCHCITY DIALOGEX 0, 0, 114, 55 STYLE DS_SETFONT | DS_FIXEDSYS | DS_CONTROL | WS_CHILD | WS_SYSMENU EXSTYLE WS_EX_TRANSPARENT | WS_EX_CONTROLPARENT @@ -289,33 +249,26 @@ BEGIN IDD_OPTIONS, DIALOG BEGIN - VERTGUIDE, 8 - VERTGUIDE, 294 BOTTOMMARGIN, 209 END - IDD_POPUP, DIALOG + IDD_EDIT, DIALOG BEGIN - RIGHTMARGIN, 306 - BOTTOMMARGIN, 233 END - IDD_TEXTOPT, DIALOG + IDD_POPUP, DIALOG BEGIN - BOTTOMMARGIN, 232 + RIGHTMARGIN, 306 + BOTTOMMARGIN, 233 END - IDD_SETUP, DIALOG + IDD_ACCOUNT_OPT, DIALOG BEGIN - BOTTOMMARGIN, 136 END - IDD_INFO, DIALOG + IDD_TEXTOPT, DIALOG BEGIN - LEFTMARGIN, 7 - RIGHTMARGIN, 217 - TOPMARGIN, 7 - BOTTOMMARGIN, 148 + BOTTOMMARGIN, 232 END IDD_SEARCHCITY, DIALOG @@ -374,15 +327,24 @@ END // Icon with lowest ID value placed first to ensure application icon // remains consistent on all systems. IDI_ICON ICON "icon.ico" + IDI_UPDATE ICON "update.ico" + IDI_READ ICON "more.ico" + IDI_S ICON "brief.ico" + IDI_LOG ICON "log.ico" + IDI_EDIT ICON "edit.ico" + IDI_MAP ICON "map.ico" + IDI_UPDATE2 ICON "update2.ico" + IDI_DISABLED ICON "disabled.ico" + #ifdef APSTUDIO_INVOKED ///////////////////////////////////////////////////////////////////////////// // diff --git a/protocols/Weather/src/proto.h b/protocols/Weather/src/proto.h new file mode 100644 index 0000000000..b44c193110 --- /dev/null +++ b/protocols/Weather/src/proto.h @@ -0,0 +1,296 @@ +#pragma once + +struct WIDATAITEM +{ + WIDATAITEM(const wchar_t *_1, const wchar_t *_2, const CMStringW &_3) : + Name(_1), + Unit(_2), + Value(_3) + {} + + const wchar_t *Name, *Unit; + CMStringW Value; +}; + +struct WIDATAITEMLIST : public OBJLIST<WIDATAITEM> +{ + WIDATAITEMLIST() : + OBJLIST<WIDATAITEM>(20) + {} + + WIDATAITEM* Find(const wchar_t *pwszName) + { + for (auto &it : *this) + if (!mir_wstrcmp(it->Name, pwszName)) + return it; + return 0; + } +}; + +struct WEATHERINFO +{ + MCONTACT hContact; + TCHAR id[128]; + TCHAR city[128]; + TCHAR update[64]; + TCHAR cond[128]; + TCHAR temp[16]; + TCHAR low[16]; + TCHAR high[16]; + TCHAR feel[16]; + TCHAR wind[16]; + TCHAR winddir[64]; + TCHAR dewpoint[16]; + TCHAR pressure[16]; + TCHAR humid[16]; + TCHAR vis[16]; + TCHAR sunrise[32]; + TCHAR sunset[32]; +}; + +struct MYOPTIONS +{ + // main options + uint8_t AutoUpdate; + uint8_t CAutoUpdate; + uint8_t UpdateOnlyConditionChanged; + uint8_t RemoveOldData; + uint8_t MakeItalic; + + uint16_t UpdateTime; + uint16_t AvatarSize; + + // units + uint16_t tUnit; + uint16_t wUnit; + uint16_t vUnit; + uint16_t pUnit; + uint16_t dUnit; + uint16_t eUnit; + wchar_t DegreeSign[4]; + uint8_t DoNotAppendUnit; + uint8_t NoFrac; + + // advanced + uint8_t DisCondIcon; + + // popup options + uint8_t UpdatePopup; + uint8_t AlertPopup; + uint8_t PopupOnChange; + uint8_t ShowWarnings; + + // popup colors + uint8_t UseWinColors; + COLORREF BGColour; + COLORREF TextColour; + + // popup actions + uint32_t LeftClickAction; + uint32_t RightClickAction; + + // popup delay + uint32_t pDelay; + + // other misc stuff + wchar_t Default[64]; + MCONTACT DefStn; +}; + +///////////////////////////////////////////////////////////////////////////////////////// +// Protocol class + +class CWeatherProto : public PROTO<CWeatherProto> +{ + friend class CEditDlg; + friend class CPopupOptsDlg; + friend class CBriefInfoDlg; + friend class COptionsTextDlg; + friend class CGeneralOptionsDlg; + friend class WeatherUserInfoDlg; + + class CProtoImpl + { + friend class CWeatherProto; + CWeatherProto &m_proto; + + CTimer m_start, m_update; + + void OnStart(CTimer *pTimer) + { + pTimer->Stop(); + m_proto.StartUpdate(); + } + + void OnUpdate(CTimer *) + { + m_proto.DoUpdate(); + } + + CProtoImpl(CWeatherProto &pro) : + m_proto(pro), + m_start(Miranda_GetSystemWindow(), UINT_PTR(this) + 1), + m_update(Miranda_GetSystemWindow(), UINT_PTR(this) + 2) + { + m_start.OnEvent = Callback(this, &CProtoImpl::OnStart); + m_update.OnEvent = Callback(this, &CProtoImpl::OnUpdate); + } + } + m_impl; + + // avatars + void AvatarDownloaded(MCONTACT hContact); + + INT_PTR __cdecl AdvancedStatusIconSvc(WPARAM, LPARAM); + INT_PTR __cdecl GetAvatarInfoSvc(WPARAM, LPARAM); + + // contacts + INT_PTR __cdecl ViewLog(WPARAM, LPARAM); + INT_PTR __cdecl LoadForecast(WPARAM, LPARAM); + INT_PTR __cdecl WeatherMap(WPARAM, LPARAM); + INT_PTR __cdecl EditSettings(WPARAM, LPARAM); + + int __cdecl BriefInfoEvt(WPARAM, LPARAM); + + bool IsMyContact(MCONTACT hContact); + + // conversions + void numToStr(double num, wchar_t *str, size_t strSize); + + void GetTemp(const wchar_t *tempchar, const wchar_t *unit, wchar_t *str); + void GetSpeed(const wchar_t *tempchar, const wchar_t *unit, wchar_t *str); + void GetPressure(const wchar_t *tempchar, const wchar_t *unit, wchar_t *str); + void GetDist(const wchar_t *tempchar, const wchar_t *unit, wchar_t *str); + void GetElev(const wchar_t *tempchar, const wchar_t *unit, wchar_t *str); + + // data + void ConvertDataValue(WIDATAITEM *UpdateData); + void EraseAllInfo(void); + WEATHERINFO LoadWeatherInfo(MCONTACT hContact); + + MHttpResponse* RunQuery(const wchar_t *id, int days); + + // menu items + HGENMENU hEnableDisableMenu; + + void InitMenuItems(); + void UpdateMenu(BOOL State); + + INT_PTR __cdecl EnableDisableCmd(WPARAM, LPARAM); + + // mwin + void AddFrameWindow(MCONTACT hContact); + void RemoveFrameWindow(MCONTACT hContact); + + void InitMwin(void); + void DestroyMwin(void); + + INT_PTR __cdecl Mwin_MenuClicked(WPARAM, LPARAM); + + // options + void LoadOptions(); + void SaveOptions(); + void RestartTimer(); + void InitPopupOptions(WPARAM); + + int __cdecl OptInit(WPARAM, LPARAM); + + CMStringW GetTextValue(int c); + void GetVarsDescr(CMStringW &str); + + // popups + int WPShowMessage(const wchar_t *lpzText, int kind); + int WeatherPopup(MCONTACT hContact, bool bNew); + + // search + bool CheckSearch(); + + int IDSearch(wchar_t *id, int searchId); + int NameSearch(wchar_t *name, int searchId); + + void __cdecl NameSearchThread(void *); + void __cdecl BasicSearchThread(void *); + + // update weather + std::vector<MCONTACT> m_updateList; + + // check if weather is currently updating + bool m_bThreadRunning; + mir_cs m_csUpdate; + + void DoUpdate(); + void StartUpdate(); + + int GetWeatherData(MCONTACT hContact); + int UpdateWeather(MCONTACT hContact); + void UpdateListAdd(MCONTACT hContact); + MCONTACT UpdateGetFirst(); + void DestroyUpdateList(void); + + void __cdecl UpdateThread(void *); + void UpdateAll(BOOL AutoUpdate, BOOL RemoveOld); + + INT_PTR __cdecl UpdateSingleStation(WPARAM, LPARAM); + INT_PTR __cdecl UpdateSingleRemove(WPARAM, LPARAM); + + INT_PTR __cdecl UpdateAllInfo(WPARAM, LPARAM); + INT_PTR __cdecl UpdateAllRemove(WPARAM, LPARAM); + + // user info + int __cdecl UserInfoInit(WPARAM, LPARAM); + +public: + CWeatherProto(const char *protoName, const wchar_t *userName); + ~CWeatherProto(); + + MYOPTIONS opt; + + CMOption<bool> m_bPopups; + CMOption<wchar_t *> m_szApiKey; + INT_PTR __cdecl BriefInfo(WPARAM, LPARAM); + + int MapCondToStatus(MCONTACT hContact); + HICON GetStatusIcon(MCONTACT hContact); + HICON GetStatusIconBig(MCONTACT hContact); + + static LRESULT CALLBACK CWeatherProto::PopupWndProc(HWND hWnd, UINT uMsg, WPARAM, LPARAM); + + // PROTO_INTERFACE + MCONTACT AddToList(int flags, PROTOSEARCHRESULT *psr) override; + HANDLE SearchBasic(const wchar_t *id) override; + HANDLE SearchAdvanced(MWindow owner) override; + MWindow CreateExtendedSearchUI(MWindow owner) override; + + INT_PTR GetCaps(int type, MCONTACT hContact) override; + int SetStatus(int iNewStatus) override; + + void __cdecl GetAwayMsgThread(void *arg); + HANDLE GetAwayMsg(MCONTACT hContact) override; + + void __cdecl AckThreadProc(void *arg); + int GetInfo(MCONTACT hContact, int) override; + + bool OnContactDeleted(MCONTACT, uint32_t flags) override; + void OnModulesLoaded() override; + void OnShutdown() override; + + static void GlobalMenuInit(); + int __cdecl BuildContactMenu(MCONTACT); + + int __cdecl OnToolbarLoaded(WPARAM, LPARAM); +}; + +typedef CProtoDlgBase<CWeatherProto> CWeatherDlgBase; + +///////////////////////////////////////////////////////////////////////////////////////// +// Plugin class + +struct CMPlugin : public ACCPROTOPLUGIN<CWeatherProto> +{ + CMPlugin(); + + HINSTANCE hIconsDll = nullptr; + + int Load() override; + int Unload() override; +}; diff --git a/protocols/Weather/src/resource.h b/protocols/Weather/src/resource.h index 67e9006fb3..809c94857b 100644 --- a/protocols/Weather/src/resource.h +++ b/protocols/Weather/src/resource.h @@ -1,6 +1,6 @@ //{{NO_DEPENDENCIES}} // Microsoft Visual C++ generated include file. -// Used by ..\res\resource.rc +// Used by W:\miranda-ng\protocols\Weather\res\resource.rc // #define IDI_ICON 101 #define IDD_USERINFO 201 @@ -9,6 +9,7 @@ #define IDD_POPUP 204 #define IDD_OPTIONS 205 #define IDI_LOG 206 +#define IDD_ACCOUNT_OPT 207 #define IDI_UPDATE2 208 #define IDI_READ 209 #define IDI_UPDATE 210 @@ -17,11 +18,9 @@ #define IDR_PMENU 213 #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 @@ -31,7 +30,6 @@ #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 @@ -39,7 +37,6 @@ #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 @@ -56,9 +53,6 @@ #define IDC_HTEXT 2028 #define IDC_DPop 2029 #define IDC_DAutoUpdate 2030 -#define IDC_IURL 2032 -#define IDC_MURL 2033 -#define IDC_PROTOCOND 2034 #define IDC_Overwrite 2035 #define IDC_UPDCONDCHG 2036 #define IDC_REMOVEOLD 2037 @@ -78,14 +72,8 @@ #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 @@ -125,23 +113,17 @@ #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_EDIT1 2128 +#define IDC_KEY 2128 #define IDC_E2 2129 +#define IDC_OBTAIN 2129 #define OIC_HAND 32513 #define OIC_QUES 32514 #define OIC_BANG 32515 @@ -158,7 +140,6 @@ #define ID_T2 40011 #define ID_MPREVIEW 40020 #define ID_MRESET 40021 -#define IDC_STATIC -1 // Next default values for new objects // @@ -167,7 +148,7 @@ #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_CONTROL_VALUE 2130 #define _APS_NEXT_SYMED_VALUE 101 #endif #endif diff --git a/protocols/Weather/src/stdafx.cxx b/protocols/Weather/src/stdafx.cxx index 13f28e1314..f111565f38 100644 --- a/protocols/Weather/src/stdafx.cxx +++ b/protocols/Weather/src/stdafx.cxx @@ -1,5 +1,5 @@ /*
-Copyright (C) 2012-24 Miranda NG team (https://miranda-ng.org)
+Copyright (C) 2012-25 Miranda NG team (https://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
diff --git a/protocols/Weather/src/stdafx.h b/protocols/Weather/src/stdafx.h index 64993c86ef..cf1f3240a3 100644 --- a/protocols/Weather/src/stdafx.h +++ b/protocols/Weather/src/stdafx.h @@ -1,6 +1,6 @@ /*
Weather Protocol plugin for Miranda NG
-Copyright (C) 2012-24 Miranda NG team
+Copyright (C) 2012-25 Miranda NG team
Copyright (c) 2005-2011 Boris Krasnovskiy All Rights Reserved
Copyright (c) 2002-2005 Calvin Che
@@ -24,8 +24,6 @@ along with this program. If not, see <http://www.gnu.org/licenses/>. #pragma once
-//============ THE INCLUDES ===========
-
#include <share.h>
#include <time.h>
#include <windows.h>
@@ -33,6 +31,8 @@ along with this program. If not, see <http://www.gnu.org/licenses/>. #include <richedit.h>
#include <malloc.h>
+#include <vector>
+
#include <newpluginapi.h>
#include <m_acc.h>
#include <m_avatars.h>
@@ -46,6 +46,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>. #include <m_history.h>
#include <m_icolib.h>
#include <m_ignore.h>
+#include <m_json.h>
#include <m_langpack.h>
#include <m_netlib.h>
#include <m_options.h>
@@ -57,13 +58,14 @@ along with this program. If not, see <http://www.gnu.org/licenses/>. #include <m_xstatus.h>
#include <m_tipper.h>
-#include <m_weather.h>
#include <m_toptoolbar.h>
#include "resource.h"
#include "version.h"
+#include "proto.h"
-//============ CONSTANTS ============
+/////////////////////////////////////////////////////////////////////////////////////////
+// CONSTANTS
// name
#define MODULENAME "Weather"
@@ -86,17 +88,10 @@ enum EWeatherCondition MAX_COND
};
-// 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
@@ -105,442 +100,62 @@ enum EWeatherCondition #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 VAR_LIST_OPT 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\n----------\n\\n\tnew line")
-
-//============ OPTION STRUCT ============
-
-// option struct
-struct MYOPTIONS
-{
- // main options
- uint8_t AutoUpdate;
- uint8_t CAutoUpdate;
- uint8_t StartupUpdate;
- uint8_t NoProtoCondition;
- uint8_t UpdateOnlyConditionChanged;
- uint8_t RemoveOldData;
- uint8_t MakeItalic;
-
- uint16_t UpdateTime;
- uint16_t AvatarSize;
-
- // units
- uint16_t tUnit;
- uint16_t wUnit;
- uint16_t vUnit;
- uint16_t pUnit;
- uint16_t dUnit;
- uint16_t eUnit;
- wchar_t DegreeSign[4];
- uint8_t DoNotAppendUnit;
- uint8_t NoFrac;
-
- // advanced
- uint8_t DisCondIcon;
-
- // popup options
- uint8_t UpdatePopup;
- uint8_t AlertPopup;
- uint8_t PopupOnChange;
- uint8_t ShowWarnings;
-
- // popup colors
- uint8_t UseWinColors;
- COLORREF BGColour;
- COLORREF TextColour;
-
- // popup actions
- uint32_t LeftClickAction;
- uint32_t RightClickAction;
-
- // popup delay
- uint32_t pDelay;
-
- // other misc stuff
- wchar_t Default[64];
- MCONTACT DefStn;
-};
-
-//============ STRUCT USED TO MAKE AN UPDATE LIST ============
-struct WCONTACTLIST {
- MCONTACT hContact;
- struct WCONTACTLIST *next;
-};
-
-typedef struct WCONTACTLIST UPDATELIST;
-
-extern UPDATELIST *UpdateListHead, *UpdateListTail;
-
-void DestroyUpdateList(void);
-
-//============ DATA FORMAT STRUCT ============
-
-#define WID_NORMAL 0
-#define WID_SET 1
-#define WID_BREAK 2
-
-struct WIDATAITEM
-{
- wchar_t *Name;
- wchar_t *Start;
- wchar_t *End;
- wchar_t *Unit;
- char *Url;
- wchar_t *Break;
- int Type;
-};
-
-struct WITEMLIST
+#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
+
+#define SM_WEATHERALERT 16
+#define WM_UPDATEDATA (WM_USER + 2687)
+
+struct WeatherReply : public JsonReply
{
- WIDATAITEM Item;
- struct WITEMLIST *Next;
+ WeatherReply(MHttpResponse *response) :
+ JsonReply(response)
+ {
+ delete response;
+ }
};
-typedef struct WITEMLIST WIDATAITEMLIST;
-
-struct WIIDSEARCH
-{
- BOOL Available;
- char *SearchURL;
- wchar_t *NotFoundStr;
- WIDATAITEM Name;
-};
+/////////////////////////////////////////////////////////////////////////////////////////
+// GLOBAL VARIABLES
-struct WINAMESEARCHTYPE
-{
- BOOL Available;
- wchar_t *First;
- WIDATAITEM Name;
- WIDATAITEM ID;
-};
-
-struct WINAMESEARCH
-{
- char *SearchURL;
- wchar_t *NotFoundStr;
- wchar_t *SingleStr;
- WINAMESEARCHTYPE Single;
- WINAMESEARCHTYPE Multiple;
-};
-
-struct STRLIST
-{
- wchar_t *Item;
- struct STRLIST *Next;
-};
-
-typedef struct STRLIST WICONDITEM;
-
-struct WICONDLIST
-{
- WICONDITEM *Head;
- WICONDITEM *Tail;
-};
-
-struct WIDATA
-{
- wchar_t *FileName;
- wchar_t *ShortFileName;
- BOOL Enabled;
-
- // header
- wchar_t *DisplayName;
- wchar_t *InternalName;
- wchar_t *Description;
- wchar_t *Author;
- wchar_t *Version;
- int InternalVer;
- size_t MemUsed;
-
- // default
- char *DefaultURL;
- wchar_t *DefaultMap;
- char *UpdateURL;
- char *UpdateURL2;
- char *UpdateURL3;
- char *UpdateURL4;
- char *Cookie;
- char *UserAgent;
-
- // items
- int UpdateDataCount;
- WIDATAITEMLIST *UpdateData;
- WIDATAITEMLIST *UpdateDataTail;
- WIIDSEARCH IDSearch;
- WINAMESEARCH NameSearch;
- WICONDLIST CondList[MAX_COND];
-};
-
-//============ DATA LIST (LINKED LIST) ============
-
-struct DATALIST
-{
- WIDATA Data;
- struct DATALIST *next;
-};
-
-typedef struct DATALIST WIDATALIST;
-
-//============ GLOBAL VARIABLES ============
-
-extern WIDATALIST *WIHead, *WITail;
-
-extern HWND hPopupWindow, hWndSetup;
-
-extern MYOPTIONS opt;
-
-extern unsigned status, old_status;
+extern HWND hPopupWindow;
extern MWindowList hDataWindowList, hWindowList;
-extern HNETLIBUSER hNetlibUser;
-extern HANDLE hHookWeatherUpdated, hHookWeatherError, hTBButton, hUpdateMutex;
-extern UINT_PTR timerId;
+extern HANDLE hTBButton;
extern HGENMENU hMwinMenu;
-// check if weather is currently updating
-extern BOOL ThreadRunning;
extern bool g_bIsUtf;
-//============ FUNCTION PRIMITIVES ============
-
-// functions in weather_addstn.c
-INT_PTR WeatherAddToList(WPARAM wParam,LPARAM lParam);
-BOOL CheckSearch();
-
-int IDSearch(wchar_t *id, const int searchId);
-int NameSearch(wchar_t *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 ContactDeleted(WPARAM wParam,LPARAM lParam);
-
-BOOL IsMyContact(MCONTACT hContact);
-
+/////////////////////////////////////////////////////////////////////////////////////////
// functions in weather_conv.c
-void GetTemp(wchar_t *tempchar, wchar_t *unit, wchar_t *str);
-void GetSpeed(wchar_t *tempchar, wchar_t *unit, wchar_t *str);
-void GetPressure(wchar_t *tempchar, wchar_t *unit, wchar_t *str);
-void GetDist(wchar_t *tempchar, wchar_t *unit, wchar_t *str);
-void GetElev(wchar_t *tempchar, wchar_t *unit, wchar_t *str);
void ClearStatusIcons();
-int MapCondToStatus(MCONTACT hContact);
-HICON GetStatusIcon(MCONTACT hContact);
-HICON GetStatusIconBig(MCONTACT hContact);
-uint16_t GetIcon(const wchar_t* cond, WIDATA *Data);
void CaseConv(wchar_t *str);
void TrimString(char *str);
void TrimString(wchar_t *str);
void ConvertBackslashes(char *str);
char *GetSearchStr(char *dis);
-wchar_t *GetDisplay(WEATHERINFO *w, const wchar_t *dis, wchar_t* str);
-INT_PTR GetDisplaySvcFunc(WPARAM wParam, LPARAM lParam);
-
-void GetSvc(wchar_t *pszID);
-void GetID(wchar_t *pszID);
+CMStringW GetDisplay(WEATHERINFO *w, const wchar_t *dis);
wchar_t *GetError(int code);
-// functions in weather_data.c
-void GetStationID(MCONTACT hContact, wchar_t* id, int idlen);
-WEATHERINFO LoadWeatherInfo(MCONTACT Change);
-int DBGetData(MCONTACT hContact, char *setting, DBVARIANT *dbv);
-
-void EraseAllInfo(void);
-
-void GetDataValue(WIDATAITEM *UpdateData, wchar_t *Data, wchar_t** szInfo);
-void ConvertDataValue(WIDATAITEM *UpdateData, wchar_t *Data);
-void wSetData(char *&Data, const char *Value);
-void wSetData(wchar_t *&Data, const char *Value);
-void wSetData(wchar_t *&Data, const wchar_t *Value);
-void wfree(char *&Data);
-void wfree(wchar_t *&Data);
-
-void DBDataManage(MCONTACT hContact, uint16_t Mode, WPARAM wParam, LPARAM lParam);
-
-// functions in weather_http.c
-int InternetDownloadFile (char *szUrl, char *cookie, char *userAgent, wchar_t** szData);
-void NetlibInit();
-
-// functions in weather_ini.c
-WIDATA* GetWIData(wchar_t *pszServ);
-
-bool IsContainedInCondList(const wchar_t *pszStr, WICONDLIST *List);
-
-void DestroyWIList();
-bool LoadWIData(bool dial);
-
-INT_PTR CALLBACK DlgPopupOpts(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam);
-
+/////////////////////////////////////////////////////////////////////////////////////////
// functions in weather_info.c
-void GetINIInfo(wchar_t *pszSvc);
-wchar_t* GetINIVersionNum(int iVersion);
-
-void MoreVarList();
-
-// functions in weather_opt.c
-void LoadOptions();
-void SaveOptions();
-
-int OptInit(WPARAM wParam,LPARAM lParam);
-
-CMStringW GetTextValue(int c);
-const wchar_t* GetDefaultText(int c);
-
-// functions in weather_popup.c
-int WeatherPopup(WPARAM wParam, LPARAM lParam);
-int WeatherError(WPARAM wParam, LPARAM lParam);
-int WPShowMessage(const wchar_t* lpzText, uint16_t kind);
-
-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(MCONTACT hContact);
-
-// functions in weather_update.c
-int UpdateWeather(MCONTACT hContact);
-
-void UpdateAll(BOOL AutoUpdate, BOOL RemoveOld);
-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(MCONTACT 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);
+const wchar_t *GetDefaultText(int c);
+/////////////////////////////////////////////////////////////////////////////////////////
// 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(MCONTACT hContact);
-void removeWindow(MCONTACT hContact);
-
-// functions in weather_userinfo.c
-int UserInfoInit(WPARAM wParam, LPARAM lParam);
-
-#define WM_UPDATEDATA WM_USER + 2687
-
-int BriefInfo(WPARAM wParam, LPARAM lParam);
-
-///////////////////////////////////////////////////////////////////////////////
-// UI Classes
-
-class WeatherMyDetailsDlg : public CUserInfoPageDlg
-{
- CCtrlButton btnReload;
-
-public:
- WeatherMyDetailsDlg();
-
- bool OnInitDialog() override;
-
- void onClick_Reload(CCtrlButton *);
-};
-
-//============ Plugin Class ============
-
-struct CMPlugin : public PLUGIN<CMPlugin>
-{
- CMPlugin();
-
- HINSTANCE hIconsDll = nullptr;
- CMOption<bool> bPopups;
-
- int Load() override;
- int Unload() override;
-};
+void UpdateMwinData(MCONTACT hContact);
diff --git a/protocols/Weather/src/version.h b/protocols/Weather/src/version.h index b63cb63edb..cf07dd1fa3 100644 --- a/protocols/Weather/src/version.h +++ b/protocols/Weather/src/version.h @@ -1,7 +1,7 @@ -#define __MAJOR_VERSION 0
-#define __MINOR_VERSION 4
+#define __MAJOR_VERSION 1
+#define __MINOR_VERSION 1
#define __RELEASE_NUM 0
-#define __BUILD_NUM 8
+#define __BUILD_NUM 1
#include <stdver.h>
@@ -10,4 +10,4 @@ #define __DESCRIPTION "Retrieves weather information and displays it in your contact list."
#define __AUTHOR "Miranda NG team"
#define __AUTHORWEB "https://miranda-ng.org/p/Weather"
-#define __COPYRIGHT "© 2002-2005 NoName, 2005-2010 Boris Krasnovskiy, 2012-24 Miranda NG team"
+#define __COPYRIGHT "© 2002-2005 NoName, 2005-2010 Boris Krasnovskiy, 2012-25 Miranda NG team"
diff --git a/protocols/Weather/src/weather.cpp b/protocols/Weather/src/weather.cpp index f5e6bb2e7b..b0ee091b46 100644 --- a/protocols/Weather/src/weather.cpp +++ b/protocols/Weather/src/weather.cpp @@ -28,33 +28,12 @@ belong to any other file. //============ GLOBAL VARIABLES ============ -WIDATALIST *WIHead; -WIDATALIST *WITail; - HWND hPopupWindow; -HANDLE hHookWeatherUpdated; -HANDLE hHookWeatherError; - MWindowList hDataWindowList, hWindowList; -HANDLE hUpdateMutex; - -unsigned status; -unsigned old_status; - -UINT_PTR timerId = 0; - CMPlugin g_plugin; -MYOPTIONS opt; - -// check if weather is currently updating -BOOL ThreadRunning; - -// variable to determine if module loaded -BOOL ModuleLoaded = FALSE; - VARSW g_pwszIconsName(L"%miranda_path%\\Icons\\proto_Weather.dll"); HANDLE hTBButton = nullptr; @@ -77,11 +56,8 @@ static const PLUGININFOEX pluginInfoEx = }; CMPlugin::CMPlugin() : - PLUGIN<CMPlugin>(MODULENAME, pluginInfoEx), - bPopups(MODULENAME, "UsePopup", true) + ACCPROTOPLUGIN<CWeatherProto>(MODULENAME, pluginInfoEx) { - opt.NoProtoCondition = g_plugin.getByte("NoStatus", true); - RegisterProtocol((opt.NoProtoCondition) ? PROTOTYPE_VIRTUAL : PROTOTYPE_PROTOCOL); SetUniqueId("ID"); } @@ -91,52 +67,10 @@ extern "C" __declspec(dllexport) const MUUID MirandaInterfaces[] = { MIID_PROTOC ///////////////////////////////////////////////////////////////////////////////////////// -int WeatherShutdown(WPARAM, LPARAM) +static int OnPreShutdown(WPARAM, LPARAM) { - KillTimer(nullptr, timerId); // kill update timer - - SaveOptions(); // save options once more - status = ID_STATUS_OFFLINE; // set status to offline - WindowList_Broadcast(hWindowList, WM_CLOSE, 0, 0); WindowList_Broadcast(hDataWindowList, WM_CLOSE, 0, 0); - SendMessage(hWndSetup, WM_CLOSE, 0, 0); - - return 0; -} - -int OnToolbarLoaded(WPARAM, LPARAM) -{ - TTBButton ttb = {}; - ttb.name = LPGEN("Enable/disable auto update"); - ttb.pszService = MS_WEATHER_ENABLED; - ttb.pszTooltipUp = LPGEN("Auto Update Enabled"); - ttb.pszTooltipDn = LPGEN("Auto Update Disabled"); - ttb.hIconHandleUp = g_plugin.getIconHandle(IDI_ICON); - ttb.hIconHandleDn = g_plugin.getIconHandle(IDI_DISABLED); - ttb.dwFlags = (g_plugin.getByte("AutoUpdate", 1) ? 0 : TTBBF_PUSHED) | TTBBF_ASPUSHBUTTON | TTBBF_VISIBLE; - hTBButton = g_plugin.addTTB(&ttb); - return 0; -} - -// weather protocol initialization function -// run after the event ME_SYSTEM_MODULESLOADED occurs -int WeatherInit(WPARAM, LPARAM) -{ - // initialize netlib - NetlibInit(); - - InitMwin(); - - // load weather menu items - AddMenuItems(); - - // timer for the first update - timerId = SetTimer(nullptr, 0, 5000, timerProc2); // first update is 5 sec after load - - // weather user detail - HookEvent(ME_USERINFO_INITIALISE, UserInfoInit); - HookEvent(ME_TTB_MODULELOADED, OnToolbarLoaded); return 0; } @@ -159,56 +93,26 @@ int CMPlugin::Load() { g_plugin.registerIcon(MODULENAME, iconList, MODULENAME); + HookEvent(ME_SYSTEM_PRESHUTDOWN, OnPreShutdown); + // load dll with icons hIconsDll = LoadLibraryW(g_pwszIconsName); - // load options and set defaults - LoadOptions(); - - // reset the weather data at startup for individual contacts - EraseAllInfo(); - - // 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); - + // window lists hDataWindowList = WindowList_Create(); hWindowList = WindowList_Create(); - hUpdateMutex = CreateMutex(nullptr, FALSE, nullptr); - - // initialize weather protocol services - InitServices(); + // add global menus + CWeatherProto::GlobalMenuInit(); // add sound event addSound("weatherupdated", _A2W(MODULENAME), LPGENW("Condition Changed")); addSound("weatheralert", _A2W(MODULENAME), LPGENW("Alert Issued")); - // popup initialization - addPopupOption(LPGEN("Weather notifications"), bPopups); - // window needed for popup commands - wchar_t SvcFunc[100]; - mir_snwprintf(SvcFunc, L"%s__PopupWindow", _A2W(MODULENAME)); - hPopupWindow = CreateWindowEx(WS_EX_TOOLWINDOW, L"static", SvcFunc, 0, CW_USEDEFAULT, CW_USEDEFAULT, + hPopupWindow = CreateWindowEx(WS_EX_TOOLWINDOW, L"static", _A2W(MODULENAME) L"__PopupWindow", 0, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, HWND_DESKTOP, nullptr, g_plugin.getInst(), nullptr); - SetWindowLongPtr(hPopupWindow, GWLP_WNDPROC, (LONG_PTR)PopupWndProc); + SetWindowLongPtr(hPopupWindow, GWLP_WNDPROC, (LONG_PTR)&CWeatherProto::PopupWndProc); return 0; } @@ -220,20 +124,9 @@ int CMPlugin::Unload() if (hIconsDll) FreeModule(hIconsDll); - DestroyMwin(); DestroyWindow(hPopupWindow); - DestroyHookableEvent(hHookWeatherUpdated); - DestroyHookableEvent(hHookWeatherError); - - Netlib_CloseHandle(hNetlibUser); - - DestroyUpdateList(); - DestroyWIList(); // unload all ini data from memory - WindowList_Destroy(hDataWindowList); WindowList_Destroy(hWindowList); - - CloseHandle(hUpdateMutex); return 0; } diff --git a/protocols/Weather/src/weather_addstn.cpp b/protocols/Weather/src/weather_addstn.cpp index 79504143ae..026b9f8c67 100644 --- a/protocols/Weather/src/weather_addstn.cpp +++ b/protocols/Weather/src/weather_addstn.cpp @@ -28,157 +28,126 @@ to the contact list. Contain code for both name and ID search. static int sttSearchId = -1; static wchar_t name1[256]; -// ============ ADDING NEW STATION ============ - +///////////////////////////////////////////////////////////////////////////////////////// // protocol service function for adding a new contact onto contact list -// lParam = PROTOSEARCHRESULT -INT_PTR WeatherAddToList(WPARAM, LPARAM lParam) + +MCONTACT CWeatherProto::AddToList(int, PROTOSEARCHRESULT *psr) { - PROTOSEARCHRESULT *psr = (PROTOSEARCHRESULT*)lParam; - if (!psr || !psr->email.w) + if (!psr || !psr->id.w) return 0; // search for existing contact - for (auto &hContact : Contacts()) { - // 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 (!g_plugin.getWString(hContact, "ID", &dbv)) { - if (!mir_wstrcmpi(psr->email.w, dbv.pwszVal)) { - // remove the flag for not on list and hidden, thus make the contact visible - // and add them on the list - if (!Contact::OnList(hContact)) { - Contact::PutOnList(hContact); - Contact::Hide(hContact, false); - } - db_free(&dbv); - // contact is added, function quitting - return (INT_PTR)hContact; + for (auto &hContact : AccContacts()) { + DBVARIANT dbv; + // check ID to see if the contact already exist in the database + if (!getWString(hContact, "ID", &dbv)) { + if (!mir_wstrcmpi(psr->id.w, dbv.pwszVal)) { + // remove the flag for not on list and hidden, thus make the contact visible + // and add them on the list + if (!Contact::OnList(hContact)) { + Contact::PutOnList(hContact); + Contact::Hide(hContact, false); } db_free(&dbv); + // contact is added, function quitting + return (INT_PTR)hContact; } + db_free(&dbv); } } // if contact with the same ID was not found, add it - if (psr->cbSize < sizeof(PROTOSEARCHRESULT)) return 0; + if (psr->cbSize < sizeof(PROTOSEARCHRESULT)) + return 0; + MCONTACT hContact = db_add_contact(); - Proto_AddToContact(hContact, MODULENAME); + Proto_AddToContact(hContact, m_szModuleName); // suppress online notification for the new contact Ignore_Ignore(hContact, IGNOREEVENT_USERONLINE); - // set contact info and settings - wchar_t svc[256]; - wcsncpy(svc, psr->email.w, _countof(svc)); svc[_countof(svc) - 1] = 0; - GetSvc(svc); - // set settings by obtaining the default for the service - if (psr->lastName.w[0] != 0) { - WIDATA *sData = GetWIData(svc); - g_plugin.setWString(hContact, "MapURL", sData->DefaultMap); - g_plugin.setString(hContact, "InfoURL", sData->DefaultURL); - } - else { // if no valid service is found, create empty strings for MapURL and InfoURL - g_plugin.setString(hContact, "MapURL", ""); - g_plugin.setString(hContact, "InfoURL", ""); - } // write the other info and settings to the database - g_plugin.setWString(hContact, "ID", psr->email.w); - g_plugin.setWString(hContact, "Nick", psr->nick.w); - g_plugin.setWord(hContact, "Status", ID_STATUS_OFFLINE); + setWString(hContact, "ID", psr->id.w); + setWString(hContact, "Nick", psr->nick.w); + if (psr->firstName.w) + setWString(hContact, "FirstName", psr->firstName.w); + setWord(hContact, "Status", ID_STATUS_OFFLINE); AvatarDownloaded(hContact); wchar_t str[256]; mir_snwprintf(str, TranslateT("Current weather information for %s."), psr->nick.w); - g_plugin.setWString(hContact, "About", str); + setWString(hContact, "About", str); // make the last update tags to something invalid - g_plugin.setString(hContact, "LastLog", "never"); - g_plugin.setString(hContact, "LastCondition", "None"); - g_plugin.setString(hContact, "LastTemperature", "None"); + setString(hContact, "LastLog", "never"); + setString(hContact, "LastCondition", "None"); + setString(hContact, "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, _countof(opt.Default)); + wcsncpy_s(opt.Default, getMStringW(hContact, "ID"), _countof(opt.Default)); opt.DefStn = hContact; - if (!g_plugin.getWString(hContact, "Nick", &dbv)) { + ptrW wszNick(getWStringA(hContact, "Nick")); + if (mir_wstrlen(wszNick)) { // notification message box - mir_snwprintf(str, TranslateT("%s is now the default weather station"), dbv.pwszVal); - db_free(&dbv); + mir_snwprintf(str, TranslateT("%s is now the default weather station"), wszNick); MessageBox(nullptr, str, TranslateT("Weather Protocol"), MB_OK | MB_ICONINFORMATION); } - g_plugin.setWString("Default", opt.Default); + + setWString("Default", opt.Default); } + // display the Edit Settings dialog box EditSettings(hContact, 0); - return (INT_PTR)hContact; + return hContact; } -// ============ WARNING DIALOG ============ +///////////////////////////////////////////////////////////////////////////////////////// +// shows a message box and cancel search if update is in process -// show a message box and cancel search if update is in process -BOOL CheckSearch() +bool CWeatherProto::CheckSearch() { - if (UpdateListHead != nullptr) { + if (!m_updateList.empty()) { MessageBox(nullptr, TranslateT("Please try again after weather update is completed."), TranslateT("Weather Protocol"), MB_OK | MB_ICONERROR); - return FALSE; + return false; } - return TRUE; + return true; } -// ============ BASIC ID SEARCH ============ - +///////////////////////////////////////////////////////////////////////////////////////// // A timer process for the ID search (threaded) -static void __cdecl BasicSearchTimerProc(void *pParam) + +void __cdecl CWeatherProto::BasicSearchThread(void *pParam) { ptrW sID((wchar_t *)pParam); - int result; // search only when it's not current updating weather. if (CheckSearch()) - result = IDSearch(sID, sttSearchId); + IDSearch(sID, sttSearchId); // broadcast the search result - ProtoBroadcastAck(MODULENAME, NULL, ACKTYPE_SEARCH, ACKRESULT_SUCCESS, (HANDLE)sttSearchId); + ProtoBroadcastAck(NULL, ACKTYPE_SEARCH, ACKRESULT_SUCCESS, (HANDLE)sttSearchId); // exit the search sttSearchId = -1; } -// the service function for ID search -// lParam = ID search string -INT_PTR WeatherBasicSearch(WPARAM, LPARAM lParam) +HANDLE CWeatherProto::SearchBasic(const wchar_t *id) { if (sttSearchId != -1) return 0; // only one search at a time sttSearchId = 1; - mir_forkthread(BasicSearchTimerProc, mir_a2u((char *)lParam)); // create a thread for the ID search - return sttSearchId; + ForkThread(&CWeatherProto::BasicSearchThread, mir_wstrdup(id)); + return (HANDLE)sttSearchId; } -// ============ NAME SEARCH ============ -// +///////////////////////////////////////////////////////////////////////////////////////// // name search timer process (threaded) -static void __cdecl NameSearchTimerProc(LPVOID) -{ - // search only when it's not current updating weather. - if (CheckSearch()) - if (name1[0] != 0) - NameSearch(name1, sttSearchId); // search nickname field - - // broadcast the result - ProtoBroadcastAck(MODULENAME, NULL, ACKTYPE_SEARCH, ACKRESULT_SUCCESS, (HANDLE)sttSearchId); - - // exit the search - sttSearchId = -1; -} static INT_PTR CALLBACK WeatherSearchAdvancedDlgProc(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM) { @@ -195,238 +164,67 @@ static INT_PTR CALLBACK WeatherSearchAdvancedDlgProc(HWND hwndDlg, UINT msg, WPA return FALSE; } -INT_PTR WeatherCreateAdvancedSearchUI(WPARAM, LPARAM lParam) +MWindow CWeatherProto::CreateExtendedSearchUI(MWindow hwndOwner) { - HWND parent = (HWND)lParam; - if (parent) - return (INT_PTR)CreateDialogParam(g_plugin.getInst(), MAKEINTRESOURCE(IDD_SEARCHCITY), parent, WeatherSearchAdvancedDlgProc, 0); + if (hwndOwner) + return CreateDialogParamW(g_plugin.getInst(), MAKEINTRESOURCE(IDD_SEARCHCITY), hwndOwner, WeatherSearchAdvancedDlgProc, 0); return 0; } +///////////////////////////////////////////////////////////////////////////////////////// // service function for name search -INT_PTR WeatherAdvancedSearch(WPARAM, LPARAM lParam) + +void __cdecl CWeatherProto::NameSearchThread(void *) { - if (sttSearchId != -1) return 0; //only one search at a time + // search only when it's not current updating weather. + if (CheckSearch()) + if (name1[0] != 0) + NameSearch(name1, sttSearchId); // search nickname field - sttSearchId = 1; - GetDlgItemText((HWND)lParam, IDC_SEARCHCITY, name1, _countof(name1)); + // broadcast the result + ProtoBroadcastAck(NULL, ACKTYPE_SEARCH, ACKRESULT_SUCCESS, (HANDLE)sttSearchId); - // search for the weather station using a thread - mir_forkthread(NameSearchTimerProc); - return sttSearchId; + // exit the search + sttSearchId = -1; } -// ============ 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(wchar_t *sID, const int searchId, WIIDSEARCH *sData, wchar_t *svc, wchar_t *svcname) +HANDLE CWeatherProto::SearchAdvanced(MWindow hwndOwner) { - wchar_t str[MAX_DATA_LEN], newID[MAX_DATA_LEN]; - - if (sData->Available) { - char loc[255]; - wchar_t *szData = nullptr; - - // load the page - mir_snprintf(loc, sData->SearchURL, _T2A(sID).get()); - BOOL bFound = (InternetDownloadFile(loc, nullptr, nullptr, &szData) == 0); - if (bFound) { - wchar_t *szInfo = szData; - - // not found - if (wcsstr(szInfo, sData->NotFoundStr) == nullptr) - GetDataValue(&sData->Name, str, &szInfo); - } - - mir_free(szData); - // Station not found exit - if (!bFound) - return 1; - } - - // give no station name but only ID if the search is unavailable - else wcsncpy(str, TranslateT("<Enter station name here>"), MAX_DATA_LEN - 1); - mir_snwprintf(newID, L"%s/%s", svc, sID); + if (sttSearchId != -1) + return 0; //only one search at a time - // set the search result and broadcast it - PROTOSEARCHRESULT psr = { sizeof(psr) }; - psr.flags = PSR_UNICODE; - psr.nick.w = str; - psr.firstName.w = L" "; - psr.lastName.w = svcname; - psr.email.w = newID; - ProtoBroadcastAck(MODULENAME, NULL, ACKTYPE_SEARCH, ACKRESULT_DATA, (HANDLE)searchId, (LPARAM)&psr); + sttSearchId = 1; + GetDlgItemText(hwndOwner, IDC_SEARCHCITY, name1, _countof(name1)); - return 0; + // search for the weather station using a thread + ForkThread(&CWeatherProto::NameSearchThread); + return (HANDLE)sttSearchId; } -// ID search (Threaded) -// sID: the ID to search for -// searchId: don't change -// return 0 if no error -int IDSearch(wchar_t *sID, const int searchId) +int CWeatherProto::IDSearch(wchar_t *sID, int searchId) { - // for a normal ID search (ID != #) - if (mir_wstrcmp(sID, L"#")) { - WIDATALIST *Item = WIHead; - - // search every weather service using the search station ID - while (Item != nullptr) { - IDSearchProc(sID, searchId, &Item->Data.IDSearch, Item->Data.InternalName, Item->Data.DisplayName); - Item = Item->next; - } - } - // if the station ID is #, return a dummy result and quit the funciton - else { - // return an empty contact on "#" + WeatherReply reply(RunQuery(sID, 0)); + if (reply) { + auto &data = reply.data(); + CMStringW id(FORMAT, L"%lf, %lf", data["latitude"].as_float(), data["longitude"].as_float()); + CMStringW address1 = data["address"].as_mstring(); + CMStringW address2 = data["resolvedAddress"].as_mstring(); + PROTOSEARCHRESULT psr = { sizeof(psr) }; psr.flags = PSR_UNICODE; - psr.nick.w = TranslateT("<Enter station name here>"); // to be entered - psr.firstName.w = L" "; + psr.email.w = L" "; psr.lastName.w = L""; - psr.email.w = TranslateT("<Enter station ID here>"); // to be entered - ProtoBroadcastAck(MODULENAME, 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(wchar_t *name, const int searchId, WINAMESEARCH *sData, wchar_t *svc, wchar_t *svcname) -{ - wchar_t Name[MAX_DATA_LEN], str[MAX_DATA_LEN], sID[MAX_DATA_LEN], *szData = nullptr, *search; - - // replace spaces with %20 - char loc[256]; - T2Utf szSearchName(name); - mir_snprintf(loc, sData->SearchURL, mir_urlEncode(szSearchName).c_str()); - if (InternetDownloadFile(loc, nullptr, nullptr, &szData) == 0) { - wchar_t *szInfo = szData; - search = wcsstr(szInfo, sData->NotFoundStr); // determine if data is available - if (search == nullptr) { // if data is found - // test if it is single result - if (sData->Single.Available && sData->Multiple.Available) - search = wcsstr(szInfo, sData->SingleStr); - // for single result - if (sData->Single.Available && (search != nullptr || !sData->Multiple.Available)) { // single result - // if station ID appears first in the downloaded data - if (!mir_wstrcmpi(sData->Single.First, L"ID")) { - GetDataValue(&sData->Single.ID, str, &szInfo); - mir_snwprintf(sID, L"%s/%s", svc, str); - GetDataValue(&sData->Single.Name, Name, &szInfo); - } - // if station name appears first in the downloaded data - else if (!mir_wstrcmpi(sData->Single.First, L"NAME")) { - GetDataValue(&sData->Single.Name, Name, &szInfo); - GetDataValue(&sData->Single.ID, str, &szInfo); - mir_snwprintf(sID, L"%s/%s", svc, str); - } - else - str[0] = 0; - - // 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) - wcsncpy(Name, name, _countof(Name)); - - // set the data and broadcast it - PROTOSEARCHRESULT psr = { sizeof(psr) }; - psr.flags = PSR_UNICODE; - psr.nick.w = Name; - psr.firstName.w = L" "; - psr.lastName.w = svcname; - psr.email.w = sID; - psr.id.w = sID; - ProtoBroadcastAck(MODULENAME, 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 - while (true) { - // if station ID appears first in the downloaded data - if (!mir_wstrcmpi(sData->Multiple.First, L"ID")) { - GetDataValue(&sData->Multiple.ID, str, &szInfo); - mir_snwprintf(sID, L"%s/%s", svc, str); - GetDataValue(&sData->Multiple.Name, Name, &szInfo); - } - // if station name appears first in the downloaded data - else if (!mir_wstrcmpi(sData->Multiple.First, L"NAME")) { - GetDataValue(&sData->Multiple.Name, Name, &szInfo); - GetDataValue(&sData->Multiple.ID, str, &szInfo); - mir_snwprintf(sID, L"%s/%s", svc, str); - } - else - break; - - // 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) - wcsncpy(Name, name, _countof(Name)); - - PROTOSEARCHRESULT psr = { sizeof(psr) }; - psr.flags = PSR_UNICODE; - psr.nick.w = Name; - psr.firstName.w = L""; - psr.lastName.w = svcname; - psr.email.w = sID; - psr.id.w = sID; - ProtoBroadcastAck(MODULENAME, 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(wchar_t *name, const int searchId) -{ - // search every weather service using the search station name - WIDATALIST *Item = WIHead; - while (Item != nullptr) { - 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; + psr.id.w = id.GetBuffer(); + psr.nick.w = address1.GetBuffer(); + psr.firstName.w = address2.GetBuffer(); + ProtoBroadcastAck(NULL, ACKTYPE_SEARCH, ACKRESULT_DATA, (HANDLE)searchId, (LPARAM)&psr); } return 0; } -// ======================MENU ITEM FUNCTION ============ - -// add a new weather station via find/add dialog -int WeatherAdd(WPARAM, LPARAM) +int CWeatherProto::NameSearch(wchar_t *name, int searchId) { - db_set_s(0, "FindAdd", "LastSearched", "Weather"); - CallService(MS_FINDADD_FINDADD, 0, 0); - return 0; + return IDSearch(name, searchId); } diff --git a/protocols/Weather/src/weather_contacts.cpp b/protocols/Weather/src/weather_contacts.cpp index 2833521275..2f5a08f4ef 100644 --- a/protocols/Weather/src/weather_contacts.cpp +++ b/protocols/Weather/src/weather_contacts.cpp @@ -25,23 +25,20 @@ the contact. #include "stdafx.h" -static void OpenUrl(wchar_t *format, wchar_t *id) +bool CWeatherProto::IsMyContact(MCONTACT hContact) { - wchar_t loc[512]; - GetID(id); - mir_snwprintf(loc, format, id); - Utils_OpenUrlW(loc); + return hContact && !mir_strcmp(m_szModuleName, Proto_GetBaseAccountName(hContact)); } -//============ BASIC CONTACTS FUNCTIONS AND LINKS ============ - +///////////////////////////////////////////////////////////////////////////////////////// // view weather log for the contact // wParam = current contact -INT_PTR ViewLog(WPARAM wParam, LPARAM lParam) + +INT_PTR CWeatherProto::ViewLog(WPARAM wParam, LPARAM lParam) { // see if the log path is set DBVARIANT dbv; - if (!g_plugin.getWString(wParam, "Log", &dbv)) { + if (!getWString(wParam, "Log", &dbv)) { if (dbv.pszVal[0] != 0) ShellExecute((HWND)lParam, L"open", dbv.pwszVal, L"", L"", SW_SHOW); db_free(&dbv); @@ -52,352 +49,203 @@ INT_PTR ViewLog(WPARAM wParam, LPARAM lParam) return 0; } +///////////////////////////////////////////////////////////////////////////////////////// // read complete forecast // wParam = current contact -INT_PTR LoadForecast(WPARAM wParam, LPARAM) + +INT_PTR CWeatherProto::LoadForecast(WPARAM hContact, LPARAM) { - wchar_t id[256], loc2[256]; - GetStationID(wParam, id, _countof(id)); - if (id[0] != 0) { - // check if the complte forecast URL is set. If it is not, display warning and quit - if (db_get_wstatic(wParam, MODULENAME, "InfoURL", loc2, _countof(loc2)) || loc2[0] == 0) { - MessageBox(nullptr, TranslateT("The URL for complete forecast has not been set. You can set it from the Edit Settings dialog."), TranslateT("Weather Protocol"), MB_ICONINFORMATION); - return 1; - } + CMStringW wszID(getMStringW(hContact, "ID")); + if (!wszID.IsEmpty()) { // set the url and open the webpage - OpenUrl(loc2, id); + CMStringA szUrl("https://www.visualcrossing.com/weather-forecast/" + mir_urlEncode(T2Utf(wszID)) + "/metric"); + Utils_OpenUrl(szUrl); } return 0; } +///////////////////////////////////////////////////////////////////////////////////////// // load weather map // wParam = current contact -INT_PTR WeatherMap(WPARAM wParam, LPARAM) -{ - wchar_t id[256], loc2[256]; - GetStationID(wParam, id, _countof(id)); - if (id[0] != 0) { - // check if the weather map URL is set. If it is not, display warning and quit - if (db_get_wstatic(wParam, MODULENAME, "MapURL", loc2, _countof(loc2)) || loc2[0] == 0) { - MessageBox(nullptr, TranslateT("The URL for weather map has not been set. You can set it from the Edit Settings dialog."), TranslateT("Weather Protocol"), MB_ICONINFORMATION); - return 1; - } +INT_PTR CWeatherProto::WeatherMap(WPARAM hContact, LPARAM) +{ + CMStringW wszID(getMStringW(hContact, "ID")); + if (!wszID.IsEmpty()) { // set the url and open the webpage - OpenUrl(loc2, id); + CMStringA szUrl("https://www.visualcrossing.com/weather-history/" + mir_urlEncode(T2Utf(wszID)) + "/metric"); + Utils_OpenUrl(szUrl); } return 0; } -//============ EDIT SETTINGS ============ - -typedef struct -{ - MCONTACT hContact; - HICON hRename; - HICON hUserDetail; - HICON hFile; - HICON hSrchAll; -} CntSetWndDataType; - +///////////////////////////////////////////////////////////////////////////////////////// // edit weather settings // lParam = current contact -static INT_PTR CALLBACK DlgProcChange(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam) + +class CEditDlg : public CWeatherDlgBase { - DBVARIANT dbv; - wchar_t str[MAX_DATA_LEN], str2[256], city[256], filter[256], *chop; - char loc[512]; - OPENFILENAME ofn; // common dialog box structure MCONTACT hContact; - WIDATA *sData; - CntSetWndDataType *wndData = nullptr; - - switch (msg) { - case WM_INITDIALOG: - TranslateDialogDefault(hwndDlg); - - wndData = (CntSetWndDataType*)mir_alloc(sizeof(CntSetWndDataType)); - wndData->hContact = hContact = lParam; - wndData->hRename = Skin_LoadIcon(SKINICON_OTHER_RENAME); - wndData->hUserDetail = Skin_LoadIcon(SKINICON_OTHER_USERDETAILS); - wndData->hFile = Skin_LoadIcon(SKINICON_EVENT_FILE); - wndData->hSrchAll = Skin_LoadIcon(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); + CCtrlEdit edtName; + CCtrlButton btnExternal, btnChange; + CCtrlMButton btnBrowse; + + wchar_t str[MAX_DATA_LEN], str2[256]; + +public: + CEditDlg(CWeatherProto *ppro, MCONTACT _1) : + CWeatherDlgBase(ppro, IDD_EDIT), + hContact(_1), + edtName(this, IDC_NAME), + btnBrowse(this, IDC_BROWSE, SKINICON_EVENT_FILE, LPGEN("Browse")), + btnChange(this, IDC_CHANGE), + btnExternal(this, IDC_External) + { + edtName.OnChange = Callback(this, &CEditDlg::onChanged_Name); + + btnBrowse.OnClick = Callback(this, &CEditDlg::onClick_Browse); + btnChange.OnClick = Callback(this, &CEditDlg::onClick_Change); + btnExternal.OnClick = Callback(this, &CEditDlg::onClick_External); + } + + bool OnInitDialog() override + { // 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)LPGENW("Get city name from ID"), BATF_UNICODE); - SendDlgItemMessage(hwndDlg, IDC_SVCINFO, BUTTONADDTOOLTIP, (WPARAM)LPGENW("Weather INI information"), BATF_UNICODE); - SendDlgItemMessage(hwndDlg, IDC_BROWSE, BUTTONADDTOOLTIP, (WPARAM)LPGENW("Browse"), BATF_UNICODE); - SendDlgItemMessage(hwndDlg, IDC_VIEW1, BUTTONADDTOOLTIP, (WPARAM)LPGENW("View webpage"), BATF_UNICODE); - SendDlgItemMessage(hwndDlg, IDC_RESET1, BUTTONADDTOOLTIP, (WPARAM)LPGENW("Reset to default"), BATF_UNICODE); - SendDlgItemMessage(hwndDlg, IDC_VIEW2, BUTTONADDTOOLTIP, (WPARAM)LPGENW("View webpage"), BATF_UNICODE); - SendDlgItemMessage(hwndDlg, IDC_RESET2, BUTTONADDTOOLTIP, (WPARAM)LPGENW("Reset to default"), BATF_UNICODE); + btnBrowse.MakeFlat(); // save the handle for the contact - WindowList_Add(hWindowList, hwndDlg, hContact); + WindowList_Add(hWindowList, m_hwnd, hContact); // start to get the settings // if the setting not exist, leave the dialog box blank - if (!g_plugin.getWString(hContact, "ID", &dbv)) { - SetDlgItemText(hwndDlg, IDC_ID, dbv.pwszVal); + DBVARIANT dbv; + if (!m_proto->getWString(hContact, "ID", &dbv)) { + SetDlgItemText(m_hwnd, IDC_ID, dbv.pwszVal); // check if the station is a default station - CheckDlgButton(hwndDlg, IDC_DEFA, mir_wstrcmp(dbv.pwszVal, opt.Default) != 0 ? BST_CHECKED : BST_UNCHECKED); + CheckDlgButton(m_hwnd, IDC_DEFA, mir_wstrcmp(dbv.pwszVal, m_proto->opt.Default) != 0 ? BST_CHECKED : BST_UNCHECKED); db_free(&dbv); } - if (!g_plugin.getWString(hContact, "Nick", &dbv)) { - SetDlgItemText(hwndDlg, IDC_NAME, dbv.pwszVal); + if (!m_proto->getWString(hContact, "Nick", &dbv)) { + SetDlgItemText(m_hwnd, IDC_NAME, dbv.pwszVal); db_free(&dbv); } - if (!g_plugin.getWString(hContact, "Log", &dbv)) { - SetDlgItemText(hwndDlg, IDC_LOG, dbv.pwszVal); + if (!m_proto->getWString(hContact, "Log", &dbv)) { + SetDlgItemText(m_hwnd, IDC_LOG, dbv.pwszVal); // if the log path is not empty, check the checkbox for external log - if (dbv.pwszVal[0]) CheckDlgButton(hwndDlg, IDC_External, BST_CHECKED); + if (dbv.pwszVal[0]) CheckDlgButton(m_hwnd, IDC_External, BST_CHECKED); db_free(&dbv); } // enable/disable the browse button depending on the value of external log checkbox - EnableWindow(GetDlgItem(hwndDlg, IDC_BROWSE), (uint8_t)IsDlgButtonChecked(hwndDlg, IDC_External)); + EnableWindow(GetDlgItem(m_hwnd, IDC_BROWSE), (uint8_t)IsDlgButtonChecked(m_hwnd, IDC_External)); // other checkbox options - CheckDlgButton(hwndDlg, IDC_DPop, g_plugin.getByte(hContact, "DPopUp", FALSE) ? BST_CHECKED : BST_UNCHECKED); - CheckDlgButton(hwndDlg, IDC_DAutoUpdate, g_plugin.getByte(hContact, "DAutoUpdate", FALSE) ? BST_CHECKED : BST_UNCHECKED); - CheckDlgButton(hwndDlg, IDC_Internal, g_plugin.getByte(hContact, "History", 0) ? BST_CHECKED : BST_UNCHECKED); - - if (!g_plugin.getWString(hContact, "InfoURL", &dbv)) { - SetDlgItemText(hwndDlg, IDC_IURL, dbv.pwszVal); - db_free(&dbv); - } - if (!g_plugin.getWString(hContact, "MapURL", &dbv)) { - SetDlgItemText(hwndDlg, IDC_MURL, dbv.pwszVal); - db_free(&dbv); - } + CheckDlgButton(m_hwnd, IDC_DPop, m_proto->getByte(hContact, "DPopUp", FALSE) ? BST_CHECKED : BST_UNCHECKED); + CheckDlgButton(m_hwnd, IDC_DAutoUpdate, m_proto->getByte(hContact, "DAutoUpdate", FALSE) ? BST_CHECKED : BST_UNCHECKED); + CheckDlgButton(m_hwnd, IDC_Internal, m_proto->getByte(hContact, "History", 0) ? BST_CHECKED : BST_UNCHECKED); // display the dialog box and free memory - Utils_RestoreWindowPositionNoMove(hwndDlg, NULL, MODULENAME, "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, _countof(str)); - chop = wcschr(str, '/'); - if (chop == nullptr) - 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, _countof(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, _countof(str)); - GetSvc(str); - sData = GetWIData(str); - GetDlgItemText(hwndDlg, IDC_ID, str, _countof(str)); - GetID(str); - // if ID search is available, do it - if (sData->IDSearch.Available) { - // load the page - mir_snprintf(loc, sData->IDSearch.SearchURL, str); - str[0] = 0; - wchar_t *pData = nullptr; - if (InternetDownloadFile(loc, nullptr, sData->UserAgent, &pData) == 0) { - wchar_t *szInfo = pData; - wchar_t *search = wcsstr(szInfo, sData->IDSearch.NotFoundStr); - - // if the page is found (ie. valid ID), get the name of the city - if (search == nullptr) - GetDataValue(&sData->IDSearch.Name, str, &szInfo); - } - // free memory - mir_free(pData); - } + Utils_RestoreWindowPositionNoSize(m_hwnd, NULL, MODULENAME, "EditSetting_"); + ShowWindow(m_hwnd, SW_SHOW); + return true; + } - // 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), (uint8_t)IsDlgButtonChecked(hwndDlg, IDC_External)); - if (!(uint8_t)IsDlgButtonChecked(hwndDlg, IDC_External)) - return TRUE; - __fallthrough; - - case IDC_BROWSE: - // browse for the external log file - GetDlgItemText(hwndDlg, IDC_LOG, str, _countof(str)); - // Initialize OPENFILENAME - memset(&ofn, 0, sizeof(OPENFILENAME)); - ofn.lStructSize = sizeof(OPENFILENAME); - ofn.hwndOwner = hwndDlg; - ofn.lpstrFile = str; - ofn.nMaxFile = _countof(str); - - // set filters - mir_snwprintf(filter, L"%s (*.txt)%c*.txt%c%s (*.*)%c*.*%c%c", TranslateT("Text Files"), 0, 0, TranslateT("All Files"), 0, 0, 0); - ofn.lpstrFilter = filter; - ofn.nFilterIndex = 1; - ofn.lpstrFileTitle = nullptr; - ofn.nMaxFileTitle = 0; - ofn.lpstrInitialDir = nullptr; - 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, _countof(str)); - if (str[0] == 0) - return TRUE; - GetDlgItemText(hwndDlg, IDC_ID, str2, _countof(str2)); - OpenUrl(str, str2); - break; - - case IDC_VIEW2: - // view the page for weather map - GetDlgItemText(hwndDlg, IDC_MURL, str, _countof(str)); - if (str[0] == 0) - return TRUE; - GetDlgItemText(hwndDlg, IDC_ID, str2, _countof(str2)); - OpenUrl(str, str2); - break; - - case IDC_RESET1: - // reset the more info url to service default - GetDlgItemText(hwndDlg, IDC_ID, str, _countof(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, _countof(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, _countof(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, _countof(str)); - g_plugin.setWString(hContact, "ID", str); - if ((uint8_t)IsDlgButtonChecked(hwndDlg, IDC_DEFA)) { // if default station is set - mir_wstrcpy(opt.Default, str); - opt.DefStn = hContact; - g_plugin.setWString("Default", opt.Default); - } - GetDlgItemText(hwndDlg, IDC_NAME, city, _countof(city)); - g_plugin.setWString(hContact, "Nick", city); - mir_snwprintf(str2, TranslateT("Current weather information for %s."), city); - if ((uint8_t)IsDlgButtonChecked(hwndDlg, IDC_External)) { - GetDlgItemText(hwndDlg, IDC_LOG, str, _countof(str)); - g_plugin.setWString(hContact, "Log", str); - } - else g_plugin.delSetting(hContact, "Log"); - - GetDlgItemText(hwndDlg, IDC_IURL, str, _countof(str)); - g_plugin.setWString(hContact, "InfoURL", str); - - GetDlgItemText(hwndDlg, IDC_MURL, str, _countof(str)); - g_plugin.setWString(hContact, "MapURL", str); - g_plugin.setWord(hContact, "Status", ID_STATUS_OFFLINE); - g_plugin.setWord(hContact, "StatusIcon", -1); - AvatarDownloaded(hContact); - g_plugin.setWString(hContact, "About", str2); - g_plugin.setByte(hContact, "History", (uint8_t)IsDlgButtonChecked(hwndDlg, IDC_Internal)); - g_plugin.setByte(hContact, "Overwrite", (uint8_t)IsDlgButtonChecked(hwndDlg, IDC_Overwrite)); - g_plugin.setByte(hContact, "File", (uint8_t)IsDlgButtonChecked(hwndDlg, IDC_External)); - g_plugin.setByte(hContact, "DPopUp", (uint8_t)IsDlgButtonChecked(hwndDlg, IDC_DPop)); - g_plugin.setByte(hContact, "DAutoUpdate", (uint8_t)IsDlgButtonChecked(hwndDlg, IDC_DAutoUpdate)); - - // re-enable the protocol and update the data for the station - g_plugin.setString(hContact, "LastCondition", "None"); - UpdateSingleStation(hContact, 0); - __fallthrough; - - case IDCANCEL: - // remove the dialog from window list and close it - DestroyWindow(hwndDlg); - break; + void OnDestroy() override + { + SetWindowLongPtr(m_hwnd, GWLP_USERDATA, 0); + + WindowList_Remove(hWindowList, m_hwnd); + Utils_SaveWindowPosition(m_hwnd, NULL, MODULENAME, "EditSetting_"); + } + + void onChanged_Name(CCtrlEdit *) + { + // check if station name is entered + // if not, don't let user change the setting + GetDlgItemText(m_hwnd, IDC_NAME, str, _countof(str)); + EnableWindow(GetDlgItem(m_hwnd, IDC_CHANGE), str[0] != 0); + } + + void onClick_External(CCtrlButton *) + { + // enable/disable the borwse button depending if the external log is enabled + EnableWindow(GetDlgItem(m_hwnd, IDC_BROWSE), (uint8_t)IsDlgButtonChecked(m_hwnd, IDC_External)); + if (!(uint8_t)IsDlgButtonChecked(m_hwnd, IDC_External)) + return; + + onClick_Browse(0); + } + + void onClick_Browse(CCtrlButton *) + { + // browse for the external log file + GetDlgItemText(m_hwnd, IDC_LOG, str, _countof(str)); + + // Initialize OPENFILENAME + OPENFILENAME ofn = {}; + ofn.lStructSize = sizeof(OPENFILENAME); + ofn.hwndOwner = m_hwnd; + ofn.lpstrFile = str; + ofn.nMaxFile = _countof(str); + + // set filters + wchar_t filter[256]; + mir_snwprintf(filter, L"%s (*.txt)%c*.txt%c%s (*.*)%c*.*%c%c", TranslateT("Text Files"), 0, 0, TranslateT("All Files"), 0, 0, 0); + ofn.lpstrFilter = filter; + ofn.nFilterIndex = 1; + ofn.lpstrFileTitle = nullptr; + ofn.nMaxFileTitle = 0; + ofn.lpstrInitialDir = nullptr; + ofn.Flags = OFN_PATHMUSTEXIST; + + // Display a Open dialog box and put the file name on the dialog + if (GetOpenFileName(&ofn)) + SetDlgItemText(m_hwnd, IDC_LOG, ofn.lpstrFile); + + // if there is no log file specified, disable external logging + EnableWindow(GetDlgItem(m_hwnd, IDC_CHANGE), ofn.lpstrFile[0] != 0); + } + + void onClick_Change(CCtrlButton *) + { + // temporary disable the protocol while applying the change + // start writing the new settings to database + GetDlgItemText(m_hwnd, IDC_ID, str, _countof(str)); + m_proto->setWString(hContact, "ID", str); + if ((uint8_t)IsDlgButtonChecked(m_hwnd, IDC_DEFA)) { // if default station is set + mir_wstrcpy(m_proto->opt.Default, str); + m_proto->opt.DefStn = hContact; + m_proto->setWString("Default", m_proto->opt.Default); + } + + wchar_t city[256]; + GetDlgItemText(m_hwnd, IDC_NAME, city, _countof(city)); + m_proto->setWString(hContact, "Nick", city); + mir_snwprintf(str2, TranslateT("Current weather information for %s."), city); + if ((uint8_t)IsDlgButtonChecked(m_hwnd, IDC_External)) { + GetDlgItemText(m_hwnd, IDC_LOG, str, _countof(str)); + m_proto->setWString(hContact, "Log", str); } - 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); - IcoLib_ReleaseIcon(wndData->hFile); - IcoLib_ReleaseIcon(wndData->hRename); - IcoLib_ReleaseIcon(wndData->hSrchAll); - IcoLib_ReleaseIcon(wndData->hUserDetail); - mir_free(wndData); - SetWindowLongPtr(hwndDlg, GWLP_USERDATA, 0); - - WindowList_Remove(hWindowList, hwndDlg); - Utils_SaveWindowPosition(hwndDlg, NULL, MODULENAME, "EditSetting_"); - break; + else m_proto->delSetting(hContact, "Log"); + + m_proto->setWord(hContact, "Status", ID_STATUS_OFFLINE); + m_proto->setWord(hContact, "StatusIcon", -1); + m_proto->AvatarDownloaded(hContact); + m_proto->setWString(hContact, "About", str2); + m_proto->setByte(hContact, "History", (uint8_t)IsDlgButtonChecked(m_hwnd, IDC_Internal)); + m_proto->setByte(hContact, "Overwrite", (uint8_t)IsDlgButtonChecked(m_hwnd, IDC_Overwrite)); + m_proto->setByte(hContact, "File", (uint8_t)IsDlgButtonChecked(m_hwnd, IDC_External)); + m_proto->setByte(hContact, "DPopUp", (uint8_t)IsDlgButtonChecked(m_hwnd, IDC_DPop)); + m_proto->setByte(hContact, "DAutoUpdate", (uint8_t)IsDlgButtonChecked(m_hwnd, IDC_DAutoUpdate)); + + // re-enable the protocol and update the data for the station + m_proto->setString(hContact, "LastCondition", "None"); + m_proto->UpdateSingleStation(hContact, 0); } - return FALSE; -} +}; -// show edit settings dialog -// wParam = current contact -INT_PTR EditSettings(WPARAM wParam, LPARAM) +INT_PTR CWeatherProto::EditSettings(WPARAM wParam, LPARAM) { HWND hEditDlg = WindowList_Find(hWindowList, wParam); @@ -410,34 +258,29 @@ INT_PTR EditSettings(WPARAM wParam, LPARAM) else { // if the dialog box is not opened, open a new one if (IsMyContact(wParam)) - CreateDialogParam(g_plugin.getInst(), MAKEINTRESOURCE(IDD_EDIT), nullptr, DlgProcChange, (LPARAM)wParam); + (new CEditDlg(this, wParam))->Create(); } return 0; } -//============ 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) -{ - if (!IsMyContact(wParam)) - return 0; - removeWindow(wParam); +bool CWeatherProto::OnContactDeleted(MCONTACT hContact, uint32_t) +{ + RemoveFrameWindow(hContact); // exit this function if it is not default station - ptrW tszID(g_plugin.getWStringA(wParam, "ID")); - if (tszID != NULL) - if (mir_wstrcmp(tszID, opt.Default)) - return 0; + ptrW tszID(getWStringA(hContact, "ID")); + if (mir_wstrcmp(tszID, opt.Default)) + return true; // now the default station is deleted, try to get a new one // start looking for other weather stations - for (auto &hContact : Contacts(MODULENAME)) { - tszID = g_plugin.getWStringA(hContact, "ID"); + for (auto &cc: AccContacts()) { + tszID = getWStringA(cc, "ID"); if (tszID == NULL) continue; @@ -445,27 +288,21 @@ int ContactDeleted(WPARAM wParam, LPARAM) // this is the first weather station encountered from the search if (mir_wstrcmp(opt.Default, tszID)) { wcsncpy_s(opt.Default, tszID, _TRUNCATE); - opt.DefStn = hContact; - ptrW tszNick(g_plugin.getWStringA(hContact, "Nick")); + opt.DefStn = cc; + ptrW tszNick(getWStringA(cc, "Nick")); if (tszNick != NULL) { wchar_t str[255]; mir_snwprintf(str, TranslateT("%s is now the default weather station"), (wchar_t*)tszNick); MessageBox(nullptr, str, TranslateT("Weather Protocol"), MB_OK | MB_ICONINFORMATION); } - g_plugin.setWString("Default", opt.Default); - return 0; // exit this function quickly + setWString("Default", opt.Default); + return true; } } // got here if no more weather station left opt.Default[0] = 0; // no default station opt.DefStn = NULL; - g_plugin.setWString("Default", opt.Default); - return 0; -} - -BOOL IsMyContact(MCONTACT hContact) -{ - const char *szProto = Proto_GetBaseAccountName(hContact); - return szProto != nullptr && mir_strcmp(MODULENAME, szProto) == 0; + setWString("Default", opt.Default); + return true; } diff --git a/protocols/Weather/src/weather_conv.cpp b/protocols/Weather/src/weather_conv.cpp index 649ca37a91..4d2c79f0ce 100644 --- a/protocols/Weather/src/weather_conv.cpp +++ b/protocols/Weather/src/weather_conv.cpp @@ -25,12 +25,12 @@ string conversions, display text parsing, etc #include "stdafx.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(wchar_t *s) + +BOOL is_number(const wchar_t *s) { BOOL tag = FALSE; // looking character by character @@ -47,7 +47,7 @@ BOOL is_number(wchar_t *s) return FALSE; } -static void numToStr(double num, wchar_t *str, size_t strSize) +void CWeatherProto::numToStr(double num, wchar_t *str, size_t strSize) { int i = (int)(num * (opt.NoFrac ? 10 : 100)); int u = abs(i); @@ -69,22 +69,18 @@ static void numToStr(double num, wchar_t *str, size_t strSize) mir_snwprintf(str, strSize, L"%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(wchar_t *tempchar, wchar_t *unit, wchar_t *str) + +void CWeatherProto::GetTemp(const wchar_t *tempchar, const wchar_t *unit, wchar_t *str) { // unit can be C, F double temp; wchar_t tstr[20]; - TrimString(tempchar); - if (tempchar[0] == '-' && tempchar[1] == ' ') - memmove(&tempchar[1], &tempchar[2], sizeof(wchar_t) * (mir_wstrlen(&tempchar[2]) + 1)); - // quit if the value obtained is N/A or not a number if (!mir_wstrcmp(tempchar, NODATA) || !mir_wstrcmp(tempchar, L"N/A")) { mir_wstrcpy(str, tempchar); @@ -123,11 +119,13 @@ void GetTemp(wchar_t *tempchar, wchar_t *unit, wchar_t *str) } } +///////////////////////////////////////////////////////////////////////////////////////// // 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(wchar_t *tempchar, wchar_t *unit, wchar_t *str) + +void CWeatherProto::GetPressure(const wchar_t *tempchar, const wchar_t *unit, wchar_t *str) { // unit can be kPa, hPa, mb, in, mm, torr double tempunit = 0, output; @@ -180,11 +178,13 @@ void GetPressure(wchar_t *tempchar, wchar_t *unit, wchar_t *str) } } +///////////////////////////////////////////////////////////////////////////////////////// // 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(wchar_t *tempchar, wchar_t *unit, wchar_t *str) + +void CWeatherProto::GetSpeed(const wchar_t *tempchar, const wchar_t *unit, wchar_t *str) { // unit can be km/h, mph, m/s, knots double tempunit; @@ -229,11 +229,13 @@ void GetSpeed(wchar_t *tempchar, wchar_t *unit, wchar_t *str) } } +///////////////////////////////////////////////////////////////////////////////////////// // 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(wchar_t *tempchar, wchar_t *unit, wchar_t *str) + +void CWeatherProto::GetDist(const wchar_t *tempchar, const wchar_t *unit, wchar_t *str) { // unit can be km, miles double tempunit = 0, output; @@ -269,11 +271,13 @@ void GetDist(wchar_t *tempchar, wchar_t *unit, wchar_t *str) } } +///////////////////////////////////////////////////////////////////////////////////////// // 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(wchar_t *tempchar, wchar_t *unit, wchar_t *str) + +void CWeatherProto::GetElev(const wchar_t *tempchar, const wchar_t *unit, wchar_t *str) { // unit can be ft, m double tempunit = 0, output; @@ -309,73 +313,9 @@ void GetElev(wchar_t *tempchar, wchar_t *unit, wchar_t *str) } } -//============ 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 wchar_t *statusStr[MAX_COND] = { L"Lightning", L"Fog", L"Snow", L"Rain", L"Partly Cloudy", L"Cloudy", L"Sunny", L"N/A", L"Rain Shower", L"Snow Shower"}; -static const uint16_t statusValue[MAX_COND] = { LIGHT, FOG, SNOW, RAIN, PCLOUDY, CLOUDY, SUNNY, NA, RSHOWER, SSHOWER }; - -uint16_t GetIcon(const wchar_t *cond, WIDATA *Data) -{ - // set the icon using ini - for (int i = 0; i < _countof(statusValue); i++) - if (IsContainedInCondList(cond, &Data->CondList[i])) - return statusValue[i]; - - // internal detection - if (wcsstr(cond, L"mainy sunny") || wcsstr(cond, L"mainy clear") || wcsstr(cond, L"partly sunny") || wcsstr(cond, L"partly cloudy") || wcsstr(cond, L"mostly") || wcsstr(cond, L"clouds")) - return PCLOUDY; - - if (wcsstr(cond, L"sunny") || wcsstr(cond, L"clear") || wcsstr(cond, L"fair")) - return SUNNY; - - if (wcsstr(cond, L"thunder") || wcsstr(cond, L"t-storm")) - return LIGHT; - - if (wcsstr(cond, L"cloud") || wcsstr(cond, L"overcast")) - return CLOUDY; - - if (wcsstr(cond, L"fog") || wcsstr(cond, L"mist") || wcsstr(cond, L"smoke") || wcsstr(cond, L"sand") || wcsstr(cond, L"dust") || wcsstr(cond, L"haze")) - return FOG; - - if (wcsstr(cond, L"snow shower")) - return SSHOWER; - - if (wcsstr(cond, L"snow") || wcsstr(cond, L"ice") || wcsstr(cond, L"freezing") || wcsstr(cond, L"wintry")) - return SNOW; - - if (wcsstr(cond, L"rain shower")) - return RSHOWER; - - if (wcsstr(cond, L"drizzle") || wcsstr(cond, L"rain")) - return RAIN; - - // set the icon using langpack - for (int i = 0; i < _countof(statusStr)-1; i++) { - wchar_t LangPackStr[64], LangPackStr1[128]; - int j = 0; - do { - j++; - // using the format _T("# Weather <condition name> <counter> #" - mir_snwprintf(LangPackStr, L"# Weather %s %i #", statusStr[i], j); - wcsncpy_s(LangPackStr1, TranslateW(LangPackStr), _TRUNCATE); - CharLowerBuff(LangPackStr1, (uint32_t)mir_wstrlen(LangPackStr1)); - if (wcsstr(cond, LangPackStr1) != nullptr) - return statusValue[i]; - // loop until the translation string exists (ie, the translated string is differ from original) - } while (mir_wstrcmp(TranslateW(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(wchar_t *str) { bool nextUp = true; @@ -391,9 +331,10 @@ void CaseConv(wchar_t *str) } } +///////////////////////////////////////////////////////////////////////////////////////// // the next 2 functions are copied from miranda source // str = the string to modify -// + void TrimString(char *str) { size_t len, start; @@ -414,7 +355,9 @@ void TrimString(wchar_t *str) memmove(str, str + start, (len - start + 1) * sizeof(wchar_t)); } +///////////////////////////////////////////////////////////////////////////////////////// // convert \t to tab and \n to linefeed + void ConvertBackslashes(char *str) { for (char *pstr = str; *pstr; pstr = CharNextA(pstr)) { @@ -429,10 +372,12 @@ void ConvertBackslashes(char *str) } } +///////////////////////////////////////////////////////////////////////////////////////// // replace spaces with _T("%20" // dis = original string // return value = the modified string with space -> _T("%20" -char *GetSearchStr(char *dis) + +char* GetSearchStr(char *dis) { char *pstr = dis; size_t len = mir_strlen(dis); @@ -448,13 +393,13 @@ char *GetSearchStr(char *dis) 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 -wchar_t *GetDisplay(WEATHERINFO *w, const wchar_t *dis, wchar_t *str) + +CMStringW GetDisplay(WEATHERINFO *w, const wchar_t *dis) { wchar_t lpzDate[32], chr; char name[256], temp[2]; @@ -462,7 +407,7 @@ wchar_t *GetDisplay(WEATHERINFO *w, const wchar_t *dis, wchar_t *str) size_t i; // Clear the string - str[0] = 0; + CMStringW str; // looking character by character for (i = 0; i < mir_wstrlen(dis); i++) { @@ -471,10 +416,10 @@ wchar_t *GetDisplay(WEATHERINFO *w, const wchar_t *dis, wchar_t *str) i++; chr = dis[i]; switch (chr) { - case '%': mir_wstrcat(str, L"%"); break; - case 't': mir_wstrcat(str, L"\t"); break; - case 'n': mir_wstrcat(str, L"\r\n"); break; - case '\\': mir_wstrcat(str, L"\\"); break; + case '%': str.Append(L"%"); break; + case 't': str.Append(L"\t"); break; + case 'n': str.Append(L"\r\n"); break; + case '\\': str.Append(L"\\"); break; } } @@ -485,29 +430,31 @@ wchar_t *GetDisplay(WEATHERINFO *w, const wchar_t *dis, wchar_t *str) // turn capitalized characters to small case if (chr < 'a' && chr != '[' && chr != '%') chr = (char)((int)chr + 32); switch (chr) { - case 'c': mir_wstrcat(str, w->cond); break; + case 'c': str.Append(w->cond); break; case 'd': // get the current date GetDateFormat(LOCALE_USER_DEFAULT, DATE_SHORTDATE, nullptr, nullptr, lpzDate, _countof(lpzDate)); - mir_wstrcat(str, lpzDate); break; - case 'e': mir_wstrcat(str, w->dewpoint); break; - case 'f': mir_wstrcat(str, w->feel); break; - case 'h': mir_wstrcat(str, w->high); break; - case 'i': mir_wstrcat(str, w->winddir); break; - case 'l': mir_wstrcat(str, w->low); break; - case 'm': mir_wstrcat(str, w->humid); break; - case 'n': mir_wstrcat(str, w->city); break; - case 'p': mir_wstrcat(str, w->pressure); break; - case 'r': mir_wstrcat(str, w->sunrise); break; - case 's': mir_wstrcat(str, w->id); break; - case 't': mir_wstrcat(str, w->temp); break; + str.Append(lpzDate); break; + case 'e': str.Append(w->dewpoint); break; + case 'f': str.Append(w->feel); break; + case 'h': str.Append(w->high); break; + case 'i': str.Append(w->winddir); break; + case 'l': str.Append(w->low); break; + case 'm': str.Append(w->humid); break; + case 'n': str.Append(w->city); break; + case 'p': str.Append(w->pressure); break; + case 'r': str.Append(w->sunrise); break; + case 's': str.Append(w->id); break; + case 't': str.Append(w->temp); break; case 'u': - if (mir_wstrcmp(w->update, NODATA)) mir_wstrcat(str, w->update); - else mir_wstrcat(str, TranslateT("<unknown time>")); + if (mir_wstrcmp(w->update, NODATA)) + str.Append(w->update); + else + str.Append(TranslateT("<unknown time>")); break; - case 'v': mir_wstrcat(str, w->vis); break; - case 'w': mir_wstrcat(str, w->wind); break; - case 'y': mir_wstrcat(str, w->sunset); break; - case '%': mir_wstrcat(str, L"%"); break; + case 'v': str.Append(w->vis); break; + case 'w': str.Append(w->wind); break; + case 'y': str.Append(w->sunset); break; + case '%': str.Append(L"%"); break; case '[': // custom variables i++; name[0] = 0; @@ -519,90 +466,77 @@ wchar_t *GetDisplay(WEATHERINFO *w, const wchar_t *dis, wchar_t *str) // access the database to get its value if (!db_get_ws(w->hContact, WEATHERCONDITION, name, &dbv)) { if (dbv.pwszVal != TranslateW(NODATA) && dbv.pwszVal != TranslateT("<Error>")) - mir_wstrcat(str, dbv.pwszVal); + str.Append(dbv.pwszVal); db_free(&dbv); } break; } } // if the character is not a variable, write the original character to the new string - else { - mir_snwprintf(lpzDate, L"%c", dis[i]); - mir_wstrcat(str, lpzDate); - } + else str.AppendChar(dis[i]); } return str; } -wchar_t svcReturnText[MAX_TEXT_SIZE]; -INT_PTR GetDisplaySvcFunc(WPARAM wParam, LPARAM lParam) -{ - WEATHERINFO winfo = LoadWeatherInfo(wParam); - return (INT_PTR)GetDisplay(&winfo, (wchar_t*)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(wchar_t *pszID) -{ - wchar_t *chop = wcschr(pszID, '/'); - if (chop != nullptr) - *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(wchar_t *pszID) -{ - wchar_t *chop = wcschr(pszID, '/'); - if (chop != nullptr) - mir_wstrcpy(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 -// + wchar_t *GetError(int code) { wchar_t *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; + case 10: str = TranslateT("Invalid ID format, missing \"/\" (10)"); break; + case 11: str = TranslateT("Invalid service (11)"); break; + case 12: str = TranslateT("Invalid station (12)"); break; + case 20: str = TranslateT("Weather service ini for this station is not found (20)"); break; + case 30: str = TranslateT("Netlib error - check your internet connection (30)"); break; + case 40: str = TranslateT("Empty data is retrieved (40)"); break; + case 42: str = TranslateT("Document not found (42)"); break; + case 43: str = TranslateT("Document too short to contain any weather data (43)"); break; + case 99: str = TranslateT("Unknown error (99)"); break; + // 100 Continue + // 101 Switching Protocols + // 200 OK + // 201 Created + // 202 Accepted + // 203 Non-Authoritative Information + case 204: str = TranslateT("HTTP Error: No content (204)"); break; + // 205 Reset Content + // 206 Partial Content + // 300 Multiple Choices + case 301: str = TranslateT("HTTP Error: Data moved (301)"); break; + // 302 Found + // 303 See Other + // 304 Not Modified + case 305: str = TranslateT("HTTP Error: Use proxy (305)"); break; + case 307: str = TranslateT("HTTP Error: Temporary redirect (307)"); break; + case 400: str = TranslateT("HTTP Error: Bad request (400)"); break; + case 401: str = TranslateT("HTTP Error: Unauthorized (401)"); break; + case 402: str = TranslateT("HTTP Error: Payment required (402)"); break; + case 403: str = TranslateT("HTTP Error: Forbidden (403)"); break; + case 404: str = TranslateT("HTTP Error: Not found (404)"); break; + case 405: str = TranslateT("HTTP Error: Method not allowed (405)"); break; + // 406 Not Acceptable + case 407: str = TranslateT("HTTP Error: Proxy authentication required (407)"); break; + // 408 Request Timeout + // 409 Conflict + case 410: str = TranslateT("HTTP Error: Gone (410)"); break; + // 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 + case 500: str = TranslateT("HTTP Error: Internal server error (500)"); break; + // 501 Not Implemented + case 502: str = TranslateT("HTTP Error: Bad gateway (502)"); break; + case 503: str = TranslateT("HTTP Error: Service unavailable (503)"); break; + case 504: str = TranslateT("HTTP Error: Gateway timeout (504)"); break; + // 505 HTTP Version Not Supported default: mir_snwprintf(str2, TranslateT("HTTP Error %i"), code); str = str2; diff --git a/protocols/Weather/src/weather_data.cpp b/protocols/Weather/src/weather_data.cpp index 0f3cf9ccc9..76e50ca139 100644 --- a/protocols/Weather/src/weather_data.cpp +++ b/protocols/Weather/src/weather_data.cpp @@ -25,31 +25,21 @@ saving individual weather data for a weather contact. #include "stdafx.h" -//============ LOAD WEATHER INFO FROM A CONTACT ============ -// get station ID from DB -// hContact = the current contact handle -// return value = the string for station ID -// -void GetStationID(MCONTACT hContact, wchar_t *id, int idlen) -{ - // accessing the database - if (db_get_wstatic(hContact, MODULENAME, "ID", id, idlen)) - id[0] = 0; -} - +///////////////////////////////////////////////////////////////////////////////////////// // initialize weather info by loading values from database // hContact = current contact handle // return value = the current weather information in WEATHERINFO struct -WEATHERINFO LoadWeatherInfo(MCONTACT hContact) + +WEATHERINFO CWeatherProto::LoadWeatherInfo(MCONTACT hContact) { // obtaining values from the DB // assuming station ID must exist at all time, but others does not have to // if the string is not found in database, a value of "N/A" is stored in the field WEATHERINFO winfo; winfo.hContact = hContact; - GetStationID(hContact, winfo.id, _countof(winfo.id)); + wcsncpy_s(winfo.id, getMStringW(hContact, "ID"), _countof(winfo.id)); - if (db_get_wstatic(hContact, MODULENAME, "Nick", winfo.city, _countof(winfo.city))) + if (db_get_wstatic(hContact, m_szModuleName, "Nick", winfo.city, _countof(winfo.city))) wcsncpy(winfo.city, NODATA, _countof(winfo.city) - 1); if (db_get_wstatic(hContact, WEATHERCONDITION, "Update", winfo.update, _countof(winfo.update))) wcsncpy(winfo.update, NODATA, _countof(winfo.update) - 1); @@ -82,64 +72,47 @@ WEATHERINFO LoadWeatherInfo(MCONTACT hContact) return winfo; } -// getting weather setting from database -// return 0 on success -int DBGetData(MCONTACT hContact, char *setting, DBVARIANT *dbv) -{ - if (db_get_ws(hContact, WEATHERCONDITION, setting, dbv)) { - size_t len = mir_strlen(setting) + 1; - char *set = (char*)alloca(len + 1); - *set = '#'; - memcpy(set + 1, setting, len); - - if (db_get_ws(hContact, WEATHERCONDITION, set, dbv)) - return 1; - } - return 0; -} - - -//============ ERASE OLD SETTINGS ============ -// +///////////////////////////////////////////////////////////////////////////////////////// // erase all current weather information from database // lastver = the last used version number in dword (using PLUGIN_MAKE_VERSION) -void EraseAllInfo() + +void CWeatherProto::EraseAllInfo() { wchar_t str[255]; int ContactCount = 0; MCONTACT LastContact = NULL; DBVARIANT dbv; // loop through all contacts - for (auto &hContact : Contacts(MODULENAME)) { - g_plugin.setWord(hContact, "Status", ID_STATUS_OFFLINE); - g_plugin.setWord(hContact, "StatusIcon", -1); + for (auto &hContact : AccContacts()) { + setWord(hContact, "Status", ID_STATUS_OFFLINE); + setWord(hContact, "StatusIcon", -1); db_unset(hContact, "CList", "MyHandle"); // clear all data - if (g_plugin.getWString(hContact, "Nick", &dbv)) { - g_plugin.setWString(hContact, "Nick", TranslateT("<Enter city name here>")); - g_plugin.setString(hContact, "LastLog", "never"); - g_plugin.setString(hContact, "LastCondition", "None"); - g_plugin.setString(hContact, "LastTemperature", "None"); + if (getWString(hContact, "Nick", &dbv)) { + setWString(hContact, "Nick", TranslateT("<Enter city name here>")); + setString(hContact, "LastLog", "never"); + setString(hContact, "LastCondition", "None"); + setString(hContact, "LastTemperature", "None"); } else db_free(&dbv); - DBDataManage(hContact, WDBM_REMOVE, 0, 0); + db_delete_module(hContact, WEATHERCONDITION); db_set_s(hContact, "UserInfo", "MyNotes", ""); // reset update tag - g_plugin.setByte(hContact, "IsUpdated", FALSE); + setByte(hContact, "IsUpdated", FALSE); // reset logging settings - if (!g_plugin.getWString(hContact, "Log", &dbv)) { - g_plugin.setByte(hContact, "File", (uint8_t)(dbv.pwszVal[0] != 0)); + if (!getWString(hContact, "Log", &dbv)) { + setByte(hContact, "File", (uint8_t)(dbv.pwszVal[0] != 0)); db_free(&dbv); } - else g_plugin.setByte(hContact, "File", FALSE); + else setByte(hContact, "File", FALSE); // if no default station find, assign a new one if (opt.Default[0] == 0) { - GetStationID(hContact, opt.Default, _countof(opt.Default)); + wcsncpy_s(opt.Default, getMStringW(hContact, "ID"), _countof(opt.Default)); opt.DefStn = hContact; - if (!g_plugin.getWString(hContact, "Nick", &dbv)) { + if (!getWString(hContact, "Nick", &dbv)) { mir_snwprintf(str, TranslateT("%s is now the default weather station"), dbv.pwszVal); db_free(&dbv); MessageBox(nullptr, str, TranslateT("Weather Protocol"), MB_OK | MB_ICONINFORMATION); @@ -147,7 +120,7 @@ void EraseAllInfo() } // get the handle of the default station if (opt.DefStn == NULL) { - if (!g_plugin.getWString(hContact, "ID", &dbv)) { + if (!getWString(hContact, "ID", &dbv)) { if (!mir_wstrcmp(dbv.pwszVal, opt.Default)) opt.DefStn = hContact; db_free(&dbv); @@ -161,281 +134,132 @@ void EraseAllInfo() // if (ContactCount != 0) status = ONLINE; // in case where the default station is missing if (opt.DefStn == NULL && ContactCount != 0) { - if (!g_plugin.getWString(LastContact, "ID", &dbv)) { + if (!getWString(LastContact, "ID", &dbv)) { wcsncpy(opt.Default, dbv.pwszVal, _countof(opt.Default) - 1); db_free(&dbv); } opt.DefStn = LastContact; - if (!g_plugin.getWString(LastContact, "Nick", &dbv)) { + if (!getWString(LastContact, "Nick", &dbv)) { mir_snwprintf(str, TranslateT("%s is now the default weather station"), dbv.pwszVal); db_free(&dbv); MessageBox(nullptr, str, TranslateT("Weather Protocol"), MB_OK | MB_ICONINFORMATION); } } // save option in case of default station changed - g_plugin.setWString("Default", opt.Default); + setWString("Default", opt.Default); } -void ConvertDataValue(WIDATAITEM *UpdateData, wchar_t *Data) -{ - wchar_t str[MAX_DATA_LEN]; +///////////////////////////////////////////////////////////////////////////////////////// - // convert the unit - if (mir_wstrcmp(Data, TranslateT("<Error>")) && mir_wstrcmp(Data, NODATA) && mir_wstrcmp(Data, TranslateW(NODATA))) { - // temperature - if (!mir_wstrcmp(UpdateData->Name, L"Temperature") || !mir_wstrcmp(UpdateData->Name, L"High") || - !mir_wstrcmp(UpdateData->Name, L"Low") || !mir_wstrcmp(UpdateData->Name, L"Feel") || - !mir_wstrcmp(UpdateData->Name, L"Dew point") || - !mir_wstrcmpi(UpdateData->Unit, L"C") || !mir_wstrcmpi(UpdateData->Unit, L"F") || - !mir_wstrcmpi(UpdateData->Unit, L"K")) { - GetTemp(Data, UpdateData->Unit, str); - mir_wstrcpy(Data, str); - } - // pressure - else if (!mir_wstrcmp(UpdateData->Name, L"Pressure") || !mir_wstrcmpi(UpdateData->Unit, L"HPA") || - !mir_wstrcmpi(UpdateData->Unit, L"KPA") || !mir_wstrcmpi(UpdateData->Unit, L"MB") || - !mir_wstrcmpi(UpdateData->Unit, L"TORR") || !mir_wstrcmpi(UpdateData->Unit, L"IN") || - !mir_wstrcmpi(UpdateData->Unit, L"MM")) { - GetPressure(Data, UpdateData->Unit, str); - mir_wstrcpy(Data, str); - } - // speed - else if (!mir_wstrcmp(UpdateData->Name, L"Wind Speed") || !mir_wstrcmpi(UpdateData->Unit, L"KM/H") || - !mir_wstrcmpi(UpdateData->Unit, L"M/S") || !mir_wstrcmpi(UpdateData->Unit, L"MPH") || - !mir_wstrcmpi(UpdateData->Unit, L"KNOTS")) { - GetSpeed(Data, UpdateData->Unit, str); - mir_wstrcpy(Data, str); - } - // visibility - else if (!mir_wstrcmp(UpdateData->Name, L"Visibility") || !mir_wstrcmpi(UpdateData->Unit, L"KM") || - !mir_wstrcmpi(UpdateData->Unit, L"MILES")) { - GetDist(Data, UpdateData->Unit, str); - mir_wstrcpy(Data, str); - } - // elevation - else if (!mir_wstrcmp(UpdateData->Name, L"Elevation") || !mir_wstrcmpi(UpdateData->Unit, L"FT") || - !mir_wstrcmpi(UpdateData->Unit, L"M")) { - GetElev(Data, UpdateData->Unit, str); - mir_wstrcpy(Data, str); - } - // converting case for condition to the upper+lower format - else if (!mir_wstrcmpi(UpdateData->Unit, L"COND")) - CaseConv(Data); - // degree sign - else if (!mir_wstrcmpi(UpdateData->Unit, L"DEG")) { - if (!opt.DoNotAppendUnit) mir_wstrcat(Data, opt.DegreeSign); - } - // percent sign - else if (!mir_wstrcmpi(UpdateData->Unit, L"%")) { - if (!opt.DoNotAppendUnit) mir_wstrcat(Data, L"%"); - } - // truncating strings for day/month to 2 or 3 characters - else if (!mir_wstrcmpi(UpdateData->Unit, L"DAY") || !mir_wstrcmpi(UpdateData->Unit, L"MONTH")) - if (opt.dUnit > 1 && mir_wstrlen(Data) > opt.dUnit) - Data[opt.dUnit] = '\0'; - } -} +static wchar_t rumbs[][16] = { + LPGENW("N"), LPGENW("NNE"), LPGENW("NE"), LPGENW("ENE"), + LPGENW("E"), LPGENW("ESE"), LPGENW("ES"), LPGENW("SSE"), + LPGENW("S"), LPGENW("SSW"), LPGENW("SW"), LPGENW("WSW"), + LPGENW("W"), LPGENW("WNW"), LPGENW("WN"), LPGENW("NNW") +}; -//============ GET THE VALUE OF A DATAITEM ============ -// -// get the value of the data using the start, end strings -// UpdateData = the WIDATAITEM struct containing start, end, unit -// Data = the string containing weather data obtained from UpdateData -// global var. used: szInfo = the downloaded string -// -void GetDataValue(WIDATAITEM *UpdateData, wchar_t *Data, wchar_t **szData) +static wchar_t *degree2str(double angle) { - wchar_t last = 0, current, *start, *end; - unsigned startloc = 0, endloc = 0, respos = 0; - BOOL tag = FALSE, symb = FALSE; - wchar_t *szInfo = *szData; - - Data[0] = 0; - // parse the data if available - if (UpdateData->Start[0] == 0 && UpdateData->End[0] == 0) return; - start = szInfo; - // the start string must be found - if (UpdateData->Start[0] != 0) { - start = wcsstr(szInfo, UpdateData->Start); - if (start != nullptr) { - // set the starting location for getting data - start += mir_wstrlen(UpdateData->Start); - szInfo = start; - } - } - - // the end string must be found too - if (UpdateData->End[0] != 0) - end = wcsstr(szInfo, UpdateData->End); - else - end = wcschr(szInfo, ' '); - - if (end != nullptr) { - // set the ending location - startloc = 0; - endloc = end - szInfo; - end += mir_wstrlen(UpdateData->End); - last = '\n'; - } + double a = 11.25; - // ignore if not both of the string found - this prevent crashes - if (start != nullptr && end != nullptr) { - // begin reading the data from start location to end location - // remove all HTML tag in between, as well as leading space, ending space, - // multiple spaces, tabs, and return key - while (startloc < endloc) { - if (szInfo[startloc] == '<') tag = TRUE; - else if (szInfo[startloc] == '&' && - (szInfo[startloc + 1] == ';' || szInfo[startloc + 2] == ';' || szInfo[startloc + 3] == ';' || - szInfo[startloc + 4] == ';' || szInfo[startloc + 5] == ';' || szInfo[startloc + 6] == ';')) { - // ...but do NOT strip − - if ((endloc - startloc) > 7 && wcsncmp(szInfo + startloc, L"−", 7) == 0) { - Data[respos++] = '-'; - startloc += 7; - continue; - } - symb = TRUE; - } - else if (szInfo[startloc] == '>') tag = FALSE; - else if (szInfo[startloc] == ';') symb = FALSE; - else { - if (!tag && !symb) { - current = szInfo[startloc]; - if (current == '\n' || current == '\t' || current == ' ' || current == '\r') - current = ' '; - if (current != ' ' || last != ' ') { - if (last != '\n' && (respos != 0 || (respos == 0 && last != ' '))) - Data[respos++] = last; - last = current; - } - } - } - ++startloc; - // prevent crashes if the string go over maximun length -> generate an error - if (respos >= MAX_DATA_LEN) { - if (opt.ShowWarnings && UpdateData->Name[0] != 0 && mir_wstrcmp(UpdateData->Name, L"Ignore")) { - mir_snwprintf(Data, MAX_DATA_LEN, TranslateT("Error when obtaining data: %s"), UpdateData->Name); - WPShowMessage(Data, SM_WARNING); - } - wcsncpy(Data, TranslateT("<Error>"), MAX_DATA_LEN); - last = ' '; - respos = MAX_DATA_LEN - 1; - break; - } - } + for (int i = 0; i < _countof(rumbs); i++, a += 22.5) + if (angle < a) + return TranslateW(rumbs[i]); - // get the last character - if (last != ' ') - Data[respos++] = last; - - // null terminate the string - Data[respos] = 0; - - // convert the unit - ConvertDataValue(UpdateData, Data); - - // remove the string before the data from szInfo - szInfo = end; - } - *szData = szInfo; -} - -//============ ALLOCATE SPACE AND COPY STRING ============ -// -// copy a string into a new memory location -// Data = the field the data is copied to -// Value = the original string, the string where data is copied from - -bool g_bIsUtf = false; - -void wSetData(char *&Data, const char *Value) -{ - if (Value[0] != 0) - Data = mir_strdup(Value); - else - Data = ""; -} - -void wSetData(wchar_t *&Data, const char *Value) -{ - if (Value[0] != 0) - Data = (g_bIsUtf) ? mir_utf8decodeW(Value) : mir_a2u(Value); - else - Data = L""; + // area between 348.75 & 360 degrees + return TranslateT("N"); } -void wSetData(wchar_t *&Data, const wchar_t *Value) +void CWeatherProto::ConvertDataValue(WIDATAITEM *p) { - if (Value[0] != 0) - Data = mir_wstrdup(Value); - else - Data = L""; -} + wchar_t str[MAX_DATA_LEN]; -// A safer free function that free memory for a string -// Data = the string occuping the data to be freed -void wfree(char *&Data) -{ - if (Data && mir_strlen(Data) > 0) - mir_free(Data); - Data = nullptr; + // temperature + if (!mir_wstrcmp(p->Name, L"Temperature") || !mir_wstrcmp(p->Name, L"High") || + !mir_wstrcmp(p->Name, L"Low") || !mir_wstrcmp(p->Name, L"Feel") || + !mir_wstrcmp(p->Name, L"Dew point") || + !mir_wstrcmpi(p->Unit, L"C") || !mir_wstrcmpi(p->Unit, L"F") || + !mir_wstrcmpi(p->Unit, L"K")) { + GetTemp(p->Value, p->Unit, str); + p->Value = str; + } + // pressure + else if (!mir_wstrcmp(p->Name, L"Pressure") || !mir_wstrcmpi(p->Unit, L"HPA") || + !mir_wstrcmpi(p->Unit, L"KPA") || !mir_wstrcmpi(p->Unit, L"MB") || + !mir_wstrcmpi(p->Unit, L"TORR") || !mir_wstrcmpi(p->Unit, L"IN") || + !mir_wstrcmpi(p->Unit, L"MM")) { + GetPressure(p->Value, p->Unit, str); + p->Value = str; + } + // speed + else if (!mir_wstrcmp(p->Name, L"Wind Speed") || !mir_wstrcmpi(p->Unit, L"KM/H") || + !mir_wstrcmpi(p->Unit, L"M/S") || !mir_wstrcmpi(p->Unit, L"MPH") || + !mir_wstrcmpi(p->Unit, L"KNOTS")) { + GetSpeed(p->Value, p->Unit, str); + p->Value = str; + } + // visibility + else if (!mir_wstrcmp(p->Name, L"Visibility") || !mir_wstrcmpi(p->Unit, L"KM") || + !mir_wstrcmpi(p->Unit, L"MILES")) { + GetDist(p->Value, p->Unit, str); + p->Value = str; + } + // elevation + else if (!mir_wstrcmp(p->Name, L"Elevation") || !mir_wstrcmpi(p->Unit, L"FT") || + !mir_wstrcmpi(p->Unit, L"M")) { + GetElev(p->Value, p->Unit, str); + p->Value = str; + } + // convert degrees to compass + else if (!mir_wstrcmpi(p->Unit, L"GRAD")) { + p->Value = degree2str(_wtof(p->Value)); + } + // degree sign + else if (!mir_wstrcmpi(p->Unit, L"DEG")) { + if (!opt.DoNotAppendUnit) + p->Value.Append(opt.DegreeSign); + } + // percent sign + else if (!mir_wstrcmpi(p->Unit, L"%")) { + if (!opt.DoNotAppendUnit) + p->Value.Append(L"%"); + } + // truncating strings for day/month to 2 or 3 characters + else if (!mir_wstrcmpi(p->Unit, L"DAY") || !mir_wstrcmpi(p->Unit, L"MONTH")) + if (opt.dUnit > 1 && mir_wstrlen(p->Value) > opt.dUnit) + p->Value.SetAt(opt.dUnit, '\0'); } -void wfree(wchar_t *&Data) -{ - if (Data && mir_wstrlen(Data) > 0) - mir_free(Data); - Data = nullptr; -} +///////////////////////////////////////////////////////////////////////////////////////// +// data query -//============ MANAGE THE ITEMS STORED IN DB ============ -// get single setting that is found -// szSetting = the setting name -// lparam = the counter -int GetWeatherDataFromDB(const char *szSetting, void *lparam) +MHttpResponse* CWeatherProto::RunQuery(const wchar_t *id, int days) { - LIST<char> *pList = (LIST<char>*)lparam; - pList->insert(mir_strdup(szSetting)); - return 0; -} + wchar_t *pKey = m_szApiKey; + if (!mir_wstrlen(pKey)) { + WPShowMessage(TranslateT("You need to obtain the personal key and enter it in the account's Options dialog"), SM_WARNING); + return nullptr; + } -// remove or display the weather information for a contact -// hContact - the contact in which the info is going to be removed -// -void DBDataManage(MCONTACT hContact, uint16_t Mode, WPARAM wParam, LPARAM) -{ - // get all the settings and store them in a temporary list - LIST<char> arSettings(10); - db_enum_settings(hContact, GetWeatherDataFromDB, WEATHERCONDITION, &arSettings); + auto *pReq = new MHttpRequest(REQUEST_GET); + pReq->flags = NLHRF_HTTP11 | NLHRF_DUMPASTEXT; + pReq->m_szUrl = "https://weather.visualcrossing.com/VisualCrossingWebServices/rest/services/timeline/" + mir_urlEncode(T2Utf(id).get()); - // begin deleting settings - auto T = arSettings.rev_iter(); - for (auto &str : T) { - ptrW wszText(db_get_wsa(hContact, WEATHERCONDITION, str)); - if (wszText == nullptr) - continue; + if (days) { + time_t today = time(0); + struct tm *p = localtime(&today); + pReq->m_szUrl.AppendFormat("/%04d-%02d-%02d", p->tm_year + 1900, p->tm_mon + 1, p->tm_mday); - switch (Mode) { - case WDBM_REMOVE: - db_unset(hContact, WEATHERCONDITION, str); - break; + today += 86400 * 7; // add one week + p = localtime(&today); + pReq->m_szUrl.AppendFormat("/%04d-%02d-%02d", p->tm_year + 1900, p->tm_mon + 1, p->tm_mday); + } - case WDBM_DETAILDISPLAY: - // skip the "WeatherInfo" variable - if (!mir_strcmp(str, "WeatherInfo") || !mir_strcmp(str, "Ignore") || str[0] == '#') - continue; + pReq << CHAR_PARAM("unitGroup", "metric") << WCHAR_PARAM("key", pKey) << CHAR_PARAM("contentType", "json"); + if (days) + pReq << CHAR_PARAM("elements", "+elevation"); - _A2T strW(str); - HWND hList = GetDlgItem((HWND)wParam, IDC_DATALIST); - LV_ITEM lvi = {}; - lvi.mask = LVIF_TEXT | LVIF_PARAM; - lvi.lParam = T.indexOf(&str); - lvi.pszText = TranslateW(strW); - lvi.iItem = ListView_InsertItem(hList, &lvi); - lvi.pszText = wszText; - ListView_SetItemText(hList, lvi.iItem, 1, wszText); - break; - } - mir_free(str); - } + auto *ret = Netlib_HttpTransaction(m_hNetlibUser, pReq); + delete pReq; + return ret; } diff --git a/protocols/Weather/src/weather_http.cpp b/protocols/Weather/src/weather_http.cpp deleted file mode 100644 index 79c9efd21e..0000000000 --- a/protocols/Weather/src/weather_http.cpp +++ /dev/null @@ -1,132 +0,0 @@ -/* -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 "stdafx.h" - -HNETLIBUSER hNetlibUser; - -//============ 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, char *userAgent, wchar_t **szData) -{ - if (userAgent == nullptr || userAgent[0] == 0) - userAgent = NETLIB_USER_AGENT; - - // initialize the netlib request - MHttpRequest nlhr(REQUEST_GET); - nlhr.flags = NLHRF_DUMPASTEXT | NLHRF_HTTP11 | NLHRF_REDIRECT; - nlhr.m_szUrl = szUrl; - nlhr.AddHeader("User-Agent", userAgent); - nlhr.AddHeader("Cache-Control", "no-cache"); - nlhr.AddHeader("Pragma", "no-cache"); - nlhr.AddHeader("Connection", "close"); - if (mir_strlen(cookie) > 0) - nlhr.AddHeader("Cookie", cookie); - - // download the page - NLHR_PTR nlhrReply(Netlib_HttpTransaction(hNetlibUser, &nlhr)); - if (nlhrReply == nullptr) { - // if the data does not downloaded successfully (ie. disconnected), then return 1000 as error code - *szData = (wchar_t*)mir_alloc(512); - // store the error code in szData - mir_wstrcpy(*szData, L"NetLib error occurred!!"); - return NLHRF_REDIRECT; - } - - // if the recieved code is 200 OK - int result; - if (nlhrReply->resultCode == 200) { - if (!nlhrReply->body.IsEmpty()) { - bool bIsUtf = false; - result = 0; - - // allocate memory and save the retrieved data - auto *pszHdr = nlhrReply->FindHeader("Content-Type"); - // look for Content-Type=utf-8 in header - if (pszHdr && strstr(_strlwr(pszHdr), "utf-8")) - bIsUtf = true; - else { - char *end = nlhrReply->body.GetBuffer(); - while (end) { - // look for - // <meta http-equiv="Content-Type" content="utf-8" /> - char *beg = strstr(end, "<meta"); - if (beg) { - end = strchr(beg, '>'); - if (end) { - char tmp = *end; - *end = 0; - - char *method = strstr(beg, "http-equiv=\""); - if (method && _strnicmp(method + 12, "Content-Type", 12) == 0 && strstr(method, "utf-8")) { - bIsUtf = true; - *end = tmp; - break; - } - else *end = tmp; - } - } - else - break; - } - } - - wchar_t *retVal = nullptr; - if (bIsUtf) - retVal = mir_utf8decodeW(nlhrReply->body); - if (retVal == nullptr) - retVal = mir_a2u(nlhrReply->body); - *szData = retVal; - } - else result = DATA_EMPTY; - } - // return error code if the recieved code is neither 200 OK nor 302 Moved - else { - // store the error code in szData - CMStringW wszError(FORMAT, L"Error occured! HTTP Error: %i\n", nlhrReply->resultCode); - *szData = wszError.Detach(); - result = nlhrReply->resultCode; - } - - // make a copy of the retrieved data, then free the memory of the http reply - return result; -} - -//============ NETLIB INITIALIZATION ============ -// -// initialize netlib support for weather protocol -void NetlibInit(void) -{ - NETLIBUSER nlu = {}; - nlu.flags = NUF_OUTGOING | NUF_HTTPCONNS | NUF_NOHTTPSOPTION; - nlu.szSettingsModule = MODULENAME; - nlu.szDescriptiveName.a = MODULENAME; - hNetlibUser = Netlib_RegisterUser(&nlu); -} diff --git a/protocols/Weather/src/weather_info.cpp b/protocols/Weather/src/weather_info.cpp deleted file mode 100644 index 5e4c79fb4a..0000000000 --- a/protocols/Weather/src/weather_info.cpp +++ /dev/null @@ -1,203 +0,0 @@ -/* -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 "stdafx.h" - -//============ INI INFORMATION ============ - -// List INI Information for all loaded INI files -static void INIInfo(HWND hwndDlg) -{ - wchar_t str[16]; - size_t memused = 0; - - HWND hIniList = GetDlgItem(hwndDlg, IDC_INFOLIST); - - ListView_DeleteAllItems(hIniList); - - LVITEM lvi = {}; - lvi.mask = LVIF_TEXT; - lvi.iItem = 0; - for (WIDATALIST *Item = WIHead; Item != nullptr; Item = Item->next) { - // 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; - lvi.pszText = GetINIVersionNum(Item->Data.InternalVer); - ListView_SetItem(hIniList, &lvi); - lvi.iSubItem = 4; - lvi.pszText = _ltow(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; - - ++lvi.iItem; - } - SetDlgItemText(hwndDlg, IDC_INICOUNT, _itow(lvi.iItem, str, 10)); - SetDlgItemText(hwndDlg, IDC_MEMUSED, _ltow((long)memused, str, 10)); -} - -struct -{ - const wchar_t *name; - unsigned size; -} -static columns[] = -{ - { LPGENW("Name"), 70 }, - { LPGENW("Author"), 100 }, - { LPGENW("File Version"), 70 }, - { LPGENW("INI Version"), 70 }, - { LPGENW("Items"), 40 }, - { LPGENW("Display Name"), 200 }, - { LPGENW("File Name"), 150 }, -}; - -WeatherMyDetailsDlg::WeatherMyDetailsDlg() : - CUserInfoPageDlg(g_plugin, IDD_INFO), - btnReload(this, IDC_RELOADINI) -{ - btnReload.OnClick = Callback(this, &WeatherMyDetailsDlg::onClick_Reload); -} - -bool WeatherMyDetailsDlg::OnInitDialog() -{ - HWND hIniList = GetDlgItem(m_hwnd, IDC_INFOLIST); - - LVCOLUMN lvc = {}; - lvc.mask = LVCF_FMT | LVCF_SUBITEM | LVCF_TEXT | LVCF_WIDTH; - lvc.fmt = LVCFMT_LEFT; - for (auto &it : columns) { - lvc.iSubItem = int(&it - columns); - lvc.pszText = TranslateW(it.name); - lvc.cx = it.size; - ListView_InsertColumn(hIniList, lvc.iSubItem, &lvc); - } - - INIInfo(m_hwnd); - return true; -} - -void WeatherMyDetailsDlg::onClick_Reload(CCtrlButton*) -{ - DestroyWIList(); - LoadWIData(true); - INIInfo(m_hwnd); -} - -// get the info of individual ini file -// pszSvc = the internal name of the service to get the data - -wchar_t* GetINIVersionNum(int iVersion) -{ - switch (iVersion) { - case 1: return L"1.0"; - case 2: return L"1.1"; - case 3: return L"1.1a"; - case 4: return L"1.2"; - case 5: return L"1.3"; - case 6: return L"1.4"; - case 7: return L"1.5"; - } - return L""; -} - -void GetINIInfo(wchar_t *pszSvc) -{ - CMStringW str; - WIDATA *sData = GetWIData(pszSvc); - // if the service does not exist among the loaded INI's - if (sData == nullptr) { - str.Format(TranslateT("The corresponding INI file for \"%s\" is not found."), pszSvc); - } - // if exist, get the information - else { - str.AppendFormat(TranslateT("Weather INI information for \"%s\":"), pszSvc); - str += L"\n\n"; - str.AppendFormat(L"%s\t%s\n", TranslateT("Name:"), sData->DisplayName); - str.AppendFormat(L"%s\t%s\n", TranslateT("Internal Name:"), sData->InternalName); - str.AppendFormat(L"%s\t%s\n", TranslateT("Author:"), sData->Author); - str.AppendFormat(L"%s\t%s\n", TranslateT("Version:"), sData->Version); - str.AppendFormat(L"%s\t%s\n", TranslateT("INI Version:"), GetINIVersionNum(sData->InternalVer)); - str.AppendFormat(L"%s\t%s\n", TranslateT("File Name:"), sData->ShortFileName); - str.AppendFormat(L"%s\t%i\n", TranslateT("Item Count:"), sData->UpdateDataCount); - str.AppendFormat(L"%s\t%i %s\n\n", TranslateT("Memory Used:"), (int)sData->MemUsed, TranslateT("bytes")); - str.AppendFormat(L"%s\n%s", TranslateT("Description:"), sData->Description); - } - - MessageBox(nullptr, str, 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) -{ - // heading - CMStringW str(TranslateT("Here is a list of custom variables that are currently available")); - str += L"\n\n"; - - // loop through all weather services to find custom variables - bool bFirst = true; - for (WIDATALIST *Item = WIHead; Item != nullptr; Item = Item->next) { - // loop through all update items in a service - for (WIDATAITEMLIST *WItem = Item->Data.UpdateData; WItem != nullptr; WItem = WItem->Next) { - // the custom variable is defined as "%[<variable name>]" - // ignore the "hi" item and hidden items - if (mir_wstrcmp(WItem->Item.Name, L"Ignore") && WItem->Item.Name[0] != '#') { - wchar_t tempstr[1024]; - mir_snwprintf(tempstr, L"%c[%s]", '%', WItem->Item.Name); - auto *find = wcsstr(str, tempstr); - // if the custom variable does not exist in the list, add it to the list - if (find == nullptr) { - if (bFirst) - bFirst = false; - else - str += L", "; - str += tempstr; - } - } - } - } - - // display the list in a message box - MessageBox(nullptr, str, TranslateT("More Variables"), MB_OK | MB_ICONINFORMATION | MB_TOPMOST); -} diff --git a/protocols/Weather/src/weather_ini.cpp b/protocols/Weather/src/weather_ini.cpp deleted file mode 100644 index 0929b06c1e..0000000000 --- a/protocols/Weather/src/weather_ini.cpp +++ /dev/null @@ -1,581 +0,0 @@ -/* -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 "stdafx.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 -static void WIListAdd(WIDATA Data) -{ - // create a new datalist item and point to the data - WIDATALIST *newItem = (WIDATALIST*)mir_alloc(sizeof(WIDATALIST)); - newItem->Data = Data; - // add to the linked list - newItem->next = nullptr; - if (WITail == nullptr) 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(wchar_t *pszServ) -{ - // loop through the list to find matching internal name - for (WIDATALIST *Item = WIHead; Item != nullptr; Item = Item->next) - // if internal name found, return the data - if (mir_wstrcmp(Item->Data.InternalName, pszServ) == 0) - return &Item->Data; - - // return NULL when no match found - return nullptr; -} - -//============ DATA ITEM LIST (LINKED LIST) ============ -// -// add a new update item into the current list -void WIItemListAdd(WIDATAITEM *DataItem, WIDATA *Data) -{ - WIDATAITEMLIST *newItem = (WIDATAITEMLIST*)mir_alloc(sizeof(WIDATAITEMLIST)); - newItem->Item = *DataItem; - newItem->Next = nullptr; - if (Data->UpdateData == nullptr) 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 wchar_t *name) -{ - Item->Name = mir_wstrdup(name); - Item->Start = L""; - Item->End = L""; - Item->Unit = L""; - Item->Url = ""; - Item->Break = L""; - 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 = nullptr; - List->Head = nullptr; -} - -// 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); - CharLowerW(newItem->Item); - newItem->Next = nullptr; - if (List->Tail == nullptr) List->Head = newItem; - else List->Tail->Next = newItem; - List->Tail = newItem; -} - -// check if the condition string matched for the assignment -bool IsContainedInCondList(const wchar_t *pszStr, WICONDLIST *List) -{ - // loop through the list to find matching internal name - for (WICONDITEM *Item = List->Head; Item != nullptr; Item = Item->Next) { - // if internal name found, return true indicating that the data is found - if (wcsstr(pszStr, Item->Item)) - return true; - - } - // return false when no match found - return false; -} - -// free the memory for icon assignment list -void DestroyCondList(WICONDLIST *List) -{ - // free the list one by one - for (WICONDITEM *temp = List->Head; temp != nullptr; temp = List->Head) { - List->Head = temp->Next; - wfree(temp->Item); // free the data struct - mir_free(temp); - } - // make sure the entire list is clear - List->Tail = nullptr; -} - - -//============ WEATHER INI SETUP DIALOG ============ -// -static INT_PTR CALLBACK DlgProcSetup(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam) -{ - switch (msg) { - case WM_INITDIALOG: - TranslateDialogDefault(hwndDlg); - - // make the buttons flat - SendDlgItemMessage(hwndDlg, IDC_STEP1, BUTTONSETASFLATBTN, TRUE, 0); - SendDlgItemMessage(hwndDlg, IDC_STEP2, BUTTONSETASFLATBTN, TRUE, 0); - SendDlgItemMessage(hwndDlg, IDC_STEP3, BUTTONSETASFLATBTN, TRUE, 0); - SendDlgItemMessage(hwndDlg, IDC_STEP4, BUTTONSETASFLATBTN, TRUE, 0); - - // set icons - Window_SetIcon_IcoLib(hwndDlg, g_plugin.getIconHandle(IDI_ICON)); - - WindowList_Add(hWindowList, hwndDlg); - ShowWindow(hwndDlg, SW_SHOW); - break; - - case WM_COMMAND: - switch (LOWORD(wParam)) { - case IDC_STEP1: - // update current data - Utils_OpenUrl("https://miranda-ng.org/"); - break; - - case IDC_STEP2: - { - CMStringW wszPath('\x00', MAX_PATH); - GetModuleFileName(GetModuleHandle(nullptr), wszPath.GetBuffer(), MAX_PATH); - int idx = wszPath.Find('\\'); - if (idx != -1) { - wszPath.Truncate(idx); - wszPath += L"\\Plugins\\weather\\"; - if (_wmkdir(wszPath) == 0) - ShellExecute((HWND)lParam, L"open", wszPath, L"", L"", SW_SHOW); - } - break; - } - - case IDC_STEP3: - if (LoadWIData(false)) - MessageBox(nullptr, - TranslateT("All update data has been reloaded."), - TranslateT("Weather Protocol"), MB_OK | MB_ICONINFORMATION); - break; - - case IDC_STEP4: - WeatherAdd(0, 0); - __fallthrough; - - case IDCANCEL: - // close the info window - DestroyWindow(hwndDlg); - break; - } - break; - - case WM_CLOSE: - DestroyWindow(hwndDlg); - break; - - case WM_DESTROY: - Window_FreeIcon_IcoLib(hwndDlg); - break; - } - return FALSE; -} - -// 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 - -static const char *statusStr[MAX_COND] = -{ - "LIGHTNING", - "FOG", - "SNOW", - "RAIN", - "PARTLY CLOUDY", - "CLOUDY", - "SUNNY", - "N/A", - "RAIN SHOWER", - "SNOW SHOWER", -}; - -static void LoadStationData(const wchar_t *pszFile, wchar_t *pszShortFile, WIDATA *Data) -{ - WIDATAITEM DataItem; - - // clean up old stuff - memset(Data, 0, sizeof(*Data)); - Data->Enabled = FALSE; - - // open the ini file - FILE *pfile = _wfsopen(pszFile, L"rt", _SH_DENYWR); - if (pfile == nullptr) - return; - - char Line[4096]; - fgets(Line, _countof(Line), pfile); - TrimString(Line); - - // make sure it is a valid weather protocol ini file - if (!mir_strcmp(Line, "[Weather 0.3.x Update Data]")) - Data->InternalVer = 1; - else if (!mir_strcmp(Line, "[Weather 0.3.x Update Data 1.1]")) - Data->InternalVer = 2; - else if (!mir_strcmp(Line, "[Weather 0.3.x Update Data 1.1a]")) - Data->InternalVer = 3; - else if (!mir_strcmp(Line, "[Weather 0.3.x Update Data 1.2]")) - Data->InternalVer = 4; - else if (!mir_strcmp(Line, "[Weather 0.3.x Update Data 1.3]")) - Data->InternalVer = 5; - else if (!mir_strcmp(Line, "[Weather 0.3.x Update Data 1.4]")) - Data->InternalVer = 6; - else if (!mir_strcmp(Line, "[Weather 0.3.x Update Data 1.5]")) - Data->InternalVer = 7; - else { - wchar_t str[4096]; - mir_snwprintf(str, TranslateT("Invalid ini format for: %s"), pszFile); - MessageBox(nullptr, str, TranslateT("Weather Protocol"), MB_OK | MB_ICONERROR); - fclose(pfile); - return; - } - - // initialize all data fields - char *Group = ""; - - Data->DisplayName = L""; - Data->InternalName = L""; - Data->Description = L""; - Data->Author = L""; - Data->Version = L""; - Data->DefaultURL = ""; - Data->DefaultMap = L""; - Data->UpdateURL = ""; - Data->UpdateURL2 = ""; - Data->UpdateURL3 = ""; - Data->UpdateURL4 = ""; - Data->Cookie = ""; - Data->UserAgent = ""; - Data->IDSearch.SearchURL = ""; - Data->IDSearch.NotFoundStr = L""; - Data->NameSearch.SearchURL = ""; - Data->NameSearch.NotFoundStr = L""; - Data->NameSearch.SingleStr = L""; - Data->NameSearch.Single.First = L""; - Data->NameSearch.Multiple.First = L""; - 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, L"ID Search - Station Name"); - ResetDataItem(&Data->NameSearch.Single.Name, L"Name Search Single Result - Station Name"); - ResetDataItem(&Data->NameSearch.Single.ID, L"Name Search Single Result - Station ID"); - ResetDataItem(&Data->NameSearch.Multiple.Name, L"Name Search Multiple Result - Station Name"); - ResetDataItem(&Data->NameSearch.Multiple.ID, L"Name Search Multiple Result - Station ID"); - - DataItem.Name = L""; - DataItem.Start = L""; - DataItem.End = L""; - DataItem.Unit = L""; - DataItem.Url = ""; - DataItem.Break = L""; - DataItem.Type = 0; - - // initialize the linked list for update items - Data->UpdateDataCount = 0; - Data->MemUsed = sizeof(WIDATA) + sizeof(WIDATALIST) + (mir_wstrlen(pszShortFile) + mir_wstrlen(pszFile) + 20) * sizeof(wchar_t); - Data->UpdateData = nullptr; - Data->UpdateDataTail = nullptr; - - // initialize the icon assignment list - for (auto &it : Data->CondList) - WICondListInit(&it); - - g_bIsUtf = false; - - while (!feof(pfile)) { - // determine current tag - if (fgets(Line, _countof(Line), pfile) == nullptr) - break; - - TrimString(Line); - - // if the line is a group header/footer - if (Line[0] == '[') { - char *chop = strchr(Line + 1, ']'); - if (chop == nullptr) - continue; - - if (Line[1] != '/') { // if it is not a footer (for old ini) - // save the group name - char *Temp = (char *)mir_alloc(mir_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") && - _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 '=' - char *Value = strchr(Line, '='); - if (Value == nullptr) - continue; - - // get the string before '=' (ValName) and after '=' (Value) - char *ValName = (char *)mir_alloc(mir_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(ValName, "UTF8")) g_bIsUtf = (0 == _stricmp(Value, "true")); - } - 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(ValName, "USERAGENT")) wSetData(Data->UserAgent, Value); - } - else if (!_stricmp(Group, "ID SEARCH")) { - if (!_stricmp(ValName, "AVAILABLE")) Data->IDSearch.Available = (0 == _stricmp(Value, "true")); - 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")) Data->NameSearch.Single.Available = (0 == _stricmp(Value, "true")); - else if (!_stricmp(ValName, "MULTIPLE RESULT")) Data->NameSearch.Multiple.Available = (0 == _stricmp(Value, "true")); - 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 (int i = 0; i < _countof(statusStr); 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")) { - wchar_t *nm = Data->UpdateDataTail->Item.Name; - size_t len = mir_wstrlen(nm) + 1; - - Data->UpdateDataTail->Item.Name = nm = (wchar_t*)mir_realloc(nm, sizeof(wchar_t)*(len + 3)); - memmove(nm + 1, nm, len*sizeof(wchar_t)); - *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 += (mir_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); -} - -//============ LOADING INI FILES ============ -// -// load the weather update data form INI files -bool LoadWIData(bool dial) -{ - // make sure that the current service data list is empty - WITail = nullptr; - WIHead = WITail; - - // find all *.ini file in the plugin\weather directory - CMStringW wszFileName('\x00', MAX_PATH); - GetModuleFileName(GetModuleHandle(nullptr), wszFileName.GetBuffer(), MAX_PATH); - int idx = wszFileName.ReverseFind('\\'); - if (idx == -1) - return false; - wszFileName.Truncate(idx); - wszFileName += L"\\Plugins\\Weather\\"; - - WIN32_FIND_DATA fd; - HANDLE hFind = FindFirstFile(wszFileName + L"*.ini", &fd); - - // load the content of the ini file into memory - if (hFind != INVALID_HANDLE_VALUE) { - do { - if (mir_wstrcmpi(fd.cFileName, L"SAMPLE_INI.INI")) { - WIDATA Data; - LoadStationData(wszFileName + fd.cFileName, fd.cFileName, &Data); - if (Data.Enabled) - WIListAdd(Data); - } - // look through the entire "plugins\weather" directory - } while (FindNextFile(hFind, &fd)); - FindClose(hFind); - } - - if (WIHead == nullptr) { - // no ini found, display an error message box. - if (dial) - hWndSetup = CreateDialog(g_plugin.getInst(), MAKEINTRESOURCE(IDD_SETUP), nullptr, DlgProcSetup); - else - MessageBox(nullptr, - TranslateT("No update data file is found. Please check your Plugins\\Weather directory."), - TranslateT("Weather Protocol"), MB_OK | MB_ICONERROR); - return false; - } - return true; -} - -//============ FREE WIDATA ITEM FROM MEMORY ============ -// -// free the WIDATA struct from memory -// Data = the struct to be freed -static void FreeWIData(WIDATA *Data) -{ - // free update items linked list first - WIDATAITEMLIST *WItem = Data->UpdateData; - while (WItem != nullptr) { - 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->UserAgent); - 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 (auto &it : Data->CondList) - DestroyCondList(&it); -} - -// remove all service data from memory -void DestroyWIList(void) -{ - // free the list one by one - while (WIHead != nullptr) { - WIDATALIST *wi = WIHead; - WIHead = wi->next; - FreeWIData(&wi->Data); // free the data struct - mir_free(wi); - } - - // make sure the entire list is clear - WITail = nullptr; -} diff --git a/protocols/Weather/src/weather_mwin.cpp b/protocols/Weather/src/weather_mwin.cpp index da08be4ce1..cb1e33849b 100644 --- a/protocols/Weather/src/weather_mwin.cpp +++ b/protocols/Weather/src/weather_mwin.cpp @@ -27,6 +27,7 @@ HGENMENU hMwinMenu; struct MWinDataType { + CWeatherProto *ppro; MCONTACT hContact; HWND hAvt; BOOL haveAvatar; @@ -44,7 +45,8 @@ static LRESULT CALLBACK wndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lPara SetWindowLongPtr(hwnd, GWLP_USERDATA, (LONG_PTR)data); data->hContact = (DWORD_PTR)((LPCREATESTRUCT)lParam)->lpCreateParams; - data->hAvt = CreateWindow(AVATAR_CONTROL_CLASS, TEXT(""), WS_CHILD, 0, 0, opt.AvatarSize, opt.AvatarSize, hwnd, 0, g_plugin.getInst(), 0); + data->ppro = (CWeatherProto *)Proto_GetContactInstance(data->hContact); + data->hAvt = CreateWindow(AVATAR_CONTROL_CLASS, TEXT(""), WS_CHILD, 0, 0, data->ppro->opt.AvatarSize, data->ppro->opt.AvatarSize, hwnd, 0, g_plugin.getInst(), 0); if (data->hAvt) SendMessage(data->hAvt, AVATAR_SETCONTACT, 0, (LPARAM)data->hContact); break; @@ -97,7 +99,7 @@ static LRESULT CALLBACK wndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lPara break; case WM_LBUTTONDBLCLK: - BriefInfo(data->hContact, 0); + data->ppro->BriefInfo(data->hContact, 0); break; case WM_COMMAND: //Needed by the contact's context menu @@ -124,7 +126,7 @@ static LRESULT CALLBACK wndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lPara break; case WM_REDRAWWIN: - if (data->hAvt != nullptr) MoveWindow(data->hAvt, 0, 0, opt.AvatarSize, opt.AvatarSize, TRUE); + if (data->hAvt != nullptr) MoveWindow(data->hAvt, 0, 0, data->ppro->opt.AvatarSize, data->ppro->opt.AvatarSize, TRUE); RedrawWindow(hwnd, nullptr, nullptr, RDW_INVALIDATE | RDW_UPDATENOW); break; @@ -133,16 +135,16 @@ static LRESULT CALLBACK wndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lPara RECT r, rc; if (GetUpdateRect(hwnd, &r, FALSE)) { - int picSize = opt.AvatarSize; + int picSize = data->ppro->opt.AvatarSize; HICON hIcon = nullptr; if (!data->haveAvatar) { picSize = GetSystemMetrics(SM_CXICON); - hIcon = GetStatusIconBig(data->hContact); + hIcon = data->ppro->GetStatusIconBig(data->hContact); } LOGFONT lfnt, lfnt1; - COLORREF clr = g_plugin.getDword("ColorMwinFrame", GetSysColor(COLOR_3DFACE)); + COLORREF clr = data->ppro->getDword("ColorMwinFrame", GetSysColor(COLOR_3DFACE)); COLORREF fntc = Font_GetW(_A2W(MODULENAME), LPGENW("Frame Font"), &lfnt); COLORREF fntc1 = Font_GetW(_A2W(MODULENAME), LPGENW("Frame Title Font"), &lfnt1); @@ -218,10 +220,17 @@ static LRESULT CALLBACK wndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lPara return(TRUE); } -static void addWindow(MCONTACT hContact) +void UpdateMwinData(MCONTACT hContact) +{ + HWND hwnd = WindowList_Find(hMwinWindowList, hContact); + if (hwnd != nullptr) + RedrawWindow(hwnd, nullptr, nullptr, RDW_INVALIDATE | RDW_UPDATENOW); +} + +void CWeatherProto::AddFrameWindow(MCONTACT hContact) { DBVARIANT dbv; - if (g_plugin.getWString(hContact, "Nick", &dbv)) + if (getWString(hContact, "Nick", &dbv)) return; wchar_t winname[512]; @@ -229,7 +238,7 @@ static void addWindow(MCONTACT hContact) db_free(&dbv); HWND hWnd = CreateWindow(L"WeatherFrame", L"", WS_CHILD | WS_VISIBLE, - 0, 0, 10, 10, g_clistApi.hwndContactList, nullptr, g_plugin.getInst(), (void*)hContact); + 0, 0, 10, 10, g_clistApi.hwndContactList, nullptr, g_plugin.getInst(), (void *)hContact); WindowList_Add(hMwinWindowList, hWnd, hContact); CLISTFrame Frame = {}; @@ -242,41 +251,34 @@ static void addWindow(MCONTACT hContact) Frame.height = 32; int frameID = g_plugin.addFrame(&Frame); - g_plugin.setDword(hContact, "mwin", frameID); + setDword(hContact, "mwin", frameID); Contact::Hide(hContact); } -void removeWindow(MCONTACT hContact) +void CWeatherProto::RemoveFrameWindow(MCONTACT hContact) { - uint32_t frameId = g_plugin.getDword(hContact, "mwin"); + uint32_t frameId = getDword(hContact, "mwin"); WindowList_Remove(hMwinWindowList, WindowList_Find(hMwinWindowList, hContact)); CallService(MS_CLIST_FRAMES_REMOVEFRAME, frameId, 0); - g_plugin.setDword(hContact, "mwin", 0); + setDword(hContact, "mwin", 0); Contact::Hide(hContact, false); } -void UpdateMwinData(MCONTACT hContact) +INT_PTR CWeatherProto::Mwin_MenuClicked(WPARAM hContact, LPARAM) { - HWND hwnd = WindowList_Find(hMwinWindowList, hContact); - if (hwnd != nullptr) - RedrawWindow(hwnd, nullptr, nullptr, RDW_INVALIDATE | RDW_UPDATENOW); -} - -INT_PTR Mwin_MenuClicked(WPARAM wParam, LPARAM) -{ - BOOL addwnd = WindowList_Find(hMwinWindowList, wParam) == nullptr; - if (addwnd) - addWindow(wParam); + if (WindowList_Find(hMwinWindowList, hContact)) + RemoveFrameWindow(hContact); else - removeWindow(wParam); + AddFrameWindow(hContact); + return 0; } -int BuildContactMenu(WPARAM wparam, LPARAM) +int CWeatherProto::BuildContactMenu(MCONTACT hContact) { - int flags = g_plugin.getDword(wparam, "mwin") ? CMIF_CHECKED : 0; + int flags = getDword(hContact, "mwin") ? CMIF_CHECKED : 0; Menu_ModifyItem(hMwinMenu, nullptr, INVALID_HANDLE_VALUE, flags); return 0; } @@ -287,7 +289,7 @@ int RedrawFrame(WPARAM, LPARAM) return 0; } -void InitMwin(void) +void CWeatherProto::InitMwin(void) { if (!ServiceExists(MS_CLIST_FRAMES_ADDFRAME)) return; @@ -337,17 +339,17 @@ void InitMwin(void) mir_strcpy(fontid.setting, "fnt1"); g_plugin.addFont(&fontid); - for (auto &hContact : Contacts(MODULENAME)) - if (g_plugin.getDword(hContact, "mwin")) - addWindow(hContact); + for (auto &hContact : AccContacts()) + if (getDword(hContact, "mwin")) + AddFrameWindow(hContact); hFontHook = HookEvent(ME_FONT_RELOAD, RedrawFrame); } -void DestroyMwin(void) +void CWeatherProto::DestroyMwin(void) { - for (auto &hContact : Contacts(MODULENAME)) { - uint32_t frameId = g_plugin.getDword(hContact, "mwin"); + for (auto &hContact : AccContacts()) { + uint32_t frameId = getDword(hContact, "mwin"); if (frameId) CallService(MS_CLIST_FRAMES_REMOVEFRAME, frameId, 0); } diff --git a/protocols/Weather/src/weather_opt.cpp b/protocols/Weather/src/weather_opt.cpp index 1d92f20191..765309e414 100644 --- a/protocols/Weather/src/weather_opt.cpp +++ b/protocols/Weather/src/weather_opt.cpp @@ -24,7 +24,6 @@ contain code for saving/loading options from the database. #include "stdafx.h" -static BOOL opt_startup; int RedrawFrame(WPARAM wParam, LPARAM lParam); //============ LOADING AND SAVING OPTIONS =========== @@ -37,9 +36,9 @@ const wchar_t* GetDefaultText(int c) case 'b': return TranslateT("Weather Condition for %n as of %u"); case 'B': - return 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]"); + return 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\\n%[Forecast Day 1]\\n\\n%[Forecast Day 2]\\n\\n%[Forecast Day 3]\\n\\n%[Forecast Day 4]\\n\\n%[Forecast Day 5]"); case 'X': case 'N': - return 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]"); + return 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\\n%[Forecast Day 1]\\n\\n%[Forecast Day 2]\\n\\n%[Forecast Day 3]\\n\\n%[Forecast Day 4]\\n\\n%[Forecast Day 5]"); case 'E': return TranslateT("%n at %u: %c, %t (feel-like %f) Wind: %i %w Humidity: %m"); case 'H': @@ -54,21 +53,21 @@ const wchar_t* GetDefaultText(int c) return L""; } -CMStringW GetTextValue(int c) +CMStringW CWeatherProto::GetTextValue(int c) { CMStringW ret; switch (c) { - case 'C': ret = g_plugin.getMStringW("DisplayText"); break; - case 'b': ret = g_plugin.getMStringW("BriefTextTitle"); break; - case 'B': ret = g_plugin.getMStringW("BriefText"); break; - case 'N': ret = g_plugin.getMStringW("NoteText"); break; - case 'E': ret = g_plugin.getMStringW("ExtText"); break; - case 'H': ret = g_plugin.getMStringW("HistoryText"); break; - case 'X': ret = g_plugin.getMStringW("ExtraText"); break; - case 'S': ret = g_plugin.getMStringW("StatusText"); break; - case 'P': ret = g_plugin.getMStringW("PopupTitle"); break; - case 'p': ret = g_plugin.getMStringW("PopupText"); break; + case 'C': ret = getMStringW("DisplayText"); break; + case 'b': ret = getMStringW("BriefTextTitle"); break; + case 'B': ret = getMStringW("BriefText"); break; + case 'N': ret = getMStringW("NoteText"); break; + case 'E': ret = getMStringW("ExtText"); break; + case 'H': ret = getMStringW("HistoryText"); break; + case 'X': ret = getMStringW("ExtraText"); break; + case 'S': ret = getMStringW("StatusText"); break; + case 'P': ret = getMStringW("PopupTitle"); break; + case 'p': ret = getMStringW("PopupText"); break; } return (ret.IsEmpty()) ? GetDefaultText(c) : ret; @@ -76,248 +75,224 @@ CMStringW GetTextValue(int c) // load options from database + set default if the setting does not exist -void LoadOptions(void) +void CWeatherProto::LoadOptions(void) { memset(&opt, 0, sizeof(opt)); // main options - opt.StartupUpdate = g_plugin.getByte("StartupUpdate", true); - opt.AutoUpdate = g_plugin.getByte("AutoUpdate", true); - opt.UpdateTime = g_plugin.getWord("UpdateTime", 30); - opt.NoProtoCondition = g_plugin.getByte("NoStatus", true); - opt.UpdateOnlyConditionChanged = g_plugin.getByte("CondChangeAsUpdate", true); - opt.RemoveOldData = g_plugin.getByte("RemoveOld", false); - opt.MakeItalic = g_plugin.getByte("MakeItalic", true); - opt.AvatarSize = g_plugin.getByte("AvatarSize", 128); + opt.AutoUpdate = getByte("AutoUpdate", true); + opt.UpdateTime = getWord("UpdateTime", 30); + opt.UpdateOnlyConditionChanged = getByte("CondChangeAsUpdate", true); + opt.RemoveOldData = getByte("RemoveOld", false); + opt.MakeItalic = getByte("MakeItalic", true); + opt.AvatarSize = getByte("AvatarSize", 128); // units - opt.tUnit = g_plugin.getWord("tUnit", 1); - opt.wUnit = g_plugin.getWord("wUnit", 2); - opt.vUnit = g_plugin.getWord("vUnit", 1); - opt.pUnit = g_plugin.getWord("pUnit", 4); - opt.dUnit = g_plugin.getWord("dUnit", 1); - opt.eUnit = g_plugin.getWord("eUnit", 2); + opt.tUnit = getWord("tUnit", 1); + opt.wUnit = getWord("wUnit", 2); + opt.vUnit = getWord("vUnit", 1); + opt.pUnit = getWord("pUnit", 4); + opt.dUnit = getWord("dUnit", 1); + opt.eUnit = getWord("eUnit", 2); - ptrW szValue(g_plugin.getWStringA("DegreeSign")); - wcsncpy_s(opt.DegreeSign, (szValue == NULL) ? L"" : szValue, _TRUNCATE); + ptrW szValue(getWStringA("DegreeSign")); + wcsncpy_s(opt.DegreeSign, !mir_wstrlen(szValue) ? L"\xB0" : szValue, _TRUNCATE); - opt.DoNotAppendUnit = g_plugin.getByte("DoNotAppendUnit", 0); - opt.NoFrac = g_plugin.getByte("NoFractions", 0); + opt.DoNotAppendUnit = getByte("DoNotAppendUnit", 0); + opt.NoFrac = getByte("NoFractions", 0); // advanced - opt.DisCondIcon = g_plugin.getByte("DisableConditionIcon", false); + opt.DisCondIcon = getByte("DisableConditionIcon", false); // popup options - opt.UpdatePopup = g_plugin.getByte("UpdatePopup", true); - opt.AlertPopup = g_plugin.getByte("AlertPopup", true); - opt.PopupOnChange = g_plugin.getByte("PopUpOnChange", true); - opt.ShowWarnings = g_plugin.getByte("ShowWarnings", true); + opt.UpdatePopup = getByte("UpdatePopup", true); + opt.AlertPopup = getByte("AlertPopup", true); + opt.PopupOnChange = getByte("PopUpOnChange", true); + opt.ShowWarnings = getByte("ShowWarnings", true); // popup colors - opt.BGColour = g_plugin.getDword("BackgroundColour", GetSysColor(COLOR_BTNFACE)); - opt.TextColour = g_plugin.getDword("TextColour", GetSysColor(COLOR_WINDOWTEXT)); - opt.UseWinColors = g_plugin.getByte("UseWinColors", false); + opt.BGColour = getDword("BackgroundColour", GetSysColor(COLOR_BTNFACE)); + opt.TextColour = getDword("TextColour", GetSysColor(COLOR_WINDOWTEXT)); + opt.UseWinColors = getByte("UseWinColors", false); // popup actions - opt.LeftClickAction = g_plugin.getDword("LeftClickAction", IDM_M2); - opt.RightClickAction = g_plugin.getDword("RightClickAction", IDM_M1); + opt.LeftClickAction = getDword("LeftClickAction", IDM_M2); + opt.RightClickAction = getDword("RightClickAction", IDM_M1); // popup delay - opt.pDelay = g_plugin.getDword("PopupDelay", 0); + opt.pDelay = getDword("PopupDelay", 0); // misc - if (szValue = g_plugin.getWStringA("Default")) + if (szValue = getWStringA("Default")) wcsncpy_s(opt.Default, szValue, _TRUNCATE); else opt.Default[0] = 0; } // save the options to database -void SaveOptions(void) +void CWeatherProto::SaveOptions(void) { // main options - g_plugin.setByte("StartupUpdate", (uint8_t)opt.StartupUpdate); - g_plugin.setByte("AutoUpdate", (uint8_t)opt.AutoUpdate); - g_plugin.setWord("UpdateTime", opt.UpdateTime); - g_plugin.setByte("NoStatus", (uint8_t)opt.NoProtoCondition); - g_plugin.setByte("CondChangeAsUpdate", (uint8_t)opt.UpdateOnlyConditionChanged); - g_plugin.setByte("RemoveOld", (uint8_t)opt.RemoveOldData); - g_plugin.setByte("MakeItalic", (uint8_t)opt.MakeItalic); - g_plugin.setByte("AvatarSize", (uint8_t)opt.AvatarSize); + setByte("AutoUpdate", (uint8_t)opt.AutoUpdate); + setWord("UpdateTime", opt.UpdateTime); + setByte("CondChangeAsUpdate", (uint8_t)opt.UpdateOnlyConditionChanged); + setByte("RemoveOld", (uint8_t)opt.RemoveOldData); + setByte("MakeItalic", (uint8_t)opt.MakeItalic); + setByte("AvatarSize", (uint8_t)opt.AvatarSize); // units - g_plugin.setWord("tUnit", opt.tUnit); - g_plugin.setWord("wUnit", opt.wUnit); - g_plugin.setWord("vUnit", opt.vUnit); - g_plugin.setWord("pUnit", opt.pUnit); - g_plugin.setWord("dUnit", opt.dUnit); - g_plugin.setWord("eUnit", opt.eUnit); - g_plugin.setWString("DegreeSign", opt.DegreeSign); - g_plugin.setByte("DoNotAppendUnit", (uint8_t)opt.DoNotAppendUnit); - g_plugin.setByte("NoFractions", (uint8_t)opt.NoFrac); + setWord("tUnit", opt.tUnit); + setWord("wUnit", opt.wUnit); + setWord("vUnit", opt.vUnit); + setWord("pUnit", opt.pUnit); + setWord("dUnit", opt.dUnit); + setWord("eUnit", opt.eUnit); + setWString("DegreeSign", opt.DegreeSign); + setByte("DoNotAppendUnit", (uint8_t)opt.DoNotAppendUnit); + setByte("NoFractions", (uint8_t)opt.NoFrac); // advanced - g_plugin.setByte("DisableConditionIcon", (uint8_t)opt.DisCondIcon); + setByte("DisableConditionIcon", (uint8_t)opt.DisCondIcon); // popup options - g_plugin.setByte("UpdatePopup", (uint8_t)opt.UpdatePopup); - g_plugin.setByte("AlertPopup", (uint8_t)opt.AlertPopup); - g_plugin.setByte("PopUpOnChange", (uint8_t)opt.PopupOnChange); - g_plugin.setByte("ShowWarnings", (uint8_t)opt.ShowWarnings); + setByte("UpdatePopup", (uint8_t)opt.UpdatePopup); + setByte("AlertPopup", (uint8_t)opt.AlertPopup); + setByte("PopUpOnChange", (uint8_t)opt.PopupOnChange); + setByte("ShowWarnings", (uint8_t)opt.ShowWarnings); // popup colors - g_plugin.setDword("BackgroundColour", opt.BGColour); - g_plugin.setDword("TextColour", opt.TextColour); - g_plugin.setByte("UseWinColors", (uint8_t)opt.UseWinColors); + setDword("BackgroundColour", opt.BGColour); + setDword("TextColour", opt.TextColour); + setByte("UseWinColors", (uint8_t)opt.UseWinColors); // popup actions - g_plugin.setDword("LeftClickAction", opt.LeftClickAction); - g_plugin.setDword("RightClickAction", opt.RightClickAction); + setDword("LeftClickAction", opt.LeftClickAction); + setDword("RightClickAction", opt.RightClickAction); // popup delay - g_plugin.setDword("PopupDelay", opt.pDelay); + setDword("PopupDelay", opt.pDelay); // misc stuff - g_plugin.setWString("Default", opt.Default); + setWString("Default", opt.Default); } -//============ MAIN OPTIONS ============ +///////////////////////////////////////////////////////////////////////////////////////// // weather options -static INT_PTR CALLBACK OptionsProc(HWND hdlg, UINT msg, WPARAM wparam, LPARAM lparam) +class CGeneralOptionsDlg : public CWeatherDlgBase { - wchar_t str[512]; +public: + CGeneralOptionsDlg(CWeatherProto *ppro) : + CWeatherDlgBase(ppro, IDD_OPTIONS) + {} + + bool OnInitDialog() override + { + wchar_t str[512]; + auto &opt = m_proto->opt; - switch (msg) { - case WM_INITDIALOG: - opt_startup = TRUE; - TranslateDialogDefault(hdlg); - // load settings _ltow(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 ? BST_CHECKED : BST_UNCHECKED); - CheckDlgButton(hdlg, IDC_UPDATE, opt.AutoUpdate ? BST_CHECKED : BST_UNCHECKED); - CheckDlgButton(hdlg, IDC_PROTOCOND, !opt.NoProtoCondition ? BST_CHECKED : BST_UNCHECKED); - CheckDlgButton(hdlg, IDC_UPDCONDCHG, opt.UpdateOnlyConditionChanged ? BST_CHECKED : BST_UNCHECKED); - CheckDlgButton(hdlg, IDC_REMOVEOLD, opt.RemoveOldData ? BST_CHECKED : BST_UNCHECKED); - CheckDlgButton(hdlg, IDC_MAKEI, opt.MakeItalic ? BST_CHECKED : BST_UNCHECKED); - CheckDlgButton(hdlg, IDC_DISCONDICON, opt.DisCondIcon ? BST_CHECKED : BST_UNCHECKED); - CheckDlgButton(hdlg, IDC_DONOTAPPUNITS, opt.DoNotAppendUnit ? BST_CHECKED : BST_UNCHECKED); - CheckDlgButton(hdlg, IDC_NOFRAC, opt.NoFrac ? BST_CHECKED : BST_UNCHECKED); + SetDlgItemTextW(m_hwnd, IDC_UPDATETIME, str); + SetDlgItemTextW(m_hwnd, IDC_DEGREE, opt.DegreeSign); + + SendDlgItemMessage(m_hwnd, IDC_AVATARSPIN, UDM_SETRANGE32, 0, 999); + SendDlgItemMessage(m_hwnd, IDC_AVATARSPIN, UDM_SETPOS, 0, opt.AvatarSize); + SendDlgItemMessage(m_hwnd, IDC_AVATARSIZE, EM_LIMITTEXT, 3, 0); + + CheckDlgButton(m_hwnd, IDC_UPDATE, opt.AutoUpdate ? BST_CHECKED : BST_UNCHECKED); + CheckDlgButton(m_hwnd, IDC_UPDCONDCHG, opt.UpdateOnlyConditionChanged ? BST_CHECKED : BST_UNCHECKED); + CheckDlgButton(m_hwnd, IDC_REMOVEOLD, opt.RemoveOldData ? BST_CHECKED : BST_UNCHECKED); + CheckDlgButton(m_hwnd, IDC_MAKEI, opt.MakeItalic ? BST_CHECKED : BST_UNCHECKED); + CheckDlgButton(m_hwnd, IDC_DISCONDICON, opt.DisCondIcon ? BST_CHECKED : BST_UNCHECKED); + CheckDlgButton(m_hwnd, IDC_DONOTAPPUNITS, opt.DoNotAppendUnit ? BST_CHECKED : BST_UNCHECKED); + CheckDlgButton(m_hwnd, IDC_NOFRAC, opt.NoFrac ? BST_CHECKED : BST_UNCHECKED); // 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; + case 1: CheckRadioButton(m_hwnd, IDC_T1, IDC_T2, IDC_T1); break; + case 2: CheckRadioButton(m_hwnd, 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; + case 1: CheckRadioButton(m_hwnd, IDC_W1, IDC_W4, IDC_W1); break; + case 2: CheckRadioButton(m_hwnd, IDC_W1, IDC_W4, IDC_W2); break; + case 3: CheckRadioButton(m_hwnd, IDC_W1, IDC_W4, IDC_W3); break; + case 4: CheckRadioButton(m_hwnd, 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; + case 1: CheckRadioButton(m_hwnd, IDC_V1, IDC_V2, IDC_V1); break; + case 2: CheckRadioButton(m_hwnd, 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; + case 1: CheckRadioButton(m_hwnd, IDC_P1, IDC_P4, IDC_P1); break; + case 2: CheckRadioButton(m_hwnd, IDC_P1, IDC_P4, IDC_P2); break; + case 3: CheckRadioButton(m_hwnd, IDC_P1, IDC_P4, IDC_P3); break; + case 4: CheckRadioButton(m_hwnd, 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; + case 1: CheckRadioButton(m_hwnd, IDC_D1, IDC_D3, IDC_D1); break; + case 2: CheckRadioButton(m_hwnd, IDC_D1, IDC_D3, IDC_D2); break; + case 3: CheckRadioButton(m_hwnd, 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; + case 1: CheckRadioButton(m_hwnd, IDC_E1, IDC_E2, IDC_E1); break; + case 2: CheckRadioButton(m_hwnd, 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 = MapCondToStatus(opt.DefStn); - ProtoBroadcastAck(MODULENAME, NULL, ACKTYPE_STATUS, ACKRESULT_SUCCESS, (HANDLE)old_status, status); - } - - // get update time and remove the old timer - GetDlgItemText(hdlg, IDC_UPDATETIME, str, _countof(str)); - opt.UpdateTime = (uint16_t)_wtoi(str); - if (opt.UpdateTime < 1) opt.UpdateTime = 1; - KillTimer(nullptr, timerId); - timerId = SetTimer(nullptr, 0, opt.UpdateTime * 60000, timerProc); - - // other general options - GetDlgItemText(hdlg, IDC_DEGREE, opt.DegreeSign, _countof(opt.DegreeSign)); - opt.StartupUpdate = IsDlgButtonChecked(hdlg, IDC_STARTUPUPD); - opt.AutoUpdate = IsDlgButtonChecked(hdlg, IDC_UPDATE); - opt.NoProtoCondition = BST_UNCHECKED == IsDlgButtonChecked(hdlg, IDC_PROTOCOND); - opt.DisCondIcon = IsDlgButtonChecked(hdlg, IDC_DISCONDICON); - opt.UpdateOnlyConditionChanged = (uint8_t)IsDlgButtonChecked(hdlg, IDC_UPDCONDCHG); - opt.RemoveOldData = IsDlgButtonChecked(hdlg, IDC_REMOVEOLD); - opt.MakeItalic = IsDlgButtonChecked(hdlg, IDC_MAKEI); - opt.AvatarSize = GetDlgItemInt(hdlg, IDC_AVATARSIZE, nullptr, 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 true; } - return 0; -} -//============ TEXT OPTION DIALOG ============ + bool OnApply() override + { + wchar_t str[512]; + auto &opt = m_proto->opt; + + // get update time and remove the old timer + GetDlgItemText(m_hwnd, IDC_UPDATETIME, str, _countof(str)); + opt.UpdateTime = (uint16_t)_wtoi(str); + if (opt.UpdateTime < 1) opt.UpdateTime = 1; + m_proto->RestartTimer(); + + // other general options + GetDlgItemText(m_hwnd, IDC_DEGREE, opt.DegreeSign, _countof(opt.DegreeSign)); + opt.AutoUpdate = IsDlgButtonChecked(m_hwnd, IDC_UPDATE); + opt.DisCondIcon = IsDlgButtonChecked(m_hwnd, IDC_DISCONDICON); + opt.UpdateOnlyConditionChanged = (uint8_t)IsDlgButtonChecked(m_hwnd, IDC_UPDCONDCHG); + opt.RemoveOldData = IsDlgButtonChecked(m_hwnd, IDC_REMOVEOLD); + opt.MakeItalic = IsDlgButtonChecked(m_hwnd, IDC_MAKEI); + opt.AvatarSize = GetDlgItemInt(m_hwnd, IDC_AVATARSIZE, nullptr, FALSE); + opt.DoNotAppendUnit = IsDlgButtonChecked(m_hwnd, IDC_DONOTAPPUNITS); + opt.NoFrac = IsDlgButtonChecked(m_hwnd, IDC_NOFRAC); + m_proto->UpdateMenu(opt.AutoUpdate); + + // save the units + if (IsDlgButtonChecked(m_hwnd, IDC_T1)) opt.tUnit = 1; + if (IsDlgButtonChecked(m_hwnd, IDC_T2)) opt.tUnit = 2; + if (IsDlgButtonChecked(m_hwnd, IDC_W1)) opt.wUnit = 1; + if (IsDlgButtonChecked(m_hwnd, IDC_W2)) opt.wUnit = 2; + if (IsDlgButtonChecked(m_hwnd, IDC_W3)) opt.wUnit = 3; + if (IsDlgButtonChecked(m_hwnd, IDC_W4)) opt.wUnit = 4; + if (IsDlgButtonChecked(m_hwnd, IDC_V1)) opt.vUnit = 1; + if (IsDlgButtonChecked(m_hwnd, IDC_V2)) opt.vUnit = 2; + if (IsDlgButtonChecked(m_hwnd, IDC_P1)) opt.pUnit = 1; + if (IsDlgButtonChecked(m_hwnd, IDC_P2)) opt.pUnit = 2; + if (IsDlgButtonChecked(m_hwnd, IDC_P3)) opt.pUnit = 3; + if (IsDlgButtonChecked(m_hwnd, IDC_P4)) opt.pUnit = 4; + if (IsDlgButtonChecked(m_hwnd, IDC_D1)) opt.dUnit = 1; + if (IsDlgButtonChecked(m_hwnd, IDC_D2)) opt.dUnit = 2; + if (IsDlgButtonChecked(m_hwnd, IDC_D3)) opt.dUnit = 3; + if (IsDlgButtonChecked(m_hwnd, IDC_E1)) opt.eUnit = 1; + if (IsDlgButtonChecked(m_hwnd, IDC_E2)) opt.eUnit = 2; + + // save the new weather options + m_proto->SaveOptions(); + + RedrawFrame(0, 0); + return true; + } +}; +///////////////////////////////////////////////////////////////////////////////////////// // text option dialog struct @@ -338,172 +313,224 @@ static controls[] = { 'S', IDC_BTITLE2, "StatusText" }, }; -static INT_PTR CALLBACK DlgProcText(HWND hdlg, UINT msg, WPARAM wParam, LPARAM lParam) +struct +{ + wchar_t symbol; + const wchar_t *pwszText; +} +static variables[] = +{ + { 'c', LPGENW("Current condition") }, + { 'd', LPGENW("Current date") }, + { 'e', LPGENW("Dewpoint") }, + { 'f', LPGENW("Feel-like temp") }, + { 'h', LPGENW("Today's high") }, + { 'i', LPGENW("Wind direction") }, + { 'l', LPGENW("Today's low") }, + { 'm', LPGENW("Humidity") }, + { 'n', LPGENW("Station name") }, + { 'p', LPGENW("Pressure") }, + { 'r', LPGENW("Sunrise") }, + { 's', LPGENW("Station ID") }, + { 't', LPGENW("Temperature") }, + { 'u', LPGENW("Update time") }, + { 'v', LPGENW("Visibility") }, + { 'w', LPGENW("Wind speed") }, + { 'y', LPGENW("Sunset") }, +}; + +class COptionsTextDlg : public CWeatherDlgBase { - RECT rc, pos; - HWND button; - HMENU hMenu, hMenu1; - switch (msg) { - case WM_INITDIALOG: - opt_startup = TRUE; + CCtrlMButton btnMore, btnReset, tm1, tm2, tm3, tm4, tm5, tm6, tm7, tm8; + +public: + COptionsTextDlg(CWeatherProto *ppro) : + CWeatherDlgBase(ppro, IDD_TEXTOPT), + btnMore(this, IDC_MORE), + btnReset(this, IDC_RESET), + tm1(this, IDC_TM1), + tm2(this, IDC_TM2), + tm3(this, IDC_TM3), + tm4(this, IDC_TM4), + tm5(this, IDC_TM5), + tm6(this, IDC_TM6), + tm7(this, IDC_TM7), + tm8(this, IDC_TM8) + { + btnMore.OnClick = Callback(this, &COptionsTextDlg::onClick_More); + btnReset.OnClick = Callback(this, &COptionsTextDlg::onClick_Reset); + + tm1.OnClick = tm2.OnClick = tm3.OnClick = tm4.OnClick = tm5.OnClick = tm6.OnClick = tm7.OnClick = tm8.OnClick = + Callback(this, &COptionsTextDlg::onClick_TM); + } + + bool OnInitDialog() override + { // set windows position, make it top-most - GetWindowRect(hdlg, &rc); - SetWindowPos(hdlg, HWND_TOPMOST, rc.left, rc.top, 0, 0, SWP_NOSIZE); - TranslateDialogDefault(hdlg); + RECT rc; + GetWindowRect(m_hwnd, &rc); + SetWindowPos(m_hwnd, HWND_TOPMOST, rc.left, rc.top, 0, 0, SWP_NOSIZE); // generate the display text for variable list - SetDlgItemText(hdlg, IDC_VARLIST, VAR_LIST_OPT); + CMStringW str; + for (auto &it : variables) + str.AppendFormat(L"%%%c\t%s\r\n", it.symbol, TranslateW(it.pwszText)); + str.Append(L"----------\r\n"); + str.AppendFormat(L"\\n\t%s\r\n", TranslateT("new line")); + SetDlgItemTextW(m_hwnd, IDC_VARLIST, str); for (auto &it : controls) - SetDlgItemText(hdlg, it.id, GetTextValue(it.c)); + SetDlgItemTextW(m_hwnd, it.id, m_proto->GetTextValue(it.c)); // make the more variable and other buttons flat - SendDlgItemMessage(hdlg, IDC_MORE, BUTTONSETASFLATBTN, TRUE, 0); - SendDlgItemMessage(hdlg, IDC_TM1, BUTTONSETASFLATBTN, TRUE, 0); - SendDlgItemMessage(hdlg, IDC_TM2, BUTTONSETASFLATBTN, TRUE, 0); - SendDlgItemMessage(hdlg, IDC_TM3, BUTTONSETASFLATBTN, TRUE, 0); - SendDlgItemMessage(hdlg, IDC_TM4, BUTTONSETASFLATBTN, TRUE, 0); - SendDlgItemMessage(hdlg, IDC_TM5, BUTTONSETASFLATBTN, TRUE, 0); - SendDlgItemMessage(hdlg, IDC_TM6, BUTTONSETASFLATBTN, TRUE, 0); - SendDlgItemMessage(hdlg, IDC_TM7, BUTTONSETASFLATBTN, TRUE, 0); - SendDlgItemMessage(hdlg, IDC_TM8, BUTTONSETASFLATBTN, TRUE, 0); - SendDlgItemMessage(hdlg, IDC_RESET, BUTTONSETASFLATBTN, TRUE, 0); - - // load the settings - 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; + tm1.MakeFlat(); + tm2.MakeFlat(); + tm3.MakeFlat(); + tm4.MakeFlat(); + tm5.MakeFlat(); + tm6.MakeFlat(); + tm7.MakeFlat(); + tm8.MakeFlat(); + btnMore.MakeFlat(); + btnReset.MakeFlat(); + return true; + } - case IDC_MORE: - // display custom variables list - MoreVarList(); - break; + bool OnApply() override + { + // save the option + for (auto &it : controls) { + wchar_t textstr[MAX_TEXT_SIZE]; + GetDlgItemText(m_hwnd, it.id, textstr, _countof(textstr)); + if (!mir_wstrcmpi(textstr, GetDefaultText(it.c))) + m_proto->delSetting(it.setting); + else + m_proto->setWString(it.setting, textstr); + } + + m_proto->SaveOptions(); + m_proto->UpdateAllInfo(0, 0); + return true; + } + + void onClick_More(CCtrlButton *) + { + // heading + CMStringW str(TranslateT("Here is a list of custom variables that are currently available")); + str += L"\n\n"; + m_proto->GetVarsDescr(str); - case IDC_TM1: - case IDC_TM2: - case IDC_TM3: - case IDC_TM4: - case IDC_TM5: - case IDC_TM6: - case IDC_TM7: - case IDC_TM8: - // display the menu - button = GetDlgItem(hdlg, LOWORD(wParam)); - GetWindowRect(button, &pos); - hMenu = LoadMenu(g_plugin.getInst(), MAKEINTRESOURCE(IDR_TMMENU)); - hMenu1 = GetSubMenu(hMenu, 0); - TranslateMenu(hMenu1); + // display the list in a message box + MessageBox(nullptr, str, TranslateT("More Variables"), MB_OK | MB_ICONINFORMATION | MB_TOPMOST); + } + + void onClick_TM(CCtrlButton *pButton) + { + // display the menu + HMENU hMenu = LoadMenu(g_plugin.getInst(), MAKEINTRESOURCE(IDR_TMMENU)); + HMENU hMenu1 = GetSubMenu(hMenu, 0); + TranslateMenu(hMenu1); + + auto &var = controls[pButton->GetCtrlId() - IDC_TM1]; + + RECT pos; + GetWindowRect(pButton->GetHwnd(), &pos); + switch (TrackPopupMenu(hMenu1, TPM_LEFTBUTTON | TPM_RETURNCMD, pos.left, pos.bottom, 0, m_hwnd, nullptr)) { + case ID_MPREVIEW: { - auto &var = controls[int(LOWORD(wParam)) - IDC_TM1]; - - switch (TrackPopupMenu(hMenu1, TPM_LEFTBUTTON | TPM_RETURNCMD, pos.left, pos.bottom, 0, hdlg, nullptr)) { - case ID_MPREVIEW: - { - // show the preview in a message box, using the weather data from the default station - WEATHERINFO winfo = LoadWeatherInfo(opt.DefStn); - wchar_t buf[2] = { var.c, 0 }, str[4096]; - GetDisplay(&winfo, buf, str); - MessageBox(nullptr, str, TranslateT("Weather Protocol Text Preview"), MB_OK | MB_TOPMOST); - } - break; - - case ID_MRESET: - SetDlgItemText(hdlg, var.id, GetDefaultText(var.c)); - break; - } - DestroyMenu(hMenu); + // show the preview in a message box, using the weather data from the default station + WEATHERINFO winfo = m_proto->LoadWeatherInfo(m_proto->opt.DefStn); + wchar_t buf[MAX_TEXT_SIZE]; + GetDlgItemTextW(m_hwnd, var.id, buf, _countof(buf)); + MessageBox(nullptr, GetDisplay(&winfo, buf), TranslateT("Weather Protocol Text Preview"), MB_OK | MB_TOPMOST); } break; - case IDC_RESET: - // left click action selection menu - button = GetDlgItem(hdlg, IDC_RESET); - GetWindowRect(button, &pos); - hMenu = LoadMenu(g_plugin.getInst(), MAKEINTRESOURCE(IDR_TMENU)); - hMenu1 = GetSubMenu(hMenu, 0); - TranslateMenu(hMenu1); - switch (TrackPopupMenu(hMenu1, TPM_LEFTBUTTON | TPM_RETURNCMD, pos.left, pos.bottom, 0, hdlg, nullptr)) { - case ID_T1: - // reset to the strings in memory, discard all changes - for (auto &it : controls) - SetDlgItemText(hdlg, it.id, GetTextValue(it.c)); - break; - - case ID_T2: - // reset to the default setting - for (auto &it : controls) - SetDlgItemText(hdlg, it.id, GetDefaultText(it.c)); - break; - } - DestroyMenu(hMenu); + case ID_MRESET: + SetDlgItemTextW(m_hwnd, var.id, GetDefaultText(var.c)); break; } - return TRUE; - case WM_NOTIFY: - switch (((LPNMHDR)lParam)->code) { - case PSN_APPLY: - // save the option - wchar_t textstr[MAX_TEXT_SIZE]; - for (auto &it : controls) { - GetDlgItemText(hdlg, it.id, textstr, _countof(textstr)); - if (!mir_wstrcmpi(textstr, GetDefaultText(it.c))) - g_plugin.delSetting(it.setting); - else - g_plugin.setWString(it.setting, textstr); - } + DestroyMenu(hMenu); + } + + void onClick_Reset(CCtrlButton *) + { + // left click action selection menu + HMENU hMenu = LoadMenu(g_plugin.getInst(), MAKEINTRESOURCE(IDR_TMENU)); + HMENU hMenu1 = GetSubMenu(hMenu, 0); + TranslateMenu(hMenu1); + + RECT pos; + GetWindowRect(btnReset.GetHwnd(), &pos); + switch (TrackPopupMenu(hMenu1, TPM_LEFTBUTTON | TPM_RETURNCMD, pos.left, pos.bottom, 0, m_hwnd, nullptr)) { + case ID_T1: + // reset to the strings in memory, discard all changes + for (auto &it : controls) + SetDlgItemTextW(m_hwnd, it.id, m_proto->GetTextValue(it.c)); + break; - SaveOptions(); - UpdateAllInfo(0, 0); + case ID_T2: + // reset to the default setting + for (auto &it : controls) + SetDlgItemTextW(m_hwnd, it.id, GetDefaultText(it.c)); break; } - break; + DestroyMenu(hMenu); } - return FALSE; -} +}; +///////////////////////////////////////////////////////////////////////////////////////// +// account options dialog -//============ OPTION INITIALIZATION ============ +class CAccountOptionsDlg : public CWeatherDlgBase +{ + CCtrlEdit edtKey; + CCtrlButton btnObtain; + +public: + CAccountOptionsDlg(CWeatherProto *ppro) : + CWeatherDlgBase(ppro, IDD_ACCOUNT_OPT), + edtKey(this, IDC_KEY), + btnObtain(this, IDC_OBTAIN) + { + CreateLink(edtKey, m_proto->m_szApiKey); + + btnObtain.OnClick = Callback(this, &CAccountOptionsDlg::onClick_Obtain); + } + + void onClick_Obtain(CCtrlButton *) + { + Utils_OpenUrl("https://www.visualcrossing.com/account"); + } +}; +///////////////////////////////////////////////////////////////////////////////////////// // register the weather option pages -int OptInit(WPARAM wParam, LPARAM) + +int CWeatherProto::OptInit(WPARAM wParam, LPARAM) { - // plugin options OPTIONSDIALOGPAGE odp = {}; + odp.szGroup.w = LPGENW("Network"); + odp.szTitle.w = m_tszUserName; odp.position = 95600; - odp.pszTemplate = MAKEINTRESOURCEA(IDD_OPTIONS); - odp.pfnDlgProc = OptionsProc; - odp.szGroup.a = LPGEN("Network"); - odp.szTitle.a = MODULENAME; - odp.szTab.a = LPGEN("General"); - odp.flags = ODPF_BOLDGROUPS; + odp.flags = ODPF_BOLDGROUPS | ODPF_UNICODE; + + // account options + odp.pDialog = new CAccountOptionsDlg(this); + odp.szTab.w = LPGENW("Account"); g_plugin.addOptions(wParam, &odp); - // text options - odp.pszTemplate = MAKEINTRESOURCEA(IDD_TEXTOPT); - odp.pfnDlgProc = DlgProcText; - odp.szTab.a = LPGEN("Display"); + // plugin options + odp.pDialog = new CGeneralOptionsDlg(this); + odp.szTab.w = LPGENW("General"); g_plugin.addOptions(wParam, &odp); - // if popup service exists, load the weather popup options - odp.position = 100000000; - odp.pszTemplate = MAKEINTRESOURCEA(IDD_POPUP); - odp.szGroup.a = LPGEN("Popups"); - odp.szTab.a = nullptr; - odp.pfnDlgProc = DlgPopupOpts; + // text options + odp.pDialog = new COptionsTextDlg(this); + odp.szTab.w = LPGENW("Display"); g_plugin.addOptions(wParam, &odp); + + if (m_bPopups) + InitPopupOptions(wParam); return 0; } diff --git a/protocols/Weather/src/weather_popup.cpp b/protocols/Weather/src/weather_popup.cpp index 992db0a69a..b9f938e41d 100644 --- a/protocols/Weather/src/weather_popup.cpp +++ b/protocols/Weather/src/weather_popup.cpp @@ -27,37 +27,33 @@ along with this program. If not, see <http://www.gnu.org/licenses/>. // variables for weather_popup.c static MCONTACT hPopupContact; -//============ SHOW WEATHER POPUPS ============ - -//============ WEATHER ERROR POPUPS ============ +///////////////////////////////////////////////////////////////////////////////////////// +// wrapper function for displaying weather warning popup by triggering an event (threaded) +// lpzText = error text +// kind = display type (see m_popup.h) -// 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) +int CWeatherProto::WPShowMessage(const wchar_t *lpzText, int kind) { - if (!g_plugin.bPopups) + if (!m_bPopups) return 0; - wchar_t* tszMsg = (wchar_t*)wParam; - - if ((uint32_t)lParam == SM_WARNING) - PUShowMessageW(tszMsg, SM_WARNING); - else if ((uint32_t)lParam == SM_NOTIFY) - PUShowMessageW(tszMsg, SM_NOTIFY); - else if ((uint32_t)lParam == SM_WEATHERALERT) { + if (kind == SM_WARNING) + PUShowMessageW(lpzText, SM_WARNING); + else if (kind == SM_NOTIFY) + PUShowMessageW(lpzText, SM_NOTIFY); + else if (kind == SM_WEATHERALERT) { POPUPDATAW ppd; wchar_t str1[512], str2[512]; // get the 2 strings - wcsncpy(str1, tszMsg, _countof(str1) - 1); - wcsncpy(str2, tszMsg, _countof(str2) - 1); + wcsncpy(str1, lpzText, _countof(str1) - 1); + wcsncpy(str2, lpzText, _countof(str2) - 1); wchar_t *chop = wcschr(str1, 255); if (chop != nullptr) *chop = '\0'; else str1[0] = 0; + chop = wcschr(str2, 255); if (chop != nullptr) wcsncpy(str2, chop + 1, _countof(str2) - 1); @@ -77,38 +73,28 @@ int WeatherError(WPARAM wParam, LPARAM lParam) 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(const wchar_t* lpzText, uint16_t 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 + static LRESULT CALLBACK PopupDlgProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) { - uint32_t ID = 0; - MCONTACT hContact; - hContact = PUGetContact(hWnd); + uint32_t ID; + MCONTACT hContact = PUGetContact(hWnd); + auto *ppro = (CWeatherProto*)Proto_GetContactInstance(hContact); switch (message) { case WM_COMMAND: - ID = opt.LeftClickAction; + ID = (ppro) ? ppro->opt.LeftClickAction : 0; if (ID != IDM_M7) PUDeletePopup(hWnd); - SendMessage(hPopupWindow, ID, hContact, 0); + SendMessage(hPopupWindow, ID, hContact, LPARAM(ppro)); return TRUE; case WM_CONTEXTMENU: - ID = opt.RightClickAction; + ID = (ppro) ? ppro->opt.RightClickAction : IDM_M7; if (ID != IDM_M7) PUDeletePopup(hWnd); - SendMessage(hPopupWindow, ID, hContact, 0); + SendMessage(hPopupWindow, ID, hContact, LPARAM(ppro)); return TRUE; case UM_FREEPLUGINDATA: @@ -119,21 +105,23 @@ static LRESULT CALLBACK PopupDlgProc(HWND hWnd, UINT message, WPARAM wParam, LPA return DefWindowProc(hWnd, message, wParam, lParam); } +///////////////////////////////////////////////////////////////////////////////////////// // display weather popups // wParam = the contact to display popup // lParam = whether the weather data is changed or not -int WeatherPopup(WPARAM hContact, LPARAM lParam) + +int CWeatherProto::WeatherPopup(MCONTACT hContact, bool bAlways) { // determine if the popup should display or not - if (g_plugin.bPopups && opt.UpdatePopup && (!opt.PopupOnChange || (BOOL)lParam) && !g_plugin.getByte(hContact, "DPopUp")) { + if (m_bPopups && opt.UpdatePopup && (!opt.PopupOnChange || bAlways) && !getByte(hContact, "DPopUp")) { WEATHERINFO winfo = LoadWeatherInfo(hContact); // setup the popup POPUPDATAW ppd; ppd.lchContact = hContact; ppd.PluginData = ppd.lchIcon = GetStatusIcon(winfo.hContact); - GetDisplay(&winfo, GetTextValue('P'), ppd.lpwzContactName); - GetDisplay(&winfo, GetTextValue('p'), ppd.lpwzText); + wcsncpy_s(ppd.lpwzContactName, GetDisplay(&winfo, GetTextValue('P')), _TRUNCATE); + wcsncpy_s(ppd.lpwzText, GetDisplay(&winfo, GetTextValue('p')), _TRUNCATE); ppd.PluginWindowProc = PopupDlgProc; ppd.colorBack = (opt.UseWinColors) ? GetSysColor(COLOR_BTNFACE) : opt.BGColour; ppd.colorText = (opt.UseWinColors) ? GetSysColor(COLOR_WINDOWTEXT) : opt.TextColour; @@ -143,24 +131,27 @@ int WeatherPopup(WPARAM hContact, LPARAM lParam) return 0; } - +///////////////////////////////////////////////////////////////////////////////////////// // process for the popup window // containing the code for popup actions -LRESULT CALLBACK PopupWndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) + +LRESULT CALLBACK CWeatherProto::PopupWndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) { POINT pt; HMENU hMenu; + auto *ppro = (CWeatherProto *)lParam; + switch (uMsg) { case IDM_M2: // brief info - BriefInfo(wParam, 0); + ppro->BriefInfo(wParam, 0); break; case IDM_M3: // read complete forecast - LoadForecast(wParam, 0); + ppro->LoadForecast(wParam, 0); break; case IDM_M4: // display weather map - WeatherMap(wParam, 0); + ppro->WeatherMap(wParam, 0); break; case IDM_M5: // open history window @@ -168,7 +159,7 @@ LRESULT CALLBACK PopupWndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam break; case IDM_M6: // open external log - ViewLog(wParam, 0); + ppro->ViewLog(wParam, 0); break; case IDM_M7: // display contact menu @@ -197,7 +188,7 @@ LRESULT CALLBACK PopupWndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam return DefWindowProc(hWnd, uMsg, wParam, lParam);//FALSE; } -//============ POPUP OPTIONS ============ +///////////////////////////////////////////////////////////////////////////////////////// struct { @@ -218,225 +209,245 @@ static void SelectMenuItem(HMENU hMenu, int Check) 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) +class CPopupOptsDlg : public CWeatherDlgBase { - wchar_t 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, _countof(str)); - int num = _wtoi(str); - opt.pDelay = num; - - // other options - opt.UseWinColors = (uint8_t)IsDlgButtonChecked(hdlg, IDC_USEWINCOLORS); - opt.UpdatePopup = (uint8_t)IsDlgButtonChecked(hdlg, IDC_POP1); - opt.AlertPopup = (uint8_t)IsDlgButtonChecked(hdlg, IDC_POP2); - opt.PopupOnChange = (uint8_t)IsDlgButtonChecked(hdlg, IDC_CH); - opt.ShowWarnings = (uint8_t)IsDlgButtonChecked(hdlg, IDC_W); -} + CCtrlEdit edtDelay; + CCtrlCheck chkUseWin; + CCtrlButton btnLeft, btnRight, btnPD1, btnPD2, btnPD3, btnPdef, btnVars, btnPreview; + + // temporary read the current option to memory + // but does not write to the database + void ReadPopupOpt(HWND hdlg) + { + wchar_t str[512]; + auto &opt = m_proto->opt; -// copied and modified from NewStatusNotify -INT_PTR CALLBACK DlgPopupOpts(HWND hdlg, UINT msg, WPARAM wParam, LPARAM lParam) -{ - int ID; - HMENU hMenu, hMenu1; - RECT pos; - HWND button; - MCONTACT hContact; + // 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, _countof(str)); + int num = _wtoi(str); + opt.pDelay = num; - switch (msg) { - case WM_INITDIALOG: - TranslateDialogDefault(hdlg); - SaveOptions(); + // other options + opt.UseWinColors = chkUseWin.IsChecked(); + opt.UpdatePopup = (uint8_t)IsDlgButtonChecked(hdlg, IDC_POP1); + opt.AlertPopup = (uint8_t)IsDlgButtonChecked(hdlg, IDC_POP2); + opt.PopupOnChange = (uint8_t)IsDlgButtonChecked(hdlg, IDC_CH); + opt.ShowWarnings = (uint8_t)IsDlgButtonChecked(hdlg, IDC_W); + } + +public: + CPopupOptsDlg(CWeatherProto *ppro) : + CWeatherDlgBase(ppro, IDD_POPUP), + btnPD1(this, IDC_PD1), + btnPD2(this, IDC_PD2), + btnPD3(this, IDC_PD3), + btnPdef(this, IDC_PDEF), + btnVars(this, IDC_VAR3), + btnLeft(this, IDC_LeftClick), + btnRight(this, IDC_RightClick), + btnPreview(this, IDC_PREVIEW), + edtDelay(this, IDC_DELAY), + chkUseWin(this, IDC_USEWINCOLORS) + { + edtDelay.OnChange = Callback(this, &CPopupOptsDlg::onChanged_Delay); + chkUseWin.OnChange = Callback(this, &CPopupOptsDlg::onChanged_UseWin); + + btnPD1.OnClick = Callback(this, &CPopupOptsDlg::onClick_PD1); + btnPD2.OnClick = Callback(this, &CPopupOptsDlg::onClick_PD2); + btnPD3.OnClick = Callback(this, &CPopupOptsDlg::onChanged_Delay); + btnPdef.OnClick = Callback(this, &CPopupOptsDlg::onClick_Pdef); + btnVars.OnClick = Callback(this, &CPopupOptsDlg::onClick_Vars); + btnLeft.OnClick = Callback(this, &CPopupOptsDlg::onClick_Left); + btnRight.OnClick = Callback(this, &CPopupOptsDlg::onClick_Right); + btnPreview.OnClick = Callback(this, &CPopupOptsDlg::onClick_Preview); + } + + bool OnInitDialog() override + { + m_proto->SaveOptions(); // click actions - hMenu = LoadMenu(g_plugin.getInst(), MAKEINTRESOURCE(IDR_PMENU)); - hMenu1 = GetSubMenu(hMenu, 0); + HMENU hMenu = LoadMenu(g_plugin.getInst(), MAKEINTRESOURCE(IDR_PMENU)); + HMENU hMenu1 = GetSubMenu(hMenu, 0); wchar_t str[512]; - GetMenuString(hMenu1, opt.LeftClickAction, str, _countof(str), MF_BYCOMMAND); - SetDlgItemText(hdlg, IDC_LeftClick, TranslateW(str)); - GetMenuString(hMenu1, opt.RightClickAction, str, _countof(str), MF_BYCOMMAND); - SetDlgItemText(hdlg, IDC_RightClick, TranslateW(str)); + auto &opt = m_proto->opt; + GetMenuStringW(hMenu1, opt.LeftClickAction, str, _countof(str), MF_BYCOMMAND); + SetDlgItemTextW(m_hwnd, IDC_LeftClick, TranslateW(str)); + GetMenuStringW(hMenu1, opt.RightClickAction, str, _countof(str), MF_BYCOMMAND); + SetDlgItemTextW(m_hwnd, IDC_RightClick, TranslateW(str)); DestroyMenu(hMenu); // other options - CheckDlgButton(hdlg, IDC_E, g_plugin.bPopups ? BST_CHECKED : BST_UNCHECKED); - CheckDlgButton(hdlg, IDC_POP2, opt.AlertPopup ? BST_CHECKED : BST_UNCHECKED); - CheckDlgButton(hdlg, IDC_POP1, opt.UpdatePopup ? BST_CHECKED : BST_UNCHECKED); - CheckDlgButton(hdlg, IDC_CH, opt.PopupOnChange ? BST_CHECKED : BST_UNCHECKED); - CheckDlgButton(hdlg, IDC_W, opt.ShowWarnings ? BST_CHECKED : BST_UNCHECKED); + CheckDlgButton(m_hwnd, IDC_POP2, opt.AlertPopup ? BST_CHECKED : BST_UNCHECKED); + CheckDlgButton(m_hwnd, IDC_POP1, opt.UpdatePopup ? BST_CHECKED : BST_UNCHECKED); + CheckDlgButton(m_hwnd, IDC_CH, opt.PopupOnChange ? BST_CHECKED : BST_UNCHECKED); + CheckDlgButton(m_hwnd, IDC_W, opt.ShowWarnings ? BST_CHECKED : BST_UNCHECKED); for (auto &it : controls) - SetDlgItemText(hdlg, it.id, GetTextValue(it.c)); + SetDlgItemText(m_hwnd, it.id, m_proto->GetTextValue(it.c)); // setting popup delay option _ltow(opt.pDelay, str, 10); - SetDlgItemText(hdlg, IDC_DELAY, str); + SetDlgItemText(m_hwnd, IDC_DELAY, str); if (opt.pDelay == -1) - CheckRadioButton(hdlg, IDC_PD1, IDC_PD3, IDC_PD2); + CheckRadioButton(m_hwnd, IDC_PD1, IDC_PD3, IDC_PD2); else if (opt.pDelay == 0) - CheckRadioButton(hdlg, IDC_PD1, IDC_PD3, IDC_PD1); + CheckRadioButton(m_hwnd, IDC_PD1, IDC_PD3, IDC_PD1); else - CheckRadioButton(hdlg, IDC_PD1, IDC_PD3, IDC_PD3); + CheckRadioButton(m_hwnd, 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); + SendDlgItemMessage(m_hwnd, IDC_BGCOLOUR, CPM_SETCOLOUR, 0, opt.BGColour); + SendDlgItemMessage(m_hwnd, 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); + chkUseWin.SetState(opt.UseWinColors); // buttons - SendDlgItemMessage(hdlg, IDC_PREVIEW, BUTTONSETASFLATBTN, TRUE, 0); - SendDlgItemMessage(hdlg, IDC_PDEF, BUTTONSETASFLATBTN, TRUE, 0); - SendDlgItemMessage(hdlg, IDC_LeftClick, BUTTONSETASFLATBTN, TRUE, 0); - SendDlgItemMessage(hdlg, IDC_RightClick, BUTTONSETASFLATBTN, TRUE, 0); - SendDlgItemMessage(hdlg, IDC_VAR3, BUTTONSETASFLATBTN, TRUE, 0); - return TRUE; + SendDlgItemMessage(m_hwnd, IDC_PREVIEW, BUTTONSETASFLATBTN, TRUE, 0); + SendDlgItemMessage(m_hwnd, IDC_PDEF, BUTTONSETASFLATBTN, TRUE, 0); + SendDlgItemMessage(m_hwnd, IDC_LeftClick, BUTTONSETASFLATBTN, TRUE, 0); + SendDlgItemMessage(m_hwnd, IDC_RightClick, BUTTONSETASFLATBTN, TRUE, 0); + SendDlgItemMessage(m_hwnd, 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; + bool OnApply() override + { + ReadPopupOpt(m_hwnd); + + wchar_t textstr[MAX_TEXT_SIZE]; + for (auto &it : controls) { + GetDlgItemText(m_hwnd, it.id, textstr, _countof(textstr)); + if (!mir_wstrcmpi(textstr, GetDefaultText(it.c))) + m_proto->delSetting(it.setting); + else + m_proto->setWString(it.setting, textstr); + } - 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; + // save the options, and update main menu + m_proto->SaveOptions(); + return true; + } - case IDC_E: - case IDC_CH: - SendMessage(GetParent(hdlg), PSM_CHANGED, 0, 0); - break; + void onChanged_UseWin(CCtrlCheck *pCheck) + { + // use window color - enable/disable color selection controls + bool bEnable = !pCheck->IsChecked(); + EnableWindow(GetDlgItem(m_hwnd, IDC_BGCOLOUR), bEnable); + EnableWindow(GetDlgItem(m_hwnd, IDC_TEXTCOLOUR), bEnable); + } - case IDC_RightClick: - // right click action selection menu - button = GetDlgItem(hdlg, IDC_RightClick); - GetWindowRect(button, &pos); - - hMenu = LoadMenu(g_plugin.getInst(), 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, nullptr); - if (ID) - opt.RightClickAction = ID; - DestroyMenu(hMenu); - - hMenu = LoadMenu(g_plugin.getInst(), MAKEINTRESOURCE(IDR_PMENU)); - hMenu1 = GetSubMenu(hMenu, 0); - GetMenuString(hMenu1, opt.RightClickAction, str, _countof(str), MF_BYCOMMAND); - SetDlgItemText(hdlg, IDC_RightClick, TranslateW(str)); - DestroyMenu(hMenu); - break; + void onClick_Right(CCtrlButton *) + { + // right click action selection menu + RECT pos; + GetWindowRect(GetDlgItem(m_hwnd, IDC_RightClick), &pos); + + HMENU hMenu = LoadMenu(g_plugin.getInst(), MAKEINTRESOURCE(IDR_PMENU)); + HMENU hMenu1 = GetSubMenu(hMenu, 0); + TranslateMenu(hMenu1); + SelectMenuItem(hMenu1, m_proto->opt.RightClickAction); + int ID = TrackPopupMenu(hMenu1, TPM_LEFTBUTTON | TPM_RETURNCMD, pos.left, pos.bottom, 0, m_hwnd, nullptr); + if (ID) + m_proto->opt.RightClickAction = ID; + DestroyMenu(hMenu); - case IDC_LeftClick: - // left click action selection menu - button = GetDlgItem(hdlg, IDC_LeftClick); - GetWindowRect(button, &pos); - - hMenu = LoadMenu(g_plugin.getInst(), 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, nullptr); - if (ID) opt.LeftClickAction = ID; - DestroyMenu(hMenu); - - hMenu = LoadMenu(g_plugin.getInst(), MAKEINTRESOURCE(IDR_PMENU)); - hMenu1 = GetSubMenu(hMenu, 0); - GetMenuString(hMenu1, opt.LeftClickAction, str, _countof(str), MF_BYCOMMAND); - SetDlgItemText(hdlg, IDC_LeftClick, TranslateW(str)); - DestroyMenu(hMenu); - break; + hMenu = LoadMenu(g_plugin.getInst(), MAKEINTRESOURCE(IDR_PMENU)); + hMenu1 = GetSubMenu(hMenu, 0); - case IDC_PD1: - // Popup delay setting from popup plugin - SetDlgItemText(hdlg, IDC_DELAY, L"0"); - CheckRadioButton(hdlg, IDC_PD1, IDC_PD3, IDC_PD1); - break; + wchar_t str[512]; + GetMenuString(hMenu1, m_proto->opt.RightClickAction, str, _countof(str), MF_BYCOMMAND); + SetDlgItemText(m_hwnd, IDC_RightClick, TranslateW(str)); + DestroyMenu(hMenu); + } - case IDC_PD2: - // Popup delay = permanent - SetDlgItemText(hdlg, IDC_DELAY, L"-1"); - CheckRadioButton(hdlg, IDC_PD1, IDC_PD3, IDC_PD2); - break; + void onClick_Left(CCtrlButton *) + { + // left click action selection menu + RECT pos; + GetWindowRect(GetDlgItem(m_hwnd, IDC_LeftClick), &pos); + + HMENU hMenu = LoadMenu(g_plugin.getInst(), MAKEINTRESOURCE(IDR_PMENU)); + HMENU hMenu1 = GetSubMenu(hMenu, 0); + TranslateMenu(hMenu1); + SelectMenuItem(hMenu1, m_proto->opt.LeftClickAction); + int ID = TrackPopupMenu(hMenu1, TPM_LEFTBUTTON | TPM_RETURNCMD, pos.left, pos.bottom, 0, m_hwnd, nullptr); + if (ID) + m_proto->opt.LeftClickAction = ID; + DestroyMenu(hMenu); - case IDC_DELAY: - // if text is edited - CheckRadioButton(hdlg, IDC_PD1, IDC_PD3, IDC_PD3); - break; + hMenu = LoadMenu(g_plugin.getInst(), MAKEINTRESOURCE(IDR_PMENU)); + hMenu1 = GetSubMenu(hMenu, 0); - case IDC_PDEF: - // set the default value for popup texts - for (auto &it : controls) - SetDlgItemText(hdlg, it.id, GetDefaultText(it.c)); - break; + wchar_t str[512]; + GetMenuString(hMenu1, m_proto->opt.LeftClickAction, str, _countof(str), MF_BYCOMMAND); + SetDlgItemText(m_hwnd, IDC_LeftClick, TranslateW(str)); + DestroyMenu(hMenu); + } - case IDC_VAR3: - // display variable list - { - CMStringW wszText; - wszText += L" \n"; // to make the message box wider - wszText += 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"); - wszText += L"\n"; - wszText += TranslateT("%[..]\tcustom variables"); - MessageBox(nullptr, wszText, TranslateT("Variable List"), MB_OK | MB_ICONASTERISK | MB_TOPMOST); - } - break; + void onClick_PD1(CCtrlButton *) + { + // Popup delay setting from popup plugin + SetDlgItemText(m_hwnd, IDC_DELAY, L"0"); + CheckRadioButton(m_hwnd, IDC_PD1, IDC_PD3, IDC_PD1); + } - 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 - LoadOptions(); // restore old option in memory - opt.DefStn = hContact; - break; - } - break; + void onClick_PD2(CCtrlButton *) + { + // Popup delay = permanent + SetDlgItemText(m_hwnd, IDC_DELAY, L"-1"); + CheckRadioButton(m_hwnd, IDC_PD1, IDC_PD3, IDC_PD2); + } - case WM_NOTIFY: //Here we have pressed either the OK or the APPLY button. - switch (((LPNMHDR)lParam)->code) { - case PSN_APPLY: - ReadPopupOpt(hdlg); - - wchar_t textstr[MAX_TEXT_SIZE]; - for (auto &it : controls) { - GetDlgItemText(hdlg, it.id, textstr, _countof(textstr)); - if (!mir_wstrcmpi(textstr, GetDefaultText(it.c))) - g_plugin.delSetting(it.setting); - else - g_plugin.setWString(it.setting, textstr); - } - - // save the options, and update main menu - SaveOptions(); - return TRUE; - } - break; + void onChanged_Delay(CCtrlEdit *) + { + // if text is edited + CheckRadioButton(m_hwnd, IDC_PD1, IDC_PD3, IDC_PD3); } - return FALSE; + + void onClick_Pdef(CCtrlButton *) + { + // set the default value for popup texts + for (auto &it : controls) + SetDlgItemText(m_hwnd, it.id, GetDefaultText(it.c)); + } + + void onClick_Vars(CCtrlButton *) + { + // display variable list + CMStringW wszText; + wszText += L" \n"; // to make the message box wider + wszText += 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"); + wszText += L"\n"; + wszText += TranslateT("%[..]\tcustom variables"); + MessageBox(nullptr, wszText, TranslateT("Variable List"), MB_OK | MB_ICONASTERISK | MB_TOPMOST); + } + + void onClick_Preview(CCtrlButton *) + { + // popup preview + MCONTACT hContact = m_proto->opt.DefStn; + ReadPopupOpt(m_hwnd); // read new options to memory + m_proto->WeatherPopup(m_proto->opt.DefStn, true); // display popup using new opt + m_proto->LoadOptions(); // restore old option in memory + m_proto->opt.DefStn = hContact; + } +}; + +void CWeatherProto::InitPopupOptions(WPARAM wParam) +{ + // if popup service exists, load the weather popup options + OPTIONSDIALOGPAGE odp = {}; + odp.flags = ODPF_BOLDGROUPS | ODPF_UNICODE; + odp.position = 100000000; + odp.szGroup.w = LPGENW("Popups"); + odp.szTitle.w = m_tszUserName; + odp.pDialog = new CPopupOptsDlg(this); + g_plugin.addOptions(wParam, &odp); } diff --git a/protocols/Weather/src/weather_proto.cpp b/protocols/Weather/src/weather_proto.cpp new file mode 100644 index 0000000000..fdb1fe443d --- /dev/null +++ b/protocols/Weather/src/weather_proto.cpp @@ -0,0 +1,166 @@ +/* +Copyright (C) 2012-25 Miranda NG team (https://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 "stdafx.h" + +CWeatherProto::CWeatherProto(const char *protoName, const wchar_t *userName) : + PROTO<CWeatherProto>(protoName, userName), + m_impl(*this), + m_bPopups(m_szModuleName, "UsePopup", true), + m_szApiKey(m_szModuleName, "ApiKey", L"") +{ + m_hProtoIcon = g_plugin.getIconHandle(IDI_ICON); + + CreateProtoService(PS_GETAVATARINFO, &CWeatherProto::GetAvatarInfoSvc); + CreateProtoService(PS_GETADVANCEDSTATUSICON, &CWeatherProto::AdvancedStatusIconSvc); + + HookProtoEvent(ME_OPT_INITIALISE, &CWeatherProto::OptInit); + HookProtoEvent(ME_CLIST_DOUBLECLICKED, &CWeatherProto::BriefInfoEvt); + + // load options and set defaults + LoadOptions(); + + // reset the weather data at startup for individual contacts + EraseAllInfo(); + + // popup initialization + CMStringW wszTitle(FORMAT, L"%s %s", m_tszUserName, TranslateT("notifications")); + g_plugin.addPopupOption(wszTitle, m_bPopups); + + // netlib + NETLIBUSER nlu = {}; + nlu.flags = NUF_OUTGOING | NUF_HTTPCONNS | NUF_NOHTTPSOPTION | NUF_UNICODE; + nlu.szSettingsModule = m_szModuleName; + nlu.szDescriptiveName.w = m_tszUserName; + m_hNetlibUser = Netlib_RegisterUser(&nlu); +} + +CWeatherProto::~CWeatherProto() +{ + DestroyMwin(); + DestroyUpdateList(); +} + +void CWeatherProto::OnModulesLoaded() +{ + InitMwin(); + InitMenuItems(); + + // timer for the first update + m_impl.m_start.Start(5000); // first update is 5 sec after load + + // weather user detail + HookProtoEvent(ME_USERINFO_INITIALISE, &CWeatherProto::UserInfoInit); + HookProtoEvent(ME_TTB_MODULELOADED, &CWeatherProto::OnToolbarLoaded); +} + +int CWeatherProto::OnToolbarLoaded(WPARAM, LPARAM) +{ + CMStringA szName(FORMAT, "%s/Enabled", m_szModuleName); + + TTBButton ttb = {}; + ttb.name = LPGEN("Enable/disable auto update"); + ttb.pszService = szName.GetBuffer(); + ttb.pszTooltipUp = LPGEN("Auto Update Enabled"); + ttb.pszTooltipDn = LPGEN("Auto Update Disabled"); + ttb.hIconHandleUp = g_plugin.getIconHandle(IDI_ICON); + ttb.hIconHandleDn = g_plugin.getIconHandle(IDI_DISABLED); + ttb.dwFlags = (getByte("AutoUpdate", 1) ? 0 : TTBBF_PUSHED) | TTBBF_ASPUSHBUTTON | TTBBF_VISIBLE; + hTBButton = g_plugin.addTTB(&ttb); + return 0; +} + +void CWeatherProto::OnShutdown() +{ + m_impl.m_update.Stop(); + + SaveOptions(); // save options once more +} + +///////////////////////////////////////////////////////////////////////////////////////// + +int CWeatherProto::SetStatus(int new_status) +{ + // if we don't want to show status for default station + if (m_iStatus != new_status) { + int old_status = m_iStatus; + m_iStatus = new_status != ID_STATUS_OFFLINE ? ID_STATUS_ONLINE : ID_STATUS_OFFLINE; + + ProtoBroadcastAck(NULL, ACKTYPE_STATUS, ACKRESULT_SUCCESS, (HANDLE)old_status, m_iStatus); + + UpdateMenu(m_iStatus != ID_STATUS_OFFLINE); + if (m_iStatus != ID_STATUS_OFFLINE) + UpdateAll(FALSE, FALSE); + } + + return 0; +} + +// get capabilities protocol service function +INT_PTR CWeatherProto::GetCaps(int type, MCONTACT) +{ + switch (type) { + case PFLAGNUM_1: + // support search and visible list + return PF1_BASICSEARCH | PF1_ADDSEARCHRES | PF1_EXTSEARCH | PF1_MODEMSGRECV; + + case PFLAGNUM_2: + case PFLAGNUM_5: + return PF2_ONLINE | PF2_INVISIBLE | PF2_SHORTAWAY | PF2_LONGAWAY | PF2_LIGHTDND | PF2_HEAVYDND | PF2_FREECHAT; + + case PFLAGNUM_4: + return PF4_AVATARS | PF4_NOCUSTOMAUTH | PF4_NOAUTHDENYREASON | PF4_FORCEAUTH; + + case PFLAG_UNIQUEIDTEXT: + return (INT_PTR)TranslateT("Coordinates"); + } + return 0; +} + +///////////////////////////////////////////////////////////////////////////////////////// +// nothing to do here because weather proto do not need to retrieve contact info form network +// so just return a 0 + +void CWeatherProto::AckThreadProc(void *param) +{ + Sleep(100); + + ProtoBroadcastAck((DWORD_PTR)param, ACKTYPE_GETINFO, ACKRESULT_SUCCESS, (HANDLE)1); +} + +int CWeatherProto::GetInfo(MCONTACT hContact, int) +{ + ForkThread(&CWeatherProto::AckThreadProc, (void *)hContact); + return 0; +} + +///////////////////////////////////////////////////////////////////////////////////////// + +void __cdecl CWeatherProto::GetAwayMsgThread(void *arg) +{ + Sleep(100); + + MCONTACT hContact = (DWORD_PTR)arg; + ptrW wszStatus(db_get_wsa(hContact, "CList", "StatusMsg")); + ProtoBroadcastAck(hContact, ACKTYPE_AWAYMSG, ACKRESULT_SUCCESS, this, wszStatus); +} + +HANDLE CWeatherProto::GetAwayMsg(MCONTACT hContact) +{ + ForkThread(&CWeatherProto::GetAwayMsgThread, (void*)hContact); + return this; +} diff --git a/protocols/Weather/src/weather_svcs.cpp b/protocols/Weather/src/weather_svcs.cpp index daeb7f8bd1..6f897e3d7a 100644 --- a/protocols/Weather/src/weather_svcs.cpp +++ b/protocols/Weather/src/weather_svcs.cpp @@ -26,89 +26,8 @@ building/changing the weather menu items. #include "stdafx.h" -static HGENMENU hEnableDisableMenu; - extern VARSW g_pwszIconsName; -//============ MIRANDA PROTOCOL SERVICES ============ - -// protocol service function for setting weather protocol status -INT_PTR WeatherSetStatus(WPARAM new_status, LPARAM) -{ - // if we don't want to show status for default station - if (status != new_status) { - old_status = status; - status = new_status = new_status != ID_STATUS_OFFLINE ? ID_STATUS_ONLINE : ID_STATUS_OFFLINE; - - if (!opt.NoProtoCondition) { - ProtoBroadcastAck(MODULENAME, 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) -{ - INT_PTR ret = 0; - - switch (wParam) { - case PFLAGNUM_1: - // support search and visible list - ret = PF1_BASICSEARCH | PF1_ADDSEARCHRES | PF1_EXTSEARCH | PF1_MODEMSGRECV; - break; - - case PFLAGNUM_2: - ret = PF2_ONLINE | PF2_INVISIBLE | PF2_SHORTAWAY | PF2_LONGAWAY | PF2_LIGHTDND | PF2_HEAVYDND | PF2_FREECHAT; - break; - - case PFLAGNUM_4: - ret = PF4_AVATARS | PF4_NOCUSTOMAUTH | PF4_NOAUTHDENYREASON | 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; - break; - - case PFLAG_UNIQUEIDTEXT: - ret = (INT_PTR)TranslateT("Station ID"); - break; - } - return ret; -} - -// protocol service function to get the current status of the protocol -INT_PTR WeatherGetStatus(WPARAM, LPARAM) -{ - return status; -} - -// protocol service function to get the icon of the protocol -INT_PTR WeatherLoadIcon(WPARAM wParam, LPARAM) -{ - return (LOWORD(wParam) == PLI_PROTOCOL) ? (INT_PTR)CopyIcon(g_plugin.getIcon(IDI_ICON)) : 0; -} - -static void __cdecl AckThreadProc(HANDLE param) -{ - Sleep(100); - ProtoBroadcastAck(MODULENAME, (DWORD_PTR)param, ACKTYPE_GETINFO, ACKRESULT_SUCCESS, (HANDLE)1); -} - -// 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, LPARAM lParam) -{ - CCSDATA *ccs = (CCSDATA *)lParam; - mir_forkthread(AckThreadProc, (void*)ccs->hContact); - return 0; -} - ///////////////////////////////////////////////////////////////////////////////////////// // avatars @@ -132,7 +51,7 @@ static statusIcons[MAX_COND] = { L"Light", 130, ID_STATUS_INVISIBLE }, }; -INT_PTR WeatherGetAvatarInfo(WPARAM, LPARAM lParam) +INT_PTR CWeatherProto::GetAvatarInfoSvc(WPARAM, LPARAM lParam) { wchar_t szSearchPath[MAX_PATH]; GetModuleFileName(GetModuleHandle(nullptr), szSearchPath, _countof(szSearchPath)); @@ -144,7 +63,7 @@ INT_PTR WeatherGetAvatarInfo(WPARAM, LPARAM lParam) szSearchPath[0] = 0; PROTO_AVATAR_INFORMATION *pai = (PROTO_AVATAR_INFORMATION*)lParam; - int iCond = g_plugin.getWord(pai->hContact, "StatusIcon", -1); + int iCond = getWord(pai->hContact, "StatusIcon", -1); if (iCond < 0 || iCond >= MAX_COND) return GAIR_NOAVATAR; @@ -163,34 +82,15 @@ INT_PTR WeatherGetAvatarInfo(WPARAM, LPARAM lParam) return GAIR_NOAVATAR; } -void AvatarDownloaded(MCONTACT hContact) +void CWeatherProto::AvatarDownloaded(MCONTACT hContact) { PROTO_AVATAR_INFORMATION ai = {}; ai.hContact = hContact; - if (WeatherGetAvatarInfo(GAIF_FORCE, (LPARAM)&ai) == GAIR_SUCCESS) - ProtoBroadcastAck(MODULENAME, hContact, ACKTYPE_AVATAR, ACKRESULT_SUCCESS, &ai); + if (GetAvatarInfoSvc(GAIF_FORCE, (LPARAM)&ai) == GAIR_SUCCESS) + ProtoBroadcastAck(hContact, ACKTYPE_AVATAR, ACKRESULT_SUCCESS, &ai); else - ProtoBroadcastAck(MODULENAME, hContact, ACKTYPE_AVATAR, ACKRESULT_STATUS, nullptr); -} - -static void __cdecl WeatherGetAwayMsgThread(void *arg) -{ - Sleep(100); - - MCONTACT hContact = (DWORD_PTR)arg; - ptrW wszStatus(db_get_wsa(hContact, "CList", "StatusMsg")); - ProtoBroadcastAck(MODULENAME, hContact, ACKTYPE_AWAYMSG, ACKRESULT_SUCCESS, (HANDLE)1, wszStatus); -} - -static INT_PTR WeatherGetAwayMsg(WPARAM, LPARAM lParam) -{ - CCSDATA* ccs = (CCSDATA*)lParam; - if (ccs == nullptr) - return 0; - - mir_forkthread(WeatherGetAwayMsgThread, (void*)ccs->hContact); - return 1; + ProtoBroadcastAck(hContact, ACKTYPE_AVATAR, ACKRESULT_STATUS, nullptr); } ///////////////////////////////////////////////////////////////////////////////////////// @@ -202,18 +102,18 @@ void ClearStatusIcons() it.clistIconId = 0; } -int MapCondToStatus(MCONTACT hContact) +int CWeatherProto::MapCondToStatus(MCONTACT hContact) { - int iCond = g_plugin.getWord(hContact, "StatusIcon", -1); + int iCond = getWord(hContact, "StatusIcon", -1); if (iCond < 0 || iCond >= MAX_COND) return ID_STATUS_OFFLINE; return statusIcons[iCond].status; } -HICON GetStatusIcon(MCONTACT hContact) +HICON CWeatherProto::GetStatusIcon(MCONTACT hContact) { - int iCond = g_plugin.getWord(hContact, "StatusIcon", -1); + int iCond = getWord(hContact, "StatusIcon", -1); if (iCond < 0 || iCond >= MAX_COND) return nullptr; @@ -224,9 +124,9 @@ HICON GetStatusIcon(MCONTACT hContact) return ImageList_GetIcon(Clist_GetImageList(), pIcon.clistIconId, ILD_NORMAL); } -HICON GetStatusIconBig(MCONTACT hContact) +HICON CWeatherProto::GetStatusIconBig(MCONTACT hContact) { - int iCond = g_plugin.getWord(hContact, "StatusIcon", -1); + int iCond = getWord(hContact, "StatusIcon", -1); if (iCond < 0 || iCond >= MAX_COND) return nullptr; @@ -236,12 +136,12 @@ HICON GetStatusIconBig(MCONTACT hContact) return hIcon; } -static INT_PTR WeatherAdvancedStatusIcon(WPARAM hContact, LPARAM) +INT_PTR CWeatherProto::AdvancedStatusIconSvc(WPARAM hContact, LPARAM) { if (!hContact || !g_plugin.hIconsDll) return -1; - int iCond = g_plugin.getWord(hContact, "StatusIcon", -1); + int iCond = getWord(hContact, "StatusIcon", -1); if (iCond < 0 || iCond >= MAX_COND) return -1; @@ -252,34 +152,14 @@ static INT_PTR WeatherAdvancedStatusIcon(WPARAM hContact, LPARAM) return MAKELONG(0, pIcon.clistIconId); } -//============ PROTOCOL INITIALIZATION ============ -// protocol services -void InitServices(void) -{ - CreateProtoServiceFunction(MODULENAME, PS_GETCAPS, WeatherGetCaps); - CreateProtoServiceFunction(MODULENAME, PS_LOADICON, WeatherLoadIcon); - CreateProtoServiceFunction(MODULENAME, PS_SETSTATUS, WeatherSetStatus); - CreateProtoServiceFunction(MODULENAME, PS_GETSTATUS, WeatherGetStatus); - CreateProtoServiceFunction(MODULENAME, PS_BASICSEARCH, WeatherBasicSearch); - CreateProtoServiceFunction(MODULENAME, PS_SEARCHBYEMAIL, WeatherBasicSearch); - CreateProtoServiceFunction(MODULENAME, PS_ADDTOLIST, WeatherAddToList); - CreateProtoServiceFunction(MODULENAME, PS_GETINFO, WeatherGetInfo); - CreateProtoServiceFunction(MODULENAME, PS_GETAVATARINFO, WeatherGetAvatarInfo); - CreateProtoServiceFunction(MODULENAME, PS_GETAWAYMSG, WeatherGetAwayMsg); - CreateProtoServiceFunction(MODULENAME, PS_CREATEADVSEARCHUI, WeatherCreateAdvancedSearchUI); - CreateProtoServiceFunction(MODULENAME, PS_SEARCHBYADVANCED, WeatherAdvancedSearch); - CreateProtoServiceFunction(MODULENAME, PS_GETADVANCEDSTATUSICON, WeatherAdvancedStatusIcon); - - CreateProtoServiceFunction(MODULENAME, MS_WEATHER_GETDISPLAY, GetDisplaySvcFunc); -} - -//============ MENU INITIALIZATION ============ +///////////////////////////////////////////////////////////////////////////////////////// +// menus -void UpdateMenu(BOOL State) +void CWeatherProto::UpdateMenu(BOOL State) { // update option setting opt.CAutoUpdate = State; - g_plugin.setByte("AutoUpdate", (uint8_t)State); + setByte("AutoUpdate", (uint8_t)State); if (State) { // to enable auto-update Menu_ModifyItem(hEnableDisableMenu, LPGENW("Auto Update Enabled"), g_plugin.getIconHandle(IDI_ICON)); @@ -293,119 +173,137 @@ void UpdateMenu(BOOL State) CallService(MS_TTB_SETBUTTONSTATE, (WPARAM)hTBButton, !State ? TTBST_PUSHED : 0); } +///////////////////////////////////////////////////////////////////////////////////////// // update the weather auto-update menu item when click on it -static INT_PTR EnableDisableCmd(WPARAM wParam, LPARAM lParam) + +INT_PTR CWeatherProto::EnableDisableCmd(WPARAM wParam, LPARAM lParam) { UpdateMenu(wParam == TRUE ? (BOOL)lParam : !opt.CAutoUpdate); return 0; } -// displays contact info dialog -static INT_PTR BriefInfoSvc(WPARAM wParam, LPARAM lParam) +///////////////////////////////////////////////////////////////////////////////////////// +// adding weather contact menus + +static std::vector<HGENMENU> g_menuItems; + +static int OnPrebuildMenu(WPARAM hContact, LPARAM) { - return BriefInfo(wParam, lParam); + auto *ppro = CMPlugin::getInstance(hContact); + for (auto &it : g_menuItems) + Menu_ShowItem(it, ppro != 0); + + if (ppro) + ppro->BuildContactMenu(hContact); + return 0; } -// adding weather contact menus -// copied and modified form "modified MSN Protocol" -void AddMenuItems(void) +void CWeatherProto::GlobalMenuInit() { CMenuItem mi(&g_plugin); // contact menu SET_UID(mi, 0x266ef52b, 0x869a, 0x4cac, 0xa9, 0xf8, 0xea, 0x5b, 0xb8, 0xab, 0xe0, 0x24); - CreateServiceFunction(MS_WEATHER_UPDATE, UpdateSingleStation); mi.position = -0x7FFFFFFA; mi.hIcolibItem = g_plugin.getIconHandle(IDI_UPDATE); mi.name.a = LPGEN("Update Weather"); - mi.pszService = MS_WEATHER_UPDATE; - Menu_AddContactMenuItem(&mi, MODULENAME); + mi.pszService = MODULENAME "/Update"; + g_menuItems.push_back(Menu_AddContactMenuItem(&mi)); + CreateServiceFunction(mi.pszService, GlobalService<&CWeatherProto::UpdateSingleStation>); SET_UID(mi, 0x45361b4, 0x8de, 0x44b4, 0x8f, 0x11, 0x9b, 0xe9, 0x6e, 0xa8, 0x83, 0x54); - CreateServiceFunction(MS_WEATHER_REFRESH, UpdateSingleRemove); mi.position = -0x7FFFFFF9; mi.hIcolibItem = g_plugin.getIconHandle(IDI_UPDATE2); mi.name.a = LPGEN("Remove Old Data then Update"); - mi.pszService = MS_WEATHER_REFRESH; - Menu_AddContactMenuItem(&mi, MODULENAME); + mi.pszService = MODULENAME "/Refresh"; + g_menuItems.push_back(Menu_AddContactMenuItem(&mi)); + CreateServiceFunction(mi.pszService, GlobalService<&CWeatherProto::UpdateSingleRemove>); SET_UID(mi, 0x4232975e, 0xb181, 0x46a5, 0xb7, 0x6e, 0xd2, 0x5f, 0xef, 0xb8, 0xc4, 0x4d); - CreateServiceFunction(MS_WEATHER_BRIEF, BriefInfoSvc); mi.position = -0x7FFFFFF8; mi.hIcolibItem = g_plugin.getIconHandle(IDI_S); mi.name.a = LPGEN("Brief Information"); - mi.pszService = MS_WEATHER_BRIEF; - Menu_AddContactMenuItem(&mi, MODULENAME); + mi.pszService = MODULENAME "/Brief"; + g_menuItems.push_back(Menu_AddContactMenuItem(&mi)); + CreateServiceFunction(mi.pszService, GlobalService<&CWeatherProto::BriefInfo>); SET_UID(mi, 0x3d6ed729, 0xd49a, 0x4ae9, 0x8e, 0x2, 0x9f, 0xe0, 0xf0, 0x2c, 0xcc, 0xb1); - CreateServiceFunction(MS_WEATHER_COMPLETE, LoadForecast); mi.position = -0x7FFFFFF7; mi.hIcolibItem = g_plugin.getIconHandle(IDI_READ); mi.name.a = LPGEN("Read Complete Forecast"); - mi.pszService = MS_WEATHER_COMPLETE; - Menu_AddContactMenuItem(&mi, MODULENAME); + mi.pszService = MODULENAME "/CompleteForecast"; + g_menuItems.push_back(Menu_AddContactMenuItem(&mi)); + CreateServiceFunction(mi.pszService, GlobalService<&CWeatherProto::LoadForecast>); SET_UID(mi, 0xc4b6c5e0, 0x13c3, 0x4e02, 0x8a, 0xeb, 0xeb, 0x8a, 0xe2, 0x66, 0x40, 0xd4); - CreateServiceFunction(MS_WEATHER_MAP, WeatherMap); mi.position = -0x7FFFFFF6; mi.hIcolibItem = g_plugin.getIconHandle(IDI_MAP); mi.name.a = LPGEN("Weather Map"); - mi.pszService = MS_WEATHER_MAP; - Menu_AddContactMenuItem(&mi, MODULENAME); + mi.pszService = MODULENAME "/Map"; + g_menuItems.push_back(Menu_AddContactMenuItem(&mi)); + CreateServiceFunction(mi.pszService, GlobalService<&CWeatherProto::WeatherMap>); SET_UID(mi, 0xee3ad7f4, 0x3377, 0x4e4c, 0x8f, 0x3c, 0x3b, 0xf5, 0xd4, 0x86, 0x28, 0x25); - CreateServiceFunction(MS_WEATHER_LOG, ViewLog); mi.position = -0x7FFFFFF5; mi.hIcolibItem = g_plugin.getIconHandle(IDI_LOG); mi.name.a = LPGEN("View Log"); - mi.pszService = MS_WEATHER_LOG; - Menu_AddContactMenuItem(&mi, MODULENAME); + mi.pszService = MODULENAME "/Log"; + g_menuItems.push_back(Menu_AddContactMenuItem(&mi)); + CreateServiceFunction(mi.pszService, GlobalService<&CWeatherProto::ViewLog>); SET_UID(mi, 0x1b01cd6a, 0xe5ee, 0x42b4, 0xa1, 0x6d, 0x43, 0xb9, 0x4, 0x58, 0x43, 0x2e); - CreateServiceFunction(MS_WEATHER_EDIT, EditSettings); mi.position = -0x7FFFFFF4; mi.hIcolibItem = g_plugin.getIconHandle(IDI_EDIT); mi.name.a = LPGEN("Edit Settings"); - mi.pszService = MS_WEATHER_EDIT; - Menu_AddContactMenuItem(&mi, MODULENAME); + mi.pszService = MODULENAME "/Edit"; + g_menuItems.push_back(Menu_AddContactMenuItem(&mi)); + CreateServiceFunction(mi.pszService, GlobalService<&CWeatherProto::EditSettings>); - // adding main menu items - mi.root = g_plugin.addRootMenu(MO_MAIN, LPGENW("Weather"), 500099000); + if (ServiceExists(MS_CLIST_FRAMES_ADDFRAME)) { + SET_UID(mi, 0xe193fe9b, 0xf6ad, 0x41ac, 0x95, 0x29, 0x45, 0x4, 0x44, 0xb1, 0xeb, 0x5d); + mi.pszService = MODULENAME "/mwin_menu"; + CreateServiceFunction(mi.pszService, GlobalService<&CWeatherProto::Mwin_MenuClicked>); + mi.position = -0x7FFFFFF0; + mi.hIcolibItem = Skin_GetIconHandle(SKINICON_OTHER_FRAME); + mi.root = nullptr; + mi.name.a = LPGEN("Display in a frame"); + g_menuItems.push_back(hMwinMenu = Menu_AddContactMenuItem(&mi)); + } + + HookEvent(ME_CLIST_PREBUILDCONTACTMENU, &OnPrebuildMenu); +} + +///////////////////////////////////////////////////////////////////////////////////////// +// adding main menu items + +void CWeatherProto::InitMenuItems() +{ + CMenuItem mi(&g_plugin); + mi.root = g_plugin.addRootMenu(MO_MAIN, m_tszUserName, 500099000); Menu_ConfigureItem(mi.root, MCI_OPT_UID, "82809D2F-2CF0-4E15-9350-D257A7748552"); SET_UID(mi, 0x5ad16188, 0xe0a0, 0x4c31, 0x85, 0xc3, 0xe4, 0x85, 0x79, 0x7e, 0x4b, 0x9c); - CreateServiceFunction(MS_WEATHER_ENABLED, EnableDisableCmd); mi.name.a = LPGEN("Enable/Disable Weather Update"); mi.hIcolibItem = g_plugin.getIconHandle(IDI_ICON); mi.position = 10100001; - mi.pszService = MS_WEATHER_ENABLED; - hEnableDisableMenu = Menu_AddMainMenuItem(&mi); + mi.pszService = "/EnableDisable"; + hEnableDisableMenu = Menu_AddMainMenuItem(&mi, m_szModuleName); UpdateMenu(opt.AutoUpdate); + CreateProtoService(mi.pszService, &CWeatherProto::EnableDisableCmd); SET_UID(mi, 0x2b1c2054, 0x2991, 0x4025, 0x87, 0x73, 0xb6, 0xf7, 0x85, 0xac, 0xc7, 0x37); - CreateServiceFunction(MS_WEATHER_UPDATEALL, UpdateAllInfo); mi.position = 20100001; mi.hIcolibItem = g_plugin.getIconHandle(IDI_UPDATE); mi.name.a = LPGEN("Update All Weather"); - mi.pszService = MS_WEATHER_UPDATEALL; - Menu_AddMainMenuItem(&mi); + mi.pszService = "/UpdateAll"; + Menu_AddMainMenuItem(&mi, m_szModuleName); + CreateProtoService(mi.pszService, &CWeatherProto::UpdateAllInfo); SET_UID(mi, 0x8234c00e, 0x788e, 0x424f, 0xbc, 0xc4, 0x2, 0xfd, 0x67, 0x58, 0x2d, 0x19); - CreateServiceFunction(MS_WEATHER_REFRESHALL, UpdateAllRemove); mi.position = 20100002; mi.hIcolibItem = g_plugin.getIconHandle(IDI_UPDATE2); mi.name.a = LPGEN("Remove Old Data then Update All"); - mi.pszService = MS_WEATHER_REFRESHALL; - Menu_AddMainMenuItem(&mi); - - if (ServiceExists(MS_CLIST_FRAMES_ADDFRAME)) { - SET_UID(mi, 0xe193fe9b, 0xf6ad, 0x41ac, 0x95, 0x29, 0x45, 0x4, 0x44, 0xb1, 0xeb, 0x5d); - mi.pszService = "Weather/mwin_menu"; - CreateServiceFunction(mi.pszService, Mwin_MenuClicked); - mi.position = -0x7FFFFFF0; - mi.hIcolibItem = nullptr; - mi.root = nullptr; - mi.name.a = LPGEN("Display in a frame"); - hMwinMenu = Menu_AddContactMenuItem(&mi, MODULENAME); - } + mi.pszService = "/RefreshAll"; + Menu_AddMainMenuItem(&mi, m_szModuleName); + CreateProtoService(mi.pszService, &CWeatherProto::UpdateAllRemove); } diff --git a/protocols/Weather/src/weather_update.cpp b/protocols/Weather/src/weather_update.cpp index fc71bfc0a7..806d41002c 100644 --- a/protocols/Weather/src/weather_update.cpp +++ b/protocols/Weather/src/weather_update.cpp @@ -26,15 +26,12 @@ menu items). #include "stdafx.h" -UPDATELIST *UpdateListHead = nullptr, *UpdateListTail = nullptr; - -//============ RETRIEVE NEW WEATHER ============ -// +///////////////////////////////////////////////////////////////////////////////////////// // retrieve weather info and display / log them // hContact = current contact -int UpdateWeather(MCONTACT hContact) + +int CWeatherProto::UpdateWeather(MCONTACT hContact) { - wchar_t str2[MAX_TEXT_SIZE]; DBVARIANT dbv; BOOL Ch = FALSE; @@ -44,10 +41,10 @@ int UpdateWeather(MCONTACT hContact) dbv.pszVal = ""; // log to netlib log for debug purpose - Netlib_LogfW(hNetlibUser, L"************************************************************************"); - int dbres = g_plugin.getWString(hContact, "Nick", &dbv); + Netlib_LogfW(m_hNetlibUser, L"************************************************************************"); + int dbres = getWString(hContact, "Nick", &dbv); - Netlib_LogfW(hNetlibUser, L"<-- Start update for station -->"); + Netlib_LogfW(m_hNetlibUser, L"<-- Start update for station -->"); // download the info and parse it // result are stored in database @@ -62,12 +59,15 @@ int UpdateWeather(MCONTACT hContact) WPShowMessage(str, SM_WARNING); } // log to netlib - Netlib_LogfW(hNetlibUser, L"Error! Update cannot continue... Start to free memory"); - Netlib_LogfW(hNetlibUser, L"<-- Error occurs while updating station: %s -->", dbv.pwszVal); - if (!dbres) db_free(&dbv); + Netlib_LogfW(m_hNetlibUser, L"Error! Update cannot continue... Start to free memory"); + Netlib_LogfW(m_hNetlibUser, L"<-- Error occurs while updating station: %s -->", dbv.pwszVal); + if (!dbres) + db_free(&dbv); return 1; } - if (!dbres) db_free(&dbv); + + if (!dbres) + db_free(&dbv); // initialize, load new weather Data WEATHERINFO winfo = LoadWeatherInfo(hContact); @@ -77,19 +77,19 @@ int UpdateWeather(MCONTACT hContact) // compare the old condition and determine if the weather had changed if (opt.UpdateOnlyConditionChanged) { // consider condition change - if (!g_plugin.getWString(hContact, "LastCondition", &dbv)) { + if (!getWString(hContact, "LastCondition", &dbv)) { if (mir_wstrcmpi(winfo.cond, dbv.pwszVal)) Ch = TRUE; // the weather condition is changed db_free(&dbv); } else Ch = TRUE; - if (!g_plugin.getWString(hContact, "LastTemperature", &dbv)) { + if (!getWString(hContact, "LastTemperature", &dbv)) { if (mir_wstrcmpi(winfo.temp, dbv.pwszVal)) Ch = TRUE; // the temperature is changed db_free(&dbv); } else Ch = TRUE; } else { // consider update time change - if (!g_plugin.getWString(hContact, "LastUpdate", &dbv)) { + if (!getWString(hContact, "LastUpdate", &dbv)) { if (mir_wstrcmpi(winfo.update, dbv.pwszVal)) Ch = TRUE; // the update time is changed db_free(&dbv); } @@ -99,74 +99,60 @@ int UpdateWeather(MCONTACT hContact) // have weather alert issued? dbres = db_get_ws(hContact, WEATHERCONDITION, "Alert", &dbv); if (!dbres && dbv.pwszVal[0] != 0) { - if (opt.AlertPopup && !g_plugin.getByte(hContact, "DPopUp") && Ch) { + if (opt.AlertPopup && !getByte(hContact, "DPopUp") && Ch) { // display alert popup CMStringW str(FORMAT, L"Alert for %s%c%s", winfo.city, 255, dbv.pwszVal); WPShowMessage(str, SM_WEATHERALERT); } // alert issued, set display to italic if (opt.MakeItalic) - g_plugin.setWord(hContact, "ApparentMode", ID_STATUS_OFFLINE); + setWord(hContact, "ApparentMode", ID_STATUS_OFFLINE); Skin_PlaySound("weatheralert"); } // alert dropped, set the display back to normal - else g_plugin.delSetting(hContact, "ApparentMode"); + else delSetting(hContact, "ApparentMode"); if (!dbres) db_free(&dbv); // backup current condition for checking if the weather is changed or not - g_plugin.setWString(hContact, "LastLog", winfo.update); - g_plugin.setWString(hContact, "LastCondition", winfo.cond); - g_plugin.setWString(hContact, "LastTemperature", winfo.temp); - g_plugin.setWString(hContact, "LastUpdate", winfo.update); + setWString(hContact, "LastLog", winfo.update); + setWString(hContact, "LastCondition", winfo.cond); + setWString(hContact, "LastTemperature", winfo.temp); + setWString(hContact, "LastUpdate", winfo.update); // display condition on contact list int iStatus = MapCondToStatus(winfo.hContact); if (opt.DisCondIcon && iStatus != ID_STATUS_OFFLINE) - g_plugin.setWord(hContact, "Status", ID_STATUS_ONLINE); + setWord(hContact, "Status", ID_STATUS_ONLINE); else - g_plugin.setWord(hContact, "Status", iStatus); + setWord(hContact, "Status", iStatus); AvatarDownloaded(hContact); - GetDisplay(&winfo, GetTextValue('C'), str2); - db_set_ws(hContact, "CList", "MyHandle", str2); + db_set_ws(hContact, "CList", "MyHandle", GetDisplay(&winfo, GetTextValue('C'))); - GetDisplay(&winfo, GetTextValue('S'), str2); - if (str2[0]) + CMStringW str2(GetDisplay(&winfo, GetTextValue('S'))); + if (!str2.IsEmpty()) db_set_ws(hContact, "CList", "StatusMsg", str2); else db_unset(hContact, "CList", "StatusMsg"); - - ProtoBroadcastAck(MODULENAME, hContact, ACKTYPE_AWAYMSG, ACKRESULT_SUCCESS, nullptr, (LPARAM)(str2[0] ? str2 : nullptr)); + ProtoBroadcastAck(hContact, ACKTYPE_AWAYMSG, ACKRESULT_SUCCESS, nullptr, (LPARAM)(str2.IsEmpty() ? nullptr : str2.c_str())); // save descriptions in MyNotes - GetDisplay(&winfo, GetTextValue('N'), str2); - db_set_ws(hContact, "UserInfo", "MyNotes", str2); - GetDisplay(&winfo, GetTextValue('X'), str2); - db_set_ws(hContact, WEATHERCONDITION, "WeatherInfo", str2); + db_set_ws(hContact, "UserInfo", "MyNotes", GetDisplay(&winfo, GetTextValue('N'))); + db_set_ws(hContact, WEATHERCONDITION, "WeatherInfo", GetDisplay(&winfo, GetTextValue('X'))); // set the update tag - g_plugin.setByte(hContact, "IsUpdated", TRUE); - - // save info for default weather condition - if (!mir_wstrcmp(winfo.id, opt.Default) && !opt.NoProtoCondition) { - // save current condition for default station to be displayed after the update - old_status = status; - status = iStatus; - // a workaround for a default station that currently have an n/a icon assigned - if (status == ID_STATUS_OFFLINE) status = NOSTATUSDATA; - ProtoBroadcastAck(MODULENAME, NULL, ACKTYPE_STATUS, ACKRESULT_SUCCESS, (HANDLE)old_status, status); - } + setByte(hContact, "IsUpdated", TRUE); // logging if (Ch) { // play the sound event Skin_PlaySound("weatherupdated"); - if (g_plugin.getByte(hContact, "File")) { + if (getByte(hContact, "File")) { // external log - if (!g_plugin.getWString(hContact, "Log", &dbv)) { + if (!getWString(hContact, "Log", &dbv)) { // for the option for overwriting the file, delete old file first - if (g_plugin.getByte(hContact, "Overwrite")) + if (getByte(hContact, "Overwrite")) DeleteFile(dbv.pwszVal); // open the file and set point to the end of file @@ -174,22 +160,19 @@ int UpdateWeather(MCONTACT hContact) db_free(&dbv); if (file != nullptr) { // write data to the file and close - GetDisplay(&winfo, GetTextValue('E'), str2); - fputws(str2, file); + fputws(GetDisplay(&winfo, GetTextValue('E')), file); fclose(file); } } } - if (g_plugin.getByte(hContact, "History")) { + if (getByte(hContact, "History")) { // internal log using history - GetDisplay(&winfo, GetTextValue('H'), str2); - - T2Utf szMessage(str2); + T2Utf szMessage(GetDisplay(&winfo, GetTextValue('H'))); DBEVENTINFO dbei = {}; - dbei.szModule = MODULENAME; - dbei.timestamp = (uint32_t)time(0); + dbei.szModule = m_szModuleName; + dbei.iTimestamp = (uint32_t)time(0); dbei.flags = DBEF_READ | DBEF_UTF; dbei.eventType = EVENTTYPE_MESSAGE; dbei.pBlob = szMessage; @@ -198,11 +181,11 @@ int UpdateWeather(MCONTACT hContact) } // show the popup - NotifyEventHooks(hHookWeatherUpdated, hContact, (LPARAM)Ch); + WeatherPopup(hContact, Ch); } - Netlib_LogfW(hNetlibUser, L"Update Completed - Start to free memory"); - Netlib_LogfW(hNetlibUser, L"<-- Update successful for station -->"); + Netlib_LogfW(m_hNetlibUser, L"Update Completed - Start to free memory"); + Netlib_LogfW(m_hNetlibUser, L"<-- Update successful for station -->"); // Update frame data UpdateMwinData(hContact); @@ -214,111 +197,84 @@ int UpdateWeather(MCONTACT hContact) return 0; } -//============ UPDATE LIST ============ -// +///////////////////////////////////////////////////////////////////////////////////////// // a linked list queue for updating weather station // this function add a weather contact to the end of queue for update // hContact = current contact -void UpdateListAdd(MCONTACT hContact) -{ - UPDATELIST *newItem = (UPDATELIST*)mir_alloc(sizeof(UPDATELIST)); - newItem->hContact = hContact; - newItem->next = nullptr; - - WaitForSingleObject(hUpdateMutex, INFINITE); - - if (UpdateListTail == nullptr) UpdateListHead = newItem; - else UpdateListTail->next = newItem; - UpdateListTail = newItem; - ReleaseMutex(hUpdateMutex); +void CWeatherProto::UpdateListAdd(MCONTACT hContact) +{ + mir_cslock lck(m_csUpdate); + m_updateList.push_back(hContact); } // get the first item from the update queue and remove it from the queue // return value = the contact for next update -MCONTACT UpdateGetFirst() +MCONTACT CWeatherProto::UpdateGetFirst() { - MCONTACT hContact = NULL; - - WaitForSingleObject(hUpdateMutex, INFINITE); - - if (UpdateListHead != nullptr) { - UPDATELIST *Item = UpdateListHead; - - hContact = Item->hContact; - UpdateListHead = Item->next; - mir_free(Item); - - if (UpdateListHead == nullptr) - UpdateListTail = nullptr; - } - - ReleaseMutex(hUpdateMutex); + mir_cslock lck(m_csUpdate); + if (m_updateList.empty()) + return 0; + auto it = m_updateList.begin(); + MCONTACT hContact = *it; + m_updateList.erase(it); return hContact; } -void DestroyUpdateList(void) +void CWeatherProto::DestroyUpdateList(void) { - WaitForSingleObject(hUpdateMutex, INFINITE); - - // free the list one by one - UPDATELIST *temp = UpdateListHead; - while (temp != nullptr) { - UpdateListHead = temp->next; - mir_free(temp); - temp = UpdateListHead; - } - // make sure the entire list is clear - UpdateListTail = nullptr; - - ReleaseMutex(hUpdateMutex); + mir_cslock lck(m_csUpdate); + m_updateList.clear(); } +///////////////////////////////////////////////////////////////////////////////////////// // update all weather thread // this thread update each weather station from the queue -static void UpdateThreadProc(void *) + +void CWeatherProto::UpdateThread(void *) { - WaitForSingleObject(hUpdateMutex, INFINITE); - if (ThreadRunning) { - ReleaseMutex(hUpdateMutex); - return; + { mir_cslock lck(m_csUpdate); + if (m_bThreadRunning) + return; + + m_bThreadRunning = true; // prevent 2 instance of this thread running } - ThreadRunning = TRUE; // prevent 2 instance of this thread running - ReleaseMutex(hUpdateMutex); // update weather by getting the first station from the queue until the queue is empty - while (UpdateListHead != nullptr && !Miranda_IsTerminated()) + while (!m_updateList.empty() && !Miranda_IsTerminated()) UpdateWeather(UpdateGetFirst()); // exit the update thread - ThreadRunning = FALSE; + m_bThreadRunning = false; } -//============ UPDATE WEATHER ============ -// +///////////////////////////////////////////////////////////////////////////////////////// // update all weather station // AutoUpdate = true if it is from automatic update using timer // false if it is from update by clicking the main menu -void UpdateAll(BOOL AutoUpdate, BOOL RemoveData) + +void CWeatherProto::UpdateAll(BOOL AutoUpdate, BOOL RemoveData) { // add all weather contact to the update queue list - for (auto &hContact : Contacts(MODULENAME)) - if (!g_plugin.getByte(hContact, "AutoUpdate") || !AutoUpdate) { + for (auto &hContact : AccContacts()) + if (!getByte(hContact, "AutoUpdate") || !AutoUpdate) { if (RemoveData) - DBDataManage(hContact, WDBM_REMOVE, 0, 0); + db_delete_module(hContact, WEATHERCONDITION); UpdateListAdd(hContact); } // if it is not updating, then start the update thread process // if it is updating, the stations just added to the queue will get updated by the already-running process - if (!ThreadRunning) - mir_forkthread(UpdateThreadProc); + if (!m_bThreadRunning) + ForkThread(&CWeatherProto::UpdateThread); } +///////////////////////////////////////////////////////////////////////////////////////// // update a single station // wParam = handle for the weather station that is going to be updated -INT_PTR UpdateSingleStation(WPARAM wParam, LPARAM) + +INT_PTR CWeatherProto::UpdateSingleStation(WPARAM wParam, LPARAM) { if (IsMyContact(wParam)) { // add the station to the end of the update queue @@ -327,278 +283,244 @@ INT_PTR UpdateSingleStation(WPARAM wParam, LPARAM) // if it is not updating, then start the update thread process // if it is updating, the stations just added to the queue will get // updated by the already-running process - if (!ThreadRunning) - mir_forkthread(UpdateThreadProc); + if (!m_bThreadRunning) + ForkThread(&CWeatherProto::UpdateThread); } return 0; } +///////////////////////////////////////////////////////////////////////////////////////// // update a single station with removing the old data // wParam = handle for the weather station that is going to be updated -INT_PTR UpdateSingleRemove(WPARAM wParam, LPARAM) + +INT_PTR CWeatherProto::UpdateSingleRemove(WPARAM hContact, LPARAM) { - if (IsMyContact(wParam)) { + if (IsMyContact(hContact)) { // add the station to the end of the update queue, and also remove old data - DBDataManage(wParam, WDBM_REMOVE, 0, 0); - UpdateListAdd(wParam); + db_delete_module(hContact, WEATHERCONDITION); + UpdateListAdd(hContact); // if it is not updating, then start the update thread process // if it is updating, the stations just added to the queue will get updated by the already-running process - if (!ThreadRunning) - mir_forkthread(UpdateThreadProc); + if (!m_bThreadRunning) + ForkThread(&CWeatherProto::UpdateThread); } return 0; } +///////////////////////////////////////////////////////////////////////////////////////// // the "Update All" menu item in main menu -INT_PTR UpdateAllInfo(WPARAM, LPARAM) + +INT_PTR CWeatherProto::UpdateAllInfo(WPARAM, LPARAM) { - if (!ThreadRunning) + if (!m_bThreadRunning) UpdateAll(FALSE, FALSE); return 0; } +///////////////////////////////////////////////////////////////////////////////////////// // the "Update All" menu item in main menu and remove the old data -INT_PTR UpdateAllRemove(WPARAM, LPARAM) + +INT_PTR CWeatherProto::UpdateAllRemove(WPARAM, LPARAM) { - if (!ThreadRunning) + if (!m_bThreadRunning) UpdateAll(FALSE, TRUE); return 0; } -//============ GETTING WEATHER DATA ============ -// +///////////////////////////////////////////////////////////////////////////////////////// // getting weather data and save them into the database // hContact = the contact to get the data -int GetWeatherData(MCONTACT hContact) -{ - // get each part of the id's - wchar_t id[256]; - GetStationID(hContact, id, _countof(id)); - - // test ID format - wchar_t *szInfo = wcschr(id, '/'); - if (szInfo == nullptr) - return INVALID_ID_FORMAT; - - GetID(id); - - wchar_t Svc[256]; - GetStationID(hContact, Svc, _countof(Svc)); - GetSvc(Svc); - - // check for invalid station - if (id[0] == 0) return INVALID_ID; - if (Svc[0] == 0) return INVALID_SVC; - // get the update strings (loaded to memory from ini files) - WIDATA *Data = GetWIData(Svc); - if (Data == nullptr) - return SVC_NOT_FOUND; // the ini for the station cannot be found +static wchar_t *moon2str(double phase) +{ + if (phase < 0.05) return TranslateT("New moon"); + if (phase < 0.26) return TranslateT("Waxing crescent"); + if (phase < 0.51) return TranslateT("Waxing gibbous"); + if (phase < 0.76) return TranslateT("Waning gibbous"); + return TranslateT("Waning crescent"); +} - uint16_t cond = NA; - char loc[256]; - for (int i = 0; i < 4; ++i) { - // generate update URL - switch (i) { - case 0: - mir_snprintf(loc, Data->UpdateURL, _T2A(id).get()); +static CMStringW parseConditions(const CMStringW &str) +{ + CMStringW ret; + int iStart = 0; + while (true) { + auto substr = str.Tokenize(L",", iStart); + if (substr.IsEmpty()) break; - case 1: - mir_snprintf(loc, Data->UpdateURL2, _T2A(id).get()); - break; + substr.Trim(); + if (!ret.IsEmpty()) + ret += ", "; + ret += TranslateW(substr); + } + return ret; +} - case 2: - mir_snprintf(loc, Data->UpdateURL3, _T2A(id).get()); - break; +static double g_elevation = 0; - case 3: - mir_snprintf(loc, Data->UpdateURL4, _T2A(id).get()); - break; +static void getData(OBJLIST<WIDATAITEM> &arValues, const JSONNode &node) +{ + arValues.insert(new WIDATAITEM(LPGENW("Date"), L"", node["datetime"].as_mstring())); + arValues.insert(new WIDATAITEM(LPGENW("Condition"), L"", parseConditions(node["conditions"].as_mstring()))); + arValues.insert(new WIDATAITEM(LPGENW("Temperature"), L"C", node["temp"].as_mstring())); + arValues.insert(new WIDATAITEM(LPGENW("High"), L"C", node["tempmax"].as_mstring())); + arValues.insert(new WIDATAITEM(LPGENW("Low"), L"C", node["tempmin"].as_mstring())); + + CMStringW wszPressure(FORMAT, L"%lf", node["pressure"].as_float() - g_elevation); + arValues.insert(new WIDATAITEM(LPGENW("Pressure"), L"mb", wszPressure)); + + arValues.insert(new WIDATAITEM(LPGENW("Sunset"), L"", node["sunset"].as_mstring())); + arValues.insert(new WIDATAITEM(LPGENW("Sunrise"), L"", node["sunrise"].as_mstring())); + arValues.insert(new WIDATAITEM(LPGENW("Moon phase"), L"", moon2str(node["moonphase"].as_float()))); + arValues.insert(new WIDATAITEM(LPGENW("Wind speed"), L"km/h", node["windspeed"].as_mstring())); + arValues.insert(new WIDATAITEM(LPGENW("Wind direction"), L"grad", node["winddir"].as_mstring())); + arValues.insert(new WIDATAITEM(LPGENW("Dew point"), L"C", node["dew"].as_mstring())); + arValues.insert(new WIDATAITEM(LPGENW("Visibility"), L"km", node["visibility"].as_mstring())); + arValues.insert(new WIDATAITEM(LPGENW("Humidity"), L"", node["humidity"].as_mstring())); + arValues.insert(new WIDATAITEM(LPGENW("Feel"), L"C", node["feelslike"].as_mstring())); +} - default: - continue; - } +int CWeatherProto::GetWeatherData(MCONTACT hContact) +{ + // get each part of the id's + CMStringW wszID(getMStringW(hContact, "ID")); + if (wszID.IsEmpty()) + return INVALID_ID; - if (loc[0] == 0) - continue; + uint16_t cond = NA; - // download the html file from the internet - wchar_t *szData = nullptr; - int retval = InternetDownloadFile(loc, Data->Cookie, Data->UserAgent, &szData); - if (retval != 0) { - mir_free(szData); - return retval; - } - if (wcsstr(szData, L"Document Not Found") != nullptr) { - mir_free(szData); - return DOC_NOT_FOUND; - } + // download the html file from the internet + WeatherReply reply(RunQuery(wszID, 7)); + if (!reply) + return reply.error(); + + auto &root = reply.data(); + + // writing current conditions + auto &curr = root["currentConditions"]; + g_elevation = root["elevation"].as_float() / 7.877; + + WIDATAITEMLIST arValues; + getData(arValues, curr); + + auto szIcon = curr["icon"].as_string(); + if (szIcon == "snow") + cond = SNOW; + else if (szIcon == "snow-showers-day" || szIcon == "snow-showers-night") + cond = SSHOWER; + else if (szIcon == "thunder" || szIcon == "thunder-showers-day" || szIcon == "thunder-showers-night") + cond = LIGHT; + else if (szIcon == "partly-cloudy-day" || szIcon == "partly-cloudy-night" || szIcon == "wind") + cond = PCLOUDY; + else if (szIcon == "fog") + cond = FOG; + else if (szIcon == "rain") + cond = RAIN; + else if (szIcon == "showers-day" || szIcon == "showers-night") + cond = RSHOWER; + else if (szIcon == "clear-day" || szIcon == "clear-night") + cond = SUNNY; + else if (szIcon == "rain") + cond = RAIN; + else if (szIcon == "cloudy") + cond = CLOUDY; + + // writing forecast + db_set_ws(hContact, WEATHERCONDITION, "Update", curr["datetime"].as_mstring()); + + for (auto &it : arValues) { + ConvertDataValue(it); + if (!it->Value.IsEmpty()) + db_set_ws(hContact, WEATHERCONDITION, _T2A(it->Name), it->Value); + } - szInfo = szData; - WIDATAITEMLIST *Item = Data->UpdateData; + int iFore = 0; + for (auto &fore : root["days"]) { + WIDATAITEMLIST arDaily; + getData(arDaily, fore); - // begin parsing item by item - while (Item != nullptr) { - if (Item->Item.Url[0] != 0 && Item->Item.Url[0] != (i + '1')) { - Item = Item->Next; + CMStringW result; + for (auto &it : arDaily) { + ConvertDataValue(it); + if (it->Value.IsEmpty()) continue; - } - wchar_t DataValue[MAX_DATA_LEN]; - switch (Item->Item.Type) { - case WID_NORMAL: - // if it is a normal item with start= and end=, then parse through the downloaded string - // to get a data value. - GetDataValue(&Item->Item, DataValue, &szInfo); - if (mir_wstrcmp(Item->Item.Name, L"Condition") && mir_wstrcmpi(Item->Item.Unit, L"Cond")) - wcsncpy(DataValue, TranslateW(DataValue), MAX_DATA_LEN - 1); - break; - - case WID_SET: - { - // for the "Set Data=" operation - DBVARIANT dbv; - wchar_t *chop, *str, str2[MAX_DATA_LEN]; - BOOL hasvar = FALSE; - size_t stl; - - // get the set data operation string - str = Item->Item.End; - DataValue[0] = 0; - // go through each part of the operation string seperated by the & operator - do { - // the end of the string, last item - chop = wcsstr(str, L" & "); - if (chop == nullptr) - chop = wcschr(str, '\0'); - - stl = min(sizeof(str2) - 1, (unsigned)(chop - str - 2)); - wcsncpy(str2, str + 1, stl); - str2[stl] = 0; - - switch (str[0]) { - case '[': // variable, add the value to the result string - hasvar = TRUE; - if (!DBGetData(hContact, _T2A(str2), &dbv)) { - mir_wstrncat(DataValue, TranslateW(dbv.pwszVal), _countof(DataValue) - mir_wstrlen(DataValue)); - DataValue[_countof(DataValue) - 1] = 0; - db_free(&dbv); - } - break; - - case'\"': // constant, add it to the result string - mir_wstrncat(DataValue, TranslateW(str2), _countof(DataValue) - mir_wstrlen(DataValue)); - DataValue[_countof(DataValue) - 1] = 0; - break; - } - - // remove the front part of the string that is done and continue parsing - str = chop + 3; - } while (chop[0] && str[0]); - - if (!hasvar) ConvertDataValue(&Item->Item, DataValue); - break; - } - case WID_BREAK: - { - // for the "Break Data=" operation - DBVARIANT dbv; - if (!DBGetData(hContact, _T2A(Item->Item.Start), &dbv)) { - wcsncpy(DataValue, dbv.pwszVal, _countof(DataValue)); - DataValue[_countof(DataValue) - 1] = 0; - db_free(&dbv); - } - else { - DataValue[0] = 0; - break; // do not continue if the source is invalid - } - - // generate the strings - wchar_t *end = wcsstr(DataValue, Item->Item.Break); - if (end == nullptr) { - DataValue[0] = 0; - break; // exit if break string is not found - } - *end = '\0'; - end += mir_wstrlen(Item->Item.Break); - while (end[0] == ' ') - end++; // remove extra space - - ConvertDataValue(&Item->Item, DataValue); - - // write the 2 strings created from the break operation - if (Item->Item.End[0]) - db_set_ws(hContact, WEATHERCONDITION, _T2A(Item->Item.End), end); - break; - } - } + // insert missing values from day 0 into current + if (iFore == 0) + if (auto *pOld = arValues.Find(it->Name)) + if (pOld->Value.IsEmpty() || pOld->Value == NODATA) + db_set_ws(hContact, WEATHERCONDITION, _T2A(it->Name), it->Value); - // don't store data if it is not available - if ((DataValue[0] != 0 && mir_wstrcmp(DataValue, NODATA) && - mir_wstrcmp(DataValue, TranslateW(NODATA)) && mir_wstrcmp(Item->Item.Name, L"Ignore")) || - (!mir_wstrcmp(Item->Item.Name, L"Alert") && i == 0)) { - // temporary workaround for mToolTip to show feel-like temperature - if (!mir_wstrcmp(Item->Item.Name, L"Feel")) - db_set_ws(hContact, WEATHERCONDITION, "Heat Index", DataValue); - GetStationID(hContact, Svc, _countof(Svc)); - if (!mir_wstrcmp(Svc, opt.Default)) - db_set_ws(0, DEFCURRENTWEATHER, _T2A(Item->Item.Name), DataValue); - if (!mir_wstrcmp(Item->Item.Name, L"Condition")) { - wchar_t buf[128], *cbuf; - mir_snwprintf(buf, L"#%s Weather", DataValue); - cbuf = TranslateW(buf); - if (cbuf[0] == '#') - cbuf = TranslateW(DataValue); - db_set_ws(hContact, WEATHERCONDITION, _T2A(Item->Item.Name), cbuf); - CharLowerBuff(DataValue, (uint32_t)mir_wstrlen(DataValue)); - cond = GetIcon(DataValue, Data); - } - else if (mir_wstrcmpi(Item->Item.Unit, L"Cond") == 0) { - wchar_t buf[128], *cbuf; - mir_snwprintf(buf, L"#%s Weather", DataValue); - cbuf = TranslateW(buf); - if (cbuf[0] == '#') - cbuf = TranslateW(DataValue); - db_set_ws(hContact, WEATHERCONDITION, _T2A(Item->Item.Name), cbuf); - } - else db_set_ws(hContact, WEATHERCONDITION, _T2A(Item->Item.Name), DataValue); - } - Item = Item->Next; + if (!result.IsEmpty()) + result += L"; "; + result.AppendFormat(L"%s: %s", TranslateW(it->Name), it->Value.c_str()); } - mir_free(szData); + + CMStringA szSetting(FORMAT, "Forecast Day %d", iFore++); + db_set_ws(hContact, WEATHERCONDITION, szSetting, result); + arValues.destroy(); } // assign condition icon - g_plugin.setWord(hContact, "StatusIcon", cond); + setWord(hContact, "StatusIcon", cond); return 0; } -//============ UPDATE TIMERS ============ -// +///////////////////////////////////////////////////////////////////////////////////////// + +static int enumSettings(const char *pszSetting, void *param) +{ + auto *pList = (OBJLIST<char>*)param; + if (!pList->find((char*)pszSetting)) + pList->insert(newStr(pszSetting)); + return 0; +} + +void CWeatherProto::GetVarsDescr(CMStringW &wszDescr) +{ + OBJLIST<char> vars(10, strcmp); + for (int i = 1; i <= 7; i++) + vars.insert(newStr(CMStringA(FORMAT, "Forecast Day %d", i))); + + for (auto &cc : AccContacts()) + db_enum_settings(cc, &enumSettings, WEATHERCONDITION, &vars); + + CMStringW str; + for (auto &it : vars) { + if (!str.IsEmpty()) + str.Append(L", "); + str.AppendFormat(L"%%[%S]", it); + } + wszDescr += str; +} + +///////////////////////////////////////////////////////////////////////////////////////// // main auto-update timer -void CALLBACK timerProc(HWND, UINT, UINT_PTR, DWORD) + +void CWeatherProto::DoUpdate() { // only run if it is not current updating and the auto update option is enabled - if (!ThreadRunning && opt.CAutoUpdate && !Miranda_IsTerminated() && (opt.NoProtoCondition || status == ID_STATUS_ONLINE)) + if (!m_bThreadRunning && opt.CAutoUpdate && !Miranda_IsTerminated() && m_iStatus == ID_STATUS_ONLINE) UpdateAll(TRUE, FALSE); } - // temporary timer for first run // when this is run, it kill the old startup timer and create the permenant one above -void CALLBACK timerProc2(HWND, UINT, UINT_PTR, DWORD) + +void CWeatherProto::StartUpdate() { - KillTimer(nullptr, timerId); - ThreadRunning = FALSE; + m_bThreadRunning = false; - if (Miranda_IsTerminated()) - return; + if (!Miranda_IsTerminated()) + m_impl.m_update.Start(opt.UpdateTime * 60000); +} - if (opt.StartupUpdate && opt.NoProtoCondition) - UpdateAll(FALSE, FALSE); - timerId = SetTimer(nullptr, 0, ((int)opt.UpdateTime) * 60000, timerProc); +void CWeatherProto::RestartTimer() +{ + m_impl.m_update.Stop(); + m_impl.m_update.Start(opt.UpdateTime * 60000); } diff --git a/protocols/Weather/src/weather_userinfo.cpp b/protocols/Weather/src/weather_userinfo.cpp index ecee919ce5..1207d01b4a 100644 --- a/protocols/Weather/src/weather_userinfo.cpp +++ b/protocols/Weather/src/weather_userinfo.cpp @@ -27,232 +27,252 @@ information #include "stdafx.h" -//============ BRIEF INFORMATION ============ -// -static int BriefDlgResizer(HWND, 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; +///////////////////////////////////////////////////////////////////////////////////////// +// dialog for more data in the user info window - case IDC_MUPDATE: - return RD_ANCHORX_LEFT | RD_ANCHORY_BOTTOM; +static unsigned tabstops = 48; - case IDC_MTOGGLE: - case IDC_MWEBPAGE: - case IDCANCEL: - return RD_ANCHORX_RIGHT | RD_ANCHORY_BOTTOM; - } - return RD_ANCHORX_LEFT | RD_ANCHORY_TOP; +static int GetWeatherDataFromDB(const char *szSetting, void *lparam) +{ + auto *pList = (OBJLIST<char>*)lparam; + pList->insert(newStr(szSetting)); + return 0; } -// set the title of the dialog and on the which rectangle -// also load brief info into message box -static void LoadBriefInfoText(HWND hwndDlg, MCONTACT hContact) +class CBriefInfoDlg : public CWeatherDlgBase { - wchar_t str[4096]; + MCONTACT hContact; + wchar_t m_buf[4098]; + int iOldItem = -1; - // load weather information from the contact into the WEATHERINFO struct - WEATHERINFO winfo = LoadWeatherInfo(hContact); - // check if data exist. If not, display error message box - if (!g_plugin.getByte(hContact, "IsUpdated")) - SetDlgItemTextW(hwndDlg, IDC_MTEXT, TranslateT("No information available.\r\nPlease update weather condition first.")); - else { - // set the display text and show the message box - GetDisplay(&winfo, GetTextValue('B'), str); - SetDlgItemTextW(hwndDlg, IDC_MTEXT, str); - } + UI_MESSAGE_MAP(CBriefInfoDlg, CWeatherDlgBase); + UI_MESSAGE(WM_UPDATEDATA, OnUpdate); + UI_MESSAGE_MAP_END(); - GetDisplay(&winfo, L"%c, %t", str); - SetWindowTextW(hwndDlg, winfo.city); - SetDlgItemTextW(hwndDlg, IDC_HEADERBAR, str); -} + CTimer m_timer; + CCtrlButton btnUpdate, btnWebpage, btnToggle; + CCtrlListView m_list; -// dialog process for more data in the user info window -// lParam = contact handle -static INT_PTR CALLBACK DlgProcMoreData(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam) -{ - static const unsigned tabstops = 48; - MCONTACT hContact = (MCONTACT)GetWindowLongPtr(hwndDlg, GWLP_USERDATA); +public: + CBriefInfoDlg(CWeatherProto *ppro, MCONTACT _1) : + CWeatherDlgBase(ppro, IDD_BRIEF), + hContact(_1), + m_list(this, IDC_DATALIST), + m_timer(this, 1), + btnToggle(this, IDC_MTOGGLE), + btnUpdate(this, IDC_MUPDATE), + btnWebpage(this, IDC_MWEBPAGE) + { + SetMinSize(350, 300); - switch (msg) { - case WM_INITDIALOG: - // save the contact handle for later use - hContact = lParam; - SetWindowLongPtr(hwndDlg, GWLP_USERDATA, (LONG_PTR)hContact); + m_list.OnHotTrack = Callback(this, &CBriefInfoDlg::onList_Track); - 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); + m_timer.OnEvent = Callback(this, &CBriefInfoDlg::onTimer); + + btnToggle.OnClick = Callback(this, &CBriefInfoDlg::onClick_Toggle); + btnUpdate.OnClick = Callback(this, &CBriefInfoDlg::onClick_Update); + btnWebpage.OnClick = Callback(this, &CBriefInfoDlg::onClick_Webpage); + } + + bool OnInitDialog() override + { + SendDlgItemMessage(m_hwnd, IDC_MTEXT, EM_AUTOURLDETECT, (WPARAM)TRUE, 0); + SendDlgItemMessage(m_hwnd, IDC_MTEXT, EM_SETEVENTMASK, 0, ENM_LINK); + SendDlgItemMessage(m_hwnd, IDC_MTEXT, EM_SETMARGINS, EC_LEFTMARGIN, 5); + SendDlgItemMessage(m_hwnd, IDC_MTEXT, EM_SETTABSTOPS, 1, (LPARAM)&tabstops); // get the list to display { - LV_COLUMN lvc = {}; - HWND hList = GetDlgItem(hwndDlg, IDC_DATALIST); RECT aRect = {}; - GetClientRect(hList, &aRect); + GetClientRect(m_list.GetHwnd(), &aRect); // managing styles - lvc.mask = LVCF_WIDTH | LVCF_TEXT; - ListView_SetExtendedListViewStyleEx(hList, - LVS_EX_FULLROWSELECT | LVS_EX_INFOTIP, - LVS_EX_FULLROWSELECT | LVS_EX_INFOTIP); + DWORD dwStyle = LVS_EX_FULLROWSELECT; + m_list.SetExtendedListViewStyleEx(dwStyle, dwStyle); // inserting columns + LV_COLUMN lvc = {}; + lvc.mask = LVCF_WIDTH | LVCF_TEXT; + lvc.cx = LIST_COLUMN; lvc.pszText = TranslateT("Variable"); - ListView_InsertColumn(hList, 0, &lvc); + m_list.InsertColumn(0, &lvc); lvc.cx = aRect.right - LIST_COLUMN - GetSystemMetrics(SM_CXVSCROLL) - 3; lvc.pszText = TranslateT("Information"); - ListView_InsertColumn(hList, 1, &lvc); + m_list.InsertColumn(1, &lvc); - // inserting data - SendMessage(hwndDlg, WM_UPDATEDATA, 0, 0); + // insert data + OnUpdate(); } - TranslateDialogDefault(hwndDlg); // prevent dups of the window - WindowList_Add(hDataWindowList, hwndDlg, hContact); + WindowList_Add(hDataWindowList, m_hwnd, hContact); // restore window position - Utils_RestoreWindowPositionNoMove(hwndDlg, NULL, MODULENAME, "BriefInfo_"); - return TRUE; + Utils_RestoreWindowPositionNoMove(m_hwnd, NULL, MODULENAME, "BriefInfo_"); + return true; + } - case WM_UPDATEDATA: - ListView_DeleteAllItems(GetDlgItem(hwndDlg, IDC_DATALIST)); - LoadBriefInfoText(hwndDlg, hContact); - DBDataManage(hContact, WDBM_DETAILDISPLAY, (WPARAM)hwndDlg, 0); + void OnDestroy() override + { + DestroyIcon((HICON)SendMessage(m_hwnd, WM_SETICON, ICON_BIG, 0)); + DestroyIcon((HICON)SendMessage(m_hwnd, WM_SETICON, ICON_SMALL, 0)); - // set icons - { - HICON hIcon = GetStatusIconBig(hContact); - DestroyIcon((HICON)SendMessage(hwndDlg, WM_SETICON, ICON_BIG, LPARAM(hIcon))); - DestroyIcon((HICON)SendMessage(hwndDlg, WM_SETICON, ICON_SMALL, LPARAM(hIcon))); - } + Utils_SaveWindowPosition(m_hwnd, NULL, MODULENAME, "BriefInfo_"); + WindowList_Remove(hDataWindowList, m_hwnd); + } - RedrawWindow(GetDlgItem(hwndDlg, IDC_HEADERBAR), nullptr, nullptr, RDW_INVALIDATE | RDW_UPDATENOW); - break; + int Resizer(UTILRESIZECONTROL *urc) override + { + switch (urc->wId) { + case IDC_HEADERBAR: + return RD_ANCHORX_LEFT | RD_ANCHORY_TOP | RD_ANCHORX_WIDTH; - 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)); + case IDC_MTEXT: + return RD_ANCHORX_LEFT | RD_ANCHORY_TOP | RD_ANCHORX_WIDTH | RD_ANCHORY_HEIGHT; + + case IDC_DATALIST: + m_list.SetColumnWidth(1, urc->dlgNewSize.cx - m_list.GetColumnWidth(0) - GetSystemMetrics(SM_CXVSCROLL)); + return RD_ANCHORX_LEFT | RD_ANCHORY_TOP | RD_ANCHORX_WIDTH | RD_ANCHORY_HEIGHT; - Utils_ResizeDialog(hwndDlg, g_plugin.getInst(), MAKEINTRESOURCEA(IDD_BRIEF), BriefDlgResizer); + 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; } - break; + return RD_ANCHORX_LEFT | RD_ANCHORY_TOP; + } - case WM_GETMINMAXINFO: - { - LPMINMAXINFO mmi = (LPMINMAXINFO)lParam; + INT_PTR OnUpdate(UINT = 0, WPARAM = 0, LPARAM = 0) + { + m_list.DeleteAllItems(); + + // load weather information from the contact into the WEATHERINFO struct + WEATHERINFO winfo = m_proto->LoadWeatherInfo(hContact); + // check if data exist. If not, display error message box + if (!m_proto->getByte(hContact, "IsUpdated")) + SetDlgItemTextW(m_hwnd, IDC_MTEXT, TranslateT("No information available.\r\nPlease update weather condition first.")); + else { + // set the display text and show the message box + SetDlgItemTextW(m_hwnd, IDC_MTEXT, GetDisplay(&winfo, m_proto->GetTextValue('B'))); + } - // The minimum width in points - mmi->ptMinTrackSize.x = 350; - // The minimum height in points - mmi->ptMinTrackSize.y = 300; + SetWindowTextW(m_hwnd, winfo.city); + SetDlgItemTextW(m_hwnd, IDC_HEADERBAR, GetDisplay(&winfo, L"%c, %t")); + + // get all the settings and store them in a temporary list + LIST<char> arSettings(10); + db_enum_settings(hContact, GetWeatherDataFromDB, WEATHERCONDITION, &arSettings); + + auto T = arSettings.rev_iter(); + for (auto &it: T) { + CMStringW wszText(db_get_wsm(hContact, WEATHERCONDITION, it)); + if (wszText.IsEmpty()) + continue; + + // skip the "WeatherInfo" variable + if (!mir_strcmp(it, "WeatherInfo") || !mir_strcmp(it, "Ignore") || it[0] == '#') + continue; + + wszText.Replace(L"; ", L";\r\n "); + + _A2T strW(it); + LV_ITEM lvi = {}; + lvi.mask = LVIF_TEXT | LVIF_PARAM; + lvi.lParam = T.indexOf(&it); + lvi.pszText = TranslateW(strW); + lvi.iItem = m_list.InsertItem(&lvi); + lvi.pszText = wszText.GetBuffer(); + m_list.SetItemText(lvi.iItem, 1, wszText); } - break; - case WM_COMMAND: - switch (LOWORD(wParam)) { - case IDCANCEL: - // close the info window - DestroyWindow(hwndDlg); - break; + // set icons + HICON hIcon = m_proto->GetStatusIconBig(hContact); + DestroyIcon((HICON)SendMessage(m_hwnd, WM_SETICON, ICON_BIG, LPARAM(hIcon))); + DestroyIcon((HICON)SendMessage(m_hwnd, WM_SETICON, ICON_SMALL, LPARAM(hIcon))); - case IDC_MUPDATE: - { - 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); - - LV_ITEM lvi = {}; - lvi.mask = LVIF_TEXT | LVIF_PARAM; - lvi.lParam = 1; - lvi.pszText = L""; - lvi.iItem = ListView_InsertItem(hList, &lvi); - lvi.pszText = TranslateT("Retrieving new data, please wait..."); - ListView_SetItemText(hList, lvi.iItem, 1, lvi.pszText); - UpdateSingleStation(hContact, 0); - break; - } + RedrawWindow(GetDlgItem(m_hwnd, IDC_HEADERBAR), nullptr, nullptr, RDW_INVALIDATE | RDW_UPDATENOW); + return 0; + } - case IDC_MWEBPAGE: - LoadForecast(hContact, 0); // read complete forecast - break; + void onList_Track(CCtrlListView::TEventInfo *ev) + { + auto *nlv = ev->nmlv; + if (nlv->iItem == -1 || nlv->iItem == iOldItem || nlv->iSubItem != 1) + return; - 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; + iOldItem = nlv->iItem; - case WM_NOTIFY: - { - LPNMHDR pNmhdr = (LPNMHDR)lParam; - if (pNmhdr->idFrom == IDC_MTEXT && pNmhdr->code == EN_LINK) { - ENLINK *enlink = (ENLINK *)lParam; - switch (enlink->msg) { - case WM_LBUTTONUP: - TEXTRANGE tr; - tr.chrg = enlink->chrg; - tr.lpstrText = (wchar_t*)mir_alloc(sizeof(wchar_t)*(tr.chrg.cpMax - tr.chrg.cpMin + 8)); - SendMessage(pNmhdr->hwndFrom, EM_GETTEXTRANGE, 0, (LPARAM)&tr); - Utils_OpenUrlW(tr.lpstrText); - mir_free(tr.lpstrText); - break; - } - } - } - break; + m_list.GetItemText(nlv->iItem, nlv->iSubItem, m_buf, _countof(m_buf)); + m_timer.Start(100); + } - case WM_CLOSE: - DestroyWindow(hwndDlg); - break; + void onTimer(CTimer *pTimer) + { + pTimer->Stop(); - case WM_DESTROY: - DestroyIcon((HICON)SendMessage(hwndDlg, WM_SETICON, ICON_BIG, 0)); - DestroyIcon((HICON)SendMessage(hwndDlg, WM_SETICON, ICON_SMALL, 0)); + if (wcslen(m_buf) > 50) { + CLCINFOTIP ti = {}; + ti.cbSize = sizeof(TOOLINFO); + ti.hItem = (HANDLE)iOldItem; + Tipper_ShowTip(m_buf, &ti); + } + else Tipper_Hide(); + } - Utils_SaveWindowPosition(hwndDlg, NULL, MODULENAME, "BriefInfo_"); - WindowList_Remove(hDataWindowList, hwndDlg); - break; + void onClick_Update(CCtrlButton *) + { + // update current data + // set the text to "updating" + SetDlgItemText(m_hwnd, IDC_MTEXT, TranslateT("Retrieving new data, please wait...")); + m_list.DeleteAllItems(); + + LV_ITEM lvi = {}; + lvi.mask = LVIF_TEXT | LVIF_PARAM; + lvi.lParam = 1; + lvi.pszText = L""; + lvi.iItem = m_list.InsertItem(&lvi); + lvi.pszText = TranslateT("Retrieving new data, please wait..."); + m_list.SetItemText(lvi.iItem, 1, lvi.pszText); + m_proto->UpdateSingleStation(hContact, 0); } - return FALSE; -} + void onClick_Webpage(CCtrlButton *) + { + m_proto->LoadForecast(hContact, 0); // read complete forecast + } + + void onClick_Toggle(CCtrlButton *) + { + if (IsWindowVisible(m_list.GetHwnd())) + SetDlgItemText(m_hwnd, IDC_MTOGGLE, TranslateT("More Info")); + else + SetDlgItemText(m_hwnd, IDC_MTOGGLE, TranslateT("Brief Info")); + ShowWindow(m_list.GetHwnd(), (int)!IsWindowVisible(m_list.GetHwnd())); + ShowWindow(GetDlgItem(m_hwnd, IDC_MTEXT), (int)!IsWindowVisible(GetDlgItem(m_hwnd, IDC_MTEXT))); + } +}; -// show brief information dialog -// wParam = current contact -int BriefInfo(WPARAM wParam, LPARAM) +INT_PTR CWeatherProto::BriefInfo(WPARAM hContact, LPARAM) { // make sure that the contact is actually a weather one - if (!IsMyContact(wParam)) + if (!IsMyContact(hContact)) return 0; - HWND hMoreDataDlg = WindowList_Find(hDataWindowList, wParam); + HWND hMoreDataDlg = WindowList_Find(hDataWindowList, hContact); if (hMoreDataDlg != nullptr) { SetForegroundWindow(hMoreDataDlg); SetFocus(hMoreDataDlg); } - else hMoreDataDlg = CreateDialogParam(g_plugin.getInst(), MAKEINTRESOURCE(IDD_BRIEF), nullptr, DlgProcMoreData, (LPARAM)wParam); + else { + auto *pDlg = new CBriefInfoDlg(this, hContact); + pDlg->Create(); + hMoreDataDlg = pDlg->GetHwnd(); + } ShowWindow(GetDlgItem(hMoreDataDlg, IDC_DATALIST), 0); ShowWindow(GetDlgItem(hMoreDataDlg, IDC_MTEXT), 1); @@ -260,12 +280,18 @@ int BriefInfo(WPARAM wParam, LPARAM) return 1; } +int CWeatherProto::BriefInfoEvt(WPARAM wParam, LPARAM) +{ + return BriefInfo(wParam, 0); +} + ///////////////////////////////////////////////////////////////////////////////////////// // User info dialog class WeatherUserInfoDlg : public CUserInfoPageDlg { CCtrlButton btnDetail; + CWeatherProto *ppro; public: WeatherUserInfoDlg() : @@ -278,13 +304,13 @@ public: bool OnInitDialog() override { SendDlgItemMessage(m_hwnd, IDC_MOREDETAIL, BUTTONSETASFLATBTN, TRUE, 0); + ppro = (CWeatherProto *)Proto_GetContactInstance(m_hContact); // load weather info for the contact - wchar_t str[MAX_TEXT_SIZE]; - WEATHERINFO w = LoadWeatherInfo(m_hContact); - SetDlgItemText(m_hwnd, IDC_INFO1, GetDisplay(&w, TranslateT("Current condition for %n"), str)); + WEATHERINFO w = ppro->LoadWeatherInfo(m_hContact); + SetDlgItemText(m_hwnd, IDC_INFO1, GetDisplay(&w, TranslateT("Current condition for %n"))); - SendDlgItemMessage(m_hwnd, IDC_INFOICON, STM_SETICON, (WPARAM)GetStatusIconBig(m_hContact), 0); + SendDlgItemMessage(m_hwnd, IDC_INFOICON, STM_SETICON, (WPARAM)ppro->GetStatusIconBig(m_hContact), 0); // bold and enlarge the current condition LOGFONT lf; @@ -296,19 +322,16 @@ public: SendDlgItemMessage(m_hwnd, IDC_INFO2, WM_SETFONT, (WPARAM)CreateFontIndirect(&lf), 0); // set the text for displaying other current weather conditions data - GetDisplay(&w, L"%c %t", str); - SetDlgItemText(m_hwnd, IDC_INFO2, str); + SetDlgItemText(m_hwnd, IDC_INFO2, GetDisplay(&w, L"%c %t")); SetDlgItemText(m_hwnd, IDC_INFO3, w.feel); SetDlgItemText(m_hwnd, IDC_INFO4, w.pressure); - GetDisplay(&w, L"%i %w", str); - SetDlgItemText(m_hwnd, IDC_INFO5, str); + SetDlgItemText(m_hwnd, IDC_INFO5, GetDisplay(&w, L"%i %w")); SetDlgItemText(m_hwnd, IDC_INFO6, w.dewpoint); SetDlgItemText(m_hwnd, IDC_INFO7, w.sunrise); SetDlgItemText(m_hwnd, IDC_INFO8, w.sunset); SetDlgItemText(m_hwnd, IDC_INFO9, w.high); SetDlgItemText(m_hwnd, IDC_INFO10, w.low); - GetDisplay(&w, TranslateT("Last update on: %u"), str); - SetDlgItemText(m_hwnd, IDC_INFO11, str); + SetDlgItemText(m_hwnd, IDC_INFO11, GetDisplay(&w, TranslateT("Last update on: %u"))); SetDlgItemText(m_hwnd, IDC_INFO12, w.humid); SetDlgItemText(m_hwnd, IDC_INFO13, w.vis); return true; @@ -323,8 +346,11 @@ public: void onClick_Detail(CCtrlButton *) { HWND hMoreDataDlg = WindowList_Find(hDataWindowList, m_hContact); - if (hMoreDataDlg == nullptr) - hMoreDataDlg = CreateDialogParam(g_plugin.getInst(), MAKEINTRESOURCE(IDD_BRIEF), nullptr, DlgProcMoreData, m_hContact); + if (hMoreDataDlg == nullptr) { + auto *pDlg = new CBriefInfoDlg(ppro, m_hContact); + pDlg->Create(); + hMoreDataDlg = pDlg->GetHwnd(); + } else { SetForegroundWindow(hMoreDataDlg); SetFocus(hMoreDataDlg); @@ -334,21 +360,16 @@ public: } }; -int UserInfoInit(WPARAM wParam, LPARAM hContact) +int CWeatherProto::UserInfoInit(WPARAM wParam, LPARAM hContact) { - USERINFOPAGE uip = {}; - uip.szTitle.a = MODULENAME; - uip.position = 100000000; - uip.flags = ODPF_ICON; - uip.dwInitParam = LPARAM(g_plugin.getIconHandle(IDI_ICON)); - - if (hContact == 0) { - uip.pDialog = new WeatherMyDetailsDlg(); - g_plugin.addUserInfo(wParam, &uip); - } - else if (IsMyContact(hContact)) { // check if it is a weather contact + // check if it is a weather contact + if (IsMyContact(hContact)) { + USERINFOPAGE uip = {}; + uip.szTitle.w = m_tszUserName; + uip.position = 100000000; + uip.flags = ODPF_ICON | ODPF_BOLDGROUPS | ODPF_UNICODE; + uip.dwInitParam = LPARAM(g_plugin.getIconHandle(IDI_ICON)); uip.pDialog = new WeatherUserInfoDlg(); - uip.flags |= ODPF_BOLDGROUPS; g_plugin.addUserInfo(wParam, &uip); } return 0; diff --git a/protocols/Weather/weather.vcxproj b/protocols/Weather/weather.vcxproj index 35e9cf3032..56a2b52edd 100644 --- a/protocols/Weather/weather.vcxproj +++ b/protocols/Weather/weather.vcxproj @@ -34,15 +34,14 @@ <ClCompile Include="src\weather_contacts.cpp" /> <ClCompile Include="src\weather_conv.cpp" /> <ClCompile Include="src\weather_data.cpp" /> - <ClCompile Include="src\weather_http.cpp" /> - <ClCompile Include="src\weather_info.cpp" /> - <ClCompile Include="src\weather_ini.cpp" /> <ClCompile Include="src\weather_mwin.cpp" /> <ClCompile Include="src\weather_opt.cpp" /> <ClCompile Include="src\weather_popup.cpp" /> + <ClCompile Include="src\weather_proto.cpp" /> <ClCompile Include="src\weather_svcs.cpp" /> <ClCompile Include="src\weather_update.cpp" /> <ClCompile Include="src\weather_userinfo.cpp" /> + <ClInclude Include="src\proto.h" /> <ClInclude Include="src\resource.h" /> <ClInclude Include="src\stdafx.h" /> <ClInclude Include="src\version.h" /> diff --git a/protocols/Weather/weather.vcxproj.filters b/protocols/Weather/weather.vcxproj.filters index a8fbc7147e..92a72a4653 100644 --- a/protocols/Weather/weather.vcxproj.filters +++ b/protocols/Weather/weather.vcxproj.filters @@ -20,15 +20,6 @@ <ClCompile Include="src\weather_data.cpp"> <Filter>Source Files</Filter> </ClCompile> - <ClCompile Include="src\weather_http.cpp"> - <Filter>Source Files</Filter> - </ClCompile> - <ClCompile Include="src\weather_info.cpp"> - <Filter>Source Files</Filter> - </ClCompile> - <ClCompile Include="src\weather_ini.cpp"> - <Filter>Source Files</Filter> - </ClCompile> <ClCompile Include="src\weather_mwin.cpp"> <Filter>Source Files</Filter> </ClCompile> @@ -47,6 +38,9 @@ <ClCompile Include="src\weather_userinfo.cpp"> <Filter>Source Files</Filter> </ClCompile> + <ClCompile Include="src\weather_proto.cpp"> + <Filter>Source Files</Filter> + </ClCompile> </ItemGroup> <ItemGroup> <ClInclude Include="src\resource.h"> @@ -58,6 +52,9 @@ <ClInclude Include="src\version.h"> <Filter>Header Files</Filter> </ClInclude> + <ClInclude Include="src\proto.h"> + <Filter>Header Files</Filter> + </ClInclude> </ItemGroup> <ItemGroup> <ResourceCompile Include="res\resource.rc"> |