diff options
Diffstat (limited to 'protocols/Weather')
56 files changed, 12780 insertions, 0 deletions
diff --git a/protocols/Weather/docs/history.txt b/protocols/Weather/docs/history.txt new file mode 100644 index 0000000000..bf3351da1d --- /dev/null +++ b/protocols/Weather/docs/history.txt @@ -0,0 +1,930 @@ +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 new file mode 100644 index 0000000000..5b6e7c66c2 --- /dev/null +++ b/protocols/Weather/docs/license.txt @@ -0,0 +1,340 @@ + 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 new file mode 100644 index 0000000000..0f3e8d80c8 --- /dev/null +++ b/protocols/Weather/docs/readme.html @@ -0,0 +1,230 @@ +<!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 new file mode 100644 index 0000000000..9a045e1a3c --- /dev/null +++ b/protocols/Weather/docs/sample_ini.ini @@ -0,0 +1,428 @@ +[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.ini b/protocols/Weather/docs/weather/gismeteo.ini new file mode 100644 index 0000000000..eb1d38231d --- /dev/null +++ b/protocols/Weather/docs/weather/gismeteo.ini @@ -0,0 +1,906 @@ +[Weather 0.3.x Update Data 1.4] + +;********************************************************* +; +; 3 gismeteo.com(ua/ru). +; +; ! +; __ ID , . +; +; +; . +; ( ) " " . +; +; +; ->->-> "" ( ) +; : + + +; %[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] +; %[Forecast Day 10] +; %[Forecast Day 11] +; %[Forecast Day 12] + + +; +; ~~~~~~~~~~~~~~~ +; http://www.gismeteo.xxx +; xxx - "com" , .. "ru", "ua" ., +; +;********************************************************* + +[Header] +Name=GisMeteo +Internal Name=gm +Description=Weather information from Gismeteo +Author=Eugene +Version=2012.05.03 +[/Header] + + +[Default] +Default URL=http://www.gismeteo.ua/city/daily/%s/ +Default Map= +Update URL=http://www.gismeteo.ua/city/daily/%s/ +[/Default] + + +;------, , +;------TODO ... +;[nodata] +;Start=<div class="nodata"> +;End=</div> +;[/nodata] +;----------------------------------------------------- + +[CityName] +Start= +End= +[/CityName] + +[Condition] +Start=<dd> +End=</dd> +[/Condition] + +[Temperature] +Start=<dd class='value m_temp c'> +End=< +Unit=C +[/Temperature] + +;[Visibility] +;Set Data=[Condition] +;[/Visibility] + +[Wind Direction] +Start=<dl title=" +End=" +[/Wind Direction] + +[Wind Speed] +Start=<dd class='value m_wind ms' style='display:inline'> +End=<span class="unit"> +Unit=m/s +[/Wind Speed] + + +[Pressure] +Start=<dd class='value m_press torr'> +End=<span class="unit"> +Unit=mm +[/Pressure] + +[Humidity] +Start=<div class="wicon hum" title=""> +End=<span class="unit"> +Unit=% +[/Humidity] + +[Update] +Start=data-obs-time=" +End=" +[/Update] + +;[Cloudy] +;Start= +;End=</b> +;[/Cloudy] + +; DATE: T - time, D - day, M - month, W - weekday +[FD1DW] +Start=<div class="wtab swtab" id="tab_wdaily1"> +End=</dt> +Hidden=true + +[FD1DDM] +Start=<dd> +End=</dd> +Hidden=true + +;------------- +[Low] +Start=<div class="temp"> +End=</span> +Unit=C +[/Low] + +[High] +Start=.. +End=</span> +Unit=C +[/High] +;------------- + +[FD2DW] +Start=<dt> +End=</dt> +Hidden=true + +[FD2DDM] +Start=<dd> +End=</dd> +Hidden=true + +[FD3DW] +Start=<dt> +End=</dt> +Hidden=true + +[FD3DDM] +Start=<dd> +End=</dd> +Hidden=true + + + +;---------------////////////////////////// +;------1--------////////////////////////// +;---------------////////////////////////// +;---------1-234-------------- + +[FD1DT] +Start=<tbody id="wdaily1"> +End=</th> + +[FD1D] +Set Data=[FD1DW] & " " & [FD1DDM] & " " & [FD1DT] + + +; CONDITION +[FD1C] +Start=<td class="cltext"> +End=</td> + +;temperature +[FD1T] +Start=<td class="temp"> +End=</span> + +; PRESSURE +[FD1P] +Start=<td> +End=</span> + +; WIND: H - Hidden data D - direction, S - Speed +[FD1WD] +Start=<dl class="wind"> +End=</dt> +Hidden=true +[FD1WS] +Start=<dd> +End=</span> +Hidden=true +[FD1W] +Set Data=[FD1WD] & " " & [FD1WS] & "m/s" + +; Humidity +[FD1H] +Start=<td> +End=</td> +Hidden=true + +; Feel Like Temperature +[FD1F] +Start=<td> +End=</span> +Hidden=true + +;================================================ + +;---------1-2-34-------------- + +[FD2DT] +Start=</tr> +End=</th> +[FD2D] +Set Data=[FD1DW] & " " & [FD1DDM] & " " & [FD2DT] +; CONDITION +[FD2C] +Start=<td class="cltext"> +End=</td> +;temperature +[FD2T] +Start=<td class="temp"> +End=</span> +; PRESSURE +[FD2P] +Start=<td> +End=</span> +; WIND: H - Hidden data D - direction, S - Speed +[FD2WD] +Start=<dl class="wind"> +End=</dt> +Hidden=true +[FD2WS] +Start=<dd> +End=</span> +Hidden=true +[FD2W] +Set Data=[FD2WD] & " " & [FD2WS] & "m/s" +; Humidity +[FD2H] +Start=<td> +End=</td> +Hidden=true +; Feel Like Temperature +[FD2F] +Start=<td> +End=</span> +Hidden=true + +;================================================ +;---------12-3-4-------------- + +[FD3DT] +Start=</tr> +End=</th> +[FD3D] +Set Data=[FD1DW] & " " & [FD1DDM] & " " & [FD3DT] +; CONDITION +[FD3C] +Start=<td class="cltext"> +End=</td> +;temperature +[FD3T] +Start=<td class="temp"> +End=</span> +; PRESSURE +[FD3P] +Start=<td> +End=</span> +; WIND: H - Hidden data D - direction, S - Speed +[FD3WD] +Start=<dl class="wind"> +End=</dt> +Hidden=true +[FD3WS] +Start=<dd> +End=</span> +Hidden=true +[FD3W] +Set Data=[FD3WD] & " " & [FD3WS] & "m/s" +; Humidity +[FD3H] +Start=<td> +End=</td> +Hidden=true +; Feel Like Temperature +[FD3F] +Start=<td> +End=</span> +Hidden=true + +;================================================ +;---------123-4-------------- + +[FD4DT] +Start=</tr> +End=</th> + +[FD4D] +Set Data=[FD1DW] & " " & [FD1DDM] & " " & [FD4DT] + + +; CONDITION +[FD4C] +Start=<td class="cltext"> +End=</td> + +;temperature +[FD4T] +Start=<td class="temp"> +End=</span> + +; PRESSURE +[FD4P] +Start=<td> +End=</span> + +; WIND: H - Hidden data D - direction, S - Speed +[FD4WD] +Start=<dl class="wind"> +End=</dt> +Hidden=true +[FD4WS] +Start=<dd> +End=</span> +Hidden=true +[FD4W] +Set Data=[FD4WD] & " " & [FD4WS] & "m/s" + +; Humidity +[FD4H] +Start=<td> +End=</td> +Hidden=true + +; Feel Like Temperature +[FD4F] +Start=<td> +End=</span> +Hidden=true + +;================================================ +;====================1=========================== +;================================================ + + +;---------------////////////////////////// +;------2--------////////////////////////// +;---------------////////////////////////// +;---------1-234-------------- + +[FD5DT] +Start=</tbody> +End=</th> + +[FD5D] +Set Data=[FD2DW] & " " & [FD2DDM] & " " & [FD5DT] + + +; CONDITION +[FD5C] +Start=<td class="cltext"> +End=</td> + +;temperature +[FD5T] +Start=<td class="temp"> +End=</span> + +; PRESSURE +[FD5P] +Start=<td> +End=</span> + +; WIND: H - Hidden data D - direction, S - Speed +[FD5WD] +Start=<dl class="wind"> +End=</dt> +Hidden=true +[FD5WS] +Start=<dd> +End=</span> +Hidden=true +[FD5W] +Set Data=[FD5WD] & " " & [FD5WS] & "m/s" + +; Humidity +[FD5H] +Start=<td> +End=</td> +Hidden=true + +; Feel Like Temperature +[FD5F] +Start=<td> +End=</span> +Hidden=true + +;================================================ + +;---------1-2-34-------------- + +[FD6DT] +Start=</tr> +End=</th> + +[FD6D] +Set Data=[FD2DW] & " " & [FD2DDM] & " " & [FD6DT] + + +; CONDITION +[FD6C] +Start=<td class="cltext"> +End=</td> + +;temperature +[FD6T] +Start=<td class="temp"> +End=</span> + +; PRESSURE +[FD6P] +Start=<td> +End=</span> + +; WIND: H - Hidden data D - direction, S - Speed +[FD6WD] +Start=<dl class="wind"> +End=</dt> +Hidden=true +[FD6WS] +Start=<dd> +End=</span> +Hidden=true +[FD6W] +Set Data=[FD6WD] & " " & [FD6WS] & "m/s" + +; Humidity +[FD6H] +Start=<td> +End=</td> +Hidden=true + +; Feel Like Temperature +[FD6F] +Start=<td> +End=</span> +Hidden=true + +;================================================ + +;---------12-3-4-------------- + +[FD7DT] +Start=</tr> +End=</th> + +[FD7D] +Set Data=[FD2DW] & " " & [FD2DDM] & " " & [FD7DT] + + +; CONDITION +[FD7C] +Start=<td class="cltext"> +End=</td> + +;temperature +[FD7T] +Start=<td class="temp"> +End=</span> + +; PRESSURE +[FD7P] +Start=<td> +End=</span> + +; WIND: H - Hidden data D - direction, S - Speed +[FD7WD] +Start=<dl class="wind"> +End=</dt> +Hidden=true +[FD7WS] +Start=<dd> +End=</span> +Hidden=true +[FD7W] +Set Data=[FD7WD] & " " & [FD7WS] & "m/s" + +; Humidity +[FD7H] +Start=<td> +End=</td> +Hidden=true + +; Feel Like Temperature +[FD7F] +Start=<td> +End=</span> +Hidden=true + + +;================================================ +;---------123-4-------------- + +[FD8DT] +Start=</tr> +End=</th> + +[FD8D] +Set Data=[FD2DW] & " " & [FD2DDM] & " " & [FD8DT] + + +; CONDITION +[FD8C] +Start=<td class="cltext"> +End=</td> + +;temperature +[FD8T] +Start=<td class="temp"> +End=</span> + +; PRESSURE +[FD8P] +Start=<td> +End=</span> + +; WIND: H - Hidden data D - direction, S - Speed +[FD8WD] +Start=<dl class="wind"> +End=</dt> +Hidden=true +[FD8WS] +Start=<dd> +End=</span> +Hidden=true +[FD8W] +Set Data=[FD8WD] & " " & [FD8WS] & "m/s" + +; Humidity +[FD8H] +Start=<td> +End=</td> +Hidden=true + +; Feel Like Temperature +[FD8F] +Start=<td> +End=</span> +Hidden=true + +;================================================ +;====================2=========================== +;================================================ + +;---------------////////////////////////// +;------3--------////////////////////////// +;---------------////////////////////////// +;---------1-234-------------- + +[FD9DT] +Start=</tbody> +End=</th> + +[FD9D] +Set Data=[FD3DW] & " " & [FD3DDM] & " " & [FD9DT] + + +; CONDITION +[FD9C] +Start=<td class="cltext"> +End=</td> + +;temperature +[FD9T] +Start=<td class="temp"> +End=</span> + +; PRESSURE +[FD9P] +Start=<td> +End=</span> + +; WIND: H - Hidden data D - direction, S - Speed +[FD9WD] +Start=<dl class="wind"> +End=</dt> +Hidden=true +[FD9WS] +Start=<dd> +End=</span> +Hidden=true +[FD9W] +Set Data=[FD9WD] & " " & [FD9WS] & "m/s" + +; Humidity +[FD9H] +Start=<td> +End=</td> +Hidden=true + +; Feel Like Temperature +[FD9F] +Start=<td> +End=</span> +Hidden=true + +;================================================ + +;---------1-2-34-------------- + +[FD10DT] +Start=</tr> +End=</th> + +[FD10D] +Set Data=[FD3DW] & " " & [FD3DDM] & " " & [FD10DT] + + +; CONDITION +[FD10C] +Start=<td class="cltext"> +End=</td> + +;temperature +[FD10T] +Start=<td class="temp"> +End=</span> + +; PRESSURE +[FD10P] +Start=<td> +End=</span> + +; WIND: H - Hidden data D - direction, S - Speed +[FD10WD] +Start=<dl class="wind"> +End=</dt> +Hidden=true +[FD10WS] +Start=<dd> +End=</span> +Hidden=true +[FD10W] +Set Data=[FD10WD] & " " & [FD10WS] & "m/s" + +; Humidity +[FD10H] +Start=<td> +End=</td> +Hidden=true + +; Feel Like Temperature +[FD10F] +Start=<td> +End=</span> +Hidden=true + +;================================================ + +;---------12-3-4-------------- + +[FD11DT] +Start=</tr> +End=</th> + +[FD11D] +Set Data=[FD3DW] & " " & [FD3DDM] & " " & [FD11DT] + + +; CONDITION +[FD11C] +Start=<td class="cltext"> +End=</td> + +;temperature +[FD11T] +Start=<td class="temp"> +End=</span> + +; PRESSURE +[FD11P] +Start=<td> +End=</span> + +; WIND: H - Hidden data D - direction, S - Speed +[FD11WD] +Start=<dl class="wind"> +End=</dt> +Hidden=true +[FD11WS] +Start=<dd> +End=</span> +Hidden=true +[FD11W] +Set Data=[FD11WD] & " " & [FD11WS] & "m/s" + +; Humidity +[FD11H] +Start=<td> +End=</td> +Hidden=true + +; Feel Like Temperature +[FD11F] +Start=<td> +End=</span> +Hidden=true + +;================================================ +;---------123-4-------------- + +[FD12DT] +Start=</tr> +End=</th> + +[FD12D] +Set Data=[FD3DW] & " " & [FD3DDM] & " " & [FD12DT] + + +; CONDITION +[FD12C] +Start=<td class="cltext"> +End=</td> + +;temperature +[FD12T] +Start=<td class="temp"> +End=</span> + +; PRESSURE +[FD12P] +Start=<td> +End=</span> + +; WIND: H - Hidden data D - direction, S - Speed +[FD12WD] +Start=<dl class="wind"> +End=</dt> +Hidden=true +[FD12WS] +Start=<dd> +End=</span> +Hidden=true +[FD12W] +Set Data=[FD12WD] & " " & [FD12WS] & "m/s" + +; Humidity +[FD12H] +Start=<td> +End=</td> +Hidden=true + +; Feel Like Temperature +[FD12F] +Start=<td> +End=</span> +Hidden=true + +;================================================ +;====================3=========================== +;================================================ + + + +[Forecast Day 1] +Set Data=[FD1D] & " : " & [FD1T] & "C [" & [FD1F] & "C]" & ", " & [FD1C] & ", " & [FD1W] & ", " & [FD1P] & " mm, " & [FD1H] & "%" +[Forecast Day 2] +Set Data=[FD2D] & " : " & [FD2T] & "C [" & [FD2F] & "C]" & ", " & [FD2C] & ", " & [FD2W] & ", " & [FD2P] & " mm, " & [FD2H] & "%" +[Forecast Day 3] +Set Data=[FD3D] & " : " & [FD3T] & "C [" & [FD3F] & "C]" & ", " & [FD3C] & ", " & [FD3W] & ", " & [FD3P] & " mm, " & [FD3H] & "%" +[Forecast Day 4] +Set Data=[FD4D] & " : " & [FD4T] & "C [" & [FD4F] & "C]" & ", " & [FD4C] & ", " & [FD4W] & ", " & [FD4P] & " mm, " & [FD4H] & "%" + +[Forecast Day 5] +Set Data=[FD5D] & " : " & [FD5T] & "C [" & [FD5F] & "C]" & ", " & [FD5C] & ", " & [FD5W] & ", " & [FD5P] & " mm, " & [FD5H] & "%" +[Forecast Day 6] +Set Data=[FD6D] & " : " & [FD6T] & "C [" & [FD6F] & "C]" & ", " & [FD6C] & ", " & [FD6W] & ", " & [FD6P] & " mm, " & [FD6H] & "%" +[Forecast Day 7] +Set Data=[FD7D] & " : " & [FD7T] & "C [" & [FD7F] & "C]" & ", " & [FD7C] & ", " & [FD7W] & ", " & [FD7P] & " mm, " & [FD7H] & "%" +[Forecast Day 8] +Set Data=[FD8D] & " : " & [FD8T] & "C [" & [FD8F] & "C]" & ", " & [FD8C] & ", " & [FD8W] & ", " & [FD8P] & " mm, " & [FD8H] & "%" + +[Forecast Day 9] +Set Data=[FD9D] & " : " & [FD9T] & "C [" & [FD9F] & "C]" & ", " & [FD9C] & ", " & [FD9W] & ", " & [FD9P] & " mm, " & [FD9H] & "%" +[Forecast Day 10] +Set Data=[FD10D] & " : " & [FD10T] & "C [" & [FD10F] & "C]" & ", " & [FD10C] & ", " & [FD10W] & ", " & [FD10P] & " mm, " & [FD10H] & "%" +[Forecast Day 11] +Set Data=[FD11D] & " : " & [FD11T] & "C [" & [FD11F] & "C]" & ", " & [FD11C] & ", " & [FD11W] & ", " & [FD11P] & " mm, " & [FD11H] & "%" +[Forecast Day 12] +Set Data=[FD12D] & " : " & [FD12T] & "C [" & [FD12F] & "C]" & ", " & [FD12C] & ", " & [FD12W] & ", " & [FD12P] & " mm, " & [FD12H] & "%" + + + +;-------------------------------------------- +[TW] +Start= : +End=° +Unit=C +[/TW] + + +[Feel] +Start=<p class="temp"> +End=° +Unit=C +[/Feel] + +[Sunrise] +Start=</strong> +End=</li> +[/Sunrise] + +[Sunset] +Start=</strong> +End=</li> +[/Sunset] + +[Day Length] +Start=</strong> +End=</li> +[/Day Length] + +[MP1] +Start=</strong> +End=</li> +Hidden=true + +[MP2] +Start=<strong> +End=</strong> +Hidden=true + +[Moon Phase] +Set Data=[MP1] & ", " & [MP2] +[/Moon Phase] + +;[Update] +;Start=<span class="icon date_bottom"> +;End=</span> +;[/Update] + + +;[Feel] +;Set Data=[FD1FH] + + +[Icons] +Sunny= +Sunny= +Partly Cloudy= +Cloudy= +Cloudy= +Rain= +Rain Shower= +Rain Shower= +Snow= +Snow= +Snow Shower= +Snow Shower= +Snow Shower= +Ligntning= +Fog= + + +[ID Search] +Available=TRUE +Search URL=http://www.gismeteo.ua/city/daily/%s/ +Not Found Str=Not Found +Name Start= . +Name End=."> +[/ID Search] + +[Name Search] +Single Result=false +Multiple Result=true +Search URL=http://www.gismeteo.ua/city/?gis=%s +Not Found Str=Not found + +Mult First=ID +Mult ID Start=<li><a href="/city/daily/ +Mult ID End=/"> +Mult Name Start=/"><span><b> +Mult Name End=</b></span></a>
\ No newline at end of file diff --git a/protocols/Weather/docs/weather/msn.ini b/protocols/Weather/docs/weather/msn.ini new file mode 100644 index 0000000000..6a2929b4b6 --- /dev/null +++ b/protocols/Weather/docs/weather/msn.ini @@ -0,0 +1,1063 @@ +[Weather 0.3.x Update Data 1.5] +[Header] +Name=MSN Weather (New Layout) +Internal Name=msn2014 +Description=Get Weather from www.msn.com/en-us/weather +Author=HostedDinner +Version=2014-11-08 + +;Id of the station is lat,long as for example New York: "40.78,-73.83" + +[Default] +Default URL=http://www.msn.com/en-us/weather/today/x/we-city-%s +Default Map=http://www.msn.com/en-us/weather/maps/x/we-city-%s +Update URL=http://www.msn.com/en-us/weather/today/x/we-city-%s?weadegreetype=C +UserAgent=Mozilla/5.0 (Windows NT 6.3; WOW64; rv:33.0) Gecko/20100101 Firefox/33.0 + + +;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=kmph +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=% + +[Dewpoint] +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 + +[Moonphase] +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 + + + + + +[Update] +Start=data-obstime=" +End=" +Url=1 + + +[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=Showers + + +;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/docs/weather/weatherxml.ini b/protocols/Weather/docs/weather/weatherxml.ini new file mode 100644 index 0000000000..ad42d4f27e --- /dev/null +++ b/protocols/Weather/docs/weather/weatherxml.ini @@ -0,0 +1,911 @@ +[Weather 0.3.x Update Data 1.2] +[Header] +Name=WeatherXML +Internal Name=wxml +Author=CNSK (Fix by BloodySword) +Version=0.0.5.3 2009-07-16 +[Default] +Default URL=http://www.weather.com/outlook/travel/businesstraveler/local/%s +Default Map=http://www.weather.com/outlook/travel/map/%s +Update URL=http://xml.weather.com/weather/local/%s?cc=*&dayf=10&unit=s + +[Station] +Start=<dnam> +End=< +[Local Time] +Start=<tm> +End=< +[Latitude] +Start=<lat> +End=< +[Longitude] +Start=<lon> +End=< +[Sunrise] +Start=<sunr> +End=< +[Sunset] +Start=<suns> +End=< +[UTC] +Start=<zone> +End=< +[Update VAR] +Start=<lsup> +End=M +[Update] +Set Data=[Update VAR] & "M" +[Observatory] +Start=<obst> +End=< +[Temperature] +Start=<tmp> +End=< +Unit=F +[Feel] +Start=<flik> +End=< +Unit=F +[Condition] +Start=<t> +End=< +unit=cond +[Pressure] +Start=<r> +End=< +Unit=in +[Pressure Tendency] +Start=<d> +End=< +[Wind Speed] +Start=<s> +End=< +Unit=mph +[Wind Gusts] +Start=<gust> +End=< +Unit=mph +[Wind Direction DEG] +Start=<d> +End=< +[WindDir] +Start=<t> +End=< +[Wind Direction] +Set Data=[Wind Direction DEG] & " [" & [WindDir] & "]" +[Humidity] +Start=<hmid> +End=< +Unit=% +[Visibility] +Start=<vis> +End=< +Unit=miles +[UVI] +Start=<i> +End=< +[UV] +Start=<t> +End=< +[UV Index] +Set Data=[UVI] & " " & [UV] +[Dewpoint] +Start=<dewp> +End=< +Unit=F +[Moon] +Start=<t> +End=</t> +[Forecast Update VAR] +Start=<lsup> +End=M +[Forecast Update] +Set Data=[Forecast Update VAR] & "M" +[W1] +Start=<day d="0" t=" +End=" +Unit=Day +[D1] +Start=dt=" +End=" +[H1] +Start=<hi> +End=< +Unit=F +[L1] +Start=<low> +End=< +Unit=F +[R1] +Start=<sunr> +End=< +[S1] +Start=<suns> +End=< +[C1D] +Start=<t> +End=< +Unit=Cond +[WS1D] +Start=<s> +End=< +Unit=mph +[WG1D] +Start=<gust> +End=</gust> +Unit=mph +[WD1D] +Start=<d> +End=< +Unit=Deg +[WT1D] +Start=<t> +End=< +[P1D] +Start=<ppcp> +End=< +Unit=% +[H1D] +Start=<hmid> +End=< +Unit=% +[C1N] +Start=<t> +End=< +Unit=Cond +[WS1N] +Start=<s> +End=< +Unit=mph +[WG1N] +Start=<gust> +End=</gust> +Unit=mph +[WD1N] +Start=<d> +End=< +Unit=Deg +[WT1N] +Start=<t> +End=< +[P1N] +Start=<ppcp> +End=< +Unit=% +[H1N] +Start=<hmid> +End=< +Unit=% +[W2] +Start=<day d="1" t=" +End=" +Unit=Day +[D2] +Start=dt=" +End="> +[H2] +Start=<hi> +End=</hi> +Unit=F +[L2] +Start=<low> +End=</low> +Unit=F +[R2] +Start=<sunr> +End=</sunr> +[S2] +Start=<suns> +End=</suns> +[C2D] +Start=<t> +End=</t> +unit=cond +[WS2D] +Start=<s> +End=</s> +Unit=mph +[WG2D] +Start=<gust> +End=</gust> +Unit=mph +[WD2D] +Start=<d> +End=</d> +Unit=Deg +[WT2D] +Start=<t> +End=</t> +[P2D] +Start=<ppcp> +End=</ppcp> +Unit=% +[H2D] +Start=<hmid> +End=</hmid> +Unit=% +[C2N] +Start=<t> +End=</t> +unit=cond +[WS2N] +Start=<s> +End=</s> +Unit=mph +[WG2N] +Start=<gust> +End=</gust> +Unit=mph +[WD2N] +Start=<d> +End=</d> +Unit=Deg +[WT2N] +Start=<t> +End=</t> +[P2N] +Start=<ppcp> +End=</ppcp> +Unit=% +[H2N] +Start=<hmid> +End=</hmid> +Unit=% +[W3] +Start=<day d="2" t=" +End=" +Unit=Day +[D3] +Start=dt=" +End="> +[H3] +Start=<hi> +End=</hi> +Unit=F +[L3] +Start=<low> +End=</low> +Unit=F +[R3] +Start=<sunr> +End=</sunr> +[S3] +Start=<suns> +End=</suns> +[C3D] +Start=<t> +End=</t> +unit=cond +[WS3D] +Start=<s> +End=</s> +Unit=mph +[WG3D] +Start=<gust> +End=</gust> +Unit=mph +[WD3D] +Start=<d> +End=</d> +Unit=Deg +[WT3D] +Start=<t> +End=</t> +[P3D] +Start=<ppcp> +End=</ppcp> +Unit=% +[H3D] +Start=<hmid> +End=</hmid> +Unit=% +[C3N] +Start=<t> +End=</t> +unit=cond +[WS3N] +Start=<s> +End=</s> +Unit=mph +[WG3N] +Start=<gust> +End=</gust> +Unit=mph +[WD3N] +Start=<d> +End=</d> +Unit=Deg +[WT3N] +Start=<t> +End=</t> +[P3N] +Start=<ppcp> +End=</ppcp> +Unit=% +[H3N] +Start=<hmid> +End=</hmid> +Unit=% +[W4] +Start=<day d="3" t=" +End=" +Unit=Day +[D4] +Start=dt=" +End="> +[H4] +Start=<hi> +End=</hi> +Unit=F +[L4] +Start=<low> +End=</low> +Unit=F +[R4] +Start=<sunr> +End=</sunr> +[S4] +Start=<suns> +End=</suns> +[C4D] +Start=<t> +End=</t> +unit=cond +[WS4D] +Start=<s> +End=</s> +Unit=mph +[WG4D] +Start=<gust> +End=</gust> +Unit=mph +[WD4D] +Start=<d> +End=</d> +Unit=Deg +[WT4D] +Start=<t> +End=</t> +[P4D] +Start=<ppcp> +End=</ppcp> +Unit=% +[H4D] +Start=<hmid> +End=</hmid> +Unit=% +[C4N] +Start=<t> +End=</t> +unit=cond +[WS4N] +Start=<s> +End=</s> +Unit=mph +[WG4N] +Start=<gust> +End=</gust> +Unit=mph +[WD4N] +Start=<d> +End=</d> +Unit=Deg +[WT4N] +Start=<t> +End=</t> +[P4N] +Start=<ppcp> +End=</ppcp> +Unit=% +[H4N] +Start=<hmid> +End=</hmid> +Unit=% +[W5] +Start=<day d="4" t=" +End=" +Unit=Day +[D5] +Start=dt=" +End="> +[H5] +Start=<hi> +End=</hi> +Unit=F +[L5] +Start=<low> +End=</low> +Unit=F +[R5] +Start=<sunr> +End=</sunr> +[S5] +Start=<suns> +End=</suns> +[C5D] +Start=<t> +End=</t> +unit=cond +[WS5D] +Start=<s> +End=</s> +Unit=mph +[WG5D] +Start=<gust> +End=</gust> +Unit=mph +[WD5D] +Start=<d> +End=</d> +Unit=Deg +[WT5D] +Start=<t> +End=</t> +[P5D] +Start=<ppcp> +End=</ppcp> +Unit=% +[H5D] +Start=<hmid> +End=</hmid> +Unit=% +[C5N] +Start=<t> +End=</t> +unit=cond +[WS5N] +Start=<s> +End=</s> +Unit=mph +[WG5N] +Start=<gust> +End=</gust> +Unit=mph +[WD5N] +Start=<d> +End=</d> +Unit=Deg +[WT5N] +Start=<t> +End=</t> +[P5N] +Start=<ppcp> +End=</ppcp> +Unit=% +[H5N] +Start=<hmid> +End=</hmid> +Unit=% +[W6] +Start=<day d="5" t=" +End=" +Unit=Day +[D6] +Start=dt=" +End="> +[H6] +Start=<hi> +End=</hi> +Unit=F +[L6] +Start=<low> +End=</low> +Unit=F +[R6] +Start=<sunr> +End=</sunr> +[S6] +Start=<suns> +End=</suns> +[C6D] +Start=<t> +End=</t> +unit=cond +[WS6D] +Start=<s> +End=</s> +Unit=mph +[WG6D] +Start=<gust> +End=</gust> +Unit=mph +[WD6D] +Start=<d> +End=</d> +Unit=Deg +[WT6D] +Start=<t> +End=</t> +[P6D] +Start=<ppcp> +End=</ppcp> +Unit=% +[H6D] +Start=<hmid> +End=</hmid> +Unit=% +[C6N] +Start=<t> +End=</t> +unit=cond +[WS6N] +Start=<s> +End=</s> +Unit=mph +[WG6N] +Start=<gust> +End=</gust> +Unit=mph +[WD6N] +Start=<d> +End=</d> +Unit=Deg +[WT6N] +Start=<t> +End=</t> +[P6N] +Start=<ppcp> +End=</ppcp> +Unit=% +[H6N] +Start=<hmid> +End=</hmid> +Unit=% +[W7] +Start=<day d="6" t=" +End=" +Unit=Day +[D7] +Start=dt=" +End="> +[H7] +Start=<hi> +End=</hi> +Unit=F +[L7] +Start=<low> +End=</low> +Unit=F +[R7] +Start=<sunr> +End=</sunr> +[S7] +Start=<suns> +End=</suns> +[C7D] +Start=<t> +End=</t> +unit=cond +[WS7D] +Start=<s> +End=</s> +Unit=mph +[WG7D] +Start=<gust> +End=</gust> +Unit=mph +[WD7D] +Start=<d> +End=</d> +Unit=Deg +[WT7D] +Start=<t> +End=</t> +[P7D] +Start=<ppcp> +End=</ppcp> +Unit=% +[H7D] +Start=<hmid> +End=</hmid> +Unit=% +[C7N] +Start=<t> +End=</t> +unit=cond +[WS7N] +Start=<s> +End=</s> +Unit=mph +[WG7N] +Start=<gust> +End=</gust> +Unit=mph +[WD7N] +Start=<d> +End=</d> +Unit=Deg +[WT7N] +Start=<t> +End=</t> +[P7N] +Start=<ppcp> +End=</ppcp> +Unit=% +[H7N] +Start=<hmid> +End=</hmid> +Unit=% +[W8] +Start=<day d="7" t=" +End=" +Unit=Day +[D8] +Start=dt=" +End="> +[H8] +Start=<hi> +End=</hi> +Unit=F +[L8] +Start=<low> +End=</low> +Unit=F +[R8] +Start=<sunr> +End=</sunr> +[S8] +Start=<suns> +End=</suns> +[C8D] +Start=<t> +End=</t> +unit=cond +[WS8D] +Start=<s> +End=</s> +Unit=mph +[WG8D] +Start=<gust> +End=</gust> +Unit=mph +[WD8D] +Start=<d> +End=</d> +Unit=Deg +[WT8D] +Start=<t> +End=</t> +[P8D] +Start=<ppcp> +End=</ppcp> +Unit=% +[H8D] +Start=<hmid> +End=</hmid> +Unit=% +[C8N] +Start=<t> +End=</t> +unit=cond +[WS8N] +Start=<s> +End=</s> +Unit=mph +[WG8N] +Start=<gust> +End=</gust> +Unit=mph +[WD8N] +Start=<d> +End=</d> +Unit=Deg +[WT8N] +Start=<t> +End=</t> +[P8N] +Start=<ppcp> +End=</ppcp> +Unit=% +[H8N] +Start=<hmid> +End=</hmid> +Unit=% +[W9] +Start=<day d="8" t=" +End=" +Unit=Day +[D9] +Start=dt=" +End="> +[H9] +Start=<hi> +End=</hi> +Unit=F +[L9] +Start=<low> +End=</low> +Unit=F +[R9] +Start=<sunr> +End=</sunr> +[S9] +Start=<suns> +End=</suns> +[C9D] +Start=<t> +End=</t> +unit=cond +[WS9D] +Start=<s> +End=</s> +Unit=mph +[WG9D] +Start=<gust> +End=</gust> +Unit=mph +[WD9D] +Start=<d> +End=</d> +Unit=Deg +[WT9D] +Start=<t> +End=</t> +[P9D] +Start=<ppcp> +End=</ppcp> +Unit=% +[H9D] +Start=<hmid> +End=</hmid> +Unit=% +[C9N] +Start=<t> +End=</t> +unit=cond +[WS9N] +Start=<s> +End=</s> +Unit=mph +[WG9N] +Start=<gust> +End=</gust> +Unit=mph +[WD9N] +Start=<d> +End=</d> +Unit=Deg +[WT9N] +Start=<t> +End=</t> +[P9N] +Start=<ppcp> +End=</ppcp> +Unit=% +[H9N] +Start=<hmid> +End=</hmid> +Unit=% +[W0] +Start=<day d="9" t=" +End=" +Unit=Day +[D0] +Start=dt=" +End="> +[H0] +Start=<hi> +End=</hi> +Unit=F +[L0] +Start=<low> +End=</low> +Unit=F +[R0] +Start=<sunr> +End=</sunr> +[S0] +Start=<suns> +End=</suns> +[C0D] +Start=<t> +End=</t> +unit=cond +[WS0D] +Start=<s> +End=</s> +Unit=mph +[WG0D] +Start=<gust> +End=</gust> +Unit=mph +[WD0D] +Start=<d> +End=</d> +Unit=Deg +[WT0D] +Start=<t> +End=</t> +[P0D] +Start=<ppcp> +End=</ppcp> +Unit=% +[H0D] +Start=<hmid> +End=</hmid> +Unit=% +[C0N] +Start=<t> +End=</t> +unit=cond +[WS0N] +Start=<s> +End=</s> +Unit=mph +[WG0N] +Start=<gust> +End=</gust> +Unit=mph +[WD0N] +Start=<d> +End=</d> +Unit=Deg +[WT0N] +Start=<t> +End=</t> +[P0N] +Start=<ppcp> +End=</ppcp> +Unit=% +[H0N] +Start=<hmid> +End=</hmid> +Unit=% +[Low] +set Data=[L1] +[High] +set Data=[H1] + +[Forecast Day 1] +Set Data=[D1] & ": " & [H1] & "/" & [L1] & "; " & "Day" & ": " & [C1D] & ", " & "Wind" & " " & [WT1D] & ", " & [WS1D] & "; " & "Night" & ": " & [C1N] & ", " & "Wind" & " " & [WT1N] & ", " & [WS1N] + +[Forecast Day 2] +Set Data=[D2] & ": " & [H2] & "/" & [L2] & "; " & "Day" & ": " & [C2D] & ", " & "Wind" & " " & [WT2D] & ", " & [WS2D] & "; " & "Night" & ": " & [C2N] & ", " & "Wind" & " " & [WT2N] & ", " & [WS2N] + +[Forecast Day 3] +Set Data=[D3] & ": " & [H3] & "/" & [L3] & "; " & "Day" & ": " & [C3D] & ", " & "Wind" & " " & [WT3D] & ", " & [WS3D] & "; " & "Night" & ": " & [C3N] & ", " & "Wind" & " " & [WT3N] & ", " & [WS3N] + +[Forecast Day 4] +Set Data=[D4] & ": " & [H4] & "/" & [L4] & "; " & "Day" & ": " & [C4D] & ", " & "Wind" & " " & [WT4D] & ", " & [WS4D] & "; " & "Night" & ": " & [C4N] & ", " & "Wind" & " " & [WT4N] & ", " & [WS4N] + +[Forecast Day 5] +Set Data=[D5] & ": " & [H5] & "/" & [L5] & "; " & "Day" & ": " & [C5D] & ", " & "Wind" & " " & [WT5D] & ", " & [WS5D] & "; " & "Night" & ": " & [C5N] & ", " & "Wind" & " " & [WT5N] & ", " & [WS5N] + +[Forecast Day 6] +Set Data=[D6] & ": " & [H6] & "/" & [L6] & "; " & "Day" & ": " & [C6D] & ", " & "Wind" & " " & [WT6D] & ", " & [WS6D] & "; " & "Night" & ": " & [C6N] & ", " & "Wind" & " " & [WT6N] & ", " & [WS6N] + +[Forecast Day 7] +Set Data=[D7] & ": " & [H7] & "/" & [L7] & "; " & "Day" & ": " & [C7D] & ", " & "Wind" & " " & [WT7D] & ", " & [WS7D] & "; " & "Night" & ": " & [C7N] & ", " & "Wind" & " " & [WT7N] & ", " & [WS7N] + +[Forecast Day 8] +Set Data=[D8] & ": " & [H8] & "/" & [L8] & "; " & "Day" & ": " & [C8D] & ", " & "Wind" & " " & [WT8D] & ", " & [WS8D] & "; " & "Night" & ": " & [C8N] & ", " & "Wind" & " " & [WT8N] & ", " & [WS8N] + +[Forecast Day 9] +Set Data=[D9] & ": " & [H9] & "/" & [L9] & "; " & "Day" & ": " & [C9D] & ", " & "Wind" & " " & [WT9D] & ", " & [WS9D] & "; " & "Night" & ": " & [C9N] & ", " & "Wind" & " " & [WT9N] & ", " & [WS9N] + +[Forecast Day 0] +Set Data=[D0] & ": " & [H0] & "/" & [L0] & "; " & "Day" & ": " & [C0D] & ", " & "Wind" & " " & [WT0D] & ", " & [WS0D] & "; " & "Night" & ": " & [C0N] & ", " & "Wind" & " " & [WT0N] & ", " & [WS0N] + + +[ID Search] +Available=TRUE +Search URL=http://xml.weather.com/weather/local/%s +Not Found Str=Invalid location provided +Name Start=<dnam> +Name End=</dnam> +[Name Search] +Single Result=TRUE +Multiple Result=TRUE +Search URL=http://xml.weather.com/search/search?where=%s +Not Found Str=<search ver="2.0" /> +Single Result Str=Moved/Location: +Single First=ID +Single Name Start=type="1"> +Single Name End=</loc> +Single ID Start=<loc id=" +Single ID End=" +Mult First=ID +Mult Name Start=type="1"> +Mult Name End=</loc> +Mult ID Start=<loc id=" +Mult ID End="
\ No newline at end of file diff --git a/protocols/Weather/docs/weather/wundergrnd_intl.ini b/protocols/Weather/docs/weather/wundergrnd_intl.ini new file mode 100644 index 0000000000..f0a9dd3954 --- /dev/null +++ b/protocols/Weather/docs/weather/wundergrnd_intl.ini @@ -0,0 +1,348 @@ +[Weather 0.3.x Update Data 1.4] + +; Short history: +; 2004/03/22 Initial release +; 2004/03/23 Some fixes in visibility +; 2004/04/08 Update to v1.1, some new variables +; 2004/04/09 Some changes in format +; 2004/04/28 Fix in station search, no wind +; 2004/04/29 Fix wind, add some variables, Retrieve text forecast +; 2004/05/05 New WU webpage format update +; 2004/06/19 Fixes in forecast, new UV variable +; 2005/09/29 Updated for new website +; 2006/03/02 Updated for new website +; 2006/03/03 Updated for new website +; 2006/07/16 Updated for new website / Fixed search +; 2006/07/18 Updated for new website +; 2006/11/19 Added Feels-Like temperature +; 2006/12/01 Fixed pressure change indication +; 2008/02/04 Updated for new website +; 2008/02/19 Many fixes +; 2008/04/24 Fixed search and wind speed +; 2008/04/25 Fixed Visibility +; 2008/04/26 Fixed Feels-Like temperature +; 2008/06/07 Fixed wind display +; 2008/07/11 Updated for new website +; 2008/12/06 Updated for new website +; 2008/12/20 Updated for new website +; 2008/12/22 Updated for new website +; 2008/12/25 Fixed wind speed +; 2010/05/09 Fixed weather display when Feel-Like temeprature does not exist +; 2011/02/13 Updated for new website + +[Header] +Name=Weather Underground Int'l +Internal Name=wu_intl +Description=Download weather information for non-US cities from www.weatherunderground.com +Author=borkra mod by Mataes +Version=2011/02/13 + +[Default] +Default URL=http://www.wunderground.com/global/stations/%s.html +Default Map= +Update URL=http://classic.wunderground.com/global/stations/%s.html +Cookie=Units=english + +[Local Time] +Start=Local Time: +End=</span> + +[Latitude] +Start=<a href="http://maps.google.com/maps?q= +End=, + +[Longitude] +End=" + +[Alert] +Start=Active Advisory: +End=</a></nobr> + +[Update] +Start=Updated: +End=</span> + +[Temperature] +Start=<div style="font-size: 17px;"> +End= °F +Unit=F + +[Condition] +Start=<div class="b" style="font-size: 14px;"> +End=</div> +Unit=Cond + +[Feel] +Set Data=[Temperature] + +[Feel] +Start=<td>Windchill: +End= °F +Unit=F + +[Humidity] +Start=Humidity: +End=</nobr> + +[Dewpoint] +Start=Dew Point: +End= +Unit=F + +[Wind Speed] +Set Data="0" +Unit=mph + +; default is set to variable wind +[Wind Direction] +Set Data="Calm" + +[WindTmp] +Start=<td>Wind:</td> +End=window.wind_animate['CONDBOXWIND']= +Hidden=True + +[Wind Speed] +Source=WindTmp +Break Data=mph +Unit=mph + +[Wind Gust] +Start=Wind Gust: +End=</span> +Unit=mph + +[Pressure] +Start=Pressure: +End= in +Unit=in + +[Pressure Change] +Set Data="Stable" + +[Pressure Change] +Start=</span>\n\t\t( +End=)\n\t\t</td> + +[Heat Index] +Start=<td>Heat Index: +End= °F +Unit=F + +[Visibility] +Start=Visibility: +End= miles +Unit=miles + +[UV Index] +Start=UV: +End=<span + +[Elevation] +Start=Elevation: +End=</span> +Unit=ft + +[Wind Direction DEG] +Start=Wind Dir: +End=°</span +Unit=Deg + +[Wind Direction] +Start=> ( +End=)</td> + +[Sunrise] +Start=Actual Time</td> +End=</td> + +[Sunset] +Start=<td> +End=</td> + +[Moonrise] +Start=Moon</td> +End=</td> + +[Moonset] +Start=<td> +End=</td> + +[Visible Light Length] +Start=Length Of Visible Light:</td> +End=</td> + +[Day Length] +Start=Length of Day</td> +End=</div> + +[Day Length Diff Time] +Start=<span class="b"> +End=s +Hidden=True + +[Day Length Diff Word] +End=</span> +Hidden=True + +[Day Length Diff] +Set Data=[Day Length Diff Time] & "s " & [Day Length Diff Word] + +[Moon Phase] +Start=<div class="b"> +End=, +Hidden=True + +[Moon Percent] +Start= +End=% +Unit=% +Hidden=True + +[Moon Visible] +Start= +End=</div> +Hidden=True + +[Moon] +Set Data=[Moon Phase] & ", " & [Moon Percent] & " " & [Moon Visible] + +[Forecast Day 1 Day] +Start=<td class="taC" style="width: 20%;"> +End=</td> + +[Forecast Day 2 Day] +Start=<td class="taC" style="width: 20%;"> +End=</td> + +[Forecast Day 3 Day] +Start=<td class="taC" style="width: 20%;"> +End=</td> + +[Forecast Day 4 Day] +Start=<td class="taC" style="width: 20%;"> +End=</td> + +[Forecast Day 5 Day] +Start=<td class="taC" style="width: 20%;"> +End=</td> + +[Forecast Day 1 High] +Start=<div class="b nobr">\n\t\t<span style="color: #900;"> +End=° +Unit=F + +[Forecast Day 1 Low] +Start=<span style="color: #009;"> +End=° F</span> +Unit=F + +[Forecast Day 2 High] +Start=<div class="b nobr">\n\t\t<span style="color: #900;"> +End=° F</span> +Unit=F + +[Forecast Day 2 Low] +Start=<span style="color: #009;"> +End=° F</span> +Unit=F + +[Forecast Day 3 High] +Start=<div class="b nobr">\n\t\t<span style="color: #900;"> +End=° +Unit=F + +[Forecast Day 3 Low] +Start=<span style="color: #009;"> +End=° +Unit=F + +[Forecast Day 4 High] +Start=<div class="b nobr">\n\t\t<span style="color: #900;"> +End=° +Unit=F + +[Forecast Day 4 Low] +Start=<span style="color: #009;"> +End=° +Unit=F + +[Forecast Day 5 High] +Start=<div class="b nobr">\n\t\t<span style="color: #900;"> +End=° +Unit=F + +[Forecast Day 5 Low] +Start=<span style="color: #009;"> +End=° +Unit=F + +[Forecast Day 1 Condition] +Start=<td class="taC" > +End=</td> +Unit=Cond + +[Forecast Day 2 Condition] +Start=<td class="taC" > +End=</td> +Unit=Cond + +[Forecast Day 3 Condition] +Start=<td class="taC" > +End=</td> +Unit=Cond + +[Forecast Day 4 Condition] +Start=<td class="taC" > +End=</td> +Unit=Cond + +[Forecast Day 5 Condition] +Start=<td class="taC" > +End=</td> +Unit=Cond + +[Max] +Set Data=[Forecast Day 1 High] + +[Min] +Set Data=[Forecast Day 1 Low] + +[Forecast Day 1] +Set Data=[Forecast Day 1 Day] & ": " & [Forecast Day 1 Condition] & ", " & [Forecast Day 1 High] & "/" & [Forecast Day 1 Low] + +[Forecast Day 2] +Set Data=[Forecast Day 2 Day] & ": " & [Forecast Day 2 Condition] & ", " & [Forecast Day 2 High] & "/" & [Forecast Day 2 Low] + +[Forecast Day 3] +Set Data=[Forecast Day 3 Day] & ": " & [Forecast Day 3 Condition] & ", " & [Forecast Day 3 High] & "/" & [Forecast Day 3 Low] + +[Forecast Day 4] +Set Data=[Forecast Day 4 Day] & ": " & [Forecast Day 4 Condition] & ", " & [Forecast Day 4 High] & "/" & [Forecast Day 4 Low] + +[Forecast Day 5] +Set Data=[Forecast Day 5 Day] & ": " & [Forecast Day 5 Condition] & ", " & [Forecast Day 5 High] & "/" & [Forecast Day 5 Low] + +[ID Search] +Available=TRUE +Search URL=http://english.wunderground.com/global/stations/%s.html +Not Found Str=City Not Found +Name Start=type="application/rss+xml" title=" +Name End= RSS" + +[Name Search] +Single Result=TRUE +Multiple Result=TRUE +Search URL=http://classic.wunderground.com/cgi-bin/findweather/getForecast?query=%s +Not Found Str=City Not Found +Single Result Str=type="application/rss+xml" title=" +Single First=Name +Single Name Start=type="application/rss+xml" title=" +Single Name End= RSS" +Single ID Start=global/stations/ +Single ID End=.xml +Mult First=ID +Mult Name Start= +Mult Name End=</a></td> +Mult ID Start=<td><a href="/global/stations/ +Mult ID End=.html"> diff --git a/protocols/Weather/docs/weather/wundergrnd_xml.ini b/protocols/Weather/docs/weather/wundergrnd_xml.ini new file mode 100644 index 0000000000..0ffbd376c1 --- /dev/null +++ b/protocols/Weather/docs/weather/wundergrnd_xml.ini @@ -0,0 +1,325 @@ +[Weather 0.3.x Update Data 1.3] + +; Short history: +; 2008/05/19 Initial release +; 2008/06/07 More data +; 2008/06/08 More data +; 2011/02/13 Fixed feel temperature + +[Header] +Name=Weather Underground XML +Internal Name=wuxml +Description=Download weather information from www.weatherunderground.com +Author=borkra +Version=2011/02/13 + +[Default] +Default URL=http://www.wunderground.com/%s.html +Default Map= + +Update URL=http://api.wunderground.com/auto/wui/geo/ForecastXML/%s.html +Update URL2=http://api.wunderground.com/auto/wui/geo/WXCurrentObXML/%s.html +Update URL3=http://api.wunderground.com/auto/wui/geo/AlertsXML/%s.html + +[Alert] +Start=<description> +End=</description> + +[Latitude] +Start=<latitude> +End=</latitude> + +[Longitude] +Start=<longitude> +End=</longitude> + +[Observatory] +Start=<station_id> +End=</station_id> + +[Update] +Start=<observation_time>Last Updated on +End=</observation_time> + +[Condition] +Start=<weather> +End=</weather> +Unit=Cond + +[Temperature] +Start=<temp_f> +End=</temp_f> +Unit=F + +[Humidity] +Start=<relative_humidity> +End=</relative_humidity> + +[Wind Direction] +Start=<wind_dir> +End=</wind_dir> + +[Wind Direction DEG] +Start=<wind_degrees> +End=</wind_degrees> +Unit=Deg + +[Wind Speed] +Start=<wind_mph> +End=</wind_mph> +Unit=mph + +[Wind Gust] +Start=<wind_gust_mph> +End=</wind_gust_mph> +Unit=mph + +[Pressure] +Start=<pressure_in> +End=</pressure_in> +Unit=in + +[Pressure Tendency] +Set Data="Unknown" + +[Dewpoint] +Start=<dewpoint_f> +End=</dewpoint_f> +Unit=F + +[Feel] +Set Data=[Temperature] +Url=1 + +[Feel] +Start=<heat_index_f> +End=</heat_index_f> +Unit=F + +[Feel] +Start=<windchill_f> +End=</windchill_f> +Unit=F + +[Visibility] +Start=<visibility_mi> +End=</visibility_mi> +Unit=miles + +[Forecast Day 1 Text] +Start=<fcttext> +End=</fcttext> + +[Forecast Day 2 Text] +Start=<fcttext> +End=</fcttext> + +[Forecast Day 1 Day] +Start=<weekday> +End=</weekday> + +[Timezone] +Start=<tz_short> +End=</tz_short> + +[Forecast Day 1 High] +Start=<fahrenheit> +End=</fahrenheit> +Unit=F + +[Forecast Day 1 Low] +Start=<fahrenheit> +End=</fahrenheit> +Unit=F + +[Forecast Day 1 Condition] +Start=<conditions> +End=</conditions> +Unit=Cond + +[Forecast Day 2 Day] +Start=<weekday> +End=</weekday> + +[Forecast Day 2 High] +Start=<fahrenheit> +End=</fahrenheit> +Unit=F + +[Forecast Day 2 Low] +Start=<fahrenheit> +End=</fahrenheit> +Unit=F + +[Forecast Day 2 Condition] +Start=<conditions> +End=</conditions> +Unit=Cond + +[Forecast Day 3 Day] +Start=<weekday> +End=</weekday> + +[Forecast Day 3 High] +Start=<fahrenheit> +End=</fahrenheit> +Unit=F + +[Forecast Day 3 Low] +Start=<fahrenheit> +End=</fahrenheit> +Unit=F + +[Forecast Day 3 Condition] +Start=<conditions> +End=</conditions> +Unit=Cond + +[Forecast Day 4 Day] +Start=<weekday> +End=</weekday> + +[Forecast Day 4 High] +Start=<fahrenheit> +End=</fahrenheit> +Unit=F + +[Forecast Day 4 Low] +Start=<fahrenheit> +End=</fahrenheit> +Unit=F + +[Forecast Day 4 Condition] +Start=<conditions> +End=</conditions> +Unit=Cond + +[Forecast Day 5 Day] +Start=<weekday> +End=</weekday> + +[Forecast Day 5 High] +Start=<fahrenheit> +End=</fahrenheit> +Unit=F + +[Forecast Day 5 Low] +Start=<fahrenheit> +End=</fahrenheit> +Unit=F + +[Forecast Day 5 Condition] +Start=<conditions> +End=</conditions> +Unit=Cond + +[Forecast Day 6 Day] +Start=<weekday> +End=</weekday> + +[Forecast Day 6 High] +Start=<fahrenheit> +End=</fahrenheit> +Unit=F + +[Forecast Day 6 Low] +Start=<fahrenheit> +End=</fahrenheit> +Unit=F + +[Forecast Day 6 Condition] +Start=<conditions> +End=</conditions> +Unit=Cond + +[High] +Set Data=[Forecast Day 1 High] + +[Low] +Set Data=[Forecast Day 1 Low] + +[Forecast Day 1] +Set Data=[Forecast Day 1 Day] & ": " & [Forecast Day 1 Condition] & ", " & [Forecast Day 1 High] & "/" & [Forecast Day 1 Low] + +[Forecast Day 2] +Set Data=[Forecast Day 2 Day] & ": " & [Forecast Day 2 Condition] & ", " & [Forecast Day 2 High] & "/" & [Forecast Day 2 Low] + +[Forecast Day 3] +Set Data=[Forecast Day 3 Day] & ": " & [Forecast Day 3 Condition] & ", " & [Forecast Day 3 High] & "/" & [Forecast Day 3 Low] + +[Forecast Day 4] +Set Data=[Forecast Day 4 Day] & ": " & [Forecast Day 4 Condition] & ", " & [Forecast Day 4 High] & "/" & [Forecast Day 4 Low] + +[Forecast Day 5] +Set Data=[Forecast Day 5 Day] & ": " & [Forecast Day 5 Condition] & ", " & [Forecast Day 5 High] & "/" & [Forecast Day 5 Low] + +[Forecast Day 6] +Set Data=[Forecast Day 6 Day] & ": " & [Forecast Day 6 Condition] & ", " & [Forecast Day 6 High] & "/" & [Forecast Day 6 Low] + +[Moon] +Start=<percentIlluminated> +End=</percentIlluminated> +Unit=% + +[LTH] +Start=<hour> +End=</hour> +Hidden=True + +[LTM] +Start=<minute> +End=</minute> +Hidden=True + +[Local Time] +Set Data=[LTH] & ":" & [LTM] & " " & [Timezone] + +[SSTH] +Start=<hour> +End=</hour> +Hidden=True + +[SSTM] +Start=<minute> +End=</minute> +Hidden=True + +[Sunset] +Set Data=[SSTH] & ":" & [SSTM] & " " & [Timezone] + +[SRTH] +Start=<hour> +End=</hour> +Hidden=True + +[SRTM] +Start=<minute> +End=</minute> +Hidden=True + +[Sunrise] +Set Data=[SRTH] & ":" & [SRTM] & " " & [Timezone] + +[ID Search] +Available=TRUE +Search URL=http://api.wunderground.com/auto/wui/geo/WXCurrentObXML/%s.html +Not Found Str=Search not found +Name Start=type=<full> +Name End=</full> + +[Name Search] +Single Result=TRUE +Multiple Result=TRUE +Search URL=http://api.wunderground.com/auto/wui/geo/GeoLookupXML/index.xml?query=%s +Not Found Str=Search not found +Single Result Str=<requesturl> +Single First=Name +Single Name Start=<city> +Single Name End=</city> +Single ID Start=<requesturl>/ +Single ID End=.html +Mult First=Name +Mult Name Start=<name> +Mult Name End=</name> +Mult ID Start=<link>/ +Mult ID End=.html diff --git a/protocols/Weather/proto_weather/proto_weather.vcxproj b/protocols/Weather/proto_weather/proto_weather.vcxproj new file mode 100644 index 0000000000..abd20e124a --- /dev/null +++ b/protocols/Weather/proto_weather/proto_weather.vcxproj @@ -0,0 +1,28 @@ +<?xml version="1.0" encoding="utf-8"?> +<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> + <ItemGroup Label="ProjectConfigurations"> + <ProjectConfiguration Include="Debug|Win32"> + <Configuration>Debug</Configuration> + <Platform>Win32</Platform> + </ProjectConfiguration> + <ProjectConfiguration Include="Debug|x64"> + <Configuration>Debug</Configuration> + <Platform>x64</Platform> + </ProjectConfiguration> + <ProjectConfiguration Include="Release|Win32"> + <Configuration>Release</Configuration> + <Platform>Win32</Platform> + </ProjectConfiguration> + <ProjectConfiguration Include="Release|x64"> + <Configuration>Release</Configuration> + <Platform>x64</Platform> + </ProjectConfiguration> + </ItemGroup> + <PropertyGroup Label="Globals"> + <ProjectName>Proto_Weather</ProjectName> + <ProjectGuid>{B2F4BA6C-1BD6-4A50-A706-DCBC6A5D439B}</ProjectGuid> + </PropertyGroup> + <ImportGroup Label="PropertySheets"> + <Import Project="$(ProjectDir)..\..\..\build\vc.common\icons.props" /> + </ImportGroup> +</Project>
\ No newline at end of file diff --git a/protocols/Weather/proto_weather/proto_weather.vcxproj.filters b/protocols/Weather/proto_weather/proto_weather.vcxproj.filters new file mode 100644 index 0000000000..28f81e7f1b --- /dev/null +++ b/protocols/Weather/proto_weather/proto_weather.vcxproj.filters @@ -0,0 +1,4 @@ +<?xml version="1.0" encoding="utf-8"?> +<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> + <Import Project="$(ProjectDir)..\..\..\build\vc.common\common.filters" /> +</Project>
\ No newline at end of file diff --git a/protocols/Weather/proto_weather/res/Cloud.ico b/protocols/Weather/proto_weather/res/Cloud.ico Binary files differnew file mode 100644 index 0000000000..52b8842c76 --- /dev/null +++ b/protocols/Weather/proto_weather/res/Cloud.ico diff --git a/protocols/Weather/proto_weather/res/FOG.ico b/protocols/Weather/proto_weather/res/FOG.ico Binary files differnew file mode 100644 index 0000000000..598889503e --- /dev/null +++ b/protocols/Weather/proto_weather/res/FOG.ico diff --git a/protocols/Weather/proto_weather/res/LIGHT.ico b/protocols/Weather/proto_weather/res/LIGHT.ico Binary files differnew file mode 100644 index 0000000000..bff56d15d2 --- /dev/null +++ b/protocols/Weather/proto_weather/res/LIGHT.ico diff --git a/protocols/Weather/proto_weather/res/NA.ico b/protocols/Weather/proto_weather/res/NA.ico Binary files differnew file mode 100644 index 0000000000..47840dafbb --- /dev/null +++ b/protocols/Weather/proto_weather/res/NA.ico diff --git a/protocols/Weather/proto_weather/res/PCLOUDY.ico b/protocols/Weather/proto_weather/res/PCLOUDY.ico Binary files differnew file mode 100644 index 0000000000..eef4eccb59 --- /dev/null +++ b/protocols/Weather/proto_weather/res/PCLOUDY.ico diff --git a/protocols/Weather/proto_weather/res/RAIN.ico b/protocols/Weather/proto_weather/res/RAIN.ico Binary files differnew file mode 100644 index 0000000000..4a43c4c62b --- /dev/null +++ b/protocols/Weather/proto_weather/res/RAIN.ico diff --git a/protocols/Weather/proto_weather/res/RSHOWER.ico b/protocols/Weather/proto_weather/res/RSHOWER.ico Binary files differnew file mode 100644 index 0000000000..dcb98b80a1 --- /dev/null +++ b/protocols/Weather/proto_weather/res/RSHOWER.ico diff --git a/protocols/Weather/proto_weather/res/SNOW.ico b/protocols/Weather/proto_weather/res/SNOW.ico Binary files differnew file mode 100644 index 0000000000..3cc60a0817 --- /dev/null +++ b/protocols/Weather/proto_weather/res/SNOW.ico diff --git a/protocols/Weather/proto_weather/res/SSHOWER.ico b/protocols/Weather/proto_weather/res/SSHOWER.ico Binary files differnew file mode 100644 index 0000000000..f2e2e45a02 --- /dev/null +++ b/protocols/Weather/proto_weather/res/SSHOWER.ico diff --git a/protocols/Weather/proto_weather/res/SUN.ico b/protocols/Weather/proto_weather/res/SUN.ico Binary files differnew file mode 100644 index 0000000000..c5a1206468 --- /dev/null +++ b/protocols/Weather/proto_weather/res/SUN.ico diff --git a/protocols/Weather/proto_weather/res/resource.rc b/protocols/Weather/proto_weather/res/resource.rc new file mode 100644 index 0000000000..5341c6dbf8 --- /dev/null +++ b/protocols/Weather/proto_weather/res/resource.rc @@ -0,0 +1,41 @@ +//Microsoft Developer Studio generated resource script. +// + +#define APSTUDIO_READONLY_SYMBOLS +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 2 resource. +// +#include "winres.h" +///////////////////////////////////////////////////////////////////////////// +#undef APSTUDIO_READONLY_SYMBOLS + +///////////////////////////////////////////////////////////////////////////// +// English (U.S.) resources + +#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU) +#ifdef _WIN32 +LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US +#pragma code_page(1252) +#endif //_WIN32 + +///////////////////////////////////////////////////////////////////////////// +// +// Icon +// + +// Icon with lowest ID value placed first to ensure application icon +// remains consistent on all systems. +104 ICON "SUN.ico" +105 ICON "NA.ico" +128 ICON "PCLOUDY.ico" +129 ICON "RSHOWER.ico" +130 ICON "LIGHT.ico" +131 ICON "RAIN.ico" +158 ICON "SNOW.ico" +159 ICON "CLOUD.ico" +1002 ICON "SSHOWER.ico" +1003 ICON "FOG.ico" + +#endif // English (U.S.) resources +/////////////////////////////////////////////////////////////////////////////
\ No newline at end of file diff --git a/protocols/Weather/res/Version.rc b/protocols/Weather/res/Version.rc new file mode 100644 index 0000000000..5a5ddd63ed --- /dev/null +++ b/protocols/Weather/res/Version.rc @@ -0,0 +1,9 @@ +// Microsoft Visual C++ generated resource script. +// +#ifdef APSTUDIO_INVOKED +#error this file is not editable by Microsoft Visual C++ +#endif //APSTUDIO_INVOKED + +#include "..\src\version.h" + +#include "..\..\build\Version.rc" diff --git a/protocols/Weather/res/brief.ico b/protocols/Weather/res/brief.ico Binary files differnew file mode 100644 index 0000000000..20b5fa1dd1 --- /dev/null +++ b/protocols/Weather/res/brief.ico diff --git a/protocols/Weather/res/disabled.ico b/protocols/Weather/res/disabled.ico Binary files differnew file mode 100644 index 0000000000..9993103efc --- /dev/null +++ b/protocols/Weather/res/disabled.ico diff --git a/protocols/Weather/res/edit.ico b/protocols/Weather/res/edit.ico Binary files differnew file mode 100644 index 0000000000..7c6b07c71a --- /dev/null +++ b/protocols/Weather/res/edit.ico diff --git a/protocols/Weather/res/icon.ico b/protocols/Weather/res/icon.ico Binary files differnew file mode 100644 index 0000000000..eef4eccb59 --- /dev/null +++ b/protocols/Weather/res/icon.ico diff --git a/protocols/Weather/res/log.ico b/protocols/Weather/res/log.ico Binary files differnew file mode 100644 index 0000000000..fc4bf7251b --- /dev/null +++ b/protocols/Weather/res/log.ico diff --git a/protocols/Weather/res/map.ico b/protocols/Weather/res/map.ico Binary files differnew file mode 100644 index 0000000000..16b359b132 --- /dev/null +++ b/protocols/Weather/res/map.ico diff --git a/protocols/Weather/res/more.ico b/protocols/Weather/res/more.ico Binary files differnew file mode 100644 index 0000000000..bfd03e8bac --- /dev/null +++ b/protocols/Weather/res/more.ico diff --git a/protocols/Weather/res/popup.ico b/protocols/Weather/res/popup.ico Binary files differnew file mode 100644 index 0000000000..5b3fe4e65b --- /dev/null +++ b/protocols/Weather/res/popup.ico diff --git a/protocols/Weather/res/popup_no.ico b/protocols/Weather/res/popup_no.ico Binary files differnew file mode 100644 index 0000000000..2b298a96ea --- /dev/null +++ b/protocols/Weather/res/popup_no.ico diff --git a/protocols/Weather/res/resource.rc b/protocols/Weather/res/resource.rc new file mode 100644 index 0000000000..9841527018 --- /dev/null +++ b/protocols/Weather/res/resource.rc @@ -0,0 +1,427 @@ +// Microsoft Visual C++ generated resource script. +// +#include "..\src\resource.h" + +#define APSTUDIO_READONLY_SYMBOLS +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 2 resource. +// +#include <winres.h> + +///////////////////////////////////////////////////////////////////////////// +#undef APSTUDIO_READONLY_SYMBOLS + +///////////////////////////////////////////////////////////////////////////// +// Немецкий (Германия) resources + +#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_DEU) +LANGUAGE LANG_GERMAN, SUBLANG_GERMAN +#pragma code_page(1252) + +///////////////////////////////////////////////////////////////////////////// +// +// Dialog +// + +IDD_BRIEF DIALOGEX 0, 0, 245, 231 +STYLE DS_SETFONT | DS_SETFOREGROUND | DS_3DLOOK | DS_FIXEDSYS | DS_CENTER | WS_MINIMIZEBOX | WS_MAXIMIZEBOX | WS_POPUP | WS_VISIBLE | WS_CAPTION | WS_SYSMENU | WS_THICKFRAME +EXSTYLE WS_EX_WINDOWEDGE | WS_EX_CONTROLPARENT +FONT 8, "MS Shell Dlg", 0, 0, 0x1 +BEGIN + CONTROL "",IDC_HEADERBAR,"MHeaderbarCtrl",0x0,0,0,245,25 + CONTROL "",IDC_MTEXT,"RichEdit50W",NOT WS_VISIBLE | WS_VSCROLL | WS_TABSTOP | 0x804,0,25,244,180,WS_EX_STATICEDGE + CONTROL "List1",IDC_DATALIST,"SysListView32",LVS_REPORT | LVS_SINGLESEL | LVS_SORTASCENDING | WS_TABSTOP,0,25,244,180,WS_EX_STATICEDGE + PUSHBUTTON "Update",IDC_MUPDATE,10,213,48,13 + PUSHBUTTON "Brief Info",IDC_MTOGGLE,79,213,48,13 + PUSHBUTTON "Webpage",IDC_MWEBPAGE,132,213,48,13 + DEFPUSHBUTTON "Close",IDCANCEL,184,213,48,13 +END + +IDD_OPTIONS DIALOGEX 0, 0, 306, 222 +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 + 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 + 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 + LTEXT "Degree sign:",IDC_STATIC,227,116,55,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 + 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 + CONTROL "3 chars",IDC_D3,"Button",BS_AUTORADIOBUTTON,176,153,56,8 + LTEXT "Elevation",IDC_STATIC,8,163,53,8 + CONTROL "ft",IDC_E1,"Button",BS_AUTORADIOBUTTON,65,163,34,8 + CONTROL "m",IDC_E2,"Button",BS_AUTORADIOBUTTON,120,163,34,8 + CONTROL "Do not append units to values",IDC_DONOTAPPUNITS,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,8,174,144,8 + CONTROL "Do not display fractional values",IDC_NOFRAC,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,155,174,139,8 + GROUPBOX "Frame",IDC_STATIC,3,187,300,29 + EDITTEXT IDC_AVATARSIZE,8,196,36,14,ES_AUTOHSCROLL | ES_NUMBER | NOT WS_BORDER,WS_EX_CLIENTEDGE | WS_EX_STATICEDGE + CONTROL "",IDC_AVATARSPIN,"msctls_updown32",UDS_SETBUDDYINT | UDS_ALIGNRIGHT | UDS_AUTOBUDDY | UDS_ARROWKEYS | UDS_NOTHOUSANDS,43,196,11,14 + LTEXT "Avatar size",IDC_STATIC,60,200,95,9 +END + +IDD_EDIT DIALOGEX 0, 0, 241, 226 +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" +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 + LTEXT "ID",IDC_STATIC,12,37,57,8,SS_CENTERIMAGE + EDITTEXT IDC_ID,69,35,146,12,ES_AUTOHSCROLL + 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 + CONTROL "Overwrite file upon update",IDC_Overwrite,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,119,80,111,8 + 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 + 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 +END + +IDD_POPUP DIALOGEX 0, 0, 312, 236 +STYLE DS_SETFONT | DS_FIXEDSYS | WS_CHILD +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 + LTEXT "Background color",IDC_STATIC,223,18,78,8,SS_CENTERIMAGE + CONTROL "",IDC_TEXTCOLOUR,"ColourPicker",WS_TABSTOP,177,30,39,11 + LTEXT "Text color",IDC_STATIC,223,31,80,8,SS_CENTERIMAGE + CONTROL "Use Windows colors",IDC_USEWINCOLORS,"Button",BS_AUTOCHECKBOX | BS_NOTIFY | WS_TABSTOP,177,43,125,13 + GROUPBOX "Popup Actions",IDC_STATIC,4,63,157,46 + LTEXT "Left Click",IDC_STATIC,13,77,42,8 + CONTROL "",IDC_LeftClick,"MButtonClass",WS_TABSTOP,59,76,95,9,WS_EX_NOACTIVATE | 0x10000000L + LTEXT "Right Click",IDC_STATIC,13,93,42,8 + CONTROL "",IDC_RightClick,"MButtonClass",WS_TABSTOP,59,92,95,9,WS_EX_NOACTIVATE | 0x10000000L + GROUPBOX "Popup Delay",IDC_STATIC,167,63,141,46 + CONTROL "Delay",IDC_PD3,"Button",BS_AUTORADIOBUTTON,177,74,53,8 + EDITTEXT IDC_DELAY,233,73,36,12,ES_RIGHT | ES_AUTOHSCROLL | ES_NUMBER | NOT WS_BORDER,WS_EX_STATICEDGE + LTEXT "seconds",IDC_STATIC,272,73,34,10 + CONTROL "From popup plugin",IDC_PD1,"Button",BS_AUTORADIOBUTTON,177,85,110,8 + CONTROL "Permanent",IDC_PD2,"Button",BS_AUTORADIOBUTTON,177,96,110,8 + GROUPBOX "Popup Text",IDC_STATIC,3,112,305,121 + LTEXT "Popup Title",IDC_STATIC,15,124,56,9 + EDITTEXT IDC_PTitle,72,121,231,12,ES_AUTOHSCROLL + LTEXT "Popup Text",IDC_STATIC,15,138,55,9 + EDITTEXT IDC_PText,72,136,231,92,ES_MULTILINE | ES_AUTOVSCROLL | ES_WANTRETURN | WS_VSCROLL + 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 +END + +IDD_TEXTOPT 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 + CONTROL "Contact List",IDC_TM1,"MButtonClass",WS_TABSTOP | 0x100,2,16,77,9,WS_EX_WINDOWEDGE | WS_EX_NOACTIVATE | 0x10000000L + EDITTEXT IDC_CTEXT,80,15,125,12,ES_AUTOHSCROLL + CONTROL "Brief Info Title",IDC_TM2,"MButtonClass",WS_TABSTOP,2,3,77,9,WS_EX_WINDOWEDGE | WS_EX_NOACTIVATE | 0x10000000L + EDITTEXT IDC_BTITLE,80,1,226,12,ES_AUTOHSCROLL + CONTROL "Brief Info",IDC_TM3,"MButtonClass",WS_TABSTOP,57,41,77,9,WS_EX_WINDOWEDGE | WS_EX_NOACTIVATE | 0x10000000L + EDITTEXT IDC_BTEXT,1,51,203,41,ES_MULTILINE | ES_WANTRETURN | WS_VSCROLL + CONTROL "Note Text",IDC_TM4,"MButtonClass",WS_TABSTOP,57,94,77,9,WS_EX_WINDOWEDGE | WS_EX_NOACTIVATE | 0x10000000L + EDITTEXT IDC_NTEXT,1,104,203,44,ES_MULTILINE | ES_WANTRETURN | WS_VSCROLL + CONTROL "Extra Text",IDC_TM5,"MButtonClass",WS_TABSTOP,57,150,77,9,WS_EX_WINDOWEDGE | WS_EX_NOACTIVATE | 0x10000000L + EDITTEXT IDC_XTEXT,2,160,202,45,ES_MULTILINE | ES_WANTRETURN | WS_VSCROLL + CONTROL "External Log",IDC_TM6,"MButtonClass",WS_TABSTOP,2,208,77,9,WS_EX_WINDOWEDGE | WS_EX_NOACTIVATE | 0x10000000L + EDITTEXT IDC_ETEXT,80,206,183,12,ES_AUTOHSCROLL + 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 "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 + CONTROL "Status Message",IDC_TM8,"MButtonClass",WS_TABSTOP | 0x100,2,29,77,9,WS_EX_WINDOWEDGE | WS_EX_NOACTIVATE | 0x10000000L +END + +IDD_USERINFO DIALOGEX 0, 0, 222, 132 +STYLE DS_SETFONT | DS_FIXEDSYS | DS_CONTROL | WS_CHILD +EXSTYLE WS_EX_CONTROLPARENT +FONT 8, "MS Shell Dlg", 0, 0, 0x1 +BEGIN + ICON "",IDC_INFOICON,16,15,20,20,SS_CENTERIMAGE + LTEXT "",IDC_INFO1,12,8,193,10 + LTEXT "Sunset",IDC_STATIC,112,58,54,8 + LTEXT "Feel-like",IDC_STATIC,12,46,39,8 + LTEXT "Today's Low",IDC_STATIC,112,82,54,8 + LTEXT "Wind",IDC_STATIC,12,70,39,8 + LTEXT "Today's High",IDC_STATIC,112,70,54,8 + LTEXT "Sunrise",IDC_STATIC,112,46,54,8 + LTEXT "",IDC_INFO11,12,121,195,9 + LTEXT "Dew point",IDC_STATIC,12,94,39,8 + LTEXT "Pressure",IDC_STATIC,12,58,39,8 + GROUPBOX "",IDC_STATIC,4,36,211,84 + GROUPBOX "",IDC_STATIC,4,1,211,35 + EDITTEXT IDC_INFO2,42,20,165,12,ES_AUTOHSCROLL | ES_READONLY | NOT WS_BORDER + EDITTEXT IDC_INFO3,51,46,57,12,ES_AUTOHSCROLL | ES_READONLY | NOT WS_BORDER + EDITTEXT IDC_INFO4,51,58,57,12,ES_AUTOHSCROLL | ES_READONLY | NOT WS_BORDER + EDITTEXT IDC_INFO5,51,70,56,12,ES_AUTOHSCROLL | ES_READONLY | NOT WS_BORDER + EDITTEXT IDC_INFO6,51,94,56,12,ES_AUTOHSCROLL | ES_READONLY | NOT WS_BORDER + EDITTEXT IDC_INFO7,166,46,41,12,ES_AUTOHSCROLL | ES_READONLY | NOT WS_BORDER + EDITTEXT IDC_INFO8,166,58,41,12,ES_AUTOHSCROLL | ES_READONLY | NOT WS_BORDER + EDITTEXT IDC_INFO9,166,70,41,12,ES_AUTOHSCROLL | ES_READONLY | NOT WS_BORDER + EDITTEXT IDC_INFO10,166,82,41,12,ES_AUTOHSCROLL | ES_READONLY | NOT WS_BORDER + LTEXT "Humidity",IDC_STATIC,12,82,39,8 + EDITTEXT IDC_INFO12,51,82,56,12,ES_AUTOHSCROLL | ES_READONLY | NOT WS_BORDER + LTEXT "Visibility",IDC_STATIC,12,106,39,8 + EDITTEXT IDC_INFO13,51,106,56,12,ES_AUTOHSCROLL | ES_READONLY | NOT WS_BORDER + 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 +FONT 8, "MS Shell Dlg", 400, 0, 0x1 +BEGIN + EDITTEXT IDC_SEARCHCITY,3,18,103,12,0,WS_EX_CLIENTEDGE + LTEXT "City:",IDC_STATIC,6,7,99,8 +END + + +///////////////////////////////////////////////////////////////////////////// +// +// DESIGNINFO +// + +#ifdef APSTUDIO_INVOKED +GUIDELINES DESIGNINFO +BEGIN + IDD_BRIEF, DIALOG + BEGIN + RIGHTMARGIN, 241 + BOTTOMMARGIN, 226 + END + + IDD_OPTIONS, DIALOG + BEGIN + VERTGUIDE, 8 + VERTGUIDE, 294 + BOTTOMMARGIN, 209 + END + + IDD_POPUP, DIALOG + BEGIN + RIGHTMARGIN, 306 + BOTTOMMARGIN, 233 + END + + IDD_TEXTOPT, DIALOG + BEGIN + BOTTOMMARGIN, 232 + END + + IDD_SETUP, DIALOG + BEGIN + BOTTOMMARGIN, 136 + END + + IDD_INFO, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 217 + TOPMARGIN, 7 + BOTTOMMARGIN, 148 + END + + IDD_SEARCHCITY, DIALOG + BEGIN + RIGHTMARGIN, 113 + BOTTOMMARGIN, 54 + END +END +#endif // APSTUDIO_INVOKED + + +///////////////////////////////////////////////////////////////////////////// +// +// Menu +// + +IDR_PMENU MENU +BEGIN + POPUP "Menu" + BEGIN + MENUITEM "Dismiss Popup", IDM_M1 + MENUITEM "Open brief information", IDM_M2 + MENUITEM "Open complete forecast", IDM_M3 + MENUITEM "Open weather map", IDM_M4 + MENUITEM "View history", IDM_M5 + MENUITEM "Open log file", IDM_M6 + MENUITEM "Show user menu", IDM_M7 + MENUITEM "Show user detail", IDM_M8 + END +END + +IDR_TMENU MENU +BEGIN + POPUP "Menu" + BEGIN + MENUITEM "To old setting", ID_T1 + MENUITEM "To default", ID_T2 + END +END + +IDR_TMMENU MENU +BEGIN + POPUP "Menu" + BEGIN + MENUITEM "Preview", ID_MPREVIEW + MENUITEM "Reset", ID_MRESET + END +END + + +///////////////////////////////////////////////////////////////////////////// +// +// Icon +// + +// 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_POPUP ICON "popup.ico" +IDI_NOPOPUP ICON "popup_no.ico" +IDI_UPDATE2 ICON "update2.ico" +IDI_DISABLED ICON "disabled.ico" + +#ifdef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// TEXTINCLUDE +// + +1 TEXTINCLUDE +BEGIN + "..\\src\\resource.h\0" +END + +2 TEXTINCLUDE +BEGIN + "#include <winres.h>\r\n" + "\0" +END + +3 TEXTINCLUDE +BEGIN + "\r\n" + "\0" +END + +#endif // APSTUDIO_INVOKED + +#endif // Немецкий (Германия) resources +///////////////////////////////////////////////////////////////////////////// + + + +#ifndef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 3 resource. +// + + +///////////////////////////////////////////////////////////////////////////// +#endif // not APSTUDIO_INVOKED + diff --git a/protocols/Weather/res/update.ico b/protocols/Weather/res/update.ico Binary files differnew file mode 100644 index 0000000000..0e4fd3171a --- /dev/null +++ b/protocols/Weather/res/update.ico diff --git a/protocols/Weather/res/update2.ico b/protocols/Weather/res/update2.ico Binary files differnew file mode 100644 index 0000000000..d702dfc8bd --- /dev/null +++ b/protocols/Weather/res/update2.ico diff --git a/protocols/Weather/src/resource.h b/protocols/Weather/src/resource.h new file mode 100644 index 0000000000..eecba58268 --- /dev/null +++ b/protocols/Weather/src/resource.h @@ -0,0 +1,175 @@ +//{{NO_DEPENDENCIES}} +// Microsoft Visual C++ generated include file. +// Used by ..\res\resource.rc +// +#define IDI_ICON 101 +#define IDD_USERINFO 201 +#define IDD_EDIT 202 +#define IDI_DISABLED 203 +#define IDD_POPUP 204 +#define IDD_OPTIONS 205 +#define IDI_LOG 206 +#define IDI_UPDATE2 208 +#define IDI_READ 209 +#define IDI_UPDATE 210 +#define IDI_S 211 +#define IDI_MAP 212 +#define IDR_PMENU 213 +#define IDI_POPUP 214 +#define IDI_NOPOPUP 215 +#define IDD_TEXTOPT 216 +#define IDD_BRIEF 217 +#define IDD_SETUP 218 +#define IDR_TMENU 219 +#define IDR_TMMENU 220 +#define IDI_EDIT 222 +#define IDD_INFO 224 +#define IDD_SEARCHCITY 225 +#define IDC_NAME 2000 +#define IDC_ID 2001 +#define IDC_LOG 2003 +#define IDC_UPDATETIME 2005 +#define IDC_CTEXT 2006 +#define IDC_AVATARSIZE 2006 +#define IDC_UPDATE 2007 +#define IDC_BTITLE 2008 +#define IDC_STARTUPUPD 2008 +#define IDC_CHANGE 2009 +#define IDC_BTITLE2 2009 +#define IDC_USEWINCOLORS 2010 +#define IDC_BTEXT 2011 +#define IDC_CH 2013 +#define IDC_NTEXT 2015 +#define IDC_DEGREE 2016 +#define IDC_E 2017 +#define IDC_W 2018 +#define IDC_POP1 2019 +#define IDC_XTEXT 2020 +#define IDC_POP2 2020 +#define IDC_PText 2021 +#define IDC_PTitle 2023 +#define IDC_Internal 2024 +#define IDC_ETEXT 2025 +#define IDC_DISCONDICON 2025 +#define IDC_External 2026 +#define IDC_DONOTAPPUNITS 2026 +#define IDC_DEFA 2027 +#define IDC_NOFRAC 2027 +#define IDC_HTEXT 2028 +#define IDC_DPop 2029 +#define IDC_DAutoUpdate 2030 +#define IDC_IURL 2032 +#define IDC_MURL 2033 +#define IDC_PROTOCOND 2034 +#define IDC_Overwrite 2035 +#define IDC_UPDCONDCHG 2036 +#define IDC_REMOVEOLD 2037 +#define IDC_MAKEI 2039 +#define IDC_BGCOLOUR 2040 +#define IDC_TEXTCOLOUR 2041 +#define IDC_LeftClick 2042 +#define IDC_PREVIEW 2043 +#define IDC_VAR3 2044 +#define IDC_RightClick 2045 +#define IDC_DELAY 2046 +#define IDC_PDEF 2047 +#define IDC_T1 2048 +#define IDC_T2 2049 +#define IDC_W1 2050 +#define IDC_W2 2051 +#define IDC_W3 2052 +#define IDC_W4 2053 +#define IDC_BROWSE 2054 +#define IDC_VIEW1 2055 +#define IDC_RESET1 2056 +#define IDC_VIEW2 2057 +#define IDC_V1 2058 +#define IDC_V2 2059 +#define IDC_RESET2 2060 +#define IDC_SVCINFO 2061 +#define IDC_GETNAME 2062 +#define IDC_P1 2063 +#define IDC_P2 2064 +#define IDC_P3 2065 +#define IDC_P4 2066 +#define IDC_RESET 2067 +#define IDC_D1 2067 +#define IDC_D2 2068 +#define IDC_D3 2069 +#define IDC_INFO1 2069 +#define IDC_INFOICON 2070 +#define IDC_INFO11 2071 +#define IDC_INFO2 2072 +#define IDC_INFO3 2073 +#define IDC_VARLIST 2074 +#define IDC_INFO4 2075 +#define IDC_INFO5 2076 +#define IDC_PD1 2077 +#define IDC_PD2 2078 +#define IDC_PD3 2079 +#define IDC_INFO6 2079 +#define IDC_TM1 2080 +#define IDC_TM2 2081 +#define IDC_TM3 2082 +#define IDC_TM4 2083 +#define IDC_TM5 2084 +#define IDC_TM6 2085 +#define IDC_TM7 2086 +#define IDC_TM8 2087 +#define IDC_INFO7 2087 +#define IDC_TM9 2088 +#define IDC_INFO8 2089 +#define IDC_INFO9 2090 +#define IDC_INFO10 2091 +#define IDC_INFO12 2092 +#define IDC_INFO13 2093 +#define IDC_MORE 2094 +#define IDC_MOREDETAIL 2095 +#define IDC_DATALIST 2096 +#define IDC_MUPDATE 2097 +#define IDC_MFRAME 2099 +#define IDC_MTOGGLE 2101 +#define IDC_MWEBPAGE 2102 +#define IDC_MTEXT 2103 +#define IDC_STEP1 2107 +#define IDC_STEP2 2108 +#define IDC_STEP3 2109 +#define IDC_STEP4 2110 +#define IDC_INFOLIST 2117 +#define IDC_RELOADINI 2118 +#define IDC_MEMUSED 2119 +#define IDC_INICOUNT 2120 +#define IDC_AVATARSPIN 2124 +#define IDC_SEARCHCITY 2125 +#define IDC_HEADERBAR 2126 +#define IDC_E1 2128 +#define IDC_E2 2129 +#define OIC_HAND 32513 +#define OIC_QUES 32514 +#define OIC_BANG 32515 +#define OIC_NOTE 32516 +#define IDM_M1 40002 +#define IDM_M2 40003 +#define IDM_M3 40004 +#define IDM_M4 40005 +#define IDM_M5 40006 +#define IDM_M6 40007 +#define IDM_M7 40008 +#define IDM_M8 40009 +#define ID_T1 40010 +#define ID_T2 40011 +#define ID_MPREVIEW 40020 +#define ID_MRESET 40021 +#define IDC_STATIC -1 + +// Next default values for new objects +// +#ifdef APSTUDIO_INVOKED +#ifndef APSTUDIO_READONLY_SYMBOLS +#define _APS_NO_MFC 1 +#define _APS_NEXT_RESOURCE_VALUE 226 +#define _APS_NEXT_COMMAND_VALUE 40030 +#define _APS_NEXT_CONTROL_VALUE 2128 +#define _APS_NEXT_SYMED_VALUE 101 +#endif +#endif diff --git a/protocols/Weather/src/stdafx.cxx b/protocols/Weather/src/stdafx.cxx new file mode 100644 index 0000000000..1b563fc866 --- /dev/null +++ b/protocols/Weather/src/stdafx.cxx @@ -0,0 +1,18 @@ +/* +Copyright (C) 2012-19 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"
\ No newline at end of file diff --git a/protocols/Weather/src/stdafx.h b/protocols/Weather/src/stdafx.h new file mode 100644 index 0000000000..eee562a9ed --- /dev/null +++ b/protocols/Weather/src/stdafx.h @@ -0,0 +1,547 @@ +/* +Weather Protocol plugin for Miranda NG +Copyright (C) 2012-19 Miranda NG team +Copyright (c) 2005-2011 Boris Krasnovskiy All Rights Reserved +Copyright (c) 2002-2005 Calvin Che + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; version 2 +of the License. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see <http://www.gnu.org/licenses/>. +*/ + +/* This file contains the includes, weather constants/declarations, + the structs, and the primitives for some of the functions. +*/ + +#pragma once + +//============ THE INCLUDES =========== + +#include <share.h> +#include <time.h> +#include <windows.h> +#include <commctrl.h> +#include <richedit.h> +#include <malloc.h> + +#include <newpluginapi.h> +#include <m_icolib.h> +#include <m_options.h> +#include <m_langpack.h> +#include <m_skin.h> +#include <m_database.h> +#include <m_history.h> +#include <m_protosvc.h> +#include <m_userinfo.h> +#include <m_netlib.h> +#include <m_ignore.h> +#include <m_findadd.h> +#include <m_button.h> +#include <m_avatars.h> +#include <m_clc.h> +#include <m_fontservice.h> +#include <m_skin_eng.h> +#include <m_cluiframes.h> +#include <m_popup.h> +#include <win2k.h> +#include <m_acc.h> + +#include <m_weather.h> +#include <m_toptoolbar.h> + +#include "resource.h" +#include "version.h" + +//============ CONSTANTS ============ + +// name +#define MODULENAME "Weather" +#define WEATHERPROTOTEXT "Weather" +#define DEFCURRENTWEATHER "WeatherCondition" +#define WEATHERCONDITION "Current" + +// weather conditions +#define SUNNY ID_STATUS_ONLINE +#define NA ID_STATUS_OFFLINE +#define PCLOUDY ID_STATUS_AWAY +#define CLOUDY ID_STATUS_NA +#define RAIN ID_STATUS_OCCUPIED +#define RSHOWER ID_STATUS_DND +#define SNOW ID_STATUS_FREECHAT +#define LIGHT ID_STATUS_INVISIBLE +#define THUNDER ID_STATUS_INVISIBLE +#define SSHOWER ID_STATUS_ONTHEPHONE +#define FOG ID_STATUS_OUTTOLUNCH +#define UNAVAIL 40081 + +// status +#define NOSTATUSDATA 1 + +// limits +#define MAX_TEXT_SIZE 4096 +#define MAX_DATA_LEN 1024 + +// db info mangement mode +#define WDBM_REMOVE 1 +#define WDBM_DETAILDISPLAY 2 + +// more info list column width +#define LIST_COLUMN 150 + +// others +#define NODATA TranslateT("N/A") +#define UM_SETCONTACT 40000 + +// weather update error codes +#define INVALID_ID_FORMAT 10 +#define INVALID_SVC 11 +#define INVALID_ID 12 +#define SVC_NOT_FOUND 20 +#define NETLIB_ERROR 30 +#define DATA_EMPTY 40 +#define DOC_NOT_FOUND 42 +#define DOC_TOO_SHORT 43 +#define UNKNOWN_ERROR 99 + +// weather update error text +#define E10 TranslateT("Invalid ID format, missing \"/\" (10)") +#define E11 TranslateT("Invalid service (11)") +#define E12 TranslateT("Invalid station (12)") +#define E20 TranslateT("Weather service ini for this station is not found (20)") +#define E30 TranslateT("Netlib error - check your internet connection (30)") +#define E40 TranslateT("Empty data is retrieved (40)") +#define E42 TranslateT("Document not found (42)") +#define E43 TranslateT("Document too short to contain any weather data (43)") +#define E99 TranslateT("Unknown error (99)") + +// HTTP error... not all translated +// 100 Continue +// 101 Switching Protocols +// 200 OK +// 201 Created +// 202 Accepted +// 203 Non-Authoritative Information +#define E204 TranslateT("HTTP Error: No content (204)") +// 205 Reset Content +// 206 Partial Content +// 300 Multiple Choices +#define E301 TranslateT("HTTP Error: Data moved (301)") +// 302 Found +// 303 See Other +// 304 Not Modified +#define E305 TranslateT("HTTP Error: Use proxy (305)") +// 306 (Unused) +#define E307 TranslateT("HTTP Error: Temporary redirect (307)") +#define E400 TranslateT("HTTP Error: Bad request (400)") +#define E401 TranslateT("HTTP Error: Unauthorized (401)") +#define E402 TranslateT("HTTP Error: Payment required (402)") +#define E403 TranslateT("HTTP Error: Forbidden (403)") +#define E404 TranslateT("HTTP Error: Not found (404)") +#define E405 TranslateT("HTTP Error: Method not allowed (405)") +// 406 Not Acceptable +#define E407 TranslateT("HTTP Error: Proxy authentication required (407)") +// 408 Request Timeout +// 409 Conflict +#define E410 TranslateT("HTTP Error: Gone (410)") +// 411 Length Required +// 412 Precondition Failed +// 413 Request Entity Too Large +// 414 Request-URI Too Long +// 415 Unsupported Media Type +// 416 Requested Range Not Satisfiable +// 417 Expectation Failed +#define E500 TranslateT("HTTP Error: Internal server error (500)") +// 501 Not Implemented +#define E502 TranslateT("HTTP Error: Bad gateway (502)") +#define E503 TranslateT("HTTP Error: Service unavailable (503)") +#define E504 TranslateT("HTTP Error: Gateway timeout (504)") +// 505 HTTP Version Not Supported + +// defaults constants +#define C_DEFAULT L"%n [%t, %c]" +#define N_DEFAULT TranslateT("%c\\nTemperature: %t\\nFeel-Like: %f\\nPressure: %p\\nWind: %i %w\\nHumidity: %m\\nDew Point: %e\\nVisibility: %v\\n\\nSun Rise: %r\\nSun Set: %y\\n\\n5 Days Forecast:\\n%[Forecast Day 1]\\n%[Forecast Day 2]\\n%[Forecast Day 3]\\n%[Forecast Day 4]\\n%[Forecast Day 5]") +#define B_DEFAULT TranslateT("Feel-Like: %f\\nPressure: %p\\nWind: %i %w\\nHumidity: %m\\nDew Point: %e\\nVisibility: %v\\n\\nSun Rise: %r\\nSun Set: %y\\n\\n5 Days Forecast:\\n%[Forecast Day 1]\\n%[Forecast Day 2]\\n%[Forecast Day 3]\\n%[Forecast Day 4]\\n%[Forecast Day 5]") +#define b_DEFAULT TranslateT("Weather Condition for %n as of %u") +#define X_DEFAULT N_DEFAULT +#define H_DEFAULT TranslateT("%c, %t (feel-like %f) Wind: %i %w Humidity: %m") +#define E_DEFAULT TranslateT("%n at %u: %c, %t (feel-like %f) Wind: %i %w Humidity: %m") +#define P_DEFAULT TranslateT("%n (%u)") +#define p_DEFAULT TranslateT("%c, %t\\nToday: High %h, Low %l") +#define s_DEFAULT TranslateT("Temperature: %[Temperature]") +#define VAR_LIST_POPUP 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") +#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") +#define WEATHER_NO_INFO TranslateT("No information available.\r\nPlease update weather condition first.") +#define CUSTOM_VARS TranslateT("%[..]\tcustom variables") +#define VARS_LIST TranslateT("Here is a list of custom variables that are currently available") +#define NO_FORECAST_URL TranslateT("The URL for complete forecast has not been set. You can set it from the Edit Settings dialog.") +#define NO_MAP_URL TranslateT("The URL for weather map has not been set. You can set it from the Edit Settings dialog.") + +//============ OPTION STRUCT ============ + +// option struct +struct MYOPTIONS +{ + // main options + BYTE AutoUpdate; + BYTE CAutoUpdate; + BYTE StartupUpdate; + BYTE NoProtoCondition; + BYTE UpdateOnlyConditionChanged; + BYTE RemoveOldData; + BYTE MakeItalic; + + WORD UpdateTime; + WORD AvatarSize; + + // units + WORD tUnit; + WORD wUnit; + WORD vUnit; + WORD pUnit; + WORD dUnit; + WORD eUnit; + wchar_t DegreeSign[4]; + BYTE DoNotAppendUnit; + BYTE NoFrac; + + // texts + wchar_t *cText; + wchar_t *bTitle; + wchar_t *bText; + wchar_t *nText; + wchar_t *eText; + wchar_t *hText; + wchar_t *xText; + wchar_t *sText; + + // advanced + BYTE DisCondIcon; + + // popup options + BYTE UsePopup; + BYTE UpdatePopup; + BYTE AlertPopup; + BYTE PopupOnChange; + BYTE ShowWarnings; + + // popup colors + BYTE UseWinColors; + COLORREF BGColour; + COLORREF TextColour; + + // popup actions + DWORD LeftClickAction; + DWORD RightClickAction; + + // popup delay + DWORD pDelay; + + // popup texts + wchar_t *pTitle; + wchar_t *pText; + + // other misc stuff + wchar_t Default[64]; + MCONTACT DefStn; +}; + +void DestroyOptions(void); + +//============ 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 + +typedef struct { + wchar_t *Name; + wchar_t *Start; + wchar_t *End; + wchar_t *Unit; + char *Url; + wchar_t *Break; + int Type; +} WIDATAITEM; + +struct WITEMLIST { + WIDATAITEM Item; + struct WITEMLIST *Next; +}; + +typedef struct WITEMLIST WIDATAITEMLIST; + +typedef struct { + BOOL Available; + char *SearchURL; + wchar_t *NotFoundStr; + WIDATAITEM Name; +} WIIDSEARCH; + +typedef struct { + BOOL Available; + wchar_t *First; + WIDATAITEM Name; + WIDATAITEM ID; +} WINAMESEARCHTYPE; + +typedef struct { + char *SearchURL; + wchar_t *NotFoundStr; + wchar_t *SingleStr; + WINAMESEARCHTYPE Single; + WINAMESEARCHTYPE Multiple; +} WINAMESEARCH; + +struct STRLIST { + wchar_t *Item; + struct STRLIST *Next; +}; + +typedef struct STRLIST WICONDITEM; + +typedef struct { + WICONDITEM *Head; + WICONDITEM *Tail; +} WICONDLIST; + +typedef struct { + 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[10]; +} WIDATA; + +//============ 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 MWindowList hDataWindowList, hWindowList; + +extern HNETLIBUSER hNetlibUser; +extern HANDLE hHookWeatherUpdated, hHookWeatherError, hTBButton, hUpdateMutex; +extern UINT_PTR timerId; + +extern HGENMENU hMwinMenu; + +// check if weather is currently updating +extern BOOL ThreadRunning; + +//============ 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); + +WORD GetIcon(const wchar_t* cond, WIDATA *Data); +void CaseConv(wchar_t *str); +void TrimString(char *str); +void TrimString(WCHAR *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); + +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 **Data, const char *Value); +void wSetData(WCHAR **Data, const WCHAR *Value); +void wfree(char **Data); +void wfree(WCHAR **Data); + +void DBDataManage(MCONTACT hContact, WORD 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); + +void MoreVarList(); + +// functions in weather_opt.c +void SetTextDefault(const char* in); +void LoadOptions(); +void SaveOptions(); + +int OptInit(WPARAM wParam,LPARAM lParam); + + +// functions in weather_popup.c +int WeatherPopup(WPARAM wParam, LPARAM lParam); +int WeatherError(WPARAM wParam, LPARAM lParam); +int WPShowMessage(wchar_t* lpzText, WORD 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); + +// 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); +INT_PTR CALLBACK DlgProcINIPage(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam); + +#define WM_UPDATEDATA WM_USER + 2687 + +int BriefInfo(WPARAM wParam, LPARAM lParam); +INT_PTR BriefInfoSvc(WPARAM wParam, LPARAM lParam); + +void InitIcons(void); +HICON LoadIconEx(const char* name, bool big); +HANDLE GetIconHandle(const char* name); +void ReleaseIconEx(HICON hIcon); + +//============ Plugin Class ============ + +struct CMPlugin : public PLUGIN<CMPlugin> +{ + CMPlugin(); + + int Load() override; + int Unload() override; +}; + diff --git a/protocols/Weather/src/version.h b/protocols/Weather/src/version.h new file mode 100644 index 0000000000..d777fe40f9 --- /dev/null +++ b/protocols/Weather/src/version.h @@ -0,0 +1,13 @@ +#define __MAJOR_VERSION 0 +#define __MINOR_VERSION 4 +#define __RELEASE_NUM 0 +#define __BUILD_NUM 4 + +#include <stdver.h> + +#define __PLUGIN_NAME "Weather" +#define __FILENAME "Weather.dll" +#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-19 Miranda NG team" diff --git a/protocols/Weather/src/weather.cpp b/protocols/Weather/src/weather.cpp new file mode 100644 index 0000000000..742f860967 --- /dev/null +++ b/protocols/Weather/src/weather.cpp @@ -0,0 +1,231 @@ +/* +Weather Protocol plugin for Miranda IM +Copyright (c) 2012 Miranda NG team +Copyright (c) 2005-2011 Boris Krasnovskiy All Rights Reserved +Copyright (c) 2002-2005 Calvin Che + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; version 2 +of the License. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see <http://www.gnu.org/licenses/>. +*/ + +/* +Main file for the Weather Protocol, includes loading, unloading, +upgrading, support for plugin uninsaller, and anything that doesn't +belong to any other file. +*/ + +#include "stdafx.h" + +//============ 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; + +CMPlugin g_plugin; + +MYOPTIONS opt; + +// check if weather is currently updating +BOOL ThreadRunning; + +// variable to determine if module loaded +BOOL ModuleLoaded; + +HANDLE hTBButton = nullptr; + +///////////////////////////////////////////////////////////////////////////////////////// +// plugin info + +static const PLUGININFOEX pluginInfoEx = +{ + sizeof(PLUGININFOEX), + __PLUGIN_NAME, + PLUGIN_MAKE_VERSION(__MAJOR_VERSION, __MINOR_VERSION, __RELEASE_NUM, __BUILD_NUM), + __DESCRIPTION, + __AUTHOR, + __COPYRIGHT, + __AUTHORWEB, + UNICODE_AWARE, + // {6B612A34-DCF2-4E32-85CF-B6FD006B745E} + {0x6b612a34, 0xdcf2, 0x4e32, {0x85, 0xcf, 0xb6, 0xfd, 0x0, 0x6b, 0x74, 0x5e}} +}; + +CMPlugin::CMPlugin() : + PLUGIN<CMPlugin>(MODULENAME, pluginInfoEx) +{ + opt.NoProtoCondition = g_plugin.getByte("NoStatus", true); + RegisterProtocol((opt.NoProtoCondition) ? PROTOTYPE_VIRTUAL : PROTOTYPE_PROTOCOL); + SetUniqueId("ID"); +} + +///////////////////////////////////////////////////////////////////////////////////////// + +extern "C" __declspec(dllexport) const MUUID MirandaInterfaces[] = { MIID_PROTOCOL, MIID_LAST }; + +///////////////////////////////////////////////////////////////////////////////////////// + +int WeatherShutdown(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 = GetIconHandle("main"); + ttb.hIconHandleDn = GetIconHandle("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; +} + +//============ MISC FUNCTIONS ============ + +// initialize the global variables at startup +void InitVar() +{ + // setup the linklist for weather update list + UpdateListTail = nullptr; + UpdateListHead = nullptr; + + // other settings + timerId = 0; + opt.DefStn = NULL; + ModuleLoaded = FALSE; +} + +int CMPlugin::Load() +{ + // initialize global variables + InitVar(); + + // load options and set defaults + LoadOptions(); + + InitIcons(); + + // 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); + + hDataWindowList = WindowList_Create(); + hWindowList = WindowList_Create(); + + hUpdateMutex = CreateMutex(nullptr, FALSE, nullptr); + + // initialize weather protocol services + InitServices(); + + // add sound event + g_plugin.addSound("weatherupdated", _A2W(MODULENAME), LPGENW("Condition Changed")); + g_plugin.addSound("weatheralert", _A2W(MODULENAME), LPGENW("Alert Issued")); + + // 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, + CW_USEDEFAULT, CW_USEDEFAULT, HWND_DESKTOP, nullptr, g_plugin.getInst(), nullptr); + SetWindowLongPtr(hPopupWindow, GWLP_WNDPROC, (LONG_PTR)PopupWndProc); + return 0; +} + +///////////////////////////////////////////////////////////////////////////////////////// +// unload function + +int CMPlugin::Unload() +{ + DestroyMwin(); + DestroyWindow(hPopupWindow); + + DestroyHookableEvent(hHookWeatherUpdated); + DestroyHookableEvent(hHookWeatherError); + + Netlib_CloseHandle(hNetlibUser); + + DestroyUpdateList(); + DestroyOptions(); + 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 new file mode 100644 index 0000000000..ca7a8ae6e3 --- /dev/null +++ b/protocols/Weather/src/weather_addstn.cpp @@ -0,0 +1,432 @@ +/* +Weather Protocol plugin for Miranda IM +Copyright (c) 2012 Miranda NG team +Copyright (c) 2005-2011 Boris Krasnovskiy All Rights Reserved +Copyright (c) 2002-2005 Calvin Che + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; version 2 +of the License. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see <http://www.gnu.org/licenses/>. +*/ + +/* This file contain the source related to search and add a weather station +to the contact list. Contain code for both name and ID search. +*/ + +#include "stdafx.h" + +// variables used for weather_addstn.c +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) +{ + PROTOSEARCHRESULT *psr = (PROTOSEARCHRESULT*)lParam; + if (!psr || !psr->email.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 (db_get_b(hContact, "CList", "NotOnList", 1)) { + db_unset(hContact, "CList", "NotOnList"); + db_unset(hContact, "CList", "Hidden"); + } + db_free(&dbv); + // contact is added, function quitting + return (INT_PTR)hContact; + } + db_free(&dbv); + } + } + } + + // if contact with the same ID was not found, add it + if (psr->cbSize < sizeof(PROTOSEARCHRESULT)) return 0; + MCONTACT hContact = db_add_contact(); + Proto_AddToContact(hContact, MODULENAME); + // suppress online notification for the new contact + CallService(MS_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); + + AvatarDownloaded(hContact); + + wchar_t str[256]; + mir_snwprintf(str, TranslateT("Current weather information for %s."), psr->nick.w); + g_plugin.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"); + + // 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)); + + opt.DefStn = hContact; + if (!g_plugin.getWString(hContact, "Nick", &dbv)) { + // notification message box + 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); + } + g_plugin.setWString("Default", opt.Default); + } + // display the Edit Settings dialog box + EditSettings(hContact, 0); + return (INT_PTR)hContact; +} + +// ============ WARNING DIALOG ============ + +// show a message box and cancel search if update is in process +BOOL CheckSearch() +{ + if (UpdateListHead != nullptr) { + MessageBox(nullptr, TranslateT("Please try again after weather update is completed."), TranslateT("Weather Protocol"), MB_OK | MB_ICONERROR); + return FALSE; + } + return TRUE; +} + +// ============ BASIC ID SEARCH ============ + +static wchar_t sttSID[32]; + +// A timer process for the ID search (threaded) +static void __cdecl BasicSearchTimerProc(LPVOID) +{ + int result; + // search only when it's not current updating weather. + if (CheckSearch()) + result = IDSearch(sttSID, sttSearchId); + + // broadcast the search result + ProtoBroadcastAck(MODULENAME, 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) +{ + if (sttSearchId != -1) return 0; //only one search at a time + wcsncpy(sttSID, (wchar_t*)lParam, _countof(sttSID)); + sttSID[_countof(sttSID) - 1] = 0; + sttSearchId = 1; + // create a thread for the ID search + mir_forkthread(BasicSearchTimerProc); + return 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) +{ + switch (msg) { + case WM_INITDIALOG: + TranslateDialogDefault(hwndDlg); + SetFocus(GetDlgItem(hwndDlg, IDC_SEARCHCITY)); + return TRUE; + + case WM_COMMAND: + if (HIWORD(wParam) == EN_SETFOCUS) + PostMessage(GetParent(hwndDlg), WM_COMMAND, MAKEWPARAM(0, EN_SETFOCUS), (LPARAM)hwndDlg); + } + return FALSE; +} + +INT_PTR WeatherCreateAdvancedSearchUI(WPARAM, LPARAM lParam) +{ + HWND parent = (HWND)lParam; + if (parent) + return (INT_PTR)CreateDialogParam(g_plugin.getInst(), MAKEINTRESOURCE(IDD_SEARCHCITY), parent, WeatherSearchAdvancedDlgProc, 0); + + return 0; +} + +// service function for name search +INT_PTR WeatherAdvancedSearch(WPARAM, LPARAM lParam) +{ + if (sttSearchId != -1) return 0; //only one search at a time + + sttSearchId = 1; + GetDlgItemText((HWND)lParam, IDC_SEARCHCITY, name1, _countof(name1)); + + // search for the weather station using a thread + mir_forkthread(NameSearchTimerProc); + return sttSearchId; +} + +// ============ 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) +{ + 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, sID); + 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); + + // 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); + + return 0; +} + +// 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) +{ + // 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 "#" + PROTOSEARCHRESULT psr = { sizeof(psr) }; + psr.flags = PSR_UNICODE; + psr.nick.w = TranslateT("<Enter station name here>"); // to be entered + psr.firstName.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; + } + + return 0; +} + +// ======================MENU ITEM FUNCTION ============ + +// add a new weather station via find/add dialog +int WeatherAdd(WPARAM, LPARAM) +{ + db_set_s(0, "FindAdd", "LastSearched", "Weather"); + CallService(MS_FINDADD_FINDADD, 0, 0); + return 0; +} diff --git a/protocols/Weather/src/weather_contacts.cpp b/protocols/Weather/src/weather_contacts.cpp new file mode 100644 index 0000000000..f572b29564 --- /dev/null +++ b/protocols/Weather/src/weather_contacts.cpp @@ -0,0 +1,480 @@ +/* +Weather Protocol plugin for Miranda IM +Copyright (c) 2012 Miranda NG team +Copyright (c) 2005-2011 Boris Krasnovskiy All Rights Reserved +Copyright (c) 2002-2005 Calvin Che + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; version 2 +of the License. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see <http://www.gnu.org/licenses/>. +*/ + +/* This file contain the source that is related to weather contacts, +include the links, edit settings, and loading weather information for +the contact. +*/ + +#include "stdafx.h" + +static void OpenUrl(wchar_t* format, wchar_t* id) +{ + wchar_t loc[512]; + GetID(id); + mir_snwprintf(loc, format, id); + Utils_OpenUrlW(loc); +} + +//============ BASIC CONTACTS FUNCTIONS AND LINKS ============ + +// view weather log for the contact +// wParam = current contact +INT_PTR ViewLog(WPARAM wParam, LPARAM lParam) +{ + // see if the log path is set + DBVARIANT dbv; + if (!g_plugin.getWString(wParam, "Log", &dbv)) { + if (dbv.pszVal[0] != 0) + ShellExecute((HWND)lParam, L"open", dbv.pwszVal, L"", L"", SW_SHOW); + db_free(&dbv); + } + else // display warning dialog if no path is specified + MessageBox(nullptr, TranslateT("Weather condition was not logged."), + TranslateT("Weather Protocol"), MB_OK | MB_ICONINFORMATION); + return 0; +} + +// read complete forecast +// wParam = current contact +INT_PTR LoadForecast(WPARAM wParam, LPARAM) +{ + 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, NO_FORECAST_URL, TranslateT("Weather Protocol"), MB_ICONINFORMATION); + return 1; + } + // set the url and open the webpage + OpenUrl(loc2, id); + } + return 0; +} + +// load weather map +// wParam = current contact +INT_PTR WeatherMap(WPARAM wParam, LPARAM) +{ + 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, NO_MAP_URL, TranslateT("Weather Protocol"), MB_ICONINFORMATION); + return 1; + } + + // set the url and open the webpage + OpenUrl(loc2, id); + } + + 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) +{ + DBVARIANT dbv; + wchar_t str[MAX_DATA_LEN], str2[256], city[256], filter[256], *pfilter, *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); + + // 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); + + // save the handle for the contact + WindowList_Add(hWindowList, hwndDlg, hContact); + + // start to get the settings + // if the setting not exist, leave the dialog box blank + if (!g_plugin.getWString(hContact, "ID", &dbv)) { + SetDlgItemText(hwndDlg, 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); + db_free(&dbv); + } + if (!g_plugin.getWString(hContact, "Nick", &dbv)) { + SetDlgItemText(hwndDlg, IDC_NAME, dbv.pwszVal); + db_free(&dbv); + } + if (!g_plugin.getWString(hContact, "Log", &dbv)) { + SetDlgItemText(hwndDlg, 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); + db_free(&dbv); + } + // enable/disable the browse button depending on the value of external log checkbox + EnableWindow(GetDlgItem(hwndDlg, IDC_BROWSE), (BYTE)IsDlgButtonChecked(hwndDlg, IDC_External)); + + // other checkbox options + CheckDlgButton(hwndDlg, IDC_DPop, 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); + } + + // 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 = wcsstr(str, L"/"); + 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); + } + + // give no station name but only ID if the search is unavailable + if (str[0] != 0) + SetDlgItemText(hwndDlg, IDC_NAME, str); + break; + + case IDC_External: + // enable/disable the borwse button depending if the external log is enabled + EnableWindow(GetDlgItem(hwndDlg, IDC_BROWSE), (BYTE)IsDlgButtonChecked(hwndDlg, IDC_External)); + if (!(BYTE)IsDlgButtonChecked(hwndDlg, IDC_External)) + return TRUE; + __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 + wcsncpy(filter, TranslateT("Text Files"), _countof(filter) - 1); + mir_wstrncat(filter, L" (*.txt)", _countof(filter) - mir_wstrlen(filter)); + pfilter = filter + mir_wstrlen(filter) + 1; + wcsncpy(pfilter, L"*.txt", _countof(filter) - 1); + pfilter = pfilter + mir_wstrlen(pfilter) + 1; + wcsncpy(pfilter, TranslateT("All Files"), _countof(filter) - 1); + mir_wstrncat(pfilter, L" (*.*)", _countof(filter) - mir_wstrlen(filter)); + pfilter = pfilter + mir_wstrlen(pfilter) + 1; + wcsncpy(pfilter, L"*.*", _countof(filter) - 1); + pfilter = pfilter + mir_wstrlen(pfilter) + 1; + *pfilter = '\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 ((BYTE)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 ((BYTE)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", ID_STATUS_OFFLINE); + AvatarDownloaded(hContact); + g_plugin.setWString(hContact, "About", str2); + g_plugin.setByte(hContact, "History", (BYTE)IsDlgButtonChecked(hwndDlg, IDC_Internal)); + g_plugin.setByte(hContact, "Overwrite", (BYTE)IsDlgButtonChecked(hwndDlg, IDC_Overwrite)); + g_plugin.setByte(hContact, "File", (BYTE)IsDlgButtonChecked(hwndDlg, IDC_External)); + g_plugin.setByte(hContact, "DPopUp", (BYTE)IsDlgButtonChecked(hwndDlg, IDC_DPop)); + g_plugin.setByte(hContact, "DAutoUpdate", (BYTE)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; + } + 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; + } + return FALSE; +} + +// show edit settings dialog +// wParam = current contact +INT_PTR EditSettings(WPARAM wParam, LPARAM) +{ + HWND hEditDlg = WindowList_Find(hWindowList, wParam); + + // search the dialog list to prevent multiple instance of dialog for the same contact + if (hEditDlg != nullptr) { + // if the dialog box already opened, bring it to the front + SetForegroundWindow(hEditDlg); + SetFocus(hEditDlg); + } + else { + // if the dialog box is not opened, open a new one + if (IsMyContact(wParam)) + CreateDialogParam(g_plugin.getInst(), MAKEINTRESOURCE(IDD_EDIT), nullptr, DlgProcChange, (LPARAM)wParam); + } + + 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); + + // 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; + + // 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"); + if (tszID == NULL) + continue; + + // if the station is not a default station, set it as the new default station + // this is the first weather station encountered from the search + if (mir_wstrcmp(opt.Default, tszID)) { + wcsncpy_s(opt.Default, tszID, _TRUNCATE); + opt.DefStn = hContact; + ptrW tszNick(g_plugin.getWStringA(hContact, "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 + } + } + + // 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 = GetContactProto(hContact); + return szProto != nullptr && mir_strcmp(MODULENAME, szProto) == 0; +} diff --git a/protocols/Weather/src/weather_conv.cpp b/protocols/Weather/src/weather_conv.cpp new file mode 100644 index 0000000000..c46b079531 --- /dev/null +++ b/protocols/Weather/src/weather_conv.cpp @@ -0,0 +1,637 @@ +/* +Weather Protocol plugin for Miranda IM +Copyright (c) 2012 Miranda NG team +Copyright (c) 2005-2011 Boris Krasnovskiy All Rights Reserved +Copyright (c) 2002-2005 Calvin Che + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; version 2 +of the License. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see <http://www.gnu.org/licenses/>. +*/ + +/* +This file contain the source related unit conversion, icon assignment, +string conversions, display text parsing, etc +*/ + +#include "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 tag = FALSE; + // looking character by character + // for a number: numerous spaces in front, then optional +/-, then the number + // don't care anything that comes after it + while (*s != '\0') { + if (*s >= '0' && *s <= '9') return TRUE; + else if (*s == ' '); + else if (*s != '+' && *s != '-') return FALSE; + else if ((*s == '+' || *s == '-') && !tag) tag = TRUE; + else return FALSE; + s++; + } + return FALSE; +} + +static void numToStr(double num, wchar_t *str, size_t strSize) +{ + int i = (int)(num * (opt.NoFrac ? 10 : 100)); + int u = abs(i); + + int r = u % 10; + int w = u / 10 + (r >= 5); + + if (opt.NoFrac) + r = 0; + else { + r = w % 10; + w /= 10; + } + + if (i < 0 && (w || r)) w = -w; + if (r) + mir_snwprintf(str, strSize, L"%i.%i", w, r); + else + 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) +{ + // 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); + return; + } + if (!is_number(tempchar)) { + mir_wstrcpy(str, NODATA); + return; + } + + // convert the string to an integer + temp = _wtof(tempchar); + + // convert all to F first + if (!mir_wstrcmpi(unit, L"C")) temp = (temp * 9 / 5) + 32; + else if (!mir_wstrcmpi(unit, L"K")) temp = ((temp - 273.15) * 9 / 5) + 32; + + // convert to apporiate unit + switch (opt.tUnit) { + case 1: + // rounding + numToStr((temp - 32) / 9 * 5, tstr, _countof(tstr)); + if (opt.DoNotAppendUnit) + wcsncpy_s(str, MAX_DATA_LEN, tstr, _TRUNCATE); + else + mir_snwprintf(str, MAX_DATA_LEN, L"%s%sC", tstr, opt.DegreeSign); + break; + + case 2: + numToStr(temp, tstr, _countof(tstr)); + if (opt.DoNotAppendUnit) + wcsncpy_s(str, MAX_DATA_LEN, tstr, _TRUNCATE); + else + mir_snwprintf(str, MAX_DATA_LEN, L"%s%sF", tstr, opt.DegreeSign); + break; + } +} + +// temperature conversion +// tempchar = the string containing the pressure value +// unit = the unit for pressure +// return value = the converted pressure with unit; if fail, return the original string +void GetPressure(wchar_t *tempchar, wchar_t *unit, wchar_t* str) +{ + // unit can be kPa, hPa, mb, in, mm, torr + double tempunit = 0, output; + int intunit; + + // convert the string to a floating point number (always positive) + // if it end up with 0, then it's not a number, return the original string and quit + output = _wtof(tempchar); + if (output == 0) { + mir_wstrcpy(str, tempchar); + return; + } + + // convert all to mb first + if (!mir_wstrcmpi(unit, L"KPA")) + tempunit = (double)output * 10; + else if (!mir_wstrcmpi(unit, L"HPA")) + tempunit = (double)output; + else if (!mir_wstrcmpi(unit, L"MB")) + tempunit = (double)output; + else if (!mir_wstrcmpi(unit, L"IN")) + tempunit = (double)output * 33.86388; + else if (!mir_wstrcmpi(unit, L"MM")) + tempunit = (double)output * 1.33322; + else if (!mir_wstrcmpi(unit, L"TORR")) + tempunit = (double)output * 1.33322; + + // convert to apporiate unit + switch (opt.pUnit) { + case 1: + intunit = (int)(tempunit + 0.5); + mir_snwprintf(str, MAX_DATA_LEN, L"%i.%i %s", intunit / 10, intunit % 10, opt.DoNotAppendUnit ? L"" : TranslateT("kPa")); + break; + case 2: + intunit = (int)(tempunit + 0.5); + mir_snwprintf(str, MAX_DATA_LEN, L"%i %s", intunit, opt.DoNotAppendUnit ? L"" : TranslateT("mb")); + break; + case 3: + intunit = (int)((tempunit * 10 / 33.86388) + 0.5); + mir_snwprintf(str, MAX_DATA_LEN, L"%i.%i %s", intunit / 10, intunit % 10, opt.DoNotAppendUnit ? L"" : TranslateT("in")); + break; + case 4: + intunit = (int)((tempunit * 10 / 1.33322) + 0.5); + mir_snwprintf(str, MAX_DATA_LEN, L"%i.%i %s", intunit / 10, intunit % 10, opt.DoNotAppendUnit ? L"" : TranslateT("mm")); + break; + default: + mir_wstrcpy(str, tempchar); + break; + + } +} + +// speed conversion +// tempchar = the string containing the speed value +// unit = the unit for speed +// return value = the converted speed with unit; if fail, return _T("" +void GetSpeed(wchar_t *tempchar, wchar_t *unit, wchar_t *str) +{ + // unit can be km/h, mph, m/s, knots + double tempunit; + wchar_t tstr[20]; + + str[0] = 0; + + // convert the string into an integer (always positive) + // if the result is 0, then the string is not a number, return _T("" + tempunit = _wtof(tempchar); + if (tempunit == 0 && tempchar[0] != '0') + return; + + // convert all to m/s first + if (!mir_wstrcmpi(unit, L"KM/H")) + tempunit /= 3.6; + // else if ( !mir_wstrcmpi(unit, L"M/S") + // tempunit = tempunit; + else if (!mir_wstrcmpi(unit, L"MPH")) + tempunit *= 0.44704; + else if (!mir_wstrcmpi(unit, L"KNOTS")) + tempunit *= 0.514444; + + // convert to apporiate unit + switch (opt.wUnit) { + case 1: + numToStr(tempunit * 3.6, tstr, _countof(tstr)); + mir_snwprintf(str, MAX_DATA_LEN, L"%s %s", tstr, opt.DoNotAppendUnit ? L"" : TranslateT("km/h")); + break; + case 2: + numToStr(tempunit, tstr, _countof(tstr)); + mir_snwprintf(str, MAX_DATA_LEN, L"%s %s", tstr, opt.DoNotAppendUnit ? L"" : TranslateT("m/s")); + break; + case 3: + numToStr(tempunit / 0.44704, tstr, _countof(tstr)); + mir_snwprintf(str, MAX_DATA_LEN, L"%s %s", tstr, opt.DoNotAppendUnit ? L"" : TranslateT("mph")); + break; + case 4: + numToStr(tempunit / 0.514444, tstr, _countof(tstr)); + mir_snwprintf(str, MAX_DATA_LEN, L"%s %s", tstr, opt.DoNotAppendUnit ? L"" : TranslateT("knots")); + break; + } +} + +// distance conversion +// tempchar = the string containing the distance value +// unit = the unit for distance +// return value = the converted distance with unit; if fail, return original string +void GetDist(wchar_t *tempchar, wchar_t *unit, wchar_t *str) +{ + // unit can be km, miles + double tempunit = 0, output; + int intunit; + + // convert the string to a floating point number (always positive) + // if it end up with 0, then it's not a number, return the original string and quit + output = _wtof(tempchar); + if (output == 0) { + mir_wstrcpy(str, tempchar); + return; + } + + // convert all to km first + if (!mir_wstrcmpi(unit, L"KM")) + tempunit = (double)output; + else if (!mir_wstrcmpi(unit, L"MILES")) + tempunit = (double)output * 1.609; + + // convert to apporiate unit + switch (opt.vUnit) { + case 1: + intunit = (int)((tempunit * 10) + 0.5); + mir_snwprintf(str, MAX_DATA_LEN, L"%i.%i %s", intunit / 10, intunit % 10, opt.DoNotAppendUnit ? L"" : TranslateT("km")); + break; + case 2: + intunit = (int)((tempunit * 10 / 1.609) + 0.5); + mir_snwprintf(str, MAX_DATA_LEN, L"%i.%i %s", intunit / 10, intunit % 10, opt.DoNotAppendUnit ? L"" : TranslateT("miles")); + break; + default: + mir_wstrcpy(str, tempchar); + break; + } +} + +// elevation conversion +// tempchar = the string containing the elevation value +// unit = the unit for elevation +// return value = the converted elevation with unit; if fail, return original string +void GetElev(wchar_t *tempchar, wchar_t *unit, wchar_t *str) +{ + // unit can be ft, m + double tempunit = 0, output; + int intunit; + + // convert the string to a floating point number (always positive) + // if it end up with 0, then it's not a number, return the original string and quit + output = _wtof(tempchar); + if (output == 0) { + mir_wstrcpy(str, tempchar); + return; + } + + // convert all to m first + if (!mir_wstrcmpi(unit, L"M")) + tempunit = (double)output; + else if (!mir_wstrcmpi(unit, L"FT")) + tempunit = (double)output / 3.28; + + // convert to apporiate unit + switch (opt.eUnit) { + case 1: + intunit = (int)((tempunit * 10 * 3.28) + 0.5); + mir_snwprintf(str, MAX_DATA_LEN, L"%i.%i %s", intunit / 10, intunit % 10, opt.DoNotAppendUnit ? L"" : TranslateT("ft")); + break; + case 2: + intunit = (int)((tempunit * 10) + 0.5); + mir_snwprintf(str, MAX_DATA_LEN, L"%i.%i %s", intunit / 10, intunit % 10, opt.DoNotAppendUnit ? L"" : TranslateT("m")); + break; + default: + mir_wstrcpy(str, tempchar); + break; + } +} + +//============ CONDITION ICON ASSIGNMENT ============ + +// assign the contact icon (status) from the condition string +// the description may be different between different sources +// cond = the string for weather condition +// return value = status for the icon (ONLINE, OFFLINE, etc) + +static const wchar_t *statusStr[10] = { L"Lightning", L"Fog", L"Snow Shower", L"Snow", L"Rain Shower", L"Rain", L"Partly Cloudy", L"Cloudy", L"Sunny", L"N/A" }; +static const WORD statusValue[10] = { LIGHT, FOG, SSHOWER, SNOW, RSHOWER, RAIN, PCLOUDY, CLOUDY, SUNNY, NA }; + +WORD GetIcon(const wchar_t* cond, WIDATA *Data) +{ + // set the icon using ini + for (int i = 0; i < 10; i++) + if (IsContainedInCondList(cond, &Data->CondList[i])) + return statusValue[i]; + + // internal detection + if ( + wcsstr(cond, L"mainy sunny") != nullptr || + wcsstr(cond, L"mainy clear") != nullptr || + wcsstr(cond, L"partly cloudy") != nullptr || + wcsstr(cond, L"mostly") != nullptr || + wcsstr(cond, L"clouds") != nullptr) { + return PCLOUDY; + } + else if ( + wcsstr(cond, L"sunny") != nullptr || + wcsstr(cond, L"clear") != nullptr || + wcsstr(cond, L"fair") != nullptr) { + return SUNNY; + } + else if ( + wcsstr(cond, L"thunder") != nullptr || + wcsstr(cond, L"t-storm") != nullptr) { + return LIGHT; + } + else if ( + wcsstr(cond, L"cloud") != nullptr || + wcsstr(cond, L"overcast") != nullptr) { + return CLOUDY; + } + else if ( + wcsstr(cond, L"fog") != nullptr || + wcsstr(cond, L"mist") != nullptr || + wcsstr(cond, L"smoke") != nullptr || + wcsstr(cond, L"sand") != nullptr || + wcsstr(cond, L"dust") != nullptr || + wcsstr(cond, L"haze") != nullptr) { + return FOG; + } + else if ( + (wcsstr(cond, L"shower") != nullptr && wcsstr(cond, L"snow") != nullptr) || + wcsstr(cond, L"flurries") != nullptr) { + return SSHOWER; + } + else if ( + wcsstr(cond, L"rain shower") != nullptr || + wcsstr(cond, L"shower") != nullptr) { + return RSHOWER; + } + else if ( + wcsstr(cond, L"snow") != nullptr || + wcsstr(cond, L"ice") != nullptr || + wcsstr(cond, L"freezing") != nullptr || + wcsstr(cond, L"wintry") != nullptr) { + return SNOW; + } + else if ( + wcsstr(cond, L"drizzle") != nullptr || + wcsstr(cond, L"rain") != nullptr) { + return RAIN; + } + + // set the icon using langpack + for (int i = 0; i < 9; 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, (DWORD)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; + + CharLowerBuffW(str, (DWORD)mir_wstrlen(str)); + for (wchar_t *pstr = str; *pstr; pstr++) { + if (*pstr == ' ' || *pstr == '-') + nextUp = true; + else if (nextUp) { + CharUpperBuffW(pstr, 1); + nextUp = false; + } + } +} + +// the next 2 functions are copied from miranda source +// str = the string to modify +// +void TrimString(char *str) +{ + size_t len, start; + + len = mir_strlen(str); + while (len && (unsigned char)str[len - 1] <= ' ') str[--len] = 0; + for (start = 0; (unsigned char)str[start] <= ' ' && str[start]; start++); + memmove(str, str + start, len - start + 1); +} + +void TrimString(WCHAR *str) +{ + size_t len, start; + + len = mir_wstrlen(str); + while (len && (unsigned char)str[len - 1] <= ' ') str[--len] = 0; + for (start = 0; (unsigned char)str[start] <= ' ' && str[start]; start++); + memmove(str, str + start, (len - start + 1)*sizeof(WCHAR)); +} + +// convert \t to tab and \n to linefeed +void ConvertBackslashes(char *str) +{ + for (char *pstr = str; *pstr; pstr = CharNextA(pstr)) { + if (*pstr == '\\') { + switch (pstr[1]) { + case 'n': *pstr = '\n'; break; + case 't': *pstr = '\t'; break; + default: *pstr = pstr[1]; break; + } + memmove(pstr + 1, pstr + 2, mir_strlen(pstr + 2) + 1); + } + } +} + +// replace spaces with _T("%20" +// dis = original string +// return value = the modified string with space -> _T("%20" +char *GetSearchStr(char *dis) +{ + char *pstr = dis; + size_t len = mir_strlen(dis); + while (*pstr != 0) { + if (*pstr == ' ') { + memmove(pstr + 3, pstr + 1, len); + memcpy(pstr, L"%20", 3); + pstr += 2; + } + pstr++; + len--; + } + return dis; +} + +//============ ICON ASSIGNMENT ============ +// +// make display and history strings +// w = WEATHERINFO data to be parsed +// dis = the string to parse +// return value = the parsed string +wchar_t* GetDisplay(WEATHERINFO *w, const wchar_t *dis, wchar_t* str) +{ + wchar_t lpzDate[32], chr; + char name[256], temp[2]; + DBVARIANT dbv; + size_t i; + + // Clear the string + str[0] = 0; + + // looking character by character + for (i = 0; i < mir_wstrlen(dis); i++) { + // for the escape characters + if (dis[i] == '\\') { + 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; + } + } + + // for the % varaibles + else if (dis[i] == '%') { + i++; + chr = dis[i]; + // turn capitalized characters to small case + if (chr < 'a' && chr != '[' && chr != '%') chr = (char)((int)chr + 32); + switch (chr) { + case 'c': mir_wstrcat(str, 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; + case 'u': + if (mir_wstrcmp(w->update, NODATA)) mir_wstrcat(str, w->update); + else mir_wstrcat(str, 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 '[': // custom variables + i++; + name[0] = 0; + // read the entire variable name + while (dis[i] != ']' && i < mir_wstrlen(dis)) { + mir_snprintf(temp, "%c", dis[i++]); + mir_strcat(name, temp); + } + // 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); + 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); + } + } + + 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 = wcsstr(pszID, L"/"); + 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 = wcsstr(pszID, L"/"); + 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; + default: + mir_snwprintf(str2, TranslateT("HTTP Error %i"), code); + str = str2; + break; + } + return mir_wstrdup(str); +} diff --git a/protocols/Weather/src/weather_data.cpp b/protocols/Weather/src/weather_data.cpp new file mode 100644 index 0000000000..e36ae9dc5b --- /dev/null +++ b/protocols/Weather/src/weather_data.cpp @@ -0,0 +1,439 @@ +/* +Weather Protocol plugin for Miranda IM +Copyright (c) 2012 Miranda NG team +Copyright (c) 2005-2011 Boris Krasnovskiy All Rights Reserved +Copyright (c) 2002-2005 Calvin Che + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; version 2 +of the License. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see <http://www.gnu.org/licenses/>. +*/ + +/* +This file contain the source related loading, obtaining, and +saving individual weather data for a weather contact. +*/ + +#include "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) +{ + // 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)); + + if (db_get_wstatic(hContact, MODULENAME, "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); + if (db_get_wstatic(hContact, WEATHERCONDITION, "Condition", winfo.cond, _countof(winfo.cond))) + wcsncpy(winfo.cond, NODATA, _countof(winfo.cond) - 1); + if (db_get_wstatic(hContact, WEATHERCONDITION, "Temperature", winfo.temp, _countof(winfo.temp))) + wcsncpy(winfo.temp, NODATA, _countof(winfo.temp) - 1); + if (db_get_wstatic(hContact, WEATHERCONDITION, "High", winfo.high, _countof(winfo.high))) + wcsncpy(winfo.high, NODATA, _countof(winfo.high) - 1); + if (db_get_wstatic(hContact, WEATHERCONDITION, "Low", winfo.low, _countof(winfo.low))) + wcsncpy(winfo.low, NODATA, _countof(winfo.low) - 1); + if (db_get_wstatic(hContact, WEATHERCONDITION, "Sunset", winfo.sunset, _countof(winfo.sunset))) + wcsncpy(winfo.sunset, NODATA, _countof(winfo.sunset) - 1); + if (db_get_wstatic(hContact, WEATHERCONDITION, "Sunrise", winfo.sunrise, _countof(winfo.sunrise))) + wcsncpy(winfo.sunrise, NODATA, _countof(winfo.sunrise) - 1); + if (db_get_wstatic(hContact, WEATHERCONDITION, "Wind Speed", winfo.wind, _countof(winfo.wind))) + wcsncpy(winfo.wind, NODATA, _countof(winfo.wind) - 1); + if (db_get_wstatic(hContact, WEATHERCONDITION, "Wind Direction", winfo.winddir, _countof(winfo.winddir))) + wcsncpy(winfo.winddir, NODATA, _countof(winfo.winddir) - 1); + if (db_get_wstatic(hContact, WEATHERCONDITION, "Dewpoint", winfo.dewpoint, _countof(winfo.dewpoint))) + wcsncpy(winfo.dewpoint, NODATA, _countof(winfo.dewpoint) - 1); + if (db_get_wstatic(hContact, WEATHERCONDITION, "Pressure", winfo.pressure, _countof(winfo.pressure))) + wcsncpy(winfo.pressure, NODATA, _countof(winfo.pressure) - 1); + if (db_get_wstatic(hContact, WEATHERCONDITION, "Visibility", winfo.vis, _countof(winfo.vis))) + wcsncpy(winfo.vis, NODATA, _countof(winfo.vis) - 1); + if (db_get_wstatic(hContact, WEATHERCONDITION, "Humidity", winfo.humid, _countof(winfo.humid))) + wcsncpy(winfo.humid, NODATA, _countof(winfo.humid) - 1); + if (db_get_wstatic(hContact, WEATHERCONDITION, "Feel", winfo.feel, _countof(winfo.feel))) + wcsncpy(winfo.feel, NODATA, _countof(winfo.feel) - 1); + + winfo.status = g_plugin.getWord(hContact, "StatusIcon", ID_STATUS_OFFLINE); + 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() +{ + 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", ID_STATUS_OFFLINE); + 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"); + } + else db_free(&dbv); + + DBDataManage(hContact, WDBM_REMOVE, 0, 0); + db_set_s(hContact, "UserInfo", "MyNotes", ""); + // reset update tag + g_plugin.setByte(hContact, "IsUpdated", FALSE); + // reset logging settings + if (!g_plugin.getWString(hContact, "Log", &dbv)) { + g_plugin.setByte(hContact, "File", (BYTE)(dbv.pwszVal[0] != 0)); + db_free(&dbv); + } + else g_plugin.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)); + + opt.DefStn = hContact; + if (!g_plugin.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); + } + } + // get the handle of the default station + if (opt.DefStn == NULL) { + if (!g_plugin.getWString(hContact, "ID", &dbv)) { + if (!mir_wstrcmp(dbv.pwszVal, opt.Default)) + opt.DefStn = hContact; + db_free(&dbv); + } + } + ContactCount++; // increment counter + LastContact = hContact; + } + + // if weather contact exists, set the status to online so it is ready for update + // if (ContactCount != 0) status = ONLINE; + // in case where the default station is missing + if (opt.DefStn == NULL && ContactCount != 0) { + if (!g_plugin.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)) { + 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); +} + +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"Dewpoint") || + !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'; + } +} + +//============ 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) +{ + 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 = wcsstr(szInfo, L" "); + + if (end != nullptr) { + // set the ending location + startloc = 0; + endloc = end - szInfo; + end += mir_wstrlen(UpdateData->End); + last = '\n'; + } + + // 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; + } + } + + // get the last character + if (last != ' ') + Data[respos++] = last; + + // null terminate the string + Data[respos] = 0; + + // convert the unit + ConvertDataValue(UpdateData, Data); + + // remove the string before the data from szInfo + szInfo = end; + } + *szData = szInfo; +} + +//============ ALLOCATE SPACE AND COPY STRING ============ +// +// copy a string into a new memory location +// Data = the field the data is copied to +// Value = the original string, the string where data is copied from +void wSetData(char **Data, const char *Value) +{ + if (Value[0] != 0) + *Data = mir_strdup(Value); + else + *Data = ""; +} + +void wSetData(WCHAR **Data, const char *Value) +{ + if (Value[0] != 0) + *Data = mir_a2u(Value); + else + *Data = L""; +} + +void wSetData(WCHAR **Data, const WCHAR *Value) +{ + if (Value[0] != 0) + *Data = mir_wstrdup(Value); + else + *Data = L""; +} + +// A safer free function that free memory for a string +// Data = the string occuping the data to be freed +void wfree(char **Data) +{ + if (*Data && mir_strlen(*Data) > 0) + mir_free(*Data); + *Data = nullptr; +} + +void wfree(WCHAR **Data) +{ + if (*Data && mir_wstrlen(*Data) > 0) + mir_free(*Data); + *Data = nullptr; +} + +//============ 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) +{ + LIST<char> *pList = (LIST<char>*)lparam; + pList->insert(mir_strdup(szSetting)); + return 0; +} + +// remove or display the weather information for a contact +// hContact - the contact in which the info is going to be removed +// +void DBDataManage(MCONTACT hContact, WORD 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); + + // begin deleting settings + auto T = arSettings.rev_iter(); + for (auto &str : T) { + ptrW wszText(db_get_wsa(hContact, WEATHERCONDITION, str)); + if (wszText == nullptr) + continue; + + switch (Mode) { + case WDBM_REMOVE: + db_unset(hContact, WEATHERCONDITION, str); + break; + + case WDBM_DETAILDISPLAY: + // skip the "WeatherInfo" variable + if (!mir_strcmp(str, "WeatherInfo") || !mir_strcmp(str, "Ignore") || str[0] == '#') + continue; + + HWND hList = GetDlgItem((HWND)wParam, IDC_DATALIST); + LV_ITEM lvi = { 0 }; + lvi.mask = LVIF_TEXT | LVIF_PARAM; + lvi.lParam = T.indexOf(&str); + lvi.pszText = TranslateW(_A2T(str)); + lvi.iItem = ListView_InsertItem(hList, &lvi); + lvi.pszText = wszText; + ListView_SetItemText(hList, lvi.iItem, 1, wszText); + break; + } + mir_free(str); + } +} diff --git a/protocols/Weather/src/weather_http.cpp b/protocols/Weather/src/weather_http.cpp new file mode 100644 index 0000000000..319663bfe7 --- /dev/null +++ b/protocols/Weather/src/weather_http.cpp @@ -0,0 +1,157 @@ +/* +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; + +static int findHeader(const NETLIBHTTPREQUEST *nlhrReply, const char *hdr) +{ + for (int i = 0; i < nlhrReply->headersCount; i++) { + if (_stricmp(nlhrReply->headers[i].szName, hdr) == 0) { + return i; + } + } + return -1; +} + +//============ 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; + + NETLIBHTTPHEADER headers[5]; + headers[0].szName = "User-Agent"; + headers[0].szValue = userAgent; + headers[1].szName = "Cache-Control"; + headers[1].szValue = "no-cache"; + headers[2].szName = "Pragma"; + headers[2].szValue = "no-cache"; + headers[3].szName = "Connection"; + headers[3].szValue = "close"; + headers[4].szName = "Cookie"; + headers[4].szValue = cookie; + + // initialize the netlib request + NETLIBHTTPREQUEST nlhr = { sizeof(nlhr) }; + nlhr.requestType = REQUEST_GET; + nlhr.flags = NLHRF_DUMPASTEXT | NLHRF_HTTP11 | NLHRF_REDIRECT; + nlhr.szUrl = szUrl; + nlhr.headers = headers; + nlhr.headersCount = _countof(headers); + + if (cookie == nullptr || cookie[0] == 0) + --nlhr.headersCount; + + // download the page + NETLIBHTTPREQUEST *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->dataLength) { + bool bIsUtf = false; + result = 0; + + // allocate memory and save the retrieved data + int i = findHeader(nlhrReply, "Content-Type"); + // look for Content-Type=utf-8 in header + if (i != -1 && strstr(_strlwr(nlhrReply->headers[i].szValue), "utf-8")) + bIsUtf = true; + else { + char *end = nlhrReply->pData; + 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->pData); + if (retVal == nullptr) + retVal = mir_a2u(nlhrReply->pData); + *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 + Netlib_FreeHttpRequest(nlhrReply); + return result; +} + +//============ NETLIB INITIALIZATION ============ +// +// initialize netlib support for weather protocol +void NetlibInit(void) +{ + NETLIBUSER nlu = {}; + nlu.flags = NUF_OUTGOING | NUF_HTTPCONNS | NUF_NOHTTPSOPTION | NUF_UNICODE; + nlu.szSettingsModule = MODULENAME; + nlu.szDescriptiveName.w = TranslateT("Weather HTTP connections"); + hNetlibUser = Netlib_RegisterUser(&nlu); +} diff --git a/protocols/Weather/src/weather_icons.cpp b/protocols/Weather/src/weather_icons.cpp new file mode 100644 index 0000000000..3e043d9280 --- /dev/null +++ b/protocols/Weather/src/weather_icons.cpp @@ -0,0 +1,64 @@ +/* +Weather Protocol plugin for Miranda IM +Copyright (c) 2012 Miranda NG team +Copyright (c) 2005-2011 Boris Krasnovskiy All Rights Reserved + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; version 2 +of the License. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see <http://www.gnu.org/licenses/>. +*/ + + +#include "stdafx.h" + +HANDLE hIcoLibIconsChanged = nullptr; + +static IconItem iconList[] = +{ + { LPGEN("Protocol icon"), "main", IDI_ICON }, + { LPGEN("Update Disabled"), "disabled", IDI_DISABLED }, + { LPGEN("View Log"), "log", IDI_LOG }, + { LPGEN("Update with Clear"), "update2", IDI_UPDATE2 }, + { LPGEN("View Brief"), "brief", IDI_S }, + { LPGEN("View Complete"), "read", IDI_READ }, + { LPGEN("Weather Update"), "update", IDI_UPDATE }, + { LPGEN("Weather Map"), "map", IDI_MAP }, + { LPGEN("Popup"), "popup", IDI_POPUP }, + { LPGEN("No Popup"), "nopopup", IDI_NOPOPUP }, + { LPGEN("Edit Settings"), "edit", IDI_EDIT }, +}; + +void InitIcons(void) +{ + g_plugin.registerIcon(MODULENAME, iconList, MODULENAME); +} + +HICON LoadIconEx(const char* name, bool big) +{ + char szSettingName[100]; + mir_snprintf(szSettingName, "%s_%s", MODULENAME, name); + return IcoLib_GetIcon(szSettingName, big); +} + +HANDLE GetIconHandle(const char* name) +{ + for (auto &it : iconList) + if (mir_strcmp(it.szName, name) == 0) + return it.hIcolib; + + return nullptr; +} + +void ReleaseIconEx(HICON hIcon) +{ + IcoLib_ReleaseIcon(hIcon); +} diff --git a/protocols/Weather/src/weather_info.cpp b/protocols/Weather/src/weather_info.cpp new file mode 100644 index 0000000000..a2395d9f69 --- /dev/null +++ b/protocols/Weather/src/weather_info.cpp @@ -0,0 +1,240 @@ +/* +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 = { 0 }; + 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; + switch (Item->Data.InternalVer) { + case 1: lvi.pszText = L"1.0"; break; + case 2: lvi.pszText = L"1.1"; break; + case 3: lvi.pszText = L"1.1a"; break; + case 4: lvi.pszText = L"1.2"; break; + case 5: lvi.pszText = L"1.3"; break; + case 6: lvi.pszText = L"1.4"; break; + case 7: lvi.pszText = L"1.5"; break; + default: lvi.pszText = L""; break; + } + 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)); +} + +static const struct tag_Columns +{ + const wchar_t *name; + unsigned size; +} +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 }, +}; + + +INT_PTR CALLBACK DlgProcINIPage(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM) +{ + switch (msg) { + case WM_INITDIALOG: + TranslateDialogDefault(hwndDlg); + { + HWND hIniList = GetDlgItem(hwndDlg, IDC_INFOLIST); + LVCOLUMN lvc = { 0 }; + + lvc.mask = LVCF_FMT | LVCF_SUBITEM | LVCF_TEXT | LVCF_WIDTH; + lvc.fmt = LVCFMT_LEFT; + for (int i = 0; i < 7; ++i) { + lvc.iSubItem = i; + lvc.pszText = TranslateW(columns[i].name); + lvc.cx = columns[i].size; + ListView_InsertColumn(hIniList, i, &lvc); + } + INIInfo(hwndDlg); + } + + break; + + case WM_DESTROY: + break; + + case WM_COMMAND: + if (HIWORD(wParam) == BN_CLICKED && + LOWORD(wParam) == IDC_RELOADINI) { + DestroyWIList(); + LoadWIData(true); + INIInfo(hwndDlg); + } + break; + } + return 0; +} + + +// get the info of individual ini file +// pszSvc = the internal name of the service to get the data +void GetINIInfo(wchar_t *pszSvc) +{ + wchar_t str2[2048]; + WIDATA *sData = GetWIData(pszSvc); + // if the service does not exist among the loaded INI's + if (sData == nullptr) { + mir_snwprintf(str2, TranslateT("The corresponding INI file for \"%s\" is not found."), pszSvc); + MessageBox(nullptr, str2, TranslateT("Weather INI information"), MB_OK | MB_ICONINFORMATION); + } + // if exist, get the information + else { + mir_snwprintf(str2, TranslateT("Weather INI information for \"%s\":"), pszSvc); + mir_wstrncat(str2, L"\n\n", _countof(str2) - mir_wstrlen(str2)); + mir_wstrncat(str2, TranslateT("Name:"), _countof(str2) - mir_wstrlen(str2)); + mir_wstrncat(str2, L"\t\t", _countof(str2) - mir_wstrlen(str2)); + mir_wstrncat(str2, sData->DisplayName, _countof(str2) - mir_wstrlen(str2)); + mir_wstrncat(str2, L"\n", _countof(str2) - mir_wstrlen(str2)); + mir_wstrncat(str2, TranslateT("Internal Name:"), _countof(str2) - mir_wstrlen(str2)); + mir_wstrncat(str2, L"\t", _countof(str2) - mir_wstrlen(str2)); + mir_wstrncat(str2, sData->InternalName, _countof(str2) - mir_wstrlen(str2)); + mir_wstrncat(str2, L"\n", _countof(str2) - mir_wstrlen(str2)); + mir_wstrncat(str2, TranslateT("Author:"), _countof(str2) - mir_wstrlen(str2)); + mir_wstrncat(str2, L"\t\t", _countof(str2) - mir_wstrlen(str2)); + mir_wstrncat(str2, sData->Author, _countof(str2) - mir_wstrlen(str2)); + mir_wstrncat(str2, L"\n", _countof(str2) - mir_wstrlen(str2)); + mir_wstrncat(str2, TranslateT("Version:"), _countof(str2) - mir_wstrlen(str2)); + mir_wstrncat(str2, L"\t\t", _countof(str2) - mir_wstrlen(str2)); + mir_wstrncat(str2, sData->Version, _countof(str2) - mir_wstrlen(str2)); + mir_wstrncat(str2, L"\n", _countof(str2) - mir_wstrlen(str2)); + mir_wstrncat(str2, TranslateT("INI Version:"), _countof(str2) - mir_wstrlen(str2)); + mir_wstrncat(str2, L"\t", _countof(str2) - mir_wstrlen(str2)); + switch (sData->InternalVer) { + case 1: mir_wstrncat(str2, L"1.0", _countof(str2) - mir_wstrlen(str2)); break; + case 2: mir_wstrncat(str2, L"1.1", _countof(str2) - mir_wstrlen(str2)); break; + case 3: mir_wstrncat(str2, L"1.1a", _countof(str2) - mir_wstrlen(str2)); break; + case 4: mir_wstrncat(str2, L"1.2", _countof(str2) - mir_wstrlen(str2)); break; + case 5: mir_wstrncat(str2, L"1.3", _countof(str2) - mir_wstrlen(str2)); break; + case 6: mir_wstrncat(str2, L"1.4", _countof(str2) - mir_wstrlen(str2)); break; + case 7: mir_wstrncat(str2, L"1.5", _countof(str2) - mir_wstrlen(str2)); break; + } + mir_wstrncat(str2, L"\n", _countof(str2) - mir_wstrlen(str2)); + mir_wstrncat(str2, TranslateT("File Name:"), _countof(str2) - mir_wstrlen(str2)); + mir_wstrncat(str2, L"\t", _countof(str2) - mir_wstrlen(str2)); + mir_wstrncat(str2, sData->ShortFileName, _countof(str2) - mir_wstrlen(str2)); + mir_wstrncat(str2, L"\n", _countof(str2) - mir_wstrlen(str2)); + mir_wstrncat(str2, TranslateT("Item Count:"), _countof(str2) - mir_wstrlen(str2)); + mir_snwprintf(str2, L"%s\t%i\n", str2, sData->UpdateDataCount); + mir_wstrncat(str2, TranslateT("Memory Used:"), _countof(str2) - mir_wstrlen(str2)); + mir_snwprintf(str2, L"%s\t%i ", str2, sData->MemUsed); + mir_wstrncat(str2, TranslateT("bytes"), _countof(str2) - mir_wstrlen(str2)); + mir_wstrncat(str2, L"\n\n", _countof(str2) - mir_wstrlen(str2)); + mir_wstrncat(str2, TranslateT("Description:"), _countof(str2) - mir_wstrlen(str2)); + mir_wstrncat(str2, L"\n", _countof(str2) - mir_wstrlen(str2)); + mir_wstrncat(str2, sData->Description, _countof(str2) - mir_wstrlen(str2)); + + // display the message box and quit + MessageBox(nullptr, str2, TranslateT("Weather INI information"), MB_OK | MB_ICONINFORMATION); + } +} + +//============ DISPLAY A LIST FOR CUSTOM VARIABLES ============ +// +// a message box for displaying the list of custom variables +// can be found when click on "More" in text option dialog +void MoreVarList(void) +{ + wchar_t str[10240], tempstr[1024]; + + // heading + wcsncpy(str, VARS_LIST, _countof(str) - 1); + mir_wstrncat(str, L"\n\n", _countof(str) - mir_wstrlen(str)); + // loop through all weather services to find custom variables + 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] != '#') { + mir_snwprintf(tempstr, L"%c[%s]", '%', WItem->Item.Name); + wchar_t *find = wcsstr(str, tempstr); + // if the custom variable does not exist in the list, add it to the list + if (find == nullptr) { + mir_wstrncat(str, tempstr, _countof(str) - mir_wstrlen(str)); + mir_wstrncat(str, L", ", _countof(str) - mir_wstrlen(str)); + } + } + } + } + // remove the last comma in the list + wchar_t* find = wcsrchr(str, ','); + if (find != nullptr) + *find = '\0'; + + // 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 new file mode 100644 index 0000000000..000eab1bc9 --- /dev/null +++ b/protocols/Weather/src/weather_ini.cpp @@ -0,0 +1,592 @@ +/* +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); + CharLowerBuff(newItem->Item, (DWORD)mir_wstrlen(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, GetIconHandle("main")); + + 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: + { + wchar_t szPath[1024]; + GetModuleFileName(GetModuleHandle(nullptr), szPath, _countof(szPath)); + wchar_t *chop = wcsrchr(szPath, '\\'); + if (chop) { + *chop = '\0'; + mir_wstrncat(szPath, L"\\Plugins\\weather\\", _countof(szPath) - mir_wstrlen(szPath)); + if (_wmkdir(szPath) == 0) + ShellExecute((HWND)lParam, L"open", szPath, 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 void LoadStationData(wchar_t *pszFile, wchar_t *pszShortFile, WIDATA *Data) +{ + WIDATAITEM DataItem; + char *Group, *Temp; + char *ValName, *Value; + + static const char *statusStr[10] = + { + "LIGHTNING", + "FOG", + "SNOW SHOWER", + "SNOW", + "RAIN SHOWER", + "RAIN", + "PARTLY CLOUDY", + "CLOUDY", + "SUNNY", + "N/A" + }; + + // clean up old stuff + memset(Data, 0, sizeof(*Data)); + Data->Enabled = FALSE; + + // open the ini file + FILE *pfile = _wfsopen(pszFile, L"rt", _SH_DENYWR); + if (pfile != nullptr) { + 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 + 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; + + Temp = ""; + + // 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 (int i = 0; i < 10; i++) + WICondListInit(&Data->CondList[i]); + + 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 + 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") && + // strcmpi(Group, "NAME SEARCH")) + // wSetData(&DataItem.Name, Group); + if (_stricmp(Group, "HEADER") && _stricmp(Group, "DEFAULT") && _stricmp(Group, "ID SEARCH") && + _stricmp(Group, "NAME SEARCH") && _stricmp(Group, "ICONS")) { + wSetData(&DataItem.Name, Temp); + DataItem.Type = WID_NORMAL; + WIItemListAdd(&DataItem, Data); + Data->UpdateDataCount++; + } + mir_free(Temp); + } + else { + wfree(&Group); + wSetData(&Group, ""); + } + } + // ignore comments and all lines without an '=' + Value = strstr(Line, "="); + if (Value == nullptr) continue; + + // get the string before '=' (ValName) and after '=' (Value) + 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(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")) { + if (!_stricmp(Value, "TRUE")) Data->IDSearch.Available = TRUE; + else Data->IDSearch.Available = FALSE; + } + else if (!_stricmp(ValName, "SEARCH URL")) wSetData(&Data->IDSearch.SearchURL, Value); + else if (!_stricmp(ValName, "NOT FOUND STR")) wSetData(&Data->IDSearch.NotFoundStr, Value); + else if (!_stricmp(ValName, "NAME START")) wSetData(&Data->IDSearch.Name.Start, Value); + else if (!_stricmp(ValName, "NAME END")) wSetData(&Data->IDSearch.Name.End, Value); + } + else if (!_stricmp(Group, "NAME SEARCH")) { + if (!_stricmp(ValName, "SINGLE RESULT")) { + if (!_stricmp(Value, "TRUE")) Data->NameSearch.Single.Available = TRUE; + else Data->NameSearch.Single.Available = FALSE; + } + else if (!_stricmp(ValName, "MULTIPLE RESULT")) { + if (!_stricmp(Value, "TRUE")) Data->NameSearch.Multiple.Available = TRUE; + else Data->NameSearch.Multiple.Available = FALSE; + } + else if (!_stricmp(ValName, "SEARCH URL")) wSetData(&Data->NameSearch.SearchURL, Value); + else if (!_stricmp(ValName, "NOT FOUND STR")) wSetData(&Data->NameSearch.NotFoundStr, Value); + else if (!_stricmp(ValName, "SINGLE RESULT STR")) wSetData(&Data->NameSearch.SingleStr, Value); + else if (!_stricmp(ValName, "SINGLE FIRST")) wSetData(&Data->NameSearch.Single.First, Value); + else if (!_stricmp(ValName, "SINGLE NAME START"))wSetData(&Data->NameSearch.Single.Name.Start, Value); + else if (!_stricmp(ValName, "SINGLE NAME END")) wSetData(&Data->NameSearch.Single.Name.End, Value); + else if (!_stricmp(ValName, "SINGLE ID START")) wSetData(&Data->NameSearch.Single.ID.Start, Value); + else if (!_stricmp(ValName, "SINGLE ID END")) wSetData(&Data->NameSearch.Single.ID.End, Value); + else if (!_stricmp(ValName, "MULT FIRST")) wSetData(&Data->NameSearch.Multiple.First, Value); + else if (!_stricmp(ValName, "MULT NAME START")) wSetData(&Data->NameSearch.Multiple.Name.Start, Value); + else if (!_stricmp(ValName, "MULT NAME END")) wSetData(&Data->NameSearch.Multiple.Name.End, Value); + else if (!_stricmp(ValName, "MULT ID START")) wSetData(&Data->NameSearch.Multiple.ID.Start, Value); + else if (!_stricmp(ValName, "MULT ID END")) wSetData(&Data->NameSearch.Multiple.ID.End, Value); + } + else if (!_stricmp(Group, "ICONS")) { + for (int i = 0; i < 10; i++) { + if (!_stricmp(ValName, statusStr[i])) { + WICondListAdd(Value, &Data->CondList[i]); + break; + } + } + } + else if (Data->UpdateDataCount != 0) { + if (!_stricmp(ValName, "START")) wSetData(&Data->UpdateDataTail->Item.Start, Value); + else if (!_stricmp(ValName, "SOURCE")) wSetData(&Data->UpdateDataTail->Item.Start, Value); + else if (!_stricmp(ValName, "END")) wSetData(&Data->UpdateDataTail->Item.End, Value); + else if (!_stricmp(ValName, "UNIT")) wSetData(&Data->UpdateDataTail->Item.Unit, Value); + else if (!_stricmp(ValName, "URL")) wSetData(&Data->UpdateDataTail->Item.Url, Value); + else if (!_stricmp(ValName, "HIDDEN")) { + if (!_stricmp(Value, "TRUE")) { + 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 + wchar_t szSearchPath[MAX_PATH], FileName[MAX_PATH]; + GetModuleFileName(GetModuleHandle(nullptr), szSearchPath, _countof(szSearchPath)); + wchar_t *chop = wcsrchr(szSearchPath, '\\'); + if (chop == nullptr) + return false; + *chop = '\0'; + mir_wstrncat(szSearchPath, L"\\Plugins\\Weather\\*.ini", _countof(szSearchPath) - mir_wstrlen(szSearchPath)); + wcsncpy(FileName, szSearchPath, MAX_PATH - 1); + + WIN32_FIND_DATA fd; + HANDLE hFind = FindFirstFile(szSearchPath, &fd); + + + // load the content of the ini file into memory + if (hFind != INVALID_HANDLE_VALUE) { + do { + chop = wcsrchr(FileName, '\\'); + chop[1] = '\0'; + mir_wstrncat(FileName, fd.cFileName, _countof(FileName) - mir_wstrlen(FileName)); + if (mir_wstrcmpi(fd.cFileName, L"SAMPLE_INI.INI")) { + WIDATA Data; + LoadStationData(FileName, fd.cFileName, &Data); + if (Data.Enabled) + WIListAdd(Data); + } + // look through the entire "plugins\weather" directory + } while (FindNextFile(hFind, &fd)); + FindClose(hFind); + } + + if (WIHead == 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 (int i = 0; i < 10; i++) + DestroyCondList(&Data->CondList[i]); +} + +// 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 new file mode 100644 index 0000000000..a240b01421 --- /dev/null +++ b/protocols/Weather/src/weather_mwin.cpp @@ -0,0 +1,364 @@ +/* +Weather Protocol plugin for Miranda IM +Copyright (c) 2012 Miranda NG team +Copyright (c) 2006-2009 Boris Krasnovskiy All Rights Reserved +Copyright (c) 2002-2006 Calvin Che + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; version 2 +of the License. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see <http://www.gnu.org/licenses/>. +*/ + +#include "stdafx.h" + +#define MS_TOOLTIP_SHOWTIP "mToolTip/ShowTip" +#define MS_TOOLTIP_HIDETIP "mToolTip/HideTip" + +static MWindowList hMwinWindowList; +static HANDLE hFontHook; + +HGENMENU hMwinMenu; + +typedef struct +{ + MCONTACT hContact; + HWND hAvt; + BOOL haveAvatar; +} MWinDataType; + +#define WM_REDRAWWIN (WM_USER + 17369) + +static LRESULT CALLBACK wndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) +{ + MWinDataType *data = (MWinDataType*)GetWindowLongPtr(hwnd, GWLP_USERDATA); + + switch (msg) { + case WM_CREATE: + data = (MWinDataType*)mir_calloc(sizeof(MWinDataType)); + SetWindowLongPtr(hwnd, GWLP_USERDATA, (LONG_PTR)data); + + data->hContact = (DWORD_PTR)((LPCREATESTRUCT)lParam)->lpCreateParams; + data->hAvt = CreateWindow(AVATAR_CONTROL_CLASS, TEXT(""), WS_CHILD, + 0, 0, opt.AvatarSize, opt.AvatarSize, hwnd, nullptr, g_plugin.getInst(), nullptr); + if (data->hAvt) SendMessage(data->hAvt, AVATAR_SETCONTACT, 0, (LPARAM)data->hContact); + break; + + case WM_DESTROY: + mir_free(data); + break; + + case WM_CONTEXTMENU: + { + POINT pt; + GetCursorPos(&pt); + HMENU hMenu = Menu_BuildContactMenu(data->hContact); + TrackPopupMenu(hMenu, TPM_LEFTALIGN, pt.x, pt.y, 0, hwnd, nullptr); + DestroyMenu(hMenu); + } + break; + + case WM_MOUSEMOVE: + { + TRACKMOUSEEVENT tme = { 0 }; + tme.cbSize = sizeof(TRACKMOUSEEVENT); + tme.hwndTrack = hwnd; + tme.dwFlags = TME_QUERY; + TrackMouseEvent(&tme); + + if (tme.dwFlags == 0) { + tme.dwFlags = TME_HOVER | TME_LEAVE; + tme.hwndTrack = hwnd; + tme.dwHoverTime = CallService(MS_CLC_GETINFOTIPHOVERTIME, 0, 0); + TrackMouseEvent(&tme); + } + } + break; + + case WM_MOUSEHOVER: + { + POINT pt; + CLCINFOTIP ti = { 0 }; + + GetCursorPos(&pt); + GetWindowRect(hwnd, &ti.rcItem); + + ti.cbSize = sizeof(ti); + ti.hItem = (HANDLE)data->hContact; + ti.ptCursor = pt; + ti.isTreeFocused = 1; + CallService(MS_TOOLTIP_SHOWTIP, 0, (LPARAM)&ti); + } + break; + + case WM_LBUTTONDBLCLK: + BriefInfo(data->hContact, 0); + break; + + case WM_COMMAND: //Needed by the contact's context menu + if (Clist_MenuProcessCommand(LOWORD(wParam), MPCF_CONTACTMENU, data->hContact)) + break; + return FALSE; + + case WM_MEASUREITEM: //Needed by the contact's context menu + return Menu_MeasureItem(lParam); + + case WM_DRAWITEM: //Needed by the contact's context menu + return Menu_DrawItem(lParam); + + case WM_NOTIFY: + if (((LPNMHDR)lParam)->code == NM_AVATAR_CHANGED) { + BOOL newava = CallService(MS_AV_GETAVATARBITMAP, data->hContact, 0) != 0; + if (newava != data->haveAvatar) { + LONG_PTR style = GetWindowLongPtr(data->hAvt, GWL_STYLE); + data->haveAvatar = newava; + SetWindowLongPtr(data->hAvt, GWL_STYLE, newava ? (style | WS_VISIBLE) : (style & ~WS_VISIBLE)); + RedrawWindow(hwnd, nullptr, nullptr, RDW_INVALIDATE); + } + } + break; + + case WM_REDRAWWIN: + if (data->hAvt != nullptr) MoveWindow(data->hAvt, 0, 0, opt.AvatarSize, opt.AvatarSize, TRUE); + RedrawWindow(hwnd, nullptr, nullptr, RDW_INVALIDATE | RDW_UPDATENOW); + break; + + case WM_PAINT: + { + RECT r, rc; + + if (GetUpdateRect(hwnd, &r, FALSE)) { + int picSize = opt.AvatarSize; + HICON hIcon = nullptr; + + if (!data->haveAvatar) { + int statusIcon = g_plugin.getWord(data->hContact, "Status"); + + picSize = GetSystemMetrics(SM_CXICON); + hIcon = Skin_LoadProtoIcon(MODULENAME, statusIcon, true); + if ((INT_PTR)hIcon == CALLSERVICE_NOTFOUND) { + picSize = GetSystemMetrics(SM_CXSMICON); + hIcon = Skin_LoadProtoIcon(MODULENAME, statusIcon); + } + } + + LOGFONT lfnt, lfnt1; + COLORREF clr = g_plugin.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); + + ptrW tszInfo(db_get_wsa(data->hContact, WEATHERCONDITION, "WeatherInfo")); + + GetClientRect(hwnd, &rc); + + PAINTSTRUCT ps; + HDC hdc = BeginPaint(hwnd, &ps); + + if (ServiceExists(MS_SKIN_DRAWGLYPH)) { + SKINDRAWREQUEST rq; + memset(&rq, 0, sizeof(rq)); + rq.hDC = hdc; + rq.rcDestRect = rc; + rq.rcClipRect = rc; + + mir_strcpy(rq.szObjectID, "Main,ID=WeatherFrame"); + CallService(MS_SKIN_DRAWGLYPH, (WPARAM)&rq, 0); + } + + if (clr != 0xFFFFFFFF) { + HBRUSH hBkgBrush = CreateSolidBrush(clr); + FillRect(hdc, &rc, hBkgBrush); + DeleteObject(hBkgBrush); + } + + if (!data->haveAvatar) + DrawIconEx(hdc, 1, 1, hIcon, 0, 0, 0, nullptr, DI_NORMAL); + + SetBkMode(hdc, TRANSPARENT); + + HFONT hfnt = CreateFontIndirect(&lfnt1); + HFONT hfntold = (HFONT)SelectObject(hdc, hfnt); + + wchar_t *nick = Clist_GetContactDisplayName(data->hContact); + + SIZE fontSize; + GetTextExtentPoint32(hdc, L"|", 1, &fontSize); + + rc.top += 1; + rc.left += picSize + fontSize.cx; + + SetTextColor(hdc, fntc1); + DrawText(hdc, nick, -1, &rc, DT_LEFT | DT_EXPANDTABS); + + rc.top += fontSize.cy; + + SelectObject(hdc, hfntold); + DeleteObject(hfnt); + + if (tszInfo) { + HFONT hFont = CreateFontIndirect(&lfnt); + HFONT hFontOld = (HFONT)SelectObject(hdc, hFont); + + SetTextColor(hdc, fntc); + DrawText(hdc, tszInfo, -1, &rc, DT_LEFT | DT_EXPANDTABS); + + SelectObject(hdc, hFontOld); + DeleteObject(hFont); + } + EndPaint(hwnd, &ps); + IcoLib_ReleaseIcon(hIcon); + } + break; + } + + default: + return DefWindowProc(hwnd, msg, wParam, lParam); + } + return(TRUE); +} + +static void addWindow(MCONTACT hContact) +{ + DBVARIANT dbv; + if (g_plugin.getWString(hContact, "Nick", &dbv)) + return; + + wchar_t winname[512]; + mir_snwprintf(winname, L"Weather: %s", dbv.pwszVal); + 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); + WindowList_Add(hMwinWindowList, hWnd, hContact); + + CLISTFrame Frame = { 0 }; + Frame.szName.w = winname; + Frame.hIcon = LoadIconEx("main", FALSE); + Frame.cbSize = sizeof(Frame); + Frame.hWnd = hWnd; + Frame.align = alBottom; + Frame.Flags = F_VISIBLE | F_NOBORDER | F_UNICODE; + Frame.height = 32; + int frameID = g_plugin.addFrame(&Frame); + + g_plugin.setDword(hContact, "mwin", frameID); + db_set_b(hContact, "CList", "Hidden", TRUE); +} + +void removeWindow(MCONTACT hContact) +{ + DWORD frameId = g_plugin.getDword(hContact, "mwin"); + + WindowList_Remove(hMwinWindowList, WindowList_Find(hMwinWindowList, hContact)); + CallService(MS_CLIST_FRAMES_REMOVEFRAME, frameId, 0); + + g_plugin.setDword(hContact, "mwin", 0); + db_unset(hContact, "CList", "Hidden"); +} + +void UpdateMwinData(MCONTACT hContact) +{ + 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); + else + removeWindow(wParam); + return 0; +} + +int BuildContactMenu(WPARAM wparam, LPARAM) +{ + int flags = g_plugin.getDword(wparam, "mwin") ? CMIF_CHECKED : 0; + Menu_ModifyItem(hMwinMenu, nullptr, INVALID_HANDLE_VALUE, flags); + return 0; +} + +int RedrawFrame(WPARAM, LPARAM) +{ + WindowList_Broadcast(hMwinWindowList, WM_REDRAWWIN, 0, 0); + return 0; +} + +void InitMwin(void) +{ + if (!ServiceExists(MS_CLIST_FRAMES_ADDFRAME)) + return; + + hMwinWindowList = WindowList_Create(); + + WNDCLASS wndclass; + wndclass.style = CS_DBLCLKS | CS_HREDRAW | CS_VREDRAW; + wndclass.lpfnWndProc = wndProc; + wndclass.cbClsExtra = 0; + wndclass.cbWndExtra = 0; + wndclass.hInstance = g_plugin.getInst(); + wndclass.hIcon = nullptr; + wndclass.hCursor = LoadCursor(nullptr, IDC_ARROW); + wndclass.hbrBackground = nullptr; //(HBRUSH)(COLOR_3DFACE+1); + wndclass.lpszMenuName = nullptr; + wndclass.lpszClassName = L"WeatherFrame"; + RegisterClass(&wndclass); + + ColourIDW colourid = {}; + mir_strcpy(colourid.dbSettingsGroup, MODULENAME); + mir_strcpy(colourid.setting, "ColorMwinFrame"); + mir_wstrcpy(colourid.name, LPGENW("Frame Background")); + mir_wstrcpy(colourid.group, _A2W(MODULENAME)); + colourid.defcolour = GetSysColor(COLOR_3DFACE); + g_plugin.addColor(&colourid); + + FontIDW fontid = {}; + fontid.flags = FIDF_ALLOWREREGISTER | FIDF_DEFAULTVALID; + mir_strcpy(fontid.dbSettingsGroup, MODULENAME); + mir_wstrcpy(fontid.group, _A2W(MODULENAME)); + mir_wstrcpy(fontid.name, LPGENW("Frame Font")); + mir_strcpy(fontid.setting, "fnt0"); + + HDC hdc = GetDC(nullptr); + fontid.deffontsettings.size = -13; + ReleaseDC(nullptr, hdc); + + fontid.deffontsettings.charset = DEFAULT_CHARSET; + mir_wstrcpy(fontid.deffontsettings.szFace, L"Verdana"); + mir_wstrcpy(fontid.backgroundGroup, _A2W(MODULENAME)); + mir_wstrcpy(fontid.backgroundName, LPGENW("Frame Background")); + g_plugin.addFont(&fontid); + + fontid.deffontsettings.style = DBFONTF_BOLD; + mir_wstrcpy(fontid.name, LPGENW("Frame Title Font")); + mir_strcpy(fontid.setting, "fnt1"); + g_plugin.addFont(&fontid); + + for (auto &hContact : Contacts(MODULENAME)) + if (g_plugin.getDword(hContact, "mwin")) + addWindow(hContact); + + hFontHook = HookEvent(ME_FONT_RELOAD, RedrawFrame); +} + +void DestroyMwin(void) +{ + for (auto &hContact : Contacts(MODULENAME)) { + DWORD frameId = g_plugin.getDword(hContact, "mwin"); + if (frameId) + CallService(MS_CLIST_FRAMES_REMOVEFRAME, frameId, 0); + } + UnregisterClass(L"WeatherFrame", g_plugin.getInst()); + WindowList_Destroy(hMwinWindowList); + UnhookEvent(hFontHook); +} diff --git a/protocols/Weather/src/weather_opt.cpp b/protocols/Weather/src/weather_opt.cpp new file mode 100644 index 0000000000..daf84d36c7 --- /dev/null +++ b/protocols/Weather/src/weather_opt.cpp @@ -0,0 +1,601 @@ +/* +Weather Protocol plugin for Miranda IM +Copyright (c) 2012 Miranda NG team +Copyright (c) 2005-2011 Boris Krasnovskiy All Rights Reserved +Copyright (c) 2002-2005 Calvin Che + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; version 2 +of the License. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see <http://www.gnu.org/licenses/>. +*/ + +/* This file contain the source related to weather option pages. It also +contain code for saving/loading options from the database. +*/ + +#include "stdafx.h" + +static BOOL opt_startup; +int RedrawFrame(WPARAM wParam, LPARAM lParam); + +//============ LOADING AND SAVING OPTIONS =========== +// +// set a string to default +// in = string to determine which field to set default "CBNEHXPp" +void SetTextDefault(const char* in) +{ + wchar_t str[MAX_TEXT_SIZE]; + + if (strchr(in, 'C') != nullptr) { + wcsncpy(str, C_DEFAULT, MAX_TEXT_SIZE - 1); + wSetData(&opt.cText, str); + } + if (strchr(in, 'b') != nullptr) { + wcsncpy(str, b_DEFAULT, MAX_TEXT_SIZE - 1); + wSetData(&opt.bTitle, str); + } + if (strchr(in, 'B') != nullptr) { + wcsncpy(str, B_DEFAULT, MAX_TEXT_SIZE - 1); + wSetData(&opt.bText, str); + } + if (strchr(in, 'N') != nullptr) { + wcsncpy(str, N_DEFAULT, MAX_TEXT_SIZE - 1); + wSetData(&opt.nText, str); + } + if (strchr(in, 'E') != nullptr) { + wcsncpy(str, E_DEFAULT, MAX_TEXT_SIZE - 1); + wSetData(&opt.eText, str); + } + if (strchr(in, 'H') != nullptr) { + wcsncpy(str, H_DEFAULT, MAX_TEXT_SIZE - 1); + wSetData(&opt.hText, str); + } + if (strchr(in, 'X') != nullptr) { + wcsncpy(str, X_DEFAULT, MAX_TEXT_SIZE - 1); + wSetData(&opt.xText, str); + } + if (strchr(in, 'P') != nullptr) { + wcsncpy(str, P_DEFAULT, MAX_TEXT_SIZE - 1); + wSetData(&opt.pTitle, str); + } + if (strchr(in, 'p') != nullptr) { + wcsncpy(str, p_DEFAULT, MAX_TEXT_SIZE - 1); + wSetData(&opt.pText, str); + } + if (strchr(in, 'S') != nullptr) { + wcsncpy(str, s_DEFAULT, MAX_TEXT_SIZE - 1); + wSetData(&opt.sText, str); + } +} + +void DestroyOptions(void) +{ + wfree(&opt.cText); + wfree(&opt.bTitle); + wfree(&opt.bText); + wfree(&opt.nText); + wfree(&opt.eText); + wfree(&opt.hText); + wfree(&opt.xText); + wfree(&opt.pTitle); + wfree(&opt.pText); + wfree(&opt.sText); +} + +// load options from database + set default if the setting does not exist +void LoadOptions(void) +{ + 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); + + // 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); + + ptrW szValue(g_plugin.getWStringA("DegreeSign")); + wcsncpy_s(opt.DegreeSign, (szValue == NULL) ? L"" : szValue, _TRUNCATE); + + opt.DoNotAppendUnit = g_plugin.getByte("DoNotAppendUnit", 0); + opt.NoFrac = g_plugin.getByte("NoFractions", 0); + + // texts + if (szValue = g_plugin.getWStringA("DisplayText")) + wSetData(&opt.cText, TranslateW(szValue)); + else + SetTextDefault("C"); + + if (szValue = g_plugin.getWStringA("BriefTextTitle")) + wSetData(&opt.bTitle, TranslateW(szValue)); + else + SetTextDefault("b"); + + if (szValue = g_plugin.getWStringA("BriefText")) + wSetData(&opt.bText, TranslateW(szValue)); + else + SetTextDefault("B"); + + if (szValue = g_plugin.getWStringA("NoteText")) + wSetData(&opt.nText, TranslateW(szValue)); + else + SetTextDefault("N"); + + if (szValue = g_plugin.getWStringA("ExtText")) + wSetData(&opt.eText, TranslateW(szValue)); + else + SetTextDefault("E"); + + if (szValue = g_plugin.getWStringA("HistoryText")) + wSetData(&opt.hText, TranslateW(szValue)); + else + SetTextDefault("H"); + + if (szValue = g_plugin.getWStringA("ExtraText")) + wSetData(&opt.xText, TranslateW(szValue)); + else + SetTextDefault("X"); + + if (szValue = g_plugin.getWStringA("StatusText")) + wSetData(&opt.sText, TranslateW(szValue)); + else + SetTextDefault("S"); + + // advanced + opt.DisCondIcon = g_plugin.getByte("DisableConditionIcon", false); + // popup options + opt.UsePopup = g_plugin.getByte("UsePopUp", true); + 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); + // 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); + // popup actions + opt.LeftClickAction = g_plugin.getDword("LeftClickAction", IDM_M2); + opt.RightClickAction = g_plugin.getDword("RightClickAction", IDM_M1); + // popup delay + opt.pDelay = g_plugin.getDword("PopupDelay", 0); + // popup texts + if (szValue = g_plugin.getWStringA("PopupTitle")) + wSetData(&opt.pTitle, szValue); + else + SetTextDefault("P"); + + if (szValue = g_plugin.getWStringA("PopupText")) + wSetData(&opt.pText, szValue); + else + SetTextDefault("p"); + + // misc + if (szValue = g_plugin.getWStringA("Default")) + wcsncpy_s(opt.Default, szValue, _TRUNCATE); + else + opt.Default[0] = 0; +} + +// save the options to database +void SaveOptions(void) +{ + // main options + g_plugin.setByte("StartupUpdate", (BYTE)opt.StartupUpdate); + g_plugin.setByte("AutoUpdate", (BYTE)opt.AutoUpdate); + g_plugin.setWord("UpdateTime", opt.UpdateTime); + g_plugin.setByte("NoStatus", (BYTE)opt.NoProtoCondition); + g_plugin.setByte("CondChangeAsUpdate", (BYTE)opt.UpdateOnlyConditionChanged); + g_plugin.setByte("RemoveOld", (BYTE)opt.RemoveOldData); + g_plugin.setByte("MakeItalic", (BYTE)opt.MakeItalic); + g_plugin.setByte("AvatarSize", (BYTE)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", (BYTE)opt.DoNotAppendUnit); + g_plugin.setByte("NoFractions", (BYTE)opt.NoFrac); + // texts + g_plugin.setWString("DisplayText", opt.cText); + g_plugin.setWString("BriefTextTitle", opt.bTitle); + g_plugin.setWString("BriefText", opt.bText); + g_plugin.setWString("NoteText", opt.nText); + g_plugin.setWString("ExtText", opt.eText); + g_plugin.setWString("HistoryText", opt.hText); + g_plugin.setWString("ExtraText", opt.xText); + g_plugin.setWString("StatusText", opt.sText); + // advanced + g_plugin.setByte("DisableConditionIcon", (BYTE)opt.DisCondIcon); + // popup options + g_plugin.setByte("UsePopUp", (BYTE)opt.UsePopup); + g_plugin.setByte("UpdatePopup", (BYTE)opt.UpdatePopup); + g_plugin.setByte("AlertPopup", (BYTE)opt.AlertPopup); + g_plugin.setByte("PopUpOnChange", (BYTE)opt.PopupOnChange); + g_plugin.setByte("ShowWarnings", (BYTE)opt.ShowWarnings); + // popup colors + g_plugin.setDword("BackgroundColour", opt.BGColour); + g_plugin.setDword("TextColour", opt.TextColour); + g_plugin.setByte("UseWinColors", (BYTE)opt.UseWinColors); + // popup actions + g_plugin.setDword("LeftClickAction", opt.LeftClickAction); + g_plugin.setDword("RightClickAction", opt.RightClickAction); + // popup delay + g_plugin.setDword("PopupDelay", opt.pDelay); + // popup texts + g_plugin.setWString("PopupTitle", opt.pTitle); + g_plugin.setWString("PopupText", opt.pText); + // misc stuff + g_plugin.setWString("Default", opt.Default); +} +//============ MAIN OPTIONS ============ + +// weather options +static INT_PTR CALLBACK OptionsProc(HWND hdlg, UINT msg, WPARAM wparam, LPARAM lparam) +{ + wchar_t str[512]; + + 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); + + // load units + switch (opt.tUnit) { // temperature + case 1: CheckRadioButton(hdlg, IDC_T1, IDC_T2, IDC_T1); break; + case 2: CheckRadioButton(hdlg, IDC_T1, IDC_T2, IDC_T2); break; + } + switch (opt.wUnit) { // wind + case 1: CheckRadioButton(hdlg, IDC_W1, IDC_W4, IDC_W1); break; + case 2: CheckRadioButton(hdlg, IDC_W1, IDC_W4, IDC_W2); break; + case 3: CheckRadioButton(hdlg, IDC_W1, IDC_W4, IDC_W3); break; + case 4: CheckRadioButton(hdlg, IDC_W1, IDC_W4, IDC_W4); break; + } + switch (opt.vUnit) { // visibility + case 1: CheckRadioButton(hdlg, IDC_V1, IDC_V2, IDC_V1); break; + case 2: CheckRadioButton(hdlg, IDC_V1, IDC_V2, IDC_V2); break; + } + switch (opt.pUnit) { // pressure + case 1: CheckRadioButton(hdlg, IDC_P1, IDC_P4, IDC_P1); break; + case 2: CheckRadioButton(hdlg, IDC_P1, IDC_P4, IDC_P2); break; + case 3: CheckRadioButton(hdlg, IDC_P1, IDC_P4, IDC_P3); break; + case 4: CheckRadioButton(hdlg, IDC_P1, IDC_P4, IDC_P4); break; + } + switch (opt.dUnit) { // pressure + case 1: CheckRadioButton(hdlg, IDC_D1, IDC_D3, IDC_D1); break; + case 2: CheckRadioButton(hdlg, IDC_D1, IDC_D3, IDC_D2); break; + case 3: CheckRadioButton(hdlg, IDC_D1, IDC_D3, IDC_D3); break; + } + + switch (opt.eUnit) { // elev + case 1: CheckRadioButton(hdlg, IDC_E1, IDC_E2, IDC_E1); break; + case 2: CheckRadioButton(hdlg, IDC_E1, IDC_E2, IDC_E2); break; + } + + opt_startup = FALSE; + return 0; + + case WM_COMMAND: + if (HIWORD(wparam) == BN_CLICKED && GetFocus() == (HWND)lparam) + if (!opt_startup) SendMessage(GetParent(hdlg), PSM_CHANGED, 0, 0); + if (!((LOWORD(wparam) == IDC_UPDATE || LOWORD(wparam) == IDC_DEGREE) && + (HIWORD(wparam) != EN_CHANGE || (HWND)lparam != GetFocus()))) + if (!opt_startup) SendMessage(GetParent(hdlg), PSM_CHANGED, 0, 0); + return 0; + + case WM_NOTIFY: + switch (((LPNMHDR)lparam)->code) { + case PSN_APPLY: + // change the status for weather protocol + if (IsDlgButtonChecked(hdlg, IDC_PROTOCOND) && opt.DefStn != NULL) { + old_status = status; + status = g_plugin.getWord(opt.DefStn, "StatusIcon", NOSTATUSDATA); + 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 = (WORD)_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 = (BYTE)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 0; +} + +//============ TEXT OPTION DIALOG ============ + +static void LoadTextSettings(HWND hdlg) +{ + // load text option settings from memory + SetDlgItemText(hdlg, IDC_CTEXT, opt.cText); + SetDlgItemText(hdlg, IDC_BTITLE, opt.bTitle); + SetDlgItemText(hdlg, IDC_BTEXT, opt.bText); + SetDlgItemText(hdlg, IDC_ETEXT, opt.eText); + SetDlgItemText(hdlg, IDC_NTEXT, opt.nText); + SetDlgItemText(hdlg, IDC_HTEXT, opt.hText); + SetDlgItemText(hdlg, IDC_XTEXT, opt.xText); + SetDlgItemText(hdlg, IDC_BTITLE2, opt.sText); +} + +// free the display text settings from memory +static void FreeTextVar(void) +{ + wfree(&opt.cText); + wfree(&opt.bText); + wfree(&opt.bTitle); + wfree(&opt.eText); + wfree(&opt.nText); + wfree(&opt.hText); + wfree(&opt.xText); + wfree(&opt.sText); +} + +// text option dialog + +static const char *varname[8] = { "C", "b", "B", "N", "X", "E", "H", "S" }; +static const int cname[8] = { IDC_CTEXT, IDC_BTITLE, IDC_BTEXT, IDC_NTEXT, IDC_XTEXT, IDC_ETEXT, IDC_HTEXT, IDC_BTITLE2 }; +static wchar_t* const *var[8] = { &opt.cText, &opt.bTitle, &opt.bText, &opt.nText, &opt.xText, &opt.eText, &opt.hText, &opt.sText }; + +static INT_PTR CALLBACK DlgProcText(HWND hdlg, UINT msg, WPARAM wParam, LPARAM lParam) +{ + RECT rc, pos; + HWND button; + HMENU hMenu, hMenu1; + wchar_t str[4096]; + switch (msg) { + case WM_INITDIALOG: + opt_startup = TRUE; + // set windows position, make it top-most + GetWindowRect(hdlg, &rc); + SetWindowPos(hdlg, HWND_TOPMOST, rc.left, rc.top, 0, 0, SWP_NOSIZE); + TranslateDialogDefault(hdlg); + // generate the display text for variable list + wcsncpy(str, VAR_LIST_OPT, _countof(str) - 1); + SetDlgItemText(hdlg, IDC_VARLIST, str); + + // 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 + LoadTextSettings(hdlg); + opt_startup = FALSE; + return TRUE; + + case WM_COMMAND: + if (opt_startup) return TRUE; + switch (LOWORD(wParam)) { + case IDC_CTEXT: + case IDC_BTITLE: + case IDC_BTEXT: + case IDC_NTEXT: + case IDC_XTEXT: + case IDC_ETEXT: + case IDC_HTEXT: + case IDC_BTITLE2: + if (HIWORD(wParam) == EN_CHANGE) + SendMessage(GetParent(hdlg), PSM_CHANGED, 0, 0); + break; + + case IDC_MORE: + // display custom variables list + MoreVarList(); + break; + + case IDC_TM1: + case IDC_TM2: + case IDC_TM3: + case IDC_TM4: + case IDC_TM5: + case IDC_TM6: + case IDC_TM7: + case IDC_TM8: + // 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); + 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); + GetDisplay(&winfo, *var[LOWORD(wParam) - IDC_TM1], str); + MessageBox(nullptr, str, TranslateT("Weather Protocol Text Preview"), MB_OK | MB_TOPMOST); + break; + } + case ID_MRESET: + unsigned varo = LOWORD(wParam) - IDC_TM1; + // remove the old setting from db and free memory + wchar_t* vartmp = *var[varo]; + wfree(&vartmp); + SetTextDefault(varname[varo]); + SetDlgItemText(hdlg, cname[varo], *var[varo]); + break; + } + DestroyMenu(hMenu); + break; + + case IDC_RESET: + // left click action selection menu + button = GetDlgItem(hdlg, IDC_RESET); + GetWindowRect(button, &pos); + hMenu = LoadMenu(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 + LoadTextSettings(hdlg); + break; + + case ID_T2: + // reset to the default setting + FreeTextVar(); + SetTextDefault("CbBENHX"); + LoadTextSettings(hdlg); + break; + } + DestroyMenu(hMenu); + break; + } + return TRUE; + case WM_NOTIFY: + switch (((LPNMHDR)lParam)->code) { + case PSN_APPLY: + // save the option + wchar_t textstr[MAX_TEXT_SIZE]; + // free memory for old settings + FreeTextVar(); + // save new settings to memory + GetDlgItemText(hdlg, IDC_CTEXT, textstr, _countof(textstr)); + wSetData(&opt.cText, textstr); + GetDlgItemText(hdlg, IDC_BTEXT, textstr, _countof(textstr)); + wSetData(&opt.bText, textstr); + GetDlgItemText(hdlg, IDC_BTITLE, textstr, _countof(textstr)); + wSetData(&opt.bTitle, textstr); + GetDlgItemText(hdlg, IDC_ETEXT, textstr, _countof(textstr)); + wSetData(&opt.eText, textstr); + GetDlgItemText(hdlg, IDC_NTEXT, textstr, _countof(textstr)); + wSetData(&opt.nText, textstr); + GetDlgItemText(hdlg, IDC_HTEXT, textstr, _countof(textstr)); + wSetData(&opt.hText, textstr); + GetDlgItemText(hdlg, IDC_XTEXT, textstr, _countof(textstr)); + wSetData(&opt.xText, textstr); + GetDlgItemText(hdlg, IDC_BTITLE2, textstr, _countof(textstr)); + wSetData(&opt.sText, textstr); + SaveOptions(); + UpdateAllInfo(0, 0); + break; + } + break; + } + return FALSE; +} + + +//============ OPTION INITIALIZATION ============ + +// register the weather option pages +int OptInit(WPARAM wParam, LPARAM) +{ + // plugin options + OPTIONSDIALOGPAGE odp = {}; + odp.position = 95600; + odp.pszTemplate = MAKEINTRESOURCEA(IDD_OPTIONS); + odp.pfnDlgProc = OptionsProc; + odp.szGroup.a = LPGEN("Network"); + odp.szTitle.a = WEATHERPROTOTEXT; + odp.szTab.a = LPGEN("General"); + odp.flags = ODPF_BOLDGROUPS; + g_plugin.addOptions(wParam, &odp); + + // text options + odp.pszTemplate = MAKEINTRESOURCEA(IDD_TEXTOPT); + odp.pfnDlgProc = DlgProcText; + odp.szTab.a = LPGEN("Display"); + g_plugin.addOptions(wParam, &odp); + + // if popup service exists, load the weather popup options + if ((ServiceExists(MS_POPUP_ADDPOPUPW))) { + odp.position = 100000000; + odp.pszTemplate = MAKEINTRESOURCEA(IDD_POPUP); + odp.szGroup.a = LPGEN("Popups"); + odp.szTab.a = nullptr; + odp.pfnDlgProc = DlgPopupOpts; + g_plugin.addOptions(wParam, &odp); + } + + return 0; +} diff --git a/protocols/Weather/src/weather_popup.cpp b/protocols/Weather/src/weather_popup.cpp new file mode 100644 index 0000000000..6e72d5595e --- /dev/null +++ b/protocols/Weather/src/weather_popup.cpp @@ -0,0 +1,428 @@ +/* +Weather Protocol plugin for Miranda IM +Copyright (c) 2012 Miranda NG team +Copyright (c) 2005-2009 Boris Krasnovskiy All Rights Reserved +Copyright (c) 2002-2005 Calvin Che + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; version 2 +of the License. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see <http://www.gnu.org/licenses/>. +*/ + +/* This file contain the source related to weather popups, including popup + options, popup display, and the code for popup process. +*/ + +#include "stdafx.h" + +// variables for weather_popup.c +static MCONTACT hPopupContact; + +//============ SHOW WEATHER POPUPS ============ + +//============ WEATHER ERROR POPUPS ============ + +// display weather error or notices (not threaded) +// wParam = error text +// lParam = display type +// Type can either be SM_WARNING, SM_NOTIFY, or SM_WEATHERALERT +int WeatherError(WPARAM wParam, LPARAM lParam) +{ + if (!opt.UsePopup) + return 0; + + wchar_t* tszMsg = (wchar_t*)wParam; + + if ((DWORD)lParam == SM_WARNING) + PUShowMessageW(tszMsg, SM_WARNING); + else if ((DWORD)lParam == SM_NOTIFY) + PUShowMessageW(tszMsg, SM_NOTIFY); + else if ((DWORD)lParam == SM_WEATHERALERT) { + POPUPDATAW ppd = { 0 }; + wchar_t str1[512], str2[512]; + + // get the 2 strings + wcsncpy(str1, tszMsg, _countof(str1) - 1); + wcsncpy(str2, tszMsg, _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); + else + str2[0] = 0; + + // setup the popup + ppd.lchIcon = (HICON)LoadImage(nullptr, MAKEINTRESOURCE(OIC_BANG), IMAGE_ICON, + GetSystemMetrics(SM_CXSMICON), GetSystemMetrics(SM_CYSMICON), LR_SHARED); + mir_wstrcpy(ppd.lpwzContactName, str1); + mir_wstrcpy(ppd.lpwzText, str2); + ppd.colorBack = (opt.UseWinColors) ? GetSysColor(COLOR_BTNFACE) : opt.BGColour; + ppd.colorText = (opt.UseWinColors) ? GetSysColor(COLOR_WINDOWTEXT) : opt.TextColour; + ppd.iSeconds = opt.pDelay; + PUAddPopupW(&ppd); + } + return 0; +} + +// wrapper function for displaying weather warning popup by triggering an event +// (threaded) +// lpzText = error text +// kind = display type (see m_popup.h) +int WPShowMessage(wchar_t* lpzText, WORD kind) +{ + NotifyEventHooks(hHookWeatherError, (WPARAM)lpzText, (LPARAM)kind); + return 0; +} + +//============ WEATHER POPUP PROCESSES ============ + +// popup dialog pocess +// for selecting actions when click on the popup window +// use for displaying contact menu +static LRESULT CALLBACK PopupDlgProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) +{ + DWORD ID = 0; + MCONTACT hContact; + hContact = PUGetContact(hWnd); + + switch (message) { + case WM_COMMAND: + ID = opt.LeftClickAction; + if (ID != IDM_M7) PUDeletePopup(hWnd); + SendMessage(hPopupWindow, ID, hContact, 0); + return TRUE; + + case WM_CONTEXTMENU: + ID = opt.RightClickAction; + if (ID != IDM_M7) PUDeletePopup(hWnd); + SendMessage(hPopupWindow, ID, hContact, 0); + return TRUE; + + case UM_FREEPLUGINDATA: + IcoLib_ReleaseIcon((HICON)PUGetPluginData(hWnd)); + return FALSE; + } + + 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) +{ + // determine if the popup should display or not + if (opt.UsePopup && opt.UpdatePopup && (!opt.PopupOnChange || (BOOL)lParam) && !g_plugin.getByte(hContact, "DPopUp")) { + WEATHERINFO winfo = LoadWeatherInfo(hContact); + + // setup the popup + POPUPDATAW ppd = { 0 }; + ppd.lchContact = hContact; + ppd.PluginData = ppd.lchIcon = Skin_LoadProtoIcon(MODULENAME, winfo.status); + GetDisplay(&winfo, opt.pTitle, ppd.lpwzContactName); + GetDisplay(&winfo, opt.pText, ppd.lpwzText); + ppd.PluginWindowProc = PopupDlgProc; + ppd.colorBack = (opt.UseWinColors) ? GetSysColor(COLOR_BTNFACE) : opt.BGColour; + ppd.colorText = (opt.UseWinColors) ? GetSysColor(COLOR_WINDOWTEXT) : opt.TextColour; + ppd.iSeconds = opt.pDelay; + PUAddPopupW(&ppd); + } + return 0; +} + + +// process for the popup window +// containing the code for popup actions +LRESULT CALLBACK PopupWndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) +{ + POINT pt; + HMENU hMenu; + switch (uMsg) { + case IDM_M2: // brief info + BriefInfo(wParam, 0); + break; + + case IDM_M3: // read complete forecast + LoadForecast(wParam, 0); + break; + + case IDM_M4: // display weather map + WeatherMap(wParam, 0); + break; + + case IDM_M5: // open history window + CallService(MS_HISTORY_SHOWCONTACTHISTORY, wParam, 0); + break; + + case IDM_M6: // open external log + ViewLog(wParam, 0); + break; + + case IDM_M7: // display contact menu + hMenu = Menu_BuildContactMenu(wParam); + GetCursorPos(&pt); + hPopupContact = wParam; + TrackPopupMenu(hMenu, TPM_LEFTALIGN, pt.x, pt.y, 0, hWnd, nullptr); + DestroyMenu(hMenu); + break; + + case IDM_M8: // display contact detail + CallService(MS_USERINFO_SHOWDIALOG, wParam, 0); + + case WM_COMMAND: //Needed by the contact's context menu + if (Clist_MenuProcessCommand(LOWORD(wParam), MPCF_CONTACTMENU, hPopupContact)) + break; + return FALSE; + + case WM_MEASUREITEM: //Needed by the contact's context menu + return Menu_MeasureItem(lParam); + + case WM_DRAWITEM: //Needed by the contact's context menu + return Menu_DrawItem(lParam); + } + + return DefWindowProc(hWnd, uMsg, wParam, lParam);//FALSE; +} + +//============ POPUP OPTIONS ============ + +// used to select the menu item for popup action menu +static void SelectMenuItem(HMENU hMenu, int Check) +{ + for (int i = 0; i <= GetMenuItemCount(hMenu) - 1; i++) + CheckMenuItem(hMenu, i, MF_BYPOSITION | ((int)GetMenuItemID(hMenu, i) == Check) * 8); +} + +// temporary read the current option to memory +// but does not write to the database +void ReadPopupOpt(HWND hdlg) +{ + wchar_t text[MAX_TEXT_SIZE]; + 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 = (BYTE)IsDlgButtonChecked(hdlg, IDC_USEWINCOLORS); + opt.UsePopup = (BYTE)IsDlgButtonChecked(hdlg, IDC_E); + opt.UpdatePopup = (BYTE)IsDlgButtonChecked(hdlg, IDC_POP1); + opt.AlertPopup = (BYTE)IsDlgButtonChecked(hdlg, IDC_POP2); + opt.PopupOnChange = (BYTE)IsDlgButtonChecked(hdlg, IDC_CH); + opt.ShowWarnings = (BYTE)IsDlgButtonChecked(hdlg, IDC_W); + + // popup texts + wfree(&opt.pText); + wfree(&opt.pTitle); + GetDlgItemText(hdlg, IDC_PText, text, _countof(text)); + wSetData(&opt.pText, text); + GetDlgItemText(hdlg, IDC_PTitle, text, _countof(text)); + wSetData(&opt.pTitle, text); +} + +// copied and modified from NewStatusNotify +INT_PTR CALLBACK DlgPopupOpts(HWND hdlg, UINT msg, WPARAM wParam, LPARAM lParam) +{ + int ID; + wchar_t str[512]; + HMENU hMenu, hMenu1; + RECT pos; + HWND button; + MCONTACT hContact; + + switch (msg) { + case WM_INITDIALOG: + TranslateDialogDefault(hdlg); + SaveOptions(); + + // click actions + 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)); + GetMenuString(hMenu1, opt.RightClickAction, str, _countof(str), MF_BYCOMMAND); + SetDlgItemText(hdlg, IDC_RightClick, TranslateW(str)); + DestroyMenu(hMenu); + + // other options + CheckDlgButton(hdlg, IDC_E, opt.UsePopup ? 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); + SetDlgItemText(hdlg, IDC_PText, opt.pText); + SetDlgItemText(hdlg, IDC_PTitle, opt.pTitle); + // setting popup delay option + _ltow(opt.pDelay, str, 10); + SetDlgItemText(hdlg, IDC_DELAY, str); + if (opt.pDelay == -1) + CheckRadioButton(hdlg, IDC_PD1, IDC_PD3, IDC_PD2); + else if (opt.pDelay == 0) + CheckRadioButton(hdlg, IDC_PD1, IDC_PD3, IDC_PD1); + else + CheckRadioButton(hdlg, IDC_PD1, IDC_PD3, IDC_PD3); + //Colours. First step is configuring the colours. + SendDlgItemMessage(hdlg, IDC_BGCOLOUR, CPM_SETCOLOUR, 0, opt.BGColour); + SendDlgItemMessage(hdlg, IDC_TEXTCOLOUR, CPM_SETCOLOUR, 0, opt.TextColour); + //Second step is disabling them if we want to use default Windows ones. + CheckDlgButton(hdlg, IDC_USEWINCOLORS, opt.UseWinColors ? BST_CHECKED : BST_UNCHECKED); + EnableWindow(GetDlgItem(hdlg, IDC_BGCOLOUR), !opt.UseWinColors); + EnableWindow(GetDlgItem(hdlg, IDC_TEXTCOLOUR), !opt.UseWinColors); + + // buttons + 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; + + case WM_COMMAND: + // enable the "apply" button + if (HIWORD(wParam) == BN_CLICKED && GetFocus() == (HWND)lParam) + SendMessage(GetParent(hdlg), PSM_CHANGED, 0, 0); + if (!((LOWORD(wParam) == IDC_UPDATE || LOWORD(wParam) == IDC_DEGREE) && + (HIWORD(wParam) != EN_CHANGE || (HWND)lParam != GetFocus()))) + SendMessage(GetParent(hdlg), PSM_CHANGED, 0, 0); + //These are simple clicks: we don't save, but we tell the Options Page to enable the "Apply" button. + switch (LOWORD(wParam)) { + case IDC_BGCOLOUR: //Fall through + case IDC_TEXTCOLOUR: + // select new colors + if (HIWORD(wParam) == CPN_COLOURCHANGED) + SendMessage(GetParent(hdlg), PSM_CHANGED, 0, 0); + break; + + case IDC_USEWINCOLORS: + // use window color - enable/disable color selection controls + EnableWindow(GetDlgItem(hdlg, IDC_BGCOLOUR), !(opt.UseWinColors)); + EnableWindow(GetDlgItem(hdlg, IDC_TEXTCOLOUR), !(opt.UseWinColors)); + SendMessage(GetParent(hdlg), PSM_CHANGED, 0, 0); + break; + + case IDC_E: + case IDC_CH: + SendMessage(GetParent(hdlg), PSM_CHANGED, 0, 0); + break; + + case IDC_RightClick: + // right click action selection menu + button = GetDlgItem(hdlg, IDC_RightClick); + GetWindowRect(button, &pos); + + hMenu = LoadMenu(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; + + 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; + + case IDC_PD1: + // Popup delay setting from Popup plugin + SetDlgItemText(hdlg, IDC_DELAY, L"0"); + CheckRadioButton(hdlg, IDC_PD1, IDC_PD3, IDC_PD1); + break; + + case IDC_PD2: + // Popup delay = permanent + SetDlgItemText(hdlg, IDC_DELAY, L"-1"); + CheckRadioButton(hdlg, IDC_PD1, IDC_PD3, IDC_PD2); + break; + + case IDC_DELAY: + // if text is edited + CheckRadioButton(hdlg, IDC_PD1, IDC_PD3, IDC_PD3); + break; + + case IDC_PDEF: + // set the default value for popup texts + SetTextDefault("Pp"); + SetDlgItemText(hdlg, IDC_PText, opt.pText); + SetDlgItemText(hdlg, IDC_PTitle, opt.pTitle); + wfree(&opt.pText); + wfree(&opt.pTitle); + break; + + case IDC_VAR3: + // display variable list + wcsncpy(str, L" \n", _countof(str) - 1); // to make the message box wider + mir_wstrncat(str, VAR_LIST_POPUP, _countof(str) - mir_wstrlen(str)); + mir_wstrncat(str, L"\n", _countof(str) - mir_wstrlen(str)); + mir_wstrncat(str, CUSTOM_VARS, _countof(str) - mir_wstrlen(str)); + MessageBox(nullptr, str, TranslateT("Variable List"), MB_OK | MB_ICONASTERISK | MB_TOPMOST); + break; + + case IDC_PREVIEW: + // popup preview + hContact = opt.DefStn; + ReadPopupOpt(hdlg); // read new options to memory + WeatherPopup((WPARAM)opt.DefStn, (BOOL)TRUE); // display popup using new opt + DestroyOptions(); + LoadOptions(); // restore old option in memory + opt.DefStn = hContact; + break; + } + break; + + case WM_NOTIFY: //Here we have pressed either the OK or the APPLY button. + switch (((LPNMHDR)lParam)->code) { + case PSN_APPLY: + ReadPopupOpt(hdlg); + + // save the options, and update main menu + SaveOptions(); + UpdatePopupMenu(opt.UsePopup); + return TRUE; + } + break; + } + return FALSE; +} diff --git a/protocols/Weather/src/weather_svcs.cpp b/protocols/Weather/src/weather_svcs.cpp new file mode 100644 index 0000000000..7c3d2611aa --- /dev/null +++ b/protocols/Weather/src/weather_svcs.cpp @@ -0,0 +1,375 @@ +/* +Weather Protocol plugin for Miranda IM +Copyright (c) 2012 Miranda NG team +Copyright (c) 2005-2011 Boris Krasnovskiy All Rights Reserved +Copyright (c) 2002-2005 Calvin Che + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; version 2 +of the License. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see <http://www.gnu.org/licenses/>. +*/ + +/* +This file contain the source related to weather protocol services +as required for a Miranda protocol. Also, it contains functions for +building/changing the weather menu items. +*/ + +#include "stdafx.h" + +static HGENMENU hEnableDisablePopupMenu; +static HGENMENU hEnableDisableMenu; + +//============ MIRANDA PROTOCOL SERVICES ============ + +// protocol service function for setting weather protocol status +INT_PTR WeatherSetStatus(WPARAM new_status, LPARAM) +{ + new_status = new_status != ID_STATUS_OFFLINE ? ID_STATUS_ONLINE : ID_STATUS_OFFLINE; + + // if we don't want to show status for default station + if (!opt.NoProtoCondition && status != new_status) { + old_status = status; + status = new_status != ID_STATUS_OFFLINE ? ID_STATUS_ONLINE : ID_STATUS_OFFLINE; + ProtoBroadcastAck(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_VISLIST | PF1_MODEMSGRECV; + break; + + case PFLAGNUM_2: + ret = PF2_ONLINE | PF2_INVISIBLE | PF2_SHORTAWAY | PF2_LONGAWAY | PF2_LIGHTDND | + PF2_HEAVYDND | PF2_FREECHAT | PF2_OUTTOLUNCH | PF2_ONTHEPHONE; + break; + + case PFLAGNUM_4: + ret = PF4_AVATARS | PF4_NOCUSTOMAUTH | PF4_NOAUTHDENYREASON | PF4_FORCEAUTH; + break; + + case PFLAGNUM_5: /* this is PFLAGNUM_5 change when alpha SDK is released */ + ret = PF2_INVISIBLE | PF2_SHORTAWAY | PF2_LONGAWAY | PF2_LIGHTDND | PF2_HEAVYDND | + PF2_FREECHAT | PF2_OUTTOLUNCH | PF2_ONTHEPHONE; + break; + + case PFLAG_UNIQUEIDTEXT: + ret = (INT_PTR)Translate("Station ID"); + break; + } + return ret; +} + +// protocol service function to get weather protocol name +INT_PTR WeatherGetName(WPARAM wParam, LPARAM lParam) +{ + strncpy((char*)lParam, WEATHERPROTOTEXT, wParam - 1); + *((char*)lParam + wParam - 1) = 0; + return 0; +} + +// protocol service function to get the current status of the protocol +INT_PTR WeatherGetStatus(WPARAM, 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(LoadIconEx("main", FALSE)) : 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 +static const wchar_t *statusStr[] = { L"Light", L"Fog", L"SShower", L"Snow", L"RShower", L"Rain", L"PCloudy", L"Cloudy", L"Sunny", L"NA" }; +static const WORD statusValue[] = { LIGHT, FOG, SSHOWER, SNOW, RSHOWER, RAIN, PCLOUDY, CLOUDY, SUNNY, NA }; + +INT_PTR WeatherGetAvatarInfo(WPARAM, LPARAM lParam) +{ + wchar_t szSearchPath[MAX_PATH], *chop; + unsigned i; + PROTO_AVATAR_INFORMATION *pai = (PROTO_AVATAR_INFORMATION*)lParam; + + GetModuleFileName(GetModuleHandle(nullptr), szSearchPath, _countof(szSearchPath)); + chop = wcsrchr(szSearchPath, '\\'); + + if (chop) *chop = '\0'; + else szSearchPath[0] = 0; + + int iStatus = g_plugin.getWord(pai->hContact, "StatusIcon"); + for (i = 0; i < 10; i++) + if (statusValue[i] == iStatus) + break; + + if (i >= 10) + return GAIR_NOAVATAR; + + pai->format = PA_FORMAT_PNG; + mir_snwprintf(pai->filename, L"%s\\Plugins\\Weather\\%s.png", szSearchPath, statusStr[i]); + if (_waccess(pai->filename, 4) == 0) + return GAIR_SUCCESS; + + pai->format = PA_FORMAT_GIF; + mir_snwprintf(pai->filename, L"%s\\Plugins\\Weather\\%s.gif", szSearchPath, statusStr[i]); + if (_waccess(pai->filename, 4) == 0) + return GAIR_SUCCESS; + + pai->format = PA_FORMAT_UNKNOWN; + pai->filename[0] = 0; + return GAIR_NOAVATAR; +} + +void AvatarDownloaded(MCONTACT hContact) +{ + PROTO_AVATAR_INFORMATION ai = { 0 }; + ai.hContact = hContact; + + if (WeatherGetAvatarInfo(GAIF_FORCE, (LPARAM)&ai) == GAIR_SUCCESS) + ProtoBroadcastAck(MODULENAME, 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; + DBVARIANT dbv; + if (!db_get_ws(hContact, "CList", "StatusMsg", &dbv)) { + ProtoBroadcastAck(MODULENAME, hContact, ACKTYPE_AWAYMSG, ACKRESULT_SUCCESS, (HANDLE)1, (LPARAM)dbv.pwszVal); + db_free(&dbv); + } + else ProtoBroadcastAck(MODULENAME, hContact, ACKTYPE_AWAYMSG, ACKRESULT_SUCCESS, (HANDLE)1); +} + +static INT_PTR WeatherGetAwayMsg(WPARAM, LPARAM lParam) +{ + CCSDATA* ccs = (CCSDATA*)lParam; + if (ccs == nullptr) + return 0; + + mir_forkthread(WeatherGetAwayMsgThread, (void*)ccs->hContact); + return 1; +} + +//============ PROTOCOL INITIALIZATION ============ +// protocol services +void InitServices(void) +{ + CreateProtoServiceFunction(MODULENAME, PS_GETCAPS, WeatherGetCaps); + CreateProtoServiceFunction(MODULENAME, PS_GETNAME, WeatherGetName); + 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, PSS_GETINFO, WeatherGetInfo); + CreateProtoServiceFunction(MODULENAME, PS_GETAVATARINFO, WeatherGetAvatarInfo); + CreateProtoServiceFunction(MODULENAME, PSS_GETAWAYMSG, WeatherGetAwayMsg); + CreateProtoServiceFunction(MODULENAME, PS_CREATEADVSEARCHUI, WeatherCreateAdvancedSearchUI); + CreateProtoServiceFunction(MODULENAME, PS_SEARCHBYADVANCED, WeatherAdvancedSearch); + + CreateProtoServiceFunction(MODULENAME, MS_WEATHER_GETDISPLAY, GetDisplaySvcFunc); +} + +//============ MENU INITIALIZATION ============ + +void UpdateMenu(BOOL State) +{ + // update option setting + opt.CAutoUpdate = State; + g_plugin.setByte("AutoUpdate", (BYTE)State); + + if (State) { // to enable auto-update + Menu_ModifyItem(hEnableDisableMenu, LPGENW("Auto Update Enabled"), GetIconHandle("main")); + opt.AutoUpdate = 1; + } + else { // to disable auto-update + Menu_ModifyItem(hEnableDisableMenu, LPGENW("Auto Update Disabled"), GetIconHandle("disabled")); + opt.AutoUpdate = 0; + } + + CallService(MS_TTB_SETBUTTONSTATE, (WPARAM)hTBButton, !State ? TTBST_PUSHED : 0); +} + +void UpdatePopupMenu(BOOL State) +{ + // update option setting + opt.UsePopup = State; + g_plugin.setByte("UsePopup", (BYTE)opt.UsePopup); + + if (State) // to enable popup + Menu_ModifyItem(hEnableDisablePopupMenu, LPGENW("Disable &weather notification"), GetIconHandle("popup")); + else // to disable popup + Menu_ModifyItem(hEnableDisablePopupMenu, LPGENW("Enable &weather notification"), GetIconHandle("nopopup")); +} + +// update the weather auto-update menu item when click on it +INT_PTR EnableDisableCmd(WPARAM wParam, LPARAM lParam) +{ + UpdateMenu(wParam == TRUE ? (BOOL)lParam : !opt.CAutoUpdate); + return 0; +} + +// update the weather popup menu item when click on it +INT_PTR MenuitemNotifyCmd(WPARAM, LPARAM) +{ + UpdatePopupMenu(!opt.UsePopup); + return 0; +} + +// adding weather contact menus +// copied and modified form "modified MSN Protocol" +void AddMenuItems(void) +{ + 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 = GetIconHandle("update"); + mi.name.a = LPGEN("Update Weather"); + mi.pszService = MS_WEATHER_UPDATE; + Menu_AddContactMenuItem(&mi, MODULENAME); + + SET_UID(mi, 0x45361b4, 0x8de, 0x44b4, 0x8f, 0x11, 0x9b, 0xe9, 0x6e, 0xa8, 0x83, 0x54); + CreateServiceFunction(MS_WEATHER_REFRESH, UpdateSingleRemove); + mi.position = -0x7FFFFFF9; + mi.hIcolibItem = GetIconHandle("update2"); + mi.name.a = LPGEN("Remove Old Data then Update"); + mi.pszService = MS_WEATHER_REFRESH; + Menu_AddContactMenuItem(&mi, MODULENAME); + + SET_UID(mi, 0x4232975e, 0xb181, 0x46a5, 0xb7, 0x6e, 0xd2, 0x5f, 0xef, 0xb8, 0xc4, 0x4d); + CreateServiceFunction(MS_WEATHER_BRIEF, BriefInfoSvc); + mi.position = -0x7FFFFFF8; + mi.hIcolibItem = GetIconHandle("brief"); + mi.name.a = LPGEN("Brief Information"); + mi.pszService = MS_WEATHER_BRIEF; + Menu_AddContactMenuItem(&mi, MODULENAME); + + SET_UID(mi, 0x3d6ed729, 0xd49a, 0x4ae9, 0x8e, 0x2, 0x9f, 0xe0, 0xf0, 0x2c, 0xcc, 0xb1); + CreateServiceFunction(MS_WEATHER_COMPLETE, LoadForecast); + mi.position = -0x7FFFFFF7; + mi.hIcolibItem = GetIconHandle("read"); + mi.name.a = LPGEN("Read Complete Forecast"); + mi.pszService = MS_WEATHER_COMPLETE; + Menu_AddContactMenuItem(&mi, MODULENAME); + + SET_UID(mi, 0xc4b6c5e0, 0x13c3, 0x4e02, 0x8a, 0xeb, 0xeb, 0x8a, 0xe2, 0x66, 0x40, 0xd4); + CreateServiceFunction(MS_WEATHER_MAP, WeatherMap); + mi.position = -0x7FFFFFF6; + mi.hIcolibItem = GetIconHandle("map"); + mi.name.a = LPGEN("Weather Map"); + mi.pszService = MS_WEATHER_MAP; + Menu_AddContactMenuItem(&mi, MODULENAME); + + SET_UID(mi, 0xee3ad7f4, 0x3377, 0x4e4c, 0x8f, 0x3c, 0x3b, 0xf5, 0xd4, 0x86, 0x28, 0x25); + CreateServiceFunction(MS_WEATHER_LOG, ViewLog); + mi.position = -0x7FFFFFF5; + mi.hIcolibItem = GetIconHandle("log"); + mi.name.a = LPGEN("View Log"); + mi.pszService = MS_WEATHER_LOG; + Menu_AddContactMenuItem(&mi, MODULENAME); + + SET_UID(mi, 0x1b01cd6a, 0xe5ee, 0x42b4, 0xa1, 0x6d, 0x43, 0xb9, 0x4, 0x58, 0x43, 0x2e); + CreateServiceFunction(MS_WEATHER_EDIT, EditSettings); + mi.position = -0x7FFFFFF4; + mi.hIcolibItem = GetIconHandle("edit"); + mi.name.a = LPGEN("Edit Settings"); + mi.pszService = MS_WEATHER_EDIT; + Menu_AddContactMenuItem(&mi, MODULENAME); + + // adding main menu items + mi.root = g_plugin.addRootMenu(MO_MAIN, LPGENW("Weather"), 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 = GetIconHandle("main"); + mi.position = 10100001; + mi.pszService = MS_WEATHER_ENABLED; + hEnableDisableMenu = Menu_AddMainMenuItem(&mi); + UpdateMenu(opt.AutoUpdate); + + SET_UID(mi, 0x2b1c2054, 0x2991, 0x4025, 0x87, 0x73, 0xb6, 0xf7, 0x85, 0xac, 0xc7, 0x37); + CreateServiceFunction(MS_WEATHER_UPDATEALL, UpdateAllInfo); + mi.position = 20100001; + mi.hIcolibItem = GetIconHandle("update"); + mi.name.a = LPGEN("Update All Weather"); + mi.pszService = MS_WEATHER_UPDATEALL; + Menu_AddMainMenuItem(&mi); + + SET_UID(mi, 0x8234c00e, 0x788e, 0x424f, 0xbc, 0xc4, 0x2, 0xfd, 0x67, 0x58, 0x2d, 0x19); + CreateServiceFunction(MS_WEATHER_REFRESHALL, UpdateAllRemove); + mi.position = 20100002; + mi.hIcolibItem = GetIconHandle("update2"); + mi.name.a = LPGEN("Remove Old Data then Update All"); + mi.pszService = MS_WEATHER_REFRESHALL; + Menu_AddMainMenuItem(&mi); + + // only run if popup service exists + if (ServiceExists(MS_POPUP_ADDPOPUPW)) { + SET_UID(mi, 0xdc5411cb, 0xb7c7, 0x443b, 0x88, 0x5a, 0x90, 0x24, 0x43, 0xde, 0x54, 0x3e); + CreateServiceFunction(MODULENAME "/PopupMenu", MenuitemNotifyCmd); + mi.name.a = LPGEN("Weather Notification"); + mi.hIcolibItem = GetIconHandle("popup"); + mi.position = 0; + mi.root = g_plugin.addRootMenu(MO_MAIN, LPGENW("Popups"), 0); + mi.pszService = MODULENAME "/PopupMenu"; + hEnableDisablePopupMenu = Menu_AddMainMenuItem(&mi); + UpdatePopupMenu(opt.UsePopup); + } + + 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); + } +} diff --git a/protocols/Weather/src/weather_update.cpp b/protocols/Weather/src/weather_update.cpp new file mode 100644 index 0000000000..12736b35be --- /dev/null +++ b/protocols/Weather/src/weather_update.cpp @@ -0,0 +1,607 @@ +/* +Weather Protocol plugin for Miranda IM +Copyright (c) 2012 Miranda NG team +Copyright (c) 2005-2011 Boris Krasnovskiy All Rights Reserved +Copyright (c) 2002-2005 Calvin Che + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; version 2 +of the License. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see <http://www.gnu.org/licenses/>. +*/ + +/* +This file contain the source related to updating new weather +information, both automatic (by timer) and manually (by selecting +menu items). +*/ + +#include "stdafx.h" + +UPDATELIST *UpdateListHead, *UpdateListTail; + +//============ RETRIEVE NEW WEATHER ============ +// +// retrieve weather info and display / log them +// hContact = current contact +int UpdateWeather(MCONTACT hContact) +{ + wchar_t str[256], str2[MAX_TEXT_SIZE]; + DBVARIANT dbv; + BOOL Ch = FALSE; + + if (hContact == NULL) // some error prevention + return 1; + + dbv.pszVal = ""; + + // log to netlib log for debug purpose + Netlib_LogfW(hNetlibUser, L"************************************************************************"); + int dbres = g_plugin.getWString(hContact, "Nick", &dbv); + + Netlib_LogfW(hNetlibUser, L"<-- Start update for station -->"); + + // download the info and parse it + // result are stored in database + int code = GetWeatherData(hContact); + if (code != 0) { + // error occurs if the return value is not equals to 0 + if (opt.ShowWarnings) { + // show warnings by popup + mir_snwprintf(str, _countof(str) - 105, + TranslateT("Unable to retrieve weather information for %s"), dbv.pwszVal); + mir_wstrncat(str, L"\n", _countof(str) - mir_wstrlen(str)); + wchar_t *tszError = GetError(code); + mir_wstrncat(str, tszError, _countof(str) - mir_wstrlen(str)); + WPShowMessage(str, SM_WARNING); + mir_free(tszError); + } + // 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); + return 1; + } + if (!dbres) db_free(&dbv); + + // initialize, load new weather Data + WEATHERINFO winfo = LoadWeatherInfo(hContact); + + // translate weather condition + mir_wstrcpy(winfo.cond, TranslateW(winfo.cond)); + + // 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 (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 (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 (mir_wstrcmpi(winfo.update, dbv.pwszVal)) Ch = TRUE; // the update time is changed + db_free(&dbv); + } + else Ch = TRUE; + } + + // 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) { + // display alert popup + mir_snwprintf(str, 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); + Skin_PlaySound("weatheralert"); + } + // alert dropped, set the display back to normal + else g_plugin.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); + + // display condition on contact list + if (opt.DisCondIcon && winfo.status != ID_STATUS_OFFLINE) + g_plugin.setWord(hContact, "Status", ID_STATUS_ONLINE); + else + g_plugin.setWord(hContact, "Status", winfo.status); + AvatarDownloaded(hContact); + + GetDisplay(&winfo, opt.cText, str2); + db_set_ws(hContact, "CList", "MyHandle", str2); + + GetDisplay(&winfo, opt.sText, str2); + if (str2[0]) + 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)); + + // save descriptions in MyNotes + GetDisplay(&winfo, opt.nText, str2); + db_set_ws(hContact, "UserInfo", "MyNotes", str2); + GetDisplay(&winfo, opt.xText, str2); + db_set_ws(hContact, WEATHERCONDITION, "WeatherInfo", str2); + + // 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 = winfo.status; + // 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); + } + + // logging + if (Ch) { + // play the sound event + Skin_PlaySound("weatherupdated"); + + if (g_plugin.getByte(hContact, "File")) { + // external log + if (!g_plugin.getWString(hContact, "Log", &dbv)) { + // for the option for overwriting the file, delete old file first + if (g_plugin.getByte(hContact, "Overwrite")) + DeleteFile(dbv.pwszVal); + + // open the file and set point to the end of file + FILE *file = _wfopen(dbv.pwszVal, L"a"); + db_free(&dbv); + if (file != nullptr) { + // write data to the file and close + GetDisplay(&winfo, opt.eText, str2); + fputws(str2, file); + fclose(file); + } + } + } + + if (g_plugin.getByte(hContact, "History")) { + // internal log using history + GetDisplay(&winfo, opt.hText, str2); + + T2Utf szMessage(str2); + + DBEVENTINFO dbei = {}; + dbei.szModule = MODULENAME; + dbei.timestamp = (DWORD)time(0); + dbei.flags = DBEF_READ | DBEF_UTF; + dbei.eventType = EVENTTYPE_MESSAGE; + dbei.pBlob = szMessage; + dbei.cbBlob = (DWORD)mir_strlen(szMessage) + 1; + db_event_add(hContact, &dbei); + } + + // show the popup + NotifyEventHooks(hHookWeatherUpdated, hContact, (LPARAM)Ch); + } + + Netlib_LogfW(hNetlibUser, L"Update Completed - Start to free memory"); + Netlib_LogfW(hNetlibUser, L"<-- Update successful for station -->"); + + // Update frame data + UpdateMwinData(hContact); + + // update brief info if its opened + HWND hMoreDataDlg = WindowList_Find(hDataWindowList, hContact); + if (hMoreDataDlg != nullptr) + PostMessage(hMoreDataDlg, WM_UPDATEDATA, 0, 0); + return 0; +} + +//============ UPDATE LIST ============ +// +// a linked list queue for updating weather station +// this function add a weather contact to the end of queue for update +// hContact = current contact +void UpdateListAdd(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); +} + +// get the first item from the update queue and remove it from the queue +// return value = the contact for next update +MCONTACT 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); + + return hContact; +} + +void 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); +} + +// update all weather thread +// this thread update each weather station from the queue +static void UpdateThreadProc(void *) +{ + WaitForSingleObject(hUpdateMutex, INFINITE); + if (ThreadRunning) { + ReleaseMutex(hUpdateMutex); + return; + } + ThreadRunning = TRUE; // prevent 2 instance of this thread running + ReleaseMutex(hUpdateMutex); + + // update weather by getting the first station from the queue until the queue is empty + while (UpdateListHead != nullptr && !Miranda_IsTerminated()) + UpdateWeather(UpdateGetFirst()); + + // exit the update thread + ThreadRunning = 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) +{ + // add all weather contact to the update queue list + for (auto &hContact : Contacts(MODULENAME)) + if (!g_plugin.getByte(hContact, "AutoUpdate") || !AutoUpdate) { + if (RemoveData) + DBDataManage(hContact, WDBM_REMOVE, 0, 0); + 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); +} + +// update a single station +// wParam = handle for the weather station that is going to be updated +INT_PTR UpdateSingleStation(WPARAM wParam, LPARAM) +{ + if (IsMyContact(wParam)) { + // add the station to the end of the update queue + UpdateListAdd(wParam); + + // if it is not updating, then start the update thread process + // if it is updating, the stations just added to the queue will get + // updated by the already-running process + if (!ThreadRunning) + mir_forkthread(UpdateThreadProc); + } + + 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) +{ + if (IsMyContact(wParam)) { + // add the station to the end of the update queue, and also remove old data + DBDataManage(wParam, WDBM_REMOVE, 0, 0); + UpdateListAdd(wParam); + + // if it is not updating, then start the update thread process + // if it is updating, the stations just added to the queue will get updated by the already-running process + if (!ThreadRunning) + mir_forkthread(UpdateThreadProc); + } + + return 0; +} + +// the "Update All" menu item in main menu +INT_PTR UpdateAllInfo(WPARAM, LPARAM) +{ + if (!ThreadRunning) + UpdateAll(FALSE, FALSE); + return 0; +} + +// the "Update All" menu item in main menu and remove the old data +INT_PTR UpdateAllRemove(WPARAM, LPARAM) +{ + if (!ThreadRunning) + UpdateAll(FALSE, TRUE); + return 0; +} + +//============ GETTING WEATHER DATA ============ +// +// getting weather data and save them into the database +// hContact = the contact to get the data +int GetWeatherData(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 + + WORD 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)); + break; + + case 1: + mir_snprintf(loc, Data->UpdateURL2, _T2A(id)); + break; + + case 2: + mir_snprintf(loc, Data->UpdateURL3, _T2A(id)); + break; + + case 3: + mir_snprintf(loc, Data->UpdateURL4, _T2A(id)); + break; + + default: + continue; + } + + if (loc[0] == 0) + continue; + + // 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; + } + + szInfo = szData; + WIDATAITEMLIST *Item = Data->UpdateData; + + // begin parsing item by item + while (Item != nullptr) { + if (Item->Item.Url[0] != 0 && Item->Item.Url[0] != (i + '1')) { + Item = Item->Next; + 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, 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; + } + } + + // 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, (DWORD)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; + } + mir_free(szData); + } + + // assign condition icon + g_plugin.setWord(hContact, "StatusIcon", cond); + g_plugin.setWString(hContact, "MirVer", Data->DisplayName); + return 0; +} + +//============ UPDATE TIMERS ============ +// +// main auto-update timer +void CALLBACK timerProc(HWND, UINT, UINT_PTR, DWORD) +{ + // 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)) + 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) +{ + KillTimer(nullptr, timerId); + ThreadRunning = FALSE; + + if (Miranda_IsTerminated()) + return; + + if (opt.StartupUpdate && opt.NoProtoCondition) + UpdateAll(FALSE, FALSE); + timerId = SetTimer(nullptr, 0, ((int)opt.UpdateTime) * 60000, timerProc); +} diff --git a/protocols/Weather/src/weather_userinfo.cpp b/protocols/Weather/src/weather_userinfo.cpp new file mode 100644 index 0000000000..3ce9460c1b --- /dev/null +++ b/protocols/Weather/src/weather_userinfo.cpp @@ -0,0 +1,358 @@ +/* +Weather Protocol plugin for Miranda IM +Copyright (c) 2012 Miranda NG team +Copyright (c) 2005-2011 Boris Krasnovskiy All Rights Reserved +Copyright (c) 2002-2005 Calvin Che + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; version 2 +of the License. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see <http://www.gnu.org/licenses/>. +*/ + + +/* +This file contain the source that is related to display contact +information, including the one shows in user detail and the brief +information +*/ + +#include "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; + + case IDC_MUPDATE: + return RD_ANCHORX_LEFT | RD_ANCHORY_BOTTOM; + + case IDC_MTOGGLE: + case IDC_MWEBPAGE: + case IDCANCEL: + return RD_ANCHORX_RIGHT | RD_ANCHORY_BOTTOM; + } + return RD_ANCHORX_LEFT | RD_ANCHORY_TOP; +} + +// 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) +{ + WEATHERINFO winfo; + wchar_t str[4096]; + + // load weather information from the contact into the WEATHERINFO struct + winfo = LoadWeatherInfo(hContact); + // check if data exist. If not, display error message box + if (!g_plugin.getByte(hContact, "IsUpdated")) + wcsncpy(str, WEATHER_NO_INFO, _countof(str) - 1); + else + // set the display text and show the message box + GetDisplay(&winfo, opt.bText, str); + SetDlgItemText(hwndDlg, IDC_MTEXT, str); + + GetDisplay(&winfo, L"%c, %t", str); + SetWindowText(hwndDlg, winfo.city); + SetDlgItemText(hwndDlg, IDC_HEADERBAR, str); +} + +// 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); + + switch (msg) { + case WM_INITDIALOG: + // save the contact handle for later use + hContact = lParam; + SetWindowLongPtr(hwndDlg, GWLP_USERDATA, (LONG_PTR)hContact); + + SendDlgItemMessage(hwndDlg, IDC_MTEXT, EM_AUTOURLDETECT, (WPARAM)TRUE, 0); + SendDlgItemMessage(hwndDlg, IDC_MTEXT, EM_SETEVENTMASK, 0, ENM_LINK); + SendDlgItemMessage(hwndDlg, IDC_MTEXT, EM_SETMARGINS, EC_LEFTMARGIN, 5); + SendDlgItemMessage(hwndDlg, IDC_MTEXT, EM_SETTABSTOPS, 1, (LPARAM)&tabstops); + + // get the list to display + { + LV_COLUMN lvc = { 0 }; + HWND hList = GetDlgItem(hwndDlg, IDC_DATALIST); + RECT aRect = { 0 }; + GetClientRect(hList, &aRect); + + // managing styles + lvc.mask = LVCF_WIDTH | LVCF_TEXT; + ListView_SetExtendedListViewStyleEx(hList, + LVS_EX_FULLROWSELECT | LVS_EX_INFOTIP, + LVS_EX_FULLROWSELECT | LVS_EX_INFOTIP); + + // inserting columns + lvc.cx = LIST_COLUMN; + lvc.pszText = TranslateT("Variable"); + ListView_InsertColumn(hList, 0, &lvc); + + lvc.cx = aRect.right - LIST_COLUMN - GetSystemMetrics(SM_CXVSCROLL) - 3; + lvc.pszText = TranslateT("Information"); + ListView_InsertColumn(hList, 1, &lvc); + + // inserting data + SendMessage(hwndDlg, WM_UPDATEDATA, 0, 0); + } + TranslateDialogDefault(hwndDlg); + + // prevent dups of the window + WindowList_Add(hDataWindowList, hwndDlg, hContact); + + // restore window position + Utils_RestoreWindowPositionNoMove(hwndDlg, NULL, MODULENAME, "BriefInfo_"); + return TRUE; + + case WM_UPDATEDATA: + ListView_DeleteAllItems(GetDlgItem(hwndDlg, IDC_DATALIST)); + LoadBriefInfoText(hwndDlg, hContact); + DBDataManage(hContact, WDBM_DETAILDISPLAY, (WPARAM)hwndDlg, 0); + + // set icons + Window_FreeIcon_IcoLib(hwndDlg); + Window_SetProtoIcon_IcoLib(hwndDlg, MODULENAME, g_plugin.getWord(hContact, "StatusIcon", 0)); + + RedrawWindow(GetDlgItem(hwndDlg, IDC_HEADERBAR), nullptr, nullptr, RDW_INVALIDATE | RDW_UPDATENOW); + break; + + case WM_SIZE: + { + RECT rc; + HWND hList = GetDlgItem(hwndDlg, IDC_DATALIST); + GetWindowRect(hList, &rc); + ListView_SetColumnWidth(hList, 1, ListView_GetColumnWidth(hList, 1) + (int)LOWORD(lParam) - (rc.right - rc.left)); + + Utils_ResizeDialog(hwndDlg, g_plugin.getInst(), MAKEINTRESOURCEA(IDD_BRIEF), BriefDlgResizer); + } + break; + + case WM_GETMINMAXINFO: + { + LPMINMAXINFO mmi = (LPMINMAXINFO)lParam; + + // The minimum width in points + mmi->ptMinTrackSize.x = 350; + // The minimum height in points + mmi->ptMinTrackSize.y = 300; + } + break; + + case WM_COMMAND: + switch (LOWORD(wParam)) { + case IDCANCEL: + // close the info window + DestroyWindow(hwndDlg); + break; + + case IDC_MUPDATE: + { + 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 = { 0 }; + 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; + } + + case IDC_MWEBPAGE: + LoadForecast(hContact, 0); // read complete forecast + break; + + case IDC_MTOGGLE: + if (IsWindowVisible(GetDlgItem(hwndDlg, IDC_DATALIST))) + SetDlgItemText(hwndDlg, IDC_MTOGGLE, TranslateT("More Info")); + else + SetDlgItemText(hwndDlg, IDC_MTOGGLE, TranslateT("Brief Info")); + ShowWindow(GetDlgItem(hwndDlg, IDC_DATALIST), (int)!IsWindowVisible( + GetDlgItem(hwndDlg, IDC_DATALIST))); + ShowWindow(GetDlgItem(hwndDlg, IDC_MTEXT), (int)!IsWindowVisible(GetDlgItem(hwndDlg, IDC_MTEXT))); + break; + } + break; + + case WM_NOTIFY: + { + LPNMHDR pNmhdr = (LPNMHDR)lParam; + if (pNmhdr->idFrom == IDC_MTEXT && pNmhdr->code == EN_LINK) { + ENLINK *enlink = (ENLINK *)lParam; + 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; + + case WM_CLOSE: + DestroyWindow(hwndDlg); + break; + + case WM_DESTROY: + Window_FreeIcon_IcoLib(hwndDlg); + Utils_SaveWindowPosition(hwndDlg, NULL, MODULENAME, "BriefInfo_"); + WindowList_Remove(hDataWindowList, hwndDlg); + break; + } + + return FALSE; +} + +// dialog process for the weather tab under user info +// lParam = current contact +static INT_PTR CALLBACK DlgProcUIPage(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam) +{ + WEATHERINFO w; + wchar_t str[MAX_TEXT_SIZE]; + + MCONTACT hContact = (MCONTACT)GetWindowLongPtr(hwndDlg, GWLP_USERDATA); + switch (msg) { + case WM_INITDIALOG: + TranslateDialogDefault(hwndDlg); + SendDlgItemMessage(hwndDlg, IDC_MOREDETAIL, BUTTONSETASFLATBTN, TRUE, 0); + // save the contact handle for later use + hContact = lParam; + SetWindowLongPtr(hwndDlg, GWLP_USERDATA, (LONG_PTR)hContact); + // load weather info for the contact + w = LoadWeatherInfo(lParam); + SetDlgItemText(hwndDlg, IDC_INFO1, GetDisplay(&w, TranslateT("Current condition for %n"), str)); + + SendDlgItemMessage(hwndDlg, IDC_INFOICON, STM_SETICON, (WPARAM)Skin_LoadProtoIcon(MODULENAME, g_plugin.getWord(hContact, "StatusIcon")), 0); + { + // bold and enlarge the current condition + LOGFONT lf; + HFONT hNormalFont = (HFONT)SendDlgItemMessage(hwndDlg, IDC_INFO2, WM_GETFONT, 0, 0); + GetObject(hNormalFont, sizeof(lf), &lf); + lf.lfWeight = FW_BOLD; + lf.lfWidth = 7; + lf.lfHeight = 15; + SendDlgItemMessage(hwndDlg, IDC_INFO2, WM_SETFONT, (WPARAM)CreateFontIndirect(&lf), 0); + } + // set the text for displaying other current weather conditions data + GetDisplay(&w, L"%c %t", str); + SetDlgItemText(hwndDlg, IDC_INFO2, str); + SetDlgItemText(hwndDlg, IDC_INFO3, w.feel); + SetDlgItemText(hwndDlg, IDC_INFO4, w.pressure); + GetDisplay(&w, L"%i %w", str); + SetDlgItemText(hwndDlg, IDC_INFO5, str); + SetDlgItemText(hwndDlg, IDC_INFO6, w.dewpoint); + SetDlgItemText(hwndDlg, IDC_INFO7, w.sunrise); + SetDlgItemText(hwndDlg, IDC_INFO8, w.sunset); + SetDlgItemText(hwndDlg, IDC_INFO9, w.high); + SetDlgItemText(hwndDlg, IDC_INFO10, w.low); + GetDisplay(&w, TranslateT("Last update on: %u"), str); + SetDlgItemText(hwndDlg, IDC_INFO11, str); + SetDlgItemText(hwndDlg, IDC_INFO12, w.humid); + SetDlgItemText(hwndDlg, IDC_INFO13, w.vis); + break; + + case WM_DESTROY: + IcoLib_ReleaseIcon((HICON)SendDlgItemMessage(hwndDlg, IDC_INFOICON, STM_SETICON, 0, 0)); + DeleteObject((HFONT)SendDlgItemMessage(hwndDlg, IDC_INFO2, WM_GETFONT, 0, 0)); + break; + + case WM_COMMAND: + switch (LOWORD(wParam)) { + case IDC_MOREDETAIL: + HWND hMoreDataDlg = WindowList_Find(hDataWindowList, hContact); + if (hMoreDataDlg == nullptr) + hMoreDataDlg = CreateDialogParam(g_plugin.getInst(), MAKEINTRESOURCE(IDD_BRIEF), nullptr, DlgProcMoreData, hContact); + else { + SetForegroundWindow(hMoreDataDlg); + SetFocus(hMoreDataDlg); + } + ShowWindow(GetDlgItem(hMoreDataDlg, IDC_MTEXT), 0); + ShowWindow(GetDlgItem(hMoreDataDlg, IDC_DATALIST), 1); + } + break; + } + return 0; +} + +//============ CONTACT INFORMATION ============ +// +// initialize user info +// lParam = current contact +int UserInfoInit(WPARAM wParam, LPARAM hContact) +{ + OPTIONSDIALOGPAGE odp = {}; + odp.position = 100000000; + odp.szTitle.a = MODULENAME; + + if (hContact == 0) { + odp.pszTemplate = MAKEINTRESOURCEA(IDD_INFO); + odp.pfnDlgProc = DlgProcINIPage; + g_plugin.addUserInfo(wParam, &odp); + } + else if (IsMyContact(hContact)) { // check if it is a weather contact + // register the contact info page + odp.pszTemplate = MAKEINTRESOURCEA(IDD_USERINFO); + odp.pfnDlgProc = DlgProcUIPage; + odp.flags = ODPF_BOLDGROUPS; + g_plugin.addUserInfo(wParam, &odp); + } + return 0; +} + + +// show brief information dialog +// wParam = current contact +int BriefInfo(WPARAM wParam, LPARAM) +{ + // make sure that the contact is actually a weather one + if (IsMyContact(wParam)) { + HWND hMoreDataDlg = WindowList_Find(hDataWindowList, wParam); + if (hMoreDataDlg != nullptr) { + SetForegroundWindow(hMoreDataDlg); + SetFocus(hMoreDataDlg); + } + else hMoreDataDlg = CreateDialogParam(g_plugin.getInst(), MAKEINTRESOURCE(IDD_BRIEF), nullptr, DlgProcMoreData, (LPARAM)wParam); + + ShowWindow(GetDlgItem(hMoreDataDlg, IDC_DATALIST), 0); + ShowWindow(GetDlgItem(hMoreDataDlg, IDC_MTEXT), 1); + SetDlgItemText(hMoreDataDlg, IDC_MTOGGLE, TranslateT("More Info")); + return 1; + } + return 0; +} + +INT_PTR BriefInfoSvc(WPARAM wParam, LPARAM lParam) +{ + return BriefInfo(wParam, lParam); +} diff --git a/protocols/Weather/weather.vcxproj b/protocols/Weather/weather.vcxproj new file mode 100644 index 0000000000..7624e51a7f --- /dev/null +++ b/protocols/Weather/weather.vcxproj @@ -0,0 +1,28 @@ +<?xml version="1.0" encoding="utf-8"?> +<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> + <ItemGroup Label="ProjectConfigurations"> + <ProjectConfiguration Include="Debug|Win32"> + <Configuration>Debug</Configuration> + <Platform>Win32</Platform> + </ProjectConfiguration> + <ProjectConfiguration Include="Debug|x64"> + <Configuration>Debug</Configuration> + <Platform>x64</Platform> + </ProjectConfiguration> + <ProjectConfiguration Include="Release|Win32"> + <Configuration>Release</Configuration> + <Platform>Win32</Platform> + </ProjectConfiguration> + <ProjectConfiguration Include="Release|x64"> + <Configuration>Release</Configuration> + <Platform>x64</Platform> + </ProjectConfiguration> + </ItemGroup> + <PropertyGroup Label="Globals"> + <ProjectName>Weather</ProjectName> + <ProjectGuid>{6BFE3E13-BD5D-4C1C-BB29-A82FB51A16CE}</ProjectGuid> + </PropertyGroup> + <ImportGroup Label="PropertySheets"> + <Import Project="$(ProjectDir)..\..\build\vc.common\plugin.props" /> + </ImportGroup> +</Project>
\ No newline at end of file diff --git a/protocols/Weather/weather.vcxproj.filters b/protocols/Weather/weather.vcxproj.filters new file mode 100644 index 0000000000..fcae13a9d8 --- /dev/null +++ b/protocols/Weather/weather.vcxproj.filters @@ -0,0 +1,4 @@ +<?xml version="1.0" encoding="utf-8"?> +<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> + <Import Project="$(ProjectDir)..\..\build\vc.common\common.filters" /> +</Project>
\ No newline at end of file |