From b61ba851da0157ace3bdfc1ebbf87156b0b76413 Mon Sep 17 00:00:00 2001 From: Kirill Volinsky Date: Wed, 6 Jun 2012 08:58:27 +0000 Subject: protocols plugins moved to protocols git-svn-id: http://svn.miranda-ng.org/main/trunk@327 1316c22d-e87f-b044-9b9b-93d7a3e3ba9c --- protocols/NewsAggregator/AtomText.txt | 482 ++++ protocols/NewsAggregator/NewsAggregator_10.sln | 26 + protocols/NewsAggregator/NewsAggregator_10.vcxproj | 210 ++ .../NewsAggregator_10.vcxproj.filters | 79 + protocols/NewsAggregator/Res/AddFeed.ico | Bin 0 -> 318 bytes protocols/NewsAggregator/Res/CheckALL.ico | Bin 0 -> 318 bytes protocols/NewsAggregator/Res/Export.ico | Bin 0 -> 318 bytes protocols/NewsAggregator/Res/Import.ico | Bin 0 -> 318 bytes protocols/NewsAggregator/Res/Main.ico | Bin 0 -> 6318 bytes protocols/NewsAggregator/Resource.rc | 148 ++ protocols/NewsAggregator/RssText.txt | 713 ++++++ protocols/NewsAggregator/Src/Common.h | 162 ++ protocols/NewsAggregator/Src/Entities.cpp | 381 +++ protocols/NewsAggregator/Src/Icons.cpp | 79 + protocols/NewsAggregator/Src/Menus.cpp | 78 + protocols/NewsAggregator/Src/NewsAggregator.cpp | 136 + protocols/NewsAggregator/Src/Options.cpp | 649 +++++ protocols/NewsAggregator/Src/Services.cpp | 240 ++ protocols/NewsAggregator/Src/Update.cpp | 147 ++ protocols/NewsAggregator/Src/Utils.cpp | 1404 +++++++++++ protocols/NewsAggregator/ToDo.txt | 11 + protocols/NewsAggregator/Version.h | 28 + protocols/NewsAggregator/Version.rc | 38 + protocols/NewsAggregator/resource.h | 39 + protocols/Quotes/Base64.cpp | 43 + protocols/Quotes/Base64.h | 12 + protocols/Quotes/Chart.h | 280 +++ protocols/Quotes/ComHelper.cpp | 39 + protocols/Quotes/ComHelper.h | 9 + protocols/Quotes/CommonOptionDlg.cpp | 272 ++ protocols/Quotes/CommonOptionDlg.h | 17 + protocols/Quotes/CreateFilePath.cpp | 45 + protocols/Quotes/CreateFilePath.h | 8 + protocols/Quotes/CurrencyConverter.cpp | 309 +++ protocols/Quotes/CurrencyConverter.h | 6 + protocols/Quotes/DBUtils.cpp | 70 + protocols/Quotes/DBUtils.h | 16 + protocols/Quotes/EconomicRateInfo.h | 59 + protocols/Quotes/ExtraImages.cpp | 143 ++ protocols/Quotes/ExtraImages.h | 39 + protocols/Quotes/Forex.cpp | 517 ++++ protocols/Quotes/Forex.rc | 573 +++++ protocols/Quotes/Forex.sln | 26 + protocols/Quotes/Forex.vcxproj | 289 +++ protocols/Quotes/Forex.vcxproj.filters | 307 +++ protocols/Quotes/HTMLParserMS.cpp | 313 +++ protocols/Quotes/HTMLParserMS.h | 36 + protocols/Quotes/HTTPSession.cpp | 262 ++ protocols/Quotes/HTTPSession.h | 27 + protocols/Quotes/IHTMLEngine.h | 18 + protocols/Quotes/IHTMLParser.h | 41 + protocols/Quotes/IQuotesProvider.h | 41 + protocols/Quotes/IXMLEngine.h | 43 + protocols/Quotes/IconLib.cpp | 106 + protocols/Quotes/IconLib.h | 21 + protocols/Quotes/ImportExport.cpp | 850 +++++++ protocols/Quotes/ImportExport.h | 11 + protocols/Quotes/IsWithinAccuracy.h | 15 + protocols/Quotes/LightMutex.cpp | 22 + protocols/Quotes/LightMutex.h | 34 + protocols/Quotes/Locale.cpp | 75 + protocols/Quotes/Locale.h | 9 + protocols/Quotes/Log.cpp | 56 + protocols/Quotes/Log.h | 13 + protocols/Quotes/ModuleInfo.cpp | 150 ++ protocols/Quotes/ModuleInfo.h | 46 + protocols/Quotes/OptionDukasCopy.cpp | 414 ++++ protocols/Quotes/OptionDukasCopy.h | 8 + protocols/Quotes/QuoteChart.cpp | 408 +++ protocols/Quotes/QuoteChart.h | 12 + protocols/Quotes/QuoteInfoDlg.cpp | 353 +++ protocols/Quotes/QuoteInfoDlg.h | 11 + protocols/Quotes/QuotesProviderBase.cpp | Bin 0 -> 59044 bytes protocols/Quotes/QuotesProviderBase.h | 112 + protocols/Quotes/QuotesProviderDukasCopy.cpp | Bin 0 -> 15324 bytes protocols/Quotes/QuotesProviderDukasCopy.h | 38 + protocols/Quotes/QuotesProviderFinance.cpp | 318 +++ protocols/Quotes/QuotesProviderFinance.h | 21 + protocols/Quotes/QuotesProviderGoogle.cpp | 543 ++++ protocols/Quotes/QuotesProviderGoogle.h | 42 + protocols/Quotes/QuotesProviderGoogleFinance.cpp | 366 +++ protocols/Quotes/QuotesProviderGoogleFinance.h | 25 + protocols/Quotes/QuotesProviderVisitor.h | 25 + .../Quotes/QuotesProviderVisitorDbSettings.cpp | 157 ++ protocols/Quotes/QuotesProviderVisitorDbSettings.h | 49 + .../QuotesProviderVisitorFormatSpecificator.cpp | 63 + .../QuotesProviderVisitorFormatSpecificator.h | 36 + protocols/Quotes/QuotesProviderVisitorFormater.cpp | 216 ++ protocols/Quotes/QuotesProviderVisitorFormater.h | 32 + protocols/Quotes/QuotesProviderVisitorTendency.cpp | 70 + protocols/Quotes/QuotesProviderVisitorTendency.h | 29 + protocols/Quotes/QuotesProviderYahoo.cpp | 193 ++ protocols/Quotes/QuotesProviderYahoo.h | 20 + protocols/Quotes/QuotesProviders.cpp | 120 + protocols/Quotes/QuotesProviders.h | 32 + protocols/Quotes/SettingsDlg.cpp | 1148 +++++++++ protocols/Quotes/SettingsDlg.h | 118 + protocols/Quotes/Utility/DukasCopy.py | 48 + protocols/Quotes/Utility/Dukascopy.xml | 1635 ++++++++++++ protocols/Quotes/Utility/Google.py | 52 + protocols/Quotes/Utility/GoogleFinance.xml | 7 + protocols/Quotes/Utility/Quotes_Readme.txt | 112 + protocols/Quotes/Utility/Yahoo.xml | 7 + protocols/Quotes/Utility/google.xml | 91 + protocols/Quotes/Version.rc | 41 + protocols/Quotes/WinCtrlHelper.cpp | 49 + protocols/Quotes/WinCtrlHelper.h | 37 + protocols/Quotes/WorkingThread.cpp | 15 + protocols/Quotes/WorkingThread.h | 6 + protocols/Quotes/XMLEngineMI.cpp | 230 ++ protocols/Quotes/XMLEngineMI.h | 17 + protocols/Quotes/dllmain.cpp | 23 + protocols/Quotes/proto_Quotes/proto_Quotes.rc | 122 + .../Quotes/proto_Quotes/proto_Quotes_10.vcxproj | 129 + .../proto_Quotes/proto_Quotes_10.vcxproj.filters | 28 + protocols/Quotes/res/CurrencyConverter.ico | Bin 0 -> 5430 bytes protocols/Quotes/res/Export quotes.ico | Bin 0 -> 1150 bytes protocols/Quotes/res/Import quotes.ico | Bin 0 -> 1150 bytes protocols/Quotes/res/Refresh.ico | Bin 0 -> 1406 bytes protocols/Quotes/res/Section.ico | Bin 0 -> 1406 bytes protocols/Quotes/res/down.ico | Bin 0 -> 1406 bytes protocols/Quotes/res/main.ico | Bin 0 -> 1150 bytes protocols/Quotes/res/notchanged.ico | Bin 0 -> 1406 bytes protocols/Quotes/res/proto_na.ico | Bin 0 -> 1406 bytes protocols/Quotes/res/proto_occupied.ico | Bin 0 -> 1406 bytes protocols/Quotes/res/proto_offline.ico | Bin 0 -> 1406 bytes protocols/Quotes/res/proto_online.ico | Bin 0 -> 1406 bytes protocols/Quotes/res/quote.ico | Bin 0 -> 1406 bytes protocols/Quotes/res/swap.ico | Bin 0 -> 318 bytes protocols/Quotes/res/up.ico | Bin 0 -> 1406 bytes protocols/Quotes/resource.h | 109 + protocols/Quotes/stdafx.cpp | 8 + protocols/Quotes/stdafx.h | 165 ++ protocols/Quotes/targetver.h | 24 + protocols/Quotes/version.h | 25 + protocols/Twitter/LICENSE.txt | 674 +++++ protocols/Twitter/README.txt | 10 + protocols/Twitter/chat.cpp | 206 ++ protocols/Twitter/common.h | 80 + protocols/Twitter/connection.cpp | 435 ++++ protocols/Twitter/contacts.cpp | 288 +++ protocols/Twitter/http.cpp | 39 + protocols/Twitter/http.h | 39 + protocols/Twitter/icons/twitter.ico | Bin 0 -> 1406 bytes protocols/Twitter/main.cpp | 168 ++ protocols/Twitter/proto.cpp | 528 ++++ protocols/Twitter/proto.h | 179 ++ protocols/Twitter/resource.h | 47 + protocols/Twitter/stubs.cpp | 140 ++ protocols/Twitter/theme.cpp | 183 ++ protocols/Twitter/theme.h | 25 + protocols/Twitter/tinyjson.hpp | 586 +++++ protocols/Twitter/twitter.cpp | 380 +++ protocols/Twitter/twitter.h | 96 + protocols/Twitter/twitter.rc | 224 ++ protocols/Twitter/twitter.sln | 26 + protocols/Twitter/twitter.vcxproj | 127 + protocols/Twitter/twitter.vcxproj.filters | 94 + protocols/Twitter/ui.cpp | 529 ++++ protocols/Twitter/ui.h | 25 + protocols/Twitter/utility.cpp | 133 + protocols/Twitter/utility.h | 107 + protocols/Twitter/version.h | 20 + protocols/YAMN/ChangeLog.txt | 243 ++ protocols/YAMN/YAMN_10.sln | 26 + protocols/YAMN/YAMN_10.vcxproj | 222 ++ protocols/YAMN/YAMN_10.vcxproj.filters | 131 + protocols/YAMN/YAMNopts.cpp | 2 + protocols/YAMN/account.cpp | 1309 ++++++++++ protocols/YAMN/browser/badconnect.cpp | 345 +++ protocols/YAMN/browser/m_browser.h | 42 + protocols/YAMN/browser/mailbrowser.cpp | 2605 ++++++++++++++++++++ protocols/YAMN/debug.cpp | 139 ++ protocols/YAMN/debug.h | 71 + protocols/YAMN/docs/InstallScript.xml | 49 + protocols/YAMN/docs/YAMN-License.txt | 340 +++ protocols/YAMN/docs/YAMN-Readme.developers.txt | 205 ++ protocols/YAMN/docs/YAMN-Readme.txt | 79 + protocols/YAMN/docs/language.pop3.txt | 118 + protocols/YAMN/docs/language.txt | 75 + protocols/YAMN/filter/Base/AggressiveOptimize.h | 168 ++ protocols/YAMN/filter/Base/Base.dsp | 108 + protocols/YAMN/filter/Base/Base.mak | 229 ++ protocols/YAMN/filter/Base/debug.cpp | 73 + protocols/YAMN/filter/Base/docs/base-readme.txt | 63 + protocols/YAMN/filter/Base/maindll.cpp | 238 ++ protocols/YAMN/filter/Simple/AggressiveOptimize.h | 168 ++ .../YAMN/filter/Simple/docs/simple-readme.txt | 51 + protocols/YAMN/filter/Simple/maindll.cpp | 132 + protocols/YAMN/filter/Simple/simple.dsp | 105 + protocols/YAMN/filter/Simple/simple.mak | 207 ++ protocols/YAMN/filter/readme.txt | 1 + protocols/YAMN/filterplugin.cpp | 204 ++ protocols/YAMN/icons/iconttbup.ico | Bin 0 -> 1150 bytes protocols/YAMN/icons/icoyamn1.ico | Bin 0 -> 1150 bytes protocols/YAMN/icons/icoyamn2.ico | Bin 0 -> 1150 bytes protocols/YAMN/icons/proto_YAMN.rc | 19 + protocols/YAMN/icons/proto_YAMN_10.vcxproj | 145 ++ protocols/YAMN/icons/proto_YAMN_10.vcxproj.filters | 37 + protocols/YAMN/icons/resource.h | 2 + protocols/YAMN/include/IcoLib.h | 26 + protocols/YAMN/mails/decode.cpp | 558 +++++ protocols/YAMN/mails/m_decode.h | 25 + protocols/YAMN/mails/mails.cpp | 499 ++++ protocols/YAMN/mails/mime.cpp | 732 ++++++ protocols/YAMN/mails/test/header.txt | 28 + protocols/YAMN/mails/test/header2.txt | 97 + protocols/YAMN/mails/test/readme.txt | 4 + protocols/YAMN/mails/test/test.cpp | 42 + protocols/YAMN/mails/test/test.dsp | 112 + protocols/YAMN/mails/test/test.dsw | 29 + protocols/YAMN/main.cpp | 566 +++++ protocols/YAMN/main.h | 61 + protocols/YAMN/mingw/base.dev | 69 + protocols/YAMN/mingw/base.win | 38 + protocols/YAMN/mingw/simple.dev | 59 + protocols/YAMN/mingw/simple.win | 35 + protocols/YAMN/mingw/yamn-2in1.dev | 469 ++++ protocols/YAMN/mingw/yamn-2in1.win | 92 + protocols/YAMN/mingw/yamn-w9x.dev | 469 ++++ protocols/YAMN/mingw/yamn-w9x.win | 92 + protocols/YAMN/mingw/yamn.dev | 469 ++++ protocols/YAMN/mingw/yamn.win | 92 + protocols/YAMN/proto/md5.c | 260 ++ protocols/YAMN/proto/md5.h | 27 + protocols/YAMN/proto/netclient.h | 22 + protocols/YAMN/proto/netlib.cpp | 271 ++ protocols/YAMN/proto/netlib.h | 55 + protocols/YAMN/proto/pop3/pop3.cpp | 370 +++ protocols/YAMN/proto/pop3/pop3.h | 66 + protocols/YAMN/proto/pop3/pop3comm.cpp | 1563 ++++++++++++ protocols/YAMN/proto/pop3/pop3comm.h | 97 + protocols/YAMN/proto/pop3/pop3opt.cpp | 1556 ++++++++++++ protocols/YAMN/proto/pop3/pop3opt.h | 42 + protocols/YAMN/protoplugin.cpp | 197 ++ protocols/YAMN/resources/YAMN.rc | 344 +++ protocols/YAMN/resources/iconeutral.ico | Bin 0 -> 1150 bytes protocols/YAMN/resources/iconttbdown.ico | Bin 0 -> 1150 bytes protocols/YAMN/resources/icooffline.ico | Bin 0 -> 1150 bytes protocols/YAMN/resources/icoyamn3.ico | Bin 0 -> 1150 bytes protocols/YAMN/resources/resource.h | 129 + protocols/YAMN/resources/yamn.bmp | Bin 0 -> 502 bytes protocols/YAMN/resources/yamn_ver.rc | 77 + protocols/YAMN/services.cpp | 515 ++++ protocols/YAMN/synchro.cpp | 359 +++ protocols/YAMN/version.h | 3 + protocols/YAMN/yamn.cpp | 334 +++ protocols/YAMN/yamn.h | 286 +++ 248 files changed, 42852 insertions(+) create mode 100644 protocols/NewsAggregator/AtomText.txt create mode 100644 protocols/NewsAggregator/NewsAggregator_10.sln create mode 100644 protocols/NewsAggregator/NewsAggregator_10.vcxproj create mode 100644 protocols/NewsAggregator/NewsAggregator_10.vcxproj.filters create mode 100644 protocols/NewsAggregator/Res/AddFeed.ico create mode 100644 protocols/NewsAggregator/Res/CheckALL.ico create mode 100644 protocols/NewsAggregator/Res/Export.ico create mode 100644 protocols/NewsAggregator/Res/Import.ico create mode 100644 protocols/NewsAggregator/Res/Main.ico create mode 100644 protocols/NewsAggregator/Resource.rc create mode 100644 protocols/NewsAggregator/RssText.txt create mode 100644 protocols/NewsAggregator/Src/Common.h create mode 100644 protocols/NewsAggregator/Src/Entities.cpp create mode 100644 protocols/NewsAggregator/Src/Icons.cpp create mode 100644 protocols/NewsAggregator/Src/Menus.cpp create mode 100644 protocols/NewsAggregator/Src/NewsAggregator.cpp create mode 100644 protocols/NewsAggregator/Src/Options.cpp create mode 100644 protocols/NewsAggregator/Src/Services.cpp create mode 100644 protocols/NewsAggregator/Src/Update.cpp create mode 100644 protocols/NewsAggregator/Src/Utils.cpp create mode 100644 protocols/NewsAggregator/ToDo.txt create mode 100644 protocols/NewsAggregator/Version.h create mode 100644 protocols/NewsAggregator/Version.rc create mode 100644 protocols/NewsAggregator/resource.h create mode 100644 protocols/Quotes/Base64.cpp create mode 100644 protocols/Quotes/Base64.h create mode 100644 protocols/Quotes/Chart.h create mode 100644 protocols/Quotes/ComHelper.cpp create mode 100644 protocols/Quotes/ComHelper.h create mode 100644 protocols/Quotes/CommonOptionDlg.cpp create mode 100644 protocols/Quotes/CommonOptionDlg.h create mode 100644 protocols/Quotes/CreateFilePath.cpp create mode 100644 protocols/Quotes/CreateFilePath.h create mode 100644 protocols/Quotes/CurrencyConverter.cpp create mode 100644 protocols/Quotes/CurrencyConverter.h create mode 100644 protocols/Quotes/DBUtils.cpp create mode 100644 protocols/Quotes/DBUtils.h create mode 100644 protocols/Quotes/EconomicRateInfo.h create mode 100644 protocols/Quotes/ExtraImages.cpp create mode 100644 protocols/Quotes/ExtraImages.h create mode 100644 protocols/Quotes/Forex.cpp create mode 100644 protocols/Quotes/Forex.rc create mode 100644 protocols/Quotes/Forex.sln create mode 100644 protocols/Quotes/Forex.vcxproj create mode 100644 protocols/Quotes/Forex.vcxproj.filters create mode 100644 protocols/Quotes/HTMLParserMS.cpp create mode 100644 protocols/Quotes/HTMLParserMS.h create mode 100644 protocols/Quotes/HTTPSession.cpp create mode 100644 protocols/Quotes/HTTPSession.h create mode 100644 protocols/Quotes/IHTMLEngine.h create mode 100644 protocols/Quotes/IHTMLParser.h create mode 100644 protocols/Quotes/IQuotesProvider.h create mode 100644 protocols/Quotes/IXMLEngine.h create mode 100644 protocols/Quotes/IconLib.cpp create mode 100644 protocols/Quotes/IconLib.h create mode 100644 protocols/Quotes/ImportExport.cpp create mode 100644 protocols/Quotes/ImportExport.h create mode 100644 protocols/Quotes/IsWithinAccuracy.h create mode 100644 protocols/Quotes/LightMutex.cpp create mode 100644 protocols/Quotes/LightMutex.h create mode 100644 protocols/Quotes/Locale.cpp create mode 100644 protocols/Quotes/Locale.h create mode 100644 protocols/Quotes/Log.cpp create mode 100644 protocols/Quotes/Log.h create mode 100644 protocols/Quotes/ModuleInfo.cpp create mode 100644 protocols/Quotes/ModuleInfo.h create mode 100644 protocols/Quotes/OptionDukasCopy.cpp create mode 100644 protocols/Quotes/OptionDukasCopy.h create mode 100644 protocols/Quotes/QuoteChart.cpp create mode 100644 protocols/Quotes/QuoteChart.h create mode 100644 protocols/Quotes/QuoteInfoDlg.cpp create mode 100644 protocols/Quotes/QuoteInfoDlg.h create mode 100644 protocols/Quotes/QuotesProviderBase.cpp create mode 100644 protocols/Quotes/QuotesProviderBase.h create mode 100644 protocols/Quotes/QuotesProviderDukasCopy.cpp create mode 100644 protocols/Quotes/QuotesProviderDukasCopy.h create mode 100644 protocols/Quotes/QuotesProviderFinance.cpp create mode 100644 protocols/Quotes/QuotesProviderFinance.h create mode 100644 protocols/Quotes/QuotesProviderGoogle.cpp create mode 100644 protocols/Quotes/QuotesProviderGoogle.h create mode 100644 protocols/Quotes/QuotesProviderGoogleFinance.cpp create mode 100644 protocols/Quotes/QuotesProviderGoogleFinance.h create mode 100644 protocols/Quotes/QuotesProviderVisitor.h create mode 100644 protocols/Quotes/QuotesProviderVisitorDbSettings.cpp create mode 100644 protocols/Quotes/QuotesProviderVisitorDbSettings.h create mode 100644 protocols/Quotes/QuotesProviderVisitorFormatSpecificator.cpp create mode 100644 protocols/Quotes/QuotesProviderVisitorFormatSpecificator.h create mode 100644 protocols/Quotes/QuotesProviderVisitorFormater.cpp create mode 100644 protocols/Quotes/QuotesProviderVisitorFormater.h create mode 100644 protocols/Quotes/QuotesProviderVisitorTendency.cpp create mode 100644 protocols/Quotes/QuotesProviderVisitorTendency.h create mode 100644 protocols/Quotes/QuotesProviderYahoo.cpp create mode 100644 protocols/Quotes/QuotesProviderYahoo.h create mode 100644 protocols/Quotes/QuotesProviders.cpp create mode 100644 protocols/Quotes/QuotesProviders.h create mode 100644 protocols/Quotes/SettingsDlg.cpp create mode 100644 protocols/Quotes/SettingsDlg.h create mode 100644 protocols/Quotes/Utility/DukasCopy.py create mode 100644 protocols/Quotes/Utility/Dukascopy.xml create mode 100644 protocols/Quotes/Utility/Google.py create mode 100644 protocols/Quotes/Utility/GoogleFinance.xml create mode 100644 protocols/Quotes/Utility/Quotes_Readme.txt create mode 100644 protocols/Quotes/Utility/Yahoo.xml create mode 100644 protocols/Quotes/Utility/google.xml create mode 100644 protocols/Quotes/Version.rc create mode 100644 protocols/Quotes/WinCtrlHelper.cpp create mode 100644 protocols/Quotes/WinCtrlHelper.h create mode 100644 protocols/Quotes/WorkingThread.cpp create mode 100644 protocols/Quotes/WorkingThread.h create mode 100644 protocols/Quotes/XMLEngineMI.cpp create mode 100644 protocols/Quotes/XMLEngineMI.h create mode 100644 protocols/Quotes/dllmain.cpp create mode 100644 protocols/Quotes/proto_Quotes/proto_Quotes.rc create mode 100644 protocols/Quotes/proto_Quotes/proto_Quotes_10.vcxproj create mode 100644 protocols/Quotes/proto_Quotes/proto_Quotes_10.vcxproj.filters create mode 100644 protocols/Quotes/res/CurrencyConverter.ico create mode 100644 protocols/Quotes/res/Export quotes.ico create mode 100644 protocols/Quotes/res/Import quotes.ico create mode 100644 protocols/Quotes/res/Refresh.ico create mode 100644 protocols/Quotes/res/Section.ico create mode 100644 protocols/Quotes/res/down.ico create mode 100644 protocols/Quotes/res/main.ico create mode 100644 protocols/Quotes/res/notchanged.ico create mode 100644 protocols/Quotes/res/proto_na.ico create mode 100644 protocols/Quotes/res/proto_occupied.ico create mode 100644 protocols/Quotes/res/proto_offline.ico create mode 100644 protocols/Quotes/res/proto_online.ico create mode 100644 protocols/Quotes/res/quote.ico create mode 100644 protocols/Quotes/res/swap.ico create mode 100644 protocols/Quotes/res/up.ico create mode 100644 protocols/Quotes/resource.h create mode 100644 protocols/Quotes/stdafx.cpp create mode 100644 protocols/Quotes/stdafx.h create mode 100644 protocols/Quotes/targetver.h create mode 100644 protocols/Quotes/version.h create mode 100644 protocols/Twitter/LICENSE.txt create mode 100644 protocols/Twitter/README.txt create mode 100644 protocols/Twitter/chat.cpp create mode 100644 protocols/Twitter/common.h create mode 100644 protocols/Twitter/connection.cpp create mode 100644 protocols/Twitter/contacts.cpp create mode 100644 protocols/Twitter/http.cpp create mode 100644 protocols/Twitter/http.h create mode 100644 protocols/Twitter/icons/twitter.ico create mode 100644 protocols/Twitter/main.cpp create mode 100644 protocols/Twitter/proto.cpp create mode 100644 protocols/Twitter/proto.h create mode 100644 protocols/Twitter/resource.h create mode 100644 protocols/Twitter/stubs.cpp create mode 100644 protocols/Twitter/theme.cpp create mode 100644 protocols/Twitter/theme.h create mode 100644 protocols/Twitter/tinyjson.hpp create mode 100644 protocols/Twitter/twitter.cpp create mode 100644 protocols/Twitter/twitter.h create mode 100644 protocols/Twitter/twitter.rc create mode 100644 protocols/Twitter/twitter.sln create mode 100644 protocols/Twitter/twitter.vcxproj create mode 100644 protocols/Twitter/twitter.vcxproj.filters create mode 100644 protocols/Twitter/ui.cpp create mode 100644 protocols/Twitter/ui.h create mode 100644 protocols/Twitter/utility.cpp create mode 100644 protocols/Twitter/utility.h create mode 100644 protocols/Twitter/version.h create mode 100644 protocols/YAMN/ChangeLog.txt create mode 100644 protocols/YAMN/YAMN_10.sln create mode 100644 protocols/YAMN/YAMN_10.vcxproj create mode 100644 protocols/YAMN/YAMN_10.vcxproj.filters create mode 100644 protocols/YAMN/YAMNopts.cpp create mode 100644 protocols/YAMN/account.cpp create mode 100644 protocols/YAMN/browser/badconnect.cpp create mode 100644 protocols/YAMN/browser/m_browser.h create mode 100644 protocols/YAMN/browser/mailbrowser.cpp create mode 100644 protocols/YAMN/debug.cpp create mode 100644 protocols/YAMN/debug.h create mode 100644 protocols/YAMN/docs/InstallScript.xml create mode 100644 protocols/YAMN/docs/YAMN-License.txt create mode 100644 protocols/YAMN/docs/YAMN-Readme.developers.txt create mode 100644 protocols/YAMN/docs/YAMN-Readme.txt create mode 100644 protocols/YAMN/docs/language.pop3.txt create mode 100644 protocols/YAMN/docs/language.txt create mode 100644 protocols/YAMN/filter/Base/AggressiveOptimize.h create mode 100644 protocols/YAMN/filter/Base/Base.dsp create mode 100644 protocols/YAMN/filter/Base/Base.mak create mode 100644 protocols/YAMN/filter/Base/debug.cpp create mode 100644 protocols/YAMN/filter/Base/docs/base-readme.txt create mode 100644 protocols/YAMN/filter/Base/maindll.cpp create mode 100644 protocols/YAMN/filter/Simple/AggressiveOptimize.h create mode 100644 protocols/YAMN/filter/Simple/docs/simple-readme.txt create mode 100644 protocols/YAMN/filter/Simple/maindll.cpp create mode 100644 protocols/YAMN/filter/Simple/simple.dsp create mode 100644 protocols/YAMN/filter/Simple/simple.mak create mode 100644 protocols/YAMN/filter/readme.txt create mode 100644 protocols/YAMN/filterplugin.cpp create mode 100644 protocols/YAMN/icons/iconttbup.ico create mode 100644 protocols/YAMN/icons/icoyamn1.ico create mode 100644 protocols/YAMN/icons/icoyamn2.ico create mode 100644 protocols/YAMN/icons/proto_YAMN.rc create mode 100644 protocols/YAMN/icons/proto_YAMN_10.vcxproj create mode 100644 protocols/YAMN/icons/proto_YAMN_10.vcxproj.filters create mode 100644 protocols/YAMN/icons/resource.h create mode 100644 protocols/YAMN/include/IcoLib.h create mode 100644 protocols/YAMN/mails/decode.cpp create mode 100644 protocols/YAMN/mails/m_decode.h create mode 100644 protocols/YAMN/mails/mails.cpp create mode 100644 protocols/YAMN/mails/mime.cpp create mode 100644 protocols/YAMN/mails/test/header.txt create mode 100644 protocols/YAMN/mails/test/header2.txt create mode 100644 protocols/YAMN/mails/test/readme.txt create mode 100644 protocols/YAMN/mails/test/test.cpp create mode 100644 protocols/YAMN/mails/test/test.dsp create mode 100644 protocols/YAMN/mails/test/test.dsw create mode 100644 protocols/YAMN/main.cpp create mode 100644 protocols/YAMN/main.h create mode 100644 protocols/YAMN/mingw/base.dev create mode 100644 protocols/YAMN/mingw/base.win create mode 100644 protocols/YAMN/mingw/simple.dev create mode 100644 protocols/YAMN/mingw/simple.win create mode 100644 protocols/YAMN/mingw/yamn-2in1.dev create mode 100644 protocols/YAMN/mingw/yamn-2in1.win create mode 100644 protocols/YAMN/mingw/yamn-w9x.dev create mode 100644 protocols/YAMN/mingw/yamn-w9x.win create mode 100644 protocols/YAMN/mingw/yamn.dev create mode 100644 protocols/YAMN/mingw/yamn.win create mode 100644 protocols/YAMN/proto/md5.c create mode 100644 protocols/YAMN/proto/md5.h create mode 100644 protocols/YAMN/proto/netclient.h create mode 100644 protocols/YAMN/proto/netlib.cpp create mode 100644 protocols/YAMN/proto/netlib.h create mode 100644 protocols/YAMN/proto/pop3/pop3.cpp create mode 100644 protocols/YAMN/proto/pop3/pop3.h create mode 100644 protocols/YAMN/proto/pop3/pop3comm.cpp create mode 100644 protocols/YAMN/proto/pop3/pop3comm.h create mode 100644 protocols/YAMN/proto/pop3/pop3opt.cpp create mode 100644 protocols/YAMN/proto/pop3/pop3opt.h create mode 100644 protocols/YAMN/protoplugin.cpp create mode 100644 protocols/YAMN/resources/YAMN.rc create mode 100644 protocols/YAMN/resources/iconeutral.ico create mode 100644 protocols/YAMN/resources/iconttbdown.ico create mode 100644 protocols/YAMN/resources/icooffline.ico create mode 100644 protocols/YAMN/resources/icoyamn3.ico create mode 100644 protocols/YAMN/resources/resource.h create mode 100644 protocols/YAMN/resources/yamn.bmp create mode 100644 protocols/YAMN/resources/yamn_ver.rc create mode 100644 protocols/YAMN/services.cpp create mode 100644 protocols/YAMN/synchro.cpp create mode 100644 protocols/YAMN/version.h create mode 100644 protocols/YAMN/yamn.cpp create mode 100644 protocols/YAMN/yamn.h (limited to 'protocols') diff --git a/protocols/NewsAggregator/AtomText.txt b/protocols/NewsAggregator/AtomText.txt new file mode 100644 index 0000000000..052516a6bb --- /dev/null +++ b/protocols/NewsAggregator/AtomText.txt @@ -0,0 +1,482 @@ + + + + 2012-01-04T06:45:38Z + http://code.google.com/feeds/p/watcher-miranda/updates/basic + + watcher-miranda project updates - Google Code + + + + + + 2012-01-04T06:45:38Z + http://code.google.com/feeds/p/watcher-miranda/updates/basic/z12pftbjzm31hlgp204cepjgmoicsl1oq1w + + <a class="ot-download-link" href="http://code.google.com/p/watcher-miranda/downloads/detail?name=miranda-0.10.latest-vc2010_x64-static.7z">miranda-0.10.latest-vc2010_x64-static.7z</a> (Miranda IM 0.10.0 Alpha #2 VC2010 x64) file uploaded by <a class="ot-profile-link-2" href="http://code.google.com/u/watcherhd/">watcherhd</a> + + watcherhd + + + <div class="ot-labels-field-wrapper"> + <span class="ot-labels-field-name">Labels: </span> + <span class="ot-labels-field-value"> + + + <span class="ot-field-label">Featured</span> + + + </span> + </div> + + + + + 2012-01-03T21:06:03Z + http://code.google.com/feeds/p/watcher-miranda/updates/basic/z12qdzfqdumlchjgm04cepjgmoicsl1oq1w + + <a class="ot-download-link" href="http://code.google.com/p/watcher-miranda/downloads/detail?name=miranda-v0100a2w11.7z">miranda-v0100a2w11.7z</a> (T - ) file uploaded by <a class="ot-profile-link-2" href="http://code.google.com/u/watcherhd/">watcherhd</a> + + watcherhd + + + <div class="ot-labels-field-wrapper"> + <span class="ot-labels-field-name">Labels: </span> + <span class="ot-labels-field-value"> + + + <span class="ot-field-label">Featured</span> + + + </span> + </div> + + + + + 2012-01-03T20:47:25Z + http://code.google.com/feeds/p/watcher-miranda/updates/basic/z135ypx45kehgtcq304cepjgmoicsl1oq1w + + <a class="ot-download-link" href="http://code.google.com/p/watcher-miranda/downloads/detail?name=miranda-v0100a2w11.7z">miranda-v0100a2w11.7z</a> (Miranda IM 0.10.0 Alpha #2 VC6111) file uploaded by <a class="ot-profile-link-2" href="http://code.google.com/u/watcherhd/">watcherhd</a> + + watcherhd + + + <div class="ot-labels-field-wrapper"> + <span class="ot-labels-field-name">Labels: </span> + <span class="ot-labels-field-value"> + + + <span class="ot-field-label">Featured</span> + + + </span> + </div> + + + + + 2012-01-03T09:21:55Z + http://code.google.com/feeds/p/watcher-miranda/updates/basic/z12szb1zzybuejnnv22pfv4p3ma4ch5kj + + <a class="ot-download-link" href="http://code.google.com/p/watcher-miranda/downloads/detail?name=mirotr1.7z">mirotr1.7z</a> (Miranda IM 0.10.0 Alpha #2 VC6) file uploaded by <a class="ot-profile-link-2" href="http://code.google.com/u/watcherhd/">watcherhd</a> + + watcherhd + + + <div class="ot-labels-field-wrapper"> + <span class="ot-labels-field-name">Labels: </span> + <span class="ot-labels-field-value"> + + + <span class="ot-field-label">Featured</span> + + + </span> + </div> + + + + + 2012-01-02T20:12:28Z + http://code.google.com/feeds/p/watcher-miranda/updates/basic/z12ltxpzuvr4xvahk04cepjgmoicsl1oq1w + + <a class="ot-download-link" href="http://code.google.com/p/watcher-miranda/downloads/detail?name=miranda32.exe">miranda32.exe</a> (Miranda32 v.0.9.40.0) file uploaded by <a class="ot-profile-link-2" href="http://code.google.com/u/watcherhd/">watcherhd</a> + + watcherhd + + + <div class="ot-labels-field-wrapper"> + <span class="ot-labels-field-name">Labels: </span> + <span class="ot-labels-field-value"> + + + <span class="ot-field-label">Featured</span> + + + </span> + </div> + + + + + 2012-01-01T18:00:06Z + http://code.google.com/feeds/p/watcher-miranda/updates/basic/z13idtjadwu5y3q2322pfv4p3ma4ch5kj + + <a class="ot-download-link" href="http://code.google.com/p/watcher-miranda/downloads/detail?name=Miranda%20IM%20Watcher%20Pack%20v3.1.0.exe">Miranda IM Watcher Pack v3.1.0.exe</a> (Miranda IM Watcher Pack v3.1.0) file uploaded by <a class="ot-profile-link-2" href="http://code.google.com/u/watcherhd/">watcherhd</a> + + watcherhd + + + <div class="ot-labels-field-wrapper"> + <span class="ot-labels-field-name">Labels: </span> + <span class="ot-labels-field-value"> + + + <span class="ot-field-label">Featured</span> + + + + <span class="ot-field-label">Type-Installer</span> + + + + <span class="ot-field-label">OpSys-Windows</span> + + + </span> + </div> + + + + + 2011-12-30T11:06:47Z + http://code.google.com/feeds/p/watcher-miranda/updates/basic/z12vzfygpwqng3m3b22pfv4p3ma4ch5kj + + <a class="ot-download-link" href="http://code.google.com/p/watcher-miranda/downloads/detail?name=Miranda_Empoli_Pack_Mod.exe">Miranda_Empoli_Pack_Mod.exe</a> (Miranda IM Empoli Pack Mod v.2.2 (core 0.9.39)) file uploaded by <a class="ot-profile-link-2" href="http://code.google.com/u/watcherhd/">watcherhd</a> + + watcherhd + + + <div class="ot-labels-field-wrapper"> + <span class="ot-labels-field-name">Labels: </span> + <span class="ot-labels-field-value"> + + + <span class="ot-field-label">Featured</span> + + + </span> + </div> + + + + + 2011-12-29T14:08:24Z + http://code.google.com/feeds/p/watcher-miranda/updates/basic/z135in4x1yi1fd2ou04cepjgmoicsl1oq1w + + <a class="ot-download-link" href="http://code.google.com/p/watcher-miranda/downloads/detail?name=mirotr.7z">mirotr.7z</a> (MirOTR 0.11.0.3) file uploaded by <a class="ot-profile-link-2" href="http://code.google.com/u/watcherhd/">watcherhd</a> + + watcherhd + + + <div class="ot-labels-field-wrapper"> + <span class="ot-labels-field-name">Labels: </span> + <span class="ot-labels-field-value"> + + + <span class="ot-field-label">Featured</span> + + + </span> + </div> + + + + + 2011-12-25T10:59:24Z + http://code.google.com/feeds/p/watcher-miranda/updates/basic/z13dgrs5elfkfp0n122pfv4p3ma4ch5kj + + <a class="ot-download-link" href="http://code.google.com/p/watcher-miranda/downloads/detail?name=LangpackSuite.exe">LangpackSuite.exe</a> (Test upload) file uploaded by <a class="ot-profile-link-2" href="http://code.google.com/u/watcherhd/">watcherhd</a> + + watcherhd + + + <div class="ot-labels-field-wrapper"> + <span class="ot-labels-field-name">Labels: </span> + <span class="ot-labels-field-value"> + + + <span class="ot-field-label">Featured</span> + + + </span> + </div> + + + + + 2011-12-25T10:58:18Z + http://code.google.com/feeds/p/watcher-miranda/updates/basic/z13cu14hyzzawjmev22pfv4p3ma4ch5kj + + <a class="ot-download-link" href="http://code.google.com/p/watcher-miranda/downloads/detail?name=LangpackSuite.exe">LangpackSuite.exe</a> (Test) file uploaded by <a class="ot-profile-link-2" href="http://code.google.com/u/watcherhd/">watcherhd</a> + + watcherhd + + + <div class="ot-labels-field-wrapper"> + <span class="ot-labels-field-name">Labels: </span> + <span class="ot-labels-field-value"> + + + <span class="ot-field-label">Featured</span> + + + </span> + </div> + + + + + 2011-12-21T21:55:28Z + http://code.google.com/feeds/p/watcher-miranda/updates/basic/z12sh1jqflzkj3ofd22pfv4p3ma4ch5kj + + <a class="ot-download-link" href="http://code.google.com/p/watcher-miranda/downloads/detail?name=Miranda%20IM%20Watcher%20Pack%20v3.0.9.exe">Miranda IM Watcher Pack v3.0.9.exe</a> (Miranda IM Watcher Pack v3.0.9) file uploaded by <a class="ot-profile-link-2" href="http://code.google.com/u/watcherhd/">watcherhd</a> + + watcherhd + + + <div class="ot-labels-field-wrapper"> + <span class="ot-labels-field-name">Labels: </span> + <span class="ot-labels-field-value"> + + + <span class="ot-field-label">Featured</span> + + + + <span class="ot-field-label">Type-Installer</span> + + + + <span class="ot-field-label">OpSys-Windows</span> + + + </span> + </div> + + + + + 2011-12-13T19:46:02Z + http://code.google.com/feeds/p/watcher-miranda/updates/basic/z13nxvbpft3ezr5ps04cepjgmoicsl1oq1w + + <a class="ot-download-link" href="http://code.google.com/p/watcher-miranda/downloads/detail?name=Miranda%20IM%20Watcher%20Pack%20v3.0.8.exe">Miranda IM Watcher Pack v3.0.8.exe</a> (Miranda IM Watcher Pack v3.0.8) file uploaded by <a class="ot-profile-link-2" href="http://code.google.com/u/watcherhd/">watcherhd</a> + + watcherhd + + + <div class="ot-labels-field-wrapper"> + <span class="ot-labels-field-name">Labels: </span> + <span class="ot-labels-field-value"> + + + <span class="ot-field-label">Featured</span> + + + + <span class="ot-field-label">Type-Installer</span> + + + + <span class="ot-field-label">OpSys-Windows</span> + + + </span> + </div> + + + + + 2011-12-04T10:52:49Z + http://code.google.com/feeds/p/watcher-miranda/updates/basic/z13vubiqswqqe1cf222pfv4p3ma4ch5kj + + <a class="ot-download-link" href="http://code.google.com/p/watcher-miranda/downloads/detail?name=Fingerprint.dll">Fingerprint.dll</a> (Fingerprint.dll WP update) file uploaded by <a class="ot-profile-link-2" href="http://code.google.com/u/watcherhd/">watcherhd</a> + + watcherhd + + + + + + + + 2011-12-04T10:52:32Z + http://code.google.com/feeds/p/watcher-miranda/updates/basic/z125fjy5qruixxloh04cepjgmoicsl1oq1w + + <a class="ot-download-link" href="http://code.google.com/p/watcher-miranda/downloads/detail?name=PackUpdater.dll">PackUpdater.dll</a> (PackUpdater.dll WP update) file uploaded by <a class="ot-profile-link-2" href="http://code.google.com/u/watcherhd/">watcherhd</a> + + watcherhd + + + + + + + + 2011-12-03T15:01:42Z + http://code.google.com/feeds/p/watcher-miranda/updates/basic/z13etferquvuyzd0z22pfv4p3ma4ch5kj + + <a class="ot-download-link" href="http://code.google.com/p/watcher-miranda/downloads/detail?name=packupdater.7z">packupdater.7z</a> (Pack Updater 0.0.1.0) file uploaded by <a class="ot-profile-link-2" href="http://code.google.com/u/watcherhd/">watcherhd</a> + + watcherhd + + + <div class="ot-labels-field-wrapper"> + <span class="ot-labels-field-name">Labels: </span> + <span class="ot-labels-field-value"> + + + <span class="ot-field-label">Featured</span> + + + </span> + </div> + + + + + 2011-12-02T22:21:54Z + http://code.google.com/feeds/p/watcher-miranda/updates/basic/z12ysnhy4zi2wvudo22pfv4p3ma4ch5kj + + <a class="ot-download-link" href="http://code.google.com/p/watcher-miranda/downloads/detail?name=fingerprintmodplus.7z">fingerprintmodplus.7z</a> (Fingerprint Mod Plus 0.2.2.4 (latest svn revision)) file uploaded by <a class="ot-profile-link-2" href="http://code.google.com/u/watcherhd/">watcherhd</a> + + watcherhd + + + <div class="ot-labels-field-wrapper"> + <span class="ot-labels-field-name">Labels: </span> + <span class="ot-labels-field-value"> + + + <span class="ot-field-label">Featured</span> + + + </span> + </div> + + + + + 2011-11-28T06:15:02Z + http://code.google.com/feeds/p/watcher-miranda/updates/basic/z13hy1xpcr2hgbrfv22pfv4p3ma4ch5kj + + <a class="ot-download-link" href="http://code.google.com/p/watcher-miranda/downloads/detail?name=Miranda%20IM%20Watcher%20Pack%20v3.0.7.exe">Miranda IM Watcher Pack v3.0.7.exe</a> (Miranda IM Watcher Pack v3.0.7) file uploaded by <a class="ot-profile-link-2" href="http://code.google.com/u/watcherhd/">watcherhd</a> + + watcherhd + + + <div class="ot-labels-field-wrapper"> + <span class="ot-labels-field-name">Labels: </span> + <span class="ot-labels-field-value"> + + + <span class="ot-field-label">Featured</span> + + + + <span class="ot-field-label">Type-Installer</span> + + + + <span class="ot-field-label">OpSys-Windows</span> + + + </span> + </div> + + + + + 2011-11-24T16:35:48Z + http://code.google.com/feeds/p/watcher-miranda/updates/basic/z13mcvxqurmeybypn04cepjgmoicsl1oq1w + + <a class="ot-download-link" href="http://code.google.com/p/watcher-miranda/downloads/detail?name=Miranda%20IM%20Watcher%20Pack%20v3.0.6.exe">Miranda IM Watcher Pack v3.0.6.exe</a> (Miranda IM Watcher Pack v3.0.6) file uploaded by <a class="ot-profile-link-2" href="http://code.google.com/u/watcherhd/">watcherhd</a> + + watcherhd + + + <div class="ot-labels-field-wrapper"> + <span class="ot-labels-field-name">Labels: </span> + <span class="ot-labels-field-value"> + + + <span class="ot-field-label">Featured</span> + + + + <span class="ot-field-label">Type-Installer</span> + + + + <span class="ot-field-label">OpSys-Windows</span> + + + </span> + </div> + + + + + 2011-11-23T04:58:16Z + http://code.google.com/feeds/p/watcher-miranda/updates/basic/z13rxxbauu3wxtfmz22pfv4p3ma4ch5kj + + <a class="ot-download-link" href="http://code.google.com/p/watcher-miranda/downloads/detail?name=simplestatusmsg.7z">simplestatusmsg.7z</a> (Simple Status Message 1.9.0.4) file uploaded by <a class="ot-profile-link-2" href="http://code.google.com/u/watcherhd/">watcherhd</a> + + watcherhd + + + <div class="ot-labels-field-wrapper"> + <span class="ot-labels-field-name">Labels: </span> + <span class="ot-labels-field-value"> + + + <span class="ot-field-label">Featured</span> + + + </span> + </div> + + + + + 2011-11-19T06:13:19Z + http://code.google.com/feeds/p/watcher-miranda/updates/basic/z13di1rprvjfhpta004cepjgmoicsl1oq1w + + <a class="ot-download-link" href="http://code.google.com/p/watcher-miranda/downloads/detail?name=Miranda%20IM%20Watcher%20Pack%20v3.0.5.exe">Miranda IM Watcher Pack v3.0.5.exe</a> (Miranda IM Watcher Pack v3.0.5) file uploaded by <a class="ot-profile-link-2" href="http://code.google.com/u/watcherhd/">watcherhd</a> + + watcherhd + + + <div class="ot-labels-field-wrapper"> + <span class="ot-labels-field-name">Labels: </span> + <span class="ot-labels-field-value"> + + + <span class="ot-field-label">Featured</span> + + + + <span class="ot-field-label">Type-Installer</span> + + + + <span class="ot-field-label">OpSys-Windows</span> + + + </span> + </div> + + + + diff --git a/protocols/NewsAggregator/NewsAggregator_10.sln b/protocols/NewsAggregator/NewsAggregator_10.sln new file mode 100644 index 0000000000..aee50b713e --- /dev/null +++ b/protocols/NewsAggregator/NewsAggregator_10.sln @@ -0,0 +1,26 @@ + +Microsoft Visual Studio Solution File, Format Version 11.00 +# Visual Studio 2010 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "NewsAggregator", "NewsAggregator_10.vcxproj", "{6DE11A47-2268-4B08-8DE5-15A1705FCE28}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Win32 = Debug|Win32 + Debug|x64 = Debug|x64 + Release|Win32 = Release|Win32 + Release|x64 = Release|x64 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {6DE11A47-2268-4B08-8DE5-15A1705FCE28}.Debug|Win32.ActiveCfg = Debug|Win32 + {6DE11A47-2268-4B08-8DE5-15A1705FCE28}.Debug|Win32.Build.0 = Debug|Win32 + {6DE11A47-2268-4B08-8DE5-15A1705FCE28}.Debug|x64.ActiveCfg = Debug|x64 + {6DE11A47-2268-4B08-8DE5-15A1705FCE28}.Debug|x64.Build.0 = Debug|x64 + {6DE11A47-2268-4B08-8DE5-15A1705FCE28}.Release|Win32.ActiveCfg = Release|Win32 + {6DE11A47-2268-4B08-8DE5-15A1705FCE28}.Release|Win32.Build.0 = Release|Win32 + {6DE11A47-2268-4B08-8DE5-15A1705FCE28}.Release|x64.ActiveCfg = Release|x64 + {6DE11A47-2268-4B08-8DE5-15A1705FCE28}.Release|x64.Build.0 = Release|x64 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/protocols/NewsAggregator/NewsAggregator_10.vcxproj b/protocols/NewsAggregator/NewsAggregator_10.vcxproj new file mode 100644 index 0000000000..4d9e94c372 --- /dev/null +++ b/protocols/NewsAggregator/NewsAggregator_10.vcxproj @@ -0,0 +1,210 @@ + + + + + Debug + Win32 + + + Debug + x64 + + + Release + Win32 + + + Release + x64 + + + + NewsAggregator + {6DE11A47-2268-4B08-8DE5-15A1705FCE28} + + + + DynamicLibrary + Unicode + true + + + DynamicLibrary + Unicode + true + + + DynamicLibrary + Unicode + + + DynamicLibrary + Unicode + + + + + + + + + + + + + + + + + + + <_ProjectFileVersion>10.0.30319.1 + $(SolutionDir)$(Configuration)\Plugins\ + $(SolutionDir)$(Configuration)64\Plugins\ + $(SolutionDir)$(Configuration)\Obj\$(ProjectName)\ + $(SolutionDir)$(Configuration)64\Obj\$(ProjectName)\ + $(SolutionDir)$(Configuration)\Plugins\ + $(SolutionDir)$(Configuration)64\Plugins\ + $(SolutionDir)$(Configuration)\Obj\$(ProjectName)\ + $(SolutionDir)$(Configuration)64\Obj\$(ProjectName)\ + true + true + true + true + + + + Disabled + ..\..\include;..\plugins\ExternalAPI;..\..\..\boost_1_49_0;%(AdditionalIncludeDirectories) + WIN32;_DEBUG;_WINDOWS;_USRDLL;NEWSAGGREGATOR_EXPORTS;%(PreprocessorDefinitions) + MultiThreadedDebugDLL + Level3 + EditAndContinue + 4996 + Use + Common.h + + + true + Windows + false + $(IntDir)$(TargetName).lib + comdlg32.lib;%(AdditionalDependencies) + ..\..\..\boost_1_49_0\lib + + + ..\..\include\msapi + _DEBUG;%(PreprocessorDefinitions) + + + + + Disabled + ..\..\include;..\plugins\ExternalAPI;..\..\..\boost_1_49_0;%(AdditionalIncludeDirectories) + WIN64;_DEBUG;_WINDOWS;_USRDLL;NEWSAGGREGATOR_EXPORTS;%(PreprocessorDefinitions) + MultiThreadedDebugDLL + Level3 + 4996 + Use + Common.h + + + comdlg32.lib;%(AdditionalDependencies) + true + Windows + false + $(IntDir)$(TargetName).lib + ..\..\..\boost_1_49_0\lib64 + + + ..\..\include\msapi + _DEBUG;%(PreprocessorDefinitions) + + + + + Full + Size + ..\..\include;..\plugins\ExternalAPI;..\..\..\boost_1_49_0;%(AdditionalIncludeDirectories) + WIN32;NDEBUG;_WINDOWS;_USRDLL;NEWSAGGREGATOR_EXPORTS;%(PreprocessorDefinitions) + Level3 + 4996 + Use + Common.h + + + Windows + true + true + false + $(IntDir)$(TargetName).lib + true + comdlg32.lib;%(AdditionalDependencies) + ..\..\..\boost_1_49_0\lib + + + ..\..\include\msapi + NDEBUG;%(PreprocessorDefinitions) + + + + + Full + Size + ..\..\include;..\plugins\ExternalAPI;..\..\..\boost_1_49_0;%(AdditionalIncludeDirectories) + WIN64;NDEBUG;_WINDOWS;_USRDLL;NEWSAGGREGATOR_EXPORTS;%(PreprocessorDefinitions) + Level3 + 4996 + Use + Common.h + + + comdlg32.lib;%(AdditionalDependencies) + Windows + true + true + false + $(IntDir)$(TargetName).lib + true + ..\..\..\boost_1_49_0\lib64 + + + ..\..\include\msapi + NDEBUG;%(PreprocessorDefinitions) + + + + + + + + + + + + + + + + + + Create + Create + Create + Create + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/protocols/NewsAggregator/NewsAggregator_10.vcxproj.filters b/protocols/NewsAggregator/NewsAggregator_10.vcxproj.filters new file mode 100644 index 0000000000..7b08037070 --- /dev/null +++ b/protocols/NewsAggregator/NewsAggregator_10.vcxproj.filters @@ -0,0 +1,79 @@ + + + + + {4FC737F1-C7A5-4376-A066-2A32D752A2FF} + cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx + + + {93995380-89BD-4b04-88EB-625FBE52EBFB} + h;hpp;hxx;hm;inl;inc;xsd + + + {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} + rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav + + + + + Resource Files + + + Resource Files + + + + + Header Files + + + Header Files + + + Header Files + + + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + + + Resource Files + + + Resource Files + + + Resource Files + + + Resource Files + + + Resource Files + + + \ No newline at end of file diff --git a/protocols/NewsAggregator/Res/AddFeed.ico b/protocols/NewsAggregator/Res/AddFeed.ico new file mode 100644 index 0000000000..2503d8ec60 Binary files /dev/null and b/protocols/NewsAggregator/Res/AddFeed.ico differ diff --git a/protocols/NewsAggregator/Res/CheckALL.ico b/protocols/NewsAggregator/Res/CheckALL.ico new file mode 100644 index 0000000000..98d434b2ba Binary files /dev/null and b/protocols/NewsAggregator/Res/CheckALL.ico differ diff --git a/protocols/NewsAggregator/Res/Export.ico b/protocols/NewsAggregator/Res/Export.ico new file mode 100644 index 0000000000..ef475bb5cd Binary files /dev/null and b/protocols/NewsAggregator/Res/Export.ico differ diff --git a/protocols/NewsAggregator/Res/Import.ico b/protocols/NewsAggregator/Res/Import.ico new file mode 100644 index 0000000000..4becddf394 Binary files /dev/null and b/protocols/NewsAggregator/Res/Import.ico differ diff --git a/protocols/NewsAggregator/Res/Main.ico b/protocols/NewsAggregator/Res/Main.ico new file mode 100644 index 0000000000..4e9d1abc51 Binary files /dev/null and b/protocols/NewsAggregator/Res/Main.ico differ diff --git a/protocols/NewsAggregator/Resource.rc b/protocols/NewsAggregator/Resource.rc new file mode 100644 index 0000000000..a092bb26ea --- /dev/null +++ b/protocols/NewsAggregator/Resource.rc @@ -0,0 +1,148 @@ +// Microsoft Visual C++ generated resource script. +// +#include "resource.h" + +#define APSTUDIO_READONLY_SYMBOLS +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 2 resource. +// +#include "afxres.h" + +///////////////////////////////////////////////////////////////////////////// +#undef APSTUDIO_READONLY_SYMBOLS + +///////////////////////////////////////////////////////////////////////////// +// () resources + +#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_RUS) +LANGUAGE LANG_RUSSIAN, SUBLANG_DEFAULT +#pragma code_page(1251) + +///////////////////////////////////////////////////////////////////////////// +// +// Icon +// + +// Icon with lowest ID value placed first to ensure application icon +// remains consistent on all systems. +IDI_ICON ICON "res/Main.ico" +IDI_CHECKALL ICON "res/CheckAll.ico" +IDI_ADDFEED ICON "res/AddFeed.ico" +IDI_IMPORTFEEDS ICON "res/Import.ico" +IDI_EXPORTFEEDS ICON "res/Export.ico" + +///////////////////////////////////////////////////////////////////////////// +// +// Dialog +// + +IDD_OPTIONS DIALOGEX 0, 0, 314, 234 +STYLE DS_SETFONT | DS_FIXEDSYS | WS_CHILD +EXSTYLE WS_EX_CONTROLPARENT +FONT 8, "MS Shell Dlg", 0, 0, 0x1 +BEGIN + CONTROL "",IDC_FEEDLIST,"SysListView32",LVS_REPORT | LVS_SINGLESEL | LVS_SHOWSELALWAYS | LVS_NOSORTHEADER | WS_TABSTOP,9,8,294,174 + PUSHBUTTON "Add",IDC_ADD,79,187,50,14 + PUSHBUTTON "Change",IDC_CHANGE,133,187,50,14 + PUSHBUTTON "Remove",IDC_REMOVE,187,187,50,14 + PUSHBUTTON "Import",IDC_IMORT,252,204,50,14 + PUSHBUTTON "Export",IDC_EXORT,252,219,50,14 +END + +IDD_ADDFEED DIALOGEX 0, 0, 250, 228 +STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | DS_NOFAILCREATE | DS_CENTER | WS_POPUP | WS_VISIBLE | WS_CAPTION | WS_SYSMENU +EXSTYLE WS_EX_CONTROLPARENT +FONT 8, "MS Shell Dlg", 400, 0, 0x1 +BEGIN + DEFPUSHBUTTON "OK",IDOK,140,209,50,14 + PUSHBUTTON "Cancel",IDCANCEL,194,209,50,14 + GROUPBOX "General Settings",IDC_STATIC,6,3,238,61 + RTEXT "Title",IDC_STATIC,17,16,44,8 + EDITTEXT IDC_FEEDTITLE,63,14,173,13,ES_AUTOHSCROLL + RTEXT "URL",IDC_STATIC,17,31,44,8 + EDITTEXT IDC_FEEDURL,63,29,173,13,ES_AUTOHSCROLL + RTEXT "Check every",IDC_STATIC,7,46,54,8 + LTEXT "minutes",IDC_STATIC,100,46,75,8 + PUSHBUTTON "Check Feed",IDC_DISCOVERY,177,44,59,12 + GROUPBOX "Authentication",IDC_STATIC,6,67,238,48 + CONTROL "Use &authentication",IDC_USEAUTH,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,13,80,157,10 + RTEXT "Login",IDC_STATIC,16,96,42,8 + EDITTEXT IDC_LOGIN,61,94,63,14,ES_AUTOHSCROLL | WS_DISABLED + RTEXT "Password",IDC_STATIC,129,96,41,8 + EDITTEXT IDC_PASSWORD,173,94,63,14,ES_PASSWORD | ES_AUTOHSCROLL | WS_DISABLED + GROUPBOX "Visualization",IDC_STATIC,6,119,238,85 + LTEXT "Display news using the following format:",IDC_STATIC,13,132,168,8 + EDITTEXT IDC_TAGSEDIT,13,143,224,36,ES_MULTILINE | ES_AUTOHSCROLL | ES_WANTRETURN | WS_VSCROLL + LTEXT "All item's tags are valid. Put them between #. Example: ##",IDC_STATIC,14,182,167,16 + PUSHBUTTON "Reset",IDC_RESET,192,184,45,14 + PUSHBUTTON "?",IDC_TAGHELP,175,184,15,14 + LTEXT "0 - check manually",IDC_STATIC,100,55,79,8 + EDITTEXT IDC_CHECKTIME,64,45,32,12,ES_RIGHT | ES_AUTOHSCROLL | ES_NUMBER + CONTROL "",IDC_TIMEOUT_VALUE_SPIN,"msctls_updown32",UDS_SETBUDDYINT | UDS_ALIGNRIGHT | UDS_AUTOBUDDY | UDS_ARROWKEYS | UDS_NOTHOUSANDS,85,45,11,12 +END + + +#ifdef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// TEXTINCLUDE +// + +1 TEXTINCLUDE +BEGIN + "resource.h\0" +END + +2 TEXTINCLUDE +BEGIN + "#include ""afxres.h""\r\n" + "\0" +END + +3 TEXTINCLUDE +BEGIN + "\r\n" + "\0" +END + +#endif // APSTUDIO_INVOKED + + +///////////////////////////////////////////////////////////////////////////// +// +// DESIGNINFO +// + +#ifdef APSTUDIO_INVOKED +GUIDELINES DESIGNINFO +BEGIN + IDD_OPTIONS, DIALOG + BEGIN + BOTTOMMARGIN, 189 + END + + IDD_ADDFEED, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 241 + TOPMARGIN, 7 + END +END +#endif // APSTUDIO_INVOKED + +#endif // () resources +///////////////////////////////////////////////////////////////////////////// + + + +#ifndef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 3 resource. +// + + +///////////////////////////////////////////////////////////////////////////// +#endif // not APSTUDIO_INVOKED + diff --git a/protocols/NewsAggregator/RssText.txt b/protocols/NewsAggregator/RssText.txt new file mode 100644 index 0000000000..b229fc9e78 --- /dev/null +++ b/protocols/NewsAggregator/RssText.txt @@ -0,0 +1,713 @@ + + + + Bash.Org.Ru + http://bash.org.ru/ + + + ru + + b3cf2d64d57bdfea405b43426ec354e4b89a98912c71f243c93568020e2f0a70 + http://bash.org.ru/quote/414990 + #414990 + Fri, 30 Dec 2011 12:12:01 +0400 + ]]> + + + 9f3028db6c6020de238a5d27b14d85c21e5f4c8a5f96506b757925df8500c940 + http://bash.org.ru/quote/414989 + #414989 + Fri, 30 Dec 2011 11:45:18 +0400 + + + + c917324b76e57d2d6103af4b154f41fb335e9a4cc3f973b0b077a8c857c1353a + http://bash.org.ru/quote/414988 + #414988 + Fri, 30 Dec 2011 11:44:38 +0400 + :
: ?
: , , )]]>
+
+ + 96b70712a7185b7d1167f6f9aee454841a4246b0f270185ea3f29d034b9bd39f + http://bash.org.ru/quote/414987 + #414987 + Fri, 30 Dec 2011 11:44:01 +0400 + :
***. !!! , . .]]>
+
+ + 793886d798688d3e6bec7d2ffb51d6397f356e5c0e00ef06d07f22b87643c93a + http://bash.org.ru/quote/414986 + #414986 + Fri, 30 Dec 2011 11:13:16 +0400 + + + + 6eac3f54c4f58d8a41c7e7f72f72ca6e0c6bf5869f0eefc99044ef4427db28d0 + http://bash.org.ru/quote/414985 + #414985 + Fri, 30 Dec 2011 11:12:02 +0400 + + + + 744d1d505dce7f1877c45baee1fdf97009a403d6dedb3ae1cd185480ec3dbbd0 + http://bash.org.ru/quote/414984 + #414984 + Fri, 30 Dec 2011 11:11:01 +0400 + ()?
.

yyy:
... .]]>
+
+ + aadc7f6194e8062c44250a9a878f010c0fe7d9d95af9a8389fbf8a8f748d6c6f + http://bash.org.ru/quote/414983 + #414983 + Fri, 30 Dec 2011 10:45:08 +0400 + xxx:
yyy: wifi ?]]>
+
+ + 01511c230d7cdf4ed42f09106b3075a5021797ae5a11d3063dc9332bb7baf858 + http://bash.org.ru/quote/414982 + #414982 + Fri, 30 Dec 2011 10:44:36 +0400 + Ergo: . . .]]> + + + cc05613e48d3f285e2a2a95a12f542586c5c0fe4499addf3c2a633cf4940e572 + http://bash.org.ru/quote/414981 + #414981 + Fri, 30 Dec 2011 10:44:01 +0400 + + + + 589fe99078c1447d672503cd8ffb9ba7524d9bd9e03cb5444e7c6fcd2be55269 + http://bash.org.ru/quote/414980 + #414980 + Fri, 30 Dec 2011 10:12:44 +0400 + + + + 58b960aeadb0e2700dd3ec5c18a0f9ca1f446d49f66edabf2ad3ea0f4a9f4933 + http://bash.org.ru/quote/414979 + #414979 + Fri, 30 Dec 2011 10:12:01 +0400 + ! >.<]]> + + + dda44cf9be0c8bf4691ce24629fd67dca371952e1dc45aa5dc1cce16ca095d29 + http://bash.org.ru/quote/414978 + #414978 + Fri, 30 Dec 2011 09:46:04 +0400 + + + + 33f18d83baf27fbd1e28e525c942b2c7e379b42a7d91f7436e2e199400ceda30 + http://bash.org.ru/quote/414977 + #414977 + Fri, 30 Dec 2011 09:45:01 +0400 + : . , - . , , " ". .]]> + + + 5599090163fe32efddbf295e457fd9cc4f3426b524eebaaaa4fa8277f34e9be2 + http://bash.org.ru/quote/414976 + #414976 + Fri, 30 Dec 2011 09:13:01 +0400 + yyy: ?]]> + + + 1bb26a5bc553b0570cbdf64be1a9ba3af74c3fd64dc60fe0bf9335ecb74600d0 + http://bash.org.ru/quote/414975 + #414975 + Fri, 30 Dec 2011 08:45:35 +0400 + yyy: :D]]> + + + cf4da48b55d3fdb9e9825e39a664bd4d41dc5c7a64227796ad1afb0900bdec19 + http://bash.org.ru/quote/414974 + #414974 + Fri, 30 Dec 2011 08:45:01 +0400 + ]]> + + + 1a7a8ba066100acdf40b79f4fbc967932320641e3565b230678920432e80e1e3 + http://bash.org.ru/quote/414973 + #414973 + Fri, 30 Dec 2011 08:12:44 +0400 + + + + 339e00558b293e087749ba42e0f06916531e712b1edfb25e470e2c0d10494aea + http://bash.org.ru/quote/414972 + #414972 + Fri, 30 Dec 2011 08:11:44 +0400 +
XXX: , , ?
, , , , ( , ) , , 2008...

YYY: ? )))]]>
+
+ + cfa6ff32cedafbf49ef812730e850a6abc9ec61c7682f3518d95fa00db4e1a14 + http://bash.org.ru/quote/414971 + #414971 + Fri, 30 Dec 2011 08:11:01 +0400 + + + + 128696d56057a228c43deb8cad49205905868817d0b4e834e37e3fdaccecafb4 + http://bash.org.ru/quote/414970 + #414970 + Thu, 29 Dec 2011 12:12:42 +0400 + yyy: , .]]> + + + 2d15491a51b88af3e66c02b4d326f1e2802656b6361f8f07dd667fbbe9dce728 + http://bash.org.ru/quote/414969 + #414969 + Thu, 29 Dec 2011 12:11:34 +0400 + + + + ed64e480321c46a51035c44a445cfd98927e2e303d972ac8874e8e36c11a8371 + http://bash.org.ru/quote/414968 + #414968 + Thu, 29 Dec 2011 12:11:01 +0400 +
troydm: , 5 ! !
muzhig: , . . .
ozgg: , ;)
Vexilurz: . - 5 ]]>
+
+ + aaa2f3a8dd486d209a697ecd4e3d728d99a2aa37dd482a3a859af5c473143b69 + http://bash.org.ru/quote/414967 + #414967 + Thu, 29 Dec 2011 11:46:07 +0400 + + + + dc470e391715c450eef79e82aaadfb0342ecc256504946f0a32d2f8c1160557e + http://bash.org.ru/quote/414966 + #414966 + Thu, 29 Dec 2011 11:45:06 +0400 +
, , , 1917 .

.]]>
+
+ + a7147227d4c9f64edae338c2cec9f4456a1214ea3f9d899c2486038abe99a8f5 + http://bash.org.ru/quote/414965 + #414965 + Thu, 29 Dec 2011 11:44:01 +0400 + + + + d35adf64ed961a7e7ff88e11a9b57760b1cd3f0a835f008b6e9782a27ee1a31a + http://bash.org.ru/quote/414964 + #414964 + Thu, 29 Dec 2011 11:13:11 +0400 + + + + 8ce06ad45b760d6b51e2432476e5c13dc9158f589c9b662147b760b0a1b967ac + http://bash.org.ru/quote/414963 + #414963 + Thu, 29 Dec 2011 11:12:01 +0400 +
. , . : , , , !]]>
+
+ + c64eb292881cc760ac0d2f7ac0b1010a8047b1271d39a0bc759076633640bbb4 + http://bash.org.ru/quote/414962 + #414962 + Thu, 29 Dec 2011 10:45:24 +0400 + Lightning: ???
Lilith: , -
Lightning: ,
Lilith: ,
Lilith: ,
Lightning: , - -?
Lilith: , ?
Lilith:
Lightning: ? ?
Lightning: ,
Lightning: , ,
Lightning: ]]>
+
+ + 19ee3858da403abdebc2f2694ade27e224d83cb2d0325964d802f3313c1333de + http://bash.org.ru/quote/414961 + #414961 + Thu, 29 Dec 2011 10:44:36 +0400 + : ??
: . . . .]]>
+
+ + e0270fd309b6e90cb9f26d9012a1db8ed681fd071f5848b395535442033ffe3a + http://bash.org.ru/quote/414960 + #414960 + Thu, 29 Dec 2011 10:44:01 +0400 + BreakDancer:
Luba: ?
BreakDancer: , ,
BreakDancer: , 29
BreakDancer: !
BreakDancer: , ]]>
+
+ + 8187c704ade265c329ccc02384e4206607407657bc6c9b9425a9542f0cb5a6a1 + http://bash.org.ru/quote/414959 + #414959 + Thu, 29 Dec 2011 10:13:01 +0400 + + + + 1e5eadf8678f61893bcf84e0dfb41290f63266eab736941b7ca07653b70f17d4 + http://bash.org.ru/quote/414958 + #414958 + Thu, 29 Dec 2011 09:45:26 +0400 + : , ...
: ? ? ?
: !
: , ...
: , ...
: , ? ?]]>
+
+ + b7c708279640f1efe4ec3401970cb89f075864203ed0fbeeb612e9592655a4c3 + http://bash.org.ru/quote/414957 + #414957 + Thu, 29 Dec 2011 09:44:52 +0400 + " ". . . , , . :
- ! - .
.]]>
+
+ + e91f03e5e391060d916a7e7e827cb6eaeec132c17a1ac5d78af70d5368461ec5 + http://bash.org.ru/quote/414956 + #414956 + Thu, 29 Dec 2011 09:44:01 +0400 + + + + c805cfaf28bf072384933e50ea8e1c48f815063c3bfbfe05a0986d6b944bd14e + http://bash.org.ru/quote/414955 + #414955 + Thu, 29 Dec 2011 09:13:01 +0400 + YYY: ?
XXX: : " " vs " ". .]]>
+
+ + 0636538a5462fc292f9b4fc6439cd6f7f8ab0fe79ba081c47e36d3d8338806fe + http://bash.org.ru/quote/414954 + #414954 + Thu, 29 Dec 2011 08:46:01 +0400 + xxx: . .
yyy: ,
: , , - ...
: ]]>
+
+ + c8591055f839c5dbc882d36e7a4d2db9ce399460048e8e0e6d466dd43a88cae1 + http://bash.org.ru/quote/414953 + #414953 + Thu, 29 Dec 2011 08:13:04 +0400 + xxx: ! , ! )))
yyy: . - , - ... =(
xxx: ... !
xxx: , , ?]]>
+
+ + 714be978a8678d201b16981150150166752145feaefa2f159980d76051602d87 + http://bash.org.ru/quote/414952 + #414952 + Thu, 29 Dec 2011 08:11:54 +0400 + , =)]]> + + + dd7d36ba1543a7ac360b28c72f669816d3551bb09f34156635f80efbc9a4f390 + http://bash.org.ru/quote/414951 + #414951 + Thu, 29 Dec 2011 08:11:01 +0400 + - , ? .
, :
- , ...]]>
+
+ + 174e14053635b5325be15ae0a37b47953115b33e0d082053064572907d2829a0 + http://bash.org.ru/quote/414950 + #414950 + Wed, 28 Dec 2011 12:46:01 +0400 + [QuizMaster7] : : 9
[EwokDoUrden] !
[EwokDoUrden] ]]>
+
+ + 691660b05378e2d242a7a60429e2cd94a44e8d2041b2facb2597cb21ec213fbf + http://bash.org.ru/quote/414949 + #414949 + Wed, 28 Dec 2011 12:13:18 +0400 + + + + 634c63c05a37bbb5933ccae9bd50bbc4e04d2a27dfd2895ab8f4be5cc77a5707 + http://bash.org.ru/quote/414948 + #414948 + Wed, 28 Dec 2011 12:12:02 +0400 + + + + 2309307a0dd79a2f77f63dbbbf3239d5de3cd41409ce23750c0e8ebecd20466f + http://bash.org.ru/quote/414946 + #414946 + Wed, 28 Dec 2011 11:44:57 +0400 +
Explay T-7, ()]]>
+
+ + c58a33a67db26dab4b121d14ebad5cd80d78040eea517835a90bbdc81887b4dc + http://bash.org.ru/quote/414945 + #414945 + Wed, 28 Dec 2011 11:44:01 +0400 + : , ?
: , ? )
: , ....]]>
+
+ + 3a8ab041c452b16f9f415d3f6d209f1d58f11ed2ab0ee5f928a5f6b8e22a78b9 + http://bash.org.ru/quote/414944 + #414944 + Wed, 28 Dec 2011 11:12:55 +0400 + + + + d72696e62bb007bb3004d7403e5915734f7ca02ef54757e08cb0a689a1b4df4d + http://bash.org.ru/quote/414943 + #414943 + Wed, 28 Dec 2011 11:12:01 +0400 + fintar: ?]]> + + + 9ffbfa3d0268a0dc955b9969e4c2b77cc50443a7d6bd9b60f9cf4102daeb7fb1 + http://bash.org.ru/quote/414942 + #414942 + Wed, 28 Dec 2011 10:45:41 +0400 + :
!
?
, ? , , , . !

, . , , , ]]>
+
+ + 6017310e922bd529b5ad3be09f4f0c5e8b6b2fb76d0bd05b617a8eac0ae27193 + http://bash.org.ru/quote/414941 + #414941 + Wed, 28 Dec 2011 10:44:47 +0400 + + + + b101af3976aa2e9b7841576433b0c68af93c3ce85ac75383a6f7b20a0106a9c6 + http://bash.org.ru/quote/414940 + #414940 + Wed, 28 Dec 2011 10:44:01 +0400 + :
- .
- .
, .
- 174 , 80 . , , , .
:
- , .
, ...]]>
+
+ + 1d3da2d78ecf5bac86c480e26d65184e8b69cab96bc8d6c038de7de9ca468ebd + http://bash.org.ru/quote/414939 + #414939 + Wed, 28 Dec 2011 10:13:07 +0400 + : " ".]]> + + + 0365ddac152e7a1f45d4fe35cc5d673ff9e9cbce8d9d125e40b5dca139cd293e + http://bash.org.ru/quote/414938 + #414938 + Wed, 28 Dec 2011 10:12:01 +0400 + + + + 8774184a10feb87ab76c3eac63fcf6873b572cd376d06b87ec2cafa48464b57b + http://bash.org.ru/quote/414937 + #414937 + Wed, 28 Dec 2011 09:45:31 +0400 + + + + 5f9e58d114c8a86764bd26780e94bb3f00f0a4db026821f84d06b4540db7b5ed + http://bash.org.ru/quote/414936 + #414936 + Wed, 28 Dec 2011 09:45:01 +0400 + yyy: - . . .
xxx: ?
yyy: . . .]]>
+
+ + 8b1acd9ec8457ac318c78b1dc88005edf4fc9f0ace4d47c1080c1b670de19e2e + http://bash.org.ru/quote/414935 + #414935 + Wed, 28 Dec 2011 09:13:01 +0400 + Dimes: ]]> + + + 187c05af1edfcce0de5da82d30a58fb83ae474e6fa897ad684bd3ad7c50e9dd7 + http://bash.org.ru/quote/414934 + #414934 + Wed, 28 Dec 2011 08:46:02 +0400 + yyy: ?
xxx:
yyy: ? )
xxx:
xxx:
yyy:
yyy: , ]]>
+
+ + 00822e572762f43d2fb56ef00c2f7be12f703a27a39949f99036f7734a26f566 + http://bash.org.ru/quote/414933 + #414933 + Wed, 28 Dec 2011 08:45:02 +0400 + misterIT: , . .
misterIT: !!! ?
xxx@qip: , , ? ? ?
misterIT:
misterIT: , !
xxx@qip: . .]]>
+
+ + a6231be02247fcfffbaa07e020f43a4c7a1c7ed628ed86af16443ffe45ed7127 + http://bash.org.ru/quote/414932 + #414932 + Wed, 28 Dec 2011 08:12:38 +0400 + + + + 039ba4efda1619b3b4374b223e344b3423a8d9788a18bf73ac07bce7bac04bea + http://bash.org.ru/quote/414931 + #414931 + Wed, 28 Dec 2011 08:12:01 +0400 + :
- ,
- ,
- , , , z !
- - ?
- , !
- ... 5 2
- .
- 5, 2, ,
- - , ... ( !!!!) .

:
, , , - ]]>
+
+ + 66fab6cb65e11c7de896d7c6840095b9a90bd70ed8d49f8fb7adc0adb9b6a43c + http://bash.org.ru/quote/414930 + #414930 + Tue, 27 Dec 2011 13:46:01 +0400 + + + + 39b40cb066f0a9b64c53dbc67c1a521a1b3948a5b021efd4b1982753059aaee1 + http://bash.org.ru/quote/414929 + #414929 + Tue, 27 Dec 2011 13:13:01 +0400 + xxx:
yyy:
xxx:
xxx: , ]]>
+
+ + 4f3b79bfba6994d73b3eb21530d98188f4830c26c4f8108a6d8120a4c0b5e8fc + http://bash.org.ru/quote/414928 + #414928 + Tue, 27 Dec 2011 12:46:01 +0400 + xxx: , , ?
yyy: .
zzz: ! , ! :)]]>
+
+ + d3162ccb1c30aa3f654c0c6b368fa9e583c020dc3d04bcc07b6c5f02eeadaaeb + http://bash.org.ru/quote/414927 + #414927 + Tue, 27 Dec 2011 12:13:01 +0400 + xxx: , , : ,
yyy: , , !
]]>
+
+ + 69e05b82fc5a5028a65e0435a584a83ffaa44e9784c024fb30eda9b7d87f38ba + http://bash.org.ru/quote/414926 + #414926 + Tue, 27 Dec 2011 11:46:03 +0400 + iNote: :D]]> + + + caa3a31eca89b56e3669c9910f23564e1ee2bd2c67f0be5472e206496b688609 + http://bash.org.ru/quote/414925 + #414925 + Tue, 27 Dec 2011 11:45:01 +0400 + xxx: .
xxx: .
xxx: , .
xxx: , , , .
xxx: .]]>
+
+ + d3db54801b673716d6b41137bbf9ca64c62a04a1211bf43ea44876c411f88728 + http://bash.org.ru/quote/414924 + #414924 + Tue, 27 Dec 2011 11:13:12 +0400 + - , ? "--", "--"
- . : "-".
- . , , "" "" )]]>
+
+ + 6206e668575ef7364ca52bacdfc3d6b45da5ab80d4c69c0f1467269cec9ee6c4 + http://bash.org.ru/quote/414923 + #414923 + Tue, 27 Dec 2011 11:12:01 +0400 + xxx: .
xxx: ! )))]]>
+
+ + 47c8ec43ac12036ac0528b4b4077f8d9f80a0fe8d4aa029f8a39b7b9d4327b6f + http://bash.org.ru/quote/414922 + #414922 + Tue, 27 Dec 2011 10:45:34 +0400 + + + + 7871bd6a1b62f062468316e82234015b27a0c448d21c39120579d4c66c1b3367 + http://bash.org.ru/quote/414921 + #414921 + Tue, 27 Dec 2011 10:45:01 +0400 + yyy: . .]]> + + + c5fcb5c4cf429099d6540943fd5f376998aee7e5ac90409e8afc3e6a61ef177f + http://bash.org.ru/quote/414920 + #414920 + Tue, 27 Dec 2011 10:13:01 +0400 + + + + 72838435dc732ed7410037dd17b0e38588ac91999f5f195421621a8355ded16e + http://bash.org.ru/quote/414919 + #414919 + Tue, 27 Dec 2011 09:45:45 +0400 +


,

]]>
+
+ + 7b098f0d541bdc4ac0f90634a82e781d38e174ef380aa56ff6c94e69734fcde8 + http://bash.org.ru/quote/414918 + #414918 + Tue, 27 Dec 2011 09:44:43 +0400 + + + + 5af15998f29f5f063b9ce01b54dc8d3f0b73bb7d3f877edcc5eaa7ff8f71013b + http://bash.org.ru/quote/414917 + #414917 + Tue, 27 Dec 2011 09:44:01 +0400 + : ? ?
: , . , . ]]>
+
+ + b5a66cb535552b46159d467911174f1e4aac941c8c1d891a62619a8cdb00a3ea + http://bash.org.ru/quote/414916 + #414916 + Tue, 27 Dec 2011 09:13:02 +0400 + xxx: , ?
yyy: . , ...]]>
+
+ + 9e007ee3d9984de85c727f6885f913891b11676f10b053ba8a51bec6fba0e23c + http://bash.org.ru/quote/414915 + #414915 + Tue, 27 Dec 2011 08:46:11 +0400 + xxx: ?
yyy:
yyy: , ]]>
+
+ + 3dc9ddc2fad185181993315c5c3a404405ab704423d3c24bd9213dcb23bad2eb + http://bash.org.ru/quote/414914 + #414914 + Tue, 27 Dec 2011 08:45:01 +0400 + : , ?
: , ]]>
+
+ + 61e793991c5dea07ea5a5afa2bbc899e49c23d8a0d8a1f48918915129a13a35c + http://bash.org.ru/quote/414913 + #414913 + Tue, 27 Dec 2011 08:12:04 +0400 +
: !
yyy: , , - ...
: , ! -!]]>
+
+ + ed2932ac0768ceb5ec1a155d4b039fb2cba050296935d7852baccb238ada1819 + http://bash.org.ru/quote/414912 + #414912 + Tue, 27 Dec 2011 08:11:31 +0400 + <xxx> , " ": , , ]]> + + + 1989a43d3a03de416d16788589caaa318ece611245b328df9b1567c13205cf70 + http://bash.org.ru/quote/414911 + #414911 + Tue, 27 Dec 2011 08:11:01 +0400 + yyy: - , ]]> + + + c207fd198261176146047e54ccfff9058582e311ab402e32dfe67837c3e61e64 + http://bash.org.ru/quote/414910 + #414910 + Mon, 26 Dec 2011 13:12:49 +0400 +
: ?
: .
: ? ?
: -. SPIDER-MAN. , , S.]]>
+
+ + 245f34c6c6da77a68ba258f717177e3ecb27865bd7cd72c5966a9bae3d68cdab + http://bash.org.ru/quote/414909 + #414909 + Mon, 26 Dec 2011 13:11:56 +0400 + yyy: ?
xxx: , !]]>
+
+ + b9674cdf642593a5c193c3262031513822c50bcb950170cc07aadfb7fddc2649 + http://bash.org.ru/quote/414908 + #414908 + Mon, 26 Dec 2011 13:11:02 +0400 + : ,
: ?
: ]]>
+
+ + f5e384c1050a5d6df2cbe999fbae0e082deda5e89839ad0a913b490b3fada8c0 + http://bash.org.ru/quote/414907 + #414907 + Mon, 26 Dec 2011 12:46:14 +0400 + : , , )))
: , ,
: - , ]]>
+
+ + 71aba0126bc495b6efcd494e8b95c11b4e27fadb96f8fa31475db7aa85c7f1a4 + http://bash.org.ru/quote/414906 + #414906 + Mon, 26 Dec 2011 12:45:14 +0400 +
xxx: , ...]]>
+
+ + 3d3b28ac59593143fe32ecbb4c5df048f39482f38d336d6dc4ad119ffbeea78b + http://bash.org.ru/quote/414905 + #414905 + Mon, 26 Dec 2011 12:44:01 +0400 + yyy: )]]> + + + 2931790e946054e81789e63e91d5dc9237bf492d3f26c6d7bc530b59ef2672fe + http://bash.org.ru/quote/414904 + #414904 + Mon, 26 Dec 2011 12:13:01 +0400 + yyy: , - , . :)]]> + + + 5ee6027cf4758aa3989a3552db60d21acfc4bce66518265e9137abc3ce1fc3c7 + http://bash.org.ru/quote/414903 + #414903 + Mon, 26 Dec 2011 11:46:01 +0400 + , . " !". , " ".]]> + + + a47fdbea7602bfa4df71054ed3d391d00a1c0dd13f8adaa983bb5f93e5ac3d90 + http://bash.org.ru/quote/414902 + #414902 + Mon, 26 Dec 2011 11:13:01 +0400 + + + + bc8b51fdf44d63edc888ad063db2fa66d1ad92c48d999408fff00a8cbec8e4ae + http://bash.org.ru/quote/414901 + #414901 + Mon, 26 Dec 2011 10:46:12 +0400 + + + + e5174f709f5372c11eaf170b06efe25bf23fd3a65dbc9669e7b55b83ad598340 + http://bash.org.ru/quote/414900 + #414900 + Mon, 26 Dec 2011 10:45:01 +0400 + yyy:
yyy: ]]>
+
+ + 0f5c7eaee411484a37e8071fb60030eb902f42a26969363233116d425faec446 + http://bash.org.ru/quote/414899 + #414899 + Mon, 26 Dec 2011 10:12:34 +0400 + + + + 1941999057f97da275dbaee167f5314de54a3de0f1ccc0f25c983cfe08845e71 + http://bash.org.ru/quote/414898 + #414898 + Mon, 26 Dec 2011 10:12:01 +0400 + + + + 1493df9ec128867419e1c9e0f8adf1e7c73eaecba9ba81e51395778f2c599faf + http://bash.org.ru/quote/414897 + #414897 + Mon, 26 Dec 2011 09:46:15 +0400 + : ? . , + .
: , : " - ".
: !
: , .]]>
+
+ + 507045f7af9d1dbc586b1ea528ecc9edb09ea5a1f35dab1141afc0dee491c7f2 + http://bash.org.ru/quote/414896 + #414896 + Mon, 26 Dec 2011 09:45:01 +0400 + + + + e4f30a21e7ffa737cc164ea71ddf1fe24a2c87b269a1b47db1dbf591ebe3e843 + http://bash.org.ru/quote/414895 + #414895 + Mon, 26 Dec 2011 09:12:45 +0400 + xxx: 12- - .]]> + + + 0ac1bcd3e77c115764edf2fef78568d7e88f0dcfa2830ebff7a4a67ca246192b + http://bash.org.ru/quote/414894 + #414894 + Mon, 26 Dec 2011 09:11:52 +0400 + Telecantrelem: - ?
1143r: Telecantrelem, . , , . . ! , !]]>
+
+ + 0b0d1ae0708037d49d4edd71c8e1d7a488907c379787b7827be44ba7adab6cef + http://bash.org.ru/quote/414893 + #414893 + Mon, 26 Dec 2011 09:11:01 +0400 +
12.12 4 "..." . , "", "". , , "" "", "" "", . . , .]]>
+
+ + 4caeec3b83a23c4ef7e6822f1b9151c62dd719538f9719fd9dc49079edf12869 + http://bash.org.ru/quote/414892 + #414892 + Mon, 26 Dec 2011 08:46:01 +0400 + : )]]> + + + 533d63288a28594dd6858f5eb212c9fd62c95da02ef6c532902585a525f78b2e + http://bash.org.ru/quote/414891 + #414891 + Mon, 26 Dec 2011 08:13:01 +0400 + : - , -
: )
: )]]>
+
+ + 92cf655d26cbe5d10b1af532ab4abb491a0d74ae9759cb81cd6dd4bb84a1d2bc + http://bash.org.ru/quote/414890 + #414890 + Sun, 25 Dec 2011 09:13:01 +0400 +
: , . 12 , , . : ! ?]]>
+
+
+
\ No newline at end of file diff --git a/protocols/NewsAggregator/Src/Common.h b/protocols/NewsAggregator/Src/Common.h new file mode 100644 index 0000000000..fedb81250c --- /dev/null +++ b/protocols/NewsAggregator/Src/Common.h @@ -0,0 +1,162 @@ +/* +Copyright (C) 2012 Mataes + +This is free software; you can redistribute it and/or +modify it under the terms of the GNU Library General Public +License as published by the Free Software Foundation; either +version 2 of the License, or (at your option) any later version. + +This 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 +Library General Public License for more details. + +You should have received a copy of the GNU Library General Public +License along with this file; see the file license.txt. If +not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. +*/ + +#define MIRANDA_VER 0x0A00 + +// Windows Header Files: +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +// Miranda header files +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include "..\version.h" +#include "..\resource.h" + +#define MODULE "NewsAggr" +#define TAGSHELP "## - The title of the item.\r\n#<description># - The item synopsis.\r\n#<link># - The URL of the item.\r\n#<author># - Email address of the author of the item.\r\n#<comments># - URL of a page for comments relating to the item.\r\n#<guid># - A string that uniquely identifies the item.\r\n#<category># - Specify one or more categories that the item belongs to." +#define TAGSDEFAULT "#<title>#\r\n#<link>#\r\n#<description>#" +#define DEFAULT_AVATARS_FOLDER "NewsAggregator" +extern HINSTANCE hInst; +extern HWND hAddFeedDlg; +extern HANDLE hChangeFeedDlgList; +extern UINT_PTR timerId; +// check if Feeds is currently updating +extern BOOL ThreadRunning; +extern BOOL UpdateListFlag; +extern TCHAR tszRoot[MAX_PATH]; +struct ItemInfo +{ + HWND hwndList; + HANDLE hContact; + int SelNumber; + TCHAR nick[MAX_PATH]; + TCHAR url[MAX_PATH]; +}; + +//============ STRUCT USED TO MAKE AN UPDATE LIST ============ + +struct NEWSCONTACTLIST { + HANDLE hContact; + struct NEWSCONTACTLIST *next; +}; + +typedef struct NEWSCONTACTLIST UPDATELIST; + +extern UPDATELIST *UpdateListHead; +extern UPDATELIST *UpdateListTail; + +void UpdateListAdd(HANDLE hContact); +void UpdateThreadProc(LPVOID hWnd); +void DestroyUpdateList(void); + +extern HANDLE hUpdateMutex; + +int NewsAggrInit(WPARAM wParam,LPARAM lParam); +INT OptInit(WPARAM wParam, LPARAM lParam); +int NewsAggrPreShutdown(WPARAM wParam,LPARAM lParam); +VOID NetlibInit(); +VOID NetlibUnInit(); +VOID InitMenu(); +VOID InitIcons(); +HICON LoadIconEx(const char* name, BOOL big); +HANDLE GetIconHandle(const char* name); +INT_PTR NewsAggrGetName(WPARAM wParam, LPARAM lParam); +INT_PTR NewsAggrGetCaps(WPARAM wp,LPARAM lp); +INT_PTR NewsAggrSetStatus(WPARAM wp,LPARAM /*lp*/); +INT_PTR NewsAggrGetStatus(WPARAM/* wp*/,LPARAM/* lp*/); +INT_PTR NewsAggrLoadIcon(WPARAM wParam,LPARAM lParam); +INT_PTR NewsAggrGetInfo(WPARAM wParam,LPARAM lParam); +INT_PTR NewsAggrGetAvatarInfo(WPARAM wParam,LPARAM lParam); + +INT_PTR CheckAllFeeds(WPARAM wParam,LPARAM lParam); +INT_PTR AddFeed(WPARAM wParam,LPARAM lParam); +INT_PTR ChangeFeed(WPARAM wParam,LPARAM lParam); +INT_PTR ImportFeeds(WPARAM wParam,LPARAM lParam); +INT_PTR ExportFeeds(WPARAM wParam,LPARAM lParam); +INT_PTR CheckFeed(WPARAM wParam,LPARAM lParam); +INT_PTR CALLBACK DlgProcAddFeedOpts(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam); +INT_PTR CALLBACK DlgProcChangeFeedOpts(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam); +INT_PTR CALLBACK DlgProcChangeFeedMenu(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam); +VOID CALLBACK timerProc(HWND hwnd, UINT uMsg, UINT_PTR idEvent, DWORD dwTime); +VOID CALLBACK timerProc2(HWND hwnd, UINT uMsg, UINT_PTR idEvent, DWORD dwTime); + +BOOL IsMyContact(HANDLE hContact); +VOID GetNewsData(TCHAR *szUrl, char** szData, HANDLE hContact, HWND hwndDlg); +VOID CreateList (HWND hwndList); +VOID UpdateList (HWND hwndList); +VOID DeleteAllItems(HWND hwndList); +time_t __stdcall DateToUnixTime(TCHAR *stamp, BOOL FeedType); +VOID CheckCurrentFeed (HANDLE hContact); +TCHAR* CheckFeed(TCHAR* tszURL, HWND hwndDlg); +size_t decode_html_entities_utf8(char *dest, const char *src); + +// =============== NewsAggr SERVICES ================ +// Check all Feeds info +// WPARAM = LPARAM = NULL +#define MS_NEWSAGGR_CHECKALLFEEDS "NEWSAGGR/CheckAllFeeds" + +// Add new Feed channel +// WPARAM = LPARAM = NULL +#define MS_NEWSAGGR_ADDFEED "NEWSAGGR/AddNewsFeed" + +// Add new Feed channel +// WPARAM = LPARAM = NULL +#define MS_NEWSAGGR_CHANGEFEED "NEWSAGGR/ChangeNewsFeed" + +// Import Feed chanels from file +// WPARAM = LPARAM = NULL +#define MS_NEWSAGGR_IMPORTFEEDS "NEWSAGGR/ImportFeeds" + +// Export Feed chanels to file +// WPARAM = LPARAM = NULL +#define MS_NEWSAGGR_EXPORTFEEDS "NEWSAGGR/ExportFeeds" + +// Check Feed info +// WPARAM = LPARAM = NULL +#define MS_NEWSAGGR_CHECKFEED "NEWSAGGR/CheckFeed" \ No newline at end of file diff --git a/protocols/NewsAggregator/Src/Entities.cpp b/protocols/NewsAggregator/Src/Entities.cpp new file mode 100644 index 0000000000..46a00d2d8d --- /dev/null +++ b/protocols/NewsAggregator/Src/Entities.cpp @@ -0,0 +1,381 @@ +#include "common.h" + +#define UNICODE_MAX 0x10FFFFul + +static const char *named_entities[][2] = +{ + { "AElig;", "Æ" }, + { "Aacute;", "Á" }, + { "Acirc;", "Â" }, + { "Agrave;", "À" }, + { "Alpha;", "Α" }, + { "Aring;", "Å" }, + { "Atilde;", "Ã" }, + { "Auml;", "Ä" }, + { "Beta;", "Β" }, + { "Ccedil;", "Ç" }, + { "Chi;", "Χ" }, + { "Dagger;", "‡" }, + { "Delta;", "Δ" }, + { "ETH;", "Ð" }, + { "Eacute;", "É" }, + { "Ecirc;", "Ê" }, + { "Egrave;", "È" }, + { "Epsilon;", "Ε" }, + { "Eta;", "Η" }, + { "Euml;", "Ë" }, + { "Gamma;", "Γ" }, + { "Iacute;", "Í" }, + { "Icirc;", "Î" }, + { "Igrave;", "Ì" }, + { "Iota;", "Ι" }, + { "Iuml;", "Ï" }, + { "Kappa;", "Κ" }, + { "Lambda;", "Λ" }, + { "Mu;", "Μ" }, + { "Ntilde;", "Ñ" }, + { "Nu;", "Ν" }, + { "OElig;", "Œ" }, + { "Oacute;", "Ó" }, + { "Ocirc;", "Ô" }, + { "Ograve;", "Ò" }, + { "Omega;", "Ω" }, + { "Omicron;", "Ο" }, + { "Oslash;", "Ø" }, + { "Otilde;", "Õ" }, + { "Ouml;", "Ö" }, + { "Phi;", "Φ" }, + { "Pi;", "Π" }, + { "Prime;", "″" }, + { "Psi;", "Ψ" }, + { "Rho;", "Ρ" }, + { "Scaron;", "Š" }, + { "Sigma;", "Σ" }, + { "THORN;", "Þ" }, + { "Tau;", "Τ" }, + { "Theta;", "Θ" }, + { "Uacute;", "Ú" }, + { "Ucirc;", "Û" }, + { "Ugrave;", "Ù" }, + { "Upsilon;", "Υ" }, + { "Uuml;", "Ü" }, + { "Xi;", "Ξ" }, + { "Yacute;", "Ý" }, + { "Yuml;", "Ÿ" }, + { "Zeta;", "Ζ" }, + { "aacute;", "á" }, + { "acirc;", "â" }, + { "acute;", "´" }, + { "aelig;", "æ" }, + { "agrave;", "à" }, + { "alefsym;", "ℵ" }, + { "alpha;", "α" }, + { "amp;", "&" }, + { "and;", "∧" }, + { "ang;", "∠" }, + { "apos;", "'" }, + { "aring;", "å" }, + { "asymp;", "≈" }, + { "atilde;", "ã" }, + { "auml;", "ä" }, + { "bdquo;", "„" }, + { "beta;", "β" }, + { "brvbar;", "¦" }, + { "bull;", "•" }, + { "cap;", "∩" }, + { "ccedil;", "ç" }, + { "cedil;", "¸" }, + { "cent;", "¢" }, + { "chi;", "χ" }, + { "circ;", "ˆ" }, + { "clubs;", "♣" }, + { "cong;", "≅" }, + { "copy;", "©" }, + { "crarr;", "↵" }, + { "cup;", "∪" }, + { "curren;", "¤" }, + { "dArr;", "⇓" }, + { "dagger;", "†" }, + { "darr;", "↓" }, + { "deg;", "°" }, + { "delta;", "δ" }, + { "diams;", "♦" }, + { "divide;", "÷" }, + { "eacute;", "é" }, + { "ecirc;", "ê" }, + { "egrave;", "è" }, + { "empty;", "∅" }, + { "emsp;", " " }, + { "ensp;", " " }, + { "epsilon;", "ε" }, + { "equiv;", "≡" }, + { "eta;", "η" }, + { "eth;", "ð" }, + { "euml;", "ë" }, + { "euro;", "€" }, + { "exist;", "∃" }, + { "fnof;", "ƒ" }, + { "forall;", "∀" }, + { "frac12;", "½" }, + { "frac14;", "¼" }, + { "frac34;", "¾" }, + { "frasl;", "⁄" }, + { "gamma;", "γ" }, + { "ge;", "≥" }, + { "gt;", ">" }, + { "hArr;", "⇔" }, + { "harr;", "↔" }, + { "hearts;", "♥" }, + { "hellip;", "…" }, + { "iacute;", "í" }, + { "icirc;", "î" }, + { "iexcl;", "¡" }, + { "igrave;", "ì" }, + { "image;", "ℑ" }, + { "infin;", "∞" }, + { "int;", "∫" }, + { "iota;", "ι" }, + { "iquest;", "¿" }, + { "isin;", "∈" }, + { "iuml;", "ï" }, + { "kappa;", "κ" }, + { "lArr;", "⇐" }, + { "lambda;", "λ" }, + { "lang;", "〈" }, + { "laquo;", "«" }, + { "larr;", "←" }, + { "lceil;", "⌈" }, + { "ldquo;", "“" }, + { "le;", "≤" }, + { "lfloor;", "⌊" }, + { "lowast;", "∗" }, + { "loz;", "◊" }, + { "lrm;", "\xE2\x80\x8E" }, + { "lsaquo;", "‹" }, + { "lsquo;", "‘" }, + { "lt;", "<" }, + { "macr;", "¯" }, + { "mdash;", "—" }, + { "micro;", "µ" }, + { "middot;", "·" }, + { "minus;", "−" }, + { "mu;", "μ" }, + { "nabla;", "∇" }, + { "nbsp;", " " }, + { "ndash;", "–" }, + { "ne;", "≠" }, + { "ni;", "∋" }, + { "not;", "¬" }, + { "notin;", "∉" }, + { "nsub;", "⊄" }, + { "ntilde;", "ñ" }, + { "nu;", "ν" }, + { "oacute;", "ó" }, + { "ocirc;", "ô" }, + { "oelig;", "œ" }, + { "ograve;", "ò" }, + { "oline;", "‾" }, + { "omega;", "ω" }, + { "omicron;", "ο" }, + { "oplus;", "⊕" }, + { "or;", "∨" }, + { "ordf;", "ª" }, + { "ordm;", "º" }, + { "oslash;", "ø" }, + { "otilde;", "õ" }, + { "otimes;", "⊗" }, + { "ouml;", "ö" }, + { "para;", "¶" }, + { "part;", "∂" }, + { "permil;", "‰" }, + { "perp;", "⊥" }, + { "phi;", "φ" }, + { "pi;", "π" }, + { "piv;", "ϖ" }, + { "plusmn;", "±" }, + { "pound;", "£" }, + { "prime;", "′" }, + { "prod;", "∏" }, + { "prop;", "∝" }, + { "psi;", "ψ" }, + { "quot;", "\"" }, + { "rArr;", "⇒" }, + { "radic;", "√" }, + { "rang;", "〉" }, + { "raquo;", "»" }, + { "rarr;", "→" }, + { "rceil;", "⌉" }, + { "rdquo;", "”" }, + { "real;", "ℜ" }, + { "reg;", "®" }, + { "rfloor;", "⌋" }, + { "rho;", "ρ" }, + { "rlm;", "\xE2\x80\x8F" }, + { "rsaquo;", "›" }, + { "rsquo;", "’" }, + { "sbquo;", "‚" }, + { "scaron;", "š" }, + { "sdot;", "⋅" }, + { "sect;", "§" }, + { "shy;", "\xC2\xAD" }, + { "sigma;", "σ" }, + { "sigmaf;", "ς" }, + { "sim;", "∼" }, + { "spades;", "♠" }, + { "sub;", "⊂" }, + { "sube;", "⊆" }, + { "sum;", "∑" }, + { "sup;", "⊃" }, + { "sup1;", "¹" }, + { "sup2;", "²" }, + { "sup3;", "³" }, + { "supe;", "⊇" }, + { "szlig;", "ß" }, + { "tau;", "τ" }, + { "there4;", "∴" }, + { "theta;", "θ" }, + { "thetasym;", "ϑ" }, + { "thinsp;", " " }, + { "thorn;", "þ" }, + { "tilde;", "˜" }, + { "times;", "×" }, + { "trade;", "™" }, + { "uArr;", "⇑" }, + { "uacute;", "ú" }, + { "uarr;", "↑" }, + { "ucirc;", "û" }, + { "ugrave;", "ù" }, + { "uml;", "¨" }, + { "upsih;", "ϒ" }, + { "upsilon;", "υ" }, + { "uuml;", "ü" }, + { "weierp;", "℘" }, + { "xi;", "ξ" }, + { "yacute;", "ý" }, + { "yen;", "¥" }, + { "yuml;", "ÿ" }, + { "zeta;", "ζ" }, + { "zwj;", "\xE2\x80\x8D" }, + { "zwnj;", "\xE2\x80\x8C" } +}; + +static int cmp(const void *key, const void *element) +{ + return strncmp((const char *)key, *(const char **)element, + strlen(*(const char **)element)); +} + +static const char *get_named_entity(const char *name) +{ + const char **entity = (const char **)bsearch(name, named_entities, sizeof(named_entities) / sizeof(*named_entities), + sizeof(*named_entities), cmp); + + return entity ? entity[1] : NULL; +} + +static size_t putc_utf8(unsigned long cp, char *buffer) +{ + unsigned char *bytes = (unsigned char *)buffer; + + if(cp <= 0x007Ful) + { + bytes[0] = (unsigned char)cp; + return 1; + } + + if(cp <= 0x07FFul) + { + bytes[1] = (unsigned char)((2u << 6) | (cp & 0x3Fu)); + bytes[0] = (unsigned char)((6u << 5) | (cp >> 6)); + return 2; + } + + if(cp <= 0xFFFFul) + { + bytes[2] = (unsigned char)(( 2u << 6) | ( cp & 0x3Fu)); + bytes[1] = (unsigned char)(( 2u << 6) | ((cp >> 6) & 0x3Fu)); + bytes[0] = (unsigned char)((14u << 4) | (cp >> 12)); + return 3; + } + + if(cp <= 0x10FFFFul) + { + bytes[3] = (unsigned char)(( 2u << 6) | ( cp & 0x3Fu)); + bytes[2] = (unsigned char)(( 2u << 6) | ((cp >> 6) & 0x3Fu)); + bytes[1] = (unsigned char)(( 2u << 6) | ((cp >> 12) & 0x3Fu)); + bytes[0] = (unsigned char)((30u << 3) | (cp >> 18)); + return 4; + } + + return 0; +} + +static BOOL parse_entity(const char *current, char **to, const char **from) +{ + const char *end = strchr(current, ';'); + if (!end) return 0; + + if(current[1] == '#') + { + char *tail = NULL; + errno = 0; + + BOOL hex = current[2] == 'x' || current[2] == 'X'; + + unsigned long cp = strtoul( + current + (hex ? 3 : 2), &tail, hex ? 16 : 10); + + if(tail == end && !errno && cp <= UNICODE_MAX) + { + *to += putc_utf8(cp, *to); + *from = end + 1; + + return 1; + } + } + else + { + const char *entity = get_named_entity(¤t[1]); + if(entity) + { + size_t len = strlen(entity); + memcpy(*to, entity, len); + + *to += len; + *from = end + 1; + + return 1; + } + } + + return 0; +} + +size_t decode_html_entities_utf8(char *dest, const char *src) +{ + if (!src) src = dest; + + char *to = dest; + const char *from = src; + + const char *current; + while(current = strchr(from, '&')) + { + memcpy(to, from, (size_t)(current - from)); + to += current - from; + + if(parse_entity(current, &to, &from)) + continue; + + from = current; + *to++ = *from++; + } + + size_t remaining = strlen(from); + + memcpy(to, from, remaining); + to += remaining; + + *to = 0; + return (size_t)(to - dest); +} \ No newline at end of file diff --git a/protocols/NewsAggregator/Src/Icons.cpp b/protocols/NewsAggregator/Src/Icons.cpp new file mode 100644 index 0000000000..096a38086b --- /dev/null +++ b/protocols/NewsAggregator/Src/Icons.cpp @@ -0,0 +1,79 @@ +/* +Copyright (C) 2012 Mataes + +This is free software; you can redistribute it and/or +modify it under the terms of the GNU Library General Public +License as published by the Free Software Foundation; either +version 2 of the License, or (at your option) any later version. + +This 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 +Library General Public License for more details. + +You should have received a copy of the GNU Library General Public +License along with this file; see the file license.txt. If +not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. +*/ + +#include "common.h" + +struct _tag_iconList +{ + TCHAR* szDescr; + char* szName; + int defIconID; + HANDLE hIconLibItem; +} + +static iconList[] = +{ + { LPGENT("Protocol icon"), "main", IDI_ICON }, + { LPGENT("Check All Feeds"), "checkall", IDI_CHECKALL }, + { LPGENT("Add Feed"), "addfeed", IDI_ADDFEED }, + { LPGENT("Import Feeds"), "importfeeds", IDI_IMPORTFEEDS }, + { LPGENT("Export Feeds"), "exportfeeds", IDI_EXPORTFEEDS }, + { LPGENT("Check Feed"), "checkfeed", IDI_CHECKALL }, +}; + +VOID InitIcons() +{ + TCHAR szFile[MAX_PATH]; + char szSettingName[100]; + SKINICONDESC sid = {0}; + unsigned i; + + GetModuleFileName(hInst, szFile, MAX_PATH); + + sid.cbSize = sizeof(SKINICONDESC); + sid.flags = SIDF_ALL_TCHAR; + sid.ptszDefaultFile = szFile; + sid.pszName = szSettingName; + sid.ptszSection = _T("News Aggregator"); + + for (i = 0; i < SIZEOF(iconList); i++) + { + mir_snprintf(szSettingName, SIZEOF(szSettingName), "%s_%s", MODULE, iconList[i].szName); + + sid.ptszDescription = iconList[i].szDescr; + sid.iDefaultIndex = -iconList[i].defIconID; + iconList[i].hIconLibItem = ( HANDLE )CallService(MS_SKIN2_ADDICON, 0, (LPARAM)&sid); + } +} + +HICON LoadIconEx(const char* name, BOOL big) +{ + char szSettingName[100]; + mir_snprintf(szSettingName, SIZEOF(szSettingName), "%s_%s", MODULE, name); + return (HICON)CallService(MS_SKIN2_GETICON, big, (LPARAM)szSettingName); +} + +HANDLE GetIconHandle(const char* name) +{ + unsigned i; + for (i=0; i < SIZEOF(iconList); i++) + if (strcmp(iconList[i].szName, name) == 0) + return iconList[i].hIconLibItem; + return NULL; +} \ No newline at end of file diff --git a/protocols/NewsAggregator/Src/Menus.cpp b/protocols/NewsAggregator/Src/Menus.cpp new file mode 100644 index 0000000000..2ff20ce596 --- /dev/null +++ b/protocols/NewsAggregator/Src/Menus.cpp @@ -0,0 +1,78 @@ +/* +Copyright (C) 2012 Mataes + +This is free software; you can redistribute it and/or +modify it under the terms of the GNU Library General Public +License as published by the Free Software Foundation; either +version 2 of the License, or (at your option) any later version. + +This 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 +Library General Public License for more details. + +You should have received a copy of the GNU Library General Public +License along with this file; see the file license.txt. If +not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. +*/ + +#include "common.h" + +HANDLE hService2[6]; + +VOID InitMenu() +{ + CLISTMENUITEM mi = {0}; + mi.cbSize = sizeof(mi); + mi.pszContactOwner = MODULE; + mi.flags = CMIF_TCHAR|CMIF_ICONFROMICOLIB|CMIF_NOTOFFLINE; + + // adding main menu items + mi.ptszPopupName = LPGENT("News Aggregator"); + mi.popupPosition = 500099000; + + mi.position=10100001; + mi.icolibItem = GetIconHandle("main"); + mi.ptszName = LPGENT("Check All Feeds"); + mi.pszService = MS_NEWSAGGR_CHECKALLFEEDS; + hService2[0] = (HANDLE)CallService(MS_CLIST_ADDMAINMENUITEM,0,(LPARAM)&mi); + + mi.position=10100002; + mi.icolibItem = GetIconHandle("addfeed"); + mi.ptszName = LPGENT("Add Feed"); + mi.pszService = MS_NEWSAGGR_ADDFEED; + hService2[1] = (HANDLE)CallService(MS_CLIST_ADDMAINMENUITEM,0,(LPARAM)&mi); + + mi.position=10100003; + mi.icolibItem = GetIconHandle("importfeeds"); + mi.ptszName = LPGENT("Import Feeds"); + mi.pszService = MS_NEWSAGGR_IMPORTFEEDS; + hService2[2] = (HANDLE)CallService(MS_CLIST_ADDMAINMENUITEM,0,(LPARAM)&mi); + + mi.position=10100004; + mi.icolibItem = GetIconHandle("exportfeeds"); + mi.ptszName = LPGENT("Export Feeds"); + mi.pszService = MS_NEWSAGGR_EXPORTFEEDS; + hService2[3] = (HANDLE)CallService(MS_CLIST_ADDMAINMENUITEM,0,(LPARAM)&mi); + + // adding contact menu items + mi.position=-0x7FFFFFFA; + mi.icolibItem = GetIconHandle("checkfeed"); + mi.ptszName = LPGENT("Check feed"); + mi.pszService = MS_NEWSAGGR_CHECKFEED; + hService2[4] = (HANDLE)CallService(MS_CLIST_ADDCONTACTMENUITEM,0,(LPARAM)&mi); + + // adding contact menu items + mi.position=-0x7FFFFFFA; + //mi.icolibItem = GetIconHandle("checkfeed"); + mi.ptszName = LPGENT("Change feed"); + mi.pszService = MS_NEWSAGGR_CHANGEFEED; + hService2[5] = (HANDLE)CallService(MS_CLIST_ADDCONTACTMENUITEM,0,(LPARAM)&mi); + + ZeroMemory(&mi, sizeof(mi)); + mi.cbSize = sizeof(mi); + mi.flags = CMIM_ICON; + mi.icolibItem = GetIconHandle("checkall"); + CallService(MS_CLIST_MODIFYMENUITEM, (WPARAM)hService2[0], (LPARAM)&mi); +} \ No newline at end of file diff --git a/protocols/NewsAggregator/Src/NewsAggregator.cpp b/protocols/NewsAggregator/Src/NewsAggregator.cpp new file mode 100644 index 0000000000..716ef85d17 --- /dev/null +++ b/protocols/NewsAggregator/Src/NewsAggregator.cpp @@ -0,0 +1,136 @@ +/* +Copyright (C) 2012 Mataes + +This is free software; you can redistribute it and/or +modify it under the terms of the GNU Library General Public +License as published by the Free Software Foundation; either +version 2 of the License, or (at your option) any later version. + +This 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 +Library General Public License for more details. + +You should have received a copy of the GNU Library General Public +License along with this file; see the file license.txt. If +not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. +*/ + +#include "Common.h" + +HINSTANCE hInst = NULL; +PLUGINLINK *pluginLink; +int hLangpack; +struct MM_INTERFACE mmi; +HANDLE hOptHook = NULL, hLoadHook = NULL, hOnPreShutdown = NULL, hPrebuildMenuHook = NULL, hPackUpdaterFolder = NULL; +HANDLE hProtoService[7]; +HWND hAddFeedDlg; +HANDLE hChangeFeedDlgList = NULL; +XML_API xi = {0}; +struct UTF8_INTERFACE utfi; +TCHAR tszRoot[MAX_PATH] = {0}; +HANDLE hUpdateMutex; +#define NUM_SERVICES 6 +HANDLE hService[NUM_SERVICES]; + +PLUGININFOEX pluginInfoEx = { + sizeof(PLUGININFOEX), + __PLUGIN_NAME, + PLUGIN_MAKE_VERSION(__MAJOR_VERSION, __MINOR_VERSION, __RELEASE_NUM, __BUILD_NUM), + __DESCRIPTION, + __AUTHOR, + __AUTHOREMAIL, + __COPYRIGHT, + __AUTHORWEB, + UNICODE_AWARE, + 0, + // {56CC3F29-CCBF-4546-A8BA-9856248A412A} + {0x56cc3f29, 0xccbf, 0x4546, {0xa8, 0xba, 0x98, 0x56, 0x24, 0x8a, 0x41, 0x2a}} +}; + +BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved) +{ + hInst = hinstDLL; + return TRUE; +} + +extern "C" __declspec(dllexport) PLUGININFOEX* MirandaPluginInfoEx(DWORD mirandaVersion) +{ + return &pluginInfoEx; +} + +static const MUUID interfaces[] = {{0x29517be5, 0x779a, 0x48e5, {0x89, 0x50, 0xcb, 0x4d, 0xe1, 0xd4, 0x31, 0x72}}, MIID_LAST}; + +extern "C" __declspec(dllexport) const MUUID* MirandaPluginInterfaces(void) +{ + return interfaces; +} + +extern "C" __declspec(dllexport) int Load(PLUGINLINK *link) +{ + pluginLink = link; + mir_getLP(&pluginInfoEx); + mir_getMMI(&mmi); + mir_getXI(&xi); + mir_getUTFI(&utfi); + + if (ServiceExists(MS_FOLDERS_REGISTER_PATH)) + { + hPackUpdaterFolder = FoldersRegisterCustomPathT("News Aggregator", "Avatars", MIRANDA_USERDATAT _T("\\Avatars\\")_T(DEFAULT_AVATARS_FOLDER)); + FoldersGetCustomPathT(hPackUpdaterFolder, tszRoot, MAX_PATH, _T("")); + } + else + { + TCHAR* tszFolder = Utils_ReplaceVarsT(_T("%miranda_userdata%\\"_T(DEFAULT_AVATARS_FOLDER))); + lstrcpyn(tszRoot, tszFolder, SIZEOF(tszRoot)); + mir_free(tszFolder); + } + + // Add options hook + hOptHook = HookEvent(ME_OPT_INITIALISE, OptInit); + hLoadHook = HookEvent(ME_SYSTEM_MODULESLOADED, NewsAggrInit); + hOnPreShutdown = HookEvent(ME_SYSTEM_PRESHUTDOWN, NewsAggrPreShutdown); + + hUpdateMutex = CreateMutex(NULL, FALSE, NULL); + hChangeFeedDlgList = (HANDLE) CallService(MS_UTILS_ALLOCWINDOWLIST,0,0); + + // register weather protocol + PROTOCOLDESCRIPTOR pd = {0}; + pd.cbSize = PROTOCOLDESCRIPTOR_V3_SIZE; + pd.szName = MODULE; + pd.type = PROTOTYPE_PROTOCOL; + CallService(MS_PROTO_REGISTERMODULE,0,(LPARAM)&pd); + + hProtoService[0] = CreateProtoServiceFunction(MODULE, PS_GETNAME, NewsAggrGetName); + hProtoService[1] = CreateProtoServiceFunction(MODULE, PS_GETCAPS, NewsAggrGetCaps); + hProtoService[2] = CreateProtoServiceFunction(MODULE, PS_SETSTATUS, NewsAggrSetStatus); + hProtoService[3] = CreateProtoServiceFunction(MODULE, PS_GETSTATUS, NewsAggrGetStatus); + hProtoService[4] = CreateProtoServiceFunction(MODULE, PS_LOADICON, NewsAggrLoadIcon); + hProtoService[5] = CreateProtoServiceFunction(MODULE, PSS_GETINFO, NewsAggrGetInfo); + hProtoService[6] = CreateProtoServiceFunction(MODULE, PS_GETAVATARINFO, NewsAggrGetAvatarInfo); + + hService[0] = CreateServiceFunction(MS_NEWSAGGR_CHECKALLFEEDS, CheckAllFeeds); + hService[1] = CreateServiceFunction(MS_NEWSAGGR_ADDFEED, AddFeed); + hService[2] = CreateServiceFunction(MS_NEWSAGGR_IMPORTFEEDS, ImportFeeds); + hService[3] = CreateServiceFunction(MS_NEWSAGGR_EXPORTFEEDS, ExportFeeds); + hService[4] = CreateServiceFunction(MS_NEWSAGGR_CHECKFEED, CheckFeed); + hService[5] = CreateServiceFunction(MS_NEWSAGGR_CHANGEFEED, ChangeFeed); + + return 0; +} + +extern "C" __declspec(dllexport) int Unload(void) +{ + for (int i = 0;i<NUM_SERVICES;i++) + DestroyServiceFunction(hService[i]); + + UnhookEvent(hOptHook); + UnhookEvent(hLoadHook); + UnhookEvent(hOnPreShutdown); + + DestroyUpdateList(); + CloseHandle(hUpdateMutex); + + return 0; +} \ No newline at end of file diff --git a/protocols/NewsAggregator/Src/Options.cpp b/protocols/NewsAggregator/Src/Options.cpp new file mode 100644 index 0000000000..b9dc78b90c --- /dev/null +++ b/protocols/NewsAggregator/Src/Options.cpp @@ -0,0 +1,649 @@ +/* +Copyright (C) 2012 Mataes + +This is free software; you can redistribute it and/or +modify it under the terms of the GNU Library General Public +License as published by the Free Software Foundation; either +version 2 of the License, or (at your option) any later version. + +This 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 +Library General Public License for more details. + +You should have received a copy of the GNU Library General Public +License along with this file; see the file license.txt. If +not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. +*/ + +#include "common.h" + +INT_PTR CALLBACK DlgProcAddFeedOpts(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam) +{ + switch (msg) + { + case WM_INITDIALOG: + { + TranslateDialogDefault(hwndDlg); + SetWindowLongPtr(hwndDlg, GWLP_USERDATA, lParam); + SetWindowText(hwndDlg, TranslateT("Add Feed")); + SetDlgItemText(hwndDlg, IDC_FEEDURL, _T("http://")); + SetDlgItemText(hwndDlg, IDC_TAGSEDIT, _T(TAGSDEFAULT)); + SendDlgItemMessage(hwndDlg, IDC_CHECKTIME, EM_LIMITTEXT, 3, 0); + SetDlgItemInt(hwndDlg, IDC_CHECKTIME, 60, TRUE); + SendDlgItemMessage(hwndDlg, IDC_TIMEOUT_VALUE_SPIN, UDM_SETRANGE32, 0, 999); + Utils_RestoreWindowPositionNoSize(hwndDlg,NULL,MODULE,"AddDlg"); + return TRUE; + } + case WM_COMMAND: + { + switch (LOWORD(wParam)) + { + case IDOK: + { + TCHAR str[MAX_PATH]; + if (!GetDlgItemText(hwndDlg, IDC_FEEDTITLE, str, SIZEOF(str))) + { + MessageBox(hwndDlg, TranslateT("Enter Feed name"), TranslateT("Error"), MB_OK); + break; + } + else if (!GetDlgItemText(hwndDlg, IDC_FEEDURL, str, SIZEOF(str)) || lstrcmp(str, _T("http://")) == 0) + { + MessageBox(hwndDlg, TranslateT("Enter Feed URL"), TranslateT("Error"), MB_OK); + break; + } + else if (GetDlgItemInt(hwndDlg, IDC_CHECKTIME, false, false) < 0) + { + MessageBox(hwndDlg, TranslateT("Enter checking interval"), TranslateT("Error"), MB_OK); + break; + } + else if (!GetDlgItemText(hwndDlg, IDC_TAGSEDIT, str, SIZEOF(str))) + { + MessageBox(hwndDlg, TranslateT("Enter message format"), TranslateT("Error"), MB_OK); + break; + } + else + { + HANDLE hContact = (HANDLE) CallService(MS_DB_CONTACT_ADD, 0, 0); + CallService(MS_PROTO_ADDTOCONTACT, (WPARAM)hContact, (LPARAM)MODULE); + GetDlgItemText(hwndDlg, IDC_FEEDTITLE, str, SIZEOF(str)); + DBWriteContactSettingTString(hContact, MODULE, "Nick", str); + HWND hwndList = (HWND)GetWindowLongPtr(hwndDlg, GWLP_USERDATA); + GetDlgItemText(hwndDlg, IDC_FEEDURL, str, SIZEOF(str)); + DBWriteContactSettingTString(hContact, MODULE, "URL", str); + DBWriteContactSettingByte(hContact, MODULE, "CheckState", 1); + DBWriteContactSettingDword(hContact, MODULE, "UpdateTime", GetDlgItemInt(hwndDlg, IDC_CHECKTIME, false, false)); + GetDlgItemText(hwndDlg, IDC_TAGSEDIT, str, SIZEOF(str)); + DBWriteContactSettingTString(hContact, MODULE, "MsgFormat", str); + DBWriteContactSettingWord(hContact, MODULE, "Status", CallProtoService(MODULE, PS_GETSTATUS, 0, 0)); + if (IsDlgButtonChecked(hwndDlg, IDC_USEAUTH)) + { + DBWriteContactSettingByte(hContact, MODULE, "UseAuth", 1); + GetDlgItemText(hwndDlg, IDC_LOGIN, str, SIZEOF(str)); + DBWriteContactSettingTString(hContact, MODULE, "Login", str); + GetDlgItemText(hwndDlg, IDC_PASSWORD, str, SIZEOF(str)); + DBWriteContactSettingTString(hContact, MODULE, "Password", str); + } + DeleteAllItems(hwndList); + UpdateList(hwndList); + } + } + + case IDCANCEL: + DestroyWindow(hwndDlg); + break; + + case IDC_USEAUTH: + { + if (IsDlgButtonChecked(hwndDlg, IDC_USEAUTH)) + { + EnableWindow(GetDlgItem(hwndDlg, IDC_LOGIN), TRUE); + EnableWindow(GetDlgItem(hwndDlg, IDC_PASSWORD), TRUE); + } + else + { + EnableWindow(GetDlgItem(hwndDlg, IDC_LOGIN), FALSE); + EnableWindow(GetDlgItem(hwndDlg, IDC_PASSWORD), FALSE); + } + } + break; + + case IDC_TAGHELP: + MessageBox(hwndDlg, TranslateT(TAGSHELP), TranslateT("Feed Tag Help"), MB_OK); + break; + + case IDC_RESET: + if (MessageBox(hwndDlg, TranslateT("Are you sure?"), TranslateT("Tags Mask Reset"), MB_YESNO | MB_ICONWARNING) == IDYES) + SetDlgItemText(hwndDlg, IDC_TAGSEDIT, _T(TAGSDEFAULT)); + break; + + case IDC_DISCOVERY: + { + EnableWindow(GetDlgItem(hwndDlg, IDC_DISCOVERY), FALSE); + SetDlgItemText(hwndDlg, IDC_DISCOVERY, TranslateT("Wait...")); + TCHAR tszURL[MAX_PATH] = {0}, *tszTitle = NULL; + if (GetDlgItemText(hwndDlg, IDC_FEEDURL, tszURL, SIZEOF(tszURL)) || lstrcmp(tszURL, _T("http://")) != 0) + tszTitle = CheckFeed(tszURL, hwndDlg); + else + MessageBox(hwndDlg, TranslateT("Enter Feed URL"), TranslateT("Error"), MB_OK); + SetDlgItemText(hwndDlg, IDC_FEEDTITLE, tszTitle); + EnableWindow(GetDlgItem(hwndDlg, IDC_DISCOVERY), TRUE); + SetDlgItemText(hwndDlg, IDC_DISCOVERY, TranslateT("Check Feed")); + } + break; + } + break; + } + case WM_CLOSE: + { + DestroyWindow(hwndDlg); + break; + } + case WM_DESTROY: + { + Utils_SaveWindowPosition(hwndDlg,NULL,MODULE,"AddDlg"); + } + } + + return FALSE; +} + +INT_PTR CALLBACK DlgProcChangeFeedOpts(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam) +{ + switch (msg) + { + case WM_INITDIALOG: + { + TranslateDialogDefault(hwndDlg); + ItemInfo &SelItem = *(ItemInfo*)lParam; + ItemInfo *nSelItem = new ItemInfo(SelItem); + SetWindowText(hwndDlg, TranslateT("Change Feed")); + SendDlgItemMessage(hwndDlg, IDC_CHECKTIME, EM_LIMITTEXT, 3, 0); + SendDlgItemMessage(hwndDlg, IDC_TIMEOUT_VALUE_SPIN, UDM_SETRANGE32, 0, 999); + + HANDLE hContact = (HANDLE)CallService(MS_DB_CONTACT_FINDFIRST, 0, 0); + while (hContact != NULL) + { + if (IsMyContact(hContact)) + { + DBVARIANT dbNick = {0}; + if (DBGetContactSettingTString(hContact, MODULE, "Nick", &dbNick)) + continue; + else if (lstrcmp(dbNick.ptszVal, SelItem.nick) == 0) + { + DBFreeVariant(&dbNick); + DBVARIANT dbURL = {0}; + if (DBGetContactSettingTString(hContact, MODULE, "URL", &dbURL)) + continue; + else if (lstrcmp(dbURL.ptszVal, SelItem.url) == 0) + { + DBFreeVariant(&dbURL); + nSelItem->hContact = hContact; + SetWindowLongPtr(hwndDlg, GWLP_USERDATA, (LONG)nSelItem); + SetDlgItemText(hwndDlg, IDC_FEEDURL, SelItem.url); + SetDlgItemText(hwndDlg, IDC_FEEDTITLE, SelItem.nick); + SetDlgItemInt(hwndDlg, IDC_CHECKTIME, DBGetContactSettingDword(hContact, MODULE, "UpdateTime", 60), TRUE); + DBVARIANT dbMsg = {0}; + if (!DBGetContactSettingTString(hContact, MODULE, "MsgFormat", &dbMsg)) + { + SetDlgItemText(hwndDlg, IDC_TAGSEDIT, dbMsg.ptszVal); + DBFreeVariant(&dbMsg); + } + if (DBGetContactSettingByte(hContact, MODULE, "UseAuth", 0)) + { + CheckDlgButton(hwndDlg, IDC_USEAUTH, BST_CHECKED); + EnableWindow(GetDlgItem(hwndDlg, IDC_LOGIN), TRUE); + EnableWindow(GetDlgItem(hwndDlg, IDC_PASSWORD), TRUE); + DBVARIANT dbLogin = {0}; + if (!DBGetContactSettingTString(hContact, MODULE, "Login", &dbLogin)) + { + SetDlgItemText(hwndDlg, IDC_LOGIN, dbLogin.ptszVal); + DBFreeVariant(&dbLogin); + } + DBVARIANT dbPass = {0}; + if (!DBGetContactSettingTString(hContact, MODULE, "Password", &dbPass)) + { + SetDlgItemText(hwndDlg, IDC_PASSWORD, dbPass.ptszVal); + DBFreeVariant(&dbPass); + } + } + break; + } + DBFreeVariant(&dbURL); + } + DBFreeVariant(&dbNick); + } + hContact = (HANDLE)CallService(MS_DB_CONTACT_FINDNEXT, (WPARAM)hContact, 0); + } + WindowList_Add(hChangeFeedDlgList,hwndDlg,hContact); + Utils_RestoreWindowPositionNoSize(hwndDlg,hContact,MODULE,"ChangeDlg"); + return TRUE; + } + case WM_COMMAND: + { + switch (LOWORD(wParam)) + { + case IDOK: + { + ItemInfo *SelItem = (ItemInfo*)GetWindowLongPtr(hwndDlg, GWLP_USERDATA); + TCHAR str[MAX_PATH]; + if (!GetDlgItemText(hwndDlg, IDC_FEEDTITLE, str, SIZEOF(str))) + { + MessageBox(hwndDlg, TranslateT("Enter Feed name"), TranslateT("Error"), MB_OK); + break; + } + else if (!GetDlgItemText(hwndDlg, IDC_FEEDURL, str, SIZEOF(str)) || lstrcmp(str, _T("http://")) == 0) + { + MessageBox(hwndDlg, TranslateT("Enter Feed URL"), TranslateT("Error"), MB_OK); + break; + } + else if (GetDlgItemInt(hwndDlg, IDC_CHECKTIME, false, false) < 0) + { + MessageBox(hwndDlg, TranslateT("Enter checking interval"), TranslateT("Error"), MB_OK); + break; + } + else if (!GetDlgItemText(hwndDlg, IDC_TAGSEDIT, str, SIZEOF(str))) + { + MessageBox(hwndDlg, TranslateT("Enter message format"), TranslateT("Error"), MB_OK); + break; + } + else + { + GetDlgItemText(hwndDlg, IDC_FEEDURL, str, SIZEOF(str)); + DBWriteContactSettingTString(SelItem->hContact, MODULE, "URL", str); + GetDlgItemText(hwndDlg, IDC_FEEDTITLE, str, SIZEOF(str)); + DBWriteContactSettingTString(SelItem->hContact, MODULE, "Nick", str); + DBWriteContactSettingDword(SelItem->hContact, MODULE, "UpdateTime", GetDlgItemInt(hwndDlg, IDC_CHECKTIME, false, false)); + GetDlgItemText(hwndDlg, IDC_TAGSEDIT, str, SIZEOF(str)); + DBWriteContactSettingTString(SelItem->hContact, MODULE, "MsgFormat", str); + if (IsDlgButtonChecked(hwndDlg, IDC_USEAUTH)) + { + DBWriteContactSettingByte(SelItem->hContact, MODULE, "UseAuth", 1); + GetDlgItemText(hwndDlg, IDC_LOGIN, str, SIZEOF(str)); + DBWriteContactSettingTString(SelItem->hContact, MODULE, "Login", str); + GetDlgItemText(hwndDlg, IDC_PASSWORD, str, SIZEOF(str)); + DBWriteContactSettingTString(SelItem->hContact, MODULE, "Password", str); + } + DeleteAllItems(SelItem->hwndList); + UpdateList(SelItem->hwndList); + } + } + + case IDCANCEL: + DestroyWindow(hwndDlg); + break; + + case IDC_USEAUTH: + { + if (IsDlgButtonChecked(hwndDlg, IDC_USEAUTH)) + { + EnableWindow(GetDlgItem(hwndDlg, IDC_LOGIN), TRUE); + EnableWindow(GetDlgItem(hwndDlg, IDC_PASSWORD), TRUE); + } + else + { + EnableWindow(GetDlgItem(hwndDlg, IDC_LOGIN), FALSE); + EnableWindow(GetDlgItem(hwndDlg, IDC_PASSWORD), FALSE); + } + break; + } + + case IDC_TAGHELP: + MessageBox(hwndDlg, TranslateT(TAGSHELP), TranslateT("Feed Tag Help"), MB_OK); + break; + + case IDC_RESET: + if (MessageBox(hwndDlg, TranslateT("Are you sure?"), TranslateT("Tags Mask Reset"), MB_YESNO | MB_ICONWARNING) == IDYES) + SetDlgItemText(hwndDlg, IDC_TAGSEDIT, _T(TAGSDEFAULT)); + break; + + case IDC_DISCOVERY: + { + TCHAR tszURL[MAX_PATH] = {0}; + if (GetDlgItemText(hwndDlg, IDC_FEEDURL, tszURL, SIZEOF(tszURL)) || lstrcmp(tszURL, _T("http://")) != 0) + { + EnableWindow(GetDlgItem(hwndDlg, IDC_DISCOVERY), FALSE); + SetDlgItemText(hwndDlg, IDC_DISCOVERY, TranslateT("Wait...")); + TCHAR *tszTitle = CheckFeed(tszURL, hwndDlg); + SetDlgItemText(hwndDlg, IDC_FEEDTITLE, tszTitle); + EnableWindow(GetDlgItem(hwndDlg, IDC_DISCOVERY), TRUE); + SetDlgItemText(hwndDlg, IDC_DISCOVERY, TranslateT("Check Feed")); + } + else + MessageBox(hwndDlg, TranslateT("Enter Feed URL"), TranslateT("Error"), MB_OK); + } + break; + } + break; + } + + case WM_CLOSE: + { + DestroyWindow(hwndDlg); + break; + } + + case WM_DESTROY: + { + HANDLE hContact = (HANDLE) GetWindowLongPtr(hwndDlg, GWLP_USERDATA); + Utils_SaveWindowPosition(hwndDlg,hContact,MODULE,"ChangeDlg"); + WindowList_Remove(hChangeFeedDlgList,hwndDlg); + ItemInfo *SelItem = (ItemInfo*)GetWindowLongPtr(hwndDlg, GWLP_USERDATA); + delete SelItem; + break; + } + } + + return FALSE; +} + +INT_PTR CALLBACK DlgProcChangeFeedMenu(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam) +{ + switch (msg) + { + case WM_INITDIALOG: + { + TranslateDialogDefault(hwndDlg); + SetWindowText(hwndDlg, TranslateT("Change Feed")); + SendDlgItemMessage(hwndDlg, IDC_CHECKTIME, UDM_SETRANGE32, 0, 999); + + HANDLE hContact = (HANDLE)lParam; + WindowList_Add(hChangeFeedDlgList,hwndDlg,hContact); + Utils_RestoreWindowPositionNoSize(hwndDlg,hContact,MODULE,"ChangeDlg"); + DBVARIANT dbNick = {0}; + if (!DBGetContactSettingTString(hContact, MODULE, "Nick", &dbNick)) + { + SetDlgItemText(hwndDlg, IDC_FEEDTITLE, dbNick.ptszVal); + DBFreeVariant(&dbNick); + DBVARIANT dbURL = {0}; + if (!DBGetContactSettingTString(hContact, MODULE, "URL", &dbURL)) + { + SetWindowLongPtr(hwndDlg, GWLP_USERDATA, (LONG)lParam); + SetDlgItemText(hwndDlg, IDC_FEEDURL, dbURL.ptszVal); + DBFreeVariant(&dbURL); + SetDlgItemInt(hwndDlg, IDC_CHECKTIME, DBGetContactSettingDword(hContact, MODULE, "UpdateTime", 60), TRUE); + DBVARIANT dbMsg = {0}; + if (!DBGetContactSettingTString(hContact, MODULE, "MsgFormat", &dbMsg)) + { + SetDlgItemText(hwndDlg, IDC_TAGSEDIT, dbMsg.ptszVal); + DBFreeVariant(&dbMsg); + } + if (DBGetContactSettingByte(hContact, MODULE, "UseAuth", 0)) + { + CheckDlgButton(hwndDlg, IDC_USEAUTH, BST_CHECKED); + EnableWindow(GetDlgItem(hwndDlg, IDC_LOGIN), TRUE); + EnableWindow(GetDlgItem(hwndDlg, IDC_PASSWORD), TRUE); + DBVARIANT dbLogin = {0}; + if (!DBGetContactSettingTString(hContact, MODULE, "Login", &dbLogin)) + { + SetDlgItemText(hwndDlg, IDC_LOGIN, dbLogin.ptszVal); + DBFreeVariant(&dbLogin); + } + DBVARIANT dbPass = {0}; + if (!DBGetContactSettingTString(hContact, MODULE, "Password", &dbPass)) + { + SetDlgItemText(hwndDlg, IDC_PASSWORD, dbPass.ptszVal); + DBFreeVariant(&dbPass); + } + } + break; + } + } + return TRUE; + } + case WM_COMMAND: + { + switch (LOWORD(wParam)) + { + case IDOK: + { + HANDLE hContact = (HANDLE)GetWindowLongPtr(hwndDlg, GWLP_USERDATA); + TCHAR str[MAX_PATH]; + if (!GetDlgItemText(hwndDlg, IDC_FEEDTITLE, str, SIZEOF(str))) + { + MessageBox(hwndDlg, TranslateT("Enter Feed name"), TranslateT("Error"), MB_OK); + break; + } + else if (!GetDlgItemText(hwndDlg, IDC_FEEDURL, str, SIZEOF(str)) || lstrcmp(str, _T("http://")) == 0) + { + MessageBox(hwndDlg, TranslateT("Enter Feed URL"), TranslateT("Error"), MB_OK); + break; + } + else if (GetDlgItemInt(hwndDlg, IDC_CHECKTIME, false, false) < 0) + { + MessageBox(hwndDlg, TranslateT("Enter checking interval"), TranslateT("Error"), MB_OK); + break; + } + else if (!GetDlgItemText(hwndDlg, IDC_TAGSEDIT, str, SIZEOF(str))) + { + MessageBox(hwndDlg, TranslateT("Enter message format"), TranslateT("Error"), MB_OK); + break; + } + else + { + GetDlgItemText(hwndDlg, IDC_FEEDURL, str, SIZEOF(str)); + DBWriteContactSettingTString(hContact, MODULE, "URL", str); + GetDlgItemText(hwndDlg, IDC_FEEDTITLE, str, SIZEOF(str)); + DBWriteContactSettingTString(hContact, MODULE, "Nick", str); + DBWriteContactSettingDword(hContact, MODULE, "UpdateTime", GetDlgItemInt(hwndDlg, IDC_CHECKTIME, false, false)); + GetDlgItemText(hwndDlg, IDC_TAGSEDIT, str, SIZEOF(str)); + DBWriteContactSettingTString(hContact, MODULE, "MsgFormat", str); + if (IsDlgButtonChecked(hwndDlg, IDC_USEAUTH)) + { + DBWriteContactSettingByte(hContact, MODULE, "UseAuth", 1); + GetDlgItemText(hwndDlg, IDC_LOGIN, str, SIZEOF(str)); + DBWriteContactSettingTString(hContact, MODULE, "Login", str); + GetDlgItemText(hwndDlg, IDC_PASSWORD, str, SIZEOF(str)); + DBWriteContactSettingTString(hContact, MODULE, "Password", str); + } + } + } + + case IDCANCEL: + DestroyWindow(hwndDlg); + break; + + case IDC_USEAUTH: + { + if (IsDlgButtonChecked(hwndDlg, IDC_USEAUTH)) + { + EnableWindow(GetDlgItem(hwndDlg, IDC_LOGIN), TRUE); + EnableWindow(GetDlgItem(hwndDlg, IDC_PASSWORD), TRUE); + } + else + { + EnableWindow(GetDlgItem(hwndDlg, IDC_LOGIN), FALSE); + EnableWindow(GetDlgItem(hwndDlg, IDC_PASSWORD), FALSE); + } + break; + } + + case IDC_TAGHELP: + MessageBox(hwndDlg, TranslateT(TAGSHELP), TranslateT("Feed Tag Help"), MB_OK); + break; + + case IDC_RESET: + if (MessageBox(hwndDlg, TranslateT("Are you sure?"), TranslateT("Tags Mask Reset"), MB_YESNO | MB_ICONWARNING) == IDYES) + SetDlgItemText(hwndDlg, IDC_TAGSEDIT, _T(TAGSDEFAULT)); + break; + + case IDC_DISCOVERY: + { + TCHAR tszURL[MAX_PATH] = {0}; + if (GetDlgItemText(hwndDlg, IDC_FEEDURL, tszURL, SIZEOF(tszURL)) || lstrcmp(tszURL, _T("http://")) != 0) + { + EnableWindow(GetDlgItem(hwndDlg, IDC_DISCOVERY), FALSE); + SetDlgItemText(hwndDlg, IDC_DISCOVERY, TranslateT("Wait...")); + TCHAR *tszTitle = CheckFeed(tszURL, hwndDlg); + SetDlgItemText(hwndDlg, IDC_FEEDTITLE, tszTitle); + EnableWindow(GetDlgItem(hwndDlg, IDC_DISCOVERY), TRUE); + SetDlgItemText(hwndDlg, IDC_DISCOVERY, TranslateT("Check Feed")); + } + else + MessageBox(hwndDlg, TranslateT("Enter Feed URL"), TranslateT("Error"), MB_OK); + } + break; + } + break; + } + + case WM_CLOSE: + { + DestroyWindow(hwndDlg); + break; + } + case WM_DESTROY: + { + HANDLE hContact = (HANDLE) GetWindowLongPtr(hwndDlg, GWLP_USERDATA); + Utils_SaveWindowPosition(hwndDlg,hContact,MODULE,"ChangeDlg"); + WindowList_Remove(hChangeFeedDlgList,hwndDlg); + } + } + + return FALSE; +} + +INT_PTR CALLBACK UpdateNotifyOptsProc(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam) +{ + HWND hwndList = GetDlgItem(hwndDlg, IDC_FEEDLIST); + switch (msg) + { + case WM_INITDIALOG: + { + TranslateDialogDefault(hwndDlg); + SetWindowLongPtr(hwndDlg, GWLP_USERDATA, 0); + CreateList(hwndList); + UpdateList(hwndList); + return TRUE; + } + + case WM_COMMAND: + { + switch (LOWORD(wParam)) + { + case IDC_ADD: + { + CreateDialogParam(hInst, MAKEINTRESOURCE(IDD_ADDFEED), hwndDlg, DlgProcAddFeedOpts, (LPARAM)hwndList); + } + return FALSE; + case IDC_CHANGE: + { + ItemInfo SelItem = {0}; + int sel = ListView_GetSelectionMark(hwndList); + ListView_GetItemText(hwndList, sel, 0, SelItem.nick, MAX_PATH); + ListView_GetItemText(hwndList, sel, 1, SelItem.url, MAX_PATH); + SelItem.hwndList = hwndList; + SelItem.SelNumber = sel; + CreateDialogParam(hInst, MAKEINTRESOURCE(IDD_ADDFEED), hwndDlg, DlgProcChangeFeedOpts, (LPARAM)&SelItem); + } + return FALSE; + case IDC_REMOVE: + { + if (MessageBox(hwndDlg, TranslateT("Are you sure?"), TranslateT("Contact deleting"), MB_YESNO | MB_ICONWARNING) == IDYES) + { + TCHAR nick[MAX_PATH], url[MAX_PATH]; + int sel = ListView_GetSelectionMark(hwndList); + ListView_GetItemText(hwndList, sel, 0, nick, MAX_PATH); + ListView_GetItemText(hwndList, sel, 1, url, MAX_PATH); + + HANDLE hContact = (HANDLE)CallService(MS_DB_CONTACT_FINDFIRST, 0, 0); + while (hContact != NULL) + { + if(IsMyContact(hContact)) + { + DBVARIANT dbNick = {0}; + if (DBGetContactSettingTString(hContact, MODULE, "Nick", &dbNick)) + break; + else if (lstrcmp(dbNick.ptszVal, nick) == 0) + { + DBFreeVariant(&dbNick); + DBVARIANT dbURL = {0}; + if (DBGetContactSettingTString(hContact, MODULE, "URL", &dbURL)) + break; + else if (lstrcmp(dbURL.ptszVal, url) == 0) + { + DBFreeVariant(&dbURL); + CallService(MS_DB_CONTACT_DELETE, (WPARAM)hContact, 0); + ListView_DeleteItem(hwndList, sel); + break; + } + DBFreeVariant(&dbURL); + } + DBFreeVariant(&dbNick); + } + hContact = (HANDLE)CallService(MS_DB_CONTACT_FINDNEXT, (WPARAM)hContact, 0); + } + } + return FALSE; + } + } + break; + } + case WM_NOTIFY: + { + NMHDR *hdr = (NMHDR *)lParam; + switch (hdr->code) + { + case PSN_APPLY: + { + HANDLE hContact= (HANDLE)CallService(MS_DB_CONTACT_FINDFIRST, 0, 0); + int i = 0; + while (hContact != NULL) + { + if(IsMyContact(hContact)) + { + DBWriteContactSettingByte(hContact, MODULE, "CheckState", ListView_GetCheckState(hwndList, i)); + i += 1; + } + hContact = (HANDLE)CallService(MS_DB_CONTACT_FINDNEXT, (WPARAM)hContact, 0); + } + break; + } + + case NM_DBLCLK: + { + ItemInfo SelItem = {0}; + int sel = ListView_GetHotItem(hwndList); + if (sel != -1) + { + ListView_GetItemText(hwndList, sel, 0, SelItem.nick, MAX_PATH); + ListView_GetItemText(hwndList, sel, 1, SelItem.url, MAX_PATH); + SelItem.hwndList = hwndList; + SelItem.SelNumber = sel; + CreateDialogParam(hInst, MAKEINTRESOURCE(IDD_ADDFEED), hwndDlg, DlgProcChangeFeedOpts, (LPARAM)&SelItem); + } + break; + } + + case LVN_ITEMCHANGED: + { + NMLISTVIEW *nmlv = (NMLISTVIEW *)lParam; + if (((nmlv->uNewState ^ nmlv->uOldState) & LVIS_STATEIMAGEMASK) && !UpdateListFlag) + { + SendMessage(GetParent(hwndDlg), PSM_CHANGED, 0, 0); + } + break; + } + } + } + }//end* switch (msg) + return FALSE; +} + +INT OptInit(WPARAM wParam, LPARAM lParam) +{ + OPTIONSDIALOGPAGE odp = {0}; + + ZeroMemory(&odp, sizeof(odp)); + odp.cbSize = sizeof(odp); + odp.position = 100000000; + odp.hInstance = hInst; + odp.flags = ODPF_TCHAR | ODPF_BOLDGROUPS; + odp.pszTemplate = MAKEINTRESOURCEA(IDD_OPTIONS); + odp.ptszGroup = LPGENT("Network"); + odp.ptszTitle = LPGENT("News Aggregator"); + odp.pfnDlgProc = UpdateNotifyOptsProc; + CallService(MS_OPT_ADDPAGE, wParam, (LPARAM)&odp); + return 0; +} \ No newline at end of file diff --git a/protocols/NewsAggregator/Src/Services.cpp b/protocols/NewsAggregator/Src/Services.cpp new file mode 100644 index 0000000000..0c23983c79 --- /dev/null +++ b/protocols/NewsAggregator/Src/Services.cpp @@ -0,0 +1,240 @@ +/* +Copyright (C) 2012 Mataes + +This is free software; you can redistribute it and/or +modify it under the terms of the GNU Library General Public +License as published by the Free Software Foundation; either +version 2 of the License, or (at your option) any later version. + +This 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 +Library General Public License for more details. + +You should have received a copy of the GNU Library General Public +License along with this file; see the file license.txt. If +not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. +*/ + +#include "common.h" + +int g_nStatus = ID_STATUS_OFFLINE; +UINT_PTR timerId = 0; + +void SetContactStatus(HANDLE hContact,int nNewStatus) +{ + if(DBGetContactSettingWord(hContact,MODULE,"Status",ID_STATUS_OFFLINE) != nNewStatus) + DBWriteContactSettingWord(hContact,MODULE,"Status",nNewStatus); +} + +static void __cdecl WorkingThread(void* param) +{ + int nStatus = (int)param; +// UpdateAll(FALSE, FALSE); + HANDLE hContact= (HANDLE)CallService(MS_DB_CONTACT_FINDFIRST, 0, 0); + while (hContact != NULL) + { + if(IsMyContact(hContact)) + { + SetContactStatus(hContact, nStatus); + } + hContact = (HANDLE)CallService(MS_DB_CONTACT_FINDNEXT, (WPARAM)hContact, 0); + } +} + +int NewsAggrInit(WPARAM wParam,LPARAM lParam) +{ + HANDLE hContact= (HANDLE)CallService(MS_DB_CONTACT_FINDFIRST, 0, 0); + while (hContact != NULL) + { + if(IsMyContact(hContact)) + { + SetContactStatus(hContact, ID_STATUS_OFFLINE); + } + hContact = (HANDLE)CallService(MS_DB_CONTACT_FINDNEXT, (WPARAM)hContact, 0); + } + NetlibInit(); + InitIcons(); + InitMenu(); + + // timer for the first update + timerId = SetTimer(NULL, 0, 5000, timerProc2); // first update is 5 sec after load + + return 0; +} + +int NewsAggrPreShutdown(WPARAM wParam,LPARAM lParam) +{ + if (hAddFeedDlg) + { + SendMessage(hAddFeedDlg, WM_CLOSE, 0, 0); + } + WindowList_Broadcast(hChangeFeedDlgList, WM_CLOSE, 0, 0); + + mir_forkthread(WorkingThread, (void*)ID_STATUS_OFFLINE); + KillTimer(NULL, timerId); + NetlibUnInit(); + + return 0; +} + +INT_PTR NewsAggrGetName(WPARAM wParam, LPARAM lParam) +{ + if(lParam) + { + lstrcpynA((char*)lParam, MODULE, wParam); + return 0; + } + else + { + return 1; + } +} + +INT_PTR NewsAggrGetCaps(WPARAM wp,LPARAM lp) +{ + switch(wp) + { + case PFLAGNUM_1: + return PF1_IM | PF1_PEER2PEER; + case PFLAGNUM_3: + case PFLAGNUM_2: + return PF2_ONLINE; + case PFLAGNUM_4: + return PF4_AVATARS; + case PFLAG_UNIQUEIDTEXT: + return (INT_PTR) "News Feed"; + case PFLAG_UNIQUEIDSETTING: + return (INT_PTR) "URL"; + default: + return 0; + } +} + +INT_PTR NewsAggrSetStatus(WPARAM wp,LPARAM /*lp*/) +{ + int nStatus = wp; + if ((ID_STATUS_ONLINE == nStatus) || (ID_STATUS_OFFLINE == nStatus)) + { + int nOldStatus = g_nStatus; + if(nStatus != g_nStatus) + { + g_nStatus = nStatus; + mir_forkthread(WorkingThread, (void*)g_nStatus); + ProtoBroadcastAck(MODULE, NULL, ACKTYPE_STATUS, ACKRESULT_SUCCESS, (HANDLE)nOldStatus, g_nStatus); + } + + } + + return 0; +} + +INT_PTR NewsAggrGetStatus(WPARAM/* wp*/,LPARAM/* lp*/) +{ + return g_nStatus; +} + +INT_PTR NewsAggrLoadIcon(WPARAM wParam,LPARAM lParam) +{ + return (LOWORD(wParam) == PLI_PROTOCOL) ? (INT_PTR)CopyIcon(LoadIconEx("main", FALSE)) : 0; +} + +static void __cdecl AckThreadProc(HANDLE param) +{ + Sleep(100); + ProtoBroadcastAck(MODULE, param, ACKTYPE_GETINFO, ACKRESULT_SUCCESS, (HANDLE) 1, 0); +} + +INT_PTR NewsAggrGetInfo(WPARAM wParam,LPARAM lParam) +{ + CCSDATA *ccs = (CCSDATA *) lParam; + mir_forkthread(AckThreadProc, ccs->hContact); + return 0; +} + +INT_PTR CheckAllFeeds(WPARAM wParam,LPARAM lParam) +{ + HANDLE hContact= (HANDLE)CallService(MS_DB_CONTACT_FINDFIRST, 0, 0); + while (hContact != NULL) + { + if(IsMyContact(hContact)) + { + UpdateListAdd(hContact); + } + hContact = (HANDLE)CallService(MS_DB_CONTACT_FINDNEXT, (WPARAM)hContact, 0); + } + if (!ThreadRunning) + mir_forkthread(UpdateThreadProc, NULL); + + + return 0; +} + +INT_PTR AddFeed(WPARAM wParam,LPARAM lParam) +{ + hAddFeedDlg = CreateDialog(hInst, MAKEINTRESOURCE(IDD_ADDFEED), NULL, DlgProcAddFeedOpts); + ShowWindow(hAddFeedDlg, SW_SHOW); + return 0; +} + +INT_PTR ChangeFeed(WPARAM wParam,LPARAM lParam) +{ + HANDLE hContact = (HANDLE) wParam; + HWND hChangeFeedDlg = WindowList_Find(hChangeFeedDlgList,hContact); + if (!hChangeFeedDlg) + { + hChangeFeedDlg = CreateDialogParam(hInst, MAKEINTRESOURCE(IDD_ADDFEED), NULL, DlgProcChangeFeedMenu, (LPARAM)hContact); + ShowWindow(hChangeFeedDlg, SW_SHOW); + } + else + { + SetForegroundWindow(hChangeFeedDlg); + SetFocus(hChangeFeedDlg); + } + return 0; +} + +INT_PTR ImportFeeds(WPARAM wParam,LPARAM lParam) +{ + return 0; +} + +INT_PTR ExportFeeds(WPARAM wParam,LPARAM lParam) +{ + return 0; +} + +INT_PTR CheckFeed(WPARAM wParam,LPARAM lParam) +{ + HANDLE hContact = (HANDLE)wParam; + if(IsMyContact(hContact)) + UpdateListAdd(hContact); + if (!ThreadRunning) + mir_forkthread(UpdateThreadProc, NULL); + return 0; +} + +INT_PTR NewsAggrGetAvatarInfo(WPARAM wParam,LPARAM lParam) +{ + PROTO_AVATAR_INFORMATION* pai = (PROTO_AVATAR_INFORMATION*) lParam; + + if (!IsMyContact(pai->hContact)) + return GAIR_NOAVATAR; + + // if GAIF_FORCE is set, we are updating the feed + // otherwise, cached avatar is used + if (wParam & GAIF_FORCE) + UpdateListAdd(pai->hContact); + //CheckCurrentFeed(pai->hContact); + if (!ThreadRunning) + mir_forkthread(UpdateThreadProc, NULL); + + DBVARIANT dbv = {0}; + if(DBGetContactSettingTString(pai->hContact,MODULE,"ImageURL",&dbv)) + { + return GAIR_NOAVATAR; + } + DBFreeVariant(&dbv); + return GAIR_WAITFOR; +} \ No newline at end of file diff --git a/protocols/NewsAggregator/Src/Update.cpp b/protocols/NewsAggregator/Src/Update.cpp new file mode 100644 index 0000000000..f2f5ecf92a --- /dev/null +++ b/protocols/NewsAggregator/Src/Update.cpp @@ -0,0 +1,147 @@ +/* +Copyright (C) 2012 Mataes + +This is free software; you can redistribute it and/or +modify it under the terms of the GNU Library General Public +License as published by the Free Software Foundation; either +version 2 of the License, or (at your option) any later version. + +This 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 +Library General Public License for more details. + +You should have received a copy of the GNU Library General Public +License along with this file; see the file license.txt. If +not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. +*/ + +#include "common.h" + +// check if Feed is currently updating +BOOL ThreadRunning; +UPDATELIST *UpdateListHead = NULL; +UPDATELIST *UpdateListTail = NULL; + +// main auto-update timer +VOID CALLBACK timerProc(HWND hwnd, UINT uMsg, UINT_PTR idEvent, DWORD dwTime) +{ + // only run if it is not current updating and the auto update option is enabled + if (!ThreadRunning && !Miranda_Terminated()) + { + BOOL HaveUpdates = FALSE; + HANDLE hContact = (HANDLE)CallService(MS_DB_CONTACT_FINDFIRST, 0, 0); + while (hContact != NULL) + { + if(IsMyContact(hContact)) + { + if (DBGetContactSettingDword(hContact, MODULE, "UpdateTime", 60)) + { + double diff = difftime(time(NULL), DBGetContactSettingDword(hContact, MODULE, "LastCheck", 0)); + if (diff >= DBGetContactSettingDword(hContact, MODULE, "UpdateTime", 60) * 60) + { + UpdateListAdd(hContact); + HaveUpdates = TRUE; + } + } + } + hContact = (HANDLE)CallService(MS_DB_CONTACT_FINDNEXT, (WPARAM)hContact, 0); + } + if (!ThreadRunning && HaveUpdates) + mir_forkthread(UpdateThreadProc, NULL); + } +} + +// temporary timer for first run +// when this is run, it kill the old startup timer and create the permenant one above +VOID CALLBACK timerProc2(HWND hwnd, UINT uMsg, UINT_PTR idEvent, DWORD dwTime) +{ + KillTimer(NULL, timerId); + ThreadRunning = FALSE; + + if (!Miranda_Terminated()) + { + CheckAllFeeds(0,0); + timerId = SetTimer(NULL, 0, 30000, (TIMERPROC)timerProc); + } +} + +void UpdateListAdd(HANDLE hContact) +{ + UPDATELIST *newItem; + + newItem = (UPDATELIST*)mir_alloc(sizeof(UPDATELIST)); + newItem->hContact = hContact; + newItem->next = NULL; + + WaitForSingleObject(hUpdateMutex, INFINITE); + + if (UpdateListTail == NULL) UpdateListHead = newItem; + else UpdateListTail->next = newItem; + UpdateListTail = newItem; + + ReleaseMutex(hUpdateMutex); +} + +HANDLE UpdateGetFirst() +{ + HANDLE hContact = NULL; + + WaitForSingleObject(hUpdateMutex, INFINITE); + + if (UpdateListHead != NULL) + { + UPDATELIST* Item = UpdateListHead; + + hContact = Item->hContact; + UpdateListHead = Item->next; + mir_free(Item); + + if (UpdateListHead == NULL) UpdateListTail = NULL; + } + + ReleaseMutex(hUpdateMutex); + + return hContact; +} + +void DestroyUpdateList(void) +{ + UPDATELIST *temp; + + WaitForSingleObject(hUpdateMutex, INFINITE); + + temp = UpdateListHead; + + // free the list one by one + while (temp != NULL) + { + UpdateListHead = temp->next; + mir_free(temp); + temp = UpdateListHead; + } + // make sure the entire list is clear + UpdateListTail = NULL; + + ReleaseMutex(hUpdateMutex); +} + +void UpdateThreadProc(LPVOID hWnd) +{ + WaitForSingleObject(hUpdateMutex, INFINITE); + if (ThreadRunning) + { + ReleaseMutex(hUpdateMutex); + return; + } + ThreadRunning = TRUE; // prevent 2 instance of this thread running + ReleaseMutex(hUpdateMutex); + + // update weather by getting the first station from the queue until the queue is empty + while (UpdateListHead != NULL && !Miranda_Terminated()) + CheckCurrentFeed(UpdateGetFirst()); + + // exit the update thread + ThreadRunning = FALSE; +} \ No newline at end of file diff --git a/protocols/NewsAggregator/Src/Utils.cpp b/protocols/NewsAggregator/Src/Utils.cpp new file mode 100644 index 0000000000..c42a3f7dd1 --- /dev/null +++ b/protocols/NewsAggregator/Src/Utils.cpp @@ -0,0 +1,1404 @@ +/* +Copyright (C) 2012 Mataes + +This is free software; you can redistribute it and/or +modify it under the terms of the GNU Library General Public +License as published by the Free Software Foundation; either +version 2 of the License, or (at your option) any later version. + +This 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 +Library General Public License for more details. + +You should have received a copy of the GNU Library General Public +License along with this file; see the file license.txt. If +not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. +*/ + +#include "common.h" + +HANDLE hNetlibUser = NULL, hNetlibHttp; +BOOL UpdateListFlag = FALSE; + +BOOL IsMyContact(HANDLE hContact) +{ + const char* szProto = (char*)CallService(MS_PROTO_GETCONTACTBASEPROTO, (WPARAM)hContact, 0); + return szProto != NULL && strcmp(MODULE, szProto) == 0; +} + +VOID NetlibInit() +{ + NETLIBUSER nlu = {0}; + nlu.cbSize = sizeof(nlu); + nlu.flags = NUF_OUTGOING | NUF_INCOMING | NUF_HTTPCONNS | NUF_TCHAR; // | NUF_HTTPGATEWAY; + nlu.ptszDescriptiveName = TranslateT("NewsAggr HTTP connection"); + nlu.szSettingsModule = MODULE; + hNetlibUser = (HANDLE)CallService(MS_NETLIB_REGISTERUSER, 0, (LPARAM)&nlu); +} + +VOID NetlibUnInit() +{ + Netlib_CloseHandle(hNetlibUser); + hNetlibUser = NULL; +} + +static void arrayToHex(BYTE* data, size_t datasz, char* res) +{ + char* resptr = res; + for (unsigned i=0; i<datasz ; i++) + { + const BYTE ch = data[i]; + + const char ch0 = (char)(ch >> 4); + *resptr++ = (char)((ch0 <= 9) ? ('0' + ch0) : (('a' - 10) + ch0)); + + const char ch1 = (char)(ch & 0xF); + *resptr++ = (char)((ch1 <= 9) ? ('0' + ch1) : (('a' - 10) + ch1)); + } + *resptr = '\0'; +} + +int GetImageFormat(const TCHAR* ext) +{ + if(lstrcmp(ext,_T(".jpg")) || lstrcmp(ext,_T(".jpeg"))) + { + return PA_FORMAT_JPEG; + } + else if(lstrcmp(ext,_T(".png"))) + { + return PA_FORMAT_PNG; + } + else if(lstrcmp(ext,_T(".gif"))) + { + return PA_FORMAT_GIF; + } + else if(lstrcmp(ext,_T(".ico"))) + { + return PA_FORMAT_ICON; + } + else if(lstrcmp(ext,_T(".bmp"))) + { + return PA_FORMAT_BMP; + } + else if(lstrcmp(ext,_T(".swf"))) + { + return PA_FORMAT_SWF; + } + else if(lstrcmp(ext,_T(".xml"))) + { + return PA_FORMAT_XML; + } + else if(lstrcmp(ext,_T(".jpg")) || lstrcmp(ext,_T(".jpeg"))) + { + return PA_FORMAT_JPEG; + } + else + { + return PA_FORMAT_UNKNOWN; + } +} +void CreateAuthString(char* auth, HANDLE hContact, HWND hwndDlg) +{ + char *user = NULL, *pass = NULL; + TCHAR *tlogin = NULL, *tpass = NULL, buf[MAX_PATH] = {0}; + if (hContact && DBGetContactSettingByte(hContact, MODULE, "UseAuth", 0)) + { + DBVARIANT dbLogin = {0}; + if (!DBGetContactSettingTString(hContact, MODULE, "Login", &dbLogin)) + { + tlogin = (TCHAR*)mir_alloc(_tcslen(dbLogin.ptszVal)*sizeof(TCHAR)); + memcpy(tlogin, dbLogin.ptszVal, _tcslen(dbLogin.ptszVal)*sizeof(TCHAR)); + tlogin[_tcslen(dbLogin.ptszVal)] = 0; + DBFreeVariant(&dbLogin); + } + DBVARIANT dbPass = {0}; + if (!DBGetContactSettingTString(hContact, MODULE, "Password", &dbPass)) + { + tpass = (TCHAR*)mir_alloc(_tcslen(dbPass.ptszVal)*sizeof(TCHAR)); + memcpy(tpass, dbPass.ptszVal, _tcslen(dbPass.ptszVal)*sizeof(TCHAR)); + tpass[_tcslen(dbPass.ptszVal)] = 0; + DBFreeVariant(&dbPass); + } + } + else if (hwndDlg && IsDlgButtonChecked(hwndDlg, IDC_USEAUTH)) + { + GetDlgItemText(hwndDlg, IDC_LOGIN, buf, SIZEOF(buf)); + tlogin = buf; + GetDlgItemText(hwndDlg, IDC_PASSWORD, buf, SIZEOF(buf)); + tpass = buf; + } + user = mir_t2a(tlogin); + pass = mir_t2a(tpass); + + char str[MAX_PATH]; + int len = mir_snprintf(str, SIZEOF(str), "%s:%s", user, pass); + mir_free(user); + mir_free(pass); + + strcpy(auth, "Basic "); + NETLIBBASE64 nlb = { auth+6, 250, (PBYTE)str, len }; + CallService(MS_NETLIB_BASE64ENCODE, 0, LPARAM(&nlb)); +} + +VOID GetNewsData(TCHAR *tszUrl, char** szData, HANDLE hContact, HWND hwndDlg) +{ + char* szRedirUrl = NULL; + NETLIBHTTPREQUEST nlhr = {0}; + NETLIBHTTPHEADER headers[5]; + + // initialize the netlib request + nlhr.cbSize = sizeof(nlhr); + nlhr.requestType = REQUEST_GET; + nlhr.flags = NLHRF_NODUMP | NLHRF_HTTP11; + char *szUrl = mir_t2a(tszUrl); + nlhr.szUrl = szUrl; + nlhr.nlc = hNetlibHttp; + + // change the header so the plugin is pretended to be IE 6 + WinXP + nlhr.headers = headers; + nlhr.headers[0].szName = "User-Agent"; + nlhr.headers[0].szValue = "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1)"; + nlhr.headers[1].szName = "Cache-Control"; + nlhr.headers[1].szValue = "no-cache"; + nlhr.headers[2].szName = "Pragma"; + nlhr.headers[2].szValue = "no-cache"; + nlhr.headers[3].szName = "Connection"; + nlhr.headers[3].szValue = "close"; + nlhr.headers[4].szName = "Accept"; + nlhr.headers[4].szValue = "ext/html, application/xml"; + if (DBGetContactSettingByte(hContact, MODULE, "UseAuth", 0) || IsDlgButtonChecked(hwndDlg, IDC_USEAUTH)) + { + nlhr.headersCount = 6; + nlhr.headers[5].szName = "Authorization"; + + char auth[256]; + CreateAuthString(auth, hContact, hwndDlg); + nlhr.headers[5].szValue = auth; + } + else + nlhr.headersCount = 5; + + // download the page + NETLIBHTTPREQUEST *nlhrReply = (NETLIBHTTPREQUEST*)CallService(MS_NETLIB_HTTPTRANSACTION, (WPARAM)hNetlibUser, (LPARAM)&nlhr); + if (nlhrReply) + { + // if the recieved code is 200 OK + switch(nlhrReply->resultCode) + { + case 200: + { + if (nlhrReply->dataLength) + { + // allocate memory and save the retrieved data + *szData = (char *)mir_alloc(nlhrReply->dataLength + 2); + memcpy(*szData, nlhrReply->pData, nlhrReply->dataLength); + (*szData)[nlhrReply->dataLength] = 0; + } + break; + } + + case 401: + { + //ShowMessage(0, TranslateT("Cannot upload VersionInfo. Incorrect username or password")); + break; + } + + case 301: + case 302: + case 307: + // get the url for the new location and save it to szInfo + // look for the reply header "Location" + for (int i=0; i<nlhrReply->headersCount; i++) + { + if (!strcmp(nlhrReply->headers[i].szName, "Location")) + { + size_t rlen = 0; + if (nlhrReply->headers[i].szValue[0] == '/') + { + const char* szPath; + const char* szPref = strstr(szUrl, "://"); + szPref = szPref ? szPref + 3 : szUrl; + szPath = strchr(szPref, '/'); + rlen = szPath != NULL ? szPath - szUrl : strlen(szUrl); + } + + szRedirUrl = (char*)mir_realloc(szRedirUrl, + rlen + strlen(nlhrReply->headers[i].szValue)*3 + 1); + + strncpy(szRedirUrl, szUrl, rlen); + strcpy(szRedirUrl+rlen, nlhrReply->headers[i].szValue); + + nlhr.szUrl = szRedirUrl; + break; + } + } + break; + + default: + //ShowMessage(0, TranslateT("Cannot upload VersionInfo. Unknown error")); + break; + } + CallService(MS_NETLIB_FREEHTTPREQUESTSTRUCT, 0, (LPARAM)nlhrReply); + } + mir_free(szUrl); +} + +VOID CreateList (HWND hwndList) +{ + SendMessage(hwndList, LVM_SETEXTENDEDLISTVIEWSTYLE, 0, LVS_EX_FULLROWSELECT | LVS_EX_CHECKBOXES); + + LVCOLUMN lvc = {0}; + // Initialize the LVCOLUMN structure. + // The mask specifies that the format, width, text, and + // subitem members of the structure are valid. + lvc.mask = LVCF_FMT | LVCF_WIDTH | LVCF_TEXT | LVCF_SUBITEM; + lvc.fmt = LVCFMT_LEFT; + + lvc.iSubItem = 0; + lvc.pszText = TranslateT("Feed"); + lvc.cx = 160; // width of column in pixels + ListView_InsertColumn(hwndList, 0, &lvc); + + lvc.iSubItem = 1; + lvc.pszText = TranslateT("URL"); + lvc.cx = 280; // width of column in pixels + ListView_InsertColumn(hwndList, 1, &lvc); +} + +VOID UpdateList (HWND hwndList) +{ + LVITEM lvI = {0}; + + // Some code to create the list-view control. + // Initialize LVITEM members that are common to all + // items. + HANDLE hContact = (HANDLE)CallService(MS_DB_CONTACT_FINDFIRST, 0, 0); + int i = 0; + while (hContact != NULL) + { + if (IsMyContact(hContact)) + { + UpdateListFlag = TRUE; + lvI.mask = LVIF_TEXT; + lvI.iSubItem = 0; + DBVARIANT dbNick = {0}; + if (!DBGetContactSettingTString(hContact, MODULE, "Nick", &dbNick)) + { + lvI.pszText = dbNick.ptszVal; + lvI.iItem = i; + ListView_InsertItem(hwndList, &lvI); + lvI.iSubItem = 1; + DBVARIANT dbURL = {0}; + if (!DBGetContactSettingTString(hContact, MODULE, "URL", &dbURL)) + { + lvI.pszText = dbURL.ptszVal; + ListView_SetItem(hwndList, &lvI); + i += 1; + ListView_SetCheckState(hwndList, lvI.iItem, DBGetContactSettingByte(hContact, MODULE, "CheckState", 1)); + DBFreeVariant(&dbURL); + } + DBFreeVariant(&dbNick); + } + } + hContact = (HANDLE)CallService(MS_DB_CONTACT_FINDNEXT, (WPARAM)hContact, 0); + } + UpdateListFlag = FALSE; +} + +VOID DeleteAllItems(HWND hwndList) +{ + ListView_DeleteAllItems(hwndList); +} + +time_t __stdcall DateToUnixTime(TCHAR* stamp, BOOL FeedType) +{ + struct tm timestamp; + TCHAR date[9]; + int i, y; + time_t t; + + if ( stamp == NULL ) return ( time_t ) 0; + + TCHAR *p = stamp; + + if (FeedType) + { + // skip '-' chars + int si = 0, sj = 0; + while (1) { + if ( p[si] == _T('-') ) + si++; + else + if ( !( p[sj++] = p[si++] )) + break; + }; + } + else + { + TCHAR weekday[4], monthstr[4], timezonesign[2]; + INT day, month, year, hour, min, sec, timezoneh, timezonem; + if (_tcsstr(p, _T(","))) + { + _stscanf( p, _T("%3s, %d %3s %d %d:%d:%d %1s%02d%02d"), &weekday, &day, &monthstr, &year, &hour, &min, &sec, &timezonesign, &timezoneh, &timezonem); + if (lstrcmpi(monthstr, _T("Jan")) ==0) + month = 1; + if (lstrcmpi(monthstr, _T("Feb")) ==0) + month = 2; + if (lstrcmpi(monthstr, _T("Mar")) ==0) + month = 3; + if (lstrcmpi(monthstr, _T("Apr")) ==0) + month = 4; + if (lstrcmpi(monthstr, _T("May")) ==0) + month = 5; + if (lstrcmpi(monthstr, _T("Jun")) ==0) + month = 6; + if (lstrcmpi(monthstr, _T("Jul")) ==0) + month = 7; + if (lstrcmpi(monthstr, _T("Aug")) ==0) + month = 8; + if (lstrcmpi(monthstr, _T("Sep")) ==0) + month = 9; + if (lstrcmpi(monthstr, _T("Oct")) ==0) + month = 10; + if (lstrcmpi(monthstr, _T("Nov")) ==0) + month = 11; + if (lstrcmpi(monthstr, _T("Dec")) ==0) + month = 12; + if (lstrcmp(timezonesign, _T("+")) ==0) + mir_sntprintf(p, 4+2+2+1+2+1+2+1+2+1, _T("%04d%02d%02dT%02d:%02d:%02d"), year, month, day, hour-timezoneh, min-timezonem, sec); + else if (lstrcmp(timezonesign, _T("-")) ==0) + mir_sntprintf(p, 4+2+2+1+2+1+2+1+2+1, _T("%04d%02d%02dT%02d:%02d:%02d"), year, month, day, hour+timezoneh, min+timezonem, sec); + else + mir_sntprintf(p, 4+2+2+1+2+1+2+1+2+1, _T("%04d%02d%02dT%02d:%02d:%02d"), year, month, day, hour, min, sec); + } + else + { + _stscanf( p, _T("%d-%d-%d %d:%d:%d %1s%02d%02d"), &year, &month, &day, &hour, &min, &sec, &timezonesign, &timezoneh, &timezonem); + if (lstrcmp(timezonesign, _T("+")) ==0) + mir_sntprintf(p, 4+2+2+1+2+1+2+1+2+1, _T("%04d%02d%02dT%02d:%02d:%02d"), year, month, day, hour-timezoneh, min-timezonem, sec); + else if (lstrcmp(timezonesign, _T("-")) ==0) + mir_sntprintf(p, 4+2+2+1+2+1+2+1+2+1, _T("%04d%02d%02dT%02d:%02d:%02d"), year, month, day, hour+timezoneh, min+timezonem, sec); + else + mir_sntprintf(p, 4+2+2+1+2+1+2+1+2+1, _T("%04d%02d%02dT%02d:%02d:%02d"), year, month, day, hour, min, sec); + } + } + // Get the date part + for ( i=0; *p!='\0' && i<8 && isdigit( *p ); p++,i++ ) + date[i] = *p; + + // Parse year + if ( i == 6 ) { + // 2-digit year ( 1970-2069 ) + y = ( date[0]-'0' )*10 + ( date[1]-'0' ); + if ( y < 70 ) y += 100; + } + else if ( i == 8 ) { + // 4-digit year + y = ( date[0]-'0' )*1000 + ( date[1]-'0' )*100 + ( date[2]-'0' )*10 + date[3]-'0'; + y -= 1900; + } + else + return ( time_t ) 0; + timestamp.tm_year = y; + // Parse month + timestamp.tm_mon = ( date[i-4]-'0' )*10 + date[i-3]-'0' - 1; + // Parse date + timestamp.tm_mday = ( date[i-2]-'0' )*10 + date[i-1]-'0'; + + // Skip any date/time delimiter + for ( ; *p!='\0' && !isdigit( *p ); p++ ); + + // Parse time + if ( _stscanf( p, _T("%d:%d:%d"), ×tamp.tm_hour, ×tamp.tm_min, ×tamp.tm_sec ) != 3 ) + return ( time_t ) 0; + + timestamp.tm_isdst = 0; // DST is already present in _timezone below + t = mktime( ×tamp ); + + _tzset(); + t -= _timezone; + + if ( t >= 0 ) + return t; + else + return ( time_t ) 0; +} + +TCHAR* StrReplace (TCHAR* Search, TCHAR* Replace, TCHAR* Resource) +{ + int i = 0; + int SearchLen = (int)_tcslen(Search); + TCHAR* Work = mir_tstrdup(Replace); + int ReplaceLen = (int)_tcslen(Work); + + TCHAR* Pointer = _tcsstr(Resource, Search); + + while (Pointer != NULL) + { + int PointerLen = (int)_tcslen(Pointer); + int ResourceLen = (int)_tcslen(Resource); + + TCHAR* NewText = (TCHAR*)mir_calloc((ResourceLen - SearchLen + ReplaceLen + 1)*sizeof(TCHAR)); + + _tcsncpy(NewText, Resource, ResourceLen - PointerLen); + _tcscat(NewText, Work); + _tcscat(NewText, Pointer + SearchLen); + + Resource = (TCHAR*)mir_alloc((ResourceLen - SearchLen + ReplaceLen + 1)*sizeof(TCHAR)); + + for (i = 0; i < (ResourceLen - SearchLen + ReplaceLen); i++) + Resource[i] = NewText[i]; + Resource[i] = 0; + mir_free(NewText); + + Pointer = _tcsstr(Resource + (ResourceLen - PointerLen + ReplaceLen), Search); + } + mir_free(Work); + + return Resource; +} + +BOOL DownloadFile(LPCTSTR tszURL, LPCTSTR tszLocal) +{ + HANDLE hFile = NULL; + DWORD dwBytes; + + NETLIBHTTPREQUEST nlhr = {0}; + nlhr.cbSize = sizeof(nlhr); + nlhr.requestType = REQUEST_GET; + nlhr.flags = NLHRF_DUMPASTEXT | NLHRF_HTTP11; + char* szUrl = mir_t2a(tszURL); + nlhr.szUrl = szUrl; + nlhr.headersCount = 4; + nlhr.headers=(NETLIBHTTPHEADER*)mir_alloc(sizeof(NETLIBHTTPHEADER)*nlhr.headersCount); + nlhr.headers[0].szName = "User-Agent"; + nlhr.headers[0].szValue = "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1)"; + nlhr.headers[1].szName = "Connection"; + nlhr.headers[1].szValue = "close"; + nlhr.headers[2].szName = "Cache-Control"; + nlhr.headers[2].szValue = "no-cache"; + nlhr.headers[3].szName = "Pragma"; + nlhr.headers[3].szValue = "no-cache"; + + bool ret = false; + NETLIBHTTPREQUEST *pReply = (NETLIBHTTPREQUEST*)CallService(MS_NETLIB_HTTPTRANSACTION, (WPARAM)hNetlibUser,(LPARAM)&nlhr); + + if(pReply) + { + if ((200 == pReply->resultCode) && (pReply->dataLength > 0)) + { + char *date = NULL, *size = NULL; + for (int i = 0; i < pReply->headersCount; i++) + { + if (lstrcmpiA(pReply->headers[i].szName, "Last-Modified") == 0) + { + date = pReply->headers[i].szValue; + continue; + } + if (lstrcmpiA(pReply->headers[i].szName, "Content-Length") == 0) + { + size = pReply->headers[i].szValue; + continue; + } + } + if (date != NULL && size != NULL) + { + TCHAR *tdate = mir_a2t(date); + TCHAR *tsize = mir_a2t(size); + int fh; + struct _stat buf; + + fh = _topen(tszLocal, _O_RDONLY); + if (fh != -1) + { + _fstat(fh, &buf); + time_t modtime = DateToUnixTime(tdate, 0); + time_t filemodtime = mktime(localtime(&buf.st_atime)); + if (modtime > filemodtime && buf.st_size != _ttoi(tsize)) + { + hFile = CreateFile(tszLocal, GENERIC_READ | GENERIC_WRITE, NULL, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); + WriteFile(hFile, pReply->pData, (DWORD)pReply->dataLength, &dwBytes, NULL); + ret = true; + } + _close(fh); + } + else + { + hFile = CreateFile(tszLocal, GENERIC_READ | GENERIC_WRITE, NULL, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); + WriteFile(hFile, pReply->pData, (DWORD)pReply->dataLength, &dwBytes, NULL); + ret = true; + } + mir_free(tdate); + mir_free(tsize); + } + else + { + hFile = CreateFile(tszLocal, GENERIC_READ | GENERIC_WRITE, NULL, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); + WriteFile(hFile, pReply->pData, (DWORD)pReply->dataLength, &dwBytes, NULL); + ret = true; + } + } + CallService(MS_NETLIB_FREEHTTPREQUESTSTRUCT,0,(LPARAM)pReply); + } + + mir_free(szUrl); + mir_free(nlhr.headers); + + if (hFile) + CloseHandle(hFile); + + return ret; +} + +size_t PathToRelative(const TCHAR *pSrc, TCHAR *pOut) +{ return CallService( MS_UTILS_PATHTORELATIVET, (WPARAM)pSrc, (LPARAM)pOut ); +} + +TCHAR* CheckFeed(TCHAR* tszURL, HWND hwndDlg) +{ + char *szData = NULL; + DBVARIANT dbVar = {0}; + if (CallProtoService(MODULE, PS_GETSTATUS, 0, 0) != ID_STATUS_OFFLINE) + { + GetNewsData(tszURL, &szData, NULL, hwndDlg); + if (szData) + { + TCHAR *tszData = mir_a2t(szData); + int bytesParsed = 0; + HXML hXml = xi.parseString(tszData, &bytesParsed, NULL); + BOOL UtfEncode = FALSE; + TCHAR *newtszData = mir_utf8decodeT(szData); + if (newtszData) + { + UtfEncode = TRUE; + mir_free(newtszData); + } + mir_free(tszData); + mir_free(szData); + if(hXml != NULL) + { + int childcount = 0; + HXML node = xi.getChild(hXml, childcount); + while(node) + { + if (lstrcmpi(xi.getName(node), _T("rss")) == 0 || lstrcmpi(xi.getName(node), _T("rdf")) == 0) + { + HXML chan = xi.getChild(node, 0); + for (int j = 0; j < xi.getChildCount(chan); j++) + { + HXML child = xi.getChild(chan, j); + if (lstrcmpi(xi.getName(child), _T("title")) == 0) + { + TCHAR mes[MAX_PATH]; + mir_sntprintf(mes, SIZEOF(mes), TranslateT("%s\nis a valid feed's address."), tszURL); + MessageBox(NULL, mes, TranslateT("New Aggregator"), MB_OK|MB_ICONINFORMATION); + TCHAR *tszTitle = (TCHAR*)xi.getText(child); + if (UtfEncode) + { + char* szstring = mir_t2a(tszTitle); + TCHAR* tszstring = mir_utf8decodeT(szstring); + tszTitle = (TCHAR*)mir_alloc(sizeof(TCHAR)*lstrlen(tszstring)+1); + _tcscpy(tszTitle, tszstring); + mir_free(tszstring); + mir_free(szstring); + } + return tszTitle; + } + } + } + else if (lstrcmpi(xi.getName(node), _T("feed")) == 0) + { + for (int j = 0; j < xi.getChildCount(node); j++) + { + HXML child = xi.getChild(node, j); + if (lstrcmpi(xi.getName(child), _T("title")) == 0) + { + TCHAR mes[MAX_PATH]; + mir_sntprintf(mes, SIZEOF(mes), TranslateT("%s\nis a valid feed's address."), tszURL); + MessageBox(NULL, mes, TranslateT("New Aggregator"), MB_OK|MB_ICONINFORMATION); + TCHAR *tszTitle = (TCHAR*)xi.getText(child); + if (UtfEncode) + { + char* szstring = mir_t2a(tszTitle); + TCHAR* tszstring = mir_utf8decodeT(szstring); + tszTitle = (TCHAR*)mir_alloc(sizeof(TCHAR)*lstrlen(tszstring)+1); + _tcscpy(tszTitle, tszstring); + mir_free(tszstring); + mir_free(szstring); + } + return tszTitle; + } + } + } + childcount +=1; + node = xi.getChild(hXml, childcount); + } + } + xi.destroyNode(hXml); + } + else + { + TCHAR mes[MAX_PATH]; + mir_sntprintf(mes, SIZEOF(mes), TranslateT("%s\nis a not valid feed's address."), tszURL); + MessageBox(NULL, mes, TranslateT("New Aggregator"), MB_OK|MB_ICONERROR); + } + } + return NULL; +} + +VOID CheckCurrentFeed(HANDLE hContact) +{ + char *szData = NULL; + DBVARIANT dbURL = {0}; + if (DBGetContactSettingTString(hContact, MODULE, "URL", &dbURL)) + return; + else if ((DBGetContactSettingWord(hContact, MODULE, "Status", ID_STATUS_OFFLINE) != ID_STATUS_OFFLINE) && DBGetContactSettingByte(hContact, MODULE, "CheckState", 1) != 0) + { + GetNewsData(dbURL.ptszVal, &szData, hContact, NULL); + DBFreeVariant(&dbURL); + if (szData) + { + TCHAR *tszData = mir_a2t(szData); + int bytesParsed = 0; + HXML hXml = xi.parseString(tszData, &bytesParsed, NULL); + BOOL UtfEncode = FALSE; + TCHAR *newtszData = mir_utf8decodeT(szData); + if (newtszData) + { + UtfEncode = TRUE; + mir_free(newtszData); + } + mir_free(tszData); + mir_free(szData); + if(hXml != NULL) + { + int childcount = 0; + HXML node = xi.getChild(hXml, childcount); + while(node) + { + if (lstrcmpi(xi.getName(node), _T("rss")) == 0 || lstrcmpi(xi.getName(node), _T("rdf")) == 0) + { + if (lstrcmpi(xi.getName(node), _T("rss")) == 0) + { + for (int i = 0; i < xi.getAttrCount(node); i++) + { + if (lstrcmpi(xi.getAttrName(node, i), _T("version")) == 0) + { + TCHAR ver[MAX_PATH]; + mir_sntprintf(ver, SIZEOF(ver), _T("RSS %s"), xi.getAttrValue(node, xi.getAttrName(node, i))); + DBWriteContactSettingTString(hContact, MODULE, "MirVer", ver); + break; + } + } + } + else if (lstrcmpi(xi.getName(node), _T("rdf")) == 0) + { + DBWriteContactSettingTString(hContact, MODULE, "MirVer", _T("RSS 1.0")); + } + + HXML chan = xi.getChild(node, 0); + for (int j = 0; j < xi.getChildCount(chan); j++) + { + HXML child = xi.getChild(chan, j); + if (lstrcmpi(xi.getName(child), _T("title")) == 0 && xi.getText(child)) + { + char* szstring = mir_t2a(xi.getText(child)); + decode_html_entities_utf8(szstring, 0); + boost::regex xRegEx("<(.|\n)*?>"); + std::string xStr(szstring); + strcpy(szstring, boost::regex_replace(xStr, xRegEx, "", boost::match_default | boost::format_perl).c_str()); + if (UtfEncode) + { + TCHAR* tszstring = mir_utf8decodeT(szstring); + DBWriteContactSettingTString(hContact, MODULE, "FirstName", tszstring); + mir_free(tszstring); + } + else + { + TCHAR* tszstring = mir_a2t(szstring); + DBWriteContactSettingTString(hContact, MODULE, "FirstName", tszstring); + mir_free(tszstring); + } + mir_free(szstring); + continue; + } + if (lstrcmpi(xi.getName(child), _T("link")) == 0) + { + DBWriteContactSettingTString(hContact, MODULE, "Homepage", xi.getText(child)); + continue; + } + if (lstrcmpi(xi.getName(child), _T("description")) == 0 && xi.getText(child)) + { + char* szstring = mir_t2a(xi.getText(child)); + decode_html_entities_utf8(szstring, 0); + boost::regex xRegEx("<(.|\n)*?>"); + std::string xStr(szstring); + strcpy(szstring, boost::regex_replace(xStr, xRegEx, "", boost::match_default | boost::format_perl).c_str()); + if (UtfEncode) + { + TCHAR* tszstring = mir_utf8decodeT(szstring); + DBWriteContactSettingTString(hContact, MODULE, "About", tszstring); + DBWriteContactSettingTString(hContact, "CList", "StatusMsg", tszstring); + mir_free(tszstring); + } + else + { + TCHAR* tszstring = mir_a2t(szstring); + DBWriteContactSettingTString(hContact, MODULE, "About", tszstring); + DBWriteContactSettingTString(hContact, "CList", "StatusMsg", tszstring); + mir_free(tszstring); + } + mir_free(szstring); + continue; + } + if (lstrcmpi(xi.getName(child), _T("language")) == 0 && xi.getText(child)) + { + char* szstring = mir_t2a(xi.getText(child)); + decode_html_entities_utf8(szstring, 0); + boost::regex xRegEx("<(.|\n)*?>"); + std::string xStr(szstring); + strcpy(szstring, boost::regex_replace(xStr, xRegEx, "", boost::match_default | boost::format_perl).c_str()); + if (UtfEncode) + { + TCHAR* tszstring = mir_utf8decodeT(szstring); + DBWriteContactSettingTString(hContact, MODULE, "Language1", tszstring); + mir_free(tszstring); + } + else + { + TCHAR* tszstring = mir_a2t(szstring); + DBWriteContactSettingTString(hContact, MODULE, "Language1", tszstring); + mir_free(tszstring); + } + mir_free(szstring); + continue; + } + if (lstrcmpi(xi.getName(child), _T("managingEditor")) == 0 && xi.getText(child)) + { + char* szstring = mir_t2a(xi.getText(child)); + decode_html_entities_utf8(szstring, 0); + boost::regex xRegEx("<(.|\n)*?>"); + std::string xStr(szstring); + strcpy(szstring, boost::regex_replace(xStr, xRegEx, "", boost::match_default | boost::format_perl).c_str()); + if (UtfEncode) + { + TCHAR* tszstring = mir_utf8decodeT(szstring); + DBWriteContactSettingTString(hContact, MODULE, "e-mail", tszstring); + mir_free(tszstring); + } + else + { + TCHAR* tszstring = mir_a2t(szstring); + DBWriteContactSettingTString(hContact, MODULE, "e-mail", tszstring); + mir_free(tszstring); + } + mir_free(szstring); + continue; + } + if (lstrcmpi(xi.getName(child), _T("category")) == 0 && xi.getText(child)) + { + char* szstring = mir_t2a(xi.getText(child)); + decode_html_entities_utf8(szstring, 0); + boost::regex xRegEx("<(.|\n)*?>"); + std::string xStr(szstring); + strcpy(szstring, boost::regex_replace(xStr, xRegEx, "", boost::match_default | boost::format_perl).c_str()); + if (UtfEncode) + { + TCHAR* tszstring = mir_utf8decodeT(szstring); + DBWriteContactSettingTString(hContact, MODULE, "Interest0Text", tszstring); + mir_free(tszstring); + } + else + { + TCHAR* tszstring = mir_a2t(szstring); + DBWriteContactSettingTString(hContact, MODULE, "Interest0Text", tszstring); + mir_free(tszstring); + } + mir_free(szstring); + continue; + } + if (lstrcmpi(xi.getName(child), _T("image")) == 0) + { + for (int x = 0; x < xi.getChildCount(child); x++) + { + HXML imageval = xi.getChild(child, x); + if (lstrcmpi(xi.getName(imageval), _T("url")) == 0) + { + LPCTSTR url = xi.getText(imageval); + DBWriteContactSettingTString(hContact, MODULE, "ImageURL", url); + + PROTO_AVATAR_INFORMATIONT pai = {NULL}; + pai.cbSize = sizeof(pai); + pai.hContact = hContact; + DBVARIANT dbVar = {0}; + + if (!DBGetContactSettingTString(hContact, MODULE, "Nick", &dbVar)) + { + TCHAR *ext = _tcsrchr((TCHAR*)url, _T('.')) + 1; + pai.format = GetImageFormat(ext); + + TCHAR *filename = dbVar.ptszVal; + mir_sntprintf(pai.filename, SIZEOF(pai.filename), _T("%s\\%s.%s"), tszRoot, filename, ext); + if (DownloadFile(url, pai.filename)) + { + DBWriteContactSettingTString(hContact, MODULE, "ImagePath", pai.filename); + ProtoBroadcastAck(MODULE, hContact, ACKTYPE_AVATAR, ACKRESULT_SUCCESS, (HANDLE) &pai, NULL); + } + else + ProtoBroadcastAck(MODULE, hContact, ACKTYPE_AVATAR, ACKRESULT_FAILED, (HANDLE) &pai, NULL); + DBFreeVariant(&dbVar); + break; + } + } + else + { + DBDeleteContactSetting(hContact, MODULE, "ImageURL"); + DBDeleteContactSetting(hContact, MODULE, "ImagePath"); + } + } + } + if (lstrcmpi(xi.getName(child), _T("lastBuildDate")) == 0 && xi.getText(child)) + { + TCHAR *lastupdtime = (TCHAR*)xi.getText(child); + time_t stamp = DateToUnixTime(lastupdtime, 0); + double deltaupd = difftime(time(NULL), stamp); + double deltacheck = difftime(time(NULL), DBGetContactSettingDword(hContact, MODULE, "LastCheck", 0)); + if (deltaupd - deltacheck >= 0) + { + DBWriteContactSettingDword(hContact, MODULE, "LastCheck", time(NULL)); + xi.destroyNode(hXml); + return; + } + continue; + } + if (lstrcmpi(xi.getName(child), _T("item")) == 0) + { + TCHAR *title = NULL, *link = NULL, *datetime = NULL, *descr = NULL, *author = NULL, *comments = NULL, *guid = NULL, *category = NULL; + for (int z = 0; z < xi.getChildCount(child); z++) + { + HXML itemval = xi.getChild(child, z); + if (lstrcmpi(xi.getName(itemval), _T("title")) == 0) + { + title = (TCHAR*)xi.getText(itemval); + continue; + } + if (lstrcmpi(xi.getName(itemval), _T("link")) == 0) + { + link = (TCHAR*)xi.getText(itemval); + continue; + } + if (lstrcmpi(xi.getName(itemval), _T("pubDate")) == 0) + { + datetime = (TCHAR*)xi.getText(itemval); + continue; + } + if (lstrcmpi(xi.getName(itemval), _T("dc:date")) == 0) + { + datetime = (TCHAR*)xi.getText(itemval); + continue; + } + if (lstrcmpi(xi.getName(itemval), _T("description")) == 0) + { + descr = (TCHAR*)xi.getText(itemval); + continue; + } + if (lstrcmpi(xi.getName(itemval), _T("author")) == 0) + { + author = (TCHAR*)xi.getText(itemval); + continue; + } + if (lstrcmpi(xi.getName(itemval), _T("comments")) == 0) + { + comments = (TCHAR*)xi.getText(itemval); + continue; + } + if (lstrcmpi(xi.getName(itemval), _T("guid")) == 0) + { + guid = (TCHAR*)xi.getText(itemval); + continue; + } + if (lstrcmpi(xi.getName(itemval), _T("category")) == 0) + { + category = (TCHAR*)xi.getText(itemval); + continue; + } + } + TCHAR* message; + DBVARIANT dbMsg = {0}; + if (DBGetContactSettingTString(hContact, MODULE, "MsgFormat", &dbMsg)) + message = _T(TAGSDEFAULT); + else + { + message = (TCHAR*)mir_alloc(_tcslen(dbMsg.ptszVal)*sizeof(TCHAR)); + memcpy(message, dbMsg.ptszVal, _tcslen(dbMsg.ptszVal)*sizeof(TCHAR)); + message[_tcslen(dbMsg.ptszVal)] = 0; + DBFreeVariant(&dbMsg); + } + if (lstrcmp(title, NULL) == 0) + message = StrReplace(_T("#<title>#"), TranslateT("empty"), message); + else + message = StrReplace(_T("#<title>#"), title, message); + if (lstrcmp(link, NULL) == 0) + message = StrReplace(_T("#<link>#"), TranslateT("empty"), message); + else + message = StrReplace(_T("#<link>#"), link, message); + if (lstrcmp(descr, NULL) == 0) + message = StrReplace(_T("#<description>#"), TranslateT("empty"), message); + else + message = StrReplace(_T("#<description>#"), descr, message); + if (lstrcmp(author, NULL) == 0) + message = StrReplace(_T("#<author>#"), TranslateT("empty"), message); + else + message = StrReplace(_T("#<author>#"), author, message); + if (lstrcmp(comments, NULL) == 0) + message = StrReplace(_T("#<comments>#"), TranslateT("empty"), message); + else + message = StrReplace(_T("#<comments>#"), comments, message); + if (lstrcmp(guid, NULL) == 0) + message = StrReplace(_T("#<guid>#"), TranslateT("empty"), message); + else + message = StrReplace(_T("#<guid>#"), guid, message); + if (lstrcmp(category, NULL) == 0) + message = StrReplace(_T("#<category>#"), TranslateT("empty"), message); + else + message = StrReplace(_T("#<category>#"), category, message); + + message = StrReplace(_T("<br>"), _T("\n"), message); + message = StrReplace(_T("<br/>"), _T("\n"), message); + message = StrReplace(_T("<br />"), _T("\n"), message); + + char* pszUtf; + if (!UtfEncode) + pszUtf = mir_utf8encodeT(message); + else + pszUtf = mir_t2a(message); + decode_html_entities_utf8(pszUtf, 0); + boost::regex xRegEx("<(.|\n)*?>"); + std::string xStr(pszUtf); + strcpy(pszUtf, boost::regex_replace(xStr, xRegEx, "", boost::match_default | boost::format_perl).c_str()); + xRegEx = "^\\s+"; + xStr = pszUtf; + strcpy(pszUtf, boost::regex_replace(xStr, xRegEx, "", boost::match_default | boost::format_perl).c_str()); + + time_t stamp; + if (lstrcmpi(datetime, NULL) ==0) + stamp = time(NULL); + else + stamp = DateToUnixTime(datetime, 0); + + DBEVENTINFO olddbei = { 0 }; + HANDLE hDbEvent = (HANDLE)CallService(MS_DB_EVENT_FINDFIRST, (WPARAM)hContact, 0); + BOOL MesExist = FALSE; + while(hDbEvent) + { + ZeroMemory(&olddbei, sizeof(olddbei)); + olddbei.cbSize = sizeof(olddbei); + olddbei.cbBlob = CallService(MS_DB_EVENT_GETBLOBSIZE, (WPARAM)hDbEvent, 0); + olddbei.pBlob = (PBYTE)mir_alloc(olddbei.cbBlob); + CallService(MS_DB_EVENT_GET, (WPARAM)hDbEvent, (LPARAM)&olddbei); + if (olddbei.cbBlob == lstrlenA(pszUtf) + 1 && lstrcmpA((char*)olddbei.pBlob, pszUtf) == 0) + MesExist = TRUE; + hDbEvent = (HANDLE)CallService(MS_DB_EVENT_FINDNEXT, (WPARAM)hDbEvent, 0); + mir_free(olddbei.pBlob); + } + + if (!MesExist) + { + DBEVENTINFO dbei = {0}; + dbei.cbSize = sizeof(dbei); + dbei.eventType = EVENTTYPE_MESSAGE; + dbei.flags = DBEF_UTF; + dbei.szModule = MODULE; + dbei.timestamp = stamp; + dbei.cbBlob = lstrlenA(pszUtf) + 1; + dbei.pBlob = (PBYTE)pszUtf; + CallService(MS_DB_EVENT_ADD, (WPARAM)hContact, (LPARAM)&dbei); + } + mir_free(pszUtf); + mir_free(message); + } + } + } + else if (lstrcmpi(xi.getName(node), _T("feed")) == 0) + { + DBWriteContactSettingTString(hContact, MODULE, "MirVer", _T("Atom 3")); + for (int j = 0; j < xi.getChildCount(node); j++) + { + HXML child = xi.getChild(node, j); + if (lstrcmpi(xi.getName(child), _T("title")) == 0 && xi.getText(child)) + { + char* szstring = mir_t2a(xi.getText(child)); + decode_html_entities_utf8(szstring, 0); + boost::regex xRegEx("<(.|\n)*?>"); + std::string xStr(szstring); + strcpy(szstring, boost::regex_replace(xStr, xRegEx, "", boost::match_default | boost::format_perl).c_str()); + if (UtfEncode) + { + TCHAR* tszstring = mir_utf8decodeT(szstring); + DBWriteContactSettingTString(hContact, MODULE, "FirstName", tszstring); + mir_free(tszstring); + } + else + { + TCHAR* tszstring = mir_a2t(szstring); + DBWriteContactSettingTString(hContact, MODULE, "FirstName", tszstring); + mir_free(tszstring); + } + mir_free(szstring); + continue; + } + if (lstrcmpi(xi.getName(child), _T("link")) == 0) + { + for (int x = 0; x < xi.getAttrCount(child); x++) + { + if (lstrcmpi(xi.getAttrName(child, x), _T("rel")) == 0) + { + if (lstrcmpi(xi.getAttrValue(child, xi.getAttrName(child, x)), _T("self")) == 0) + break; + } + if (lstrcmpi(xi.getAttrName(child, x), _T("href")) == 0) + { + DBWriteContactSettingTString(hContact, MODULE, "Homepage", xi.getAttrValue(child, xi.getAttrName(child, x))); + } + } + continue; + } + if (lstrcmpi(xi.getName(child), _T("subtitle")) == 0 && xi.getText(child)) + { + char* szstring = mir_t2a(xi.getText(child)); + decode_html_entities_utf8(szstring, 0); + boost::regex xRegEx("<(.|\n)*?>"); + std::string xStr(szstring); + strcpy(szstring, boost::regex_replace(xStr, xRegEx, "", boost::match_default | boost::format_perl).c_str()); + if (UtfEncode) + { + TCHAR* tszstring = mir_utf8decodeT(szstring); + DBWriteContactSettingTString(hContact, MODULE, "About", tszstring); + DBWriteContactSettingTString(hContact, "CList", "StatusMsg", tszstring); + mir_free(tszstring); + } + else + { + TCHAR* tszstring = mir_a2t(szstring); + DBWriteContactSettingTString(hContact, MODULE, "About", tszstring); + DBWriteContactSettingTString(hContact, "CList", "StatusMsg", tszstring); + mir_free(tszstring); + } + mir_free(szstring); + continue; + } + if (lstrcmpi(xi.getName(child), _T("language")) == 0 && xi.getText(child)) + { + char* szstring = mir_t2a(xi.getText(child)); + decode_html_entities_utf8(szstring, 0); + boost::regex xRegEx("<(.|\n)*?>"); + std::string xStr(szstring); + strcpy(szstring, boost::regex_replace(xStr, xRegEx, "", boost::match_default | boost::format_perl).c_str()); + if (UtfEncode) + { + TCHAR* tszstring = mir_utf8decodeT(szstring); + DBWriteContactSettingTString(hContact, MODULE, "Language1", tszstring); + mir_free(tszstring); + } + else + { + TCHAR* tszstring = mir_a2t(szstring); + DBWriteContactSettingTString(hContact, MODULE, "Language1", tszstring); + mir_free(tszstring); + } + mir_free(szstring); + continue; + } + if (lstrcmpi(xi.getName(child), _T("author")) == 0) + { + for (int x = 0; x < xi.getChildCount(child); x++) + { + HXML authorval = xi.getChild(child, x); + if (lstrcmpi(xi.getName(authorval), _T("name")) == 0) + { + DBWriteContactSettingTString(hContact, MODULE, "e-mail", xi.getText(authorval)); + break; + } + } + continue; + } + if (lstrcmpi(xi.getName(child), _T("category")) == 0 && xi.getText(child)) + { + char* szstring = mir_t2a(xi.getText(child)); + decode_html_entities_utf8(szstring, 0); + boost::regex xRegEx("<(.|\n)*?>"); + std::string xStr(szstring); + strcpy(szstring, boost::regex_replace(xStr, xRegEx, "", boost::match_default | boost::format_perl).c_str()); + if (UtfEncode) + { + TCHAR* tszstring = mir_utf8decodeT(szstring); + DBWriteContactSettingTString(hContact, MODULE, "Interest0Text", tszstring); + mir_free(tszstring); + } + else + { + TCHAR* tszstring = mir_a2t(szstring); + DBWriteContactSettingTString(hContact, MODULE, "Interest0Text", tszstring); + mir_free(tszstring); + } + mir_free(szstring); + continue; + } + if (lstrcmpi(xi.getName(child), _T("icon")) == 0) + { + for (int x = 0; x < xi.getChildCount(child); x++) + { + HXML imageval = xi.getChild(child, x); + if (lstrcmpi(xi.getName(imageval), _T("url")) == 0) + { + LPCTSTR url = xi.getText(imageval); + DBWriteContactSettingTString(hContact, MODULE, "ImageURL", url); + + PROTO_AVATAR_INFORMATIONT pai = {NULL}; + pai.cbSize = sizeof(pai); + pai.hContact = hContact; + DBVARIANT dbVar = {0}; + + if (!DBGetContactSettingTString(hContact, MODULE, "Nick", &dbVar)) + { + TCHAR *ext = _tcsrchr((TCHAR*)url, _T('.')) + 1; + pai.format = GetImageFormat(ext); + + TCHAR *filename = dbVar.ptszVal; + mir_sntprintf(pai.filename, SIZEOF(pai.filename), _T("%s\\%s.%s"), tszRoot, filename, ext); + if (DownloadFile(url, pai.filename)) + { + DBWriteContactSettingTString(hContact, MODULE, "ImagePath", pai.filename); + ProtoBroadcastAck(MODULE, hContact, ACKTYPE_AVATAR, ACKRESULT_SUCCESS, (HANDLE) &pai, NULL); + } + else + ProtoBroadcastAck(MODULE, hContact, ACKTYPE_AVATAR, ACKRESULT_FAILED, (HANDLE) &pai, NULL); + DBFreeVariant(&dbVar); + break; + } + } + else + { + DBDeleteContactSetting(hContact, MODULE, "ImageURL"); + DBDeleteContactSetting(hContact, MODULE, "ImagePath"); + } + } + } + if (lstrcmpi(xi.getName(child), _T("updated")) == 0 && xi.getText(child)) + { + TCHAR *lastupdtime = (TCHAR*)xi.getText(child); + time_t stamp = DateToUnixTime(lastupdtime, 1); + double deltaupd = difftime(time(NULL), stamp); + double deltacheck = difftime(time(NULL), DBGetContactSettingDword(hContact, MODULE, "LastCheck", 0)); + if (deltaupd - deltacheck >= 0) + { + DBWriteContactSettingDword(hContact, MODULE, "LastCheck", time(NULL)); + xi.destroyNode(hXml); + return; + } + continue; + } + if (lstrcmpi(xi.getName(child), _T("entry")) == 0) + { + TCHAR *title = NULL, *link = NULL, *datetime = NULL, *descr = NULL, *author = NULL, *comments = NULL, *guid = NULL, *category = NULL; + for (int z = 0; z < xi.getChildCount(child); z++) + { + HXML itemval = xi.getChild(child, z); + if (lstrcmpi(xi.getName(itemval), _T("title")) == 0 && xi.getText(itemval)) + { + char* szstring = mir_t2a(xi.getText(itemval)); + decode_html_entities_utf8(szstring, 0); + boost::regex xRegEx("<(.|\n)*?>"); + std::string xStr(szstring); + strcpy(szstring, boost::regex_replace(xStr, xRegEx, "", boost::match_default | boost::format_perl).c_str()); + title = mir_a2t(szstring); + mir_free(szstring); + continue; + } + if (lstrcmpi(xi.getName(itemval), _T("link")) == 0) + { + for (int x = 0; x < xi.getAttrCount(itemval); x++) + { + if (lstrcmpi(xi.getAttrName(itemval, x), _T("href")) == 0) + { + link = (TCHAR*)xi.getAttrValue(itemval, xi.getAttrName(itemval, x)); + break; + } + } + continue; + } + if (lstrcmpi(xi.getName(itemval), _T("updated")) == 0) + { + datetime = (TCHAR*)xi.getText(itemval); + continue; + } + if ((lstrcmpi(xi.getName(itemval), _T("summary")) == 0 || lstrcmpi(xi.getName(itemval), _T("content")) == 0) && xi.getText(itemval)) + { + char* szstring = mir_t2a(xi.getText(itemval)); + decode_html_entities_utf8(szstring, 0); + boost::regex xRegEx("<(.|\n)*?>"); + std::string xStr(szstring); + strcpy(szstring, boost::regex_replace(xStr, xRegEx, "", boost::match_default | boost::format_perl).c_str()); + descr = mir_a2t(szstring); + mir_free(szstring); + continue; + } + if (lstrcmpi(xi.getName(itemval), _T("author")) == 0) + { + for (int x = 0; x < xi.getChildCount(itemval); x++) + { + HXML authorval = xi.getChild(itemval, x); + if (lstrcmpi(xi.getName(authorval), _T("name")) == 0 && xi.getText(authorval)) + { + char* szstring = mir_t2a(xi.getText(authorval)); + decode_html_entities_utf8(szstring, 0); + boost::regex xRegEx("<(.|\n)*?>"); + std::string xStr(szstring); + strcpy(szstring, boost::regex_replace(xStr, xRegEx, "", boost::match_default | boost::format_perl).c_str()); + author = mir_a2t(szstring); + mir_free(szstring); + break; + } + } + continue; + } + if (lstrcmpi(xi.getName(itemval), _T("comments")) == 0 && xi.getText(itemval)) + { + char* szstring = mir_t2a(xi.getText(itemval)); + decode_html_entities_utf8(szstring, 0); + boost::regex xRegEx("<(.|\n)*?>"); + std::string xStr(szstring); + strcpy(szstring, boost::regex_replace(xStr, xRegEx, "", boost::match_default | boost::format_perl).c_str()); + comments = mir_a2t(szstring); + mir_free(szstring); + continue; + } + if (lstrcmpi(xi.getName(itemval), _T("id")) == 0) + { + guid = (TCHAR*)xi.getText(itemval); + continue; + } + if (lstrcmpi(xi.getName(itemval), _T("category")) == 0) + { + for (int x = 0; x < xi.getAttrCount(itemval); x++) + { + if (lstrcmpi(xi.getAttrName(itemval, x), _T("term")) == 0 && xi.getText(itemval)) + { + char* szstring = mir_t2a(xi.getAttrValue(itemval, xi.getAttrName(itemval, x))); + decode_html_entities_utf8(szstring, 0); + boost::regex xRegEx("<(.|\n)*?>"); + std::string xStr(szstring); + strcpy(szstring, boost::regex_replace(xStr, xRegEx, "", boost::match_default | boost::format_perl).c_str()); + category = mir_a2t(szstring); + mir_free(szstring); + break; + } + } + continue; + } + } + TCHAR* message; + DBVARIANT dbMsg = {0}; + if (DBGetContactSettingTString(hContact, MODULE, "MsgFormat", &dbMsg)) + message = _T(TAGSDEFAULT); + else + { + message = (TCHAR*)mir_alloc(_tcslen(dbMsg.ptszVal)*sizeof(TCHAR)); + memcpy(message, dbMsg.ptszVal, _tcslen(dbMsg.ptszVal)*sizeof(TCHAR)); + message[_tcslen(dbMsg.ptszVal)] = 0; + DBFreeVariant(&dbMsg); + } + if (lstrcmp(title, NULL) == 0) + message = StrReplace(_T("#<title>#"), TranslateT("empty"), message); + else + message = StrReplace(_T("#<title>#"), title, message); + if (lstrcmp(link, NULL) == 0) + message = StrReplace(_T("#<link>#"), TranslateT("empty"), message); + else + message = StrReplace(_T("#<link>#"), link, message); + if (lstrcmp(descr, NULL) == 0) + message = StrReplace(_T("#<description>#"), TranslateT("empty"), message); + else + message = StrReplace(_T("#<description>#"), descr, message); + if (lstrcmp(author, NULL) == 0) + message = StrReplace(_T("#<author>#"), TranslateT("empty"), message); + else + message = StrReplace(_T("#<author>#"), author, message); + if (lstrcmp(comments, NULL) == 0) + message = StrReplace(_T("#<comments>#"), TranslateT("empty"), message); + else + message = StrReplace(_T("#<comments>#"), comments, message); + if (lstrcmp(guid, NULL) == 0) + message = StrReplace(_T("#<guid>#"), TranslateT("empty"), message); + else + message = StrReplace(_T("#<guid>#"), guid, message); + if (lstrcmp(category, NULL) == 0) + message = StrReplace(_T("#<category>#"), TranslateT("empty"), message); + else + message = StrReplace(_T("#<category>#"), category, message); + + message = StrReplace(_T("<br>"), _T("\n"), message); + message = StrReplace(_T("<br/>"), _T("\n"), message); + message = StrReplace(_T("<br />"), _T("\n"), message); + + char* pszUtf; + if (!UtfEncode) + pszUtf = mir_utf8encodeT(message); + else + pszUtf = mir_t2a(message); + decode_html_entities_utf8(pszUtf, 0); + boost::regex xRegEx("<(.|\n)*?>"); + std::string xStr(pszUtf); + strcpy(pszUtf, boost::regex_replace(xStr, xRegEx, "", boost::match_default | boost::format_perl).c_str()); + xRegEx = "^\\s+"; + xStr = pszUtf; + strcpy(pszUtf, boost::regex_replace(xStr, xRegEx, "", boost::match_default | boost::format_perl).c_str()); + + time_t stamp; + if (lstrcmpi(datetime, NULL) ==0) + stamp = time(NULL); + else + stamp = DateToUnixTime(datetime, 1); + + DBEVENTINFO olddbei = { 0 }; + HANDLE hDbEvent = (HANDLE)CallService(MS_DB_EVENT_FINDFIRST, (WPARAM)hContact, 0); + BOOL MesExist = FALSE; + while(hDbEvent) + { + ZeroMemory(&olddbei, sizeof(olddbei)); + olddbei.cbSize = sizeof(olddbei); + olddbei.cbBlob = CallService(MS_DB_EVENT_GETBLOBSIZE, (WPARAM)hDbEvent, 0); + olddbei.pBlob = (PBYTE)malloc(olddbei.cbBlob); + CallService(MS_DB_EVENT_GET, (WPARAM)hDbEvent, (LPARAM)&olddbei); + if (olddbei.cbBlob == lstrlenA(pszUtf) + 1 && lstrcmpA((char*)olddbei.pBlob, pszUtf) == 0) + MesExist = TRUE; + hDbEvent = (HANDLE)CallService(MS_DB_EVENT_FINDNEXT, (WPARAM)hDbEvent, 0); + } + + if (!MesExist) + { + DBEVENTINFO dbei = {0}; + dbei.cbSize = sizeof(dbei); + dbei.eventType = EVENTTYPE_MESSAGE; + dbei.flags = DBEF_UTF; + dbei.szModule = MODULE; + dbei.timestamp = stamp; + dbei.cbBlob = lstrlenA(pszUtf) + 1; + dbei.pBlob = (PBYTE)pszUtf; + CallService(MS_DB_EVENT_ADD, (WPARAM)hContact, (LPARAM)&dbei); + } + mir_free(pszUtf); + } + } + } + childcount +=1; + node = xi.getChild(hXml, childcount); + } + xi.destroyNode(hXml); + } + } + DBWriteContactSettingDword(hContact, MODULE, "LastCheck", time(NULL)); + } +} \ No newline at end of file diff --git a/protocols/NewsAggregator/ToDo.txt b/protocols/NewsAggregator/ToDo.txt new file mode 100644 index 0000000000..fa08c1a5f3 --- /dev/null +++ b/protocols/NewsAggregator/ToDo.txt @@ -0,0 +1,11 @@ + xml +\ + + + html' + +xml parse +contacts export\import +autoimport from file service +authorization +replace all html to text \ No newline at end of file diff --git a/protocols/NewsAggregator/Version.h b/protocols/NewsAggregator/Version.h new file mode 100644 index 0000000000..fe5d837fe3 --- /dev/null +++ b/protocols/NewsAggregator/Version.h @@ -0,0 +1,28 @@ +#define __MAJOR_VERSION 0 +#define __MINOR_VERSION 0 +#define __RELEASE_NUM 0 +#define __BUILD_NUM 1 + +#define __FILEVERSION_STRING __MAJOR_VERSION,__MINOR_VERSION,__RELEASE_NUM,__BUILD_NUM +#define __FILEVERSION_DOTS __MAJOR_VERSION.__MINOR_VERSION.__RELEASE_NUM.__BUILD_NUM + +#define __STRINGIFY_IMPL(x) #x +#define __STRINGIFY(x) __STRINGIFY_IMPL(x) +#define __VERSION_STRING __STRINGIFY(__FILEVERSION_DOTS) + +#ifdef _UNICODE +#if defined(WIN64) || defined(_WIN64) + #define __PLUGIN_NAME "NewsAggregator (Unicode x64)" +#else + #define __PLUGIN_NAME "NewsAggregator (Unicode)" +#endif +#else + #define __PLUGIN_NAME "NewsAggregator" +#endif +#define __INTERNAL_NAME "NewsAggregator" +#define __FILENAME "NewsAggregator.dll" +#define __DESCRIPTION "RSS/Atom news aggregator." +#define __AUTHOR "Mataes, FREAK_THEMIGHTY" +#define __AUTHOREMAIL "mataes2007@gmail.com" +#define __AUTHORWEB "http://mataes.googlecode.com/svn/Miranda/Plugins/NewsAggregator/" +#define __COPYRIGHT " 2012 Mataes, FREAK_THEMIGHTY" diff --git a/protocols/NewsAggregator/Version.rc b/protocols/NewsAggregator/Version.rc new file mode 100644 index 0000000000..e637f0cb33 --- /dev/null +++ b/protocols/NewsAggregator/Version.rc @@ -0,0 +1,38 @@ +// Microsoft Visual C++ generated resource script. +// +#include "afxres.h" +#include "version.h" + +#ifdef _WIN32 +LANGUAGE LANG_NEUTRAL, SUBLANG_NEUTRAL +#endif //_WIN32 + +VS_VERSION_INFO VERSIONINFO + FILEVERSION __FILEVERSION_STRING + PRODUCTVERSION __FILEVERSION_STRING + FILEFLAGSMASK 0x17L +#ifdef _DEBUG + FILEFLAGS 0x1L +#else + FILEFLAGS 0x0L +#endif + FILEOS 0x4L + FILETYPE 0x0L + FILESUBTYPE 0x0L +BEGIN + BLOCK "StringFileInfo" + BEGIN + BLOCK "000004b0" + BEGIN + VALUE "FileDescription", __DESCRIPTION + VALUE "InternalName", __PLUGIN_NAME + VALUE "LegalCopyright", __COPYRIGHT + VALUE "OriginalFilename", __FILENAME + VALUE "ProductName", __PLUGIN_NAME + END + END + BLOCK "VarFileInfo" + BEGIN + VALUE "Translation", 0x0, 1200 + END +END diff --git a/protocols/NewsAggregator/resource.h b/protocols/NewsAggregator/resource.h new file mode 100644 index 0000000000..f243b95585 --- /dev/null +++ b/protocols/NewsAggregator/resource.h @@ -0,0 +1,39 @@ +//{{NO_DEPENDENCIES}} +// Microsoft Visual C++ generated include file. +// Used by Resource.rc +// +#define IDD_OPTIONS 101 +#define IDI_ICON 109 +#define IDD_ADDFEED 110 +#define IDI_CHECKALL 111 +#define IDI_ADDFEED 112 +#define IDI_IMPORTFEEDS 113 +#define IDI_EXPORTFEEDS 114 +#define IDC_TIMEOUT_VALUE_SPIN 1035 +#define IDC_FEEDLIST 1036 +#define IDC_ADD 1037 +#define IDC_CHANGE 1038 +#define IDC_REMOVE 1039 +#define IDC_IMORT 1040 +#define IDC_EXORT 1041 +#define IDC_FEEDTITLE 1042 +#define IDC_FEEDURL 1043 +#define IDC_CHECKTIME 1044 +#define IDC_DISCOVERY 1045 +#define IDC_USEAUTH 1046 +#define IDC_LOGIN 1047 +#define IDC_PASSWORD 1048 +#define IDC_TAGSEDIT 1049 +#define IDC_RESET 1050 +#define IDC_TAGHELP 1051 + +// Next default values for new objects +// +#ifdef APSTUDIO_INVOKED +#ifndef APSTUDIO_READONLY_SYMBOLS +#define _APS_NEXT_RESOURCE_VALUE 111 +#define _APS_NEXT_COMMAND_VALUE 40075 +#define _APS_NEXT_CONTROL_VALUE 1052 +#define _APS_NEXT_SYMED_VALUE 101 +#endif +#endif diff --git a/protocols/Quotes/Base64.cpp b/protocols/Quotes/Base64.cpp new file mode 100644 index 0000000000..1854fb42fd --- /dev/null +++ b/protocols/Quotes/Base64.cpp @@ -0,0 +1,43 @@ +#include "StdAfx.h" +#include "Base64.h" + +bool base64::encode(const BYTE* in, size_t inlen,std::vector<char>& out) +{ + int nOutLength = Base64EncodeGetRequiredLength((int)inlen); + out.resize(nOutLength); + char* p = &*out.begin(); + bool bResult = (TRUE == Base64Encode(in,(int)inlen,p,&nOutLength)); + if(false == bResult) + { + out.resize(nOutLength); + p = &*out.begin(); + bResult = (TRUE == Base64Encode(in,(int)inlen,p,&nOutLength)); + } + if(bResult) + { + out.resize(nOutLength); + } + + return bResult; +} + + +bool base64::decode(const char* in, size_t inlen,std::vector<BYTE>& out) +{ + int nOutLength = (int)inlen; + out.resize(nOutLength); + BYTE* p = &*out.begin(); + bool bResult = TRUE == Base64Decode(in,(int)inlen,p,&nOutLength); + if(false == bResult) + { + out.resize(nOutLength); + p = &*out.begin(); + bResult = TRUE == Base64Decode(in,(int)inlen,p,&nOutLength); + } + if(bResult) + { + out.resize(nOutLength); + } + + return true; +} diff --git a/protocols/Quotes/Base64.h b/protocols/Quotes/Base64.h new file mode 100644 index 0000000000..3f911bfeb8 --- /dev/null +++ b/protocols/Quotes/Base64.h @@ -0,0 +1,12 @@ +#ifndef __FBB8ABCA_315E_4ace_B2EB_51E03AD6F8D1_Base64_h__ +#define __FBB8ABCA_315E_4ace_B2EB_51E03AD6F8D1_Base64_h__ + +#pragma once + +namespace base64 +{ + bool encode(const BYTE* in, size_t inlen,std::vector<char>& out); + bool decode(const char* in, size_t inlen,std::vector<BYTE>& out); +} + +#endif //__FBB8ABCA_315E_4ace_B2EB_51E03AD6F8D1_Base64_h__ diff --git a/protocols/Quotes/Chart.h b/protocols/Quotes/Chart.h new file mode 100644 index 0000000000..62a658d818 --- /dev/null +++ b/protocols/Quotes/Chart.h @@ -0,0 +1,280 @@ +#ifndef __FAE7F26E_61ED_4951_BE87_5E022CDF21DF_Chart_h__ +#define __FAE7F26E_61ED_4951_BE87_5E022CDF21DF_Chart_h__ + +#pragma once + +namespace detail +{ + template<class T> struct CConverter + { + static double Convert(const T& v) + { + return boost::numeric_cast<double>(v); + } + + static tstring ToString(const T& v) + { + return boost::lexical_cast<tstring>(v); + } + }; + + template<> struct CConverter<double> + { + static double Convert(double v) + { + return v; + } + + static tstring ToString(double v) + { + tostringstream s; + s.imbue(std::locale("")); + s << std::fixed << v; + return s.str(); + } + }; +} + +template<class TXValue,class TYValue,class TXConverter = detail::CConverter<TXValue>,class TYConverter = detail::CConverter<TYValue> > +class CChart +{ +private: + typedef std::pair<TXValue,TYValue> TValue; + typedef std::vector<TValue> TValues; + +public: + CChart() : m_MaxY(),m_MinY() + { + ZeroMemory(&m_rect,sizeof(m_rect)); + } + + ~CChart() + { + } + + void AddValue(const TXValue& x,const TYValue& y) + { + if(m_aValues.empty()) + { + m_MaxY = m_MinY = y; + } + else + { + m_MaxY = __max(y,m_MaxY); + m_MinY = __min(y,m_MinY); + } + m_aValues.push_back(std::make_pair(x,y)); + } + + void SetRect(int x,int y,int cx,int cy) + { + m_rect.left = x; + m_rect.right = x + cx; + m_rect.top = y; + m_rect.bottom = y + cy; + } + + void Draw(HDC hdc)const + { + RECT rc = m_rect; + DrawBackground(hdc,rc); + if(false == m_aValues.empty()) + { + ::InflateRect(&rc,-10,-10); + DrawGrid(hdc,rc); + DrawAxis(hdc,rc); + DrawPoints(hdc,rc); + } + else + { + HFONT hFont = static_cast<HFONT>(::GetStockObject(DEFAULT_GUI_FONT)); + HFONT hOldFont = static_cast<HFONT>(::SelectObject(hdc,hFont)); + + LPCTSTR pszText = TranslateT("There is no to show"); + int nDrawTextResult = ::DrawText(hdc,pszText,::lstrlen(pszText),&rc,DT_SINGLELINE|DT_VCENTER|DT_CENTER); + assert(0 != nDrawTextResult); + + ::SelectObject(hdc,hOldFont); + BOOL bResult = ::DeleteObject(hFont); + assert(TRUE == bResult); + } + } + +private: + void DrawBackground(HDC hdc,RECT& rc)const + { +// HBRUSH hBrush = ::CreateSolidBrush(RGB(255,0,0));//user preferable background color here! +// ::FillRect(hdc,&m_rect,hBrush); +// ::DeleteBrush(hBrush); + } + + void DrawGrid(HDC hdc,RECT& rc)const + { + enum{number_of_lines = 5}; + HPEN hPen = ::CreatePen(PS_SOLID,1,RGB(125,125,125)); + HPEN hPenOld = static_cast<HPEN>(::SelectObject(hdc,hPen)); + HFONT hFont = static_cast<HFONT>(::GetStockObject(DEFAULT_GUI_FONT)); + HFONT hOldFont = static_cast<HFONT>(::SelectObject(hdc,hFont)); + + //vertical grid + int step = (rc.bottom-rc.top)/number_of_lines; + TYValue y_val = m_MinY + ((m_MaxY-m_MinY)/number_of_lines); + int nXIndent = 0; + for(int y = rc.bottom-step;y > rc.top;y-=step,y_val+=((m_MaxY-m_MinY)/number_of_lines)) + { + tstring sY = TYConverter::ToString(y_val); + SIZE sizeText = {0,0}; + BOOL bResult = ::GetTextExtentPoint32(hdc,sY.c_str(), (int)sY.size(), &sizeText); + assert(TRUE == bResult); + nXIndent = __max(nXIndent,sizeText.cx); + } + + y_val = m_MinY + ((m_MaxY-m_MinY)/number_of_lines); + nXIndent += 2; + rc.left += nXIndent; + for(int y = rc.bottom-step;y > rc.top;y-=step,y_val+=((m_MaxY-m_MinY)/number_of_lines)) + { + tstring sY = TYConverter::ToString(y_val); + SIZE sizeText = {0,0}; + BOOL bResult = ::GetTextExtentPoint32(hdc, sY.c_str(), (int)sY.size(), &sizeText); + assert(TRUE == bResult); + + RECT rcText = {rc.left-nXIndent,y-(sizeText.cy/2),rc.left-1,y+(sizeText.cy/2)}; + int nDrawTextResult = ::DrawText(hdc, sY.c_str(), (int)sY.size(), &rcText, DT_SINGLELINE|DT_VCENTER|DT_RIGHT); + assert(0 != nDrawTextResult); + + bResult = ::MoveToEx(hdc,rc.left,y,NULL); + assert(TRUE == bResult); + + bResult = ::LineTo(hdc,rc.right,y); + assert(TRUE == bResult); + } + + // horizontal grid + HRGN rgnAllLables = ::CreateRectRgn(0,0,0,0); + HRGN rgnTemporary = ::CreateRectRgn(0,0,0,0); + bool bFixedRect = false; + step = (rc.right-rc.left)/number_of_lines; + TXValue x_val = m_aValues[0].first + ((m_aValues[m_aValues.size()-1].first-m_aValues[0].first)/number_of_lines); + for(int x = rc.left+step;x < rc.right;x+=step,x_val+=((m_aValues[m_aValues.size()-1].first-m_aValues[0].first)/number_of_lines)) + { + tstring sX = TXConverter::ToString(x_val); + SIZE sizeText = {0,0}; + BOOL bResult = ::GetTextExtentPoint32(hdc, sX.c_str(), (int)sX.size(), &sizeText); + assert(TRUE == bResult); + + if(false == bFixedRect) + { + rc.bottom -= sizeText.cy+2; + bFixedRect = true; + } + + RECT rcText = {x-(sizeText.cx/2),rc.bottom,x+(sizeText.cx/2),rc.bottom+sizeText.cy-1}; + // Draw a label if it doesn't overlap with previous ones + HRGN rgnCurrentLable = ::CreateRectRgnIndirect(&rcText); + if(NULLREGION == ::CombineRgn(rgnTemporary,rgnCurrentLable,rgnAllLables,RGN_AND)) + { + int nDrawTextResult = ::DrawText(hdc, sX.c_str(), (int)sX.size(), &rcText, DT_SINGLELINE|DT_VCENTER|DT_CENTER); + assert(0 != nDrawTextResult); + int nCombineRgnResult = ::CombineRgn(rgnTemporary,rgnCurrentLable,rgnAllLables,RGN_OR); + assert(ERROR != nCombineRgnResult); + nCombineRgnResult = ::CombineRgn(rgnAllLables,rgnTemporary,NULL,RGN_COPY); + assert(ERROR != nCombineRgnResult); + } + bResult = ::DeleteObject(rgnCurrentLable); + assert(TRUE == bResult); + + bResult = ::MoveToEx(hdc,x,rc.bottom,NULL); + assert(TRUE == bResult); + + bResult = ::LineTo(hdc,x,rc.top); + assert(TRUE == bResult); + } + + BOOL bResult = ::DeleteObject(rgnAllLables); + assert(TRUE == bResult); + bResult = ::DeleteObject(rgnTemporary); + assert(TRUE == bResult); + + ::SelectObject(hdc,hOldFont); + ::SelectObject(hdc,hPenOld); + bResult = ::DeleteObject(hFont); + assert(TRUE == bResult); + bResult = ::DeleteObject(hPen); + assert(TRUE == bResult); + } + + void DrawAxis(HDC hdc,RECT& rc)const + { + HPEN hPen = ::CreatePen(PS_SOLID,2,RGB(0,0,0)); + HPEN hPenOld = static_cast<HPEN>(::SelectObject(hdc,hPen)); + + // draw Y-axes + BOOL bResult = ::MoveToEx(hdc,rc.left+1,rc.bottom-1,NULL); + assert(TRUE == bResult); + bResult = ::LineTo(hdc,rc.left+1,rc.top+1); + assert(TRUE == bResult); + + // draw X-axes + bResult = ::MoveToEx(hdc,rc.left+1,rc.bottom-1,NULL); + assert(TRUE == bResult); + bResult = ::LineTo(hdc,rc.right-1,rc.bottom-1); + assert(TRUE == bResult); + + ::SelectObject(hdc,hPenOld); + bResult = ::DeleteObject(hPen); + assert(TRUE == bResult); + } + + void DrawPoints(HDC hdc,RECT& rc)const + { + TXValue xMin(m_aValues[0].first); + double dx = TXConverter::Convert(m_aValues[m_aValues.size()-1].first-xMin); + double dY = TYConverter::Convert(m_MaxY-m_MinY); + + HPEN hPen = ::CreatePen(PS_SOLID,1,RGB(255,0,0)); + HGDIOBJ hPenOld = ::SelectObject(hdc,hPen); + + HBRUSH hBrush = ::CreateSolidBrush(RGB(255,0,0)); + HGDIOBJ hBrushOld = ::SelectObject(hdc,hBrush); + + bool bPrevValid = false; + int xPrex,yPrev; + + BOOST_FOREACH(const TValue& v,m_aValues) + { + double k = TXConverter::Convert(v.first-xMin); + + int x = rc.left+boost::numeric_cast<int>((rc.right-rc.left)*(k/dx)); + k = TYConverter::Convert(v.second-m_MinY); + int y = rc.bottom-boost::numeric_cast<int>((rc.bottom-rc.top)*(k/dY)); + ::Ellipse(hdc,x-5,y-5,x+5,y+5); + if(bPrevValid) + { + BOOL bResult = ::MoveToEx(hdc,xPrex,yPrev,NULL); + assert(TRUE == bResult); + bResult = ::LineTo(hdc,x,y); + assert(TRUE == bResult); + } + + xPrex = x,yPrev = y; + bPrevValid = true; + } + + ::SelectObject(hdc,hPenOld); + BOOL bResult = ::DeleteObject(hPen); + assert(TRUE == bResult); + + ::SelectObject(hdc,hBrushOld); + bResult = ::DeleteObject(hBrush); + assert(TRUE == bResult); + } + +private: + TValues m_aValues; + RECT m_rect; + TYValue m_MaxY; + TYValue m_MinY; +}; + +#endif // __FAE7F26E_61ED_4951_BE87_5E022CDF21DF_Chart_h__ diff --git a/protocols/Quotes/ComHelper.cpp b/protocols/Quotes/ComHelper.cpp new file mode 100644 index 0000000000..e15d05d739 --- /dev/null +++ b/protocols/Quotes/ComHelper.cpp @@ -0,0 +1,39 @@ +#include "StdAfx.h" +#include "ComHelper.h" +#include "Log.h" +#include "WinCtrlHelper.h" + +tstring ComException2Msg(_com_error& e,const tstring& rsAdditionalInfo) +{ + HRESULT hError = e.Error(); + tostringstream o; + if(false == rsAdditionalInfo.empty()) + { + o << rsAdditionalInfo << "\n"; + } + + o << e.ErrorMessage() << _T(" (") << std::hex << hError << _T(")"); + + IErrorInfo* p = e.ErrorInfo(); + CComPtr<IErrorInfo> pErrorInfo(p); + if(NULL != p) + { + p->Release(); + } + + if(pErrorInfo) + { + o << _T("\n") << e.Description(); + } + + return o.str(); +} + +void ShowComError(_com_error& e,const tstring& rsAdditionalInfo) +{ + tstring sErrorMsg = ComException2Msg(e,rsAdditionalInfo); + LogIt(Error,sErrorMsg); + Quotes_MessageBox(NULL,sErrorMsg.c_str(),MB_OK|MB_ICONERROR); +} + + diff --git a/protocols/Quotes/ComHelper.h b/protocols/Quotes/ComHelper.h new file mode 100644 index 0000000000..0b4140d80d --- /dev/null +++ b/protocols/Quotes/ComHelper.h @@ -0,0 +1,9 @@ +#ifndef __37ae28ab_c414_4aba_bbef_d23dd68643a5_ComHelper_h__ +#define __37ae28ab_c414_4aba_bbef_d23dd68643a5_ComHelper_h__ + +#include <string> + +void ShowComError(_com_error& e,const tstring& rsAdditionalInfo); +tstring ComException2Msg(_com_error& e,const tstring& rsAdditionalInfo); + +#endif//__37ae28ab_c414_4aba_bbef_d23dd68643a5_ComHelper_h__ diff --git a/protocols/Quotes/CommonOptionDlg.cpp b/protocols/Quotes/CommonOptionDlg.cpp new file mode 100644 index 0000000000..0b460665c5 --- /dev/null +++ b/protocols/Quotes/CommonOptionDlg.cpp @@ -0,0 +1,272 @@ +#include "StdAfx.h" +#include "CommonOptionDlg.h" +#include "QuotesProviderBase.h" +#include "resource.h" +#include "EconomicRateInfo.h" +#include "DBUtils.h" +#include "QuotesProviderVisitorDbSettings.h" +#include "WinCtrlHelper.h" +#include "SettingsDlg.h" + +namespace +{ + typedef boost::shared_ptr<CAdvProviderSettings> TAdvSettingsPtr; + typedef std::map<const IQuotesProvider*,TAdvSettingsPtr> TAdvSettings; + + TAdvSettings g_aAdvSettings; + + CAdvProviderSettings* get_adv_settings(const IQuotesProvider* pProvider,bool bCreateIfNonExist) + { + TAdvSettings::iterator i = g_aAdvSettings.find(pProvider); + if(i != g_aAdvSettings.end()) + { + return i->second.get(); + } + else if(true == bCreateIfNonExist) + { + TAdvSettingsPtr pAdvSet(new CAdvProviderSettings(pProvider)); + g_aAdvSettings.insert(std::make_pair(pProvider,pAdvSet)); + return pAdvSet.get(); + } + else + { + return NULL; + } + } + + void remove_adv_settings(const IQuotesProvider* pProvider) + { + TAdvSettings::iterator i = g_aAdvSettings.find(pProvider); + if(i != g_aAdvSettings.end()) + { + g_aAdvSettings.erase(i); + } + } +} + +void CommonOptionDlgProc(HWND hWnd,UINT msg,WPARAM wp,LPARAM lp,CCommonDlgProcData& rData) +{ + switch(msg) + { + case WM_INITDIALOG: + { + assert(rData.m_pQuotesProvider); + + CQuotesProviderVisitorDbSettings visitor; + rData.m_pQuotesProvider->Accept(visitor); + assert(visitor.m_pszDbRefreshRateType); + assert(visitor.m_pszDbRefreshRateValue); + assert(visitor.m_pszDbDisplayNameFormat); + assert(visitor.m_pszDbStatusMsgFormat); + assert(visitor.m_pszDbTendencyFormat); + + // set contact list display format + tstring sDspNameFrmt = Quotes_DBGetStringT(NULL,QUOTES_MODULE_NAME,visitor.m_pszDbDisplayNameFormat,visitor.m_pszDefDisplayFormat); + ::SetDlgItemText(hWnd,IDC_EDIT_CONTACT_LIST_FORMAT,sDspNameFrmt.c_str()); + + // set status message display format + tstring sStatusMsgFrmt = Quotes_DBGetStringT(NULL,QUOTES_MODULE_NAME,visitor.m_pszDbStatusMsgFormat,visitor.m_pszDefStatusMsgFormat); + ::SetDlgItemText(hWnd,IDC_EDIT_STATUS_MESSAGE_FORMAT,sStatusMsgFrmt.c_str()); + + // set tendency format + tstring sTendencyFrmt = Quotes_DBGetStringT(NULL,QUOTES_MODULE_NAME,visitor.m_pszDbTendencyFormat,visitor.m_pszDefTendencyFormat); + ::SetDlgItemText(hWnd,IDC_EDIT_TENDENCY_FORMAT,sTendencyFrmt.c_str()); + + // refresh rate + HWND hwndCombo = ::GetDlgItem(hWnd,IDC_COMBO_REFRESH_RATE); + LPCTSTR pszRefreshRateTypes[] = {TranslateT("Seconds"),TranslateT("Minutes"),TranslateT("Hours")}; + for(int i = 0;i < SIZEOF(pszRefreshRateTypes);++i) + { + ::SendMessage(hwndCombo,CB_ADDSTRING,0,reinterpret_cast<LPARAM>(pszRefreshRateTypes[i])); + } + + int nRefreshRateType = DBGetContactSettingWord(NULL,QUOTES_MODULE_NAME,visitor.m_pszDbRefreshRateType,RRT_MINUTES); + if(nRefreshRateType < RRT_SECONDS || nRefreshRateType > RRT_HOURS) + { + nRefreshRateType = RRT_MINUTES; + } + + UINT nRate = DBGetContactSettingWord(NULL,QUOTES_MODULE_NAME,visitor.m_pszDbRefreshRateValue,1); + switch(nRefreshRateType) + { + default: + case RRT_SECONDS: + case RRT_MINUTES: + if(nRate < 1 || nRate > 60) + { + nRate = 1; + } + spin_set_range(::GetDlgItem(hWnd,IDC_SPIN_REFRESH_RATE),1,60); + break; + case RRT_HOURS: + if(nRate < 1 || nRate > 24) + { + nRate = 1; + } + spin_set_range(::GetDlgItem(hWnd,IDC_SPIN_REFRESH_RATE),1,24); + break; + } + + ::SendMessage(hwndCombo,CB_SETCURSEL,nRefreshRateType,0); + ::SetDlgItemInt(hWnd,IDC_EDIT_REFRESH_RATE,nRate,FALSE); + + PropSheet_UnChanged(::GetParent(hWnd),hWnd); + } + break; + case WM_COMMAND: + switch(HIWORD(wp)) + { + case CBN_SELCHANGE: + if(IDC_COMBO_REFRESH_RATE == LOWORD(wp)) + { + ERefreshRateType nType = static_cast<ERefreshRateType>(::SendMessage(reinterpret_cast<HWND>(lp),CB_GETCURSEL,0,0)); + switch(nType) + { + default: + case RRT_SECONDS: + case RRT_MINUTES: + spin_set_range(::GetDlgItem(hWnd,IDC_SPIN_REFRESH_RATE),1,60); + break; + case RRT_HOURS: + { + spin_set_range(::GetDlgItem(hWnd,IDC_SPIN_REFRESH_RATE),1,24); + BOOL bOk = FALSE; + UINT nRefreshRate = ::GetDlgItemInt(hWnd,IDC_EDIT_REFRESH_RATE,&bOk,FALSE); + if(TRUE == bOk && nRefreshRate > 24) + { + ::SetDlgItemInt(hWnd,IDC_EDIT_REFRESH_RATE,24,FALSE); + } + } + break; + } + + PropSheet_Changed(::GetParent(hWnd),hWnd); + } + break; + case EN_CHANGE: + switch(LOWORD(wp)) + { + case IDC_EDIT_REFRESH_RATE: + case IDC_EDIT_CONTACT_LIST_FORMAT: + case IDC_EDIT_STATUS_MESSAGE_FORMAT: + case IDC_EDIT_TENDENCY_FORMAT: + if(reinterpret_cast<HWND>(lp) == ::GetFocus()) + { + PropSheet_Changed(::GetParent(hWnd),hWnd); + } + break; + } + break; + case BN_CLICKED: + switch( LOWORD(wp)) + { + case IDC_BUTTON_DESCRIPTION: + show_variable_list(hWnd,rData.m_pQuotesProvider); + break; + case IDC_BUTTON_ADVANCED_SETTINGS: + { + CAdvProviderSettings* pAdvSet = get_adv_settings(rData.m_pQuotesProvider,true); + assert(pAdvSet); + if(true == ShowSettingsDlg(hWnd,pAdvSet)) + { + PropSheet_Changed(::GetParent(hWnd),hWnd); + } + } + break; + } + break; + } + break; + case WM_NOTIFY: + { + LPNMHDR pNMHDR = reinterpret_cast<LPNMHDR>(lp); + switch(pNMHDR->code) + { + case PSN_KILLACTIVE: + { + BOOL bOk = FALSE; + UINT nRefreshRate = ::GetDlgItemInt(hWnd,IDC_EDIT_REFRESH_RATE,&bOk,FALSE); + ERefreshRateType nType = static_cast<ERefreshRateType>(::SendMessage(::GetDlgItem(hWnd,IDC_COMBO_REFRESH_RATE),CB_GETCURSEL,0,0)); + switch(nType) + { + default: + case RRT_MINUTES: + case RRT_SECONDS: + if(FALSE == bOk || nRefreshRate < 1 || nRefreshRate > 60) + { + prepare_edit_ctrl_for_error(::GetDlgItem(hWnd,IDC_EDIT_REFRESH_RATE)); + Quotes_MessageBox(hWnd,TranslateT("Enter integer value between 1 and 60."),MB_OK|MB_ICONERROR); + bOk = FALSE; + } + break; + case RRT_HOURS: + if(FALSE == bOk || nRefreshRate < 1 || nRefreshRate > 24) + { + prepare_edit_ctrl_for_error(::GetDlgItem(hWnd,IDC_EDIT_REFRESH_RATE)); + Quotes_MessageBox(hWnd,TranslateT("Enter integer value between 1 and 24."),MB_OK|MB_ICONERROR); + bOk = FALSE; + } + break; + } + + if(TRUE == bOk) + { + HWND hEdit = ::GetDlgItem(hWnd,IDC_EDIT_CONTACT_LIST_FORMAT); + assert(IsWindow(hEdit)); + + tstring s = get_window_text(hEdit); + if(true == s.empty()) + { + prepare_edit_ctrl_for_error(hEdit); + Quotes_MessageBox(hWnd,TranslateT("Enter text to display in contact list."),MB_OK|MB_ICONERROR); + bOk = FALSE; + } + } + + ::SetWindowLongPtr(hWnd,DWLP_MSGRESULT,(TRUE == bOk) ? FALSE : TRUE); + } + break; + case PSN_APPLY: + { + BOOL bOk = FALSE; + UINT nRefreshRate = ::GetDlgItemInt(hWnd,IDC_EDIT_REFRESH_RATE,&bOk,FALSE); + assert(TRUE == bOk); + ERefreshRateType nType = static_cast<ERefreshRateType>(::SendMessage(::GetDlgItem(hWnd,IDC_COMBO_REFRESH_RATE),CB_GETCURSEL,0,0)); + + assert(rData.m_pQuotesProvider); + + CQuotesProviderVisitorDbSettings visitor; + rData.m_pQuotesProvider->Accept(visitor); + assert(visitor.m_pszDbRefreshRateType); + assert(visitor.m_pszDbRefreshRateValue); + assert(visitor.m_pszDbDisplayNameFormat); + assert(visitor.m_pszDbStatusMsgFormat); + + rData.m_bFireSetingsChangedEvent = true; + DBWriteContactSettingWord(NULL,QUOTES_MODULE_NAME,visitor.m_pszDbRefreshRateType,nType); + DBWriteContactSettingWord(NULL,QUOTES_MODULE_NAME,visitor.m_pszDbRefreshRateValue,nRefreshRate); + + tstring s = get_window_text(::GetDlgItem(hWnd,IDC_EDIT_CONTACT_LIST_FORMAT)); + DBWriteContactSettingTString(NULL,QUOTES_MODULE_NAME,visitor.m_pszDbDisplayNameFormat,s.c_str()); + + s = get_window_text(::GetDlgItem(hWnd,IDC_EDIT_STATUS_MESSAGE_FORMAT)); + DBWriteContactSettingTString(NULL,QUOTES_MODULE_NAME,visitor.m_pszDbStatusMsgFormat,s.c_str()); + + s = get_window_text(::GetDlgItem(hWnd,IDC_EDIT_TENDENCY_FORMAT)); + DBWriteContactSettingTString(NULL,QUOTES_MODULE_NAME,visitor.m_pszDbTendencyFormat,s.c_str()); + + CAdvProviderSettings* pAdvSet = get_adv_settings(rData.m_pQuotesProvider,false); + if(pAdvSet) + { + pAdvSet->SaveToDb(); + } + } + break; + } + } + break; + case WM_DESTROY: + remove_adv_settings(rData.m_pQuotesProvider); + break; + } +} \ No newline at end of file diff --git a/protocols/Quotes/CommonOptionDlg.h b/protocols/Quotes/CommonOptionDlg.h new file mode 100644 index 0000000000..b9f696362a --- /dev/null +++ b/protocols/Quotes/CommonOptionDlg.h @@ -0,0 +1,17 @@ +#ifndef __c85fe710_f71b_4a58_9d44_3e39f6209c5f_CommonOptionDlg_h__ +#define __c85fe710_f71b_4a58_9d44_3e39f6209c5f_CommonOptionDlg_h__ + +class CQuotesProviderBase; + +struct CCommonDlgProcData +{ + CCommonDlgProcData(const CQuotesProviderBase* pQuotesProvider) + : m_pQuotesProvider(pQuotesProvider),m_bFireSetingsChangedEvent(false){} + + const CQuotesProviderBase* m_pQuotesProvider; + bool m_bFireSetingsChangedEvent; +}; + +void CommonOptionDlgProc(HWND hWnd,UINT msg,WPARAM wp,LPARAM lp,CCommonDlgProcData& rData); + +#endif//__c85fe710_f71b_4a58_9d44_3e39f6209c5f_CommonOptionDlg_h__ diff --git a/protocols/Quotes/CreateFilePath.cpp b/protocols/Quotes/CreateFilePath.cpp new file mode 100644 index 0000000000..f1a3e4f331 --- /dev/null +++ b/protocols/Quotes/CreateFilePath.cpp @@ -0,0 +1,45 @@ +#include "StdAfx.h" +#include "CreateFilePath.h" + +#include <sstream> +#include "ModuleInfo.h" + +namespace +{ + TCHAR replace_invalid_symbol(TCHAR chr) + { + TCHAR InvaliSymbols[] = {_T('\\'),_T('/'),_T(':'),_T('*'),_T('?'),_T('"'),_T('<'),_T('>'),_T('|')}; + for(int i = 0; i < sizeof(InvaliSymbols)/sizeof(InvaliSymbols[0]);++i) + { + if(chr == InvaliSymbols[i]) + { + return _T('_'); + } + } + + return chr; + } + + void prepare_name(tstring& rsName) + { + std::transform(rsName.begin(),rsName.end(),rsName.begin(),boost::bind(replace_invalid_symbol,_1)); + } +} + +tstring CreateFilePath(const tstring& rsName) +{ + TCHAR szPath[_MAX_PATH]; + ::GetModuleFileName(CModuleInfo::GetModuleHandle(),szPath,_MAX_PATH); + + TCHAR* p = _tcsrchr(szPath,_T('\\')); + if(p) + { + *p = 0; + } + + tstring s(rsName); + prepare_name(s); + tostringstream o; + o << szPath << _T("\\Quotes\\") << s; + return o.str(); +} \ No newline at end of file diff --git a/protocols/Quotes/CreateFilePath.h b/protocols/Quotes/CreateFilePath.h new file mode 100644 index 0000000000..f097e59a52 --- /dev/null +++ b/protocols/Quotes/CreateFilePath.h @@ -0,0 +1,8 @@ +#ifndef _aaf3bee6_cee7_4023_8848_5911ad7a9660_CreateFilePath_h__ +#define _aaf3bee6_cee7_4023_8848_5911ad7a9660_CreateFilePath_h__ + +#include <string> + +tstring CreateFilePath(const tstring& rsName); + +#endif //_aaf3bee6_cee7_4023_8848_5911ad7a9660_CreateFilePath_h__ diff --git a/protocols/Quotes/CurrencyConverter.cpp b/protocols/Quotes/CurrencyConverter.cpp new file mode 100644 index 0000000000..0e04d2562e --- /dev/null +++ b/protocols/Quotes/CurrencyConverter.cpp @@ -0,0 +1,309 @@ +#include "StdAfx.h" +#include "CurrencyConverter.h" +#include "ModuleInfo.h" +#include "resource.h" + +#include "QuotesProviderGoogle.h" +#include "QuotesProviders.h" +#include "WinCtrlHelper.h" +#include "EconomicRateInfo.h" +#include "Locale.h" +#include "DBUtils.h" +#include "IconLib.h" + +#define WINDOW_PREFIX "CurrenyConverter_" + +#define DB_STR_CC_QUOTE_FROM_ID "CurrencyConverter_FromID" +#define DB_STR_CC_QUOTE_TO_ID "CurrencyConverter_ToID" +#define DB_STR_CC_AMOUNT "CurrencyConverter_Amount" + +namespace +{ + CQuotesProviderGoogle* get_google_provider() + { + CModuleInfo::TQuotesProvidersPtr& pProviders = CModuleInfo::GetQuoteProvidersPtr(); + const CQuotesProviders::TQuotesProviders& rapQuotesProviders = pProviders->GetProviders(); + for(CQuotesProviders::TQuotesProviders::const_iterator i = rapQuotesProviders.begin();i != rapQuotesProviders.end();++i) + { + const CQuotesProviders::TQuotesProviderPtr& pProvider = *i; + CQuotesProviderGoogle* pGoogle = dynamic_cast<CQuotesProviderGoogle*>(pProvider.get()); + if(pGoogle) + { + return pGoogle; + } + } + + assert(!"We should never get here!"); + return NULL; + } + + + CQuotesProviderGoogle::CQuoteSection get_quotes(const CQuotesProviderGoogle* pProvider = NULL) + { + if(NULL == pProvider) + { + pProvider = get_google_provider(); + } + + if(pProvider) + { + const CQuotesProviderGoogle::CQuoteSection& rQuotes = pProvider->GetQuotes(); + if(rQuotes.GetSectionCount() > 0) + { + return rQuotes.GetSection(0); + } + } + + return CQuotesProviderGoogle::CQuoteSection(); + } + + inline tstring make_quote_name(const CQuotesProviderGoogle::CQuote& rQuote) + { + const tstring& rsDesc = rQuote.GetName(); + return((false == rsDesc.empty()) ? rsDesc : rQuote.GetSymbol()); + } + + inline void update_convert_button(HWND hDlg) + { + int nFrom = static_cast<int>(::SendMessage(::GetDlgItem(hDlg,IDC_COMBO_CONVERT_FROM),CB_GETCURSEL,0,0)); + int nTo = static_cast<int>(::SendMessage(::GetDlgItem(hDlg,IDC_COMBO_CONVERT_INTO),CB_GETCURSEL,0,0)); + bool bEnableButton = ((CB_ERR != nFrom) + && (CB_ERR != nTo) + && (nFrom != nTo) + && (GetWindowTextLength(GetDlgItem(hDlg,IDC_EDIT_VALUE)) > 0)); + EnableWindow(GetDlgItem(hDlg,IDC_BUTTON_CONVERT),bEnableButton); + } + + inline void update_swap_button(HWND hDlg) + { + int nFrom = static_cast<int>(::SendMessage(::GetDlgItem(hDlg,IDC_COMBO_CONVERT_FROM),CB_GETCURSEL,0,0)); + int nTo = static_cast<int>(::SendMessage(::GetDlgItem(hDlg,IDC_COMBO_CONVERT_INTO),CB_GETCURSEL,0,0)); + bool bEnableButton = ((CB_ERR != nFrom) + && (CB_ERR != nTo) + && (nFrom != nTo)); + EnableWindow(GetDlgItem(hDlg,IDC_BUTTON_SWAP),bEnableButton); + } + + inline tstring double2str(double dValue) + { + tostringstream output; + output.imbue(GetSystemLocale()); + output << std::fixed << std::setprecision(2) << dValue; + return output.str(); + } + + inline bool str2double(const tstring& s,double& d) + { + tistringstream input(s); + input.imbue(GetSystemLocale()); + input >> d; + return ((false == input.bad()) && (false == input.fail())); + } + + + INT_PTR CALLBACK CurrencyConverterDlgProc(HWND hDlg,UINT msg,WPARAM wp,LPARAM lp) + { + switch(msg) + { + case WM_INITDIALOG: + { + HANDLE hWL = CModuleInfo::GetInstance().GetWindowList(WINDOW_PREFIX,false); + assert(hWL); + WindowList_Add(hWL,hDlg,NULL); + + TranslateDialogDefault(hDlg); + + ::SendMessage(hDlg,WM_SETICON,FALSE,reinterpret_cast<LPARAM>(Quotes_LoadIconEx(ICON_STR_CURRENCY_CONVERTER))); + ::SendMessage(hDlg,WM_SETICON,TRUE,reinterpret_cast<LPARAM>(Quotes_LoadIconEx(ICON_STR_CURRENCY_CONVERTER,true))); + + HWND hcbxFrom = ::GetDlgItem(hDlg,IDC_COMBO_CONVERT_FROM); + HWND hcbxTo = ::GetDlgItem(hDlg,IDC_COMBO_CONVERT_INTO); + + tstring sFromQuoteID = Quotes_DBGetStringT(NULL,QUOTES_MODULE_NAME,DB_STR_CC_QUOTE_FROM_ID); + tstring sToQuoteID = Quotes_DBGetStringT(NULL,QUOTES_MODULE_NAME,DB_STR_CC_QUOTE_TO_ID); + + const CQuotesProviderGoogle* pProvider = get_google_provider(); + const CQuotesProviderGoogle::CQuoteSection& rSection = get_quotes(pProvider); + size_t cQuotes = rSection.GetQuoteCount(); + for(size_t i = 0;i < cQuotes;++i) + { + const CQuotesProviderGoogle::CQuote& rQuote = rSection.GetQuote(i); + tstring sName = make_quote_name(rQuote); + LPCTSTR pszName = sName.c_str(); + LRESULT nFrom = ::SendMessage(hcbxFrom,CB_ADDSTRING,0,reinterpret_cast<LPARAM>(pszName)); + LRESULT nTo = ::SendMessage(hcbxTo,CB_ADDSTRING,0,reinterpret_cast<LPARAM>(pszName)); + + if(0 == quotes_stricmp(rQuote.GetID().c_str(),sFromQuoteID.c_str())) + { + ::SendMessage(hcbxFrom,CB_SETCURSEL,nFrom,0); + } + + if(0 == quotes_stricmp(rQuote.GetID().c_str(),sToQuoteID.c_str())) + { + ::SendMessage(hcbxTo,CB_SETCURSEL,nTo,0); + } + } + + double dAmount = 1.0; + Quotes_DBReadDouble(NULL,QUOTES_MODULE_NAME,DB_STR_CC_AMOUNT,dAmount); + ::SetDlgItemText(hDlg,IDC_EDIT_VALUE,double2str(dAmount).c_str()); + + const IQuotesProvider::CProviderInfo& pi = pProvider->GetInfo(); + tostringstream o; + o << TranslateT("Info provided by") << _T(" <a href=\"") << pi.m_sURL << _T("\">") << pi.m_sName << _T("</a>"); + + ::SetDlgItemText(hDlg,IDC_SYSLINK_PROVIDER,o.str().c_str()); + + ::SendMessage(::GetDlgItem(hDlg,IDC_BUTTON_SWAP),BM_SETIMAGE,IMAGE_ICON, + reinterpret_cast<LPARAM>(Quotes_LoadIconEx(ICON_STR_SWAP))); + + update_convert_button(hDlg); + update_swap_button(hDlg); + + Utils_RestoreWindowPositionNoSize(hDlg,NULL,QUOTES_PROTOCOL_NAME,WINDOW_PREFIX); + ::ShowWindow(hDlg,SW_SHOW); + } + return (TRUE); + case WM_CLOSE: + { + HANDLE hWL = CModuleInfo::GetInstance().GetWindowList(WINDOW_PREFIX,false); + assert(hWL); + WindowList_Remove(hWL,hDlg); + Utils_SaveWindowPosition(hDlg,NULL,QUOTES_PROTOCOL_NAME,WINDOW_PREFIX); + EndDialog(hDlg,0); + } + return (TRUE); + case WM_COMMAND: + switch(LOWORD(wp)) + { + case IDC_COMBO_CONVERT_FROM: + case IDC_COMBO_CONVERT_INTO: + if(CBN_SELCHANGE == HIWORD(wp)) + { + update_convert_button(hDlg); + update_swap_button(hDlg); + } + return TRUE; + case IDC_EDIT_VALUE: + if(EN_CHANGE == HIWORD(wp)) + { + update_convert_button(hDlg); + } + return TRUE; + case IDCANCEL: + { + SendMessage(hDlg, WM_CLOSE, 0, 0); + } + return (TRUE); + case IDC_BUTTON_SWAP: + { + HWND wndFrom = ::GetDlgItem(hDlg,IDC_COMBO_CONVERT_FROM); + HWND wndTo = ::GetDlgItem(hDlg,IDC_COMBO_CONVERT_INTO); + WPARAM nFrom = ::SendMessage(wndFrom,CB_GETCURSEL,0,0); + WPARAM nTo = ::SendMessage(wndTo,CB_GETCURSEL,0,0); + + ::SendMessage(wndFrom,CB_SETCURSEL,nTo,0); + ::SendMessage(wndTo,CB_SETCURSEL,nFrom,0); + } + return (TRUE); + case IDC_BUTTON_CONVERT: + { + HWND hwndAmount = GetDlgItem(hDlg,IDC_EDIT_VALUE); + tstring sText = get_window_text(hwndAmount); + + double dAmount = 1.0; + if ((true == str2double(sText,dAmount)) && (dAmount > 0.0)) + { + Quotes_DBWriteDouble(NULL,QUOTES_MODULE_NAME,DB_STR_CC_AMOUNT,dAmount); + + size_t nFrom = static_cast<size_t>(::SendMessage(::GetDlgItem(hDlg,IDC_COMBO_CONVERT_FROM),CB_GETCURSEL,0,0)); + size_t nTo = static_cast<size_t>(::SendMessage(::GetDlgItem(hDlg,IDC_COMBO_CONVERT_INTO),CB_GETCURSEL,0,0)); + if ((CB_ERR != nFrom) && (CB_ERR != nTo) && (nFrom != nTo)) + { + const CQuotesProviderGoogle::CQuoteSection& rSection = get_quotes(); + size_t cQuotes = rSection.GetQuoteCount(); + if ((nFrom < cQuotes) && (nTo < cQuotes)) + { + CQuotesProviderGoogle::CRateInfo ri; + CQuotesProviderGoogle::CQuote from = rSection.GetQuote(nFrom); + CQuotesProviderGoogle::CQuote to = rSection.GetQuote(nTo); + + DBWriteContactSettingTString(NULL,QUOTES_MODULE_NAME,DB_STR_CC_QUOTE_FROM_ID,from.GetID().c_str()); + DBWriteContactSettingTString(NULL,QUOTES_MODULE_NAME,DB_STR_CC_QUOTE_TO_ID,to.GetID().c_str()); + + const CQuotesProviderGoogle* pProvider = get_google_provider(); + assert(pProvider); + if(pProvider) + { + tstring sResult; + std::string sError; + try + { + double dResult = pProvider->Convert(dAmount,from,to); + tostringstream ss; + ss.imbue(GetSystemLocale()); + ss << std::fixed << std::setprecision(2) << dAmount << " " << from.GetName() << " = " << dResult << " " << to.GetName(); + sResult = ss.str(); + } + catch(std::exception& e) + { + sError = e.what(); + //Quotes_MessageBox(hDlg,sResult.c_str()); + } + + if(false == sError.empty()) + { + //USES_CONVERSION; + sResult = quotes_a2t(sError.c_str());//A2T(sError.c_str()); + } + + SetDlgItemText(hDlg,IDC_EDIT_RESULT,sResult.c_str()); + } + } + } + } + else + { + Quotes_MessageBox(hDlg,TranslateT("Enter positive number."),MB_OK|MB_ICONERROR); + prepare_edit_ctrl_for_error(GetDlgItem(hDlg,IDC_EDIT_VALUE)); + } + } + return (TRUE); + } + return (FALSE); + case WM_NOTIFY: + { + LPNMHDR pNMHDR = reinterpret_cast<LPNMHDR>(lp); + switch(pNMHDR->code) + { + case NM_CLICK: + if(IDC_SYSLINK_PROVIDER == wp) + { + PNMLINK pNMLink = reinterpret_cast<PNMLINK>(pNMHDR); + ::ShellExecute(hDlg,_T("open"),pNMLink->item.szUrl,NULL,NULL,SW_SHOWNORMAL); + } + break; + } + } + break; + } + return (FALSE); + } +} + +INT_PTR QuotesMenu_CurrencyConverter(WPARAM wp,LPARAM lp) +{ + HANDLE hWL = CModuleInfo::GetInstance().GetWindowList(WINDOW_PREFIX,true); + HWND hWnd = WindowList_Find(hWL,NULL); + if(NULL != hWnd) + { + SetForegroundWindow(hWnd); + SetFocus(hWnd); + } + else + { + CreateDialogParam(CModuleInfo::GetModuleHandle(), MAKEINTRESOURCE(IDD_CURRENCY_CONVERTER), NULL, CurrencyConverterDlgProc, 0); + } + + return 0; +} diff --git a/protocols/Quotes/CurrencyConverter.h b/protocols/Quotes/CurrencyConverter.h new file mode 100644 index 0000000000..9af7c6bca1 --- /dev/null +++ b/protocols/Quotes/CurrencyConverter.h @@ -0,0 +1,6 @@ +#ifndef __4FB6320B_2D02_408b_BAF5_426C185AAA11_CurrencyConverter_h__ +#define __4FB6320B_2D02_408b_BAF5_426C185AAA11_CurrencyConverter_h__ + +INT_PTR QuotesMenu_CurrencyConverter(WPARAM wp,LPARAM lp); + +#endif //__4FB6320B_2D02_408b_BAF5_426C185AAA11_CurrencyConverter_h__ diff --git a/protocols/Quotes/DBUtils.cpp b/protocols/Quotes/DBUtils.cpp new file mode 100644 index 0000000000..11c0fb3d0d --- /dev/null +++ b/protocols/Quotes/DBUtils.cpp @@ -0,0 +1,70 @@ +#include "StdAfx.h" +#include "DBUtils.h" + +std::string Quotes_DBGetStringA(HANDLE hContact,const char* szModule,const char* szSetting,const char* pszDefValue /*= NULL*/) +{ + std::string sResult; + char* pszSymbol = DBGetString(hContact,szModule,szSetting); + if(NULL != pszSymbol) + { + sResult = pszSymbol; + mir_free(pszSymbol); + } + else if(NULL != pszDefValue) + { + sResult = pszDefValue; + } + + return sResult; +} + +std::wstring Quotes_DBGetStringW(HANDLE hContact,const char* szModule,const char* szSetting,const wchar_t* pszDefValue/* = NULL*/) +{ + std::wstring sResult; + wchar_t* pszSymbol = DBGetStringW(hContact,szModule,szSetting); + if(NULL != pszSymbol) + { + sResult = pszSymbol; + mir_free(pszSymbol); + } + else if(NULL != pszDefValue) + { + sResult = pszDefValue; + } + + return sResult; +} + +bool Quotes_DBWriteDouble(HANDLE hContact,const char* szModule,const char* szSetting,double dValue) +{ + DBCONTACTWRITESETTING cws = {0}; + + cws.szModule = szModule; + cws.szSetting = szSetting; + cws.value.type = DBVT_BLOB; + cws.value.cpbVal = sizeof(dValue); + cws.value.pbVal = reinterpret_cast<BYTE*>(&dValue); + return 0 == CallService(MS_DB_CONTACT_WRITESETTING,reinterpret_cast<WPARAM>(hContact),reinterpret_cast<LPARAM>(&cws)); +} + +bool Quotes_DBReadDouble(HANDLE hContact,const char* szModule,const char* szSetting,double& rdValue) +{ + DBVARIANT dbv = {0}; + DBCONTACTGETSETTING cgs; + cgs.szModule=szModule; + cgs.szSetting=szSetting; + cgs.pValue = &dbv; + dbv.type = DBVT_BLOB; + + bool bResult = ((0 == CallService(MS_DB_CONTACT_GETSETTING,(WPARAM)hContact,(LPARAM)&cgs)) + && (DBVT_BLOB == dbv.type)); + + if(bResult) + { + rdValue = *reinterpret_cast<double*>(dbv.pbVal); + } + + DBFreeVariant(&dbv); + return bResult; +} + diff --git a/protocols/Quotes/DBUtils.h b/protocols/Quotes/DBUtils.h new file mode 100644 index 0000000000..d154e99075 --- /dev/null +++ b/protocols/Quotes/DBUtils.h @@ -0,0 +1,16 @@ +#ifndef __54294385_3fdd_4f0c_98c3_c583a96e7fb4_DBUtils_h__ +#define __54294385_3fdd_4f0c_98c3_c583a96e7fb4_DBUtils_h__ + +std::string Quotes_DBGetStringA(HANDLE hContact,const char* szModule,const char* szSetting,const char* pszDefValue = NULL); +std::wstring Quotes_DBGetStringW(HANDLE hContact,const char* szModule,const char* szSetting,const wchar_t* pszDefValue = NULL); + +#ifdef _UNICODE +#define Quotes_DBGetStringT Quotes_DBGetStringW +#else +#define Quotes_DBGetStringT Quotes_DBGetStringA +#endif + +bool Quotes_DBWriteDouble(HANDLE hContact,const char* szModule,const char* szSetting,double dValue); +bool Quotes_DBReadDouble(HANDLE hContact,const char* szModule,const char* szSetting,double& rdValue); + +#endif //__54294385_3fdd_4f0c_98c3_c583a96e7fb4_DBUtils_h__ diff --git a/protocols/Quotes/EconomicRateInfo.h b/protocols/Quotes/EconomicRateInfo.h new file mode 100644 index 0000000000..73e269619c --- /dev/null +++ b/protocols/Quotes/EconomicRateInfo.h @@ -0,0 +1,59 @@ +#ifndef __87d726e0_26c6_485d_8016_1fba819b037d_EconomicRateInfo__ +#define __87d726e0_26c6_485d_8016_1fba819b037d_EconomicRateInfo__ + +#define QUOTES_PROTOCOL_NAME "Quotes"// protocol name + +#define QUOTES_MODULE_NAME QUOTES_PROTOCOL_NAME // db settings module path + +enum ERefreshRateType +{ + RRT_SECONDS = 0, + RRT_MINUTES = 1, + RRT_HOURS = 2 +}; + +#define DB_STR_ENABLE_LOG "EnableLog" +#define DB_STR_QUOTE_PROVIDER "QuoteProvider" +#define DB_STR_QUOTE_ID "QuoteID" +#define DB_STR_QUOTE_SYMBOL "QuoteSymbol" +#define DB_STR_QUOTE_DESCRIPTION "QuoteDescription" +#define DB_STR_QUOTE_PREV_VALUE "PreviousQuoteValue" +#define DB_STR_QUOTE_CURR_VALUE "CurrentQuoteValue" +#define DB_STR_QUOTE_FETCH_TIME "FetchTime" + + +enum ELogMode +{ + lmDisabled = 0x0000, + lmInternalHistory = 0x0001, + lmExternalFile = 0x0002, + lmPopup = 0x0004, +}; + +#define DB_STR_CONTACT_SPEC_SETTINGS "ContactSpecSettings" +#define DB_STR_QUOTE_LOG "Log" +#define DB_STR_QUOTE_LOG_FILE "LogFile" +#define DB_STR_QUOTE_FORMAT_LOG_FILE "LogFileFormat" +#define DB_STR_QUOTE_FORMAT_HISTORY "HistoryFormat" +#define DB_STR_QUOTE_LOG_FILE_CONDITION "AddToLogOnlyIfValueIsChanged" +#define DB_STR_QUOTE_HISTORY_CONDITION "AddToHistoryOnlyIfValueIsChanged" +#define DB_STR_QUOTE_EXTRA_IMAGE_SLOT "ExtraImageSlot" +#define DB_STR_QUOTE_FORMAT_POPUP "PopupFormat" +#define DB_STR_QUOTE_POPUP_CONDITION "ShowPopupOnlyIfValueIsChanged" + +#define DB_STR_QUOTE_POPUP_COLOUR_MODE "PopupColourMode" +#define DB_STR_QUOTE_POPUP_COLOUR_BK "PopupColourBk" +#define DB_STR_QUOTE_POPUP_COLOUR_TEXT "PopupColourText" +#define DB_STR_QUOTE_POPUP_DELAY_MODE "PopupDelayMode" +#define DB_STR_QUOTE_POPUP_DELAY_TIMEOUT "PopupDelayTimeout" +#define DB_STR_QUOTE_POPUP_HISTORY_FLAG "PopupHistoryFlag" + + +// #define DB_STR_NICK "Nick" +#define DB_STR_STATUS "Status" + +#define LIST_MODULE_NAME "CList" +#define CONTACT_LIST_NAME "MyHandle" +#define STATUS_MSG_NAME "StatusMsg" + +#endif //__87d726e0_26c6_485d_8016_1fba819b037d_EconomicRateInfo__ diff --git a/protocols/Quotes/ExtraImages.cpp b/protocols/Quotes/ExtraImages.cpp new file mode 100644 index 0000000000..35a59a8c1d --- /dev/null +++ b/protocols/Quotes/ExtraImages.cpp @@ -0,0 +1,143 @@ +#include "StdAfx.h" +#include "ExtraImages.h" +#include "IconLib.h" +#include "EconomicRateInfo.h" +#include "ModuleInfo.h" +#include "QuotesProviders.h" +#include "IQuotesProvider.h" +#include "Log.h" +#include "DBUtils.h" + +namespace +{ + inline HANDLE extra_add_icon(const char* psz) + { + return reinterpret_cast<HANDLE>( + CallService(MS_CLIST_EXTRA_ADD_ICON,reinterpret_cast<WPARAM>(Quotes_LoadIconEx(psz)),0)); + } + + const HANDLE INVALID_IMAGE_HANDLE = reinterpret_cast<HANDLE>(-1); +} + +CExtraImages::CExtraImages() + : m_hExtraIcons(ExtraIcon_Register(ICON_STR_QUOTE,QUOTES_PROTOCOL_NAME,Quotes_MakeIconName(ICON_STR_MAIN).c_str())), + m_bExtraImagesInit(false), + m_nSlot(DBGetContactSettingWord(NULL,QUOTES_PROTOCOL_NAME,DB_STR_QUOTE_EXTRA_IMAGE_SLOT,EXTRA_ICON_ADV1)) +{ + m_ahExtraImages[eiUp] = INVALID_IMAGE_HANDLE; + m_ahExtraImages[eiDown] = INVALID_IMAGE_HANDLE; + m_ahExtraImages[eiNotChanged] = INVALID_IMAGE_HANDLE; +} + +CExtraImages::~CExtraImages() +{ +} + +CExtraImages& CExtraImages::GetInstance() +{ + static CExtraImages s_ei; + return s_ei; +} + +void CExtraImages::RebuildExtraImages() +{ + if(NULL == m_hExtraIcons) + { + m_bExtraImagesInit = false; + CGuard<CLightMutex> cs(m_lmExtraImages); + m_ahExtraImages[eiUp] = extra_add_icon(ICON_STR_QUOTE_UP); + m_ahExtraImages[eiDown] = extra_add_icon(ICON_STR_QUOTE_DOWN); + m_ahExtraImages[eiNotChanged] = extra_add_icon(ICON_STR_QUOTE_NOT_CHANGED); + m_bExtraImagesInit = true; + } +} + + +bool CExtraImages::SetContactExtraImage(HANDLE hContact,EImageIndex nIndex)const +{ +// tstring s = Quotes_DBGetStringT(hContact,LIST_MODULE_NAME,CONTACT_LIST_NAME); +// tostringstream o; +// o << _T("SetContactExtraImage for ") << s << _T("\nExtra image list init: ") << m_bExtraImagesInit << _T("\n"); + + bool bResult = false; + if(m_hExtraIcons) + { +// o << "Using extra icon interface\n"; + std::string sIconName; + switch(nIndex) + { + case eiUp: + sIconName = Quotes_MakeIconName(ICON_STR_QUOTE_UP); + break; + case eiDown: + sIconName = Quotes_MakeIconName(ICON_STR_QUOTE_DOWN); + break; + case eiNotChanged: + sIconName = Quotes_MakeIconName(ICON_STR_QUOTE_NOT_CHANGED); + break; + } + bResult = (0 == ExtraIcon_SetIcon(m_hExtraIcons,hContact,sIconName.c_str())); + } + else if(m_bExtraImagesInit && ServiceExists(MS_CLIST_EXTRA_ADD_ICON)) + { +// o << "Using contact list interface index is "; + IconExtraColumn iec = {0}; + iec.cbSize = sizeof(iec); + iec.ColumnType = m_nSlot; + + { + CGuard<CLightMutex> cs(m_lmExtraImages); + switch(nIndex) + { + case eiUp: +// o << "up\n"; + iec.hImage = m_ahExtraImages[eiUp]; + break; + case eiDown: +// o << "down\n"; + iec.hImage = m_ahExtraImages[eiDown]; + break; + case eiNotChanged: +// o << "not changed\n"; + iec.hImage = m_ahExtraImages[eiNotChanged]; + break; + default: +// o << "invalid\n"; + iec.hImage = INVALID_IMAGE_HANDLE; + break; + } + } + + bResult = (0 == CallService(MS_CLIST_EXTRA_SET_ICON,reinterpret_cast<WPARAM>(hContact),reinterpret_cast<LPARAM>(&iec))); + } + +// o << "Result is " << bResult; +// LogIt(Info,o.str()); + return bResult; +} + +int QuotesEventFunc_onExtraImageListRebuild(WPARAM /*wp*/,LPARAM /*lp*/) +{ + if (ServiceExists(MS_CLIST_EXTRA_ADD_ICON)) + { + CExtraImages::GetInstance().RebuildExtraImages(); + } + + return 0; +} + +int QuotesEventFunc_onExtraImageApply(WPARAM wp,LPARAM lp) +{ + HANDLE hContact = reinterpret_cast<HANDLE>(wp); + + const CModuleInfo::TQuotesProvidersPtr& pProviders = CModuleInfo::GetQuoteProvidersPtr(); + CQuotesProviders::TQuotesProviderPtr pProvider = pProviders->GetContactProviderPtr(hContact); + if(pProvider) + { + pProvider->SetContactExtraIcon(hContact); + } + + return 0; +} + + diff --git a/protocols/Quotes/ExtraImages.h b/protocols/Quotes/ExtraImages.h new file mode 100644 index 0000000000..ec8ae01e39 --- /dev/null +++ b/protocols/Quotes/ExtraImages.h @@ -0,0 +1,39 @@ +#ifndef __9d0dac0c_12e4_46ce_809a_db6dc7d6f269_ExtraImages_h__ +#define __9d0dac0c_12e4_46ce_809a_db6dc7d6f269_ExtraImages_h__ + +#include "LightMutex.h" + +class CExtraImages : private boost::noncopyable +{ +public: + enum EImageIndex + { + eiUp = 0, + eiDown = 1, + eiNotChanged = 2, + eiEmpty = 3, + ImageCount = 3 + }; + +private: + CExtraImages(); + ~CExtraImages(); + +public: + static CExtraImages& GetInstance(); + + void RebuildExtraImages(); + bool SetContactExtraImage(HANDLE hContact,EImageIndex nIndex)const; + +private: + mutable CLightMutex m_lmExtraImages; + HANDLE m_ahExtraImages[ImageCount]; + HANDLE m_hExtraIcons; + bool m_bExtraImagesInit; + int m_nSlot; +}; + +int QuotesEventFunc_onExtraImageListRebuild(WPARAM wp,LPARAM lp); +int QuotesEventFunc_onExtraImageApply(WPARAM wp,LPARAM lp); + +#endif //__9d0dac0c_12e4_46ce_809a_db6dc7d6f269_ExtraImages_h__ diff --git a/protocols/Quotes/Forex.cpp b/protocols/Quotes/Forex.cpp new file mode 100644 index 0000000000..3bb25a9f99 --- /dev/null +++ b/protocols/Quotes/Forex.cpp @@ -0,0 +1,517 @@ +// Forex.cpp : Defines the exported functions for the DLL application. +// + +#include "stdafx.h" + +#pragma warning(disable:4996) +#include <m_protocols.h> +#include <m_protomod.h> +#pragma warning(default:4996) +#include "WorkingThread.h" +#include <m_protosvc.h> +#include "resource.h" +#include "IconLib.h" +#include <m_options.h> +#include <m_updater.h> +#include <m_userinfo.h> +#include "QuoteInfoDlg.h" +#include "ModuleInfo.h" +#include "QuotesProviders.h" +#include "IQuotesProvider.h" +#include "EconomicRateInfo.h" +#include "DBUtils.h" +#include "ExtraImages.h" +#include "HTTPSession.h" +#include "CurrencyConverter.h" +#ifdef CHART_IMPLEMENT +#include "QuoteChart.h" +#endif +#include "WinCtrlHelper.h" +#include "ImportExport.h" +#include "m_Quotes.h" +#include "version.h" + +PLUGINLINK* pluginLink = NULL; +struct MM_INTERFACE mmi; +struct UTF8_INTERFACE utfi; +int hLangpack; + +HANDLE g_hEventWorkThreadStop; +int g_nStatus = ID_STATUS_OFFLINE; +HGENMENU g_hMenuEditSettings = NULL; +HGENMENU g_hMenuOpenLogFile = NULL; +#ifdef CHART_IMPLEMENT +HGENMENU g_hMenuChart = NULL; +#endif +HGENMENU g_hMenuRefresh = NULL; + +namespace +{ + typedef std::vector<HANDLE> THandles; + THandles g_ahEvents; + THandles g_ahServices; + THandles g_ahThreads; + std::vector<HGENMENU> g_ahMenus; + + PLUGININFOEX Global_pluginInfo = + { + sizeof(PLUGININFOEX), + __PLUGIN_NAME, + PLUGIN_MAKE_VERSION(__MAJOR_VERSION, __MINOR_VERSION, __RELEASE_NUM, __BUILD_NUM), + __DESCRIPTION, + __AUTHOR, + __AUTHOREMAIL, + __COPYRIGHT, + __AUTHORWEB, + UNICODE_AWARE, + 0 +#ifdef _UNICODE + // {E882056D-0D1D-4131-9A98-404CBAEA6A9C} + ,{0xe882056d, 0xd1d, 0x4131, { 0x9a, 0x98, 0x40, 0x4c, 0xba, 0xea, 0x6a, 0x9c } } +#else + // {8CE16273-89EA-4e12-8CF1-2D38AB6BF431} + ,{0x8ce16273, 0x89ea, 0x4e12, { 0x8c, 0xf1, 0x2d, 0x38, 0xab, 0x6b, 0xf4, 0x31 } } +#endif + }; + + INT_PTR QuotesMenu_RefreshAll(WPARAM wp,LPARAM lp) + { + const CQuotesProviders::TQuotesProviders& apProviders = CModuleInfo::GetQuoteProvidersPtr()->GetProviders(); + std::for_each(apProviders.begin(),apProviders.end(),boost::bind(&IQuotesProvider::RefreshAll,_1)); + return 0; + } + + void InitMenu() + { +// USES_CONVERSION; + + CLISTMENUITEM mi = {0}; + mi.cbSize = sizeof(CLISTMENUITEM); + //mi.ptszPopupName = _T("Quotes"); + mi.ptszName = _T("Quotes"); + mi.flags = CMIF_TCHAR|CMIF_ICONFROMICOLIB|CMIF_ROOTPOPUP; + mi.icolibItem = Quotes_GetIconHandle(IDI_ICON_MAIN); + HGENMENU hMenuRoot = reinterpret_cast<HGENMENU>(CallService(MS_CLIST_ADDMAINMENUITEM,0,reinterpret_cast<LPARAM>(&mi))); + g_ahMenus.push_back(hMenuRoot); + + mi.ptszName = _T("Refresh All Quotes\\Rates"); + mi.flags = CMIF_TCHAR|CMIF_ICONFROMICOLIB|CMIF_ROOTHANDLE; + //mi.position = 0x0FFFFFFF; + mi.icolibItem = Quotes_GetIconHandle(IDI_ICON_MAIN); + mi.pszService = "Quotes/RefreshAll"; + mi.hParentMenu = hMenuRoot; + HGENMENU hMenu = reinterpret_cast<HGENMENU>(CallService(MS_CLIST_ADDMAINMENUITEM,0,reinterpret_cast<LPARAM>(&mi))); + g_ahMenus.push_back(hMenu); + HANDLE h = CreateServiceFunction(mi.pszService, QuotesMenu_RefreshAll); + g_ahServices.push_back(h); + + mi.ptszName = _T("Currency Converter..."); + //mi.flags = CMIF_TCHAR|CMIF_ICONFROMICOLIB|CMIF_ROOTHANDLE; + //mi.position = 0x0FFFFFFF; + mi.icolibItem = Quotes_GetIconHandle(IDI_ICON_CURRENCY_CONVERTER); + mi.pszService = "Quotes/CurrencyConverter"; + hMenu = reinterpret_cast<HGENMENU>(CallService(MS_CLIST_ADDMAINMENUITEM,0,reinterpret_cast<LPARAM>(&mi))); + g_ahMenus.push_back(hMenu); + h = CreateServiceFunction(mi.pszService, QuotesMenu_CurrencyConverter); + g_ahServices.push_back(h); + +#ifdef TEST_IMPORT_EXPORT + mi.ptszName = _T("Export All Quotes"); + //mi.flags = CMIF_TCHAR|CMIF_ICONFROMICOLIB|CMIF_ROOTHANDLE; + mi.icolibItem = Quotes_GetIconHandle(IDI_ICON_EXPORT); + mi.pszService = "Quotes/ExportAll"; + hMenu = reinterpret_cast<HGENMENU>(CallService(MS_CLIST_ADDMAINMENUITEM,0,reinterpret_cast<LPARAM>(&mi))); + g_ahMenus.push_back(hMenu); + h = CreateServiceFunction(mi.pszService, QuotesMenu_ExportAll); + g_ahServices.push_back(h); + + mi.ptszName =_T("Import All Quotes"); + //mi.flags = CMIF_TCHAR|CMIF_ICONFROMICOLIB|CMIF_ROOTHANDLE; + mi.icolibItem = Quotes_GetIconHandle(IDI_ICON_IMPORT); + mi.pszService = "Quotes/ImportAll"; + hMenu = reinterpret_cast<HGENMENU>(CallService(MS_CLIST_ADDMAINMENUITEM,0,reinterpret_cast<LPARAM>(&mi))); + g_ahMenus.push_back(hMenu); + h = CreateServiceFunction(mi.pszService, QuotesMenu_ImportAll); + g_ahServices.push_back(h); +#endif + + bool bSubGroups = 1 == ServiceExists(MS_CLIST_ADDSUBGROUPMENUITEM); + + h = HookEvent(ME_CLIST_PREBUILDCONTACTMENU,Quotes_PrebuildContactMenu); + g_ahEvents.push_back(h); + + ZeroMemory(&mi,sizeof(mi)); + mi.cbSize = sizeof(mi); + mi.pszContactOwner = QUOTES_PROTOCOL_NAME; + hMenuRoot = NULL; + if(bSubGroups) + { + mi.pszPopupName=(char *)-1; + mi.icolibItem = Quotes_GetIconHandle(IDI_ICON_MAIN); + mi.flags = CMIF_ICONFROMICOLIB|CMIF_TCHAR|CMIF_ROOTPOPUP; + tstring sProtocolName = quotes_a2t(QUOTES_PROTOCOL_NAME); + mi.ptszName = const_cast<TCHAR*>(sProtocolName.c_str());//A2T(QUOTES_PROTOCOL_NAME); + mi.position = 0; + + hMenuRoot = reinterpret_cast<HGENMENU>(CallService(MS_CLIST_ADDCONTACTMENUITEM,0,reinterpret_cast<LPARAM>(&mi))); + } + + mi.flags = CMIF_TCHAR; + if(bSubGroups) + { + mi.flags |= CMIF_CHILDPOPUP; + mi.pszPopupName = (char*)hMenuRoot; + } + + mi.ptszName = _T("Refresh"); + mi.popupPosition = 0; + mi.flags |= CMIF_ICONFROMICOLIB; + mi.icolibItem = Quotes_GetIconHandle(IDI_ICON_REFRESH); + mi.pszService = "Quotes/RefreshContact"; + hMenu = reinterpret_cast<HGENMENU>(CallService(MS_CLIST_ADDCONTACTMENUITEM,0,reinterpret_cast<LPARAM>(&mi))); + g_hMenuRefresh = hMenu; + g_ahMenus.push_back(hMenu); + h = CreateServiceFunction(mi.pszService, QuotesMenu_RefreshContact); + g_ahServices.push_back(h); + + mi.ptszName = _T("Open Log File..."); + mi.popupPosition = 1; + mi.icolibItem = NULL; + mi.pszService = "Quotes/OpenLogFile"; + hMenu = reinterpret_cast<HGENMENU>(CallService(MS_CLIST_ADDCONTACTMENUITEM,0,reinterpret_cast<LPARAM>(&mi))); + g_hMenuOpenLogFile = hMenu; + g_ahMenus.push_back(hMenu); + h = CreateServiceFunction(mi.pszService, QuotesMenu_OpenLogFile); + g_ahServices.push_back(h); + +#ifdef CHART_IMPLEMENT + mi.ptszName = _T("Chart..."); + mi.popupPosition = 2; + mi.icolibItem = NULL; + mi.pszService = "Quotes/Chart"; + hMenu = reinterpret_cast<HGENMENU>(CallService(MS_CLIST_ADDCONTACTMENUITEM,0,reinterpret_cast<LPARAM>(&mi))); + g_hMenuChart = hMenu; + g_ahMenus.push_back(hMenu); + h = CreateServiceFunction(mi.pszService, QuotesMenu_Chart); + g_ahServices.push_back(h); +#endif + + mi.ptszName = _T("Edit Settings..."); +#ifdef CHART_IMPLEMENT + mi.popupPosition = 3; +#else + mi.popupPosition = 2; +#endif + mi.icolibItem = NULL; + mi.pszService = "Quotes/EditSettings"; + hMenu = reinterpret_cast<HGENMENU>(CallService(MS_CLIST_ADDCONTACTMENUITEM,0,reinterpret_cast<LPARAM>(&mi))); + g_hMenuEditSettings = hMenu; + g_ahMenus.push_back(hMenu); + h = CreateServiceFunction(mi.pszService, QuotesMenu_EditSettings); + g_ahServices.push_back(h); + } + + + int QuotesEventFunc_OnModulesLoaded(WPARAM, LPARAM) + { + CHTTPSession::Init(); + + if(ServiceExists(MS_UPDATE_REGISTER)) + { + Update update = {0}; + char szVersion[16]; + + update.szComponentName = Global_pluginInfo.shortName; + update.szVersionURL = "http://addons.miranda-im.org/details.php?action=viewfile&id=4021"; + update.pbVersionPrefix = (BYTE *)"<span class=\"fileNameHeader\">Quotes "; + update.cpbVersionPrefix = (int)strlen((char *)update.pbVersionPrefix); + update.szUpdateURL = "http://addons.miranda-im.org/feed.php?dlfile=4021"; + + update.szBetaVersionURL = NULL; + update.pbBetaVersionPrefix = NULL; + update.cpbBetaVersionPrefix = 0; + update.szBetaUpdateURL = NULL; + + update.pbVersion = (BYTE*)CreateVersionString(Global_pluginInfo.version,szVersion); + update.cpbVersion = (int)strlen((char *)update.pbVersion); + + update.szBetaChangelogURL = NULL; + + CallService(MS_UPDATE_REGISTER,0,(WPARAM)&update); + } + + HANDLE h = HookEvent(ME_CLIST_EXTRA_LIST_REBUILD,QuotesEventFunc_onExtraImageListRebuild); + g_ahEvents.push_back(h); +// QuotesEventFunc_onExtraImageListRebuild(0,0); + + h = HookEvent(ME_CLIST_EXTRA_IMAGE_APPLY,QuotesEventFunc_onExtraImageApply); + g_ahEvents.push_back(h); + + g_hEventWorkThreadStop = ::CreateEvent(NULL,TRUE,FALSE,NULL); + h = (ME_USERINFO_INITIALISE,QuotesEventFunc_OnUserInfoInit); + g_ahEvents.push_back(h); + + + h = HookEvent(ME_CLIST_DOUBLECLICKED,Quotes_OnContactDoubleClick); + g_ahEvents.push_back(h); + + InitMenu(); + + return 0; + } + + int QuotesEventFunc_OnContactDeleted(WPARAM wParam, LPARAM) + { + HANDLE hContact = reinterpret_cast<HANDLE>(wParam); + + const CModuleInfo::TQuotesProvidersPtr& pProviders = CModuleInfo::GetQuoteProvidersPtr(); + CQuotesProviders::TQuotesProviderPtr pProvider = pProviders->GetContactProviderPtr(hContact); + if(pProvider) + { + pProvider->DeleteContact(hContact); + } + + return 0; + } + + INT_PTR QuoteProtoFunc_GetStatus(WPARAM/* wp*/,LPARAM/* lp*/) + { + return g_nStatus; + } + + void WaitForWorkingThreads() + { + size_t cThreads = g_ahThreads.size(); + if(cThreads > 0) + { + HANDLE* paHandles = &*(g_ahThreads.begin()); + ::WaitForMultipleObjects((DWORD)cThreads,paHandles,TRUE,INFINITE); + } + } + + INT_PTR QuoteProtoFunc_SetStatus(WPARAM wp,LPARAM /*lp*/) + { + int nStatus = wp; + if ((ID_STATUS_ONLINE == nStatus) || (ID_STATUS_OFFLINE == nStatus)) + { + int nOldStatus = g_nStatus; + if(nStatus != g_nStatus) + { + g_nStatus = nStatus; + if ((ID_STATUS_ONLINE == nOldStatus) && (ID_STATUS_OFFLINE == g_nStatus)) + { + BOOL b = ::SetEvent(g_hEventWorkThreadStop); + assert(b); + } + else if ((ID_STATUS_ONLINE == g_nStatus) && (ID_STATUS_OFFLINE == nOldStatus)) + { + BOOL b = ::ResetEvent(g_hEventWorkThreadStop); + assert(b && "Failed to reset event"); + + const CModuleInfo::TQuotesProvidersPtr& pProviders = CModuleInfo::GetQuoteProvidersPtr(); + const CQuotesProviders::TQuotesProviders& rapProviders = pProviders->GetProviders(); + for(CQuotesProviders::TQuotesProviders::const_iterator i = rapProviders.begin();i != rapProviders.end();++i) + { + const CQuotesProviders::TQuotesProviderPtr& pProvider = *i; + HANDLE hThread = reinterpret_cast<HANDLE>(mir_forkthread(WorkingThread,pProvider.get())); + g_ahThreads.push_back(hThread); + } + } + + ProtoBroadcastAck(QUOTES_PROTOCOL_NAME,NULL,ACKTYPE_STATUS,ACKRESULT_SUCCESS,reinterpret_cast<HANDLE>(nOldStatus),g_nStatus); + } + + } + + return 0; + } + + int QuotesEventFunc_PreShutdown(WPARAM wParam, LPARAM lParam) + { + QuoteProtoFunc_SetStatus(ID_STATUS_OFFLINE,0); + //WindowList_Broadcast(g_hWindowListEditSettings,WM_CLOSE,0,0); + CModuleInfo::GetInstance().OnMirandaShutdown(); + return 0; + } + + INT_PTR QuoteProtoFunc_GetName(WPARAM wParam, LPARAM lParam) + { + if(lParam) + { + lstrcpynA(reinterpret_cast<char*>(lParam),QUOTES_PROTOCOL_NAME,wParam); + return 0; + } + else + { + return 1; + } + } + + INT_PTR QuoteProtoFunc_GetCaps(WPARAM wp,LPARAM lp) + { + int ret = 0; + switch(wp) + { + case PFLAGNUM_1: + ret = PF1_PEER2PEER; + break; + case PFLAGNUM_3: + case PFLAGNUM_2: + ret = PF2_ONLINE|PF2_LONGAWAY; + if(CModuleInfo::GetInstance().GetExtendedStatusFlag()) + { + ret |= PF2_LIGHTDND; + } + break; + } + + return ret; + } + + INT_PTR QuoteProtoFunc_LoadIcon(WPARAM wp,LPARAM /*lp*/) + { + if ((wp & 0xffff) == PLI_PROTOCOL) + { + return reinterpret_cast<int>(::CopyIcon(Quotes_LoadIconEx(ICON_STR_MAIN))); + } + + return 0; + } + + int QuotesEventFunc_OptInitialise(WPARAM wp,LPARAM/* lp*/) + { +// USES_CONVERSION; + + const CModuleInfo::TQuotesProvidersPtr& pProviders = CModuleInfo::GetQuoteProvidersPtr(); + const CQuotesProviders::TQuotesProviders& rapProviders = pProviders->GetProviders(); + + OPTIONSDIALOGPAGE odp; + ZeroMemory(&odp,sizeof(odp)); + + odp.cbSize = sizeof(odp); + odp.position = 910000000; + odp.hInstance = CModuleInfo::GetModuleHandle(); + tstring sProtocolName = quotes_a2t(QUOTES_PROTOCOL_NAME); + odp.ptszTitle = const_cast<TCHAR*>(sProtocolName.c_str());//A2T(QUOTES_PROTOCOL_NAME); + odp.ptszGroup = _T("Network"); + odp.hIcon = Quotes_LoadIconEx(ICON_STR_MAIN); + odp.flags = ODPF_TCHAR|ODPF_USERINFOTAB; + + std::for_each(rapProviders.begin(),rapProviders.end(),boost::bind(&IQuotesProvider::ShowPropertyPage,_1,wp,boost::ref(odp))); + return 0; + } + + inline int Quotes_DestroyServiceFunction(HANDLE h) + { + return DestroyServiceFunction(h); + } + + inline int Quotes_UnhookEvent(HANDLE h) + { + return UnhookEvent(h); + } + + inline int Quotes_RemoveMenuItem(HGENMENU h) + { + return CallService(MS_CLIST_REMOVECONTACTMENUITEM,reinterpret_cast<WPARAM>(h),0); + } + +// PROTO_INTERFACE* protoInit(const char* pszProtoName, const TCHAR* tszUserName) +// { +// CAimProto *ppro = new CAimProto(pszProtoName, tszUserName); +// g_Instances.insert(ppro); +// return ppro; +// } +// +// int protoUninit(PROTO_INTERFACE* ppro) +// { +// g_Instances.remove((CAimProto*)ppro); +// return 0; +// } + +} + +extern "C" +{ + __declspec(dllexport) PLUGININFOEX* MirandaPluginInfoEx(DWORD mirandaVersion) + { + return &Global_pluginInfo; + } + + +#define MIID_QUOTES {0x723243c2, 0x8d4b, 0x4c29, { 0x8a, 0x37, 0xc0, 0x11, 0x48, 0x65, 0xb0, 0x80}} + + __declspec(dllexport) const MUUID* MirandaPluginInterfaces() + { + static const MUUID interfaces[] = {MIID_PROTOCOL,MIID_QUOTES,MIID_LAST}; + return interfaces; + } + + int __declspec(dllexport) Load(PLUGINLINK *link) + { + pluginLink = link; + mir_getMMI(&mmi); + mir_getUTFI(&utfi); + mir_getLP(&Global_pluginInfo); +// if ((mirandaVersion >= 0x0800) && (1 == mir_getXI(&xi))) +// { +// CModuleInfo::SetXMLEnginePtr(CModuleInfo::TXMLEnginePtr(new CXMLEngineMI)); +// } + + if(false == CModuleInfo::Verify()) + { + return 1; + } + + Quotes_IconsInit(); + + PROTOCOLDESCRIPTOR pd = {0}; + pd.cbSize = /*sizeof(pd)*/PROTOCOLDESCRIPTOR_V3_SIZE; + pd.szName = QUOTES_PROTOCOL_NAME; + pd.type = PROTOTYPE_PROTOCOL; +// pd.fnInit = protoInit; +// pd.fnUninit = protoUninit; + + CallService( MS_PROTO_REGISTERMODULE, 0, ( LPARAM )&pd ); + + HANDLE h = CreateProtoServiceFunction(QUOTES_PROTOCOL_NAME, PS_GETNAME, QuoteProtoFunc_GetName); + g_ahServices.push_back(h); + h = CreateProtoServiceFunction(QUOTES_PROTOCOL_NAME, PS_GETCAPS, QuoteProtoFunc_GetCaps); + g_ahServices.push_back(h); + h = CreateProtoServiceFunction(QUOTES_PROTOCOL_NAME, PS_SETSTATUS, QuoteProtoFunc_SetStatus); + g_ahServices.push_back(h); + h = CreateProtoServiceFunction(QUOTES_PROTOCOL_NAME, PS_GETSTATUS, QuoteProtoFunc_GetStatus); + g_ahServices.push_back(h); + h = CreateProtoServiceFunction(QUOTES_PROTOCOL_NAME, PS_LOADICON, QuoteProtoFunc_LoadIcon); + g_ahServices.push_back(h); + + h = HookEvent(ME_SYSTEM_MODULESLOADED,QuotesEventFunc_OnModulesLoaded); + g_ahEvents.push_back(h); + h = HookEvent(ME_DB_CONTACT_DELETED,QuotesEventFunc_OnContactDeleted); + g_ahEvents.push_back(h); + h = HookEvent(ME_SYSTEM_PRESHUTDOWN,QuotesEventFunc_PreShutdown); + g_ahEvents.push_back(h); + h = HookEvent(ME_OPT_INITIALISE,QuotesEventFunc_OptInitialise); + g_ahEvents.push_back(h); + + h = CreateServiceFunction(MS_QUOTES_EXPORT, Quotes_Export); + g_ahServices.push_back(h); + h = CreateServiceFunction(MS_QUOTES_IMPORT, Quotes_Import); + g_ahServices.push_back(h); + + return 0; + } + + __declspec(dllexport) int Unload(void) + { + std::for_each(g_ahServices.begin(),g_ahServices.end(),boost::bind(Quotes_DestroyServiceFunction,_1)); + std::for_each(g_ahEvents.begin(),g_ahEvents.end(),boost::bind(Quotes_UnhookEvent,_1)); + std::for_each(g_ahMenus.begin(),g_ahMenus.end(),boost::bind(Quotes_RemoveMenuItem,_1)); + + WaitForWorkingThreads(); + + ::CloseHandle(g_hEventWorkThreadStop); + + return 0; + } +} diff --git a/protocols/Quotes/Forex.rc b/protocols/Quotes/Forex.rc new file mode 100644 index 0000000000..2bfbe8eb69 --- /dev/null +++ b/protocols/Quotes/Forex.rc @@ -0,0 +1,573 @@ +// Microsoft Visual C++ generated resource script. +// +#include "resource.h" + +#define APSTUDIO_READONLY_SYMBOLS +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 2 resource. +// +#include "afxres.h" + +///////////////////////////////////////////////////////////////////////////// +#undef APSTUDIO_READONLY_SYMBOLS + +///////////////////////////////////////////////////////////////////////////// +// Neutral resources + +#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_NEU) +LANGUAGE LANG_NEUTRAL, SUBLANG_NEUTRAL +#pragma code_page(1251) + +///////////////////////////////////////////////////////////////////////////// +// +// Icon +// + +// Icon with lowest ID value placed first to ensure application icon +// remains consistent on all systems. +IDI_ICON_MAIN ICON "res\\main.ico" +IDI_ICON_SECTION ICON "res\\Section.ico" +IDI_ICON_QUOTE ICON "res\\quote.ico" +IDI_ICON_UP ICON "res\\up.ico" +IDI_ICON_DOWN ICON "res\\down.ico" +IDI_ICON_CURRENCY_CONVERTER ICON "res\\CurrencyConverter.ico" +IDI_ICON_REFRESH ICON "res\\Refresh.ico" +IDI_ICON_EXPORT ICON "res\\Export quotes.ico" +IDI_ICON_SWAP ICON "res\\swap.ico" +IDI_ICON_IMPORT ICON "res\\Import quotes.ico" +#endif // Neutral resources +///////////////////////////////////////////////////////////////////////////// + + +///////////////////////////////////////////////////////////////////////////// +// Russian (Russia) resources + +#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_RUS) +LANGUAGE LANG_RUSSIAN, SUBLANG_DEFAULT +#pragma code_page(1251) + +#ifdef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// TEXTINCLUDE +// + +1 TEXTINCLUDE +BEGIN + "resource.h\0" +END + +2 TEXTINCLUDE +BEGIN + "#include ""afxres.h""\r\n" + "\0" +END + +3 TEXTINCLUDE +BEGIN + "\r\n" + "\0" +END + +#endif // APSTUDIO_INVOKED + + +///////////////////////////////////////////////////////////////////////////// +// +// Dialog +// + +IDD_DIALOG_VARIABLE_LIST DIALOGEX 0, 0, 216, 182 +STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU +CAPTION "Variable List" +FONT 8, "MS Shell Dlg", 400, 0, 0x1 +BEGIN + DEFPUSHBUTTON "OK",IDOK,83,161,50,14 + EDITTEXT IDC_EDIT_VARIABLE,7,7,202,147,ES_MULTILINE | ES_AUTOHSCROLL | ES_READONLY +END + + +///////////////////////////////////////////////////////////////////////////// +// +// DESIGNINFO +// + +#ifdef APSTUDIO_INVOKED +GUIDELINES DESIGNINFO +BEGIN + IDD_DIALOG_VARIABLE_LIST, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 209 + TOPMARGIN, 7 + BOTTOMMARGIN, 175 + END +END +#endif // APSTUDIO_INVOKED + +#endif // Russian (Russia) resources +///////////////////////////////////////////////////////////////////////////// + + +///////////////////////////////////////////////////////////////////////////// +// English (United States) resources + +#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU) +LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US +#pragma code_page(1252) + +///////////////////////////////////////////////////////////////////////////// +// +// Icon +// + +// Icon with lowest ID value placed first to ensure application icon +// remains consistent on all systems. +IDI_ICON_NOTCHANGED ICON "res\\notchanged.ico" + +///////////////////////////////////////////////////////////////////////////// +// +// Dialog +// + +IDD_CONTACT_SETTINGS DIALOGEX 0, 0, 323, 269 +STYLE DS_SETFONT | DS_MODALFRAME | DS_SETFOREGROUND | DS_FIXEDSYS | DS_CENTER | WS_POPUP | WS_VISIBLE | WS_CAPTION | WS_SYSMENU +EXSTYLE WS_EX_CONTROLPARENT +CAPTION "Edit Settings" +FONT 8, "MS Shell Dlg", 400, 0, 0x1 +BEGIN + CONTROL "Use contact specific settings",IDC_CHECK_CONTACT_SPECIFIC, + "Button",BS_AUTOCHECKBOX | WS_TABSTOP,7,22,151,10 + GROUPBOX "Log",IDC_STATIC,26,35,290,137 + CONTROL "Use &Internal History",IDC_CHECK_INTERNAL_HISTORY, + "Button",BS_AUTOCHECKBOX | WS_TABSTOP,37,49,140,10 + LTEXT "&Format:",IDC_STATIC_HISTORY_FORMAT,50,63,47,8 + EDITTEXT IDC_EDIT_HISTORY_FORMAT,101,61,137,12,ES_AUTOHSCROLL + PUSHBUTTON "&Variables...",IDC_BUTTON_HISTORY_DESCRIPTION,241,61,65,12 + CONTROL "&Add to History only if Value Changed",IDC_CHECK_HISTORY_CONDITION, + "Button",BS_AUTOCHECKBOX | WS_TABSTOP,50,77,252,10 + CONTROL "Use &External File",IDC_CHECK_EXTERNAL_FILE,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,37,97,127,10 + LTEXT "&Select File:",IDC_STATIC_SELECT_FILE,50,113,49,8 + EDITTEXT IDC_EDIT_FILE_NAME,101,111,137,12,ES_AUTOHSCROLL + PUSHBUTTON "&Browse...",IDC_BUTTON_BROWSE,241,111,65,12 + LTEXT "Variables Allowed: %miranda_userdata%,%quotename%",IDC_STATIC,50,126,257,8,WS_DISABLED + LTEXT "F&ormat:",IDC_STATIC_LOG_FILE_FORMAT,50,142,47,8 + EDITTEXT IDC_EDIT_LOG_FILE_FORMAT,101,140,137,12,ES_AUTOHSCROLL + PUSHBUTTON "V&ariables...",IDC_BUTTON_LOG_FILE_DESCRIPTION,241,140,65,12 + CONTROL "Add to &Log only if Value Changed",IDC_CHECK_LOG_FILE_CONDITION, + "Button",BS_AUTOCHECKBOX | WS_TABSTOP,50,156,224,10 + CONTROL "Show &Popup Window",IDC_CHECK_SHOW_POPUP,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,7,180,120,10 + LTEXT "F&ormat:",IDC_STATIC_POPUP_FORMAT,30,197,47,8 + EDITTEXT IDC_EDIT_POPUP_FORMAT,81,195,137,12,ES_AUTOHSCROLL + PUSHBUTTON "V&ariables...",IDC_BUTTON_POPUP_FORMAT_DESCRIPTION,221,195,65,12 + CONTROL "Show Popup Window Only if Value &Changed",IDC_CHECK_SHOW_POPUP_ONLY_VALUE_CHANGED, + "Button",BS_AUTOCHECKBOX | WS_TABSTOP,30,210,245,10 + DEFPUSHBUTTON "OK",IDOK,107,248,50,14 + PUSHBUTTON "Cancel",IDCANCEL,163,248,50,14 + EDITTEXT IDC_EDIT_NAME,7,7,309,12,ES_CENTER | ES_AUTOHSCROLL | ES_READONLY | NOT WS_BORDER + PUSHBUTTON "Popup settings...",IDC_BUTTON_POPUP_SETTINGS,98,222,111,14 +END + +IDD_CURRENCY_CONVERTER DIALOGEX 0, 0, 347, 101 +STYLE DS_SETFONT | DS_SETFOREGROUND | DS_FIXEDSYS | DS_CENTER | WS_POPUP | WS_VISIBLE | WS_CAPTION | WS_SYSMENU +EXSTYLE WS_EX_CONTROLPARENT +CAPTION "Currency Converter" +FONT 8, "MS Shell Dlg", 400, 0, 0x1 +BEGIN + EDITTEXT IDC_EDIT_VALUE,6,7,56,13,ES_AUTOHSCROLL + COMBOBOX IDC_COMBO_CONVERT_FROM,68,7,105,44,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP + LTEXT "&to:",IDC_STATIC,214,9,14,8 + COMBOBOX IDC_COMBO_CONVERT_INTO,230,7,105,44,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP + PUSHBUTTON "&Swap",IDC_BUTTON_SWAP,180,7,24,12,BS_ICON + PUSHBUTTON "Convert",IDC_BUTTON_CONVERT,134,24,79,14 + EDITTEXT IDC_EDIT_RESULT,7,44,328,12,ES_CENTER | ES_AUTOHSCROLL | ES_READONLY + CONTROL "Info provided by <a href=""http://www.google.com"">Google</a>",IDC_SYSLINK_PROVIDER, + "SysLink",WS_TABSTOP,7,61,159,11 + PUSHBUTTON "Close",IDCANCEL,148,80,50,14 +END + +IDD_CHART DIALOGEX 0, 0, 394, 279 +STYLE DS_SETFONT | DS_SETFOREGROUND | DS_FIXEDSYS | DS_CENTER | WS_MINIMIZEBOX | WS_MAXIMIZEBOX | WS_POPUP | WS_VISIBLE | WS_CLIPCHILDREN | WS_CAPTION | WS_SYSMENU | WS_THICKFRAME +EXSTYLE WS_EX_WINDOWEDGE | WS_EX_CONTROLPARENT +CAPTION "Chart" +FONT 8, "MS Shell Dlg", 400, 0, 0x1 +BEGIN + CONTROL "Info provided by <a href=""http://www.dukascopy.com"">Dukascopy Swiss Forex Group</a>",IDC_SYSLINK_PROVIDER, + "SysLink",WS_TABSTOP,7,261,176,11 + PUSHBUTTON "Close",IDCANCEL,337,258,50,14 + CONTROL "",IDC_STATIC_IMAGE,"Static",SS_ETCHEDFRAME | NOT WS_VISIBLE,7,24,380,230,WS_EX_TRANSPARENT + LTEXT "Get data from:",IDC_STATIC,7,9,69,8 + COMBOBOX IDC_COMBO_DATA_SOURCE,79,7,85,54,CBS_DROPDOWNLIST | CBS_SORT | WS_VSCROLL | WS_TABSTOP + LTEXT "Filter:",IDC_STATIC,170,9,29,8 + COMBOBOX IDC_COMBO_FILTER,204,7,69,47,CBS_DROPDOWNLIST | CBS_SORT | WS_VSCROLL | WS_TABSTOP + EDITTEXT IDC_EDIT_FROM,277,7,53,12,ES_AUTOHSCROLL | NOT WS_VISIBLE + EDITTEXT IDC_EDIT_TO,334,7,53,12,ES_AUTOHSCROLL | NOT WS_VISIBLE +END + +IDD_PROVIDER_ADV_SETTINGS DIALOGEX 0, 0, 303, 260 +STYLE DS_SETFONT | DS_MODALFRAME | DS_SETFOREGROUND | DS_FIXEDSYS | DS_CENTER | WS_POPUP | WS_VISIBLE | WS_CAPTION | WS_SYSMENU +EXSTYLE WS_EX_CONTROLPARENT +CAPTION "Edit Settings" +FONT 8, "MS Shell Dlg", 400, 0, 0x1 +BEGIN + GROUPBOX "Log",IDC_STATIC,7,23,289,139 + CONTROL "Use &Internal History",IDC_CHECK_INTERNAL_HISTORY, + "Button",BS_AUTOCHECKBOX | WS_TABSTOP,17,37,140,10 + LTEXT "&Format:",IDC_STATIC_HISTORY_FORMAT,30,51,47,8 + EDITTEXT IDC_EDIT_HISTORY_FORMAT,81,49,137,12,ES_AUTOHSCROLL + PUSHBUTTON "&Variables...",IDC_BUTTON_HISTORY_DESCRIPTION,221,49,65,12 + CONTROL "&Add to History only if Value Changed",IDC_CHECK_HISTORY_CONDITION, + "Button",BS_AUTOCHECKBOX | WS_TABSTOP,30,65,252,10 + CONTROL "Use &External File",IDC_CHECK_EXTERNAL_FILE,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,17,85,127,10 + LTEXT "&Select File:",IDC_STATIC_SELECT_FILE,30,101,49,8 + EDITTEXT IDC_EDIT_FILE_NAME,81,99,137,12,ES_AUTOHSCROLL + PUSHBUTTON "&Browse...",IDC_BUTTON_BROWSE,221,99,65,12 + LTEXT "Variables Allowed: %miranda_userdata%,%quotename%",IDC_STATIC,30,115,257,8,WS_DISABLED + LTEXT "F&ormat:",IDC_STATIC_LOG_FILE_FORMAT,30,131,47,8 + EDITTEXT IDC_EDIT_LOG_FILE_FORMAT,81,129,137,12,ES_AUTOHSCROLL + PUSHBUTTON "V&ariables...",IDC_BUTTON_LOG_FILE_DESCRIPTION,221,129,65,12 + CONTROL "Add to &Log only if Value Changed",IDC_CHECK_LOG_FILE_CONDITION, + "Button",BS_AUTOCHECKBOX | WS_TABSTOP,30,145,224,10 + CONTROL "Show &Popup Window",IDC_CHECK_SHOW_POPUP,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,7,167,120,10 + LTEXT "F&ormat:",IDC_STATIC_POPUP_FORMAT,30,184,47,8 + EDITTEXT IDC_EDIT_POPUP_FORMAT,81,182,137,12,ES_AUTOHSCROLL + PUSHBUTTON "V&ariables...",IDC_BUTTON_POPUP_FORMAT_DESCRIPTION,221,182,65,12 + CONTROL "Show Popup Window Only if Value &Changed",IDC_CHECK_SHOW_POPUP_ONLY_VALUE_CHANGED, + "Button",BS_AUTOCHECKBOX | WS_TABSTOP,30,197,245,10 + DEFPUSHBUTTON "OK",IDOK,98,239,50,14 + PUSHBUTTON "Cancel",IDCANCEL,154,239,50,14 + EDITTEXT IDC_EDIT_NAME,7,7,289,12,ES_CENTER | ES_AUTOHSCROLL | ES_READONLY | NOT WS_BORDER + PUSHBUTTON "Popup settings...",IDC_BUTTON_POPUP_SETTINGS,86,210,111,14 +END + +IDD_DIALOG_POPUP DIALOGEX 0, 0, 319, 160 +STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU +CAPTION "Popup Window Settings" +FONT 8, "MS Shell Dlg", 400, 0, 0x1 +BEGIN + GROUPBOX "Colours",IDC_STATIC,7,7,149,82,WS_GROUP + CONTROL "Use default colours",IDC_RADIO_DEFAULT_COLOURS,"Button",BS_AUTORADIOBUTTON | WS_TABSTOP,15,20,82,10 + CONTROL "Use user-defined colours",IDC_RADIO_USER_DEFINED_COLOURS, + "Button",BS_AUTORADIOBUTTON,15,34,97,10 + LTEXT "Background colour",IDC_STATIC,70,53,66,8 + CONTROL "",IDC_BGCOLOR,"ColourPicker",WS_TABSTOP,26,49,35,14 + LTEXT "Text colour",IDC_STATIC,70,71,66,8 + CONTROL "",IDC_TEXTCOLOR,"ColourPicker",WS_TABSTOP,26,67,35,14 + GROUPBOX "Delay",IDC_STATIC,162,6,149,82,WS_GROUP + CONTROL "From PopUp plugin",IDC_DELAYFROMPU,"Button",BS_AUTORADIOBUTTON | WS_GROUP | WS_TABSTOP,174,20,76,10 + CONTROL "Custom",IDC_DELAYCUSTOM,"Button",BS_AUTORADIOBUTTON,174,35,47,10 + CONTROL "Permanent",IDC_DELAYPERMANENT,"Button",BS_AUTORADIOBUTTON,174,50,50,10 + EDITTEXT IDC_DELAY,252,33,35,14,ES_AUTOHSCROLL | ES_NUMBER | WS_GROUP + CONTROL "Do not add to popup's history",IDC_CHECK_DONT_USE_POPUPHISTORY, + "Button",BS_AUTOCHECKBOX | WS_TABSTOP,7,96,200,10 + PUSHBUTTON "Preview",IDC_PREV,134,114,50,14 + DEFPUSHBUTTON "OK",IDOK,101,139,50,14 + PUSHBUTTON "Cancel",IDCANCEL,167,139,50,14 +END + + +///////////////////////////////////////////////////////////////////////////// +// +// DESIGNINFO +// + +#ifdef APSTUDIO_INVOKED +GUIDELINES DESIGNINFO +BEGIN + IDD_CONTACT_SETTINGS, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 316 + TOPMARGIN, 7 + BOTTOMMARGIN, 262 + END + + IDD_CURRENCY_CONVERTER, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 335 + TOPMARGIN, 7 + BOTTOMMARGIN, 94 + END + + IDD_CHART, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 387 + TOPMARGIN, 7 + BOTTOMMARGIN, 272 + END + + IDD_PROVIDER_ADV_SETTINGS, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 296 + TOPMARGIN, 7 + BOTTOMMARGIN, 253 + END + + IDD_DIALOG_POPUP, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 312 + TOPMARGIN, 7 + BOTTOMMARGIN, 153 + END +END +#endif // APSTUDIO_INVOKED + + +///////////////////////////////////////////////////////////////////////////// +// +// Dialog Info +// + +IDD_CHART DLGINIT +BEGIN + IDC_COMBO_DATA_SOURCE, 0x403, 9, 0 +0x6f4c, 0x2067, 0x6946, 0x656c, "\000" + IDC_COMBO_DATA_SOURCE, 0x403, 18, 0 +0x694d, 0x6172, 0x646e, 0x2761, 0x2073, 0x6948, 0x7473, 0x726f, 0x0079, + + IDC_COMBO_FILTER, 0x403, 4, 0 +0x6c41, 0x006c, + IDC_COMBO_FILTER, 0x403, 9, 0 +0x614c, 0x7473, 0x4420, 0x7961, "\000" + IDC_COMBO_FILTER, 0x403, 10, 0 +0x614c, 0x7473, 0x5720, 0x6565, 0x006b, + IDC_COMBO_FILTER, 0x403, 11, 0 +0x614c, 0x7473, 0x4d20, 0x6e6f, 0x6874, "\000" + IDC_COMBO_FILTER, 0x403, 10, 0 +0x614c, 0x7473, 0x5920, 0x6165, 0x0072, + IDC_COMBO_FILTER, 0x403, 13, 0 +0x7355, 0x7265, 0x442d, 0x6665, 0x6e69, 0x6465, "\000" + 0 +END + +#endif // English (United States) resources +///////////////////////////////////////////////////////////////////////////// + + +///////////////////////////////////////////////////////////////////////////// +// English (United Kingdom) resources + +#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENG) +LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_UK +#pragma code_page(1252) + +///////////////////////////////////////////////////////////////////////////// +// +// Dialog +// + +IDD_DIALOG_ECONOMIC_RATES DIALOGEX 0, 0, 310, 230 +STYLE DS_SETFONT | DS_FIXEDSYS | WS_CHILD | WS_VISIBLE +EXSTYLE WS_EX_CONTROLPARENT +FONT 8, "MS Shell Dlg", 400, 0, 0x1 +BEGIN + LTEXT "&Choose Quotes to watch in contact list:",IDC_STATIC,7,7,298,8 + CONTROL "",IDC_TREE_ECONOMIC_RATES,"SysTreeView32",TVS_HASBUTTONS | TVS_HASLINES | TVS_LINESATROOT | TVS_DISABLEDRAGDROP | TVS_CHECKBOXES | TVS_NOHSCROLL | WS_BORDER | WS_TABSTOP,21,18,284,126 + LTEXT "&Refresh Quotes Every:",IDC_STATIC,7,150,108,8 + EDITTEXT IDC_EDIT_REFRESH_RATE,118,148,40,12,ES_AUTOHSCROLL + CONTROL "",IDC_SPIN_REFRESH_RATE,"msctls_updown32",UDS_SETBUDDYINT | UDS_ALIGNRIGHT | UDS_AUTOBUDDY | UDS_ARROWKEYS | UDS_HOTTRACK,230,147,11,14 + COMBOBOX IDC_COMBO_REFRESH_RATE,161,148,69,59,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP + LTEXT "&Display in Contact List as:",IDC_STATIC,7,165,109,8 + EDITTEXT IDC_EDIT_CONTACT_LIST_FORMAT,118,162,120,12,ES_AUTOHSCROLL + PUSHBUTTON "&Variables...",IDC_BUTTON_DESCRIPTION,240,162,65,12 + LTEXT "&Status Message:",IDC_STATIC,7,178,107,8 + EDITTEXT IDC_EDIT_STATUS_MESSAGE_FORMAT,118,176,120,12,ES_AUTOHSCROLL + LTEXT "&Tendency:",IDC_STATIC,7,192,102,8 + EDITTEXT IDC_EDIT_TENDENCY_FORMAT,118,190,120,12,ES_AUTOHSCROLL + PUSHBUTTON "&Advanced Settings...",IDC_BUTTON_ADVANCED_SETTINGS,103,208,110,14 +END + +IDD_DIALOG_QUOTE_INFO DIALOGEX 0, 0, 222, 132 +STYLE DS_SETFONT | DS_FIXEDSYS | DS_CENTER | WS_CHILD +FONT 8, "MS Shell Dlg", 400, 0, 0x1 +BEGIN + CTEXT "Static",IDC_STATIC_QUOTE_NAME,7,7,208,8 + CONTROL "<a>SysLink1</a>",IDC_SYSLINK_PROVIDER,"SysLink",WS_TABSTOP,7,110,208,14 + LTEXT "Current Rate:",IDC_STATIC,21,62,72,8 + EDITTEXT IDC_EDIT_RATE,97,60,61,12,ES_AUTOHSCROLL | ES_READONLY + LTEXT "Rate Fetch Time:",IDC_STATIC,21,47,73,8 + EDITTEXT IDC_EDIT_RATE_FETCH_TIME,97,45,98,12,ES_AUTOHSCROLL | ES_READONLY + LTEXT "Previous Rate:",IDC_STATIC,21,77,71,8 + EDITTEXT IDC_EDIT_PREVIOUS_RATE,97,75,61,12,ES_AUTOHSCROLL | ES_READONLY +END + +IDD_DIALOG_OPT_GOOGLE DIALOGEX 0, 0, 310, 233 +STYLE DS_SETFONT | DS_3DLOOK | DS_FIXEDSYS | WS_CHILD | WS_VISIBLE +EXSTYLE WS_EX_CONTROLPARENT +FONT 8, "MS Shell Dlg", 400, 0, 0x1 +BEGIN + LTEXT "&Convert:",IDC_STATIC,7,9,56,8 + COMBOBOX IDC_COMBO_CONVERT_FROM,64,7,105,44,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP + LTEXT "&to:",IDC_STATIC,175,9,21,8 + COMBOBOX IDC_COMBO_CONVERT_INTO,200,7,105,44,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP + PUSHBUTTON "&Add",IDC_BUTTON_ADD,255,35,50,14 + LTEXT "&Watched currency rates:",IDC_STATIC,7,23,110,8 + LISTBOX IDC_LIST_RATES,19,35,231,111,LBS_NOINTEGRALHEIGHT | WS_VSCROLL | WS_TABSTOP + PUSHBUTTON "&Remove",IDC_BUTTON_REMOVE,255,52,50,14 + LTEXT "&Refresh Rates Every:",IDC_STATIC,7,153,107,8 + EDITTEXT IDC_EDIT_REFRESH_RATE,117,151,40,12,ES_AUTOHSCROLL + CONTROL "",IDC_SPIN_REFRESH_RATE,"msctls_updown32",UDS_SETBUDDYINT | UDS_ALIGNRIGHT | UDS_AUTOBUDDY | UDS_ARROWKEYS | UDS_HOTTRACK,234,150,11,14 + COMBOBOX IDC_COMBO_REFRESH_RATE,160,151,69,59,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP + LTEXT "&Display in Contact List as:",IDC_STATIC,7,168,107,8 + EDITTEXT IDC_EDIT_CONTACT_LIST_FORMAT,117,165,120,12,ES_AUTOHSCROLL + PUSHBUTTON "&Variables...",IDC_BUTTON_DESCRIPTION,240,165,65,12 + LTEXT "&Status Message:",IDC_STATIC,7,181,108,8 + EDITTEXT IDC_EDIT_STATUS_MESSAGE_FORMAT,117,179,120,12,ES_AUTOHSCROLL + LTEXT "&Tendency:",IDC_STATIC,7,195,102,8 + EDITTEXT IDC_EDIT_TENDENCY_FORMAT,117,193,120,12,ES_AUTOHSCROLL + PUSHBUTTON "&Advanced Settings...",IDC_BUTTON_ADVANCED_SETTINGS,102,211,110,14 +END + +IDD_DIALOG_QUOTE_INFO_1 DIALOGEX 0, 0, 222, 143 +STYLE DS_SETFONT | DS_MODALFRAME | DS_3DLOOK | DS_FIXEDSYS | DS_CENTER | WS_POPUP | WS_VISIBLE | WS_CAPTION | WS_SYSMENU +CAPTION "Quote\\Rate Info" +FONT 8, "MS Shell Dlg", 400, 0, 0x1 +BEGIN + CTEXT "Static",IDC_STATIC_QUOTE_NAME,7,7,208,8 + CONTROL "<a>SysLink1</a>",IDC_SYSLINK_PROVIDER,"SysLink",WS_TABSTOP,7,98,208,14 + LTEXT "Current Rate:",IDC_STATIC,15,57,81,8 + EDITTEXT IDC_EDIT_RATE,108,55,61,12,ES_AUTOHSCROLL | ES_READONLY + LTEXT "Rate Fetch Time:",IDC_STATIC,15,42,81,8 + EDITTEXT IDC_EDIT_RATE_FETCH_TIME,108,40,98,12,ES_AUTOHSCROLL | ES_READONLY + LTEXT "Previous Rate:",IDC_STATIC,15,72,92,8 + EDITTEXT IDC_EDIT_PREVIOUS_RATE,108,70,61,12,ES_AUTOHSCROLL | ES_READONLY + PUSHBUTTON "Close",IDOK,85,122,50,14 +END + +IDD_DIALOG_OPT_FINANCE DIALOGEX 0, 0, 310, 232 +STYLE DS_SETFONT | DS_3DLOOK | DS_FIXEDSYS | WS_CHILD | WS_VISIBLE +EXSTYLE WS_EX_CONTROLPARENT +FONT 8, "MS Shell Dlg", 400, 0, 0x1 +BEGIN + LTEXT "Type &Stock Name or Symbol:",IDC_STATIC,7,10,96,8 + EDITTEXT IDC_EDIT_QUOTE,106,7,143,14,ES_AUTOHSCROLL + PUSHBUTTON "&Add",IDC_BUTTON_ADD,255,7,50,14 + LTEXT "&Watched Quotes:",IDC_STATIC,7,23,110,8 + LISTBOX IDC_LIST_RATES,19,35,231,112,LBS_NOINTEGRALHEIGHT | WS_VSCROLL | WS_TABSTOP + PUSHBUTTON "&Remove",IDC_BUTTON_REMOVE,255,35,50,14 + LTEXT "&Refresh Rates Every:",IDC_STATIC,7,153,107,8 + EDITTEXT IDC_EDIT_REFRESH_RATE,117,151,40,12,ES_AUTOHSCROLL + CONTROL "",IDC_SPIN_REFRESH_RATE,"msctls_updown32",UDS_SETBUDDYINT | UDS_ALIGNRIGHT | UDS_AUTOBUDDY | UDS_ARROWKEYS | UDS_HOTTRACK,234,150,11,14 + COMBOBOX IDC_COMBO_REFRESH_RATE,160,151,69,59,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP + LTEXT "&Display in Contact List as:",IDC_STATIC,7,168,107,8 + EDITTEXT IDC_EDIT_CONTACT_LIST_FORMAT,117,165,120,12,ES_AUTOHSCROLL + PUSHBUTTON "&Variables...",IDC_BUTTON_DESCRIPTION,240,165,65,12 + LTEXT "Status &Message:",IDC_STATIC,7,181,108,8 + EDITTEXT IDC_EDIT_STATUS_MESSAGE_FORMAT,117,179,120,12,ES_AUTOHSCROLL + LTEXT "&Tendency:",IDC_STATIC,7,195,102,8 + EDITTEXT IDC_EDIT_TENDENCY_FORMAT,117,193,120,12,ES_AUTOHSCROLL + PUSHBUTTON "&Advanced Settings...",IDC_BUTTON_ADVANCED_SETTINGS,99,210,110,14 +END + + +///////////////////////////////////////////////////////////////////////////// +// +// DESIGNINFO +// + +#ifdef APSTUDIO_INVOKED +GUIDELINES DESIGNINFO +BEGIN + IDD_DIALOG_ECONOMIC_RATES, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 305 + TOPMARGIN, 7 + BOTTOMMARGIN, 222 + END + + IDD_DIALOG_QUOTE_INFO, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 215 + TOPMARGIN, 7 + BOTTOMMARGIN, 124 + END + + IDD_DIALOG_OPT_GOOGLE, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 305 + VERTGUIDE, 249 + TOPMARGIN, 7 + BOTTOMMARGIN, 225 + END + + IDD_DIALOG_QUOTE_INFO_1, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 215 + TOPMARGIN, 7 + BOTTOMMARGIN, 135 + END + + IDD_DIALOG_OPT_FINANCE, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 305 + VERTGUIDE, 249 + TOPMARGIN, 7 + BOTTOMMARGIN, 224 + END +END +#endif // APSTUDIO_INVOKED + + +///////////////////////////////////////////////////////////////////////////// +// +// Dialog Info +// + +IDD_DIALOG_ECONOMIC_RATES DLGINIT +BEGIN + IDC_COMBO_REFRESH_RATE, 0x403, 8, 0 +0x6553, 0x6f63, 0x646e, 0x0073, + IDC_COMBO_REFRESH_RATE, 0x403, 8, 0 +0x694d, 0x756e, 0x6574, 0x0073, + IDC_COMBO_REFRESH_RATE, 0x403, 6, 0 +0x6f48, 0x7275, 0x0073, + 0 +END + +IDD_DIALOG_OPT_GOOGLE DLGINIT +BEGIN + IDC_COMBO_REFRESH_RATE, 0x403, 8, 0 +0x6553, 0x6f63, 0x646e, 0x0073, + IDC_COMBO_REFRESH_RATE, 0x403, 8, 0 +0x694d, 0x756e, 0x6574, 0x0073, + IDC_COMBO_REFRESH_RATE, 0x403, 6, 0 +0x6f48, 0x7275, 0x0073, + 0 +END + +IDD_DIALOG_OPT_FINANCE DLGINIT +BEGIN + IDC_COMBO_REFRESH_RATE, 0x403, 8, 0 +0x6553, 0x6f63, 0x646e, 0x0073, + IDC_COMBO_REFRESH_RATE, 0x403, 8, 0 +0x694d, 0x756e, 0x6574, 0x0073, + IDC_COMBO_REFRESH_RATE, 0x403, 6, 0 +0x6f48, 0x7275, 0x0073, + 0 +END + +#endif // English (United Kingdom) resources +///////////////////////////////////////////////////////////////////////////// + + + +#ifndef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 3 resource. +// + + +///////////////////////////////////////////////////////////////////////////// +#endif // not APSTUDIO_INVOKED + diff --git a/protocols/Quotes/Forex.sln b/protocols/Quotes/Forex.sln new file mode 100644 index 0000000000..5f0d619104 --- /dev/null +++ b/protocols/Quotes/Forex.sln @@ -0,0 +1,26 @@ + +Microsoft Visual Studio Solution File, Format Version 11.00 +# Visual Studio 2010 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Quotes", "Forex.vcxproj", "{C619A811-8023-4441-B3D7-785388A09DF0}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Win32 = Debug|Win32 + Debug|x64 = Debug|x64 + Release|Win32 = Release|Win32 + Release|x64 = Release|x64 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {C619A811-8023-4441-B3D7-785388A09DF0}.Debug|Win32.ActiveCfg = Debug|Win32 + {C619A811-8023-4441-B3D7-785388A09DF0}.Debug|Win32.Build.0 = Debug|Win32 + {C619A811-8023-4441-B3D7-785388A09DF0}.Debug|x64.ActiveCfg = Debug|x64 + {C619A811-8023-4441-B3D7-785388A09DF0}.Debug|x64.Build.0 = Debug|x64 + {C619A811-8023-4441-B3D7-785388A09DF0}.Release|Win32.ActiveCfg = Release|Win32 + {C619A811-8023-4441-B3D7-785388A09DF0}.Release|Win32.Build.0 = Release|Win32 + {C619A811-8023-4441-B3D7-785388A09DF0}.Release|x64.ActiveCfg = Release|x64 + {C619A811-8023-4441-B3D7-785388A09DF0}.Release|x64.Build.0 = Release|x64 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/protocols/Quotes/Forex.vcxproj b/protocols/Quotes/Forex.vcxproj new file mode 100644 index 0000000000..4dd737de9c --- /dev/null +++ b/protocols/Quotes/Forex.vcxproj @@ -0,0 +1,289 @@ +<?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"> + <ProjectGuid>{C619A811-8023-4441-B3D7-785388A09DF0}</ProjectGuid> + <ProjectName>Quotes</ProjectName> + </PropertyGroup> + <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" /> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration"> + <ConfigurationType>DynamicLibrary</ConfigurationType> + <CharacterSet>Unicode</CharacterSet> + <WholeProgramOptimization>true</WholeProgramOptimization> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration"> + <ConfigurationType>DynamicLibrary</ConfigurationType> + <CharacterSet>Unicode</CharacterSet> + <WholeProgramOptimization>true</WholeProgramOptimization> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration"> + <ConfigurationType>DynamicLibrary</ConfigurationType> + <CharacterSet>Unicode</CharacterSet> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration"> + <ConfigurationType>DynamicLibrary</ConfigurationType> + <CharacterSet>Unicode</CharacterSet> + </PropertyGroup> + <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" /> + <ImportGroup Label="ExtensionSettings"> + </ImportGroup> + <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="PropertySheets"> + <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" /> + </ImportGroup> + <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="PropertySheets"> + <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" /> + </ImportGroup> + <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="PropertySheets"> + <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" /> + </ImportGroup> + <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="PropertySheets"> + <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" /> + </ImportGroup> + <PropertyGroup Label="UserMacros" /> + <PropertyGroup> + <_ProjectFileVersion>10.0.30319.1</_ProjectFileVersion> + <OutDir Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">$(SolutionDir)$(Configuration)\Plugins\</OutDir> + <OutDir Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">$(SolutionDir)$(Configuration)64\Plugins\</OutDir> + <IntDir Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">$(SolutionDir)$(Configuration)\Obj\$(ProjectName)\</IntDir> + <IntDir Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">$(SolutionDir)$(Configuration)64\Obj\$(ProjectName)\</IntDir> + <OutDir Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">$(SolutionDir)$(Configuration)\Plugins\</OutDir> + <OutDir Condition="'$(Configuration)|$(Platform)'=='Release|x64'">$(SolutionDir)$(Configuration)64\Plugins\</OutDir> + <IntDir Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">$(SolutionDir)$(Configuration)\Obj\$(ProjectName)\</IntDir> + <IntDir Condition="'$(Configuration)|$(Platform)'=='Release|x64'">$(SolutionDir)$(Configuration)64\Obj\$(ProjectName)\</IntDir> + <IgnoreImportLibrary Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</IgnoreImportLibrary> + <IgnoreImportLibrary Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</IgnoreImportLibrary> + <IgnoreImportLibrary Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">true</IgnoreImportLibrary> + <IgnoreImportLibrary Condition="'$(Configuration)|$(Platform)'=='Release|x64'">true</IgnoreImportLibrary> + </PropertyGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"> + <ClCompile> + <Optimization>Disabled</Optimization> + <AdditionalIncludeDirectories>..\..\include;..\plugins\ExternalAPI;..\..\..\boost_1_49_0;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> + <PreprocessorDefinitions>WIN32;_DEBUG;_WINDOWS;_USRDLL;FOREX_EXPORTS;%(PreprocessorDefinitions)</PreprocessorDefinitions> + <BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks> + <RuntimeLibrary>MultiThreadedDebugDLL</RuntimeLibrary> + <PrecompiledHeader>Use</PrecompiledHeader> + <WarningLevel>Level3</WarningLevel> + <DebugInformationFormat>EditAndContinue</DebugInformationFormat> + </ClCompile> + <Link> + <AdditionalDependencies>comsuppw.lib;comctl32.lib;%(AdditionalDependencies)</AdditionalDependencies> + <GenerateDebugInformation>true</GenerateDebugInformation> + <SubSystem>Windows</SubSystem> + <ImportLibrary>$(IntDir)$(TargetName).lib</ImportLibrary> + <RandomizedBaseAddress>false</RandomizedBaseAddress> + <AdditionalLibraryDirectories>..\..\..\boost_1_49_0\lib</AdditionalLibraryDirectories> + </Link> + <ResourceCompile> + <AdditionalIncludeDirectories>..\..\include\msapi</AdditionalIncludeDirectories> + <PreprocessorDefinitions>_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions> + </ResourceCompile> + </ItemDefinitionGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'"> + <ClCompile> + <Optimization>Disabled</Optimization> + <AdditionalIncludeDirectories>..\..\include;..\plugins\ExternalAPI;..\..\..\boost_1_49_0;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> + <PreprocessorDefinitions>WIN64;_DEBUG;_WINDOWS;_USRDLL;FOREX_EXPORTS;%(PreprocessorDefinitions)</PreprocessorDefinitions> + <BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks> + <RuntimeLibrary>MultiThreadedDebugDLL</RuntimeLibrary> + <PrecompiledHeader>Use</PrecompiledHeader> + <WarningLevel>Level3</WarningLevel> + </ClCompile> + <Link> + <AdditionalDependencies>comsuppw.lib;comctl32.lib;%(AdditionalDependencies)</AdditionalDependencies> + <GenerateDebugInformation>true</GenerateDebugInformation> + <SubSystem>Windows</SubSystem> + <ImportLibrary>$(IntDir)$(TargetName).lib</ImportLibrary> + <RandomizedBaseAddress>false</RandomizedBaseAddress> + <AdditionalLibraryDirectories>..\..\..\boost_1_49_0\lib64</AdditionalLibraryDirectories> + </Link> + <ResourceCompile> + <AdditionalIncludeDirectories>..\..\include\msapi</AdditionalIncludeDirectories> + <PreprocessorDefinitions>_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions> + </ResourceCompile> + </ItemDefinitionGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> + <ClCompile> + <Optimization>Full</Optimization> + <IntrinsicFunctions>true</IntrinsicFunctions> + <FavorSizeOrSpeed>Size</FavorSizeOrSpeed> + <AdditionalIncludeDirectories>..\..\include;..\plugins\ExternalAPI;..\..\..\boost_1_49_0;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> + <PreprocessorDefinitions>WIN32;NDEBUG;_WINDOWS;_USRDLL;FOREX_EXPORTS;%(PreprocessorDefinitions)</PreprocessorDefinitions> + <FunctionLevelLinking>true</FunctionLevelLinking> + <PrecompiledHeader>Use</PrecompiledHeader> + <WarningLevel>Level3</WarningLevel> + </ClCompile> + <Link> + <AdditionalDependencies>comsuppw.lib;comctl32.lib;%(AdditionalDependencies)</AdditionalDependencies> + <GenerateDebugInformation>true</GenerateDebugInformation> + <SubSystem>Windows</SubSystem> + <OptimizeReferences>true</OptimizeReferences> + <EnableCOMDATFolding>true</EnableCOMDATFolding> + <ImportLibrary>$(IntDir)$(TargetName).lib</ImportLibrary> + <RandomizedBaseAddress>false</RandomizedBaseAddress> + <AdditionalLibraryDirectories>..\..\..\boost_1_49_0\lib</AdditionalLibraryDirectories> + </Link> + <ResourceCompile> + <AdditionalIncludeDirectories>..\..\include\msapi</AdditionalIncludeDirectories> + <PreprocessorDefinitions>NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions> + </ResourceCompile> + </ItemDefinitionGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'"> + <ClCompile> + <Optimization>Full</Optimization> + <IntrinsicFunctions>true</IntrinsicFunctions> + <FavorSizeOrSpeed>Size</FavorSizeOrSpeed> + <AdditionalIncludeDirectories>..\..\include;..\plugins\ExternalAPI;..\..\..\boost_1_49_0;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> + <PreprocessorDefinitions>WIN64;NDEBUG;_WINDOWS;_USRDLL;FOREX_EXPORTS;%(PreprocessorDefinitions)</PreprocessorDefinitions> + <FunctionLevelLinking>true</FunctionLevelLinking> + <PrecompiledHeader>Use</PrecompiledHeader> + <WarningLevel>Level3</WarningLevel> + </ClCompile> + <Link> + <AdditionalDependencies>comsuppw.lib;comctl32.lib;%(AdditionalDependencies)</AdditionalDependencies> + <GenerateDebugInformation>true</GenerateDebugInformation> + <SubSystem>Windows</SubSystem> + <OptimizeReferences>true</OptimizeReferences> + <EnableCOMDATFolding>true</EnableCOMDATFolding> + <ImportLibrary>$(IntDir)$(TargetName).lib</ImportLibrary> + <RandomizedBaseAddress>false</RandomizedBaseAddress> + <AdditionalLibraryDirectories>..\..\..\boost_1_49_0\lib64</AdditionalLibraryDirectories> + </Link> + <ResourceCompile> + <AdditionalIncludeDirectories>..\..\include\msapi</AdditionalIncludeDirectories> + <PreprocessorDefinitions>NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions> + </ResourceCompile> + </ItemDefinitionGroup> + <ItemGroup> + <ClCompile Include="Base64.cpp" /> + <ClCompile Include="ComHelper.cpp" /> + <ClCompile Include="CommonOptionDlg.cpp" /> + <ClCompile Include="CreateFilePath.cpp" /> + <ClCompile Include="CurrencyConverter.cpp" /> + <ClCompile Include="DBUtils.cpp" /> + <ClCompile Include="dllmain.cpp" /> + <ClCompile Include="ExtraImages.cpp" /> + <ClCompile Include="Forex.cpp" /> + <ClCompile Include="HTMLParserMS.cpp" /> + <ClCompile Include="HTTPSession.cpp" /> + <ClCompile Include="IconLib.cpp" /> + <ClCompile Include="ImportExport.cpp" /> + <ClCompile Include="LightMutex.cpp" /> + <ClCompile Include="Locale.cpp" /> + <ClCompile Include="Log.cpp" /> + <ClCompile Include="ModuleInfo.cpp" /> + <ClCompile Include="OptionDukasCopy.cpp" /> + <ClCompile Include="QuoteChart.cpp" /> + <ClCompile Include="QuoteInfoDlg.cpp" /> + <ClCompile Include="QuotesProviderBase.cpp" /> + <ClCompile Include="QuotesProviderDukasCopy.cpp" /> + <ClCompile Include="QuotesProviderFinance.cpp" /> + <ClCompile Include="QuotesProviderGoogle.cpp" /> + <ClCompile Include="QuotesProviderGoogleFinance.cpp" /> + <ClCompile Include="QuotesProviders.cpp" /> + <ClCompile Include="QuotesProviderVisitorDbSettings.cpp" /> + <ClCompile Include="QuotesProviderVisitorFormater.cpp" /> + <ClCompile Include="QuotesProviderVisitorFormatSpecificator.cpp" /> + <ClCompile Include="QuotesProviderVisitorTendency.cpp" /> + <ClCompile Include="QuotesProviderYahoo.cpp" /> + <ClCompile Include="SettingsDlg.cpp" /> + <ClCompile Include="stdafx.cpp"> + <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">Create</PrecompiledHeader> + <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">Create</PrecompiledHeader> + <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">Create</PrecompiledHeader> + <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release|x64'">Create</PrecompiledHeader> + </ClCompile> + <ClCompile Include="WinCtrlHelper.cpp" /> + <ClCompile Include="WorkingThread.cpp" /> + <ClCompile Include="XMLEngineMI.cpp" /> + </ItemGroup> + <ItemGroup> + <ClInclude Include="Base64.h" /> + <ClInclude Include="Chart.h" /> + <ClInclude Include="ComHelper.h" /> + <ClInclude Include="CommonOptionDlg.h" /> + <ClInclude Include="CreateFilePath.h" /> + <ClInclude Include="CurrencyConverter.h" /> + <ClInclude Include="DBUtils.h" /> + <ClInclude Include="EconomicRateInfo.h" /> + <ClInclude Include="ExtraImages.h" /> + <ClInclude Include="HTMLParserMS.h" /> + <ClInclude Include="HTTPSession.h" /> + <ClInclude Include="IconLib.h" /> + <ClInclude Include="IHTMLEngine.h" /> + <ClInclude Include="IHTMLParser.h" /> + <ClInclude Include="ImportExport.h" /> + <ClInclude Include="IQuotesProvider.h" /> + <ClInclude Include="IsWithinAccuracy.h" /> + <ClInclude Include="IXMLEngine.h" /> + <ClInclude Include="LightMutex.h" /> + <ClInclude Include="Locale.h" /> + <ClInclude Include="Log.h" /> + <ClInclude Include="ModuleInfo.h" /> + <ClInclude Include="OptionDukasCopy.h" /> + <ClInclude Include="QuoteChart.h" /> + <ClInclude Include="QuoteInfoDlg.h" /> + <ClInclude Include="QuotesProviderBase.h" /> + <ClInclude Include="QuotesProviderDukasCopy.h" /> + <ClInclude Include="QuotesProviderFinance.h" /> + <ClInclude Include="QuotesProviderGoogle.h" /> + <ClInclude Include="QuotesProviderGoogleFinance.h" /> + <ClInclude Include="QuotesProviders.h" /> + <ClInclude Include="QuotesProviderVisitor.h" /> + <ClInclude Include="QuotesProviderVisitorDbSettings.h" /> + <ClInclude Include="QuotesProviderVisitorFormater.h" /> + <ClInclude Include="QuotesProviderVisitorFormatSpecificator.h" /> + <ClInclude Include="QuotesProviderVisitorTendency.h" /> + <ClInclude Include="QuotesProviderYahoo.h" /> + <ClInclude Include="resource.h" /> + <ClInclude Include="SettingsDlg.h" /> + <ClInclude Include="stdafx.h" /> + <ClInclude Include="targetver.h" /> + <ClInclude Include="version.h" /> + <ClInclude Include="WinCtrlHelper.h" /> + <ClInclude Include="WorkingThread.h" /> + <ClInclude Include="XMLEngineMI.h" /> + </ItemGroup> + <ItemGroup> + <None Include="res\CurrencyConverter.ico" /> + <None Include="res\down.ico" /> + <None Include="res\Export quotes.ico" /> + <None Include="res\Import quotes.ico" /> + <None Include="res\main.ico" /> + <None Include="res\notchanged.ico" /> + <None Include="res\quote.ico" /> + <None Include="res\Refresh.ico" /> + <None Include="res\Section.ico" /> + <None Include="res\swap.ico" /> + <None Include="res\up.ico" /> + </ItemGroup> + <ItemGroup> + <ResourceCompile Include="Forex.rc" /> + <ResourceCompile Include="Version.rc" /> + </ItemGroup> + <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" /> + <ImportGroup Label="ExtensionTargets"> + </ImportGroup> + <ProjectExtensions> + <VisualStudio> + <UserProperties RESOURCE_FILE="Forex.rc" /> + </VisualStudio> + </ProjectExtensions> +</Project> \ No newline at end of file diff --git a/protocols/Quotes/Forex.vcxproj.filters b/protocols/Quotes/Forex.vcxproj.filters new file mode 100644 index 0000000000..127582eda6 --- /dev/null +++ b/protocols/Quotes/Forex.vcxproj.filters @@ -0,0 +1,307 @@ +<?xml version="1.0" encoding="utf-8"?> +<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> + <ItemGroup> + <Filter Include="Source Files"> + <UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier> + <Extensions>cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx</Extensions> + </Filter> + <Filter Include="Header Files"> + <UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier> + <Extensions>h;hpp;hxx;hm;inl;inc;xsd</Extensions> + </Filter> + <Filter Include="Resource Files"> + <UniqueIdentifier>{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}</UniqueIdentifier> + <Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav</Extensions> + </Filter> + </ItemGroup> + <ItemGroup> + <ClCompile Include="Base64.cpp"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="ComHelper.cpp"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="CommonOptionDlg.cpp"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="CreateFilePath.cpp"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="CurrencyConverter.cpp"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="DBUtils.cpp"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="dllmain.cpp"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="ExtraImages.cpp"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="Forex.cpp"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="HTMLParserMS.cpp"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="HTTPSession.cpp"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="IconLib.cpp"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="ImportExport.cpp"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="LightMutex.cpp"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="Locale.cpp"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="Log.cpp"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="ModuleInfo.cpp"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="OptionDukasCopy.cpp"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="QuoteChart.cpp"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="QuoteInfoDlg.cpp"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="QuotesProviderBase.cpp"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="QuotesProviderDukasCopy.cpp"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="QuotesProviderGoogle.cpp"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="QuotesProviderGoogleFinance.cpp"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="QuotesProviders.cpp"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="QuotesProviderVisitorDbSettings.cpp"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="QuotesProviderVisitorFormater.cpp"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="QuotesProviderVisitorFormatSpecificator.cpp"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="stdafx.cpp"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="WinCtrlHelper.cpp"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="WorkingThread.cpp"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="XMLEngineMI.cpp"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="SettingsDlg.cpp"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="QuotesProviderVisitorTendency.cpp"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="QuotesProviderFinance.cpp"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="QuotesProviderYahoo.cpp"> + <Filter>Source Files</Filter> + </ClCompile> + </ItemGroup> + <ItemGroup> + <ClInclude Include="Base64.h"> + <Filter>Header Files</Filter> + </ClInclude> + <ClInclude Include="ComHelper.h"> + <Filter>Header Files</Filter> + </ClInclude> + <ClInclude Include="CommonOptionDlg.h"> + <Filter>Header Files</Filter> + </ClInclude> + <ClInclude Include="CreateFilePath.h"> + <Filter>Header Files</Filter> + </ClInclude> + <ClInclude Include="CurrencyConverter.h"> + <Filter>Header Files</Filter> + </ClInclude> + <ClInclude Include="DBUtils.h"> + <Filter>Header Files</Filter> + </ClInclude> + <ClInclude Include="EconomicRateInfo.h"> + <Filter>Header Files</Filter> + </ClInclude> + <ClInclude Include="ExtraImages.h"> + <Filter>Header Files</Filter> + </ClInclude> + <ClInclude Include="HTMLParserMS.h"> + <Filter>Header Files</Filter> + </ClInclude> + <ClInclude Include="HTTPSession.h"> + <Filter>Header Files</Filter> + </ClInclude> + <ClInclude Include="IconLib.h"> + <Filter>Header Files</Filter> + </ClInclude> + <ClInclude Include="IHTMLEngine.h"> + <Filter>Header Files</Filter> + </ClInclude> + <ClInclude Include="IHTMLParser.h"> + <Filter>Header Files</Filter> + </ClInclude> + <ClInclude Include="ImportExport.h"> + <Filter>Header Files</Filter> + </ClInclude> + <ClInclude Include="IQuotesProvider.h"> + <Filter>Header Files</Filter> + </ClInclude> + <ClInclude Include="IsWithinAccuracy.h"> + <Filter>Header Files</Filter> + </ClInclude> + <ClInclude Include="IXMLEngine.h"> + <Filter>Header Files</Filter> + </ClInclude> + <ClInclude Include="LightMutex.h"> + <Filter>Header Files</Filter> + </ClInclude> + <ClInclude Include="Locale.h"> + <Filter>Header Files</Filter> + </ClInclude> + <ClInclude Include="Log.h"> + <Filter>Header Files</Filter> + </ClInclude> + <ClInclude Include="ModuleInfo.h"> + <Filter>Header Files</Filter> + </ClInclude> + <ClInclude Include="OptionDukasCopy.h"> + <Filter>Header Files</Filter> + </ClInclude> + <ClInclude Include="QuoteChart.h"> + <Filter>Header Files</Filter> + </ClInclude> + <ClInclude Include="QuoteInfoDlg.h"> + <Filter>Header Files</Filter> + </ClInclude> + <ClInclude Include="QuotesProviderBase.h"> + <Filter>Header Files</Filter> + </ClInclude> + <ClInclude Include="QuotesProviderDukasCopy.h"> + <Filter>Header Files</Filter> + </ClInclude> + <ClInclude Include="QuotesProviderGoogle.h"> + <Filter>Header Files</Filter> + </ClInclude> + <ClInclude Include="QuotesProviderGoogleFinance.h"> + <Filter>Header Files</Filter> + </ClInclude> + <ClInclude Include="QuotesProviders.h"> + <Filter>Header Files</Filter> + </ClInclude> + <ClInclude Include="QuotesProviderVisitor.h"> + <Filter>Header Files</Filter> + </ClInclude> + <ClInclude Include="QuotesProviderVisitorDbSettings.h"> + <Filter>Header Files</Filter> + </ClInclude> + <ClInclude Include="QuotesProviderVisitorFormater.h"> + <Filter>Header Files</Filter> + </ClInclude> + <ClInclude Include="QuotesProviderVisitorFormatSpecificator.h"> + <Filter>Header Files</Filter> + </ClInclude> + <ClInclude Include="resource.h"> + <Filter>Header Files</Filter> + </ClInclude> + <ClInclude Include="stdafx.h"> + <Filter>Header Files</Filter> + </ClInclude> + <ClInclude Include="targetver.h"> + <Filter>Header Files</Filter> + </ClInclude> + <ClInclude Include="WinCtrlHelper.h"> + <Filter>Header Files</Filter> + </ClInclude> + <ClInclude Include="WorkingThread.h"> + <Filter>Header Files</Filter> + </ClInclude> + <ClInclude Include="XMLEngineMI.h"> + <Filter>Header Files</Filter> + </ClInclude> + <ClInclude Include="SettingsDlg.h"> + <Filter>Header Files</Filter> + </ClInclude> + <ClInclude Include="version.h"> + <Filter>Header Files</Filter> + </ClInclude> + <ClInclude Include="Chart.h"> + <Filter>Header Files</Filter> + </ClInclude> + <ClInclude Include="QuotesProviderVisitorTendency.h"> + <Filter>Header Files</Filter> + </ClInclude> + <ClInclude Include="QuotesProviderFinance.h"> + <Filter>Header Files</Filter> + </ClInclude> + <ClInclude Include="QuotesProviderYahoo.h"> + <Filter>Header Files</Filter> + </ClInclude> + </ItemGroup> + <ItemGroup> + <None Include="res\CurrencyConverter.ico"> + <Filter>Resource Files</Filter> + </None> + <None Include="res\down.ico"> + <Filter>Resource Files</Filter> + </None> + <None Include="res\Export quotes.ico"> + <Filter>Resource Files</Filter> + </None> + <None Include="res\Import quotes.ico"> + <Filter>Resource Files</Filter> + </None> + <None Include="res\main.ico"> + <Filter>Resource Files</Filter> + </None> + <None Include="res\notchanged.ico"> + <Filter>Resource Files</Filter> + </None> + <None Include="res\quote.ico"> + <Filter>Resource Files</Filter> + </None> + <None Include="res\Refresh.ico"> + <Filter>Resource Files</Filter> + </None> + <None Include="res\Section.ico"> + <Filter>Resource Files</Filter> + </None> + <None Include="res\up.ico"> + <Filter>Resource Files</Filter> + </None> + <None Include="res\swap.ico"> + <Filter>Resource Files</Filter> + </None> + </ItemGroup> + <ItemGroup> + <ResourceCompile Include="Forex.rc"> + <Filter>Resource Files</Filter> + </ResourceCompile> + <ResourceCompile Include="Version.rc"> + <Filter>Resource Files</Filter> + </ResourceCompile> + </ItemGroup> +</Project> \ No newline at end of file diff --git a/protocols/Quotes/HTMLParserMS.cpp b/protocols/Quotes/HTMLParserMS.cpp new file mode 100644 index 0000000000..bfe58b43b1 --- /dev/null +++ b/protocols/Quotes/HTMLParserMS.cpp @@ -0,0 +1,313 @@ +#include "StdAfx.h" +#include "HTMLParserMS.h" + +using _com_util::CheckError; + +namespace +{ + class CHTMLNode : public IHTMLNode + { + public: + typedef CComPtr<IDispatch> TComPtr; + typedef CComPtr<IHTMLDocument3> TDocumentPtr; + + protected: + typedef CComPtr<IHTMLElementCollection> TElementCollectionPtr; + + public: + CHTMLNode(const TComPtr& pElement,const TDocumentPtr& pDocument) + : m_pElement(pElement),m_pDocument(pDocument){} + + virtual THTMLNodePtr GetElementByID(const tstring& rsID)const + { + if(m_pDocument) + { + CComPtr<IHTMLElement> pElement; + if(SUCCEEDED(m_pDocument->getElementById(bstr_t(rsID.c_str()),&pElement)) + && pElement) + { + TComPtr p(pElement); + return THTMLNodePtr(new CHTMLNode(p,m_pDocument)); + } + } + + return THTMLNodePtr(); + } + + virtual size_t GetChildCount()const + { + TElementCollectionPtr pColl = GetElementCollectionPtr(); + if(pColl) + { + LONG celem = 0; + HRESULT hr = pColl->get_length(&celem); + if(S_OK == hr) + { + return celem; + } + } + + return 0; + } + + virtual THTMLNodePtr GetChildPtr(size_t nIndex) + { + TElementCollectionPtr pColl = GetElementCollectionPtr(); + if(pColl) + { + VARIANT varIndex; + varIndex.vt = VT_UINT; + varIndex.lVal = (LONG)nIndex; + VARIANT var2; + VariantInit(&var2); + TComPtr pDisp; + HRESULT hr = pColl->item(varIndex,var2,&pDisp); + if(S_OK == hr && pDisp) + { + return THTMLNodePtr(new CHTMLNode(pDisp,m_pDocument)); + } + } + + return THTMLNodePtr(); + } + + virtual bool Is(EType nType)const + { + switch(nType) + { + case Table: + { + CComPtr<IHTMLTable> pTable; + return (SUCCEEDED(m_pElement->QueryInterface(IID_IHTMLTable,reinterpret_cast<void**>(&pTable))) && (pTable)); + } + case TableRow: + { + CComPtr<IHTMLTableRow> pRow; + return (SUCCEEDED(m_pElement->QueryInterface(IID_IHTMLTableRow,reinterpret_cast<void**>(&pRow))) && (pRow)); + } + case TableColumn: + { + CComPtr<IHTMLTableCol> pCol; + return (SUCCEEDED(m_pElement->QueryInterface(IID_IHTMLTableCol,reinterpret_cast<void**>(&pCol))) && (pCol)); + } + } + + return false; + } + + virtual tstring GetAttribute(const tstring& rsAttrName)const + { + USES_CONVERSION; + + tstring sAttr; + CComPtr<IHTMLElement> pElement; + if(SUCCEEDED(m_pElement->QueryInterface(IID_IHTMLElement,reinterpret_cast<void**>(&pElement))) && pElement) + { + _variant_t vAttribute; + BSTR pbstrAttrName = T2BSTR(rsAttrName.c_str()); + if(SUCCEEDED(pElement->getAttribute(pbstrAttrName,1,&vAttribute)) + && VT_NULL != vAttribute.vt && VT_EMPTY != vAttribute.vt) + { + try + { + _bstr_t b(vAttribute); + LPCTSTR psz = b; + if(psz) + { + sAttr = psz; + } + } + catch(_com_error&) + { + } + } + } + + return sAttr; + } + + virtual tstring GetText()const + { +// USES_CONVERSION; + + tstring sText; + CComPtr<IHTMLElement> pElement; + if(SUCCEEDED(m_pElement->QueryInterface(IID_IHTMLElement,reinterpret_cast<void**>(&pElement))) && pElement) + { + BSTR bstrText; + if(SUCCEEDED(pElement->get_innerText(&bstrText)) && bstrText) + { + try + { + sText = _bstr_t(bstrText); + } + catch(_com_error&) + { + } + + ::SysFreeString(bstrText); + } + } + + return sText; + } + + protected: + virtual TElementCollectionPtr GetElementCollectionPtr()const + { + TElementCollectionPtr pColl; + HRESULT hr = m_pElement->QueryInterface(IID_IHTMLElementCollection,reinterpret_cast<void**>(&pColl)); + if(FAILED(hr)) + { + CComPtr<IHTMLElement> pElement; + if(SUCCEEDED(m_pElement->QueryInterface(IID_IHTMLElement,reinterpret_cast<void**>(&pElement))) && pElement) + { + CComPtr<IDispatch> pDisp; + if(SUCCEEDED(pElement->get_children(&pDisp)) && pDisp) + { + hr = pDisp->QueryInterface(IID_IHTMLElementCollection,reinterpret_cast<void**>(&pColl)); + } + } + } + + return pColl; + } + + private: + TComPtr m_pElement; + TDocumentPtr m_pDocument; + }; +} + +CHTMLParserMS::CHTMLParserMS() : m_bCallUninit(false) +{ + try + { + CheckError(::CoInitialize(NULL)); + + m_bCallUninit = true; + + _com_util::CheckError( + ::CoCreateInstance(CLSID_HTMLDocument, + NULL, + CLSCTX_INPROC_SERVER, + IID_IHTMLDocument2, + (LPVOID*)&m_pDoc) + ); + + CComPtr<IPersistStreamInit> pPersist; + _com_util::CheckError(m_pDoc->QueryInterface(IID_IPersistStreamInit, + (LPVOID*)&pPersist)); + + _com_util::CheckError(pPersist->InitNew()); + + _com_util::CheckError(m_pDoc->QueryInterface(IID_IMarkupServices, + (LPVOID*)&m_pMS)); + + if(m_pMS) + { + _com_util::CheckError(m_pMS->CreateMarkupPointer(&m_pMkStart)); + _com_util::CheckError(m_pMS->CreateMarkupPointer(&m_pMkFinish)); + } + } + catch(_com_error&/* e*/) + { +// show_com_error_msg(e); + } + +} + +CHTMLParserMS::~CHTMLParserMS() +{ + if(true == m_bCallUninit) + { + ::CoUninitialize(); + } +} + +CHTMLParserMS::THTMLNodePtr CHTMLParserMS::ParseString(const tstring& rsHTML) +{ + USES_CONVERSION; + + try + { + CGuard<CLightMutex> cs(m_cs); + + OLECHAR* p = T2OLE(const_cast<LPTSTR>(rsHTML.c_str())); + CComPtr<IMarkupContainer> pMC; + _com_util::CheckError(m_pMS->ParseString(p,0,&pMC,m_pMkStart,m_pMkFinish)); + + if(pMC) + { + CComPtr<IHTMLDocument2> pNewDoc; + + _com_util::CheckError(pMC->QueryInterface(IID_IHTMLDocument, + (LPVOID*)&pNewDoc)); + + if(pNewDoc) + { + CComPtr<IHTMLElementCollection> pColl; + _com_util::CheckError(pNewDoc->get_all(&pColl)); + + CHTMLNode::TDocumentPtr pDoc; + pMC->QueryInterface(IID_IHTMLDocument3,(LPVOID*)&pDoc); + + + return THTMLNodePtr(new CHTMLNode(CHTMLNode::TComPtr(pColl),pDoc)); + } + } + } + catch(_com_error&/* e*/) + { +// show_com_error_msg(e); + } + + return THTMLNodePtr(); +} + +bool CHTMLParserMS::IsInstalled() +{ + bool bResult = true; + bool bCallUninit = false; + try + { + CheckError(::CoInitialize(NULL)); + + bCallUninit = true; + + CComPtr<IHTMLDocument2> pDoc; + _com_util::CheckError( + ::CoCreateInstance(CLSID_HTMLDocument, + NULL, + CLSCTX_INPROC_SERVER, + IID_IHTMLDocument2, + reinterpret_cast<LPVOID*>(&pDoc)) + ); + } + catch(_com_error&/* e*/) + { + bResult = false; + } + + if(bCallUninit) + { + ::CoUninitialize(); + } + + return bResult; +} + +CHTMLEngineMS::CHTMLEngineMS() +{ + +} + +CHTMLEngineMS::~CHTMLEngineMS() +{ + +} + +CHTMLEngineMS::THTMLParserPtr CHTMLEngineMS::GetParserPtr()const +{ + return THTMLParserPtr(new CHTMLParserMS); +} diff --git a/protocols/Quotes/HTMLParserMS.h b/protocols/Quotes/HTMLParserMS.h new file mode 100644 index 0000000000..0773efa42a --- /dev/null +++ b/protocols/Quotes/HTMLParserMS.h @@ -0,0 +1,36 @@ +#ifndef __3c99e3f7_ecd9_4d9b_8f86_fe293c5fc8e6_HTMLParserMS_h__ +#define __3c99e3f7_ecd9_4d9b_8f86_fe293c5fc8e6_HTMLParserMS_h__ + +#include "ihtmlparser.h" +#include "LightMutex.h" +#include "IHTMLEngine.h" + +class CHTMLParserMS : public IHTMLParser +{ +public: + CHTMLParserMS(); + ~CHTMLParserMS(); + + virtual THTMLNodePtr ParseString(const tstring& rsHTML); + + static bool IsInstalled(); + +private: + bool m_bCallUninit; + CComPtr<IHTMLDocument2> m_pDoc; + CComPtr<IMarkupServices> m_pMS; + CComPtr<IMarkupPointer> m_pMkStart; + CComPtr<IMarkupPointer> m_pMkFinish; + mutable CLightMutex m_cs; +}; + +class CHTMLEngineMS : public IHTMLEngine +{ +public: + CHTMLEngineMS(); + ~CHTMLEngineMS(); + + virtual THTMLParserPtr GetParserPtr()const; +}; + +#endif //__3c99e3f7_ecd9_4d9b_8f86_fe293c5fc8e6_HTMLParserMS_h__ diff --git a/protocols/Quotes/HTTPSession.cpp b/protocols/Quotes/HTTPSession.cpp new file mode 100644 index 0000000000..aa66948ae9 --- /dev/null +++ b/protocols/Quotes/HTTPSession.cpp @@ -0,0 +1,262 @@ +#include "StdAfx.h" +#include "HTTPSession.h" +#include "EconomicRateInfo.h" +#include "LightMutex.h" + +class CHTTPSession::CImpl +{ +public: + CImpl() {} + virtual ~CImpl() {} + + virtual bool OpenURL(const tstring& rsURL) = 0; + virtual bool ReadResponce(tstring& rsResponce)const = 0; +}; + +namespace +{ +// class CImplMS : public CHTTPSession::CImpl +// { +// public: +// CImplMS() +// : m_hSession(::InternetOpen(_T("Dioksin"),PRE_CONFIG_INTERNET_ACCESS,NULL,INTERNET_INVALID_PORT_NUMBER,0)), +// m_hRequest(NULL) +// { +// +// } +// +// ~CImplMS() +// { +// if(m_hRequest) +// { +// ::InternetCloseHandle(m_hRequest); +// } +// +// if(m_hSession) +// { +// ::InternetCloseHandle(m_hSession); +// } +// } +// +// virtual bool OpenURL(const tstring& rsURL) +// { +// if(NULL == m_hSession) +// { +// return false; +// } +// +// if(NULL != m_hRequest) +// { +// ::InternetCloseHandle(m_hRequest); +// m_hRequest = NULL; +// } +// +// m_hRequest = ::InternetOpenUrl(m_hSession,rsURL.c_str(),NULL,0,INTERNET_FLAG_RELOAD,0); +// return NULL != m_hRequest; +// } +// +// virtual bool ReadResponce(tstring& rsResponce)const +// { +// if(NULL == m_hRequest) +// { +// return false; +// } +// +// std::string sBuffer; +// bool bResult = true; +// DWORD cbRead = 0; +// char szBuffer[1024]; +// do{ +// if(FALSE == ::InternetReadFile(m_hRequest,szBuffer,1024,&cbRead)) +// { +// bResult = false; +// break; +// } +// if (0 == cbRead) +// { +// break; // Stop. +// } +// else +// { +// sBuffer.insert(sBuffer.size(),szBuffer,cbRead); +// } +// }while(true); +// +// if(true == bResult) +// { +// USES_CONVERSION; +// rsResponce = A2CT(sBuffer.c_str()); +// } +// +// return bResult; +// } +// private: +// HINTERNET m_hSession; +// HINTERNET m_hRequest; +// }; +// + int find_header(const NETLIBHTTPREQUEST* pRequest,const char* hdr) + { + for(int i = 0;i < pRequest->headersCount; ++i) + { + if (0 == _stricmp(pRequest->headers[i].szName,hdr)) + { + return i; + } + } + + return -1; + } + + + class CImplMI : public CHTTPSession::CImpl + { + public: + CImplMI() {} + + static bool Init() + { + assert(NULL == g_hNetLib); + + NETLIBUSER nlu = {0}; + nlu.cbSize = sizeof(nlu); + nlu.flags = NUF_OUTGOING|NUF_HTTPCONNS|NUF_NOHTTPSOPTION|NUF_TCHAR; + nlu.szSettingsModule = QUOTES_PROTOCOL_NAME; + nlu.ptszDescriptiveName = TranslateT("Quotes HTTP connections"); + g_hNetLib = reinterpret_cast<HANDLE>(CallService(MS_NETLIB_REGISTERUSER,0,(LPARAM)&nlu)); + return (NULL != g_hNetLib); + } + + static bool IsValid(){return NULL != g_hNetLib;} + + virtual bool OpenURL(const tstring& rsURL) + { +// USES_CONVERSION; + + m_aURL.swap(TBuffer()); + + std::string s = quotes_t2a(rsURL.c_str()); + const char* psz = s.c_str();//T2CA(rsURL.c_str()); + m_aURL.insert(m_aURL.begin(),psz,psz+strlen(psz)+1); + return true; + + } + virtual bool ReadResponce(tstring& rsResponce)const + { + if(true == m_aURL.empty()) + { + return false; + } + + + NETLIBHTTPREQUEST nlhr = {0}; + nlhr.cbSize = sizeof(nlhr); + nlhr.requestType = REQUEST_GET; + nlhr.flags = NLHRF_DUMPASTEXT|NLHRF_HTTP11|NLHRF_REDIRECT; + char* pURL = &*(m_aURL.begin()); + nlhr.szUrl = pURL; + + nlhr.headersCount = 4; + nlhr.headers=(NETLIBHTTPHEADER*)mir_alloc(sizeof(NETLIBHTTPHEADER)*nlhr.headersCount); + nlhr.headers[0].szName = "User-Agent"; + nlhr.headers[0].szValue = "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1)"; + nlhr.headers[1].szName = "Connection"; + nlhr.headers[1].szValue = "close"; + nlhr.headers[2].szName = "Cache-Control"; + nlhr.headers[2].szValue = "no-cache"; + nlhr.headers[3].szName = "Pragma"; + nlhr.headers[3].szValue = "no-cache"; + // nlhr.headers[4].szName = "Accept-Encoding"; + // nlhr.headers[4].szValue = "deflate, gzip"; + // nlhr.headers[5].szName = "Cookie"; + // nlhr.headers[5].szValue = cookie; + + bool bResult = false; + NETLIBHTTPREQUEST* pReply = NULL; + + { + CGuard<CLightMutex> guard(m_mx); + pReply = reinterpret_cast<NETLIBHTTPREQUEST*>(CallService(MS_NETLIB_HTTPTRANSACTION, + reinterpret_cast<WPARAM>(g_hNetLib),reinterpret_cast<LPARAM>(&nlhr))); + } + + if(pReply) + { + if ((200 == pReply->resultCode) && (pReply->dataLength > 0)) + { + TBuffer apBuffer; + apBuffer.insert(apBuffer.begin(),pReply->pData,pReply->pData+pReply->dataLength); + apBuffer.push_back('\0'); + + char* pResult = &*(apBuffer.begin()); + int nIndex = find_header(pReply,"Content-Type"); + if ((-1 != nIndex) && (NULL != strstr(_strlwr(pReply->headers[nIndex].szValue),"utf-8"))) + { + TCHAR* p = mir_utf8decodeT(pResult); + rsResponce = p; + mir_free(p); + } + else + { +// USES_CONVERSION; +// LPCTSTR p = A2CT(pResult); + rsResponce = quotes_a2t(pResult);//p; + } + + bResult = true; + } + + CallService(MS_NETLIB_FREEHTTPREQUESTSTRUCT,0,reinterpret_cast<LPARAM>(pReply)); + } + + mir_free(nlhr.headers); + + return bResult; + } + + private: + static HANDLE g_hNetLib; + typedef std::vector<char> TBuffer; + mutable TBuffer m_aURL; + mutable CLightMutex m_mx; + }; + + HANDLE CImplMI::g_hNetLib = NULL; + +// CHTTPSession::CImpl* create_impl() +// { +// if(true == CImplMI::IsValid()) +// { +// return new CImplMI; +// } +// else +// { +// return new CImplMS; +// } +// } +} + + +CHTTPSession::CHTTPSession() + : m_pImpl(new CImplMI) +{ +} + +CHTTPSession::~CHTTPSession() +{ +} + +bool CHTTPSession::OpenURL(const tstring& rsURL) +{ + return m_pImpl->OpenURL(rsURL); +} + +bool CHTTPSession::ReadResponce(tstring& rsResponce)const +{ + return m_pImpl->ReadResponce(rsResponce); +} + +bool CHTTPSession::Init() +{ + return CImplMI::Init(); +} \ No newline at end of file diff --git a/protocols/Quotes/HTTPSession.h b/protocols/Quotes/HTTPSession.h new file mode 100644 index 0000000000..fe93a2dce5 --- /dev/null +++ b/protocols/Quotes/HTTPSession.h @@ -0,0 +1,27 @@ +#ifndef __8C9706FF_6B05_4d0d_85B8_5724E5DC0BA4_HTTPSession_h__ +#define __8C9706FF_6B05_4d0d_85B8_5724E5DC0BA4_HTTPSession_h__ + +#include <string> + +class CHTTPSession +{ +public: + CHTTPSession(); + ~CHTTPSession(); + + static bool Init(); + + bool OpenURL(const tstring& rsURL); + bool ReadResponce(tstring& rsResponce)const; + + +public: + class CImpl; +private: + typedef boost::scoped_ptr<CImpl> TImpl; + +private: + TImpl m_pImpl; +}; + +#endif //__8C9706FF_6B05_4d0d_85B8_5724E5DC0BA4_HTTPSession_h__ diff --git a/protocols/Quotes/IHTMLEngine.h b/protocols/Quotes/IHTMLEngine.h new file mode 100644 index 0000000000..7df3074d3e --- /dev/null +++ b/protocols/Quotes/IHTMLEngine.h @@ -0,0 +1,18 @@ +#ifndef __85dbfa97_919b_4776_919c_7410a1c3d787_HTMLEngine_h__ +#define __85dbfa97_919b_4776_919c_7410a1c3d787_HTMLEngine_h__ + +class IHTMLParser; + +class IHTMLEngine +{ +public: + typedef boost::shared_ptr<IHTMLParser> THTMLParserPtr; + +public: + IHTMLEngine(void){} + virtual ~IHTMLEngine() {} + + virtual THTMLParserPtr GetParserPtr()const = 0; +}; + +#endif //__85dbfa97_919b_4776_919c_7410a1c3d787_HTMLEngine_h__ diff --git a/protocols/Quotes/IHTMLParser.h b/protocols/Quotes/IHTMLParser.h new file mode 100644 index 0000000000..defc6f61cb --- /dev/null +++ b/protocols/Quotes/IHTMLParser.h @@ -0,0 +1,41 @@ +#ifndef __98ad6d6d_2a27_43fd_bf3e_c18416a45e54_IHTMLParser_h__ +#define __98ad6d6d_2a27_43fd_bf3e_c18416a45e54_IHTMLParser_h__ + +class IHTMLNode +{ +public: + typedef boost::shared_ptr<IHTMLNode> THTMLNodePtr; + + enum EType + { + Table = 1, + TableRow, + TableColumn + }; + +public: + IHTMLNode() {} + virtual ~IHTMLNode() {} + + virtual size_t GetChildCount()const = 0; + virtual THTMLNodePtr GetChildPtr(size_t nIndex) = 0; + virtual bool Is(EType nType)const = 0; + + virtual THTMLNodePtr GetElementByID(const tstring& rsID)const = 0; + + virtual tstring GetAttribute(const tstring& rsAttrName)const = 0; + virtual tstring GetText()const = 0; +}; + +class IHTMLParser +{ +public: + typedef IHTMLNode::THTMLNodePtr THTMLNodePtr; +public: + IHTMLParser() {} + virtual ~IHTMLParser() {} + + virtual THTMLNodePtr ParseString(const tstring& rsHTML) = 0; +}; + +#endif //__98ad6d6d_2a27_43fd_bf3e_c18416a45e54_IHTMLParser_h__ diff --git a/protocols/Quotes/IQuotesProvider.h b/protocols/Quotes/IQuotesProvider.h new file mode 100644 index 0000000000..a03a2a9bcd --- /dev/null +++ b/protocols/Quotes/IQuotesProvider.h @@ -0,0 +1,41 @@ +#pragma once + +#ifndef __ac71e133_786c_41a7_ab07_625b76ff2a8c_QuotesProvider_h__ +#define __ac71e133_786c_41a7_ab07_625b76ff2a8c_QuotesProvider_h__ + +#include <boost\noncopyable.hpp> +#include <string> + +class CQuotesProviderVisitor; + +class IQuotesProvider : private boost::noncopyable +{ +public: + struct CProviderInfo + { + tstring m_sName; + tstring m_sURL; + + }; + +public: + IQuotesProvider() {} + virtual ~IQuotesProvider() {} + + virtual bool Init() = 0; + virtual const CProviderInfo& GetInfo()const = 0; + + virtual void AddContact(HANDLE hContact) = 0; + virtual void DeleteContact(HANDLE hContact) = 0; + + virtual void ShowPropertyPage(WPARAM wp,OPTIONSDIALOGPAGE& odp) = 0; + virtual void RefreshAll() = 0; + virtual void RefreshContact(HANDLE hContact) = 0; + virtual void SetContactExtraIcon(HANDLE hContact)const = 0; + + virtual void Run() = 0; + + virtual void Accept(CQuotesProviderVisitor& visitor)const = 0; +}; + +#endif //__ac71e133_786c_41a7_ab07_625b76ff2a8c_QuotesProvider_h__ diff --git a/protocols/Quotes/IXMLEngine.h b/protocols/Quotes/IXMLEngine.h new file mode 100644 index 0000000000..910c3efea0 --- /dev/null +++ b/protocols/Quotes/IXMLEngine.h @@ -0,0 +1,43 @@ +#ifndef __f88e20d7_5e65_40fb_a7b5_7c7af1ee1c78_IXMLEngine_h__ +#define __f88e20d7_5e65_40fb_a7b5_7c7af1ee1c78_IXMLEngine_h__ + +class IXMLNode +{ +public: + typedef boost::shared_ptr<IXMLNode> TXMLNodePtr; + +public: + IXMLNode() {} + virtual ~IXMLNode() {} + + virtual size_t GetChildCount()const = 0; + virtual TXMLNodePtr GetChildNode(size_t nIndex)const = 0; + + virtual tstring GetText()const = 0; + virtual tstring GetName()const = 0; + + virtual bool AddChild(const TXMLNodePtr& pNode) = 0; + virtual bool AddAttribute(const tstring& rsName,const tstring& rsValue) = 0; + virtual tstring GetAttributeValue(const tstring& rsAttrName) = 0; + virtual void Write(tostream& o)const = 0; +}; + +inline tostream& operator<<(tostream& o,const IXMLNode& node) +{ + node.Write(o); + return o; +} + +class IXMLEngine +{ +public: + IXMLEngine() {} + + virtual ~IXMLEngine() {} + + virtual IXMLNode::TXMLNodePtr LoadFile(const tstring& rsFileName)const = 0; + virtual bool SaveFile(const tstring& rsFileName,const IXMLNode::TXMLNodePtr& pNode)const = 0; + virtual IXMLNode::TXMLNodePtr CreateNode(const tstring& rsName,const tstring& rsText)const = 0; +}; + +#endif //__f88e20d7_5e65_40fb_a7b5_7c7af1ee1c78_IXMLEngine_h__ diff --git a/protocols/Quotes/IconLib.cpp b/protocols/Quotes/IconLib.cpp new file mode 100644 index 0000000000..9702bfe3d8 --- /dev/null +++ b/protocols/Quotes/IconLib.cpp @@ -0,0 +1,106 @@ +#include "StdAfx.h" +#include "IconLib.h" +#include <m_icolib.h> +#include "resource.h" +#include "EconomicRateInfo.h" +// #include <newpluginapi.h> +#include <m_langpack.h> +#include <sstream> +#pragma warning (disable:4996) +#include <m_utils.h> +#pragma warning (default:4996) +#include "ModuleInfo.h" + +// extern HMODULE g_hInstance; + +namespace +{ + struct CIconList + { + TCHAR* szDescr; + char* szName; + int defIconID; +// TCHAR* szSection; + HANDLE hIconLibItem; + }; + + CIconList iconList[] = + { + {_T("Protocol icon"),ICON_STR_MAIN,IDI_ICON_MAIN}, + {_T("Quote/Rate up"),ICON_STR_QUOTE_UP,IDI_ICON_UP}, + {_T("Quote/Rate down"),ICON_STR_QUOTE_DOWN,IDI_ICON_DOWN}, + {_T("Quote/Rate not changed"),ICON_STR_QUOTE_NOT_CHANGED,IDI_ICON_NOTCHANGED}, + {_T("Quote Section"),ICON_STR_SECTION,IDI_ICON_SECTION}, + {_T("Quote"),ICON_STR_QUOTE,IDI_ICON_QUOTE}, + {_T("Currency Converter"),ICON_STR_CURRENCY_CONVERTER,IDI_ICON_CURRENCY_CONVERTER}, + {_T("Refresh"),ICON_STR_REFRESH,IDI_ICON_REFRESH}, + {_T("Export"),ICON_STR_EXPORT,IDI_ICON_EXPORT}, + {_T("Swap button"),ICON_STR_SWAP,IDI_ICON_SWAP}, + {_T("Import"),ICON_STR_IMPORT,IDI_ICON_IMPORT}, + }; +} + +void Quotes_IconsInit() +{ + USES_CONVERSION; + + SKINICONDESC sid = {0}; + TCHAR szFile[MAX_PATH]; + ::GetModuleFileName(CModuleInfo::GetModuleHandle(), szFile, MAX_PATH); + + sid.cbSize = sizeof(SKINICONDESC); + sid.ptszDefaultFile = szFile; + sid.cx = sid.cy = 16; + sid.flags = SIDF_ALL_TCHAR; + sid.ptszSection = A2T(QUOTES_PROTOCOL_NAME); + +// TCHAR* szRootSection = TranslateTS(A2T(QUOTES_PROTOCOL_NAME)); + + for ( int i = 0; i < SIZEOF(iconList); i++ ) + { +// char szSettingName[100]; +// TCHAR szSectionName[100]; +// mir_snprintf( szSettingName, sizeof( szSettingName ),"%s_%s",QUOTES_PROTOCOL_NAME, iconList[i].szName ); +// { +// mir_sntprintf( szSectionName, SIZEOF( szSectionName ),_T("%s/%s"), TranslateT("Protocols"), szRootSection); +// sid.ptszSection = szSectionName; +// } + + std::string sName = Quotes_MakeIconName( iconList[i].szName); + sid.pszName = const_cast<char*>(sName.c_str()); + sid.ptszDescription = iconList[i].szDescr; + sid.iDefaultIndex = -iconList[i].defIconID; + iconList[i].hIconLibItem = reinterpret_cast<HANDLE>(CallService(MS_SKIN2_ADDICON,0,reinterpret_cast<LPARAM>(&sid))); + } +} + +std::string Quotes_MakeIconName(const char* name) +{ + assert(name); + //char szSettingName[100]; + //mir_snprintf(szSettingName,SIZEOF(szSettingName),"%s_%s",QUOTES_PROTOCOL_NAME,name); + std::string sName(QUOTES_PROTOCOL_NAME); + sName += "_"; + sName += name; + return sName; +} + +HICON Quotes_LoadIconEx(const char* name,bool bBig /*= false*/) +{ + std::string sIconName = Quotes_MakeIconName(name); + return reinterpret_cast<HICON>(CallService( MS_SKIN2_GETICON,((bBig) ? 1 : 0),reinterpret_cast<LPARAM>(sIconName.c_str()))); +} + +HANDLE Quotes_GetIconHandle(int iconId) +{ + for(int i=0;i < SIZEOF(iconList);i++) + { + if(iconList[i].defIconID == iconId) + { + return iconList[i].hIconLibItem; + } + } + + return NULL; +} + diff --git a/protocols/Quotes/IconLib.h b/protocols/Quotes/IconLib.h new file mode 100644 index 0000000000..29b0326622 --- /dev/null +++ b/protocols/Quotes/IconLib.h @@ -0,0 +1,21 @@ +#ifndef __8821d334_afac_439e_9a81_76318e1ac4ef_IconLib_h__ +#define __8821d334_afac_439e_9a81_76318e1ac4ef_IconLib_h__ + +#define ICON_STR_MAIN "main" +#define ICON_STR_QUOTE_UP "quote_up" +#define ICON_STR_QUOTE_DOWN "quote_down" +#define ICON_STR_QUOTE_NOT_CHANGED "quote_not_changed" +#define ICON_STR_SECTION "quote_section" +#define ICON_STR_QUOTE "quote" +#define ICON_STR_CURRENCY_CONVERTER "currency_converter" +#define ICON_STR_REFRESH "refresh" +#define ICON_STR_IMPORT "import" +#define ICON_STR_EXPORT "export" +#define ICON_STR_SWAP "swap" + +void Quotes_IconsInit(); +HICON Quotes_LoadIconEx(const char* name,bool bBig = false); +HANDLE Quotes_GetIconHandle(int iconId); +std::string Quotes_MakeIconName(const char* name); + +#endif //__8821d334_afac_439e_9a81_76318e1ac4ef_IconLib_h__ diff --git a/protocols/Quotes/ImportExport.cpp b/protocols/Quotes/ImportExport.cpp new file mode 100644 index 0000000000..2e38be0c0f --- /dev/null +++ b/protocols/Quotes/ImportExport.cpp @@ -0,0 +1,850 @@ +#include "StdAfx.h" +#include "ImportExport.h" +#include "ModuleInfo.h" +#include "QuotesProviders.h" +#ifdef TEST_IMPORT_EXPORT +#include "m_Quotes.h" +#endif +#include "IXMLEngine.h" +#include "Base64.h" +#include "EconomicRateInfo.h" +#include "IQuotesProvider.h" +#include "QuotesProviderVisitor.h" +#include "QuotesProviderDukasCopy.h" +#include "QuotesProviderGoogle.h" +#include "QuotesProviderGoogleFinance.h" +#include "Locale.h" + +namespace +{ + LPCTSTR g_pszXmlValue = _T("Value"); + LPCTSTR g_pszXmlName = _T("Name"); + LPCTSTR g_pszXmlSetting = _T("Setting"); + LPCTSTR g_pszXmlModule = _T("Module"); + LPCTSTR g_pszXmlContact = _T("Contact"); + LPCTSTR g_pszXmlContacts = _T("Contacts"); + LPCTSTR g_pszXmlType = _T("type"); + LPCTSTR g_pszXmlTypeByte = _T("byte"); + LPCTSTR g_pszXmlTypeWord = _T("word"); + LPCTSTR g_pszXmlTypeDword = _T("dword"); + LPCTSTR g_pszXmlTypeAsciiz = _T("asciiz"); + LPCTSTR g_pszXmlTypeWchar = _T("wchar"); + LPCTSTR g_pszXmlTypeUtf8 = _T("utf8"); + LPCTSTR g_pszXmlTypeBlob = _T("blob"); + + struct CEnumContext + { + CModuleInfo::TXMLEnginePtr m_pXmlEngine; + IXMLNode::TXMLNodePtr m_pNode; + HANDLE m_hContact; + LPCSTR m_pszModule; + }; + + struct mir_safety_dbvar + { + mir_safety_dbvar(DBVARIANT* p) : m_p(p){} + ~mir_safety_dbvar(){DBFreeVariant(m_p);} + DBVARIANT* m_p; + }; + + static int enum_contact_settings(const char* szSetting,LPARAM lp) + { +// USES_CONVERSION; + CEnumContext* ctx = reinterpret_cast<CEnumContext*>(lp); + + DBVARIANT dbv; + DBCONTACTGETSETTING cgs; + + cgs.szModule = ctx->m_pszModule; + cgs.szSetting = szSetting; + cgs.pValue = &dbv; + if(0 == CallService(MS_DB_CONTACT_GETSETTING, + reinterpret_cast<WPARAM>(ctx->m_hContact), + reinterpret_cast<LPARAM>(&cgs))) + { + mir_safety_dbvar sdbvar(&dbv); + + tstring sType; + tostringstream sValue; + sValue.imbue(GetSystemLocale()); + + switch(dbv.type) + { + case DBVT_BYTE: + sValue << dbv.bVal; + sType = g_pszXmlTypeByte; + break; + case DBVT_WORD: + sValue << dbv.wVal; + sType = g_pszXmlTypeWord; + break; + case DBVT_DWORD: + sValue << dbv.dVal; + sType = g_pszXmlTypeDword; + break; + case DBVT_ASCIIZ: + sType = g_pszXmlTypeAsciiz; + if(dbv.pszVal) + { + sValue << dbv.pszVal; +// mir_safe_string<char> mss(mir_utf8encode(dbv.pszVal)); +// if(mss.m_p) +// { +// sValue << mss.m_p; +// } + } + break; + case DBVT_WCHAR: + sType = g_pszXmlTypeWchar; + if(dbv.pwszVal) + { + sValue << dbv.pwszVal; +// mir_safe_string<char> mss(mir_utf8encodeW(dbv.pwszVal)); +// if(mss.m_p) +// { +// sValue << mss.m_p; +// } + } + break; + case DBVT_UTF8: + sType = g_pszXmlTypeUtf8; + if(dbv.pszVal) + { + sValue << dbv.pszVal; + } + break; + case DBVT_BLOB: + sType = g_pszXmlTypeBlob; + if(dbv.pbVal) + { + std::vector<char> buf; + if(true == base64::encode(dbv.pbVal,dbv.cpbVal,buf)) + { + buf.push_back('\0'); + sValue << &*buf.begin(); + } + } + break; + } + +// mir_safe_string<char> mssSetting(mir_utf8encode(szSetting)); +// if(mssSetting.m_p) + { + IXMLNode::TXMLNodePtr pXmlSet = ctx->m_pXmlEngine->CreateNode(g_pszXmlSetting,tstring()); + if(pXmlSet) + { + IXMLNode::TXMLNodePtr pXmlName = ctx->m_pXmlEngine->CreateNode(g_pszXmlName,quotes_a2t(szSetting)); + + IXMLNode::TXMLNodePtr pXmlValue = ctx->m_pXmlEngine->CreateNode(g_pszXmlValue,sValue.str()); + if(pXmlName && pXmlValue) + { + pXmlValue->AddAttribute(g_pszXmlType,sType); + + pXmlSet->AddChild(pXmlName); + pXmlSet->AddChild(pXmlValue); + ctx->m_pNode->AddChild(pXmlSet); + } + } + } + } + + return 0; + } + + int EnumDbModules(const char* szModuleName, DWORD ofsModuleName, LPARAM lp) + { +// USES_CONVERSION; + CEnumContext* ctx = reinterpret_cast<CEnumContext*>(lp); + IXMLNode::TXMLNodePtr pXml = ctx->m_pNode; + IXMLNode::TXMLNodePtr pModule = ctx->m_pXmlEngine->CreateNode(g_pszXmlModule,quotes_a2t(szModuleName)/*A2CT(szModuleName)*/); + if(pModule) + { + ctx->m_pszModule = szModuleName; + ctx->m_pNode = pModule; + + DBCONTACTENUMSETTINGS dbces; + dbces.pfnEnumProc = &enum_contact_settings; + dbces.szModule = szModuleName; + dbces.lParam = reinterpret_cast<LPARAM>(ctx); + + CallService(MS_DB_CONTACT_ENUMSETTINGS,reinterpret_cast<WPARAM>(ctx->m_hContact),reinterpret_cast<LPARAM>(&dbces)); + if(pModule->GetChildCount() > 0) + { + pXml->AddChild(pModule); + } + ctx->m_pNode = pXml; + } + + return 0; + } + + IXMLNode::TXMLNodePtr export_contact(HANDLE hContact,const CModuleInfo::TXMLEnginePtr& pXmlEngine) + { + IXMLNode::TXMLNodePtr pNode = pXmlEngine->CreateNode(g_pszXmlContact,tstring()); + if(pNode) + { + CEnumContext ctx; + ctx.m_pXmlEngine = pXmlEngine; + ctx.m_pNode = pNode; + ctx.m_hContact = hContact; + + CallService(MS_DB_MODULES_ENUM,reinterpret_cast<WPARAM>(&ctx),reinterpret_cast<LPARAM>(EnumDbModules)); + } + return pNode; + } + + LPCTSTR prepare_filter(LPTSTR pszBuffer,size_t cBuffer) + { + LPTSTR p = pszBuffer; + LPCTSTR pszXml = TranslateT("Xml File (*.xml)"); + lstrcpyn(p,pszXml, (int)cBuffer); + size_t nLen = (int)lstrlen(pszXml)+1; + p+= nLen; + if(nLen < cBuffer) + { + lstrcpyn(p,_T("*.xml"),(int)(cBuffer-nLen)); + p+= 6; + nLen += 6; + } + + if(nLen < cBuffer) + { + LPCTSTR pszAll = TranslateT("All files (*.*)"); + lstrcpyn(p,pszAll,(int)(cBuffer-nLen)); + size_t n = lstrlen(pszAll)+1; + nLen += n; + p+= n; + } + + if(nLen < cBuffer) + { + lstrcpyn(p,_T("*.*"),(int)(cBuffer-nLen)); + p+= 4; + nLen += 4; + } + + if(nLen < cBuffer) + { + *p = _T('\0'); + } + + return pszBuffer; + } + + bool show_open_file_dialog(bool bOpen,tstring& rsFile) + { + TCHAR szBuffer[MAX_PATH]; + TCHAR szFilter[MAX_PATH]; + OPENFILENAME ofn; + memset(&ofn,0,sizeof(ofn)); + + ofn.lStructSize = sizeof(OPENFILENAME); + + ofn.hwndOwner = NULL; + ofn.lpstrFilter = prepare_filter(szFilter,MAX_PATH); + ofn.Flags = OFN_PATHMUSTEXIST|OFN_HIDEREADONLY|OFN_EXPLORER; + ofn.lpstrDefExt = _T("xml"); + if(true == bOpen) + { + ofn.Flags |= OFN_FILEMUSTEXIST; + } + else + { + ofn.Flags |= OFN_OVERWRITEPROMPT; + } + ofn.nMaxFile = MAX_PATH; + ofn.lpstrFile = szBuffer; + ofn.lpstrFile[0] = _T('\0'); + + if(bOpen) + { + if(FALSE == GetOpenFileName(&ofn)) + { + return false; + } + } + else + { + if(FALSE == GetSaveFileName(&ofn)) + { + return false; + } + } + + rsFile = szBuffer; + + return true; + } +} + +INT_PTR Quotes_Export(WPARAM wp,LPARAM lp) +{ +// USES_CONVERSION; + + tstring sFileName; + const char* pszFile = reinterpret_cast<const char*>(lp); + if(NULL == pszFile) + { + if(false == show_open_file_dialog(false,sFileName)) + { + return -1; + } + } + else + { + sFileName = quotes_a2t(pszFile);//A2CT(pszFile); + } + + CModuleInfo::TXMLEnginePtr pXmlEngine = CModuleInfo::GetInstance().GetXMLEnginePtr(); + CModuleInfo::TQuotesProvidersPtr pProviders = CModuleInfo::GetInstance().GetQuoteProvidersPtr(); + IXMLNode::TXMLNodePtr pRoot = pXmlEngine->CreateNode(g_pszXmlContacts,tstring()); + HANDLE hContact = reinterpret_cast<HANDLE>(wp); + if(hContact) + { + CQuotesProviders::TQuotesProviderPtr pProvider = pProviders->GetContactProviderPtr(hContact); + if(pProvider) + { + IXMLNode::TXMLNodePtr pNode = export_contact(hContact,pXmlEngine); + if(pNode) + { + pRoot->AddChild(pNode); + } + } + } + else + { + for(hContact = reinterpret_cast<HANDLE>(CallService(MS_DB_CONTACT_FINDFIRST,0,0));hContact;hContact = reinterpret_cast<HANDLE>(CallService(MS_DB_CONTACT_FINDNEXT,reinterpret_cast<WPARAM>(hContact),0))) + { + CQuotesProviders::TQuotesProviderPtr pProvider = pProviders->GetContactProviderPtr(hContact); + if(pProvider) + { + IXMLNode::TXMLNodePtr pNode = export_contact(hContact,pXmlEngine); + if(pNode) + { + pRoot->AddChild(pNode); + } + } + } + } + + return ((true == pXmlEngine->SaveFile(sFileName,pRoot)) ? 0 : 1); +} + +namespace +{ + bool set_contact_settings(HANDLE hContact,DBCONTACTWRITESETTING& dbs) + { + assert(DBVT_DELETED != dbs.value.type); + return (0 == CallService(MS_DB_CONTACT_WRITESETTING,reinterpret_cast<WPARAM>(hContact), + reinterpret_cast<LPARAM>(&dbs))); + } + + bool handle_module(HANDLE hContact,const IXMLNode::TXMLNodePtr& pXmlModule,UINT nFlags) + { +// USES_CONVERSION; + + size_t cCreatedRecords = 0; + tstring sModuleName = pXmlModule->GetText(); + if(false == sModuleName.empty()) + { + DBCONTACTWRITESETTING dbs; + std::string s = quotes_t2a(sModuleName.c_str()); + dbs.szModule = s.c_str();//T2CA(sModuleName.c_str()); + + bool bCListModule = 0 == quotes_stricmp(sModuleName.c_str(),_T("CList")); + + size_t cChild = pXmlModule->GetChildCount(); + for(size_t i = 0;i < cChild;++i) + { + IXMLNode::TXMLNodePtr pSetting = pXmlModule->GetChildNode(i); + tstring sSetting = pSetting->GetName(); + if(0 == quotes_stricmp(g_pszXmlSetting,sSetting.c_str())) + { + size_t cSetChild = pSetting->GetChildCount(); + if(cSetChild >= 2) + { + tstring sName; + tstring sValue; + tstring sType; + for(size_t i = 0;i < cSetChild;++i) + { + IXMLNode::TXMLNodePtr pNode = pSetting->GetChildNode(i); + tstring sNode = pNode->GetName(); + if(0 == quotes_stricmp(g_pszXmlName,sNode.c_str())) + { + sName = pNode->GetText(); + } + else if(0 == quotes_stricmp(g_pszXmlValue,sNode.c_str())) + { + sValue = pNode->GetText(); + sType = pNode->GetAttributeValue(g_pszXmlType); + } + } + + if ((false == sName.empty()) && (false == sType.empty())) + { + std::string s = quotes_t2a(sName.c_str()); + dbs.szSetting = s.c_str();//T2CA(sName.c_str()); + if(0 == quotes_stricmp(g_pszXmlTypeByte,sType.c_str())) + { + tistringstream in(sValue.c_str()); + in.imbue(GetSystemLocale()); + dbs.value.cVal = in.get(); + if(in.good() && in.eof()) + { + dbs.value.type = DBVT_BYTE; + if(set_contact_settings(hContact,dbs)) + { + ++cCreatedRecords; + } + } + } + else if(0 == quotes_stricmp(g_pszXmlTypeWord,sType.c_str())) + { + tistringstream in(sValue.c_str()); + in.imbue(GetSystemLocale()); + in >> dbs.value.wVal; + if(in.good() || in.eof()) + { + dbs.value.type = DBVT_WORD; + if(set_contact_settings(hContact,dbs)) + { + ++cCreatedRecords; + } + } + } + else if(0 == quotes_stricmp(g_pszXmlTypeDword,sType.c_str())) + { + tistringstream in(sValue.c_str()); + in.imbue(GetSystemLocale()); + in >> dbs.value.dVal; + if(in.good() || in.eof()) + { + dbs.value.type = DBVT_DWORD; + if(set_contact_settings(hContact,dbs)) + { + ++cCreatedRecords; + } + } + } + else if(0 == quotes_stricmp(g_pszXmlTypeAsciiz,sType.c_str())) + { + CT2A v(sValue.c_str()); + dbs.value.pszVal = v; + dbs.value.type = DBVT_ASCIIZ; + if(set_contact_settings(hContact,dbs)) + { + ++cCreatedRecords; + } + } + else if(0 == quotes_stricmp(g_pszXmlTypeUtf8,sType.c_str())) + { + dbs.value.pszVal = mir_utf8encodeT(sValue.c_str()); + dbs.value.type = DBVT_UTF8; + if(set_contact_settings(hContact,dbs)) + { + ++cCreatedRecords; + } + mir_free(dbs.value.pszVal); + } + else if(0 == quotes_stricmp(g_pszXmlTypeWchar,sType.c_str())) + { + CT2W val(sValue.c_str()); + dbs.value.pwszVal = val; + dbs.value.type = DBVT_WCHAR; + if(set_contact_settings(hContact,dbs)) + { + ++cCreatedRecords; + } + mir_free(dbs.value.pwszVal); + } + else if(0 == quotes_stricmp(g_pszXmlTypeBlob,sType.c_str())) + { + std::vector<BYTE> blob_buf; + std::string p = quotes_t2a(sValue.c_str());//T2A(sValue.c_str()); + if(true == base64::decode(p.c_str(),lstrlenA(p.c_str()),blob_buf)) + { + dbs.value.pbVal = &*blob_buf.begin(); + dbs.value.cpbVal = (WORD)blob_buf.size(); + dbs.value.type = DBVT_BLOB; + + if(set_contact_settings(hContact,dbs)) + { + ++cCreatedRecords; + } + } + } + + if ((true == bCListModule) && (0 == quotes_stricmp(sName.c_str(),_T("Group")))) + { + CallService(MS_CLIST_GROUPCREATE,NULL,reinterpret_cast<LPARAM>(sValue.c_str())); + } + } + } + } + } + } + + return true; + } + + size_t count_contacts(const IXMLNode::TXMLNodePtr& pXmlRoot,bool bInContactsGroup) + { + size_t cContacts = 0; + size_t cChild = pXmlRoot->GetChildCount(); + for(size_t i = 0;i < cChild;++i) + { + IXMLNode::TXMLNodePtr pNode = pXmlRoot->GetChildNode(i); + tstring sName = pNode->GetName(); + if(false == bInContactsGroup) + { + if(0 == quotes_stricmp(g_pszXmlContacts,sName.c_str())) + { + cContacts += count_contacts(pNode,true); + } + else + { + cContacts += count_contacts(pNode,false); + } + } + else + { + if(0 == quotes_stricmp(g_pszXmlContact,sName.c_str())) + { + ++ cContacts; + } + } + } + + return cContacts; + } + + struct CImportContext + { + CImportContext(size_t cTotalContacts) : m_cTotalContacts(cTotalContacts),m_cHandledContacts(0),m_nFlags(0){} + + size_t m_cTotalContacts; + size_t m_cHandledContacts; + UINT m_nFlags; + }; + + struct CContactState + { + CContactState() : m_hContact(NULL),m_bNewContact(false){} + HANDLE m_hContact; + CQuotesProviders::TQuotesProviderPtr m_pProvider; + bool m_bNewContact; + }; + + IXMLNode::TXMLNodePtr find_quotes_module(const IXMLNode::TXMLNodePtr& pXmlContact) + { +// USES_CONVERSION; +// LPCTSTR pszQuotes = A2T(QUOTES_MODULE_NAME); + static const tstring g_sQuotes = quotes_a2t(QUOTES_MODULE_NAME); + size_t cChild = pXmlContact->GetChildCount(); + for(size_t i = 0;i < cChild;++i) + { + IXMLNode::TXMLNodePtr pNode = pXmlContact->GetChildNode(i); + tstring sName = pNode->GetName(); + if ((0 == quotes_stricmp(g_pszXmlModule,sName.c_str())) + && (0 == quotes_stricmp(g_sQuotes.c_str(),pNode->GetText().c_str()))) + { + return pNode; + } + } + + return IXMLNode::TXMLNodePtr(); + } + + typedef std::pair<tstring,tstring> TNameValue;//first is name,second is value + TNameValue parse_setting_node(const IXMLNode::TXMLNodePtr& pXmlSetting) + { + assert(pXmlSetting); + + tstring sName,sValue; + size_t cSettingChildItems = pXmlSetting->GetChildCount(); + for(size_t j = 0;j < cSettingChildItems;++j) + { + IXMLNode::TXMLNodePtr pXMLSetChild = pXmlSetting->GetChildNode(j); + if(pXMLSetChild) + { + if(0 == quotes_stricmp(g_pszXmlName,pXMLSetChild->GetName().c_str())) + { + sName = pXMLSetChild->GetText(); + } + else if(0 == quotes_stricmp(g_pszXmlValue,pXMLSetChild->GetName().c_str())) + { + sValue = pXMLSetChild->GetText(); + } + } + } + + return std::make_pair(sName,sValue); + } + + CQuotesProviders::TQuotesProviderPtr find_provider(const IXMLNode::TXMLNodePtr& pXmlQuotesModule) + { +// USES_CONVERSION; + static const tstring g_sQuotesProvider = quotes_a2t(DB_STR_QUOTE_PROVIDER);//A2CT(DB_STR_QUOTE_PROVIDER); + size_t cChild = pXmlQuotesModule->GetChildCount(); + for(size_t i = 0;i < cChild;++i) + { + IXMLNode::TXMLNodePtr pXMLSetting = pXmlQuotesModule->GetChildNode(i); + if(pXMLSetting && (0 == quotes_stricmp(g_pszXmlSetting,pXMLSetting->GetName().c_str()))) + { + TNameValue Item = parse_setting_node(pXMLSetting); + if ((0 == quotes_stricmp(g_sQuotesProvider.c_str(),Item.first.c_str())) && (false == Item.second.empty())) + { + return CModuleInfo::GetInstance().GetQuoteProvidersPtr()->FindProvider(Item.second); + } + } + } + + return CQuotesProviders::TQuotesProviderPtr(); + } + + bool get_contact_state(const IXMLNode::TXMLNodePtr& pXmlContact,CContactState& cst) + { + class visitor : public CQuotesProviderVisitor + { + public: + visitor(const IXMLNode::TXMLNodePtr& pXmlQuotes) + : m_hContact(NULL),m_pXmlQuotes(pXmlQuotes){} + + HANDLE GetContact()const{return m_hContact;} + + private: + virtual void Visit(const CQuotesProviderDukasCopy& rProvider) + { + tstring sQuoteID = GetXMLNodeValue(DB_STR_QUOTE_ID); + if(false == sQuoteID.empty()) + { + m_hContact = rProvider.GetContactByQuoteID(sQuoteID); + } + } + + virtual void Visit(const CQuotesProviderGoogle& rProvider) + { +// USES_CONVERSION; + static const tstring g_sFromID = quotes_a2t(DB_STR_FROM_ID);//A2CT(DB_STR_FROM_ID); + static const tstring g_sToID = quotes_a2t(DB_STR_TO_ID);//A2CT(DB_STR_TO_ID); + + tstring sFromID; + tstring sToID; + size_t cChild = m_pXmlQuotes->GetChildCount(); + for(size_t i = 0;i < cChild;++i) + { + IXMLNode::TXMLNodePtr pNode = m_pXmlQuotes->GetChildNode(i); + if(pNode && (0 == quotes_stricmp(g_pszXmlSetting, pNode->GetName().c_str()))) + { + TNameValue Item = parse_setting_node(pNode); + if(0 == quotes_stricmp(g_sFromID.c_str(),Item.first.c_str())) + { + sFromID = Item.second; + } + else if(0 == quotes_stricmp(g_sToID.c_str(),Item.first.c_str())) + { + sToID = Item.second; + } + } + } + + if ((false == sFromID.empty()) && (false == sToID.empty())) + { + m_hContact = rProvider.GetContactByID(sFromID,sToID); + } + } + + virtual void Visit(const CQuotesProviderFinance& rProvider) + { + tstring sQuoteID = GetXMLNodeValue(DB_STR_QUOTE_ID); + if(false == sQuoteID.empty()) + { + m_hContact = rProvider.GetContactByQuoteID(sQuoteID); + } + } + + tstring GetXMLNodeValue(const char* pszXMLNodeName)const + { +// USES_CONVERSION; + tstring sXMLNodeName = quotes_a2t(pszXMLNodeName);//A2CT(pszXMLNodeName); + + tstring sValue; + size_t cChild = m_pXmlQuotes->GetChildCount(); + for(size_t i = 0;i < cChild;++i) + { + IXMLNode::TXMLNodePtr pNode = m_pXmlQuotes->GetChildNode(i); + if(pNode && (0 == quotes_stricmp(g_pszXmlSetting, pNode->GetName().c_str()))) + { + TNameValue Item = parse_setting_node(pNode); + if(0 == quotes_stricmp(Item.first.c_str(),sXMLNodeName.c_str())) + { + sValue = Item.second; + break; + } + } + } + + return sValue; + } + + private: + HANDLE m_hContact; + IXMLNode::TXMLNodePtr m_pXmlQuotes; + }; + + IXMLNode::TXMLNodePtr pXmlQuotes = find_quotes_module(pXmlContact); + if(pXmlQuotes) + { + cst.m_pProvider = find_provider(pXmlQuotes); + if(cst.m_pProvider) + { + visitor vs(pXmlQuotes); + cst.m_pProvider->Accept(vs); + cst.m_hContact = vs.GetContact(); + return true; + } + } + + return false; + } + + bool import_contact(const IXMLNode::TXMLNodePtr& pXmlContact,CImportContext& impctx) + { + ++ impctx.m_cHandledContacts; + + CContactState cst; + bool bResult = get_contact_state(pXmlContact,cst); + if(bResult) + { + if(NULL == cst.m_hContact) + { + cst.m_hContact = reinterpret_cast<HANDLE>(CallService(MS_DB_CONTACT_ADD,0,0)); + cst.m_bNewContact = true; + } + else if(impctx.m_nFlags"ES_IMPORT_SKIP_EXISTING_CONTACTS) + { + return true; + } + + if(cst.m_hContact) + { + size_t cChild = pXmlContact->GetChildCount(); + for(size_t i = 0;i < cChild && bResult;++i) + { + IXMLNode::TXMLNodePtr pNode = pXmlContact->GetChildNode(i); + tstring sName = pNode->GetName(); + if(0 == quotes_stricmp(g_pszXmlModule,sName.c_str())) + { + bResult &= handle_module(cst.m_hContact,pNode,impctx.m_nFlags); + } + } + + if(cst.m_bNewContact && bResult) + { + cst.m_pProvider->AddContact(cst.m_hContact); + cst.m_pProvider->RefreshContact(cst.m_hContact); + } + } + else + { + bResult = false; + } + } + + return bResult; + + } + + size_t import_contacts(const IXMLNode::TXMLNodePtr& pXmlContacts,CImportContext& impctx) + { + size_t cContacts = 0; + size_t cChild = pXmlContacts->GetChildCount(); + for(size_t i = 0;i < cChild;++i) + { + IXMLNode::TXMLNodePtr pNode = pXmlContacts->GetChildNode(i); + tstring sName = pNode->GetName(); + if(0 == quotes_stricmp(g_pszXmlContact,sName.c_str())) + { + if(true == import_contact(pNode,impctx)) + { + ++ cContacts; + } + } + } + + return cContacts; + + } + + size_t handle_contacts_node(const IXMLNode::TXMLNodePtr& pXmlRoot,CImportContext& impctx) + { + size_t cContacts = 0; + size_t cChild = pXmlRoot->GetChildCount(); + for(size_t i = 0;i < cChild;++i) + { + IXMLNode::TXMLNodePtr pNode = pXmlRoot->GetChildNode(i); + tstring sName = pNode->GetName(); + if(0 == quotes_stricmp(g_pszXmlContacts,sName.c_str())) + { + cContacts += import_contacts(pNode,impctx); + } + else + { + cContacts += handle_contacts_node(pNode,impctx); + } + } + + return cContacts; + + } + + bool do_import(const IXMLNode::TXMLNodePtr& pXmlRoot,UINT nFlags) + { + CImportContext imctx(count_contacts(pXmlRoot,false)); + imctx.m_cHandledContacts = 0; + imctx.m_nFlags = nFlags; + + return (handle_contacts_node(pXmlRoot,imctx) > 0); + } +} + +INT_PTR Quotes_Import(WPARAM wp,LPARAM lp) +{ +// USES_CONVERSION; + + tstring sFileName; + const char* pszFile = reinterpret_cast<const char*>(lp); + if(NULL == pszFile) + { + if(false == show_open_file_dialog(true,sFileName)) + { + return -1; + } + } + else + { + sFileName = quotes_a2t(pszFile);//A2CT(pszFile); + } + CModuleInfo::TXMLEnginePtr pXmlEngine = CModuleInfo::GetInstance().GetXMLEnginePtr(); + IXMLNode::TXMLNodePtr pXmlRoot = pXmlEngine->LoadFile(sFileName); + if(pXmlRoot) + { + return ((true == do_import(pXmlRoot,wp)) ? 0 : 1); + } + + return 1; +} + +#ifdef TEST_IMPORT_EXPORT +INT_PTR QuotesMenu_ImportAll(WPARAM wp,LPARAM lp) +{ + return CallService(MS_QUOTES_IMPORT,0,0); +} + +INT_PTR QuotesMenu_ExportAll(WPARAM wp,LPARAM lp) +{ + return CallService(MS_QUOTES_EXPORT,0,0); +} +#endif + diff --git a/protocols/Quotes/ImportExport.h b/protocols/Quotes/ImportExport.h new file mode 100644 index 0000000000..da2053e9a3 --- /dev/null +++ b/protocols/Quotes/ImportExport.h @@ -0,0 +1,11 @@ +#ifndef __F86374E6_713C_4600_85FB_903A5CDF7251_IMPORT_EXPORT_H__ +#define __F86374E6_713C_4600_85FB_903A5CDF7251_IMPORT_EXPORT_H__ + +INT_PTR Quotes_Export(WPARAM wp,LPARAM lp); +INT_PTR Quotes_Import(WPARAM wp,LPARAM lp); + +#ifdef TEST_IMPORT_EXPORT +INT_PTR QuotesMenu_ImportAll(WPARAM wp,LPARAM lp); +INT_PTR QuotesMenu_ExportAll(WPARAM wp,LPARAM lp); +#endif +#endif //__F86374E6_713C_4600_85FB_903A5CDF7251_IMPORT_EXPORT_H__ diff --git a/protocols/Quotes/IsWithinAccuracy.h b/protocols/Quotes/IsWithinAccuracy.h new file mode 100644 index 0000000000..5e39281719 --- /dev/null +++ b/protocols/Quotes/IsWithinAccuracy.h @@ -0,0 +1,15 @@ +#ifndef __C8C6FB80_D66B_4382_8FAB_E92C83F77BB8_IsWithinAcuracy_h__ +#define __C8C6FB80_D66B_4382_8FAB_E92C83F77BB8_IsWithinAcuracy_h__ + +inline bool IsWithinAccuracy(double dValue1, double dValue2, double dAccuracy = 1e-4) +{ + double dDifference = dValue1 - dValue2 ; + + if ((-dAccuracy <= dDifference) && (dDifference <= dAccuracy)) + return true ; + else + return false ; +} + + +#endif //__C8C6FB80_D66B_4382_8FAB_E92C83F77BB8_IsWithinAcuracy_h__ diff --git a/protocols/Quotes/LightMutex.cpp b/protocols/Quotes/LightMutex.cpp new file mode 100644 index 0000000000..8d14e8e7bb --- /dev/null +++ b/protocols/Quotes/LightMutex.cpp @@ -0,0 +1,22 @@ +#include "StdAfx.h" +#include "LightMutex.h" + +CLightMutex::CLightMutex() +{ + InitializeCriticalSection(&m_cs); +} + +CLightMutex::~CLightMutex() +{ + ::DeleteCriticalSection(&m_cs); +} + +void CLightMutex::Lock() +{ + ::EnterCriticalSection(&m_cs); +} + +void CLightMutex::Unlock() +{ + ::LeaveCriticalSection(&m_cs); +} diff --git a/protocols/Quotes/LightMutex.h b/protocols/Quotes/LightMutex.h new file mode 100644 index 0000000000..e8c7363ba1 --- /dev/null +++ b/protocols/Quotes/LightMutex.h @@ -0,0 +1,34 @@ +#ifndef __a33da2bb_d4fe4aa7_aaf5_f9f8c3156ce6_LightMutex_h__ +#define __a33da2bb_d4fe4aa7_aaf5_f9f8c3156ce6_LightMutex_h__ + +class CLightMutex +{ +public: + CLightMutex(); + ~CLightMutex(); + + void Lock(); + void Unlock(); + +private: + CRITICAL_SECTION m_cs; +}; + +template<class TObject> class CGuard +{ +public: + CGuard(TObject& obj) : m_obj(obj) + { + m_obj.Lock(); + } + + ~CGuard() + { + m_obj.Unlock(); + } + +private: + TObject& m_obj; +}; + +#endif //__a33da2bb_d4fe4aa7_aaf5_f9f8c3156ce6_LightMutex_h__ diff --git a/protocols/Quotes/Locale.cpp b/protocols/Quotes/Locale.cpp new file mode 100644 index 0000000000..c01f67148a --- /dev/null +++ b/protocols/Quotes/Locale.cpp @@ -0,0 +1,75 @@ +#include "StdAfx.h" +#include "Locale.h" + +const std::locale GetSystemLocale() +{ + return std::locale(""); +} + +namespace +{ + tstring get_int_registry_value(LPCTSTR pszValueName) + { + tstring sResult; + HKEY hKey = NULL; + LONG lResult = ::RegOpenKeyEx(HKEY_CURRENT_USER, + _T("Control Panel\\International"),0,KEY_QUERY_VALUE,&hKey); + if ((ERROR_SUCCESS == lResult) && (NULL != hKey)) + { + DWORD dwType = 0; + DWORD dwSize = 0; + lResult = ::RegQueryValueEx(hKey,pszValueName,nullptr,&dwType,nullptr,&dwSize); + if ((ERROR_SUCCESS == lResult) && ((REG_SZ == dwType) || (REG_EXPAND_SZ == dwType))) + { + std::vector<TCHAR> aBuffer(dwSize); + lResult = ::RegQueryValueEx(hKey,pszValueName,nullptr,nullptr,reinterpret_cast<LPBYTE>(&*aBuffer.begin()),&dwSize); + if(ERROR_SUCCESS == lResult) + { + std::copy(aBuffer.begin(),aBuffer.end(),std::back_inserter(sResult)); + } + } + } + + if(NULL != hKey) + { + lResult = ::RegCloseKey(hKey); + assert(ERROR_SUCCESS == lResult); + } + + return sResult; + } + + tstring date_win_2_boost(const tstring& sFrmt) + { + tstring sResult(_T("%d.%m.%y")); + if(sFrmt == _T("dd/MM/yy")) + { + sResult = _T("%d/%m/%y"); + } + else if(sFrmt == _T("yyyy-MM-dd")) + { + sResult = _T("%y-%m-%d"); + } + return sResult; + } + + tstring time_win_2_boost(const tstring& sFrmt) + { + tstring sResult = _T("%H:%M:%S"); + if(sFrmt == _T("H:mm") || sFrmt == _T("HH:mm")) + { + sResult = _T("%H:%M"); + } + return sResult; + } +} + +tstring Quotes_GetDateFormat(bool bShort) +{ + return date_win_2_boost(get_int_registry_value(bShort ? _T("sShortDate") : _T("sLongDate"))); +} + +tstring Quotes_GetTimeFormat(bool bShort) +{ + return time_win_2_boost(get_int_registry_value(bShort ? _T("sShortTime") : _T("sTimeFormat"))); +} \ No newline at end of file diff --git a/protocols/Quotes/Locale.h b/protocols/Quotes/Locale.h new file mode 100644 index 0000000000..92d3a56ed4 --- /dev/null +++ b/protocols/Quotes/Locale.h @@ -0,0 +1,9 @@ +#ifndef __11f7afd0_5a66_4029_8bf3_e3c66346b349_Locale_h_ +#define __11f7afd0_5a66_4029_8bf3_e3c66346b349_Locale_h_ + +// std::string GetLocaleInfoString(LCTYPE LCType,LCID Locale = LOCALE_USER_DEFAULT); +const std::locale GetSystemLocale(); +tstring Quotes_GetDateFormat(bool bShort); +tstring Quotes_GetTimeFormat(bool bShort); + +#endif //__11f7afd0_5a66_4029_8bf3_e3c66346b349_Locale_h_ diff --git a/protocols/Quotes/Log.cpp b/protocols/Quotes/Log.cpp new file mode 100644 index 0000000000..d692763bad --- /dev/null +++ b/protocols/Quotes/Log.cpp @@ -0,0 +1,56 @@ +#include "StdAfx.h" +#include "Log.h" +#include "LightMutex.h" +#include "EconomicRateInfo.h" +#include "CreateFilePath.h" + +namespace +{ + CLightMutex g_Mutex; + + tstring get_log_file_name() + { + return CreateFilePath(_T("Quotes.log")); + } + + bool is_log_enabled() + { +#ifdef _DEBUG + return true; +#else + return (1 == DBGetContactSettingByte(NULL,QUOTES_PROTOCOL_NAME,DB_STR_ENABLE_LOG,false)); +#endif + } + + void do_log(const tstring& rsFileName,ESeverity nSeverity,const tstring& rsMsg) + { + CGuard<CLightMutex> guard(g_Mutex); + tofstream file(rsFileName.c_str(),std::ios::ate|std::ios::app); + if(file.good()) + { + TCHAR szTime[20]; +// TCHAR sz[10000+1]; + _tstrtime_s(szTime); + file << szTime << _T(" ================================>\n") << rsMsg << _T("\n\n"); + +// size_t cBytes = rsMsg.size(); +// const TCHAR* p = rsMsg.c_str(); +// for(size_t c = 0;c < cBytes;c += 10000,p+=10000) +// { +// _tcsncpy_s(sz,p,10000); +// file << sz; +// } +// +// file << "\n\n"; + } + } +} + +void LogIt(ESeverity nSeverity,const tstring& rsMsg) +{ + if(is_log_enabled()) + { + tstring sFileName = get_log_file_name(); + do_log(sFileName,nSeverity,rsMsg); + } +} diff --git a/protocols/Quotes/Log.h b/protocols/Quotes/Log.h new file mode 100644 index 0000000000..274fcfec06 --- /dev/null +++ b/protocols/Quotes/Log.h @@ -0,0 +1,13 @@ +#ifndef __653719be_16d6_4058_8555_8aa7d5404214_OutputDlg_h__ +#define __653719be_16d6_4058_8555_8aa7d5404214_OutputDlg_h__ + +enum ESeverity +{ + Info, + Warning, + Error +}; + +void LogIt(ESeverity nSeverity,const tstring& rsMsg); + +#endif //__653719be_16d6_4058_8555_8aa7d5404214_OutputDlg_h__ diff --git a/protocols/Quotes/ModuleInfo.cpp b/protocols/Quotes/ModuleInfo.cpp new file mode 100644 index 0000000000..69a835409e --- /dev/null +++ b/protocols/Quotes/ModuleInfo.cpp @@ -0,0 +1,150 @@ +#include "StdAfx.h" +#include "ModuleInfo.h" +#include "QuotesProviders.h" +#include "HTMLParserMS.h" +#include "LightMutex.h" +#include "WinCtrlHelper.h" +#include "EconomicRateInfo.h" +#include "XMLEngineMI.h" + +namespace +{ + HINSTANCE g_hInstance = NULL; + CModuleInfo::TXMLEnginePtr g_pXMLEngine; + CModuleInfo::THTMLEnginePtr g_pHTMLEngine; + CLightMutex g_lmParsers; +} + +CModuleInfo::CModuleInfo() + : m_bExtendedStatusInfo(1 == DBGetContactSettingByte(NULL,QUOTES_MODULE_NAME,"ExtendedStatus",false)) +{ +} + +CModuleInfo::~CModuleInfo() +{ +} + +CModuleInfo& CModuleInfo::GetInstance() +{ + static CModuleInfo mi; + return mi; +} + +HANDLE CModuleInfo::GetWindowList(const std::string& rsKey,bool bAllocateIfNonExist /*= true*/) +{ + HANDLE hResult = NULL; + THandles::const_iterator i = m_ahWindowLists.find(rsKey); + if(i != m_ahWindowLists.end()) + { + hResult = i->second; + } + else if(bAllocateIfNonExist) + { + hResult = reinterpret_cast<HANDLE>(CallService(MS_UTILS_ALLOCWINDOWLIST,0,0)); + if(hResult) + { + m_ahWindowLists.insert(std::make_pair(rsKey,hResult)); + } + } + + return hResult; +} + +void CModuleInfo::OnMirandaShutdown() +{ + BOOST_FOREACH(THandles::value_type p,m_ahWindowLists) + { + WindowList_Broadcast(p.second,WM_CLOSE,0,0); + } +} + +void CModuleInfo::SetModuleHandle(HINSTANCE hInstance) +{ + assert(NULL == g_hInstance); + assert(NULL != hInstance); + + g_hInstance = hInstance; +} + +HINSTANCE CModuleInfo::GetModuleHandle() +{ + assert(NULL != g_hInstance); + return g_hInstance; +} + +CModuleInfo::TQuotesProvidersPtr CModuleInfo::GetQuoteProvidersPtr() +{ + static TQuotesProvidersPtr pProviders(new CQuotesProviders); + return pProviders; +} + +CModuleInfo::TXMLEnginePtr CModuleInfo::GetXMLEnginePtr() +{ + if (!g_pXMLEngine) + { + CGuard<CLightMutex> cs(g_lmParsers); + if (!g_pXMLEngine) + { + mir_getXI(&xi); + g_pXMLEngine = TXMLEnginePtr(new CXMLEngineMI); + } + } + + return g_pXMLEngine; +} + +// void CModuleInfo::SetXMLEnginePtr(TXMLEnginePtr pEngine) +// { +// g_pXMLEngine = pEngine; +// } + +CModuleInfo::THTMLEnginePtr CModuleInfo::GetHTMLEngine() +{ + if (!g_pHTMLEngine) + { + CGuard<CLightMutex> cs(g_lmParsers); + if (!g_pHTMLEngine) + { + g_pHTMLEngine = THTMLEnginePtr(new CHTMLEngineMS); + } + } + + return g_pHTMLEngine; +} + +void CModuleInfo::SetHTMLEngine(THTMLEnginePtr pEngine) +{ + g_pHTMLEngine = pEngine; +} + +bool CModuleInfo::Verify() +{ + INITCOMMONCONTROLSEX icc = {0}; + icc.dwSize = sizeof(icc); + icc.dwICC = ICC_WIN95_CLASSES|ICC_LINK_CLASS; + if(FALSE == ::InitCommonControlsEx(&icc)) + { + return false; + } + + if (!GetXMLEnginePtr()) + { + Quotes_MessageBox(NULL,TranslateT("Miranda could not load Quotes plugin. XML parser is missing."),MB_OK|MB_ICONERROR); + return false; + } + + if (!g_pHTMLEngine && (false == CHTMLParserMS::IsInstalled())) + { + Quotes_MessageBox(NULL, + TranslateT("Miranda could not load Quotes plugin. Microsoft HTML parser is missing."), + MB_YESNO|MB_ICONQUESTION); + return false; + } + + return true; +} + +bool CModuleInfo::GetExtendedStatusFlag()const +{ + return m_bExtendedStatusInfo; +} diff --git a/protocols/Quotes/ModuleInfo.h b/protocols/Quotes/ModuleInfo.h new file mode 100644 index 0000000000..5dcf7e5de6 --- /dev/null +++ b/protocols/Quotes/ModuleInfo.h @@ -0,0 +1,46 @@ +#ifndef __d0f22b66_3135_4bbe_bee5_a31ea631ce58_ModuleInfo__ +#define __d0f22b66_3135_4bbe_bee5_a31ea631ce58_ModuleInfo__ + +class CQuotesProviders; +class IXMLEngine; +class IHTMLEngine; +// class IHTMLParser; + +class CModuleInfo +{ +public: + typedef boost::shared_ptr<CQuotesProviders> TQuotesProvidersPtr; + typedef boost::shared_ptr<IXMLEngine> TXMLEnginePtr; + typedef boost::shared_ptr<IHTMLEngine> THTMLEnginePtr; + +private: + CModuleInfo(); + ~CModuleInfo(void); + +public: + static CModuleInfo& GetInstance(); + + void OnMirandaShutdown(); + HANDLE GetWindowList(const std::string& rsKey,bool bAllocateIfNonExist = true); + bool GetExtendedStatusFlag()const; + + static void SetModuleHandle(HINSTANCE hInstance); + static HINSTANCE GetModuleHandle(); + + static bool Verify(); + + static TQuotesProvidersPtr GetQuoteProvidersPtr(); + + static TXMLEnginePtr GetXMLEnginePtr(); +// static void SetXMLEnginePtr(TXMLEnginePtr pEngine); + + static THTMLEnginePtr GetHTMLEngine(); + static void SetHTMLEngine(THTMLEnginePtr pEngine); + +private: + typedef std::map<std::string,HANDLE> THandles; + THandles m_ahWindowLists; + bool m_bExtendedStatusInfo; +}; + +#endif //__d0f22b66_3135_4bbe_bee5_a31ea631ce58_ModuleInfo__ diff --git a/protocols/Quotes/OptionDukasCopy.cpp b/protocols/Quotes/OptionDukasCopy.cpp new file mode 100644 index 0000000000..1aef56b824 --- /dev/null +++ b/protocols/Quotes/OptionDukasCopy.cpp @@ -0,0 +1,414 @@ +#include "StdAfx.h" +#include "OptionDukasCopy.h" +#include "IconLib.h" +#include "ModuleInfo.h" +#include "QuotesProviders.h" +#include "QuotesProviderDukasCopy.h" +#include "resource.h" +#include "EconomicRateInfo.h" +#include "CommonOptionDlg.h" + +// extern HANDLE g_hEventSettingsCnanged; + +namespace +{ + enum ETreeCheckBoxState + { + // tree check box state + TCBS_NOSTATEBOX = 0, + TCBS_UNCHECKED = 1, + TCBS_CHECKED = 2, + }; + + enum + { + TREE_VIEW_CHECK_STATE_CHANGE = WM_USER + 100, + IMAGE_INDEX_SECTION = 0, + IMAGE_INDEX_QUOTE = 1 + }; + + // typedef CQuotesProviders::TQuotesProviders TQuotesProviders; + // typedef CQuotesProviders::TQuotesProviderPtr TQuotesProviderPtr; + + HTREEITEM tree_insert_item(HWND hwndTree, + const tstring& rsName, + HTREEITEM htiParent, + int nImage, + LPARAM lp = 0) + { +// USES_CONVERSION; + TVINSERTSTRUCT tvi; + ZeroMemory(&tvi,sizeof(tvi)); + + tvi.hParent = htiParent; + tvi.hInsertAfter = TVI_LAST; + tvi.item.mask = TVIF_TEXT|TVIF_PARAM|TVIF_IMAGE|TVIF_SELECTEDIMAGE; + +// CA2T name(rsName.c_str()); + + tvi.item.pszText = const_cast<LPTSTR>(rsName.c_str());//name; + tvi.item.lParam = lp; + tvi.item.iImage = nImage; + tvi.item.iSelectedImage = nImage; + return TreeView_InsertItem(hwndTree,&tvi); + } + + bool add_quote_to_tree(const CQuotesProviderDukasCopy::CQuote& q,HWND hwndTree,HTREEITEM htiParent,const CQuotesProviderDukasCopy* pQuotesProvier) + { + bool bChecked = pQuotesProvier->IsQuoteWatched(q); + HTREEITEM hti = tree_insert_item(hwndTree,((false == q.GetName().empty()) ? q.GetName() : q.GetSymbol()),htiParent,IMAGE_INDEX_QUOTE); + if(hti && bChecked) + { + HWND hDlg = ::GetParent(hwndTree); + assert(::IsWindow(hDlg)); + ::PostMessage(hDlg,TREE_VIEW_CHECK_STATE_CHANGE,MAKEWPARAM(0,TCBS_CHECKED),reinterpret_cast<LPARAM>(hti)); + } + + return (NULL != hti && bChecked); + } + + void add_section_to_tree(const CQuotesProviderDukasCopy::CQuoteSection& qs, + HWND hwndTree, + HTREEITEM htiParent, + const CQuotesProviderDukasCopy* pQuotesProvier, + bool& rbIsChecked, + bool& rbIsExpended, + bool bExpand = false) + { + rbIsChecked = false; + rbIsExpended = false; + HTREEITEM hti = tree_insert_item(hwndTree,qs.GetName(),htiParent,IMAGE_INDEX_SECTION); + + size_t cCheckedItems = 0; + size_t cSection = qs.GetSectionCount(); + for(size_t i = 0;i < cSection;++i) + { + bool bIsChecked = false; + bool bIsExpanded = false; + CQuotesProviderDukasCopy::CQuoteSection other = qs.GetSection(i); + add_section_to_tree(other,hwndTree,hti,pQuotesProvier,bIsChecked,bIsExpanded); + + if(bIsChecked) + { + ++cCheckedItems; + } + + if(bIsExpanded) + { + bExpand = true; + } + } + + size_t cQuotes = qs.GetQuoteCount(); + for(size_t i = 0;i < cQuotes;++i) + { + CQuotesProviderDukasCopy::CQuote q = qs.GetQuote(i); + if(true == add_quote_to_tree(q,hwndTree,hti,pQuotesProvier)) + { + ++ cCheckedItems; + } + } + + if(bExpand || cCheckedItems > 0) + { + rbIsExpended = true; + TreeView_Expand(hwndTree,hti,TVE_EXPAND); + } + + if(cCheckedItems == (cSection+cQuotes)) + { + rbIsChecked = true; + HWND hDlg = ::GetParent(hwndTree); + assert(::IsWindow(hDlg)); + ::PostMessage(hDlg,TREE_VIEW_CHECK_STATE_CHANGE,MAKEWPARAM(0,TCBS_CHECKED),reinterpret_cast<LPARAM>(hti)); + } + } + + void add_provider_to_tree(const CQuotesProviderDukasCopy* pQuotesProvier,HWND hwndTree) + { + CQuotesProviderDukasCopy::CQuoteSection qs = pQuotesProvier->GetQuotes(); + bool bIsChecked = false; + bool bIsExpanded = false; + add_section_to_tree(qs,hwndTree,TVI_ROOT,pQuotesProvier,bIsChecked,bIsExpanded,true); + } + + inline HTREEITEM tree_get_child_item(HWND hwndTree,HTREEITEM hti) + { + return reinterpret_cast<HTREEITEM>(::SendMessage(hwndTree, TVM_GETNEXTITEM, TVGN_CHILD,reinterpret_cast<LPARAM>(hti))); + } + + inline HTREEITEM tree_get_next_sibling_item(HWND hwndTree,HTREEITEM hti) + { + return reinterpret_cast<HTREEITEM>(::SendMessage(hwndTree, TVM_GETNEXTITEM, TVGN_NEXT,reinterpret_cast<LPARAM>(hti))); + } + + inline ETreeCheckBoxState tree_get_state_image(HWND hwndTree,HTREEITEM hti) + { + TVITEM tvi; + tvi.hItem = hti; + tvi.mask = TVIF_STATE|TVIF_HANDLE; + tvi.stateMask = TVIS_STATEIMAGEMASK; + if(TRUE == ::SendMessage(hwndTree,TVM_GETITEM,0,reinterpret_cast<LPARAM>(&tvi))) + { + UINT nState = (tvi.state >> 12); + return static_cast<ETreeCheckBoxState>(nState); + } + else + { + return TCBS_UNCHECKED; + } + } + + void tree_do_set_item_state(HWND hwndTree,HTREEITEM hti,ETreeCheckBoxState nState) + { + TVITEM tvi; + ZeroMemory(&tvi,sizeof(tvi)); + + tvi.mask = TVIF_STATE|TVIF_HANDLE; + tvi.hItem = hti; + + tvi.stateMask = TVIS_STATEIMAGEMASK; + tvi.state = INDEXTOSTATEIMAGEMASK(nState); + + ::SendMessage(hwndTree,TVM_SETITEM,0,reinterpret_cast<LPARAM>(&tvi)); + } + + void tree_set_item_state(HWND hwndTree,HTREEITEM hti,ETreeCheckBoxState nState,bool bRecursively) + { + if(true == bRecursively) + { + for(hti = tree_get_child_item(hwndTree,hti);hti;hti = tree_get_next_sibling_item(hwndTree,hti)) + { + tree_do_set_item_state(hwndTree,hti,nState); + tree_set_item_state(hwndTree,hti,nState,bRecursively); + } + } + else + { + tree_do_set_item_state(hwndTree,hti,nState); + } + } + + void save_quote_selection(HWND hwndTree,HTREEITEM h,const CQuotesProviderDukasCopy::CQuote& q,CQuotesProviderDukasCopy* pQuotesProvier) + { + ETreeCheckBoxState nState = tree_get_state_image(hwndTree,h); + pQuotesProvier->WatchForQuote(q,(TCBS_CHECKED == nState)); + } + + void recursive_save_quote_section_selection(HWND hwndTree,HTREEITEM h,const CQuotesProviderDukasCopy::CQuoteSection& qs,CQuotesProviderDukasCopy* pQuotesProvier) + { + size_t cSection = qs.GetSectionCount(); + h = tree_get_child_item(hwndTree,h); + for(size_t i = 0;h && (i < cSection);++i,h = tree_get_next_sibling_item(hwndTree,h)) + { + CQuotesProviderDukasCopy::CQuoteSection other = qs.GetSection(i); + recursive_save_quote_section_selection(hwndTree,h,other,pQuotesProvier); + } + + size_t cQuotes = qs.GetQuoteCount(); + for(size_t i = 0;h && (i < cQuotes);++i,h = tree_get_next_sibling_item(hwndTree,h)) + { + CQuotesProviderDukasCopy::CQuote q = qs.GetQuote(i); + save_quote_selection(hwndTree,h,q,pQuotesProvier); + } + } + + void recursive_save_selection(HWND hwndTree,CQuotesProviderDukasCopy* pQuotesProvider) + { + // CModuleInfo::TQuotesProvidersPtr& pProviders = CModuleInfo::GetQuoteProvidersPtr(); + // const TQuotesProviders& rapQuotesProviders = pProviders->GetProviders(); + // + // TQuotesProviders::const_iterator i = rapQuotesProviders.begin(); + // TQuotesProviders::const_iterator iE = rapQuotesProviders.end(); + // for(HTREEITEM h = tree_get_child_item(hwndTree,TVI_ROOT);h && (i!=iE);++i,h = tree_get_next_sibling_item(hwndTree,h)) + // { + // const TQuotesProviderPtr& pQuotesProvier = *i; + CQuotesProviderDukasCopy::CQuoteSection qs = pQuotesProvider->GetQuotes(); + recursive_save_quote_section_selection(hwndTree,tree_get_child_item(hwndTree,TVI_ROOT),qs,pQuotesProvider); + // } + } + + class CImageListWrapper + { + public: + CImageListWrapper() + : m_hImageList(ImageList_Create(::GetSystemMetrics(SM_CXSMICON), + ::GetSystemMetrics(SM_CYSMICON), + ILC_COLOR24|ILC_MASK,2,0)) + { + if(m_hImageList) + { + ImageList_AddIcon(m_hImageList,Quotes_LoadIconEx(ICON_STR_SECTION)); + ImageList_AddIcon(m_hImageList,Quotes_LoadIconEx(ICON_STR_QUOTE)); + } + } + + ~CImageListWrapper() + { + if(m_hImageList) + { + ImageList_Destroy(m_hImageList); + } + } + + operator HIMAGELIST()const + { + return m_hImageList; + } + + private: + HIMAGELIST m_hImageList; + }; + + HIMAGELIST get_image_list() + { + static CImageListWrapper wrapper; + return wrapper; + } + + CQuotesProviderDukasCopy* get_dukas_copy_provider() + { + CModuleInfo::TQuotesProvidersPtr& pProviders = CModuleInfo::GetQuoteProvidersPtr(); + const CQuotesProviders::TQuotesProviders& rapQuotesProviders = pProviders->GetProviders(); + for(CQuotesProviders::TQuotesProviders::const_iterator i = rapQuotesProviders.begin();i != rapQuotesProviders.end();++i) + { + const CQuotesProviders::TQuotesProviderPtr& pProvider = *i; + CQuotesProviderDukasCopy* pDukas = dynamic_cast<CQuotesProviderDukasCopy*>(pProvider.get()); + if(pDukas) + { + return pDukas; + } + } + + assert(!"We should never get here!"); + return NULL; + } + + INT_PTR CALLBACK EconomicRatesDlgProc(HWND hdlg,UINT message,WPARAM wParam,LPARAM lParam) + { + CCommonDlgProcData d(get_dukas_copy_provider()); + CommonOptionDlgProc(hdlg,message,wParam,lParam,d); + + switch(message) + { + case WM_INITDIALOG: + { + TranslateDialogDefault(hdlg); + + HWND hwndTree = ::GetDlgItem(hdlg,IDC_TREE_ECONOMIC_RATES); + HIMAGELIST hImage = get_image_list(); + if(hImage) + { + TreeView_SetImageList(hwndTree,hImage,TVSIL_NORMAL); + } + + const CQuotesProviderDukasCopy* pDukasProvider = get_dukas_copy_provider(); + if(pDukasProvider) + { + add_provider_to_tree(pDukasProvider,hwndTree); + } + // Window_SetIcon_IcoLib(hdlg, SKINICON_OTHER_MIRANDA); + } + return TRUE; + + case WM_NOTIFY: + { + LPNMHDR pNMHDR = reinterpret_cast<LPNMHDR>(lParam); + switch(pNMHDR->code) + { + case TVN_KEYDOWN: + if(IDC_TREE_ECONOMIC_RATES == wParam) + { + LPNMTVKEYDOWN pKeyDown = reinterpret_cast<LPNMTVKEYDOWN>(lParam); + if(VK_SPACE == pKeyDown->wVKey) + { + HTREEITEM hti = TreeView_GetSelection(::GetDlgItem(hdlg,IDC_TREE_ECONOMIC_RATES)); + ::PostMessage(hdlg,TREE_VIEW_CHECK_STATE_CHANGE,MAKEWPARAM(1,0),reinterpret_cast<LPARAM>(hti)); + PropSheet_Changed(::GetParent(hdlg),hdlg); + } + } + break; + case NM_CLICK: + if(IDC_TREE_ECONOMIC_RATES == wParam) + { + DWORD pos = ::GetMessagePos(); + + HWND hwndTree = ::GetDlgItem(hdlg,IDC_TREE_ECONOMIC_RATES); + + TVHITTESTINFO tvhti; + tvhti.pt.x = LOWORD(pos); + tvhti.pt.y = HIWORD(pos); + ::ScreenToClient(hwndTree,&(tvhti.pt)); + + HTREEITEM hti = reinterpret_cast<HTREEITEM>(::SendMessage(hwndTree,TVM_HITTEST,0,reinterpret_cast<LPARAM>(&tvhti))); + if(hti && (tvhti.flags&TVHT_ONITEMSTATEICON)) + { + ::PostMessage(hdlg,TREE_VIEW_CHECK_STATE_CHANGE,MAKEWPARAM(1,0),reinterpret_cast<LPARAM>(hti)); + PropSheet_Changed(::GetParent(hdlg),hdlg); + } + } + break; + case PSN_APPLY: + { + CQuotesProviderDukasCopy* pDukasProvider = get_dukas_copy_provider(); + if(pDukasProvider) + { + recursive_save_selection(::GetDlgItem(hdlg,IDC_TREE_ECONOMIC_RATES),pDukasProvider); + pDukasProvider->RefreshAll(); + } + } + break; + } + } + return TRUE; + + case TREE_VIEW_CHECK_STATE_CHANGE: + { + HWND hwndTree = ::GetDlgItem(hdlg,IDC_TREE_ECONOMIC_RATES); + HTREEITEM hti = reinterpret_cast<HTREEITEM>(lParam); + + ETreeCheckBoxState nState; + + bool bRecursively = 1 == LOWORD(wParam); + if(bRecursively) + { + nState = tree_get_state_image(hwndTree,hti); + } + else + { + nState = static_cast<ETreeCheckBoxState>(HIWORD(wParam)); + } + + tree_set_item_state(hwndTree,hti,nState,bRecursively); + } + break; + // case WM_CLOSE: + // DestroyWindow(hdlg); + // break; + // case WM_DESTROY: + // g_hwndEconomicRates = NULL; + // break; + } + + return FALSE; + } +} + +void ShowDukasCopyPropPage(CQuotesProviderDukasCopy* pProvider,WPARAM wp,OPTIONSDIALOGPAGE& odp) +{ + const IQuotesProvider::CProviderInfo& pi = pProvider->GetInfo(); + + odp.pszTemplate = MAKEINTRESOURCEA(IDD_DIALOG_ECONOMIC_RATES); + odp.pfnDlgProc = EconomicRatesDlgProc; +// #if MIRANDA_VER >= 0x0600 + //odp.ptszTab = TranslateTS(const_cast<LPTSTR>(pi.m_sName.c_str())); + odp.ptszTab = const_cast<LPTSTR>(pi.m_sName.c_str()); +// #else +// tostringstream o; +// o << TranslateTS(QUOTES_PROTOCOL_NAME) << _T(" - ") << TranslateTS(pi.m_sName.c_str()); +// tstring sTitle = o.str(); +// odp.ptszTitle = TranslateTS(const_cast<LPTSTR>(sTitle.c_str())); +// #endif + + CallService(MS_OPT_ADDPAGE,wp,reinterpret_cast<LPARAM>(&odp)); +} diff --git a/protocols/Quotes/OptionDukasCopy.h b/protocols/Quotes/OptionDukasCopy.h new file mode 100644 index 0000000000..0674119e83 --- /dev/null +++ b/protocols/Quotes/OptionDukasCopy.h @@ -0,0 +1,8 @@ +#ifndef __60a5d152_872c_4bc4_b9ae_cd561d110b2dOptionDukasCopy_h__ +#define __60a5d152_872c_4bc4_b9ae_cd561d110b2dOptionDukasCopy_h__ + +class CQuotesProviderDukasCopy; + +void ShowDukasCopyPropPage(CQuotesProviderDukasCopy* pProvider,WPARAM wp,OPTIONSDIALOGPAGE& odp); + +#endif //__60a5d152_872c_4bc4_b9ae_cd561d110b2dOptionDukasCopy_h__ diff --git a/protocols/Quotes/QuoteChart.cpp b/protocols/Quotes/QuoteChart.cpp new file mode 100644 index 0000000000..3746540d23 --- /dev/null +++ b/protocols/Quotes/QuoteChart.cpp @@ -0,0 +1,408 @@ +#include "StdAfx.h" +#include "QuoteChart.h" + +#ifdef CHART_IMPLEMENT + +// #include "QuotesProviderDukasCopy.h" +// #include "QuotesProviders.h" +#include "ModuleInfo.h" +#include "EconomicRateInfo.h" +// #include "WinCtrlHelper.h" +#include "resource.h" +#include "DBUtils.h" +#include "Locale.h" +#include "SettingsDlg.h" +#include "Chart.h" +#include "WinCtrlHelper.h" + +#define WINDOW_PREFIX "Quotes Chart_" +#define CHART_CTRL_CLASS _T("DioksinChart") + +namespace +{ + struct CTimeConvert + { + static double Convert(const boost::posix_time::time_duration& v) + { + return boost::numeric_cast<double>(v.ticks()); + } + + static tstring ToString(const boost::posix_time::ptime& v) + { + tostringstream k; + k.imbue(std::locale(GetSystemLocale(),new ttime_facet(_T("%d/%m/%y %H:%M:%S")))); + k << v; + return k.str(); + } + }; + + typedef CChart<boost::posix_time::ptime,double,CTimeConvert> TChart; + + inline TChart* get_chart_ptr(HWND hWnd) + { + TChart* pChart = reinterpret_cast<TChart*>(GetWindowLongPtr(hWnd,GWLP_USERDATA)); + return pChart; + } + + bool read_log_file(HANDLE hContact,TChart& rChart) + { + tstring sLogFileName = GetContactLogFileName(hContact); + if(false == sLogFileName.empty()) + { + std::locale loc(GetSystemLocale(),new ttime_input_facet(_T("%d.%m.%y %H:%M:%S"))); + boost::posix_time::ptime oDateTime; + double dRate; + + tifstream file(sLogFileName.c_str()); + file.imbue(loc); + while((false == file.fail()) && (false == file.eof())) + { + tstring sLine; + std::getline(file,sLine); + + tistringstream line(sLine); + line.imbue(loc); + + tstring sName; + std::getline(line,sName,_T('\t')); + line >> oDateTime >> dRate; + if ((false == line.fail()) && (true == line.eof())) + { + rChart.AddValue(oDateTime,dRate); + } + } + + return true; + } + return false; + } + + + enum + { + ID_CHART = 0x1969, + + srcLogFile = 0, + srcHistory = 1, + + filterAll = 0, + filterLastDay = 1, + filterLastWeek = 2, + filterLastMonth = 3, + filterLastYear = 4, + filterUserDefined = 5, + + CHART_SET_SOURCE = WM_USER + 1, + CHART_SET_FILTER = WM_USER + 2, + }; + + LRESULT CALLBACK ChartWndProc(HWND hWnd,UINT msg,WPARAM wp,LPARAM lp) + { + switch(msg) + { + case WM_CREATE: + { + CREATESTRUCT* pCS = reinterpret_cast<CREATESTRUCT*>(lp); + HANDLE hContact = reinterpret_cast<HANDLE>(pCS->lpCreateParams); + + TChart* pChart = new TChart; + read_log_file(hContact,*pChart); + + ::SetWindowLongPtr(hWnd,GWLP_USERDATA,reinterpret_cast<LONG_PTR>(pChart)); + } + return 0; + + case CHART_SET_SOURCE: + break; + + case CHART_SET_FILTER: + break; + + case WM_SIZE: + { + TChart* pChart = get_chart_ptr(hWnd); + pChart->SetRect(0,0,LOWORD(lp),HIWORD(lp)); + } + return 0; + + case WM_PAINT: + if(TRUE == ::GetUpdateRect(hWnd,NULL,FALSE)) + { + PAINTSTRUCT ps; + HDC hdc = ::BeginPaint(hWnd,&ps); + if(NULL != hdc) + { + TChart* pChart = get_chart_ptr(hWnd); + pChart->Draw(hdc); + ::EndPaint(hWnd,&ps); + } + } + + return 0; + case WM_DESTROY: + { + TChart* pChart = get_chart_ptr(hWnd); + ::SetWindowLongPtr(hWnd,GWLP_USERDATA,NULL); + delete pChart; + } + break; + } + + return ::DefWindowProc(hWnd,msg,wp,lp); + } + + void register_chart_control() + { + static bool g_bRegister = false; + if(g_bRegister) + { + return; + } + + WNDCLASS wc; + + wc.style = CS_HREDRAW | CS_VREDRAW; + wc.lpfnWndProc = ChartWndProc; + wc.cbClsExtra = 0; + wc.cbWndExtra = 0; + wc.hInstance = CModuleInfo::GetInstance().GetModuleHandle(); + wc.hIcon = NULL; + wc.hCursor = LoadCursor(NULL,IDC_ARROW); + wc.hbrBackground = static_cast<HBRUSH>(::GetStockObject(WHITE_BRUSH)); + wc.lpszMenuName = NULL; + wc.lpszClassName = CHART_CTRL_CLASS; + + if(RegisterClass(&wc)) + { + g_bRegister = true; + } + } + + + bool screen_2_client(HWND hWnd,LPRECT pRect) + { + POINT pt; + pt.x = pRect->left; + pt.y = pRect->top; + bool bResult = TRUE == ::ScreenToClient(hWnd,&pt); + pRect->left = pt.x; + pRect->top = pt.y; + pt.x = pRect->right; + pt.y = pRect->bottom; + bResult |= TRUE == ::ScreenToClient(hWnd,&pt); + pRect->right = pt.x; + pRect->bottom = pt.y; + return bResult; + } + + inline HANDLE get_contact(HWND hWnd) + { + HANDLE hContact = reinterpret_cast<HANDLE>(GetWindowLongPtr(hWnd,GWLP_USERDATA)); + return hContact; + } + + void update_filter_controls(HWND hDlg) + { + int nSel = ::SendDlgItemMessage(hDlg,IDC_COMBO_FILTER,CB_GETCURSEL,0,0); + + ::ShowWindow(::GetDlgItem(hDlg,IDC_EDIT_FROM),(filterUserDefined == nSel) ? SW_SHOW : SW_HIDE); + ::ShowWindow(::GetDlgItem(hDlg,IDC_EDIT_TO),(filterUserDefined == nSel) ? SW_SHOW : SW_HIDE); + } + + INT_PTR CALLBACK ChartDlgProc(HWND hDlg,UINT msg,WPARAM wp,LPARAM lp) + { + switch(msg) + { + case WM_INITDIALOG: + { + HANDLE hContact = reinterpret_cast<HANDLE>(lp); + + TranslateDialogDefault(hDlg); + + tstring sName = get_window_text(hDlg); + sName += _T(" - "); + sName += GetContactName(hContact); + ::SetWindowText(hDlg,sName.c_str()); + + HANDLE hWL = CModuleInfo::GetInstance().GetWindowList(WINDOW_PREFIX,false); + assert(hWL); + WindowList_Add(hWL,hDlg,hContact); + + ::SetWindowLongPtr(hDlg,GWLP_USERDATA,reinterpret_cast<LONG_PTR>(hContact)); + + static LPCTSTR szSources[] = {_T("Log File"),_T("Miranda's History")}; + static LPCTSTR szFilters[] = {_T("All"),_T("Last Day"),_T("Last Week"),_T("Last Month"),_T("Last Year"),_T("User-Defined")}; + + for(int i = 0;i < sizeof(szSources)/sizeof(szSources[0]);++i) + { + LPCTSTR p = TranslateTS(szSources[i]); + ::SendDlgItemMessage(hDlg,IDC_COMBO_DATA_SOURCE,CB_INSERTSTRING,-1,reinterpret_cast<LPARAM>(p)); + } + + int nSel = DBGetContactSettingByte(hContact,QUOTES_PROTOCOL_NAME,"Chart_Source",srcLogFile); + ::SendDlgItemMessage(hDlg,IDC_COMBO_DATA_SOURCE,CB_SETCURSEL,nSel,0); + + for(int i = 0;i < sizeof(szFilters)/sizeof(szFilters[0]);++i) + { + LPCTSTR p = TranslateTS(szSources[i]); + ::SendDlgItemMessage(hDlg,IDC_COMBO_FILTER,CB_INSERTSTRING,-1,reinterpret_cast<LPARAM>(szFilters[i])); + } + + nSel = DBGetContactSettingByte(hContact,QUOTES_PROTOCOL_NAME,"Chart_Filter",filterAll); + ::SendDlgItemMessage(hDlg,IDC_COMBO_FILTER,CB_SETCURSEL,nSel,0); + + update_filter_controls(hDlg); + + register_chart_control(); + HWND hwndImage = ::GetDlgItem(hDlg,IDC_STATIC_IMAGE); + RECT rcImage; + ::GetWindowRect(hwndImage,&rcImage); + screen_2_client(hDlg,&rcImage); + //BOOL bResult = ShowWindow(hwndImage,SW_HIDE); + //assert(bResult); + + HWND hChart = ::CreateWindowEx(0L,CHART_CTRL_CLASS,NULL,WS_CHILDWINDOW|WS_VISIBLE, + rcImage.left,rcImage.top,rcImage.right-rcImage.left,rcImage.bottom-rcImage.top, + hDlg,reinterpret_cast<HMENU>(ID_CHART),CModuleInfo::GetInstance().GetModuleHandle(),hContact); + assert(NULL != hChart); + + Utils_RestoreWindowPosition(hDlg,hContact,QUOTES_MODULE_NAME,WINDOW_PREFIX); + BOOL bResult = ::ShowWindow(hDlg,SW_SHOW); + assert(bResult); + } + return (TRUE); + case WM_CLOSE: + { + HANDLE hContact = get_contact(hDlg); + SetWindowLongPtr(hDlg,GWLP_USERDATA,0); + +// save_options(hDlg,hContact); + + HANDLE hWL = CModuleInfo::GetInstance().GetWindowList(WINDOW_PREFIX,false); + assert(hWL); + WindowList_Remove(hWL,hDlg); + Utils_SaveWindowPosition(hDlg,hContact,QUOTES_MODULE_NAME,WINDOW_PREFIX); + + HWND hwndChart = ::GetDlgItem(hDlg,ID_CHART); + BOOL bResult = ::DestroyWindow(hwndChart); + assert(bResult); + + ::EndDialog(hDlg,0); + } + return (TRUE); + case WM_COMMAND: + switch(LOWORD(wp)) + { + case IDCANCEL: + { + SendMessage(hDlg, WM_CLOSE, 0, 0); + } + return (TRUE); + case IDC_COMBO_FILTER: + if(CBN_SELCHANGE == HIWORD(wp)) + { + ::SendDlgItemMessage(hDlg,ID_CHART,CHART_SET_FILTER,::SendDlgItemMessage(hDlg,IDC_COMBO_FILTER,CB_GETCURSEL,0,0),0); + update_filter_controls(hDlg); + } + break; + case IDC_COMBO_DATA_SOURCE: + if(CBN_SELCHANGE == HIWORD(wp)) + { + ::SendDlgItemMessage(hDlg,ID_CHART,CHART_SET_SOURCE,::SendDlgItemMessage(hDlg,IDC_COMBO_DATA_SOURCE,CB_GETCURSEL,0,0),0); + } + break; + } + return (FALSE); + case WM_NOTIFY: + { + LPNMHDR pNMHDR = reinterpret_cast<LPNMHDR>(lp); + switch(pNMHDR->code) + { + case NM_CLICK: + if(IDC_SYSLINK_PROVIDER == wp) + { + PNMLINK pNMLink = reinterpret_cast<PNMLINK>(pNMHDR); + ::ShellExecute(hDlg,_T("open"),pNMLink->item.szUrl,NULL,NULL,SW_SHOWNORMAL); + } + break; + } + } + break; +// case WM_ERASEBKGND: +// { +// HDC hdc = reinterpret_cast<HDC>(wp); +// TChart* pChart = get_chart_ptr(hDlg); +// pChart->DrawBackground(hdc); +// return TRUE; +// } +// break; + case WM_SIZE: + { + enum{ INDENT = 7}; + + int nWidth = LOWORD(lp); + int nHeight = HIWORD(lp); + + HWND hwndChart = GetDlgItem(hDlg,ID_CHART); + HWND hwndLink = GetDlgItem(hDlg,IDC_SYSLINK_PROVIDER); + HWND hwndClose = GetDlgItem(hDlg,IDCANCEL); + + RECT rcDlg; + GetClientRect(hDlg,&rcDlg); + + RECT rcChart; + GetWindowRect(hwndChart,&rcChart); + screen_2_client(hDlg,&rcChart); + + RECT rcLink; + GetWindowRect(hwndLink,&rcLink); + screen_2_client(hDlg,&rcLink); + SetWindowPos(hwndLink,NULL,rcDlg.left + INDENT, + rcDlg.bottom-INDENT-(rcLink.bottom-rcLink.top), + 0,0,SWP_NOSIZE|SWP_NOZORDER|SWP_NOACTIVATE); + + RECT rcClose; + GetWindowRect(hwndClose,&rcClose); + screen_2_client(hDlg,&rcClose); + SetWindowPos(hwndClose,NULL,rcDlg.right - INDENT - (rcClose.right-rcClose.left), + rcDlg.bottom-INDENT-(rcClose.bottom-rcClose.top), + 0,0,SWP_NOSIZE|SWP_NOZORDER|SWP_NOACTIVATE); + + SetWindowPos(hwndChart,NULL,rcDlg.left + INDENT, + rcChart.top, + (nWidth-INDENT*2), + nHeight-(rcClose.bottom-rcClose.top)-INDENT*2-rcChart.top, + SWP_NOZORDER|SWP_NOACTIVATE); + + } + break; + } + return (FALSE); + } +} + +INT_PTR QuotesMenu_Chart(WPARAM wp,LPARAM lp) +{ + HANDLE hContact = reinterpret_cast<HANDLE>(wp); + if(NULL == hContact) + { + return 0; + } + + HANDLE hWL = CModuleInfo::GetInstance().GetWindowList(WINDOW_PREFIX,true); + assert(hWL); + HWND hWnd = WindowList_Find(hWL,hContact); + if(NULL != hWnd) + { + SetForegroundWindow(hWnd); + SetFocus(hWnd); + } + else + { + CreateDialogParam(CModuleInfo::GetModuleHandle(), MAKEINTRESOURCE(IDD_DUKASCOPY_CHART), NULL, ChartDlgProc, reinterpret_cast<LPARAM>(hContact)); + } + + return 0; +} + +#endif //CHART_IMPLEMENT diff --git a/protocols/Quotes/QuoteChart.h b/protocols/Quotes/QuoteChart.h new file mode 100644 index 0000000000..1b40f428b5 --- /dev/null +++ b/protocols/Quotes/QuoteChart.h @@ -0,0 +1,12 @@ +#ifndef __39BE8775_A837_494f_925C_0ABF7910F238_QuoteChart_h__ +#define __39BE8775_A837_494f_925C_0ABF7910F238_QuoteChart_h__ + +#ifdef CHART_IMPLEMENT + +#pragma once + +INT_PTR QuotesMenu_Chart(WPARAM wp,LPARAM lp); + +#endif + +#endif //__39BE8775_A837_494f_925C_0ABF7910F238_QuoteChart_h__ diff --git a/protocols/Quotes/QuoteInfoDlg.cpp b/protocols/Quotes/QuoteInfoDlg.cpp new file mode 100644 index 0000000000..88253ec45d --- /dev/null +++ b/protocols/Quotes/QuoteInfoDlg.cpp @@ -0,0 +1,353 @@ +#include "StdAfx.h" +#include "QuoteInfoDlg.h" +#include "EconomicRateInfo.h" +#include "resource.h" +#include "ModuleInfo.h" +#include "QuotesProviders.h" +#include "IconLib.h" +#include "DBUtils.h" +#include "IQuotesProvider.h" +#include "Locale.h" +#include "SettingsDlg.h" + +// extern HANDLE g_hWindowListEditSettings; +extern HGENMENU g_hMenuEditSettings; +extern HGENMENU g_hMenuOpenLogFile; +#ifdef CHART_IMPLEMENT +extern HGENMENU g_hMenuChart; +#endif +extern HGENMENU g_hMenuRefresh; + + +#define WINDOW_PREFIX_INFO "Quote Info" + + +namespace +{ + HANDLE g_hContact; + + inline bool IsMyContact(HANDLE hContact) + { + CQuotesProviders::TQuotesProviderPtr pProvider = CModuleInfo::GetQuoteProvidersPtr()->GetContactProviderPtr(hContact); + return (NULL != pProvider); + } + + inline HANDLE get_contact(HWND hWnd) + { + return reinterpret_cast<HANDLE>(GetWindowLongPtr(hWnd,GWLP_USERDATA)); + } + + + bool get_fetch_time(time_t& rTime,HANDLE hContact) + { + DBVARIANT dbv; + DBCONTACTGETSETTING cgs; + + cgs.szModule=QUOTES_PROTOCOL_NAME; + cgs.szSetting=DB_STR_QUOTE_FETCH_TIME; + cgs.pValue=&dbv; + if(CallService(MS_DB_CONTACT_GETSETTING,reinterpret_cast<WPARAM>(hContact),reinterpret_cast<LPARAM>(&cgs)) + || (DBVT_DWORD != dbv.type)) + { + return false; + } + + rTime = dbv.dVal; + return true; + } + + INT_PTR CALLBACK QuoteInfoDlgProcImpl(HANDLE hContact,HWND hdlg,UINT msg,WPARAM wParam,LPARAM lParam) + { + switch(msg) + { + case WM_INITDIALOG: + { + assert(hContact); + + TranslateDialogDefault(hdlg); + + tstring sDescription = GetContactName(hContact); + ::SetDlgItemText(hdlg,IDC_STATIC_QUOTE_NAME,sDescription.c_str()); + + double dRate = 0.0; + if(true == Quotes_DBReadDouble(hContact,QUOTES_PROTOCOL_NAME,DB_STR_QUOTE_PREV_VALUE,dRate)) + { + tostringstream o; + o.imbue(GetSystemLocale()); + o << dRate; + + ::SetDlgItemText(hdlg,IDC_EDIT_PREVIOUS_RATE,o.str().c_str()); + } + + dRate = 0.0; + if(true == Quotes_DBReadDouble(hContact,QUOTES_PROTOCOL_NAME,DB_STR_QUOTE_CURR_VALUE,dRate)) + { + tostringstream o; + o.imbue(GetSystemLocale()); + o << dRate; + + ::SetDlgItemText(hdlg,IDC_EDIT_RATE,o.str().c_str()); + } + + time_t nFetchTime; + if(true == get_fetch_time(nFetchTime,hContact)) + { + TCHAR szTime[50]; + if(0 == _tctime_s(szTime,50,&nFetchTime)) + { + szTime[::_tcslen(szTime)-1] = _T('\0'); + ::SetDlgItemText(hdlg,IDC_EDIT_RATE_FETCH_TIME,szTime); + } + } + + CQuotesProviders::TQuotesProviderPtr pProvider = CModuleInfo::GetQuoteProvidersPtr()->GetContactProviderPtr(hContact); + + const IQuotesProvider::CProviderInfo& pi = pProvider->GetInfo(); + tostringstream o; + o << TranslateT("Info provided by") << _T(" <a href=\"") << pi.m_sURL << _T("\">") << pi.m_sName << _T("</a>"); + + ::SetDlgItemText(hdlg,IDC_SYSLINK_PROVIDER,o.str().c_str()); + } + return TRUE; + case WM_NOTIFY: + { + LPNMHDR pNMHDR = reinterpret_cast<LPNMHDR>(lParam); + switch(pNMHDR->code) + { + case NM_CLICK: + if(IDC_SYSLINK_PROVIDER == wParam) + { + PNMLINK pNMLink = reinterpret_cast<PNMLINK>(pNMHDR); + ::ShellExecute(hdlg,_T("open"),pNMLink->item.szUrl,NULL,NULL,SW_SHOWNORMAL); + } + break; + } + } + break; + } + return FALSE; + } + + INT_PTR CALLBACK QuoteInfoDlgProc(HWND hdlg,UINT msg,WPARAM wParam,LPARAM lParam) + { + return QuoteInfoDlgProcImpl(g_hContact,hdlg,msg,wParam,lParam); + } +} + +int QuotesEventFunc_OnUserInfoInit(WPARAM wp,LPARAM lp) +{ + HANDLE hContact = reinterpret_cast<HANDLE>(lp); + if(NULL == hContact) + { + return 0; + } + + + if(false == IsMyContact(hContact)) + { + return 0; + } + + g_hContact = hContact; + + OPTIONSDIALOGPAGE odp = {0}; + odp.cbSize = sizeof( odp ); + odp.hInstance = CModuleInfo::GetModuleHandle(); + //odp.dwInitParam = ( LPARAM )this; + + odp.hIcon = Quotes_LoadIconEx(ICON_STR_MAIN); + odp.flags = ODPF_TCHAR; + odp.pfnDlgProc = QuoteInfoDlgProc; + odp.position = -2000000000; + odp.pszTemplate = MAKEINTRESOURCEA(IDD_DIALOG_QUOTE_INFO); + odp.ptszTitle = TranslateT("Quote"); + CallService(MS_USERINFO_ADDPAGE,wp,reinterpret_cast<LPARAM>(&odp)); + + return 0; +} + + +INT_PTR QuotesMenu_EditSettings(WPARAM wp,LPARAM lp) +{ + HANDLE hContact = reinterpret_cast<HANDLE>(wp); + if(NULL == hContact) + { + return 0; + } + + ShowSettingsDlg(hContact); + + return 0; +} + +namespace +{ + bool get_log_file(HANDLE hContact,tstring& rsLogfile) + { + rsLogfile = GetContactLogFileName(hContact); + return ((rsLogfile.empty()) ? false : true); + } +} + +INT_PTR QuotesMenu_OpenLogFile(WPARAM wp,LPARAM lp) +{ + HANDLE hContact = reinterpret_cast<HANDLE>(wp); + if(NULL == hContact) + { + return 0; + } + + tstring sLogFileName; + if ((true == get_log_file(hContact,sLogFileName)) && (false == sLogFileName.empty())) + { + ::ShellExecute(NULL,_T("open"),sLogFileName.c_str(),NULL,NULL,SW_SHOWNORMAL); + } + + return 0; +} + +INT_PTR QuotesMenu_RefreshContact(WPARAM wp,LPARAM lp) +{ + HANDLE hContact = reinterpret_cast<HANDLE>(wp); + if(NULL == hContact) + { + return 0; + } + + CQuotesProviders::TQuotesProviderPtr pProvider = CModuleInfo::GetQuoteProvidersPtr()->GetContactProviderPtr(hContact); + if (!pProvider) + { + return 0; + } + + pProvider->RefreshContact(hContact); + + return 0; +} + +namespace +{ + INT_PTR CALLBACK QuoteInfoDlgProc1(HWND hdlg,UINT msg,WPARAM wParam,LPARAM lParam) + { + HANDLE hContact = NULL; + switch(msg) + { + case WM_INITDIALOG: + { + hContact = reinterpret_cast<HANDLE>(lParam); + HANDLE hWL = CModuleInfo::GetInstance().GetWindowList(WINDOW_PREFIX_INFO,false); + assert(hWL); + WindowList_Add(hWL,hdlg,hContact); + + ::SetWindowLongPtr(hdlg,GWLP_USERDATA,reinterpret_cast<LONG>(hContact)); + Utils_RestoreWindowPositionNoSize(hdlg,hContact,QUOTES_MODULE_NAME,WINDOW_PREFIX_INFO); + ::ShowWindow(hdlg,SW_SHOW); + } + break; + case WM_CLOSE: + DestroyWindow(hdlg); + return FALSE; + case WM_DESTROY: + { + HANDLE hContact = get_contact(hdlg); + if(hContact) + { + SetWindowLongPtr(hdlg,GWLP_USERDATA,0); + + HANDLE hWL = CModuleInfo::GetInstance().GetWindowList(WINDOW_PREFIX_INFO,false); + assert(hWL); + WindowList_Remove(hWL,hdlg); + Utils_SaveWindowPosition(hdlg,hContact,QUOTES_MODULE_NAME,WINDOW_PREFIX_INFO); + } + } + return FALSE; + case WM_COMMAND: + if(LOWORD(wParam) == IDOK) + { + ::DestroyWindow(hdlg); + return FALSE; + } + + default: + hContact = get_contact(hdlg); + break; + } + + return QuoteInfoDlgProcImpl(hContact,hdlg,msg,wParam,lParam); + } +} + +int Quotes_OnContactDoubleClick(WPARAM wp,LPARAM/* lp*/) +{ + HANDLE hContact = reinterpret_cast<HANDLE>(wp); + if(CModuleInfo::GetQuoteProvidersPtr()->GetContactProviderPtr(hContact)) + { + HANDLE hWL = CModuleInfo::GetInstance().GetWindowList(WINDOW_PREFIX_INFO,true); + assert(hWL); + HWND hWnd = WindowList_Find(hWL,hContact); + if(NULL != hWnd) + { + SetForegroundWindow(hWnd); + SetFocus(hWnd); + } + else if(true == IsMyContact(hContact)) + { + CreateDialogParam(CModuleInfo::GetModuleHandle(),MAKEINTRESOURCE(IDD_DIALOG_QUOTE_INFO_1),NULL,QuoteInfoDlgProc1,reinterpret_cast<LPARAM>(hContact)); + } + + return 1; + } + else + { + return 0; + } +} + +namespace +{ + void enable_menu(HANDLE hMenu,bool bEnable) + { + CLISTMENUITEM clmi = {0}; + clmi.cbSize = sizeof( CLISTMENUITEM ); + clmi.flags = CMIM_FLAGS; + if(false == bEnable) + { + clmi.flags |= /*CMIF_HIDDEN*/CMIF_GRAYED; + } + + CallService(MS_CLIST_MODIFYMENUITEM,reinterpret_cast<WPARAM>(hMenu),reinterpret_cast<LPARAM>(&clmi)); + } +} + +int Quotes_PrebuildContactMenu(WPARAM wp,LPARAM lp) +{ + enable_menu(g_hMenuEditSettings,false); + enable_menu(g_hMenuOpenLogFile,false); +#ifdef CHART_IMPLEMENT + enable_menu(g_hMenuChart,false); +#endif + enable_menu(g_hMenuRefresh,false); + + HANDLE hContact = reinterpret_cast<HANDLE>(wp); + if(NULL == hContact) + { + return 0; + } + + enable_menu(g_hMenuEditSettings,true); + + enable_menu(g_hMenuRefresh,true); + + tstring sLogFileName; + bool bThereIsLogFile = (true == get_log_file(hContact,sLogFileName)) + && (false == sLogFileName.empty()) && (0 == _taccess(sLogFileName.c_str(),04)); + if(true == bThereIsLogFile) + { +#ifdef CHART_IMPLEMENT + enable_menu(g_hMenuChart,true); +#endif + enable_menu(g_hMenuOpenLogFile,true); + } + + return 0; +} diff --git a/protocols/Quotes/QuoteInfoDlg.h b/protocols/Quotes/QuoteInfoDlg.h new file mode 100644 index 0000000000..c4a1999a4c --- /dev/null +++ b/protocols/Quotes/QuoteInfoDlg.h @@ -0,0 +1,11 @@ +#ifndef __aa849fa0_ff3f_49e9_b47a_e7dd34783dc2_QuoteInfoDlg_h__ +#define __aa849fa0_ff3f_49e9_b47a_e7dd34783dc2_QuoteInfoDlg_h__ + +int QuotesEventFunc_OnUserInfoInit(WPARAM wp,LPARAM lp); +INT_PTR QuotesMenu_EditSettings(WPARAM wp,LPARAM lp); +INT_PTR QuotesMenu_OpenLogFile(WPARAM wp,LPARAM lp); +INT_PTR QuotesMenu_RefreshContact(WPARAM wp,LPARAM lp); +int Quotes_PrebuildContactMenu(WPARAM wp,LPARAM lp); +int Quotes_OnContactDoubleClick(WPARAM wp,LPARAM lp); + +#endif //__aa849fa0_ff3f_49e9_b47a_e7dd34783dc2_QuoteInfoDlg_h__ diff --git a/protocols/Quotes/QuotesProviderBase.cpp b/protocols/Quotes/QuotesProviderBase.cpp new file mode 100644 index 0000000000..c92c748a02 Binary files /dev/null and b/protocols/Quotes/QuotesProviderBase.cpp differ diff --git a/protocols/Quotes/QuotesProviderBase.h b/protocols/Quotes/QuotesProviderBase.h new file mode 100644 index 0000000000..76db155f4c --- /dev/null +++ b/protocols/Quotes/QuotesProviderBase.h @@ -0,0 +1,112 @@ +#ifndef __3e6cb4ec_fc47_468f_a2c8_a77941176bc9_QuotesProviderBase_h__ +#define __3e6cb4ec_fc47_468f_a2c8_a77941176bc9_QuotesProviderBase_h__ + +#include "iquotesprovider.h" +#include <vector> +#include "LightMutex.h" + +class CQuotesProviderBase : public IQuotesProvider +{ +public: + class CQuote + { + public: + CQuote(const tstring& rsID = _T(""),const tstring& rsSymbol = _T(""),const tstring& rsName = _T("")) + : m_sSymbol(rsSymbol),m_sName(rsName),m_sID(rsID){} + + const tstring& GetSymbol()const{return m_sSymbol;} + const tstring& GetName()const{return m_sName;} + const tstring& GetID()const{return m_sID;} + + private: + tstring m_sSymbol; + tstring m_sName; + tstring m_sID; + }; + + class CQuoteSection + { + public: + typedef std::vector<CQuoteSection> TSections; + typedef std::vector<CQuote> TQuotes; + + public: + CQuoteSection(const tstring& rsName = _T(""),const TSections& raSections = TSections(),const TQuotes& raQuotes = TQuotes()) + : m_sName(rsName),m_aSections(raSections),m_aQuotes(raQuotes){} + + const tstring& GetName()const + {return m_sName;} + + size_t GetSectionCount()const + {return m_aSections.size();} + CQuoteSection GetSection(size_t nIndex)const + {return ((nIndex < m_aSections.size()) ? m_aSections[nIndex] : CQuoteSection());} + + size_t GetQuoteCount()const + {return m_aQuotes.size();} + CQuote GetQuote(size_t nIndex)const + {return ((nIndex < m_aQuotes.size()) ? m_aQuotes[nIndex] : CQuote());} + + private: + tstring m_sName; + TSections m_aSections; + TQuotes m_aQuotes; + }; + +protected: + typedef std::vector<HANDLE> TContracts; + +public: + struct CXMLFileInfo; + +public: + CQuotesProviderBase(); + ~CQuotesProviderBase(); + + + const CQuoteSection& GetQuotes()const; +// void SetSettingsEvent(); + + virtual bool Init(); + virtual const CProviderInfo& GetInfo()const; + virtual void AddContact(HANDLE hContact); + virtual void DeleteContact(HANDLE hContact); + virtual void Run(); + virtual void Accept(CQuotesProviderVisitor& visitor)const; + virtual void RefreshAll(); + virtual void RefreshContact(HANDLE hContact); + virtual void SetContactExtraIcon(HANDLE hContact)const; + +protected: + const tstring& GetURL()const; + HANDLE CreateNewContact(const tstring& rsName); + static bool IsOnline(); + static void SetContactStatus(HANDLE hContact,int nNewStatus); + void WriteContactRate(HANDLE hContact,double dRate,const tstring& rsSymbol = _T("")); + +private: + virtual void RefreshQuotes(TContracts& anContacts) = 0; + +private: + virtual void OnEndRun(); + +private: + CXMLFileInfo* GetXMLFileInfo()const; + +protected: + TContracts m_aContacts; + mutable CLightMutex m_cs; + +private: + typedef boost::scoped_ptr<CXMLFileInfo> TXMLFileInfoPtr; + mutable TXMLFileInfoPtr m_pXMLInfo; + HANDLE m_hEventSettingsChanged; + HANDLE m_hEventRefreshContact; + tstring m_sContactListFormat; + tstring m_sStatusMsgFormat; + tstring m_sTendencyFormat; + TContracts m_aRefreshingContacts; + bool m_bRefreshInProgress; +}; + +#endif //__3e6cb4ec_fc47_468f_a2c8_a77941176bc9_QuotesProviderBase_h__ diff --git a/protocols/Quotes/QuotesProviderDukasCopy.cpp b/protocols/Quotes/QuotesProviderDukasCopy.cpp new file mode 100644 index 0000000000..a7ffc5331a Binary files /dev/null and b/protocols/Quotes/QuotesProviderDukasCopy.cpp differ diff --git a/protocols/Quotes/QuotesProviderDukasCopy.h b/protocols/Quotes/QuotesProviderDukasCopy.h new file mode 100644 index 0000000000..d6ec498bcf --- /dev/null +++ b/protocols/Quotes/QuotesProviderDukasCopy.h @@ -0,0 +1,38 @@ +#ifndef __93121758_68c7_4836_b571_da84dfe82b84_QuotesProviderDukasCopy_h__ +#define __93121758_68c7_4836_b571_da84dfe82b84_QuotesProviderDukasCopy_h__ + +#include "quotesproviderbase.h" +#include <vector> + +#define DB_STR_REFRESH_RATE_TYPE "RefreshRateType" +#define DB_STR_REFRESH_RATE_VALUE "RefreshRateValue" +#define DB_STR_DC_DISPLAY_NAME_FORMAT "DC_DisplayNameFormat" +// #define DB_STR_DC_LOG_FILE_FORMAT "DC_LogFileFormat" +// #define DB_STR_DC_HISTORY_FORMAT "DC_HistoryFormat" + +class CQuotesProviderDukasCopy : public CQuotesProviderBase +{ +public: + CQuotesProviderDukasCopy(); + ~CQuotesProviderDukasCopy(); + + bool WatchForQuote(const CQuote& rQuote,bool bWatch); + bool IsQuoteWatched(const CQuote& rQuote)const; + + HANDLE GetContactByQuoteID(const tstring& rsQuoteID)const; +// #ifdef CHART_IMPLEMENT +// bool Chart(HANDLE hContact,const tstring& url)const; +// #endif + +private: + //IQuotesProvider implementation + virtual void RefreshQuotes(TContracts& anContacts); + virtual void ShowPropertyPage(WPARAM wp,OPTIONSDIALOGPAGE& odp); + virtual void Accept(CQuotesProviderVisitor& visitor)const; + +private: + tstring BuildHTTPURL()const; + +}; + +#endif //__93121758_68c7_4836_b571_da84dfe82b84_QuotesProviderDukasCopy_h__ diff --git a/protocols/Quotes/QuotesProviderFinance.cpp b/protocols/Quotes/QuotesProviderFinance.cpp new file mode 100644 index 0000000000..99d6127b32 --- /dev/null +++ b/protocols/Quotes/QuotesProviderFinance.cpp @@ -0,0 +1,318 @@ +#include "stdafx.h" +#include "QuotesProviderFinance.h" +#include "EconomicRateInfo.h" +#include "DBUtils.h" +#include "QuotesProviderVisitor.h" +#include "ModuleInfo.h" +#include "QuotesProviders.h" +#include "CommonOptionDlg.h" +#include "resource.h" +#include "WinCtrlHelper.h" + +void CQuotesProviderFinance::GetWatchedQuotes(TQuotes& raQuotes)const +{ + raQuotes.clear(); + BOOST_FOREACH(HANDLE hContact,m_aContacts) + { + tstring sID = Quotes_DBGetStringT(hContact,QUOTES_MODULE_NAME,DB_STR_QUOTE_ID); + tstring sSymbol = Quotes_DBGetStringT(hContact,QUOTES_MODULE_NAME,DB_STR_QUOTE_SYMBOL,sID.c_str()); + tstring sDescr = Quotes_DBGetStringT(hContact,QUOTES_MODULE_NAME,DB_STR_QUOTE_DESCRIPTION); + CQuotesProviderBase::CQuote quote(sID,sSymbol,sDescr); + + raQuotes.push_back(quote); + } +} + +namespace +{ + inline tstring get_quote_id(HANDLE hContact) + { + return Quotes_DBGetStringT(hContact,QUOTES_MODULE_NAME,DB_STR_QUOTE_ID); + } + + inline bool is_quote_id_equal(HANDLE hContact,const tstring& sID) + { + return sID == get_quote_id(hContact); + } +} + +bool CQuotesProviderFinance::WatchForQuote(const CQuote& rQuote,bool bWatch) +{ + const tstring& sQuoteID = rQuote.GetID(); + TContracts::iterator i = std::find_if(m_aContacts.begin(),m_aContacts.end(), + boost::bind(is_quote_id_equal,_1,sQuoteID)); + + if ((false == bWatch) && (i != m_aContacts.end())) + { + HANDLE hContact = *i; + {// for CCritSection + CGuard<CLightMutex> cs(m_cs); + m_aContacts.erase(i); + } + + CallService(MS_DB_CONTACT_DELETE,reinterpret_cast<WPARAM>(hContact),0); + return true; + } + else if ((true == bWatch) && (i == m_aContacts.end())) + { + HANDLE hContact = CreateNewContact(rQuote.GetSymbol()); + if(hContact) + { + DBWriteContactSettingTString(hContact,QUOTES_PROTOCOL_NAME,DB_STR_QUOTE_ID,sQuoteID.c_str()); + if(false == rQuote.GetName().empty()) + { + DBWriteContactSettingTString(hContact,QUOTES_PROTOCOL_NAME,DB_STR_QUOTE_DESCRIPTION,rQuote.GetName().c_str()); + } + + return true; + } + } + + return false; +} + +HANDLE CQuotesProviderFinance::GetContactByQuoteID(const tstring& rsQuoteID)const +{ + CGuard<CLightMutex> cs(m_cs); + + TContracts::const_iterator i = std::find_if(m_aContacts.begin(),m_aContacts.end(), + boost::bind(std::equal_to<tstring>(),rsQuoteID,boost::bind(get_quote_id,_1))); + if(i != m_aContacts.end()) + { + return *i; + } + else + { + return NULL; + } +} + +void CQuotesProviderFinance::Accept(CQuotesProviderVisitor& visitor)const +{ + CQuotesProviderBase::Accept(visitor); + visitor.Visit(*this); +} + +namespace +{ + inline tstring make_quote_name(const CQuotesProviderBase::CQuote& rQuote) + { + const tstring& rsDesc = rQuote.GetName(); + return((false == rsDesc.empty()) ? rsDesc : rQuote.GetSymbol()); + } + + int add_quote_to_wnd(const CQuotesProviderBase::CQuote& rQuote,HWND hwnd) + { + tstring sName = make_quote_name(rQuote); + int nIndex = ::SendMessage(hwnd,LB_ADDSTRING,0,reinterpret_cast<LPARAM>(sName.c_str())); + if(nIndex >= 0) + { + CQuotesProviderBase::CQuote* pQuote = new CQuotesProviderBase::CQuote(rQuote); + if(LB_ERR == ::SendMessage(hwnd,LB_SETITEMDATA,nIndex,reinterpret_cast<LPARAM>(pQuote))) + { + delete pQuote; + } + } + return nIndex; + } + +// typedef CQuotesProviderFinance::TQuotes TQuotes; +// TQuotes g_aWatchedQuotes; + +// inline bool cmp_quotes(const tstring& rsQuoteId,const CQuotesProviderBase::CQuote& quote) +// { +// return (0 == quotes_stricmp(rsQuoteId.c_str(),quote.GetID().c_str())); +// } + + CQuotesProviderBase::CQuote* get_quote_ptr_from_lb_index(HWND hwndListBox,int nIndex) + { + LRESULT lResult = ::SendMessage(hwndListBox,LB_GETITEMDATA,nIndex,0); + return (((LB_ERR != lResult) && (0 != lResult)) ? (reinterpret_cast<CQuotesProviderBase::CQuote*>(lResult)) : nullptr); + } + + int is_quote_added(HWND hwndList,const tstring& rsQuoteID) + { + int cItems = ::SendMessage(hwndList,LB_GETCOUNT,0,0); + for(int i = 0;i < cItems;++i) + { + const CQuotesProviderBase::CQuote* pQuote = get_quote_ptr_from_lb_index(hwndList,i); + if ((nullptr != pQuote) + && ((0 == quotes_stricmp(rsQuoteID.c_str(),pQuote->GetID().c_str())) + || (0 == quotes_stricmp(rsQuoteID.c_str(),pQuote->GetName().c_str())) + || (0 == quotes_stricmp(rsQuoteID.c_str(),pQuote->GetSymbol().c_str())))) + { + return i; + } + } + return LB_ERR; + } + + INT_PTR CALLBACK GoogleFinanceOptDlgProc(HWND hDlg,UINT message,WPARAM wParam,LPARAM lParam) + { + CQuotesProviderFinance* pProvider = nullptr; + if(WM_INITDIALOG == message) + { + pProvider = reinterpret_cast<CQuotesProviderFinance*>(lParam); + SetWindowLongPtr(hDlg,GWLP_USERDATA,lParam); + } + else + { + pProvider = reinterpret_cast<CQuotesProviderFinance*>(GetWindowLongPtr(hDlg,GWLP_USERDATA)); + } + + CCommonDlgProcData d(pProvider); + CommonOptionDlgProc(hDlg,message,wParam,lParam,d); + + switch(message) + { + case WM_INITDIALOG: + { + TranslateDialogDefault(hDlg); + + CQuotesProviderFinance::TQuotes aQuotes; + pProvider->GetWatchedQuotes(aQuotes); + + HWND hwndList = GetDlgItem(hDlg,IDC_LIST_RATES); + std::for_each(aQuotes.begin(),aQuotes.end(), + boost::bind(add_quote_to_wnd,_1,hwndList)); + + ::EnableWindow(::GetDlgItem(hDlg,IDC_BUTTON_ADD),FALSE); + ::EnableWindow(::GetDlgItem(hDlg,IDC_BUTTON_REMOVE),FALSE); + } + return (TRUE); + case WM_COMMAND: + switch (LOWORD(wParam)) + { + case IDC_EDIT_QUOTE: + if(EN_CHANGE == HIWORD(wParam)) + { + ::EnableWindow(::GetDlgItem(hDlg,IDC_BUTTON_ADD),GetWindowTextLength(GetDlgItem(hDlg,IDC_EDIT_QUOTE)) > 0); + } + return (TRUE); + case IDC_BUTTON_ADD: + if(BN_CLICKED == HIWORD(wParam)) + { + HWND hEdit = GetDlgItem(hDlg,IDC_EDIT_QUOTE); + tstring sQuoteSymbol = get_window_text(hEdit); + assert(false == sQuoteSymbol.empty()); + HWND hwndList = GetDlgItem(hDlg,IDC_LIST_RATES); + if(LB_ERR == is_quote_added(hwndList,sQuoteSymbol)) + { + CQuotesProviderBase::CQuote quote(sQuoteSymbol,sQuoteSymbol); + if(add_quote_to_wnd(quote,hwndList) >= 0) + { + SetDlgItemText(hDlg,IDC_EDIT_QUOTE,_T("")); + SetFocus(hEdit); + PropSheet_Changed(::GetParent(hDlg),hDlg); + } + else + { + ::MessageBeep(MB_ICONERROR); + } + } + } + return (TRUE); + case IDC_BUTTON_REMOVE: + if(BN_CLICKED == HIWORD(wParam)) + { + HWND hWnd = ::GetDlgItem(hDlg,IDC_LIST_RATES); + int nSel = ::SendMessage(hWnd,LB_GETCURSEL,0,0); + if(LB_ERR != nSel) + { + CQuotesProviderBase::CQuote* pQuote = get_quote_ptr_from_lb_index(hWnd,nSel); + delete pQuote; + if(LB_ERR != ::SendMessage(hWnd,LB_DELETESTRING,nSel,0)) + { + PropSheet_Changed(::GetParent(hDlg),hDlg); + } + } + + nSel = ::SendMessage(hWnd,LB_GETCURSEL,0,0); + ::EnableWindow(::GetDlgItem(hDlg,IDC_BUTTON_REMOVE),(LB_ERR != nSel)); + } + return (TRUE); + case IDC_LIST_RATES: + if(CBN_SELCHANGE == HIWORD(wParam)) + { + int nSel = ::SendMessage(::GetDlgItem(hDlg,IDC_LIST_RATES),LB_GETCURSEL,0,0); + ::EnableWindow(::GetDlgItem(hDlg,IDC_BUTTON_REMOVE),(LB_ERR != nSel)); + } + return (TRUE); + } + return (FALSE); + + case WM_NOTIFY: + { + LPNMHDR pNMHDR = reinterpret_cast<LPNMHDR>(lParam); + switch(pNMHDR->code) + { + case PSN_APPLY: + if(pProvider) + { + CQuotesProviderFinance::TQuotes aTemp; + pProvider->GetWatchedQuotes(aTemp); + + typedef std::vector<const CQuotesProviderBase::CQuote*> TQuotesPtr; + TQuotesPtr apCurrent; + HWND hwndListBox = GetDlgItem(hDlg,IDC_LIST_RATES); + int cItems = ::SendMessage(hwndListBox,LB_GETCOUNT,0,0); + for(int i = 0;i < cItems;++i) + { + const CQuotesProviderBase::CQuote* pQuote = get_quote_ptr_from_lb_index(hwndListBox,i); + if(pQuote) + { + apCurrent.push_back(pQuote); + } + } + + std::for_each(aTemp.begin(),aTemp.end(), + [&apCurrent,pProvider](const CQuotesProviderBase::CQuote& quote) + { + if(apCurrent.end() == std::find_if(apCurrent.begin(),apCurrent.end(), + ["e](const CQuotesProviderBase::CQuote* pQuote){return 0 == quotes_stricmp(pQuote->GetID().c_str(),quote.GetID().c_str());})) + { + pProvider->WatchForQuote(quote,false); + } + }); + + std::for_each(apCurrent.begin(),apCurrent.end(), + [&aTemp,pProvider](const CQuotesProviderBase::CQuote* pQuote) + { + if(aTemp.end() == + std::find_if(aTemp.begin(),aTemp.end(), + [pQuote](const CQuotesProviderBase::CQuote& quote){return 0 == quotes_stricmp(pQuote->GetID().c_str(),quote.GetID().c_str());})) + { + pProvider->WatchForQuote(*pQuote,true); + } + + }); + + pProvider->RefreshAll(); + } + + return (TRUE); + } + } + return (FALSE); + case WM_DESTROY: + HWND hwndListBox = GetDlgItem(hDlg,IDC_LIST_RATES); + int cItems = ::SendMessage(hwndListBox,LB_GETCOUNT,0,0); + for(int i = 0;i < cItems;++i) + { + const CQuotesProviderBase::CQuote* pQuote = get_quote_ptr_from_lb_index(hwndListBox,i); + delete pQuote; + } + return (FALSE); + } + return (FALSE); + } +} + +void CQuotesProviderFinance::ShowPropertyPage(WPARAM wp,OPTIONSDIALOGPAGE& odp) +{ + odp.pszTemplate = MAKEINTRESOURCEA(IDD_DIALOG_OPT_FINANCE); + odp.pfnDlgProc = GoogleFinanceOptDlgProc; + odp.dwInitParam = reinterpret_cast<DWORD>(static_cast<CQuotesProviderFinance*>(this)); + odp.ptszTab = const_cast<LPTSTR>(GetInfo().m_sName.c_str()); + CallService(MS_OPT_ADDPAGE,wp,reinterpret_cast<LPARAM>(&odp)); +} diff --git a/protocols/Quotes/QuotesProviderFinance.h b/protocols/Quotes/QuotesProviderFinance.h new file mode 100644 index 0000000000..f63077071d --- /dev/null +++ b/protocols/Quotes/QuotesProviderFinance.h @@ -0,0 +1,21 @@ +#ifndef __95A13A68_0DF0_43FA_B6C1_81D83AED59AA_QuotesProviderFinance_h__ +#define __95A13A68_0DF0_43FA_B6C1_81D83AED59AA_QuotesProviderFinance_h__ + +#include "QuotesProviderBase.h" + +class CQuotesProviderFinance : public CQuotesProviderBase +{ +public: + typedef std::vector<CQuotesProviderBase::CQuote> TQuotes; + +public: + void GetWatchedQuotes(TQuotes& raQuotes)const; + bool WatchForQuote(const CQuote& rQuote,bool bWatch); + HANDLE GetContactByQuoteID(const tstring& rsQuoteID)const; + +protected: + virtual void ShowPropertyPage(WPARAM wp,OPTIONSDIALOGPAGE& odp); + virtual void Accept(CQuotesProviderVisitor& visitor)const; +}; + +#endif //__95A13A68_0DF0_43FA_B6C1_81D83AED59AA_QuotesProviderFinance_h__ \ No newline at end of file diff --git a/protocols/Quotes/QuotesProviderGoogle.cpp b/protocols/Quotes/QuotesProviderGoogle.cpp new file mode 100644 index 0000000000..6458180324 --- /dev/null +++ b/protocols/Quotes/QuotesProviderGoogle.cpp @@ -0,0 +1,543 @@ +#include "StdAfx.h" +#include "QuotesProviderGoogle.h" +#include "resource.h" +#include "HTTPSession.h" +#include "Log.h" +#include "DBUtils.h" +#include "EconomicRateInfo.h" +#include "ModuleInfo.h" +#include "QuotesProviders.h" +#include "IHTMLParser.h" +#include "IHTMLEngine.h" +#include "CommonOptionDlg.h" +#include "QuotesProviderVisitor.h" + +CQuotesProviderGoogle::CQuotesProviderGoogle() +{ +} + +CQuotesProviderGoogle::~CQuotesProviderGoogle() +{ +} + +namespace +{ + inline tstring make_contact_name(const tstring& rsSymbolFrom,const tstring& rsSymbolTo) + { + tostringstream o; + o << rsSymbolFrom << _T("/") << rsSymbolTo; + return o.str(); + } + + inline bool is_rate_watched(HANDLE hContact, + const CQuotesProviderBase::CQuote& from, + const CQuotesProviderBase::CQuote& to) + { + tstring sFrom = Quotes_DBGetStringT(hContact,QUOTES_PROTOCOL_NAME,DB_STR_FROM_ID); + tstring sTo = Quotes_DBGetStringT(hContact,QUOTES_PROTOCOL_NAME,DB_STR_TO_ID); + return ((0 == quotes_stricmp(from.GetID().c_str(),sFrom.c_str())) + && (0 == quotes_stricmp(to.GetID().c_str(),sTo.c_str()))); + } +} + +bool CQuotesProviderGoogle::WatchForRate(const CRateInfo& ri, + bool bWatch) +{ + TContracts::const_iterator i = std::find_if(m_aContacts.begin(),m_aContacts.end(), + boost::bind(is_rate_watched,_1,ri.m_from,ri.m_to)); + if ((true == bWatch) && (i == m_aContacts.end())) + { + tstring sName = make_contact_name(ri.m_from.GetSymbol(),ri.m_to.GetSymbol()); + HANDLE hContact = CreateNewContact(sName); + if(hContact) + { + DBWriteContactSettingTString(hContact,QUOTES_PROTOCOL_NAME,DB_STR_FROM_ID,ri.m_from.GetID().c_str()); + DBWriteContactSettingTString(hContact,QUOTES_PROTOCOL_NAME,DB_STR_TO_ID,ri.m_to.GetID().c_str()); + if(false == ri.m_from.GetName().empty()) + { + DBWriteContactSettingTString(hContact,QUOTES_PROTOCOL_NAME,DB_STR_FROM_DESCRIPTION,ri.m_from.GetName().c_str()); + } + if(false == ri.m_to.GetName().empty()) + { + DBWriteContactSettingTString(hContact,QUOTES_PROTOCOL_NAME,DB_STR_TO_DESCRIPTION,ri.m_to.GetName().c_str()); + } + + return true; + } + } + else if ((false == bWatch) && (i != m_aContacts.end())) + { + HANDLE hContact = *i; + {// for CCritSection + CGuard<CLightMutex> cs(m_cs); + m_aContacts.erase(i); + } + + CallService(MS_DB_CONTACT_DELETE,reinterpret_cast<WPARAM>(hContact),0); + return true; + } + + return false; +} + +size_t CQuotesProviderGoogle::GetWatchedRateCount()const +{ + return m_aContacts.size(); +} + +bool CQuotesProviderGoogle::GetWatchedRateInfo(size_t nIndex,CRateInfo& rRateInfo) +{ + if(nIndex < m_aContacts.size()) + { + HANDLE hContact = m_aContacts[nIndex]; + tstring sSymbolFrom = Quotes_DBGetStringT(hContact,QUOTES_PROTOCOL_NAME,DB_STR_FROM_ID); + tstring sSymbolTo = Quotes_DBGetStringT(hContact,QUOTES_PROTOCOL_NAME,DB_STR_TO_ID); + tstring sDescFrom = Quotes_DBGetStringT(hContact,QUOTES_PROTOCOL_NAME,DB_STR_FROM_DESCRIPTION); + tstring sDescTo = Quotes_DBGetStringT(hContact,QUOTES_PROTOCOL_NAME,DB_STR_TO_DESCRIPTION); + + rRateInfo.m_from = CQuote(sSymbolFrom,sSymbolFrom,sDescFrom); + rRateInfo.m_to = CQuote(sSymbolTo,sSymbolTo,sDescTo); + return true; + } + else + { + return false; + } +} + +namespace +{ + tstring build_url(const tstring& rsURL,const tstring& from,const tstring& to,double dAmount) + { + tostringstream o; + o << rsURL << _T("?a=") << std::fixed << dAmount << _T("&from=") << from << _T("&to=") << to; + return o.str(); + } + tstring build_url(HANDLE hContact,const tstring& rsURL,double dAmount = 1.0) + { + tstring sFrom = Quotes_DBGetStringT(hContact,QUOTES_PROTOCOL_NAME,DB_STR_FROM_ID); + tstring sTo = Quotes_DBGetStringT(hContact,QUOTES_PROTOCOL_NAME,DB_STR_TO_ID); + return build_url(rsURL,sFrom,sTo,dAmount); + } + + typedef IHTMLNode::THTMLNodePtr THTMLNodePtr; + + bool parse_html_node(const THTMLNodePtr& pNode,double& rdRate) + { + tstring sID = pNode->GetAttribute(_T("id")); + if ((false == sID.empty()) && (0 == quotes_stricmp(sID.c_str(),_T("currency_converter_result")))) + { + size_t cChild = pNode->GetChildCount(); +// assert(1 == cChild); + if(cChild > 0) + { + THTMLNodePtr pChild = pNode->GetChildPtr(0); + tstring sRate = pChild->GetText(); + + tistringstream input(sRate); + input >> rdRate; + + return ((false == input.bad()) && (false == input.fail())); + } + } + else + { + size_t cChild = pNode->GetChildCount(); + for(size_t i = 0;i < cChild;++i) + { + THTMLNodePtr pChild = pNode->GetChildPtr(i); + if(pChild && (true == parse_html_node(pChild,rdRate))) + { + return true; + } + } + } + + return false; + } + + bool parse_responce(const tstring& rsHTML,double& rdRate) + { + IHTMLEngine::THTMLParserPtr pHTMLParser = CModuleInfo::GetHTMLEngine()->GetParserPtr(); + THTMLNodePtr pRoot = pHTMLParser->ParseString(rsHTML); + if(pRoot) + { + return parse_html_node(pRoot,rdRate); + } + else + { + return false; + } + } +} + +void CQuotesProviderGoogle::RefreshQuotes(TContracts& anContacts) +{ + CHTTPSession http; + tstring sURL = GetURL(); + + bool bUseExtendedStatus = CModuleInfo::GetInstance().GetExtendedStatusFlag(); + + for(TContracts::const_iterator i = anContacts.begin();i != anContacts.end() && IsOnline();++i) + { + HANDLE hContact = *i; + + if(bUseExtendedStatus) + { + SetContactStatus(hContact,ID_STATUS_OCCUPIED); + } + + tstring sFullURL = build_url(hContact,sURL); +// LogIt(Info,sFullURL); + if ((true == http.OpenURL(sFullURL)) && (true == IsOnline())) + { + tstring sHTML; + if ((true == http.ReadResponce(sHTML)) && (true == IsOnline())) + { +// LogIt(Info,sHTML); + + double dRate = 0.0; + if ((true == parse_responce(sHTML,dRate)) && (true == IsOnline())) + { + WriteContactRate(hContact,dRate); + continue; + } + } + } + + SetContactStatus(hContact,ID_STATUS_NA); + } +} + +namespace +{ + inline tstring make_quote_name(const CQuotesProviderGoogle::CQuote& rQuote) + { + const tstring& rsDesc = rQuote.GetName(); + return((false == rsDesc.empty()) ? rsDesc : rQuote.GetSymbol()); + } + + CQuotesProviderGoogle* get_google_provider() + { + CModuleInfo::TQuotesProvidersPtr& pProviders = CModuleInfo::GetQuoteProvidersPtr(); + const CQuotesProviders::TQuotesProviders& rapQuotesProviders = pProviders->GetProviders(); + for(CQuotesProviders::TQuotesProviders::const_iterator i = rapQuotesProviders.begin();i != rapQuotesProviders.end();++i) + { + const CQuotesProviders::TQuotesProviderPtr& pProvider = *i; + CQuotesProviderGoogle* pGoogle = dynamic_cast<CQuotesProviderGoogle*>(pProvider.get()); + if(pGoogle) + { + return pGoogle; + } + } + + assert(!"We should never get here!"); + return NULL; + } + + CQuotesProviderGoogle::CQuoteSection get_quotes() + { + const CQuotesProviderGoogle* pProvider = get_google_provider(); + if(pProvider) + { + const CQuotesProviderGoogle::CQuoteSection& rQuotes = pProvider->GetQuotes(); + if(rQuotes.GetSectionCount() > 0) + { + return rQuotes.GetSection(0); + } + } + + return CQuotesProviderGoogle::CQuoteSection(); + } + + tstring make_rate_name(const CQuotesProviderGoogle::CQuote& rFrom, + const CQuotesProviderGoogle::CQuote& rTo) + { + if ((false == rFrom.GetName().empty()) && (false == rTo.GetName().empty())) + { + return make_contact_name(rFrom.GetName(),rTo.GetName()); + } + else + { + return make_contact_name(rFrom.GetSymbol(),rTo.GetSymbol()); + } + } + + typedef std::vector<CQuotesProviderGoogle::CRateInfo> TWatchedRates; + TWatchedRates g_aWatchedRates; + + bool is_equal_rate(const CQuotesProviderGoogle::CRateInfo& riL,const CQuotesProviderGoogle::CRateInfo& riR) + { + return ((0 == quotes_stricmp(riL.m_from.GetID().c_str(),riR.m_from.GetID().c_str())) + && ((0 == quotes_stricmp(riL.m_to.GetID().c_str(),riR.m_to.GetID().c_str())))); + } + + INT_PTR CALLBACK GoogleOptDlgProc(HWND hdlg,UINT message,WPARAM wParam,LPARAM lParam) + { + CQuotesProviderGoogle* pProvider = get_google_provider(); + + CCommonDlgProcData d(pProvider); + CommonOptionDlgProc(hdlg,message,wParam,lParam,d); + + switch(message) + { + case WM_NOTIFY: + { + LPNMHDR pNMHDR = reinterpret_cast<LPNMHDR>(lParam); + switch(pNMHDR->code) + { + case PSN_APPLY: + { + if(pProvider) + { + TWatchedRates aTemp(g_aWatchedRates); + TWatchedRates aRemove; + size_t cWatchedRates = pProvider->GetWatchedRateCount(); + for(size_t i = 0;i < cWatchedRates;++i) + { + CQuotesProviderGoogle::CRateInfo ri; + if(true == pProvider->GetWatchedRateInfo(i,ri)) + { + TWatchedRates::iterator it = + std::find_if(aTemp.begin(),aTemp.end(), + boost::bind(is_equal_rate,_1,boost::cref(ri))); + if(it == aTemp.end()) + { + aRemove.push_back(ri); + } + else + { + aTemp.erase(it); + } + } + } + + std::for_each(aRemove.begin(),aRemove.end(),boost::bind(&CQuotesProviderGoogle::WatchForRate,pProvider,_1,false)); + std::for_each(aTemp.begin(),aTemp.end(),boost::bind(&CQuotesProviderGoogle::WatchForRate,pProvider,_1,true)); + + pProvider->RefreshAll(); + } + } + break; + } + } + break; + case WM_INITDIALOG: + { + TranslateDialogDefault(hdlg); + + g_aWatchedRates.clear(); + + HWND hcbxFrom = ::GetDlgItem(hdlg,IDC_COMBO_CONVERT_FROM); + HWND hcbxTo = ::GetDlgItem(hdlg,IDC_COMBO_CONVERT_INTO); + + const CQuotesProviderGoogle::CQuoteSection& rSection = get_quotes(); + size_t cQuotes = rSection.GetQuoteCount(); + for(size_t i = 0;i < cQuotes;++i) + { + const CQuotesProviderGoogle::CQuote& rQuote = rSection.GetQuote(i); + tstring sName = make_quote_name(rQuote); + LPCTSTR pszName = sName.c_str(); + ::SendMessage(hcbxFrom,CB_ADDSTRING,0,reinterpret_cast<LPARAM>(pszName)); + ::SendMessage(hcbxTo,CB_ADDSTRING,0,reinterpret_cast<LPARAM>(pszName)); + } + + CQuotesProviderGoogle* pProvider = get_google_provider(); + if(pProvider) + { + size_t cWatchedRates = pProvider->GetWatchedRateCount(); + for(size_t i = 0;i < cWatchedRates;++i) + { + CQuotesProviderGoogle::CRateInfo ri; + if(true == pProvider->GetWatchedRateInfo(i,ri)) + { + g_aWatchedRates.push_back(ri); + tstring sRate = make_rate_name(ri.m_from,ri.m_to); + LPCTSTR pszRateName = sRate.c_str(); + ::SendMessage(::GetDlgItem(hdlg,IDC_LIST_RATES),LB_ADDSTRING,0,reinterpret_cast<LPARAM>(pszRateName)); + } + } + } + + ::EnableWindow(::GetDlgItem(hdlg,IDC_BUTTON_ADD),FALSE); + ::EnableWindow(::GetDlgItem(hdlg,IDC_BUTTON_REMOVE),FALSE); + } + return TRUE; + case WM_COMMAND: + switch(HIWORD(wParam)) + { + case CBN_SELCHANGE: + switch(LOWORD(wParam)) + { + case IDC_COMBO_REFRESH_RATE: + break; + case IDC_COMBO_CONVERT_FROM: + case IDC_COMBO_CONVERT_INTO: + { + int nFrom = static_cast<int>(::SendMessage(::GetDlgItem(hdlg,IDC_COMBO_CONVERT_FROM),CB_GETCURSEL,0,0)); + int nTo = static_cast<int>(::SendMessage(::GetDlgItem(hdlg,IDC_COMBO_CONVERT_INTO),CB_GETCURSEL,0,0)); + bool bEnableAddButton = ((CB_ERR != nFrom) && (CB_ERR != nTo) && (nFrom != nTo)); + EnableWindow(GetDlgItem(hdlg,IDC_BUTTON_ADD),bEnableAddButton); + } + break; + case IDC_LIST_RATES: + { + int nSel = ::SendMessage(::GetDlgItem(hdlg,IDC_LIST_RATES),LB_GETCURSEL,0,0); + ::EnableWindow(::GetDlgItem(hdlg,IDC_BUTTON_REMOVE),(LB_ERR != nSel)); + } + break; + } + break; + case BN_CLICKED: + switch(LOWORD(wParam)) + { + case IDC_BUTTON_ADD: + { + size_t nFrom = static_cast<size_t>(::SendMessage(::GetDlgItem(hdlg,IDC_COMBO_CONVERT_FROM),CB_GETCURSEL,0,0)); + size_t nTo = static_cast<size_t>(::SendMessage(::GetDlgItem(hdlg,IDC_COMBO_CONVERT_INTO),CB_GETCURSEL,0,0)); + if ((CB_ERR != nFrom) && (CB_ERR != nTo) && (nFrom != nTo)) + { + const CQuotesProviderGoogle::CQuoteSection& rSection = get_quotes(); + size_t cQuotes = rSection.GetQuoteCount(); + if ((nFrom < cQuotes) && (nTo < cQuotes)) + { + CQuotesProviderGoogle::CRateInfo ri; + ri.m_from = rSection.GetQuote(nFrom); + ri.m_to = rSection.GetQuote(nTo); + + g_aWatchedRates.push_back(ri); + + tstring sRate = make_rate_name(ri.m_from,ri.m_to); + LPCTSTR pszRateName = sRate.c_str(); + ::SendMessage(::GetDlgItem(hdlg,IDC_LIST_RATES),LB_ADDSTRING,0,reinterpret_cast<LPARAM>(pszRateName)); + PropSheet_Changed(::GetParent(hdlg),hdlg); + } + } + } + break; + case IDC_BUTTON_REMOVE: + { + HWND hWnd = ::GetDlgItem(hdlg,IDC_LIST_RATES); + int nSel = ::SendMessage(hWnd,LB_GETCURSEL,0,0); + if(LB_ERR != nSel) + { + if ((LB_ERR != ::SendMessage(hWnd, LB_DELETESTRING,nSel,0)) + && (nSel < static_cast<int>(g_aWatchedRates.size()))) + { + + TWatchedRates::iterator i = g_aWatchedRates.begin(); + std::advance(i,nSel); + g_aWatchedRates.erase(i); + PropSheet_Changed(::GetParent(hdlg),hdlg); + } + } + + nSel = ::SendMessage(hWnd,LB_GETCURSEL,0,0); + ::EnableWindow(::GetDlgItem(hdlg,IDC_BUTTON_REMOVE),(LB_ERR != nSel)); + } + break; + } + break; +// case LBN_SELCHANGE: +// switch(LOWORD(lParam)) +// { +// case IDC_LIST_RATES: +// { +// int nSel = ::SendMessage(::GetDlgItem(hdlg,IDC_LIST_RATES),LB_GETCURSEL,0,0); +// ::EnableWindow(::GetDlgItem(hdlg,IDC_BUTTON_REMOVE),(-1 != nSel)); +// } +// } +// break; + } + break; + + } + + return FALSE; + } +} + +void CQuotesProviderGoogle::ShowPropertyPage(WPARAM wp,OPTIONSDIALOGPAGE& odp) +{ + odp.pszTemplate = MAKEINTRESOURCEA(IDD_DIALOG_OPT_GOOGLE); + odp.pfnDlgProc = GoogleOptDlgProc; +// #if MIRANDA_VER >= 0x0600 + //odp.ptszTab = TranslateTS(const_cast<LPTSTR>(GetInfo().m_sName.c_str())); + odp.ptszTab = const_cast<LPTSTR>(GetInfo().m_sName.c_str()); +// #else +// tostringstream o; +// o << TranslateTS(QUOTES_PROTOCOL_NAME) << _T(" - ") << TranslateTS(GetInfo().m_sName.c_str()); +// tstring sTitle = o.str(); +// odp.ptszTitle = TranslateTS(const_cast<LPTSTR>(sTitle.c_str())); +// #endif + CallService(MS_OPT_ADDPAGE,wp,reinterpret_cast<LPARAM>(&odp)); +} + +void CQuotesProviderGoogle::Accept(CQuotesProviderVisitor& visitor)const +{ + CQuotesProviderBase::Accept(visitor); + visitor.Visit(*this); +} + +double CQuotesProviderGoogle::Convert(double dAmount,const CQuote& from,const CQuote& to)const +{ + tstring sFullURL = build_url(GetURL(),from.GetID(),to.GetID(),dAmount); +// LogIt(Info,sFullURL); + + CHTTPSession http; + if ((true == http.OpenURL(sFullURL))) + { + tstring sHTML; + if ((true == http.ReadResponce(sHTML))) + { +// LogIt(Info,sHTML); + + double dResult = 0.0; + if ((true == parse_responce(sHTML,dResult))) + { + return dResult; + } + else + { + throw std::runtime_error(Translate("Error occurred during html parsing.")); + } + } + else + { + throw std::runtime_error(Translate("Error occurred during site access.")); + } + } + else + { + throw std::runtime_error(Translate("Error occurred during site access.")); + } + + return 0.0; +} + +namespace +{ + bool is_equal_ids(HANDLE hContact,const tstring& rsFromID,const tstring& rsToID) + { + tstring sFrom = Quotes_DBGetStringT(hContact,QUOTES_PROTOCOL_NAME,DB_STR_FROM_ID); + tstring sTo = Quotes_DBGetStringT(hContact,QUOTES_PROTOCOL_NAME,DB_STR_TO_ID); + return ((0 == quotes_stricmp(rsFromID.c_str(),sFrom.c_str())) + && (0 == quotes_stricmp(rsToID.c_str(),sTo.c_str()))); + } +} + +HANDLE CQuotesProviderGoogle::GetContactByID(const tstring& rsFromID,const tstring& rsToID)const +{ + CGuard<CLightMutex> cs(m_cs); + + TContracts::const_iterator i = std::find_if(m_aContacts.begin(),m_aContacts.end(), + boost::bind(is_equal_ids,_1,boost::cref(rsFromID),boost::cref(rsToID))); + if(i != m_aContacts.end()) + { + return *i; + } + else + { + return NULL; + } +} diff --git a/protocols/Quotes/QuotesProviderGoogle.h b/protocols/Quotes/QuotesProviderGoogle.h new file mode 100644 index 0000000000..4289861178 --- /dev/null +++ b/protocols/Quotes/QuotesProviderGoogle.h @@ -0,0 +1,42 @@ +#ifndef __c0e48a95_b3f0_4227_8adc_455e265f3c14_QuotesProviderGoogle_h__ +#define __c0e48a95_b3f0_4227_8adc_455e265f3c14_QuotesProviderGoogle_h__ + +#include "quotesproviderBase.h" + +#define DB_STR_FROM_ID "FromID" +#define DB_STR_TO_ID "ToID" +#define DB_STR_FROM_DESCRIPTION "FromDesc" +#define DB_STR_TO_DESCRIPTION "ToDesc" +#define DB_STR_GOOGLE_REFRESH_RATE_TYPE "Google_RefreshRateType" +#define DB_STR_GOOGLE_REFRESH_RATE_VALUE "Google_RefreshRateValue" +#define DB_STR_GOOGLE_DISPLAY_NAME_FORMAT "Google_DspNameFrmt" +// #define DB_STR_GOOGLE_LOG_FILE_FORMAT "Google_LogFileFormat" +// #define DB_STR_GOOGLE_HISTORY_FORMAT "Google_HistoryFormat" + +class CQuotesProviderGoogle : public CQuotesProviderBase +{ +public: + struct CRateInfo + { + CQuotesProviderBase::CQuote m_from; + CQuotesProviderBase::CQuote m_to; + }; +public: + CQuotesProviderGoogle(); + ~CQuotesProviderGoogle(); + + bool WatchForRate(const CRateInfo& ri,bool bWatch); + size_t GetWatchedRateCount()const; + bool GetWatchedRateInfo(size_t nIndex,CRateInfo& rRateInfo); + + HANDLE GetContactByID(const tstring& rsFromID,const tstring& rsToID)const; + + double Convert(double dAmount,const CQuote& from,const CQuote& to)const; + +private: + virtual void RefreshQuotes(TContracts& anContacts); + virtual void ShowPropertyPage(WPARAM wp,OPTIONSDIALOGPAGE& odp); + virtual void Accept(CQuotesProviderVisitor& visitor)const; +}; + +#endif //__c0e48a95_b3f0_4227_8adc_455e265f3c14_QuotesProviderGoogle_h__ diff --git a/protocols/Quotes/QuotesProviderGoogleFinance.cpp b/protocols/Quotes/QuotesProviderGoogleFinance.cpp new file mode 100644 index 0000000000..8a129b6b8b --- /dev/null +++ b/protocols/Quotes/QuotesProviderGoogleFinance.cpp @@ -0,0 +1,366 @@ +#include "StdAfx.h" +#include "QuotesProviderGoogleFinance.h" +#include "QuotesProviderVisitor.h" +#include "EconomicRateInfo.h" +#include "DBUtils.h" +#include "resource.h" +#include "ModuleInfo.h" +// #include "QuotesProviders.h" +// #include "CommonOptionDlg.h" +// #include "WinCtrlHelper.h" +#include "IHTMLParser.h" +#include "IHTMLEngine.h" +#include "HTTPSession.h" +#include "Log.h" +#include "Locale.h" + +CQuotesProviderGoogleFinance::CQuotesProviderGoogleFinance() +{ +} + +CQuotesProviderGoogleFinance::~CQuotesProviderGoogleFinance() +{ +} + +namespace +{ + tstring build_url(HANDLE hContact,const tstring& rsURL) + { + tostringstream o; + o << rsURL << _T("?q=") << Quotes_DBGetStringT(hContact,QUOTES_MODULE_NAME,DB_STR_QUOTE_ID); + return o.str(); + } + + struct CGoogleInfo + { + enum + { + giRate = 0x0001, + giOpen = 0x0002, + giPercentChangeAfterHours = 0x0004, + giPercentChangeToYesterdayClose = 0x0008 + }; + CGoogleInfo() + : m_dRate(0.0),m_dOpenValue(0.0),m_dPercentChangeAfterHours(0.0),m_dPercentChangeToYersterdayClose(0.0),m_nFlags(0){} +// tstring m_sCmpID; + tstring m_sCmpName; + double m_dRate; + double m_dOpenValue; + double m_dPercentChangeAfterHours; + double m_dPercentChangeToYersterdayClose; + +// tstring m_sRateID; +// tstring m_sDiffID; + byte m_nFlags; + }; + + tstring make_rate_id_value(const tstring& rsCmpID,int nFlags) + { + tostringstream o; + o << _T("ref_") << rsCmpID; + switch(nFlags) + { + default: + assert(!"Unknown type of value"); + case CGoogleInfo::giRate: + o << _T("_l"); + break; + case CGoogleInfo::giPercentChangeAfterHours: + o << _T("_ecp"); + break; + case CGoogleInfo::giPercentChangeToYesterdayClose: + o << _T("_cp"); + break; + } + + return o.str(); + } + + tstring get_var_value(const tstring& rsHTML,LPCTSTR pszVarName,size_t cVarNameLength) + { + tstring sResult; + tstring::size_type n = rsHTML.find(pszVarName); + if(tstring::npos != n) + { + size_t cLengthHTML = rsHTML.size(); + for(size_t i = n + cVarNameLength;i < cLengthHTML;++i) + { + TCHAR c = rsHTML[i]; + if(_T(';') == c) + { + break; + } + else + { + sResult.push_back(c); + } + } + } + + return sResult; + } + + tstring get_company_id(const tstring& rsHTML) + { + static LPCTSTR pszVarName = _T("setCompanyId("); + static size_t cVarNameLength = _tcslen(pszVarName); + + tstring sResult; + tstring::size_type n = rsHTML.find(pszVarName); + if(tstring::npos != n) + { + size_t cLengthHTML = rsHTML.size(); + for(size_t i = n + cVarNameLength;i < cLengthHTML;++i) + { + TCHAR c = rsHTML[i]; + if(_T(')') == c) + { + break; + } + else + { + sResult.push_back(c); + } + } + } + return sResult; +// return get_var_value(rsHTML,pszVarName,cVarNameLength); + } + + tstring get_company_name(const tstring& rsHTML) + { + static LPCTSTR pszVarName = _T("var _companyName = "); + static size_t cVarNameLength = _tcslen(pszVarName); + + tstring s = get_var_value(rsHTML,pszVarName,cVarNameLength); + if(s.size() > 0 && _T('\'') == s[0]) + { + s.erase(s.begin()); + } + + if(s.size() > 0 && _T('\'') == s[s.size()-1]) + { + s.erase(s.rbegin().base()-1); + } + + return s; + } + + bool get_double_value(const tstring& rsText,double& rdValue) + { + tistringstream input(rsText); + input.imbue(std::locale("English_United States.1252")); + input >> rdValue; + + if ((true == input.bad()) || (true == input.fail())) + { + tistringstream inputSys(rsText); + input.imbue(GetSystemLocale()); + input >> rdValue; + return (false == inputSys.bad()) && (false == inputSys.fail()); + } + else + { + return true; + } + } + + bool get_rate(const IHTMLNode::THTMLNodePtr& pRate,CGoogleInfo& rInfo) + { + tstring sRate = pRate->GetText(); + + if(true == get_double_value(sRate,rInfo.m_dRate)) + { + rInfo.m_nFlags |= CGoogleInfo::giRate; + return true; + } + else + { + return false; + } + } + + bool get_inline_data(const IHTMLNode::THTMLNodePtr& pNode,CGoogleInfo& rInfo) + { + size_t cChild = pNode->GetChildCount(); + for(size_t i = 0;i < cChild;++i) + { + IHTMLNode::THTMLNodePtr pChild = pNode->GetChildPtr(i); + size_t c = pChild->GetChildCount(); + assert(2 == c); + if(c >= 2) + { + IHTMLNode::THTMLNodePtr pName = pChild->GetChildPtr(0); + + tstring sName = pName->GetText(); + if(0 == quotes_stricmp(sName.c_str(),_T("Open"))) + { + IHTMLNode::THTMLNodePtr pValue = pChild->GetChildPtr(1); + tstring sValue = pValue->GetText(); + if(true == get_double_value(sValue,rInfo.m_dOpenValue)) + { + rInfo.m_nFlags |= CGoogleInfo::giOpen; + } + return true; + } + } + } + + return false; + } + + bool get_dif_value(const IHTMLNode::THTMLNodePtr& pNode,CGoogleInfo& rInfo,int nItem) + { + tstring sDiff = pNode->GetText(); + // this value is in brackets and it has percentage sign. + // Remove these symbols. + for(tstring::iterator i = sDiff.begin();i != sDiff.end();) + { + TCHAR s = *i; + if(_T('(') == s || _T(')') == s || _T('%') == s) + { + i = sDiff.erase(i); + } + else + { + ++i; + } + } + + double* pValue = NULL; + switch(nItem) + { + case CGoogleInfo::giPercentChangeAfterHours: + pValue = &rInfo.m_dPercentChangeAfterHours; + break; + case CGoogleInfo::giPercentChangeToYesterdayClose: + pValue = &rInfo.m_dPercentChangeToYersterdayClose; + break; + } + + assert(pValue); + + if ((pValue) && (true == get_double_value(sDiff,*pValue))) + { + rInfo.m_nFlags |= nItem; + return true; + } + else + { + return false; + } + + } + + bool parse_responce(const tstring& rsHTML,CGoogleInfo& rInfo) + { + IHTMLEngine::THTMLParserPtr pHTMLParser = CModuleInfo::GetHTMLEngine()->GetParserPtr(); + IHTMLNode::THTMLNodePtr pRoot = pHTMLParser->ParseString(rsHTML); + if(pRoot) + { + tstring sCmpID = get_company_id(rsHTML); + if(false == sCmpID.empty()) + { + tstring sRateID = make_rate_id_value(sCmpID,CGoogleInfo::giRate); + IHTMLNode::THTMLNodePtr pRate = pRoot->GetElementByID(sRateID); + if(pRate && get_rate(pRate,rInfo)) + { + rInfo.m_sCmpName = get_company_name(rsHTML); + + IHTMLNode::THTMLNodePtr pInline = pRoot->GetElementByID(_T("snap-data")); + if(pInline) + { + get_inline_data(pInline,rInfo); + } + + tstring sDiffID = make_rate_id_value(sCmpID,CGoogleInfo::giPercentChangeAfterHours); + IHTMLNode::THTMLNodePtr pDiff = pRoot->GetElementByID(sDiffID); + if(pDiff) + { + get_dif_value(pDiff,rInfo,CGoogleInfo::giPercentChangeAfterHours); + } + + sDiffID = make_rate_id_value(sCmpID,CGoogleInfo::giPercentChangeToYesterdayClose); + pDiff = pRoot->GetElementByID(sDiffID); + if(pDiff) + { + get_dif_value(pDiff,rInfo,CGoogleInfo::giPercentChangeToYesterdayClose); + } + + return true; + } + + //return (true == parse_html_node(pRoot,rInfo)); + } + } + + return false; + } +} + +void CQuotesProviderGoogleFinance::RefreshQuotes(TContracts& anContacts) +{ + CHTTPSession http; + tstring sURL = GetURL(); + bool bUseExtendedStatus = CModuleInfo::GetInstance().GetExtendedStatusFlag(); + + for(TContracts::const_iterator i = anContacts.begin();i != anContacts.end() && IsOnline();++i) + { + HANDLE hContact = *i; + + if(bUseExtendedStatus) + { + SetContactStatus(hContact,ID_STATUS_OCCUPIED); + } + + tstring sFullURL = build_url(hContact,sURL); +// LogIt(Info,sFullURL); + if ((true == http.OpenURL(sFullURL)) && (true == IsOnline())) + { + tstring sHTML; + if ((true == http.ReadResponce(sHTML)) && (true == IsOnline())) + { +// LogIt(Info,sHTML); + + CGoogleInfo Info; + parse_responce(sHTML,Info); + if(true == IsOnline()) + { + if(Info.m_nFlags&CGoogleInfo::giRate) + { + if(Info.m_nFlags&CGoogleInfo::giOpen) + { + Quotes_DBWriteDouble(hContact,QUOTES_MODULE_NAME,DB_STR_GOOGLE_FINANCE_OPEN_VALUE,Info.m_dOpenValue); + } + if(Info.m_nFlags&CGoogleInfo::giPercentChangeAfterHours) + { + Quotes_DBWriteDouble(hContact,QUOTES_MODULE_NAME,DB_STR_GOOGLE_FINANCE_DIFF,Info.m_dPercentChangeAfterHours); + } + if(Info.m_nFlags&CGoogleInfo::giPercentChangeToYesterdayClose) + { + Quotes_DBWriteDouble(hContact,QUOTES_MODULE_NAME,DB_STR_GOOGLE_FINANCE_PERCENT_CHANGE_TO_YERSTERDAY_CLOSE,Info.m_dPercentChangeToYersterdayClose); + } + if(false == Info.m_sCmpName.empty()) + { + DBWriteContactSettingTString(hContact,QUOTES_MODULE_NAME,DB_STR_QUOTE_DESCRIPTION,Info.m_sCmpName.c_str()); + } + + WriteContactRate(hContact,Info.m_dRate); + continue; + } + } + } + } + + SetContactStatus(hContact,ID_STATUS_NA); + } + +} + + +void CQuotesProviderGoogleFinance::Accept(CQuotesProviderVisitor& visitor)const +{ + CQuotesProviderFinance::Accept(visitor); + visitor.Visit(*this); +} + diff --git a/protocols/Quotes/QuotesProviderGoogleFinance.h b/protocols/Quotes/QuotesProviderGoogleFinance.h new file mode 100644 index 0000000000..075498a4dd --- /dev/null +++ b/protocols/Quotes/QuotesProviderGoogleFinance.h @@ -0,0 +1,25 @@ +#ifndef __89D3CC58_7DED_484f_AA25_62BDBB57E18B_QuotesProvider_Google_Finance_h__ +#define __89D3CC58_7DED_484f_AA25_62BDBB57E18B_QuotesProvider_Google_Finance_h__ + +#include "QuotesProviderFinance.h" + +#define DB_STR_GOOGLE_FINANCE_OPEN_VALUE "OpenQuotePrice" +#define DB_STR_GOOGLE_FINANCE_DIFF "DifferentFromStartOfDay" +#define DB_STR_GOOGLE_FINANCE_PERCENT_CHANGE_TO_YERSTERDAY_CLOSE "PercentChangeToYersterdayClose" + +// #define DB_STR_GOOGLE_FINANCE_COMP_NAME "CompanyName" + + +class CQuotesProviderGoogleFinance : public CQuotesProviderFinance +{ + +public: + CQuotesProviderGoogleFinance(); + ~CQuotesProviderGoogleFinance(); + +private: + virtual void RefreshQuotes(TContracts& anContacts); + virtual void Accept(CQuotesProviderVisitor& visitor)const; +}; + +#endif //__89D3CC58_7DED_484f_AA25_62BDBB57E18B_QuotesProvider_Google_Finance_h__ diff --git a/protocols/Quotes/QuotesProviderVisitor.h b/protocols/Quotes/QuotesProviderVisitor.h new file mode 100644 index 0000000000..9ae601f2a1 --- /dev/null +++ b/protocols/Quotes/QuotesProviderVisitor.h @@ -0,0 +1,25 @@ +#ifndef __7fca59e7_17b2_4849_bd7a_02c7675f2d76_QuotesProviderVisitor_h__ +#define __7fca59e7_17b2_4849_bd7a_02c7675f2d76_QuotesProviderVisitor_h__ + +class CQuotesProviderBase; +class CQuotesProviderFinance; +class CQuotesProviderDukasCopy; +class CQuotesProviderGoogle; +class CQuotesProviderGoogleFinance; +class CQuotesProviderYahoo; + +class CQuotesProviderVisitor +{ +public: + CQuotesProviderVisitor() {} + virtual ~CQuotesProviderVisitor() {} + + virtual void Visit(const CQuotesProviderBase& rProvider){} + virtual void Visit(const CQuotesProviderFinance& rProvider){} + virtual void Visit(const CQuotesProviderDukasCopy& rProvider){} + virtual void Visit(const CQuotesProviderGoogle& rProvider){} + virtual void Visit(const CQuotesProviderGoogleFinance& rProvider){} + virtual void Visit(const CQuotesProviderYahoo& rProvider){} +}; + +#endif //__7fca59e7_17b2_4849_bd7a_02c7675f2d76_QuotesProviderVisitor_h__ diff --git a/protocols/Quotes/QuotesProviderVisitorDbSettings.cpp b/protocols/Quotes/QuotesProviderVisitorDbSettings.cpp new file mode 100644 index 0000000000..5caea48685 --- /dev/null +++ b/protocols/Quotes/QuotesProviderVisitorDbSettings.cpp @@ -0,0 +1,157 @@ +#include "StdAfx.h" +#include "QuotesProviderVisitorDbSettings.h" + +#include "QuotesProviderGoogle.h" +#include "QuotesProviderDukasCopy.h" + +CQuotesProviderVisitorDbSettings::CQuotesProviderVisitorDbSettings() + : m_pszDbRefreshRateType(NULL), + m_pszDbRefreshRateValue(NULL), + m_pszDbDisplayNameFormat(NULL), + m_pszDefDisplayFormat(NULL), + m_pszDefLogFileFormat(NULL), + m_pszDefHistoryFormat(NULL), + m_pszXMLIniFileName(NULL), + m_pszDbStatusMsgFormat(NULL), + m_pszDefStatusMsgFormat(NULL), + m_pszDbLogMode(NULL), + m_pszDbHistoryFormat(NULL), + m_pszDbHistoryCondition(NULL), + m_pszDbLogFile(NULL), + m_pszDbLogFormat(NULL), + m_pszDbLogCondition(NULL), + m_pszDbPopupFormat(NULL), + m_pszDefPopupFormat(NULL), + m_pszDbPopupCondition(NULL), + m_pszDbPopupColourMode(NULL), + m_pszDbPopupBkColour(NULL), + m_pszDbPopupTextColour(NULL), + m_pszDbPopupDelayMode(NULL), + m_pszDbPopupDelayTimeout(NULL), + m_pszDbPopupHistoryFlag(NULL), + m_pszDbTendencyFormat(nullptr), + m_pszDefTendencyFormat(_T("%r>%p")) +{ +} + +CQuotesProviderVisitorDbSettings::~CQuotesProviderVisitorDbSettings() +{ +} + +void CQuotesProviderVisitorDbSettings::Visit(const CQuotesProviderBase&/* rProvider*/) +{ + m_pszDefLogFileFormat = _T("%s\\t%t\\t%r\\n"); + m_pszDefHistoryFormat = _T("%s %r"); + m_pszDefPopupFormat = _T("\\nCurrent = %r\\nPrevious = %p"); +} + +void CQuotesProviderVisitorDbSettings::Visit(const CQuotesProviderDukasCopy&/* rProvider*/) +{ + m_pszDbRefreshRateType = DB_STR_REFRESH_RATE_TYPE; + m_pszDbRefreshRateValue = DB_STR_REFRESH_RATE_VALUE; + m_pszDbDisplayNameFormat = DB_STR_DC_DISPLAY_NAME_FORMAT; + m_pszDefDisplayFormat = _T("%s %r"); + m_pszXMLIniFileName = _T("Dukascopy.xml"); + m_pszDbStatusMsgFormat = "DC_StatusMessageFormat"; + + m_pszDbLogMode = "DC_LogMode"; + m_pszDbHistoryFormat = "DC_HistoryFormat"; + m_pszDbHistoryCondition = "DC_AddToHistoryOnlyIfValueIsChanged"; + m_pszDbLogFile = "DC_LogFile"; + m_pszDbLogFormat = "DC_LogFileFormat"; + m_pszDbLogCondition = "DC_AddToLogOnlyIfValueIsChanged"; + m_pszDbPopupFormat ="DC_PopupFormat"; + m_pszDbPopupCondition = "DC_ShowPopupOnlyIfValueChanged"; + + m_pszDbPopupColourMode = "DC_PopupColourMode"; + m_pszDbPopupBkColour = "DC_PopupColourBk"; + m_pszDbPopupTextColour = "DC_PopupColourText"; + m_pszDbPopupDelayMode = "DC_PopupDelayMode"; + m_pszDbPopupDelayTimeout = "DC_PopupDelayTimeout"; + m_pszDbPopupHistoryFlag = "DC_PopupHistoryFlag"; + m_pszDbTendencyFormat = "DC_TendencyFormat"; +} + +void CQuotesProviderVisitorDbSettings::Visit(const CQuotesProviderGoogle&/* rProvider*/) +{ + m_pszDbRefreshRateType = DB_STR_GOOGLE_REFRESH_RATE_TYPE; + m_pszDbRefreshRateValue = DB_STR_GOOGLE_REFRESH_RATE_VALUE; + m_pszDbDisplayNameFormat = DB_STR_GOOGLE_DISPLAY_NAME_FORMAT; + m_pszDefDisplayFormat = _T("1 %f = %r %i"); + m_pszXMLIniFileName = _T("Google.xml"); + m_pszDbStatusMsgFormat = "Google_StatusMessageFormat"; + + m_pszDbLogMode = "Google_LogMode"; + m_pszDbHistoryFormat = "Google_HistoryFormat"; + m_pszDbHistoryCondition = "Google_AddToHistoryOnlyIfValueIsChanged"; + m_pszDbLogFile = "Google_LogFile"; + m_pszDbLogFormat = "Google_LogFileFormat"; + m_pszDbLogCondition = "Google_AddToLogOnlyIfValueIsChanged"; + m_pszDbPopupFormat ="Google_PopupFormat"; + m_pszDbPopupCondition = "Google_ShowPopupOnlyIfValueChanged"; + + m_pszDbPopupColourMode = "Google_PopupColourMode"; + m_pszDbPopupBkColour = "Google_PopupColourBk"; + m_pszDbPopupTextColour = "Google_PopupColourText"; + m_pszDbPopupDelayMode = "Google_PopupDelayMode"; + m_pszDbPopupDelayTimeout = "Google_PopupDelayTimeout"; + m_pszDbPopupHistoryFlag = "Google_PopupHistoryFlag"; + + m_pszDbTendencyFormat = "Google_TendencyFormat"; +} + +void CQuotesProviderVisitorDbSettings::Visit(const CQuotesProviderGoogleFinance&/* rProvider*/) +{ + m_pszDbRefreshRateType = "GoogleFinance_RefreshRateType"; + m_pszDbRefreshRateValue = "GoogleFinance_RefreshRateValue"; + m_pszDbDisplayNameFormat = "GoogleFinance_DspNameFrmt"; + m_pszDefDisplayFormat = _T("%s %r"); + m_pszXMLIniFileName = _T("GoogleFinance.xml"); + m_pszDbStatusMsgFormat = "GoogleFinance_StatusMessageFormat"; + + m_pszDbLogMode = "GoogleFinance_LogMode"; + m_pszDbHistoryFormat = "GoogleFinance_HistoryFormat"; + m_pszDbHistoryCondition = "GoogleFinance_AddToHistoryOnlyIfValueIsChanged"; + m_pszDbLogFile = "GoogleFinance_LogFile"; + m_pszDbLogFormat = "GoogleFinance_LogFileFormat"; + m_pszDbLogCondition = "GoogleFinance_AddToLogOnlyIfValueIsChanged"; + m_pszDbPopupFormat ="GoogleFinance_PopupFormat"; + m_pszDbPopupCondition = "GoogleFinance_ShowPopupOnlyIfValueChanged"; + + m_pszDbPopupColourMode = "GoogleFinance_PopupColourMode"; + m_pszDbPopupBkColour = "GoogleFinance_PopupColourBk"; + m_pszDbPopupTextColour = "GoogleFinance_PopupColourText"; + m_pszDbPopupDelayMode = "GoogleFinance_PopupDelayMode"; + m_pszDbPopupDelayTimeout = "GoogleFinance_PopupDelayTimeout"; + m_pszDbPopupHistoryFlag = "GoogleFinance_PopupHistoryFlag"; + + m_pszDbTendencyFormat = "GoogleFinance_TendencyFormat"; +} + +void CQuotesProviderVisitorDbSettings::Visit(const CQuotesProviderYahoo& rProvider) +{ + m_pszDbRefreshRateType = "Yahoo_RefreshRateType"; + m_pszDbRefreshRateValue = "Yahoo_RefreshRateValue"; + m_pszDbDisplayNameFormat = "Yahoo_DspNameFrmt"; + m_pszDefDisplayFormat = _T("%s %r"); + m_pszXMLIniFileName = _T("Yahoo.xml"); + m_pszDbStatusMsgFormat = "Yahoo_StatusMessageFormat"; + + m_pszDbLogMode = "Yahoo_LogMode"; + m_pszDbHistoryFormat = "Yahoo_HistoryFormat"; + m_pszDbHistoryCondition = "Yahoo_AddToHistoryOnlyIfValueIsChanged"; + m_pszDbLogFile = "Yahoo_LogFile"; + m_pszDbLogFormat = "Yahoo_LogFileFormat"; + m_pszDbLogCondition = "Yahoo_AddToLogOnlyIfValueIsChanged"; + m_pszDbPopupFormat ="Yahoo_PopupFormat"; + m_pszDbPopupCondition = "Yahoo_ShowPopupOnlyIfValueChanged"; + + m_pszDbPopupColourMode = "Yahoo_PopupColourMode"; + m_pszDbPopupBkColour = "Yahoo_PopupColourBk"; + m_pszDbPopupTextColour = "Yahoo_PopupColourText"; + m_pszDbPopupDelayMode = "Yahoo_PopupDelayMode"; + m_pszDbPopupDelayTimeout = "Yahoo_PopupDelayTimeout"; + m_pszDbPopupHistoryFlag = "Yahoo_PopupHistoryFlag"; + + m_pszDbTendencyFormat = "Yahoo_TendencyFormat"; +} diff --git a/protocols/Quotes/QuotesProviderVisitorDbSettings.h b/protocols/Quotes/QuotesProviderVisitorDbSettings.h new file mode 100644 index 0000000000..728a436dfa --- /dev/null +++ b/protocols/Quotes/QuotesProviderVisitorDbSettings.h @@ -0,0 +1,49 @@ +#ifndef __97cd432a_1119_4803_a96f_0abc1cc2653f_QuotesProviderVisitorDbSettings_h__ +#define __97cd432a_1119_4803_a96f_0abc1cc2653f_QuotesProviderVisitorDbSettings_h__ + +#include "quotesprovidervisitor.h" + +class CQuotesProviderVisitorDbSettings : public CQuotesProviderVisitor +{ +public: + CQuotesProviderVisitorDbSettings(); + ~CQuotesProviderVisitorDbSettings(); + +private: + virtual void Visit(const CQuotesProviderBase& rProvider); + virtual void Visit(const CQuotesProviderDukasCopy& rProvider); + virtual void Visit(const CQuotesProviderGoogle& rProvider); + virtual void Visit(const CQuotesProviderGoogleFinance& rProvider); + virtual void Visit(const CQuotesProviderYahoo& rProvider); +public: + LPCSTR m_pszDbRefreshRateType; + LPCSTR m_pszDbRefreshRateValue; + LPCSTR m_pszDbDisplayNameFormat; + LPCTSTR m_pszDefDisplayFormat; + LPCTSTR m_pszDefLogFileFormat; + LPCTSTR m_pszDefHistoryFormat; + LPCTSTR m_pszXMLIniFileName; + LPCSTR m_pszDbStatusMsgFormat; + LPCTSTR m_pszDefStatusMsgFormat; + LPCTSTR m_pszDefPopupFormat; + LPCSTR m_pszDbTendencyFormat; + LPCTSTR m_pszDefTendencyFormat; + + //global settings + LPCSTR m_pszDbLogMode; + LPCSTR m_pszDbHistoryFormat; + LPCSTR m_pszDbHistoryCondition; + LPCSTR m_pszDbLogFile; + LPCSTR m_pszDbLogFormat; + LPCSTR m_pszDbLogCondition; + LPCSTR m_pszDbPopupFormat; + LPCSTR m_pszDbPopupCondition; + LPCSTR m_pszDbPopupColourMode; + LPCSTR m_pszDbPopupBkColour; + LPCSTR m_pszDbPopupTextColour; + LPCSTR m_pszDbPopupDelayMode; + LPCSTR m_pszDbPopupDelayTimeout; + LPCSTR m_pszDbPopupHistoryFlag; +}; + +#endif //__97cd432a_1119_4803_a96f_0abc1cc2653f_QuotesProviderVisitorDbSettings_h__ diff --git a/protocols/Quotes/QuotesProviderVisitorFormatSpecificator.cpp b/protocols/Quotes/QuotesProviderVisitorFormatSpecificator.cpp new file mode 100644 index 0000000000..9e643fe1b6 --- /dev/null +++ b/protocols/Quotes/QuotesProviderVisitorFormatSpecificator.cpp @@ -0,0 +1,63 @@ +#include "StdAfx.h" +#include "QuotesProviderVisitorFormatSpecificator.h" + +CQuotesProviderVisitorFormatSpecificator::CQuotesProviderVisitorFormatSpecificator() +{ +} + +CQuotesProviderVisitorFormatSpecificator::~CQuotesProviderVisitorFormatSpecificator() +{ +} + +void CQuotesProviderVisitorFormatSpecificator::Visit(const CQuotesProviderDukasCopy&/* rProvider*/) +{ + m_aSpecificators.push_back(CFormatSpecificator(_T("%s"),TranslateT("Quote Symbol"))); + m_aSpecificators.push_back(CFormatSpecificator(_T("%d"),TranslateT("Quote Name"))); +} + +void CQuotesProviderVisitorFormatSpecificator::Visit(const CQuotesProviderGoogle&/* rProvider*/) +{ + m_aSpecificators.push_back(CFormatSpecificator(_T("%F"),TranslateT("From Currency Full Name"))); + m_aSpecificators.push_back(CFormatSpecificator(_T("%f"),TranslateT("From Currency Short Name"))); + m_aSpecificators.push_back(CFormatSpecificator(_T("%I"),TranslateT("Into Currency Full Name"))); + m_aSpecificators.push_back(CFormatSpecificator(_T("%i"),TranslateT("Into Currency Short Name"))); + m_aSpecificators.push_back(CFormatSpecificator(_T("%s"),TranslateT("Short notation for \"%f/%i\""))); +} + +void CQuotesProviderVisitorFormatSpecificator::Visit(const CQuotesProviderBase&/* rProvider*/) +{ + m_aSpecificators.push_back(CFormatSpecificator(_T("%S"),TranslateT("Source of Information"))); + m_aSpecificators.push_back(CFormatSpecificator(_T("%r"),TranslateT("Rate Value"))); + m_aSpecificators.push_back(CFormatSpecificator(_T("%p"),TranslateT("Previous Rate Value"))); + m_aSpecificators.push_back(CFormatSpecificator(_T("%X"),TranslateT("Fetch Time"))); + m_aSpecificators.push_back(CFormatSpecificator(_T("%x"),TranslateT("Fetch Date"))); + m_aSpecificators.push_back(CFormatSpecificator(_T("%t"),TranslateT("Fetch Time and Date"))); + m_aSpecificators.push_back(CFormatSpecificator(_T("\\%"),TranslateT("Percentage Character (%)"))); + m_aSpecificators.push_back(CFormatSpecificator(_T("\\t"),TranslateT("Tabulation"))); + m_aSpecificators.push_back(CFormatSpecificator(_T("\\\\"),TranslateT("Left slash (\\)"))); +} + +void CQuotesProviderVisitorFormatSpecificator::Visit(const CQuotesProviderGoogleFinance&/* rProvider*/) +{ + m_aSpecificators.push_back(CFormatSpecificator(_T("%s"),TranslateT("Quote Symbol"))); + m_aSpecificators.push_back(CFormatSpecificator(_T("%n"),TranslateT("Quote Name"))); + m_aSpecificators.push_back(CFormatSpecificator(_T("%o"),TranslateT("Open Price"))); + m_aSpecificators.push_back(CFormatSpecificator(_T("%d"),TranslateT("Percent Change to After Hours"))); + m_aSpecificators.push_back(CFormatSpecificator(_T("%y"),TranslateT("Percent Change to Yesterday Close"))); +} + +const CQuotesProviderVisitorFormatSpecificator::TFormatSpecificators& CQuotesProviderVisitorFormatSpecificator::GetSpecificators()const +{ + return m_aSpecificators; +} + +void CQuotesProviderVisitorFormatSpecificator::Visit(const CQuotesProviderYahoo& rProvider) +{ + m_aSpecificators.push_back(CFormatSpecificator(_T("%s"),TranslateT("Quote Symbol"))); + m_aSpecificators.push_back(CFormatSpecificator(_T("%n"),TranslateT("Quote Name"))); + m_aSpecificators.push_back(CFormatSpecificator(_T("%o"),TranslateT("Open Price"))); + m_aSpecificators.push_back(CFormatSpecificator(_T("%h"),TranslateT("Day's High"))); + m_aSpecificators.push_back(CFormatSpecificator(_T("%g"),TranslateT("Day's Low"))); + m_aSpecificators.push_back(CFormatSpecificator(_T("%P"),TranslateT("Previous Close"))); + m_aSpecificators.push_back(CFormatSpecificator(_T("%c"),TranslateT("Change"))); +} diff --git a/protocols/Quotes/QuotesProviderVisitorFormatSpecificator.h b/protocols/Quotes/QuotesProviderVisitorFormatSpecificator.h new file mode 100644 index 0000000000..870ab00634 --- /dev/null +++ b/protocols/Quotes/QuotesProviderVisitorFormatSpecificator.h @@ -0,0 +1,36 @@ +#ifndef __00c159f3_525a_41e9_8fc5_00464b6fafa3_QuotesProviderVisitorFormatSpecificator_h__ +#define __00c159f3_525a_41e9_8fc5_00464b6fafa3_QuotesProviderVisitorFormatSpecificator_h__ + +#include "quotesprovidervisitor.h" + +class CQuotesProviderVisitorFormatSpecificator : public CQuotesProviderVisitor +{ +public: + struct CFormatSpecificator + { + CFormatSpecificator(const tstring& rsSymbol = _T(""),const tstring& rsDec = _T("")) + : m_sSymbol(rsSymbol),m_sDesc(rsDec){} + + tstring m_sSymbol; + tstring m_sDesc; + }; + typedef std::vector<CFormatSpecificator> TFormatSpecificators; + +public: + CQuotesProviderVisitorFormatSpecificator(); + ~CQuotesProviderVisitorFormatSpecificator(); + + const TFormatSpecificators& GetSpecificators()const; + +private: + virtual void Visit(const CQuotesProviderDukasCopy& rProvider); + virtual void Visit(const CQuotesProviderGoogle& rProvider); + virtual void Visit(const CQuotesProviderBase& rProvider); + virtual void Visit(const CQuotesProviderGoogleFinance& rProvider); + virtual void Visit(const CQuotesProviderYahoo& rProvider); + +private: + TFormatSpecificators m_aSpecificators; +}; + +#endif//__00c159f3_525a_41e9_8fc5_00464b6fafa3_QuotesProviderVisitorFormatSpecificator_h__ diff --git a/protocols/Quotes/QuotesProviderVisitorFormater.cpp b/protocols/Quotes/QuotesProviderVisitorFormater.cpp new file mode 100644 index 0000000000..4b1d73bb05 --- /dev/null +++ b/protocols/Quotes/QuotesProviderVisitorFormater.cpp @@ -0,0 +1,216 @@ +#include "StdAfx.h" +#include "QuotesProviderVisitorFormater.h" +#include "DBUtils.h" +#include "EconomicRateInfo.h" +#include "QuotesProviderGoogle.h" +#include "Locale.h" +#include "IsWithinAccuracy.h" +#include "QuotesProviderGoogleFinance.h" +#include "QuotesProviderYahoo.h" + +CQuotesProviderVisitorFormater::CQuotesProviderVisitorFormater(HANDLE hContact,TCHAR chr,int nWidth) + : m_hContact(hContact), + m_chr(chr), + m_nWidth(nWidth) +{ +} + +CQuotesProviderVisitorFormater::~CQuotesProviderVisitorFormater() +{ +} + +const tstring& CQuotesProviderVisitorFormater::GetResult()const +{ + return m_sResult; +} + +void CQuotesProviderVisitorFormater::Visit(const CQuotesProviderDukasCopy& rProvider) +{ + if(_T('d') == m_chr || _T('D') == m_chr) + { + m_sResult = Quotes_DBGetStringT(m_hContact,QUOTES_MODULE_NAME,DB_STR_QUOTE_DESCRIPTION); + } +} + +void CQuotesProviderVisitorFormater::Visit(const CQuotesProviderGoogle& rProvider) +{ + switch(m_chr) + { + case _T('F'): + m_sResult = Quotes_DBGetStringT(m_hContact,QUOTES_MODULE_NAME,DB_STR_FROM_DESCRIPTION); + break; + case _T('f'): + m_sResult = Quotes_DBGetStringT(m_hContact,QUOTES_MODULE_NAME,DB_STR_FROM_ID); + break; + case _T('I'): + m_sResult = Quotes_DBGetStringT(m_hContact,QUOTES_MODULE_NAME,DB_STR_TO_DESCRIPTION); + break; + case _T('i'): + m_sResult = Quotes_DBGetStringT(m_hContact,QUOTES_MODULE_NAME,DB_STR_TO_ID); + break; + } +} + +namespace +{ + bool get_fetch_time(HANDLE hContact,time_t& rTime) + { + DBVARIANT dbv; + DBCONTACTGETSETTING cgs; + + cgs.szModule=QUOTES_MODULE_NAME; + cgs.szSetting=DB_STR_QUOTE_FETCH_TIME; + cgs.pValue=&dbv; + if(CallService(MS_DB_CONTACT_GETSETTING,reinterpret_cast<WPARAM>(hContact),reinterpret_cast<LPARAM>(&cgs)) + || (DBVT_DWORD != dbv.type)) + { + return false; + } + + rTime = dbv.dVal; + return true; + } + + tstring format_fetch_time(const CQuotesProviderBase& rProvider,HANDLE hContact,const tstring& rsFormat) + { + time_t nTime; + if(true == get_fetch_time(hContact,nTime)) + { + boost::posix_time::ptime time = boost::date_time::c_local_adjustor<boost::posix_time::ptime>::utc_to_local(boost::posix_time::from_time_t(nTime)); + tostringstream k; + k.imbue(std::locale(GetSystemLocale(),new ttime_facet(rsFormat.c_str()))); + k << time; + return k.str(); + } + + return tstring(); + } +} + +void CQuotesProviderVisitorFormater::Visit(const CQuotesProviderBase& rProvider) +{ + switch(m_chr) + { +// default: +// m_sResult = m_chr; +// break; + case _T('%'): + case _T('\t'): + case _T('\\'): + m_sResult = m_chr; + break; + case _T('S'): + m_sResult = Quotes_DBGetStringT(m_hContact,QUOTES_MODULE_NAME,DB_STR_QUOTE_PROVIDER); + break; + case _T('s'): + m_sResult = Quotes_DBGetStringT(m_hContact,QUOTES_MODULE_NAME,DB_STR_QUOTE_SYMBOL); + break; + case _T('X'): + //m_sResult = format_fetch_time(rProvider,m_hContact,_T("%H:%M:%S")); + m_sResult = format_fetch_time(rProvider,m_hContact,Quotes_GetTimeFormat(true)); + break; + case _T('x'): + //m_sResult = format_fetch_time(rProvider,m_hContact,_T("%d.%m.%y")); + m_sResult = format_fetch_time(rProvider,m_hContact,Quotes_GetDateFormat(true)); + break; + case _T('t'): + { + tstring sFrmt = Quotes_GetDateFormat(true); + sFrmt += _T(" "); + sFrmt += Quotes_GetTimeFormat(true); + m_sResult = format_fetch_time(rProvider,m_hContact,sFrmt); + + //m_sResult = format_fetch_time(rProvider,m_hContact,_T("%d.%m.%y %H:%M:%S")); + } + break; + case _T('r'): + case _T('R'): + FormatDoubleHelper(DB_STR_QUOTE_CURR_VALUE); + break; + case _T('p'): + FormatDoubleHelper(DB_STR_QUOTE_PREV_VALUE); + break; +// case _T('c'): +// FormatChangeValueHelper(false); +// break; +// case _T('C'): +// FormatChangeValueHelper(true); +// break; + } +} + +void CQuotesProviderVisitorFormater::Visit(const CQuotesProviderGoogleFinance&/* rProvider*/) +{ + switch(m_chr) + { + case _T('o'): + FormatDoubleHelper(DB_STR_GOOGLE_FINANCE_OPEN_VALUE); + break; + case _T('d'): + FormatDoubleHelper(DB_STR_GOOGLE_FINANCE_DIFF,_T("0")); + break; + case _T('y'): + FormatDoubleHelper(DB_STR_GOOGLE_FINANCE_PERCENT_CHANGE_TO_YERSTERDAY_CLOSE,_T("0")); + break; + case _T('n'): + m_sResult = Quotes_DBGetStringT(m_hContact,QUOTES_MODULE_NAME,DB_STR_QUOTE_DESCRIPTION); + break; + } +} + +namespace +{ + tstring format_double(double dValue,int nWidth) + { + tostringstream o; + o.imbue(GetSystemLocale()); + + if(nWidth > 0 && nWidth <= 9) + { + o << std::setprecision(nWidth) << std::showpoint << std::fixed; + } + o << dValue; + + return o.str(); + } +} + +void CQuotesProviderVisitorFormater::FormatDoubleHelper(LPCSTR pszDbSet, + const tstring sInvalid/* = _T("-")*/) +{ + double d = 0.0; + if(true == Quotes_DBReadDouble(m_hContact,QUOTES_MODULE_NAME,pszDbSet,d)) + { + m_sResult = format_double(d,m_nWidth); + } + else + { + m_sResult = sInvalid; + } +} + +void CQuotesProviderVisitorFormater::Visit(const CQuotesProviderYahoo& rProvider) +{ + switch(m_chr) + { + case _T('o'): + FormatDoubleHelper(DB_STR_YAHOO_OPEN_VALUE); + break; + case _T('h'): + FormatDoubleHelper(DB_STR_YAHOO_DAY_HIGH); + break; + case _T('P'): + FormatDoubleHelper(DB_STR_YAHOO_PREVIOUS_CLOSE); + break; + case _T('c'): + FormatDoubleHelper(DB_STR_YAHOO_CHANGE); + break; + case _T('g'): + FormatDoubleHelper(DB_STR_YAHOO_DAY_LOW); + break; + case _T('n'): + m_sResult = Quotes_DBGetStringT(m_hContact,QUOTES_MODULE_NAME,DB_STR_QUOTE_DESCRIPTION); + break; + } + +} diff --git a/protocols/Quotes/QuotesProviderVisitorFormater.h b/protocols/Quotes/QuotesProviderVisitorFormater.h new file mode 100644 index 0000000000..7c9c222269 --- /dev/null +++ b/protocols/Quotes/QuotesProviderVisitorFormater.h @@ -0,0 +1,32 @@ +#ifndef __2b5ddd05_9255_4be0_9408_e59768b70568_QuotesProviderVisitorFormater_h__ +#define __2b5ddd05_9255_4be0_9408_e59768b70568_QuotesProviderVisitorFormater_h__ + +#include "quotesprovidervisitor.h" + +class CQuotesProviderVisitorFormater : public CQuotesProviderVisitor +{ +public: + CQuotesProviderVisitorFormater(HANDLE hContact,TCHAR chr,int nWidth); + ~CQuotesProviderVisitorFormater(); + + const tstring& GetResult()const; + +private: + virtual void Visit(const CQuotesProviderDukasCopy& rProvider); + virtual void Visit(const CQuotesProviderGoogle& rProvider); + virtual void Visit(const CQuotesProviderBase& rProvider); + virtual void Visit(const CQuotesProviderGoogleFinance& rProvider); + virtual void Visit(const CQuotesProviderYahoo& rProvider); + +private: + void FormatDoubleHelper(LPCSTR pszDbSet,const tstring sInvalid = _T("-")); +// void FormatChangeValueHelper(bool bPercentage); + +private: + HANDLE m_hContact; + TCHAR m_chr; + tstring m_sResult; + int m_nWidth; +}; + +#endif //__2b5ddd05_9255_4be0_9408_e59768b70568_QuotesProviderVisitorFormater_h__ diff --git a/protocols/Quotes/QuotesProviderVisitorTendency.cpp b/protocols/Quotes/QuotesProviderVisitorTendency.cpp new file mode 100644 index 0000000000..00703521b3 --- /dev/null +++ b/protocols/Quotes/QuotesProviderVisitorTendency.cpp @@ -0,0 +1,70 @@ +#include "stdafx.h" +#include "QuotesProviderVisitorTendency.h" +#include "DBUtils.h" +#include "QuotesProviderGoogleFinance.h" +#include "EconomicRateInfo.h" +#include "QuotesProviderYahoo.h" + +CQuotesProviderVisitorTendency::CQuotesProviderVisitorTendency(HANDLE hContact,TCHAR chr) + : m_hContact(hContact),m_chr(chr),m_bValid(false),m_dResult(0.0) +{ +} + +void CQuotesProviderVisitorTendency::Visit(const CQuotesProviderBase& rProvider) +{ + switch(m_chr) + { + case _T('r'): + case _T('R'): + GetValue(DB_STR_QUOTE_CURR_VALUE); + break; + case _T('p'): + GetValue(DB_STR_QUOTE_PREV_VALUE); + break; + } +} + +void CQuotesProviderVisitorTendency::Visit(const CQuotesProviderGoogleFinance& rProvider) +{ + switch(m_chr) + { + case _T('o'): + GetValue(DB_STR_GOOGLE_FINANCE_OPEN_VALUE); + break; + case _T('d'): + GetValue(DB_STR_GOOGLE_FINANCE_DIFF); + break; + case _T('y'): + GetValue(DB_STR_GOOGLE_FINANCE_PERCENT_CHANGE_TO_YERSTERDAY_CLOSE); + break; + } +} + +void CQuotesProviderVisitorTendency::Visit(const CQuotesProviderYahoo& rProvider) +{ + switch(m_chr) + { + case _T('o'): + GetValue(DB_STR_YAHOO_OPEN_VALUE); + break; + case _T('h'): + GetValue(DB_STR_YAHOO_DAY_HIGH); + break; + case _T('P'): + GetValue(DB_STR_YAHOO_PREVIOUS_CLOSE); + break; + case _T('c'): + GetValue(DB_STR_YAHOO_CHANGE); + break; + case _T('g'): + GetValue(DB_STR_YAHOO_DAY_LOW); + break; + } + +} + + +void CQuotesProviderVisitorTendency::GetValue(LPCSTR pszDbKeyName) +{ + m_bValid = Quotes_DBReadDouble(m_hContact,QUOTES_MODULE_NAME,pszDbKeyName,m_dResult); +} diff --git a/protocols/Quotes/QuotesProviderVisitorTendency.h b/protocols/Quotes/QuotesProviderVisitorTendency.h new file mode 100644 index 0000000000..fa0f04c5f0 --- /dev/null +++ b/protocols/Quotes/QuotesProviderVisitorTendency.h @@ -0,0 +1,29 @@ +#ifndef __AD721194_E9944366_9CF1_0307460EF32F_QuotesProviderVisitorTendency_h__ +#define __AD721194_E9944366_9CF1_0307460EF32F_QuotesProviderVisitorTendency_h__ + +#include "quotesprovidervisitor.h" + +class CQuotesProviderVisitorTendency : public CQuotesProviderVisitor +{ +public: + CQuotesProviderVisitorTendency(HANDLE hContact,TCHAR chr); + + bool IsValid()const{return m_bValid;} + double GetResult()const{return m_dResult;} + +private: + virtual void Visit(const CQuotesProviderBase& rProvider); + virtual void Visit(const CQuotesProviderGoogleFinance& rProvider); + virtual void Visit(const CQuotesProviderYahoo& rProvider); + +private: + void GetValue(LPCSTR pszDbKeyName); + +private: + HANDLE m_hContact; + TCHAR m_chr; + bool m_bValid; + double m_dResult; +}; + +#endif //__AD721194_E9944366_9CF1_0307460EF32F_QuotesProviderVisitorTendency_h__ diff --git a/protocols/Quotes/QuotesProviderYahoo.cpp b/protocols/Quotes/QuotesProviderYahoo.cpp new file mode 100644 index 0000000000..35edb3207c --- /dev/null +++ b/protocols/Quotes/QuotesProviderYahoo.cpp @@ -0,0 +1,193 @@ +#include "stdafx.h" +#include "QuotesProviderYahoo.h" +#include "QuotesProviderVisitor.h" +#include "ModuleInfo.h" +#include "DBUtils.h" +#include "EconomicRateInfo.h" +#include "HTTPSession.h" + +namespace +{ + void remove_quotes(tstring& s) + { + if (*s.begin() == _T('"')) + { + s.erase(s.begin()); + } + if (*s.rbegin() == _T('"')) + { + tstring::iterator i(s.begin()); + std::advance(i,s.size()-1); + s.erase(i); + } + } + + void remove_end_of_line(tstring& s) + { + if (*s.rbegin() == _T('\n')) + { + tstring::iterator i(s.begin()); + std::advance(i,s.size()-1); + s.erase(i); + } + if (*s.rbegin() == _T('\r')) + { + tstring::iterator i(s.begin()); + std::advance(i,s.size()-1); + s.erase(i); + } + } + + bool t2d(const tstring& s,double& d) + { + tistringstream stream(s); + stream >> d; + return ((false == stream.fail()) && (false == stream.bad())); +// try +// { +// d = boost::lexical_cast<double>(s); +// return true; +// } +// catch(boost::bad_lexical_cast& e) +// { +// } +// return false; + } + + typedef std::vector<tstring> TStrings; + + bool get_double_from_parsed_line(HANDLE hContact,const TStrings& rasParsedLine,size_t nIndex,const char* pszDbName) + { + if(rasParsedLine.size() > nIndex) + { + double d = 0.0; + if(true == t2d(rasParsedLine[nIndex],d)) + { + return Quotes_DBWriteDouble(hContact,QUOTES_MODULE_NAME,pszDbName,d); + } + } + + DBWriteContactSettingTString(hContact,QUOTES_MODULE_NAME,pszDbName,_T("")); + return false; + } +} + +void CQuotesProviderYahoo::RefreshQuotes(TContracts& anContacts) +{ + tstring sURL = GetURL(); + bool bUseExtendedStatus = CModuleInfo::GetInstance().GetExtendedStatusFlag(); + + typedef std::map<tstring,HANDLE> TQuoteID2ContractHandles; + TQuoteID2ContractHandles aQuoteID2Handles; + tostringstream oURL; + oURL << sURL << _T("dioksin.txt?s="); + for(TContracts::const_iterator i = anContacts.begin();i != anContacts.end() && IsOnline();++i) + { + HANDLE hContact = *i; + if(bUseExtendedStatus) + { + SetContactStatus(hContact,ID_STATUS_OCCUPIED); + } + + tstring sQuoteID = Quotes_DBGetStringT(hContact,QUOTES_MODULE_NAME,DB_STR_QUOTE_ID); + aQuoteID2Handles[sQuoteID] = hContact; + if(i != anContacts.begin()) + { + oURL << _T("+"); + } + oURL << sQuoteID; + } + + if(true == IsOnline()) + { + oURL << _T("&f=snl1ohgpc1"); + CHTTPSession http; + if ((true == http.OpenURL(oURL.str())) && (true == IsOnline())) + { + tstring sFile; + if ((true == http.ReadResponce(sFile)) && (true == IsOnline())) + { + tistringstream out_str(sFile.c_str()); + while(false == out_str.eof()) + { + tstring sLine; + std::getline(out_str,sLine); + if(false == sLine.empty()) + { + remove_end_of_line(sLine); + + TStrings asStrings; + for(tstring::size_type nPos = sLine.find(_T(','));nPos != tstring::npos; nPos = sLine.find(_T(','))) + { + tstring::iterator i(sLine.begin()); + std::advance(i,nPos); + tstring s(sLine.begin(),i); + remove_quotes(s); + asStrings.push_back(s); + + if(i != sLine.end()) + { + std::advance(i,1); + } + sLine.erase(sLine.begin(),i); + } + + if(false == sLine.empty()) + { + remove_quotes(sLine); + + if(false == sLine.empty()) + asStrings.push_back(sLine); + } + + size_t cItems = asStrings.size(); + if(cItems >= 3) + { + enum + { + indexSymbol = 0, + indexName, + indexLastTrade, + indexOpen, + indexDayHigh, + indexDayLow, + indexPreviousClose, + indexChange + }; + auto it3 = aQuoteID2Handles.find(asStrings[indexSymbol]); + if(it3 != aQuoteID2Handles.end()) + { + HANDLE hContact = it3->second; + double dRate = 0.0; + if(true == t2d(asStrings[indexLastTrade],dRate)) + { + DBWriteContactSettingTString(hContact,QUOTES_MODULE_NAME,DB_STR_QUOTE_DESCRIPTION,asStrings[indexName].c_str()); + + get_double_from_parsed_line(hContact,asStrings,indexOpen,DB_STR_YAHOO_OPEN_VALUE); + get_double_from_parsed_line(hContact,asStrings,indexDayHigh,DB_STR_YAHOO_DAY_HIGH); + get_double_from_parsed_line(hContact,asStrings,indexDayLow,DB_STR_YAHOO_DAY_LOW); + get_double_from_parsed_line(hContact,asStrings,indexPreviousClose,DB_STR_YAHOO_PREVIOUS_CLOSE); + get_double_from_parsed_line(hContact,asStrings,indexChange,DB_STR_YAHOO_CHANGE); + WriteContactRate(hContact,dRate); + aQuoteID2Handles.erase(it3); + } + } + } + } + } + } + } + + if(true == IsOnline()) + { + std::for_each(aQuoteID2Handles.begin(),aQuoteID2Handles.end(), + [](const TQuoteID2ContractHandles::value_type& pair){SetContactStatus(pair.second,ID_STATUS_NA);}); + } + } +} + +void CQuotesProviderYahoo::Accept(CQuotesProviderVisitor& visitor)const +{ + CQuotesProviderFinance::Accept(visitor); + visitor.Visit(*this); +} diff --git a/protocols/Quotes/QuotesProviderYahoo.h b/protocols/Quotes/QuotesProviderYahoo.h new file mode 100644 index 0000000000..feadefbca4 --- /dev/null +++ b/protocols/Quotes/QuotesProviderYahoo.h @@ -0,0 +1,20 @@ +#ifndef __E927F394_5452_458E_AF48_71E44F9EE793_QuotesProviderYahoo_h__ +#define __E927F394_5452_458E_AF48_71E44F9EE793_QuotesProviderYahoo_h__ + +#include "QuotesProviderFinance.h" + + +#define DB_STR_YAHOO_OPEN_VALUE "OpenQuotePrice" +#define DB_STR_YAHOO_DAY_HIGH "DayHigh" +#define DB_STR_YAHOO_DAY_LOW "DayLow" +#define DB_STR_YAHOO_PREVIOUS_CLOSE "PreviousClose" +#define DB_STR_YAHOO_CHANGE "Change" + +class CQuotesProviderYahoo : public CQuotesProviderFinance +{ +private: + virtual void RefreshQuotes(TContracts& anContacts); + virtual void Accept(CQuotesProviderVisitor& visitor)const; +}; + +#endif //__E927F394_5452_458E_AF48_71E44F9EE793_QuotesProviderYahoo_h__ diff --git a/protocols/Quotes/QuotesProviders.cpp b/protocols/Quotes/QuotesProviders.cpp new file mode 100644 index 0000000000..5fac2af14f --- /dev/null +++ b/protocols/Quotes/QuotesProviders.cpp @@ -0,0 +1,120 @@ +#include "StdAfx.h" +#include "QuotesProviders.h" + +#include "QuotesProviderDukasCopy.h" +#include "EconomicRateInfo.h" +#include "QuotesProviderGoogle.h" +#include "DBUtils.h" +#include "QuotesProviderGoogleFinance.h" +#include "QuotesProviderYahoo.h" + +#define LAST_RUN_VERSION "LastRunVersion" + +CQuotesProviders::CQuotesProviders() +{ + InitProviders(); +} + +CQuotesProviders::~CQuotesProviders() +{ + ClearProviders(); +} + +const CQuotesProviders::TQuotesProviders& CQuotesProviders::GetProviders()const +{ + return m_apProviders; +} + +namespace +{ + template<class T>void create_provider(CQuotesProviders::TQuotesProviders& apProviders) + { + CQuotesProviders::TQuotesProviderPtr pProvider(new T); + if(pProvider->Init()) + { + apProviders.push_back(pProvider); + } + } +} + +void CQuotesProviders::CreateProviders() +{ + create_provider<CQuotesProviderDukasCopy>(m_apProviders); + create_provider<CQuotesProviderGoogle>(m_apProviders); + create_provider<CQuotesProviderGoogleFinance>(m_apProviders); + create_provider<CQuotesProviderYahoo>(m_apProviders); +} + +void CQuotesProviders::ClearProviders() +{ + m_apProviders.clear(); +} + +namespace +{ + void convert_contact_settings(HANDLE hContact) + { + WORD dwLogMode = DBGetContactSettingWord(hContact,QUOTES_PROTOCOL_NAME,DB_STR_QUOTE_LOG,static_cast<WORD>(lmDisabled)); + if ((dwLogMode&lmInternalHistory) || (dwLogMode&lmExternalFile)) + { + DBWriteContactSettingByte(hContact,QUOTES_PROTOCOL_NAME,DB_STR_CONTACT_SPEC_SETTINGS,1); + } + } +} +void CQuotesProviders::InitProviders() +{ + CreateProviders(); + + const WORD nCurrentVersion = 17; + WORD nVersion = DBGetContactSettingWord(NULL,QUOTES_MODULE_NAME,LAST_RUN_VERSION,1); + + for(HANDLE hContact = reinterpret_cast<HANDLE>(CallService(MS_DB_CONTACT_FINDFIRST,0,0));hContact;hContact = reinterpret_cast<HANDLE>(CallService(MS_DB_CONTACT_FINDNEXT,reinterpret_cast<WPARAM>(hContact),0))) + { + TQuotesProviderPtr pProvider = GetContactProviderPtr(hContact); + if(pProvider) + { + pProvider->AddContact(hContact); + if(nVersion < nCurrentVersion) + { + convert_contact_settings(hContact); + } + } + } + + DBWriteContactSettingWord(NULL,QUOTES_MODULE_NAME,LAST_RUN_VERSION,nCurrentVersion); +} + +CQuotesProviders::TQuotesProviderPtr CQuotesProviders::GetContactProviderPtr(HANDLE hContact)const +{ + char* szProto = reinterpret_cast<char*>(CallService(MS_PROTO_GETCONTACTBASEPROTO, + reinterpret_cast<WPARAM>(hContact),0)); + if(NULL == szProto || 0 != ::_stricmp(szProto,QUOTES_PROTOCOL_NAME)) + { + return TQuotesProviderPtr(); + } + + tstring sProvider = Quotes_DBGetStringT(hContact,QUOTES_MODULE_NAME,DB_STR_QUOTE_PROVIDER); + if(true == sProvider.empty()) + { + return TQuotesProviderPtr(); + } + + return FindProvider(sProvider); +} + +CQuotesProviders::TQuotesProviderPtr CQuotesProviders::FindProvider(const tstring& rsName)const +{ + TQuotesProviderPtr pResult; + for(TQuotesProviders::const_iterator i = m_apProviders.begin();i != m_apProviders.end();++i) + { + const TQuotesProviderPtr& pProvider = *i; + const IQuotesProvider::CProviderInfo& rInfo = pProvider->GetInfo(); + if(0 == ::quotes_stricmp(rsName.c_str(),rInfo.m_sName.c_str())) + { + pResult = pProvider; + break; + } + } + + return pResult; +} diff --git a/protocols/Quotes/QuotesProviders.h b/protocols/Quotes/QuotesProviders.h new file mode 100644 index 0000000000..02aa5184c9 --- /dev/null +++ b/protocols/Quotes/QuotesProviders.h @@ -0,0 +1,32 @@ +#ifndef __148306d1_da2a_43df_b1ad_0cdc8ef8a79e_QuotesProviders_h__ +#define __148306d1_da2a_43df_b1ad_0cdc8ef8a79e_QuotesProviders_h__ + +#include <boost\shared_ptr.hpp> +#include <vector> + +class IQuotesProvider; + +class CQuotesProviders +{ +public: + typedef boost::shared_ptr<IQuotesProvider> TQuotesProviderPtr; + typedef std::vector<TQuotesProviderPtr> TQuotesProviders; + +public: + CQuotesProviders(); + ~CQuotesProviders(); + + TQuotesProviderPtr FindProvider(const tstring& rsName)const; + TQuotesProviderPtr GetContactProviderPtr(HANDLE hContact)const; + const TQuotesProviders& GetProviders()const; + +private: + void InitProviders(); + void CreateProviders(); + void ClearProviders(); + +private: + TQuotesProviders m_apProviders; +}; + +#endif //__148306d1_da2a_43df_b1ad_0cdc8ef8a79e_QuotesProviders_h__ diff --git a/protocols/Quotes/SettingsDlg.cpp b/protocols/Quotes/SettingsDlg.cpp new file mode 100644 index 0000000000..e5795b51d1 --- /dev/null +++ b/protocols/Quotes/SettingsDlg.cpp @@ -0,0 +1,1148 @@ +#include "StdAfx.h" +#include "SettingsDlg.h" +#include "EconomicRateInfo.h" +#include "ModuleInfo.h" +#include "WinCtrlHelper.h" +#include "CreateFilePath.h" +#include "QuotesProviderVisitorDbSettings.h" +#include "DBUtils.h" +#include "resource.h" +#include "QuotesProviders.h" +#include "IQuotesProvider.h" + +#define WINDOW_PREFIX_SETTINGS "Edit Settings_" + +namespace +{ + LPCTSTR g_pszVariableQuoteName = _T("%quotename%"); + LPCTSTR g_pszVariableUserProfile = _T("%miranda_userdata%"); + + void update_file_controls(HWND hDlg) + { + bool bEnable = (1 == ::IsDlgButtonChecked(hDlg,IDC_CHECK_EXTERNAL_FILE)); + + ::EnableWindow(::GetDlgItem(hDlg,IDC_EDIT_FILE_NAME),bEnable); + ::EnableWindow(::GetDlgItem(hDlg,IDC_STATIC_SELECT_FILE),bEnable); + ::EnableWindow(::GetDlgItem(hDlg,IDC_BUTTON_BROWSE),bEnable); + ::EnableWindow(::GetDlgItem(hDlg,IDC_STATIC_LOG_FILE_FORMAT),bEnable); + ::EnableWindow(::GetDlgItem(hDlg,IDC_EDIT_LOG_FILE_FORMAT),bEnable); + ::EnableWindow(::GetDlgItem(hDlg,IDC_BUTTON_LOG_FILE_DESCRIPTION),bEnable); + ::EnableWindow(::GetDlgItem(hDlg,IDC_CHECK_LOG_FILE_CONDITION),bEnable); + } + + void update_history_controls(HWND hDlg) + { + bool bEnable = (1 == ::IsDlgButtonChecked(hDlg,IDC_CHECK_INTERNAL_HISTORY)); + + ::EnableWindow(::GetDlgItem(hDlg,IDC_STATIC_HISTORY_FORMAT),bEnable); + ::EnableWindow(::GetDlgItem(hDlg,IDC_EDIT_HISTORY_FORMAT),bEnable); + ::EnableWindow(::GetDlgItem(hDlg,IDC_BUTTON_HISTORY_DESCRIPTION),bEnable); + ::EnableWindow(::GetDlgItem(hDlg,IDC_CHECK_HISTORY_CONDITION),bEnable); + } + + void update_popup_controls(HWND hDlg) + { + bool bEnable = (1 == ::IsDlgButtonChecked(hDlg,IDC_CHECK_SHOW_POPUP)); + ::EnableWindow(::GetDlgItem(hDlg,IDC_EDIT_POPUP_FORMAT),bEnable); + ::EnableWindow(::GetDlgItem(hDlg,IDC_CHECK_SHOW_POPUP_ONLY_VALUE_CHANGED),bEnable); + ::EnableWindow(::GetDlgItem(hDlg,IDC_STATIC_POPUP_FORMAT),bEnable); + ::EnableWindow(::GetDlgItem(hDlg,IDC_BUTTON_POPUP_FORMAT_DESCRIPTION),bEnable); + ::EnableWindow(::GetDlgItem(hDlg,IDC_BUTTON_POPUP_SETTINGS),bEnable); + } + + bool enable_popup_controls(HWND hDlg) + { + bool bIsPopupServiceEnabled = 1 == ServiceExists(MS_POPUP_ADDPOPUPT); + ::EnableWindow(::GetDlgItem(hDlg,IDC_CHECK_SHOW_POPUP),bIsPopupServiceEnabled); + ::EnableWindow(::GetDlgItem(hDlg,IDC_EDIT_POPUP_FORMAT),bIsPopupServiceEnabled); + ::EnableWindow(::GetDlgItem(hDlg,IDC_CHECK_SHOW_POPUP_ONLY_VALUE_CHANGED),bIsPopupServiceEnabled); + ::EnableWindow(::GetDlgItem(hDlg,IDC_STATIC_POPUP_FORMAT),bIsPopupServiceEnabled); + ::EnableWindow(::GetDlgItem(hDlg,IDC_BUTTON_POPUP_FORMAT_DESCRIPTION),bIsPopupServiceEnabled); + ::EnableWindow(::GetDlgItem(hDlg,IDC_BUTTON_POPUP_SETTINGS),bIsPopupServiceEnabled); + + return bIsPopupServiceEnabled; + } + + void update_all_controls(HWND hDlg) + { + bool bIsCheckedContactSpec = (1 == ::IsDlgButtonChecked(hDlg,IDC_CHECK_CONTACT_SPECIFIC)); + bool bIsCheckedExternal = (1 == ::IsDlgButtonChecked(hDlg,IDC_CHECK_EXTERNAL_FILE)); + + ::EnableWindow(::GetDlgItem(hDlg,IDC_CHECK_EXTERNAL_FILE),bIsCheckedContactSpec); + ::EnableWindow(::GetDlgItem(hDlg,IDC_EDIT_FILE_NAME),(bIsCheckedContactSpec&&bIsCheckedExternal)); + ::EnableWindow(::GetDlgItem(hDlg,IDC_STATIC_SELECT_FILE),(bIsCheckedContactSpec&&bIsCheckedExternal)); + ::EnableWindow(::GetDlgItem(hDlg,IDC_BUTTON_BROWSE),(bIsCheckedContactSpec&&bIsCheckedExternal)); + ::EnableWindow(::GetDlgItem(hDlg,IDC_STATIC_LOG_FILE_FORMAT),(bIsCheckedContactSpec&&bIsCheckedExternal)); + ::EnableWindow(::GetDlgItem(hDlg,IDC_EDIT_LOG_FILE_FORMAT),(bIsCheckedContactSpec&&bIsCheckedExternal)); + ::EnableWindow(::GetDlgItem(hDlg,IDC_BUTTON_LOG_FILE_DESCRIPTION),(bIsCheckedContactSpec&&bIsCheckedExternal)); + ::EnableWindow(::GetDlgItem(hDlg,IDC_CHECK_LOG_FILE_CONDITION),(bIsCheckedContactSpec&&bIsCheckedExternal)); + + bool bIsCheckedHistory = (1 == ::IsDlgButtonChecked(hDlg,IDC_CHECK_INTERNAL_HISTORY)); + ::EnableWindow(::GetDlgItem(hDlg,IDC_CHECK_INTERNAL_HISTORY),bIsCheckedContactSpec); + ::EnableWindow(::GetDlgItem(hDlg,IDC_STATIC_HISTORY_FORMAT),(bIsCheckedContactSpec&&bIsCheckedHistory)); + ::EnableWindow(::GetDlgItem(hDlg,IDC_EDIT_HISTORY_FORMAT),(bIsCheckedContactSpec&&bIsCheckedHistory)); + ::EnableWindow(::GetDlgItem(hDlg,IDC_BUTTON_HISTORY_DESCRIPTION),(bIsCheckedContactSpec&&bIsCheckedHistory)); + ::EnableWindow(::GetDlgItem(hDlg,IDC_CHECK_HISTORY_CONDITION),(bIsCheckedContactSpec&&bIsCheckedHistory)); + + bool bIsPopupServiceEnabled = 1 == ServiceExists(MS_POPUP_ADDPOPUPT); + bool bIsCheckedShowPopup = (1 == ::IsDlgButtonChecked(hDlg,IDC_CHECK_SHOW_POPUP)); + ::EnableWindow(::GetDlgItem(hDlg,IDC_CHECK_SHOW_POPUP),(bIsCheckedContactSpec&&bIsPopupServiceEnabled)); + ::EnableWindow(::GetDlgItem(hDlg,IDC_EDIT_POPUP_FORMAT),(bIsCheckedContactSpec&&bIsPopupServiceEnabled&&bIsCheckedShowPopup)); + ::EnableWindow(::GetDlgItem(hDlg,IDC_CHECK_SHOW_POPUP_ONLY_VALUE_CHANGED),(bIsCheckedContactSpec&&bIsPopupServiceEnabled&&bIsCheckedShowPopup)); + ::EnableWindow(::GetDlgItem(hDlg,IDC_STATIC_POPUP_FORMAT),(bIsCheckedContactSpec&&bIsPopupServiceEnabled&&bIsCheckedShowPopup)); + ::EnableWindow(::GetDlgItem(hDlg,IDC_BUTTON_POPUP_FORMAT_DESCRIPTION),(bIsCheckedContactSpec&&bIsPopupServiceEnabled&&bIsCheckedShowPopup)); + ::EnableWindow(::GetDlgItem(hDlg,IDC_BUTTON_POPUP_SETTINGS),(bIsCheckedContactSpec&&bIsPopupServiceEnabled)); + } + + std::vector<TCHAR> get_filter() + { + std::vector<TCHAR> aFilter; + LPCTSTR pszFilterParts[] = {_T("Log Files (*.txt,*.log)"),_T("*.txt;*.log"),_T("All files (*.*)"),_T("*.*")}; + for(int i = 0;i < sizeof(pszFilterParts)/sizeof(pszFilterParts[0]);++i) + { + tstring sPart = TranslateTS(pszFilterParts[i]); + std::copy(sPart.begin(),sPart.end(),std::back_inserter(aFilter)); + aFilter.push_back(_T('\0')); + + } + aFilter.push_back(_T('\0')); + return aFilter; + } + void select_log_file(HWND hDlg) + { +// tstring sFileName = GenerateLogFileName( +// get_window_text(::GetDlgItem(hDlg,IDC_EDIT_FILE_NAME)),tstring(),glfnResolveUserProfile); + std::vector<TCHAR> aFileBuffer(_MAX_PATH*2,_T('\0')); +// std::copy(sFileName.begin(),sFileName.end(),aFileBuffer.begin()); + LPTSTR pszFile = &*aFileBuffer.begin(); + + std::vector<TCHAR> aFilterBuffer = get_filter(); + LPCTSTR pszFilter = &*aFilterBuffer.begin(); + + OPENFILENAME ofn = {0}; + ofn.lStructSize = sizeof(OPENFILENAME); + ofn.hwndOwner = hDlg; + ofn.lpstrFile = pszFile; + ofn.nMaxFile = (DWORD)aFileBuffer.size(); + ofn.lpstrFilter = pszFilter; + ofn.nFilterIndex = 1; + ofn.hInstance = CModuleInfo::GetModuleHandle(); + ofn.lpstrDefExt = _T("log"); +// ofn.lpstrFileTitle = NULL; +// ofn.nMaxFileTitle = 0; +// ofn.lpstrInitialDir = NULL; + ofn.Flags = OFN_PATHMUSTEXIST|OFN_HIDEREADONLY|OFN_EXPLORER; + + BOOL b = GetOpenFileName(&ofn); + if(TRUE == b) + { + SetDlgItemText(hDlg,IDC_EDIT_FILE_NAME,ofn.lpstrFile); + } + } + + struct CSettingWindowParam + { + CSettingWindowParam(HANDLE hContact) : m_hContact(hContact),m_pPopupSettings(NULL){} + ~CSettingWindowParam(){delete m_pPopupSettings;} + + HANDLE m_hContact; + CPopupSettings* m_pPopupSettings; + }; + + inline CSettingWindowParam* get_param(HWND hWnd) + { + return reinterpret_cast<CSettingWindowParam*>(GetWindowLongPtr(hWnd,GWLP_USERDATA)); + } + + +// inline HANDLE get_contact(HWND hWnd) +// { +// return reinterpret_cast<HANDLE>(GetWindowLong(hWnd,GWLP_USERDATA)); +// } + + void update_popup_controls_settings(HWND hDlg) + { + bool bIsColoursEnabled = 1 == IsDlgButtonChecked(hDlg,IDC_RADIO_USER_DEFINED_COLOURS); + ::EnableWindow(::GetDlgItem(hDlg,IDC_BGCOLOR),bIsColoursEnabled); + ::EnableWindow(::GetDlgItem(hDlg,IDC_TEXTCOLOR),bIsColoursEnabled); + + bool bIsDelayEnabled = 1 == IsDlgButtonChecked(hDlg,IDC_DELAYCUSTOM); + ::EnableWindow(::GetDlgItem(hDlg,IDC_DELAY),bIsDelayEnabled); + + } + + INT_PTR CALLBACK EditPopupSettingsDlgProc(HWND hWnd,UINT msg,WPARAM wp,LPARAM lp) + { + switch(msg) + { + case WM_INITDIALOG: + { + CPopupSettings* pSettings = reinterpret_cast<CPopupSettings*>(lp); + TranslateDialogDefault( hWnd ); +// ::SendDlgItemMessage(hWnd,IDC_BGCOLOR,CPM_SETDEFAULTCOLOUR,0,::GetSysColor(COLOR_BTNFACE)); +// ::SendDlgItemMessage(hWnd,IDC_TEXTCOLOR,CPM_SETDEFAULTCOLOUR,0,::GetSysColor(COLOR_BTNTEXT)); + ::SendDlgItemMessage(hWnd,IDC_BGCOLOR,CPM_SETCOLOUR,0,pSettings->GetColourBk()); + ::SendDlgItemMessage(hWnd,IDC_TEXTCOLOR,CPM_SETCOLOUR,0,pSettings->GetColourText()); + + ::CheckDlgButton(hWnd,IDC_CHECK_DONT_USE_POPUPHISTORY,pSettings->GetHistoryFlag()); + + ::CheckRadioButton(hWnd,IDC_RADIO_DEFAULT_COLOURS,IDC_RADIO_USER_DEFINED_COLOURS,(CPopupSettings::colourDefault == pSettings->GetColourMode()) ? IDC_RADIO_DEFAULT_COLOURS : IDC_RADIO_USER_DEFINED_COLOURS); + UINT n; + switch(pSettings->GetDelayMode()) + { + default: + assert(!"Unknown delay mode. Please, fix it"); + case CPopupSettings::delayFromPopup: + n = IDC_DELAYFROMPU; + break; + case CPopupSettings::delayCustom: + n = IDC_DELAYCUSTOM; + break; + case CPopupSettings::delayPermanent: + n = IDC_DELAYPERMANENT; + break; + } + ::CheckRadioButton(hWnd,IDC_DELAYFROMPU,IDC_DELAYPERMANENT,n); + + ::SetDlgItemInt(hWnd,IDC_DELAY,pSettings->GetDelayTimeout(),FALSE); + + update_popup_controls_settings(hWnd); + + ::SetWindowLongPtr(hWnd,GWLP_USERDATA,reinterpret_cast<LONG_PTR>(pSettings)); + } + return TRUE; + case WM_COMMAND: + switch(LOWORD(wp)) + { + case IDC_RADIO_DEFAULT_COLOURS: + case IDC_RADIO_USER_DEFINED_COLOURS: + case IDC_DELAYFROMPU: + case IDC_DELAYCUSTOM: + case IDC_DELAYPERMANENT: + update_popup_controls_settings(hWnd); + break; + + case IDCANCEL: + ::EndDialog(hWnd,IDCANCEL); + break; + case IDOK: + { + CPopupSettings* pSettings = reinterpret_cast<CPopupSettings*>(GetWindowLongPtr(hWnd,GWLP_USERDATA)); + + bool bError = false; + BOOL bOk = FALSE; + UINT nDelay = ::GetDlgItemInt(hWnd,IDC_DELAY,&bOk,FALSE); + CPopupSettings::EDelayMode nModeDelay = pSettings->GetDelayMode(); + if(1 == ::IsDlgButtonChecked(hWnd,IDC_DELAYFROMPU)) + { + nModeDelay = CPopupSettings::delayFromPopup; + } + else if(1 == ::IsDlgButtonChecked(hWnd,IDC_DELAYCUSTOM)) + { + if(TRUE == bOk) + { + nModeDelay = CPopupSettings::delayCustom; + } + else + { + prepare_edit_ctrl_for_error(::GetDlgItem(hWnd,IDC_DELAY)); + Quotes_MessageBox(hWnd,TranslateT("Enter integer value"),MB_OK|MB_ICONERROR); + bError = true; + } + } + else if(1 == ::IsDlgButtonChecked(hWnd,IDC_DELAYPERMANENT)) + { + nModeDelay = CPopupSettings::delayPermanent; + } + if(false == bError) + { + pSettings->SetDelayMode(nModeDelay); + if(TRUE == bOk) + { + pSettings->SetDelayTimeout(nDelay); + } + pSettings->SetHistoryFlag((1 == IsDlgButtonChecked(hWnd,IDC_CHECK_DONT_USE_POPUPHISTORY))); + + if(1 == ::IsDlgButtonChecked(hWnd,IDC_RADIO_DEFAULT_COLOURS)) + { + pSettings->SetColourMode(CPopupSettings::colourDefault); + } + else if(1 == ::IsDlgButtonChecked(hWnd,IDC_RADIO_USER_DEFINED_COLOURS)) + { + pSettings->SetColourMode(CPopupSettings::colourUserDefined); + } + + pSettings->SetColourBk(static_cast<COLORREF>(::SendDlgItemMessage(hWnd,IDC_BGCOLOR,CPM_GETCOLOUR,0,0))); + pSettings->SetColourText(static_cast<COLORREF>(::SendDlgItemMessage(hWnd,IDC_TEXTCOLOR,CPM_GETCOLOUR,0,0))); + + ::EndDialog(hWnd,IDOK); + } + } + break; + } + break; + } + + return FALSE; + } + + INT_PTR CALLBACK EditSettingsPerContactDlgProc(HWND hWnd,UINT msg,WPARAM wp,LPARAM lp) + { + switch(msg) + { + case WM_INITDIALOG: + { + HANDLE hContact = reinterpret_cast<HANDLE>(lp); + TranslateDialogDefault(hWnd); + + HANDLE hWL = CModuleInfo::GetInstance().GetWindowList(WINDOW_PREFIX_SETTINGS,false); + assert(hWL); + WindowList_Add(hWL,hWnd,hContact); + + tstring sName = GetContactName(hContact); + ::SetDlgItemText(hWnd,IDC_EDIT_NAME,sName.c_str()); + + CQuotesProviders::TQuotesProviderPtr pProvider = CModuleInfo::GetQuoteProvidersPtr()->GetContactProviderPtr(hContact); + + BYTE bUseContactSpecific = DBGetContactSettingByte(hContact,QUOTES_PROTOCOL_NAME,DB_STR_CONTACT_SPEC_SETTINGS,0); + ::CheckDlgButton(hWnd,IDC_CHECK_CONTACT_SPECIFIC,bUseContactSpecific); + + CAdvProviderSettings setGlobal(pProvider.get()); + // log to history + WORD dwLogMode = DBGetContactSettingWord(hContact,QUOTES_PROTOCOL_NAME,DB_STR_QUOTE_LOG,setGlobal.GetLogMode()); + UINT nCheck = (dwLogMode&lmInternalHistory) ? 1 : 0; + ::CheckDlgButton(hWnd,IDC_CHECK_INTERNAL_HISTORY,nCheck); + + tstring sHistoryFrmt = Quotes_DBGetStringT(hContact,QUOTES_PROTOCOL_NAME,DB_STR_QUOTE_FORMAT_HISTORY,setGlobal.GetHistoryFormat().c_str()); + ::SetDlgItemText(hWnd,IDC_EDIT_HISTORY_FORMAT,sHistoryFrmt.c_str()); + + WORD wOnlyIfChanged = DBGetContactSettingWord(hContact,QUOTES_PROTOCOL_NAME,DB_STR_QUOTE_HISTORY_CONDITION,setGlobal.GetHistoryOnlyChangedFlag()); + ::CheckDlgButton(hWnd,IDC_CHECK_HISTORY_CONDITION,(1 == wOnlyIfChanged) ? 1 : 0); + + // log to file + nCheck = (dwLogMode&lmExternalFile) ? 1 : 0; + ::CheckDlgButton(hWnd,IDC_CHECK_EXTERNAL_FILE,nCheck); + + tstring sLogFileName = Quotes_DBGetStringT(hContact,QUOTES_PROTOCOL_NAME,DB_STR_QUOTE_LOG_FILE); + if(true == sLogFileName.empty()) + { + sLogFileName = GenerateLogFileName(setGlobal.GetLogFileName(),Quotes_DBGetStringT(hContact,QUOTES_PROTOCOL_NAME,DB_STR_QUOTE_SYMBOL),glfnResolveQuoteName); + } + ::SetDlgItemText(hWnd,IDC_EDIT_FILE_NAME,sLogFileName.c_str()); + + tstring sLogFileFrmt = Quotes_DBGetStringT(hContact,QUOTES_PROTOCOL_NAME,DB_STR_QUOTE_FORMAT_LOG_FILE,setGlobal.GetLogFormat().c_str()); + ::SetDlgItemText(hWnd,IDC_EDIT_LOG_FILE_FORMAT,sLogFileFrmt.c_str()); + + wOnlyIfChanged = DBGetContactSettingWord(hContact,QUOTES_PROTOCOL_NAME,DB_STR_QUOTE_LOG_FILE_CONDITION,setGlobal.GetLogOnlyChangedFlag()); + ::CheckDlgButton(hWnd,IDC_CHECK_LOG_FILE_CONDITION,(1 == wOnlyIfChanged) ? 1 : 0); + + // popup + nCheck = (dwLogMode&lmPopup) ? 1 : 0; + ::CheckDlgButton(hWnd,IDC_CHECK_SHOW_POPUP,nCheck); + tstring sPopupFrmt = Quotes_DBGetStringT(hContact,QUOTES_PROTOCOL_NAME,DB_STR_QUOTE_FORMAT_POPUP,setGlobal.GetPopupFormat().c_str()); + ::SetDlgItemText(hWnd,IDC_EDIT_POPUP_FORMAT,sPopupFrmt.c_str()); + bool bOnlyIfChanged = 1 == DBGetContactSettingByte(hContact,QUOTES_PROTOCOL_NAME,DB_STR_QUOTE_POPUP_CONDITION,setGlobal.GetShowPopupIfValueChangedFlag()); + ::CheckDlgButton(hWnd,IDC_CHECK_SHOW_POPUP_ONLY_VALUE_CHANGED,(true == bOnlyIfChanged) ? 1 : 0); + + update_all_controls(hWnd); + + CSettingWindowParam* pParam = new CSettingWindowParam(hContact); + ::SetWindowLongPtr(hWnd,GWLP_USERDATA,reinterpret_cast<LONG_PTR>(pParam)); + Utils_RestoreWindowPositionNoSize(hWnd,hContact,QUOTES_MODULE_NAME,WINDOW_PREFIX_SETTINGS); + ::ShowWindow(hWnd,SW_SHOW); + } + break; + case WM_COMMAND: + switch(LOWORD(wp)) + { + case IDC_BUTTON_HISTORY_DESCRIPTION: + case IDC_BUTTON_LOG_FILE_DESCRIPTION: + case IDC_BUTTON_POPUP_FORMAT_DESCRIPTION: + if(BN_CLICKED == HIWORD(wp)) + { + CQuotesProviders::TQuotesProviderPtr pProvider = CModuleInfo::GetQuoteProvidersPtr()->GetContactProviderPtr(get_param(hWnd)->m_hContact); + show_variable_list(hWnd,pProvider.get()); + } + break; + + case IDC_CHECK_CONTACT_SPECIFIC: + if(BN_CLICKED == HIWORD(wp)) + { + update_all_controls(hWnd); + } + break; + case IDC_CHECK_EXTERNAL_FILE: + if(BN_CLICKED == HIWORD(wp)) + { + update_file_controls(hWnd); + } + break; + case IDC_CHECK_INTERNAL_HISTORY: + if(BN_CLICKED == HIWORD(wp)) + { + update_history_controls(hWnd); + } + break; + case IDC_CHECK_SHOW_POPUP: + if(BN_CLICKED == HIWORD(wp)) + { + update_popup_controls(hWnd); + } + break; + case IDC_BUTTON_BROWSE: + if(BN_CLICKED == HIWORD(wp)) + { + select_log_file(hWnd); + } + break; + case IDC_BUTTON_POPUP_SETTINGS: + if(BN_CLICKED == HIWORD(wp)) + { + CSettingWindowParam* pParam = get_param(hWnd); + if (!pParam->m_pPopupSettings) + { + CQuotesProviders::TQuotesProviderPtr pProvider = CModuleInfo::GetQuoteProvidersPtr()->GetContactProviderPtr(pParam->m_hContact); + + pParam->m_pPopupSettings = new CPopupSettings(pProvider.get()); + pParam->m_pPopupSettings->InitForContact(pParam->m_hContact); + } + + DialogBoxParam(CModuleInfo::GetModuleHandle(), + MAKEINTRESOURCE(IDD_DIALOG_POPUP), + hWnd, + EditPopupSettingsDlgProc,reinterpret_cast<LPARAM>(pParam->m_pPopupSettings)); + } + break; + + case IDOK: + { + CSettingWindowParam* pParam = get_param(hWnd); + HANDLE hContact = pParam->m_hContact; + + bool bUseContactSpec = 1 == ::IsDlgButtonChecked(hWnd,IDC_CHECK_CONTACT_SPECIFIC); + + WORD nLogMode = lmDisabled; + UINT nCheck = ::IsDlgButtonChecked(hWnd,IDC_CHECK_EXTERNAL_FILE); + if(1 == nCheck) + { + nLogMode |= lmExternalFile; + } + + nCheck = ::IsDlgButtonChecked(hWnd,IDC_CHECK_INTERNAL_HISTORY); + if(1 == nCheck) + { + nLogMode |= lmInternalHistory; + } + + nCheck = ::IsDlgButtonChecked(hWnd,IDC_CHECK_SHOW_POPUP); + if(1 == nCheck) + { + nLogMode |= lmPopup; + } + + bool bOk = true; + HWND hwndLogFile = ::GetDlgItem(hWnd,IDC_EDIT_FILE_NAME); + HWND hwndLogFileFrmt = ::GetDlgItem(hWnd,IDC_EDIT_LOG_FILE_FORMAT); + HWND hwndHistoryFrmt = ::GetDlgItem(hWnd,IDC_EDIT_HISTORY_FORMAT); + tstring sLogFile = get_window_text(hwndLogFile); + tstring sLogFileFormat = get_window_text(hwndLogFileFrmt); + tstring sHistoryFormat = get_window_text(hwndHistoryFrmt); + if ((nLogMode&lmExternalFile)) + { + if(true == sLogFile.empty()) + { + prepare_edit_ctrl_for_error(hwndLogFile); + Quotes_MessageBox(hWnd,TranslateT("Enter log file name."),MB_OK|MB_ICONERROR); + bOk = false; + } + else if(true == sLogFileFormat.empty()) + { + prepare_edit_ctrl_for_error(hwndLogFileFrmt); + Quotes_MessageBox(hWnd,TranslateT("Enter log file format."),MB_OK|MB_ICONERROR); + bOk = false; + } + } + + if ((true == bOk) && (nLogMode&lmInternalHistory) && (true == sHistoryFormat.empty())) + { + prepare_edit_ctrl_for_error(hwndHistoryFrmt); + Quotes_MessageBox(hWnd,TranslateT("Enter history format."),MB_OK|MB_ICONERROR); + bOk = false; + } + + HWND hwndPopupFrmt = ::GetDlgItem(hWnd,IDC_EDIT_POPUP_FORMAT); + tstring sPopupFormat = get_window_text(hwndPopupFrmt); + if ((true == bOk) && (nLogMode&lmPopup) && (true == sPopupFormat.empty())) + { + prepare_edit_ctrl_for_error(hwndPopupFrmt); + Quotes_MessageBox(hWnd,TranslateT("Enter popup window format."),MB_OK|MB_ICONERROR); + bOk = false; + } + + if(true == bOk) + { + UINT nIfChangedHistory = IsDlgButtonChecked(hWnd,IDC_CHECK_HISTORY_CONDITION); + UINT nIfChangedFile = IsDlgButtonChecked(hWnd,IDC_CHECK_LOG_FILE_CONDITION); + bool bIfChangedPopup = (1 == IsDlgButtonChecked(hWnd,IDC_CHECK_SHOW_POPUP_ONLY_VALUE_CHANGED)); + + DBWriteContactSettingByte(hContact,QUOTES_PROTOCOL_NAME,DB_STR_CONTACT_SPEC_SETTINGS,bUseContactSpec); + DBWriteContactSettingWord(hContact,QUOTES_PROTOCOL_NAME,DB_STR_QUOTE_LOG,nLogMode); + DBWriteContactSettingWord(hContact,QUOTES_PROTOCOL_NAME,DB_STR_QUOTE_LOG_FILE_CONDITION,nIfChangedFile); + DBWriteContactSettingWord(hContact,QUOTES_PROTOCOL_NAME,DB_STR_QUOTE_HISTORY_CONDITION,nIfChangedHistory); + DBWriteContactSettingByte(hContact,QUOTES_PROTOCOL_NAME,DB_STR_QUOTE_POPUP_CONDITION,bIfChangedPopup); + DBWriteContactSettingTString(hContact,QUOTES_PROTOCOL_NAME,DB_STR_QUOTE_LOG_FILE,sLogFile.c_str()); + DBWriteContactSettingTString(hContact,QUOTES_PROTOCOL_NAME,DB_STR_QUOTE_FORMAT_LOG_FILE,sLogFileFormat.c_str()); + DBWriteContactSettingTString(hContact,QUOTES_PROTOCOL_NAME,DB_STR_QUOTE_FORMAT_HISTORY,sHistoryFormat.c_str()); + DBWriteContactSettingTString(hContact,QUOTES_PROTOCOL_NAME,DB_STR_QUOTE_FORMAT_POPUP,sPopupFormat.c_str()); + + if(pParam->m_pPopupSettings) + { + pParam->m_pPopupSettings->SaveForContact(hContact); + } + + ::DestroyWindow(hWnd); + } + } + break; + case IDCANCEL: + DestroyWindow(hWnd); + break; + } + break; + case WM_CLOSE: + DestroyWindow(hWnd); + break; + case WM_DESTROY: + { + CSettingWindowParam* pParam = get_param(hWnd); + SetWindowLongPtr(hWnd,GWLP_USERDATA,0); + + HANDLE hWL = CModuleInfo::GetInstance().GetWindowList(WINDOW_PREFIX_SETTINGS,false); + assert(hWL); + WindowList_Remove(hWL,hWnd); + Utils_SaveWindowPosition(hWnd,pParam->m_hContact,QUOTES_MODULE_NAME,WINDOW_PREFIX_SETTINGS); + delete pParam; + } + break; + } + + return FALSE; + } +} + + +void ShowSettingsDlg(HANDLE hContact) +{ + HANDLE hWL = CModuleInfo::GetInstance().GetWindowList(WINDOW_PREFIX_SETTINGS,true); + assert(hWL); + HWND hWnd = WindowList_Find(hWL,hContact); + if(NULL != hWnd) + { + SetForegroundWindow(hWnd); + SetFocus(hWnd); + } + else + { + CreateDialogParam(CModuleInfo::GetModuleHandle(),MAKEINTRESOURCE(IDD_CONTACT_SETTINGS),NULL,EditSettingsPerContactDlgProc,reinterpret_cast<LPARAM>(hContact)); + } +} + +////////////////////////////////////////////////////////////////////////// + +namespace +{ + INT_PTR CALLBACK EditSettingsPerProviderDlgProc(HWND hWnd,UINT msg,WPARAM wp,LPARAM lp) + { + switch(msg) + { + case WM_INITDIALOG: + { + TranslateDialogDefault(hWnd); + CAdvProviderSettings* pAdvSettings = reinterpret_cast<CAdvProviderSettings*>(lp); + + ::SetDlgItemText(hWnd,IDC_EDIT_NAME,pAdvSettings->GetProviderPtr()->GetInfo().m_sName.c_str()); + + // log to history + WORD dwLogMode = pAdvSettings->GetLogMode(); + UINT nCheck = (dwLogMode&lmInternalHistory) ? 1 : 0; + ::CheckDlgButton(hWnd,IDC_CHECK_INTERNAL_HISTORY,nCheck); + ::SetDlgItemText(hWnd,IDC_EDIT_HISTORY_FORMAT,pAdvSettings->GetHistoryFormat().c_str()); + ::CheckDlgButton(hWnd,IDC_CHECK_HISTORY_CONDITION,(true == pAdvSettings->GetHistoryOnlyChangedFlag()) ? 1 : 0); + + // log to file + nCheck = (dwLogMode&lmExternalFile) ? 1 : 0; + ::CheckDlgButton(hWnd,IDC_CHECK_EXTERNAL_FILE,nCheck); + ::SetDlgItemText(hWnd,IDC_EDIT_FILE_NAME,pAdvSettings->GetLogFileName().c_str()); + ::SetDlgItemText(hWnd,IDC_EDIT_LOG_FILE_FORMAT,pAdvSettings->GetLogFormat().c_str()); + ::CheckDlgButton(hWnd,IDC_CHECK_LOG_FILE_CONDITION,(true == pAdvSettings->GetLogOnlyChangedFlag()) ? 1 : 0); + + update_file_controls(hWnd); + update_history_controls(hWnd); + + // popup + nCheck = (dwLogMode&lmPopup) ? 1 : 0; + ::CheckDlgButton(hWnd,IDC_CHECK_SHOW_POPUP,nCheck); + ::SetDlgItemText(hWnd,IDC_EDIT_POPUP_FORMAT,pAdvSettings->GetPopupFormat().c_str()); + ::CheckDlgButton(hWnd,IDC_CHECK_SHOW_POPUP_ONLY_VALUE_CHANGED,(true == pAdvSettings->GetShowPopupIfValueChangedFlag()) ? 1 : 0); + + if(true == enable_popup_controls(hWnd)) + { + update_popup_controls(hWnd); + } + + ::SetWindowLongPtr(hWnd,GWLP_USERDATA,reinterpret_cast<LONG>(pAdvSettings)); + } + return TRUE; + case WM_COMMAND: + switch(LOWORD(wp)) + { + case IDOK: + { + WORD nLogMode = lmDisabled; + UINT nCheck = ::IsDlgButtonChecked(hWnd,IDC_CHECK_EXTERNAL_FILE); + if(1 == nCheck) + { + nLogMode |= lmExternalFile; + } + + nCheck = ::IsDlgButtonChecked(hWnd,IDC_CHECK_INTERNAL_HISTORY); + if(1 == nCheck) + { + nLogMode |= lmInternalHistory; + } + + nCheck = ::IsDlgButtonChecked(hWnd,IDC_CHECK_SHOW_POPUP); + if(1 == nCheck) + { + nLogMode |= lmPopup; + } + + bool bOk = true; + HWND hwndLogFile = ::GetDlgItem(hWnd,IDC_EDIT_FILE_NAME); + HWND hwndLogFileFrmt = ::GetDlgItem(hWnd,IDC_EDIT_LOG_FILE_FORMAT); + + tstring sLogFile = get_window_text(hwndLogFile); + tstring sLogFileFormat = get_window_text(hwndLogFileFrmt); + + if ((nLogMode&lmExternalFile)) + { + if(true == sLogFile.empty()) + { + prepare_edit_ctrl_for_error(hwndLogFile); + Quotes_MessageBox(hWnd,TranslateT("Enter log file name."),MB_OK|MB_ICONERROR); + bOk = false; + } + else if(true == sLogFileFormat.empty()) + { + prepare_edit_ctrl_for_error(hwndLogFileFrmt); + Quotes_MessageBox(hWnd,TranslateT("Enter log file format."),MB_OK|MB_ICONERROR); + bOk = false; + } + } + + HWND hwndHistoryFrmt = ::GetDlgItem(hWnd,IDC_EDIT_HISTORY_FORMAT); + tstring sHistoryFormat = get_window_text(hwndHistoryFrmt); + if ((true == bOk) && (nLogMode&lmInternalHistory) && (true == sHistoryFormat.empty())) + { + prepare_edit_ctrl_for_error(hwndHistoryFrmt); + Quotes_MessageBox(hWnd,TranslateT("Enter history format."),MB_OK|MB_ICONERROR); + bOk = false; + } + + HWND hwndPopupFrmt = ::GetDlgItem(hWnd,IDC_EDIT_POPUP_FORMAT); + tstring sPopupFormat = get_window_text(hwndPopupFrmt); + if ((true == bOk) && (nLogMode&lmPopup) && (true == sPopupFormat.empty())) + { + prepare_edit_ctrl_for_error(hwndPopupFrmt); + Quotes_MessageBox(hWnd,TranslateT("Enter popup window format."),MB_OK|MB_ICONERROR); + bOk = false; + } + + if(true == bOk) + { + CAdvProviderSettings* pAdvSettings = reinterpret_cast<CAdvProviderSettings*>(GetWindowLongPtr(hWnd,GWLP_USERDATA)); + + pAdvSettings->SetLogMode(nLogMode); + pAdvSettings->SetHistoryOnlyChangedFlag(1 == IsDlgButtonChecked(hWnd,IDC_CHECK_HISTORY_CONDITION)); + pAdvSettings->SetLogOnlyChangedFlag(1 == IsDlgButtonChecked(hWnd,IDC_CHECK_LOG_FILE_CONDITION)); + pAdvSettings->SetShowPopupIfValueChangedFlag(1 == IsDlgButtonChecked(hWnd,IDC_CHECK_SHOW_POPUP_ONLY_VALUE_CHANGED)); + pAdvSettings->SetLogFileName(sLogFile); + pAdvSettings->SetLogFormat(sLogFileFormat); + pAdvSettings->SetHistoryFormat(sHistoryFormat); + pAdvSettings->SetPopupFormat(sPopupFormat); + + ::EndDialog(hWnd,IDOK); + } + } + break; + case IDCANCEL: + ::EndDialog(hWnd,IDCANCEL); + break; + case IDC_BUTTON_HISTORY_DESCRIPTION: + case IDC_BUTTON_LOG_FILE_DESCRIPTION: + case IDC_BUTTON_POPUP_FORMAT_DESCRIPTION: + if(BN_CLICKED == HIWORD(wp)) + { + const CAdvProviderSettings* pAdvSettings = reinterpret_cast<CAdvProviderSettings*>(GetWindowLongPtr(hWnd,GWLP_USERDATA)); + show_variable_list(hWnd,pAdvSettings->GetProviderPtr()); + } + break; + case IDC_CHECK_EXTERNAL_FILE: + if(BN_CLICKED == HIWORD(wp)) + { + update_file_controls(hWnd); + } + break; + case IDC_CHECK_INTERNAL_HISTORY: + if(BN_CLICKED == HIWORD(wp)) + { + update_history_controls(hWnd); + } + break; + case IDC_CHECK_SHOW_POPUP: + if(BN_CLICKED == HIWORD(wp)) + { + update_popup_controls(hWnd); + } + break; + case IDC_BUTTON_BROWSE: + if(BN_CLICKED == HIWORD(wp)) + { + select_log_file(hWnd); + } + break; + case IDC_BUTTON_POPUP_SETTINGS: + { + const CAdvProviderSettings* pAdvSettings = reinterpret_cast<CAdvProviderSettings*>(GetWindowLongPtr(hWnd,GWLP_USERDATA)); + DialogBoxParam(CModuleInfo::GetModuleHandle(), + MAKEINTRESOURCE(IDD_DIALOG_POPUP), + hWnd, + EditPopupSettingsDlgProc,reinterpret_cast<LPARAM>(pAdvSettings->GetPopupSettingsPtr())); + + } + break; + } + break; + } + return FALSE; + } +} + +CAdvProviderSettings::CAdvProviderSettings(const IQuotesProvider* pQuotesProvider) + : m_pQuotesProvider(pQuotesProvider), + m_wLogMode(lmDisabled), + m_bIsOnlyChangedHistory(false), + m_bIsOnlyChangedLogFile(false), + m_bShowPopupIfValueChanged(false), + m_pPopupSettings(nullptr) +{ + assert(m_pQuotesProvider); + + CQuotesProviderVisitorDbSettings visitor; + m_pQuotesProvider->Accept(visitor); + + assert(visitor.m_pszDefLogFileFormat); + assert(visitor.m_pszDefHistoryFormat); + assert(visitor.m_pszDbLogMode); + assert(visitor.m_pszDbHistoryFormat); + assert(visitor.m_pszDbHistoryCondition); + assert(visitor.m_pszDbLogFile); + assert(visitor.m_pszDbLogFormat); + assert(visitor.m_pszDbLogCondition); + + m_wLogMode = DBGetContactSettingWord(NULL,QUOTES_PROTOCOL_NAME,visitor.m_pszDbLogMode,static_cast<WORD>(lmDisabled)); + m_sFormatHistory = Quotes_DBGetStringT(NULL,QUOTES_PROTOCOL_NAME,visitor.m_pszDbHistoryFormat,visitor.m_pszDefHistoryFormat); + m_bIsOnlyChangedHistory = 1 == DBGetContactSettingByte(NULL,QUOTES_PROTOCOL_NAME,visitor.m_pszDbHistoryCondition,0); + + m_sLogFileName = Quotes_DBGetStringT(NULL,QUOTES_PROTOCOL_NAME,visitor.m_pszDbLogFile); + if(true == m_sLogFileName.empty()) + { + m_sLogFileName = g_pszVariableUserProfile; + m_sLogFileName += _T("\\Quotes\\"); + m_sLogFileName += g_pszVariableQuoteName; + m_sLogFileName += _T(".log"); + } + + m_sFormatLogFile = Quotes_DBGetStringT(NULL,QUOTES_PROTOCOL_NAME,visitor.m_pszDbLogFormat,visitor.m_pszDefLogFileFormat); + m_bIsOnlyChangedLogFile = (1 == DBGetContactSettingByte(NULL,QUOTES_PROTOCOL_NAME,visitor.m_pszDbLogCondition,0)); + + m_sPopupFormat = Quotes_DBGetStringT(NULL,QUOTES_PROTOCOL_NAME,visitor.m_pszDbPopupFormat,visitor.m_pszDefPopupFormat); + m_bShowPopupIfValueChanged = (1 == DBGetContactSettingByte(NULL,QUOTES_PROTOCOL_NAME,visitor.m_pszDbPopupCondition,0)); +} + +CAdvProviderSettings::~CAdvProviderSettings() +{ + delete m_pPopupSettings; +} + +const IQuotesProvider* CAdvProviderSettings::GetProviderPtr()const +{ + return m_pQuotesProvider; +} + +void CAdvProviderSettings::SaveToDb()const +{ + CQuotesProviderVisitorDbSettings visitor; + m_pQuotesProvider->Accept(visitor); + + assert(visitor.m_pszDbLogMode); + assert(visitor.m_pszDbHistoryFormat); + assert(visitor.m_pszDbHistoryCondition); + assert(visitor.m_pszDbLogFile); + assert(visitor.m_pszDbLogFormat); + assert(visitor.m_pszDbLogCondition); + assert(visitor.m_pszDbPopupColourMode); + assert(visitor.m_pszDbPopupBkColour); + assert(visitor.m_pszDbPopupTextColour); + assert(visitor.m_pszDbPopupDelayMode); + assert(visitor.m_pszDbPopupDelayTimeout); + assert(visitor.m_pszDbPopupHistoryFlag); + + DBWriteContactSettingWord(NULL,QUOTES_PROTOCOL_NAME,visitor.m_pszDbLogMode,m_wLogMode); + DBWriteContactSettingTString(NULL,QUOTES_PROTOCOL_NAME,visitor.m_pszDbHistoryFormat,m_sFormatHistory.c_str()); + DBWriteContactSettingByte(NULL,QUOTES_PROTOCOL_NAME,visitor.m_pszDbHistoryCondition,m_bIsOnlyChangedHistory); + DBWriteContactSettingTString(NULL,QUOTES_PROTOCOL_NAME,visitor.m_pszDbLogFile,m_sLogFileName.c_str()); + DBWriteContactSettingTString(NULL,QUOTES_PROTOCOL_NAME,visitor.m_pszDbLogFormat,m_sFormatLogFile.c_str()); + DBWriteContactSettingByte(NULL,QUOTES_PROTOCOL_NAME,visitor.m_pszDbLogCondition,m_bIsOnlyChangedLogFile); + DBWriteContactSettingTString(NULL,QUOTES_PROTOCOL_NAME,visitor.m_pszDbPopupFormat,m_sPopupFormat.c_str()); + DBWriteContactSettingByte(NULL,QUOTES_PROTOCOL_NAME,visitor.m_pszDbPopupCondition,m_bShowPopupIfValueChanged); + + if(nullptr != m_pPopupSettings) + { + DBWriteContactSettingByte(NULL,QUOTES_PROTOCOL_NAME,visitor.m_pszDbPopupColourMode,static_cast<BYTE>(m_pPopupSettings->GetColourMode())); + DBWriteContactSettingDword(NULL,QUOTES_PROTOCOL_NAME,visitor.m_pszDbPopupBkColour,m_pPopupSettings->GetColourBk()); + DBWriteContactSettingDword(NULL,QUOTES_PROTOCOL_NAME,visitor.m_pszDbPopupTextColour,m_pPopupSettings->GetColourText()); + DBWriteContactSettingByte(NULL,QUOTES_PROTOCOL_NAME,visitor.m_pszDbPopupDelayMode,static_cast<BYTE>(m_pPopupSettings->GetDelayMode())); + DBWriteContactSettingWord(NULL,QUOTES_PROTOCOL_NAME,visitor.m_pszDbPopupDelayTimeout,m_pPopupSettings->GetDelayTimeout()); + DBWriteContactSettingByte(NULL,QUOTES_PROTOCOL_NAME,visitor.m_pszDbPopupHistoryFlag,m_pPopupSettings->GetHistoryFlag()); + } +} + +WORD CAdvProviderSettings::GetLogMode()const +{ + return m_wLogMode; +} + +void CAdvProviderSettings::SetLogMode(WORD wMode) +{ + m_wLogMode = wMode; +} + +tstring CAdvProviderSettings::GetHistoryFormat()const +{ + return m_sFormatHistory; +} + +void CAdvProviderSettings::SetHistoryFormat(const tstring& rsFormat) +{ + m_sFormatHistory = rsFormat; +} + +bool CAdvProviderSettings::GetHistoryOnlyChangedFlag()const +{ + return m_bIsOnlyChangedHistory; +} + +void CAdvProviderSettings::SetHistoryOnlyChangedFlag(bool bMode) +{ + m_bIsOnlyChangedHistory = bMode; +} + +tstring CAdvProviderSettings::GetLogFileName()const +{ + return m_sLogFileName; +} + +void CAdvProviderSettings::SetLogFileName(const tstring& rsFile) +{ + m_sLogFileName = rsFile; +} + +tstring CAdvProviderSettings::GetLogFormat()const +{ + return m_sFormatLogFile; +} + +void CAdvProviderSettings::SetLogFormat(const tstring& rsFormat) +{ + m_sFormatLogFile = rsFormat; +} + +bool CAdvProviderSettings::GetLogOnlyChangedFlag()const +{ + return m_bIsOnlyChangedLogFile; +} + +void CAdvProviderSettings::SetLogOnlyChangedFlag(bool bMode) +{ + m_bIsOnlyChangedLogFile = bMode; +} + +const tstring& CAdvProviderSettings::GetPopupFormat() const +{ + return m_sPopupFormat; +} + +void CAdvProviderSettings::SetPopupFormat(const tstring& val) +{ + m_sPopupFormat = val; +} + +bool CAdvProviderSettings::GetShowPopupIfValueChangedFlag() const +{ + return m_bShowPopupIfValueChanged; +} + +void CAdvProviderSettings::SetShowPopupIfValueChangedFlag(bool val) +{ + m_bShowPopupIfValueChanged = val; +} + +CPopupSettings* CAdvProviderSettings::GetPopupSettingsPtr()const +{ + if(nullptr == m_pPopupSettings) + { + m_pPopupSettings = new CPopupSettings(m_pQuotesProvider); + } + + return m_pPopupSettings; +} + +CPopupSettings::CPopupSettings(const IQuotesProvider* pQuotesProvider) + : m_modeColour(colourDefault), + m_modeDelay(delayFromPopup), + m_rgbBkg(GetDefColourBk()), + m_rgbText(GetDefColourText()), + m_wDelay(3), + m_bUseHistory(false) + +{ + CQuotesProviderVisitorDbSettings visitor; + pQuotesProvider->Accept(visitor); + + assert(visitor.m_pszDbPopupColourMode); + assert(visitor.m_pszDbPopupBkColour); + assert(visitor.m_pszDbPopupTextColour); + assert(visitor.m_pszDbPopupDelayMode); + assert(visitor.m_pszDbPopupDelayTimeout); + assert(visitor.m_pszDbPopupHistoryFlag); + + BYTE m = DBGetContactSettingByte(NULL,QUOTES_PROTOCOL_NAME,visitor.m_pszDbPopupColourMode,static_cast<BYTE>(m_modeColour)); + if(m >= colourDefault && m <= colourUserDefined) + { + m_modeColour = static_cast<EColourMode>(m); + } + + m_rgbBkg = DBGetContactSettingDword(NULL,QUOTES_PROTOCOL_NAME,visitor.m_pszDbPopupBkColour,m_rgbBkg); + m_rgbText = DBGetContactSettingDword(NULL,QUOTES_PROTOCOL_NAME,visitor.m_pszDbPopupTextColour,m_rgbText); + + m = DBGetContactSettingByte(NULL,QUOTES_PROTOCOL_NAME,visitor.m_pszDbPopupDelayMode,static_cast<BYTE>(m_modeDelay)); + if(m >= delayFromPopup && m <= delayPermanent) + { + m_modeDelay = static_cast<EDelayMode>(m); + } + m_wDelay = DBGetContactSettingWord(NULL,QUOTES_PROTOCOL_NAME,visitor.m_pszDbPopupDelayTimeout,m_wDelay); + m_bUseHistory = (1 == DBGetContactSettingByte(NULL,QUOTES_PROTOCOL_NAME,visitor.m_pszDbPopupHistoryFlag,m_bUseHistory)); +} + +/*static */ +COLORREF CPopupSettings::GetDefColourBk() +{ + return ::GetSysColor(COLOR_BTNFACE); +} + +/*static */ +COLORREF CPopupSettings::GetDefColourText() +{ + return ::GetSysColor(COLOR_BTNTEXT); +} + +void CPopupSettings::InitForContact(HANDLE hContact) +{ + BYTE m = DBGetContactSettingByte(hContact,QUOTES_PROTOCOL_NAME,DB_STR_QUOTE_POPUP_COLOUR_MODE,static_cast<BYTE>(m_modeColour)); + if(m >= CPopupSettings::colourDefault && m <= CPopupSettings::colourUserDefined) + { + m_modeColour = static_cast<CPopupSettings::EColourMode>(m); + } + + m_rgbBkg = DBGetContactSettingDword(hContact,QUOTES_PROTOCOL_NAME,DB_STR_QUOTE_POPUP_COLOUR_BK,m_rgbBkg); + m_rgbText = DBGetContactSettingDword(hContact,QUOTES_PROTOCOL_NAME,DB_STR_QUOTE_POPUP_COLOUR_TEXT,m_rgbText); + + m = DBGetContactSettingByte(hContact,QUOTES_PROTOCOL_NAME,DB_STR_QUOTE_POPUP_DELAY_MODE,static_cast<BYTE>(m_modeDelay)); + if(m >= CPopupSettings::delayFromPopup && m <= CPopupSettings::delayPermanent) + { + m_modeDelay = static_cast<CPopupSettings::EDelayMode>(m); + } + m_wDelay = DBGetContactSettingWord(hContact,QUOTES_PROTOCOL_NAME,DB_STR_QUOTE_POPUP_DELAY_TIMEOUT,m_wDelay); + m_bUseHistory = 1 == DBGetContactSettingByte(hContact,QUOTES_PROTOCOL_NAME,DB_STR_QUOTE_POPUP_HISTORY_FLAG,m_bUseHistory); +} + +void CPopupSettings::SaveForContact(HANDLE hContact)const +{ + DBWriteContactSettingByte(hContact,QUOTES_PROTOCOL_NAME,DB_STR_QUOTE_POPUP_COLOUR_MODE,static_cast<BYTE>(m_modeColour)); + DBWriteContactSettingDword(hContact,QUOTES_PROTOCOL_NAME,DB_STR_QUOTE_POPUP_COLOUR_BK,m_rgbBkg); + DBWriteContactSettingDword(hContact,QUOTES_PROTOCOL_NAME,DB_STR_QUOTE_POPUP_COLOUR_TEXT,m_rgbText); + DBWriteContactSettingByte(hContact,QUOTES_PROTOCOL_NAME,DB_STR_QUOTE_POPUP_DELAY_MODE,static_cast<BYTE>(m_modeDelay)); + DBWriteContactSettingWord(hContact,QUOTES_PROTOCOL_NAME,DB_STR_QUOTE_POPUP_DELAY_TIMEOUT,m_wDelay); + DBWriteContactSettingByte(hContact,QUOTES_PROTOCOL_NAME,DB_STR_QUOTE_POPUP_HISTORY_FLAG,m_bUseHistory); +} + +CPopupSettings::EColourMode CPopupSettings::GetColourMode()const +{ + return m_modeColour; +} + +void CPopupSettings::SetColourMode(EColourMode nMode) +{ + m_modeColour = nMode; +} + +COLORREF CPopupSettings::GetColourBk()const +{ + return m_rgbBkg; +} + +void CPopupSettings::SetColourBk(COLORREF rgb) +{ + m_rgbBkg = rgb; +} + +COLORREF CPopupSettings::GetColourText()const +{ + return m_rgbText; +} + +void CPopupSettings::SetColourText(COLORREF rgb) +{ + m_rgbText = rgb; +} + +CPopupSettings::EDelayMode CPopupSettings::GetDelayMode()const +{ + return m_modeDelay; +} + +void CPopupSettings::SetDelayMode(EDelayMode nMode) +{ + m_modeDelay = nMode; +} + +WORD CPopupSettings::GetDelayTimeout()const +{ + return m_wDelay; +} + +void CPopupSettings::SetDelayTimeout(WORD delay) +{ + m_wDelay = delay; +} + +bool CPopupSettings::GetHistoryFlag()const +{ + return m_bUseHistory; +} + +void CPopupSettings::SetHistoryFlag(bool flag) +{ + m_bUseHistory = flag; +} + +bool ShowSettingsDlg(HWND hWndParent,CAdvProviderSettings* pAdvSettings) +{ + assert(pAdvSettings); + + return (IDOK == DialogBoxParam(CModuleInfo::GetModuleHandle(), + MAKEINTRESOURCE(IDD_PROVIDER_ADV_SETTINGS), + hWndParent, + EditSettingsPerProviderDlgProc, + reinterpret_cast<LPARAM>(pAdvSettings))); +} + +namespace +{ + void replace_invalid_char(tstring::value_type& rChar,tstring::value_type repl) + { + static const TCHAR charInvalidSigns[] = {_T('\\'), _T('/'), _T(':'), _T('*'), _T('?'), _T('\"'), _T('<'), _T('>'), _T('|')}; + + for(int i = 0; i < sizeof(charInvalidSigns)/sizeof(charInvalidSigns[0]);++i) + { + if(rChar == charInvalidSigns[i]) + { + rChar = repl; + break; + } + } + } + +} + +tstring GenerateLogFileName(const tstring& rsLogFilePattern, + const tstring& rsQuoteSymbol, + int nFlags/* = glfnResolveAll*/) +{ + tstring sPath = rsLogFilePattern; + if(nFlags&glfnResolveQuoteName) + { + assert(false == rsQuoteSymbol.empty()); + + tstring::size_type n = sPath.find(g_pszVariableQuoteName); + if(tstring::npos != n) + { + tstring s = rsQuoteSymbol; + std::for_each(s.begin(),s.end(),boost::bind(replace_invalid_char,_1,_T('_'))); + sPath.replace(n,lstrlen(g_pszVariableQuoteName),s.c_str()); + } + } + + if(nFlags&glfnResolveUserProfile) + { + REPLACEVARSDATA dat = {0}; + dat.cbSize = sizeof(dat); + dat.dwFlags = RVF_TCHAR; + + TCHAR* ptszParsedName = reinterpret_cast<TCHAR*>(CallService(MS_UTILS_REPLACEVARS, + reinterpret_cast<WPARAM>(sPath.c_str()),reinterpret_cast<LPARAM>(&dat))); + if(ptszParsedName) + { + sPath = ptszParsedName; + mir_free(ptszParsedName); + } + } + + return sPath; +} + +tstring GetContactLogFileName(HANDLE hContact) +{ + tstring result; + + const CQuotesProviders::TQuotesProviderPtr& pProvider = CModuleInfo::GetQuoteProvidersPtr()->GetContactProviderPtr(hContact); + if(pProvider) + { + tstring sPattern; + bool bUseContactSpecific = (DBGetContactSettingByte(hContact,QUOTES_PROTOCOL_NAME,DB_STR_CONTACT_SPEC_SETTINGS,0) > 0); + if(bUseContactSpecific) + { + sPattern = Quotes_DBGetStringT(hContact,QUOTES_PROTOCOL_NAME,DB_STR_QUOTE_LOG_FILE); + } + else + { + CAdvProviderSettings global_settings(pProvider.get()); + sPattern = global_settings.GetLogFileName(); + } + + result = GenerateLogFileName(sPattern,Quotes_DBGetStringT(hContact,QUOTES_PROTOCOL_NAME,DB_STR_QUOTE_SYMBOL)); + } + + return result; +} + +tstring GetContactName(HANDLE hContact) +{ + tstring sDescription = Quotes_DBGetStringT(hContact,QUOTES_PROTOCOL_NAME,DB_STR_QUOTE_DESCRIPTION); + if(sDescription.empty()) + { + sDescription = Quotes_DBGetStringT(hContact,QUOTES_PROTOCOL_NAME,DB_STR_QUOTE_SYMBOL); + } + return sDescription; +} diff --git a/protocols/Quotes/SettingsDlg.h b/protocols/Quotes/SettingsDlg.h new file mode 100644 index 0000000000..569d0b7d2c --- /dev/null +++ b/protocols/Quotes/SettingsDlg.h @@ -0,0 +1,118 @@ +#ifndef __E211E4D9_383C_43BE_A787_7EF1D585B90D_SettingsDlg_h__ +#define __E211E4D9_383C_43BE_A787_7EF1D585B90D_SettingsDlg_h__ + +class IQuotesProvider; + +class CPopupSettings +{ +public: + enum EColourMode + { + colourDefault, + colourUserDefined, + }; + + enum EDelayMode + { + delayFromPopup, + delayCustom, + delayPermanent + }; + +public: + CPopupSettings(const IQuotesProvider* pQuotesProvider); + + static COLORREF GetDefColourBk(); + static COLORREF GetDefColourText(); + + void InitForContact(HANDLE hContact); + void SaveForContact(HANDLE hContact)const; + + EColourMode GetColourMode()const; + void SetColourMode(EColourMode nMode); + + COLORREF GetColourBk()const; + void SetColourBk(COLORREF rgb); + + COLORREF GetColourText()const; + void SetColourText(COLORREF rgb); + + EDelayMode GetDelayMode()const; + void SetDelayMode(EDelayMode nMode); + + WORD GetDelayTimeout()const; + void SetDelayTimeout(WORD delay); + + bool GetHistoryFlag()const; + void SetHistoryFlag(bool flag); + +private: + EColourMode m_modeColour; + EDelayMode m_modeDelay; + COLORREF m_rgbBkg; + COLORREF m_rgbText; + WORD m_wDelay; + bool m_bUseHistory; +}; + + +class CAdvProviderSettings +{ +public: + CAdvProviderSettings(const IQuotesProvider* pQuotesProvider); + ~CAdvProviderSettings(); + + void SaveToDb()const; + + const IQuotesProvider* GetProviderPtr()const; + + WORD GetLogMode()const; + void SetLogMode(WORD wMode); + tstring GetHistoryFormat()const; + void SetHistoryFormat(const tstring& rsFormat); + bool GetHistoryOnlyChangedFlag()const; + void SetHistoryOnlyChangedFlag(bool bMode); + + tstring GetLogFileName()const; + void SetLogFileName(const tstring& rsFile); + tstring GetLogFormat()const; + void SetLogFormat(const tstring& rsFormat); + bool GetLogOnlyChangedFlag()const; + void SetLogOnlyChangedFlag(bool bMode); + + const tstring& GetPopupFormat() const; + void SetPopupFormat(const tstring& val); + + bool GetShowPopupIfValueChangedFlag() const; + void SetShowPopupIfValueChangedFlag(bool val); + + CPopupSettings* GetPopupSettingsPtr()const; + +private: + const IQuotesProvider* m_pQuotesProvider; + WORD m_wLogMode; + tstring m_sFormatHistory; + bool m_bIsOnlyChangedHistory; + tstring m_sLogFileName; + tstring m_sFormatLogFile; + bool m_bIsOnlyChangedLogFile; + tstring m_sPopupFormat; + bool m_bShowPopupIfValueChanged; + mutable CPopupSettings* m_pPopupSettings; +}; + +void ShowSettingsDlg(HANDLE hContact); +bool ShowSettingsDlg(HWND hWndParent,CAdvProviderSettings* pAdvSettings); + +enum +{ + glfnResolveQuoteName = 0x0001, + glfnResolveUserProfile = 0x0002, + glfnResolveAll = glfnResolveQuoteName|glfnResolveUserProfile, +}; +tstring GenerateLogFileName(const tstring& rsLogFilePattern,const tstring& rsQuoteSymbol,int nFlags = glfnResolveAll); +tstring GetContactLogFileName(HANDLE hContact); +tstring GetContactName(HANDLE hContact); + +#endif //__E211E4D9_383C_43BE_A787_7EF1D585B90D_SettingsDlg_h__ + diff --git a/protocols/Quotes/Utility/DukasCopy.py b/protocols/Quotes/Utility/DukasCopy.py new file mode 100644 index 0000000000..2d12d1c4ec --- /dev/null +++ b/protocols/Quotes/Utility/DukasCopy.py @@ -0,0 +1,48 @@ +from html.parser import HTMLParser +import sys + +class MyHTMLParser(HTMLParser): + def __init__(self, in_fn,out_fn): + HTMLParser.__init__(self) + f_in = open(in_fn,'r') + self.quote = 0 + self.descr = '' + self.f_out = open(out_fn,'w') + self.feed(f_in.read()) + f_in.close() + self.f_out.close() + + def handle_starttag(self, tag, attrs): + #print ("start of a %s" % tag) + #print (attrs) + self.start = 1 + if tag == 'input': + self.f_out.write('\n<quote>') + for k in attrs: + if k[0] == 'stname': + self.f_out.write('\n\t<symbol>%s</symbol>'%k[1]) + if k[0] == 'stid': + self.f_out.write('\n\t<id>%s</id>'%k[1]) + self.quote = 1 + + + def handle_endtag(self, tag): + self.start = 0 + if tag == 'tr' and self.quote == 1: + if self.descr: + self.f_out.write('\n\t<description>%s</description>'%self.descr) + self.f_out.write('\n</quote>') + self.quote = 0 + self.descr = 1 + #print ("end of a %s" % tag) + + def handle_data(self, data): + if self.start == 1: + self.descr = data + #print ("Data %s" % self.descr) + + + +parser = MyHTMLParser(sys.argv[1],sys.argv[2]) +parser.close() + \ No newline at end of file diff --git a/protocols/Quotes/Utility/Dukascopy.xml b/protocols/Quotes/Utility/Dukascopy.xml new file mode 100644 index 0000000000..92890888b9 --- /dev/null +++ b/protocols/Quotes/Utility/Dukascopy.xml @@ -0,0 +1,1635 @@ +<?xml version="1.0" encoding="utf-8"?> + +<Provider> + <name>Dukascopy Swiss Forex Group</name> + <ref>http://www.dukascopy.com</ref> + <url>http://freeserv.dukascopy.com/qt/?&STOCKS=</url> + + <!--European Stocks--> + + <section> + <name>European Stocks</name> + +<quote> + <id>127</id> + <symbol>BA</symbol> + <description>BAE Systems</description> +</quote> +<quote> + <id>130</id> + <symbol>BKIR</symbol> + <description>Bank of Ireland</description> +</quote> +<quote> + <id>131</id> + <symbol>BP</symbol> + <description>British Petroleum</description> +</quote> +<quote> + <id>138</id> + <symbol>SBRY</symbol> + <description>Sainsbury</description> +</quote> +<quote> + <id>142</id> + <symbol>AZN</symbol> + <description>Astrazeneca</description> +</quote> +<quote> + <id>145</id> + <symbol>CNA</symbol> + <description>Centrica</description> +</quote> +<quote> + <id>153</id> + <symbol>MKS</symbol> + <description> Spencer</description> +</quote> +<quote> + <id>155</id> + <symbol>RTR</symbol> + <description>Reuters Group</description> +</quote> +<quote> + <id>156</id> + <symbol>RR</symbol> + <description>Rolls Royce</description> +</quote> +<quote> + <id>158</id> + <symbol>TSCO</symbol> + <description>Tesco</description> +</quote> +<quote> + <id>165</id> + <symbol>ALV</symbol> + <description>Alliaz AG</description> +</quote> +<quote> + <id>167</id> + <symbol>BAY</symbol> + <description>Bayer AG</description> +</quote> +<quote> + <id>169</id> + <symbol>CBK</symbol> + <description>Commerzbank AG</description> +</quote> +<quote> + <id>171</id> + <symbol>DBK</symbol> + <description>Deutsche Bank AG</description> +</quote> +<quote> + <id>177</id> + <symbol>SIE</symbol> + <description>Siemens AG</description> +</quote> +<quote> + <id>178</id> + <symbol>TKA</symbol> + <description>Thyssenkrupp AG</description> +</quote> +<quote> + <id>179</id> + <symbol>VOW</symbol> + <description>Volkswagen AG</description> +</quote> +<quote> + <id>183</id> + <symbol>FTE</symbol> + <description>France Telecom</description> +</quote> +<quote> + <id>191</id> + <symbol>OR</symbol> + <description>LOreal</description> +</quote> +<quote> + <id>192</id> + <symbol>ML</symbol> + <description>Michelin</description> +</quote> +<quote> + <id>193</id> + <symbol>RNO</symbol> + <description>Renault</description> +</quote> +<quote> + <id>195</id> + <symbol>UG</symbol> + <description>Peugeot SA</description> +</quote> +<quote> + <id>198</id> + <symbol>LG</symbol> + <description>Lafarge</description> +</quote> +<quote> + <id>206</id> + <symbol>PIN</symbol> + <description>Pinguin</description> +</quote> +<quote> + <id>213</id> + <symbol>RBACW</symbol> + <description>Rabo Agaath Bank</description> +</quote> +<quote> + <id>221</id> + <symbol>ABBN</symbol> + <description>ABB Finance</description> +</quote> +<quote> + <id>222</id> + <symbol>ADEN</symbol> + <description>Adecco SA</description> +</quote> +<quote> + <id>224</id> + <symbol>RUKN</symbol> + <description>Swiss Reinsurance</description> +</quote> +<quote> + <id>232</id> + <symbol>GFC</symbol> + <description>Gecina</description> +</quote> +<quote> + <id>234</id> + <symbol>VK</symbol> + <description>Vallourec</description> +</quote> +<quote> + <id>235</id> + <symbol>FLE</symbol> + <description>Fleury Michon</description> +</quote> +<quote> + <id>242</id> + <symbol>NEX</symbol> + <description>National Express Group</description> +</quote> +<quote> + <id>245</id> + <symbol>IMT</symbol> + <description>Imperial Tobacco</description> +</quote> +<quote> + <id>338</id> + <symbol>Pseudo</symbol> + <description>Pseudo</description> +</quote> +<quote> + <id>340</id> + <symbol>Pseudo1</symbol> + <description>Pseudo1</description> +</quote> +<quote> + <id>321</id> + <symbol>ROS</symbol> + <description>OAO Rostelecom</description> +</quote> +<quote> + <id>325</id> + <symbol>FIA</symbol> + <description>Fiat S.p.A.</description> +</quote> +<quote> + <id>326</id> + <symbol>E</symbol> + <description>Eni S.p.A.</description> +</quote> +<quote> + <id>327</id> + <symbol>EN</symbol> + <description>Enel S.p.A.</description> +</quote> +<quote> + <id>152</id> + <symbol>LLOY</symbol> + <description>Lloyds TSB Bank</description> +</quote> +<quote> + <id>226</id> + <symbol>AKZA</symbol> + <description>Akzo Nobel NV</description> +</quote> +<quote> + <id>135</id> + <symbol>BSY</symbol> + <description>British Sky Broadcast</description> +</quote> +<quote> + <id>144</id> + <symbol>CW</symbol> + <description> Wireless</description> +</quote> +<quote> + <id>146</id> + <symbol>GSK</symbol> + <description>Glaxosmithkline</description> +</quote> +<quote> + <id>149</id> + <symbol>HSBA</symbol> + <description>HSBC Bank</description> +</quote> +<quote> + <id>151</id> + <symbol>KGF</symbol> + <description>Kingfisher</description> +</quote> +<quote> + <id>166</id> + <symbol>BAS</symbol> + <description>BASF AG</description> +</quote> +<quote> + <id>172</id> + <symbol>DPW</symbol> + <description>Deutsche Post AG</description> +</quote> +<quote> + <id>173</id> + <symbol>DTE</symbol> + <description>Deutsche Telecom</description> +</quote> +<quote> + <id>249</id> + <symbol>CA</symbol> + <description>Carrefour</description> +</quote> +<quote> + <id>218</id> + <symbol>NESN</symbol> + <description>Nestle SA</description> +</quote> +<quote> + <id>219</id> + <symbol>UBSN</symbol> + <description>UBS AG</description> +</quote> +<quote> + <id>229</id> + <symbol>DIE</symbol> + <description>DIeteren Trading</description> +</quote> +<quote> + <id>237</id> + <symbol>GAM</symbol> + <description>Gaumont</description> +</quote> +<quote> + <id>238</id> + <symbol>AGE</symbol> + <description>AGFA Gevaert NV</description> +</quote> +<quote> + <id>243</id> + <symbol>CBRY</symbol> + <description>Cadbury Schweppes</description> +</quote> +<quote> + <id>246</id> + <symbol>MLW</symbol> + <description>Merrill Lynch World</description> +</quote> +<quote> + <id>248</id> + <symbol>MASN</symbol> + <description>Micronas Semiconductors</description> +</quote> +<quote> + <id>255</id> + <symbol>ARE</symbol> + <description>Groupe Ares</description> +</quote> +<quote> + <id>200</id> + <symbol>DELB</symbol> + <description>Delhaize Group</description> +</quote> +<quote> + <id>215</id> + <symbol>PHIA</symbol> + <description>Philips Electronics</description> +</quote> +<quote> + <id>216</id> + <symbol>CSGN</symbol> + <description>Credit Suisse Groupe CAP</description> +</quote> +<quote> + <id>772</id> + <symbol>VOD</symbol> + <description>VODAFONE </description> +</quote> +<quote> + <id>773</id> + <symbol>BA</symbol> + <description>British Airways</description> +</quote> + + </section> + + <!--US Stocks--> + + <section> + <name>US Stocks</name> + + +<quote> + <id>99</id> + <symbol>INTC</symbol> + <description>Intel Corp.</description> +</quote> +<quote> + <id>98</id> + <symbol>QCOM</symbol> + <description>QUALCOMM Incorporated</description> +</quote> +<quote> + <id>97</id> + <symbol>CSCO</symbol> + <description>Cisco Systems, Inc.</description> +</quote> +<quote> + <id>96</id> + <symbol>AMGN</symbol> + <description>Amgen Inc.</description> +</quote> +<quote> + <id>94</id> + <symbol>ORCL</symbol> + <description>Oracle Corp.</description> +</quote> +<quote> + <id>92</id> + <symbol>MXIM</symbol> + <description>Maxim Integrated Products, Inc.</description> +</quote> +<quote> + <id>85</id> + <symbol>SBUX</symbol> + <description>Starbucks Corp.</description> +</quote> +<quote> + <id>82</id> + <symbol>CTAS</symbol> + <description>Cintas Corp.</description> +</quote> +<quote> + <id>81</id> + <symbol>BMET</symbol> + <description>Biomet, Inc.</description> +</quote> +<quote> + <id>80</id> + <symbol>PAYX</symbol> + <description>Paychex, Inc</description> +</quote> +<quote> + <id>79</id> + <symbol>XLNX</symbol> + <description>Xilinx, Inc.</description> +</quote> +<quote> + <id>75</id> + <symbol>FISV</symbol> + <description>Fiserv, Inc.</description> +</quote> +<quote> + <id>69</id> + <symbol>COST</symbol> + <description>Costco Wholesale Corp.</description> +</quote> +<quote> + <id>64</id> + <symbol>PCAR</symbol> + <description>PACCAR Inc.</description> +</quote> +<quote> + <id>62</id> + <symbol>ADBE</symbol> + <description>Adobe Systems Incorporated</description> +</quote> +<quote> + <id>61</id> + <symbol>SPLS</symbol> + <description>Staples, Inc.</description> +</quote> +<quote> + <id>33</id> + <symbol>T</symbol> + <description>T Corp.</description> +</quote> +<quote> + <id>31</id> + <symbol>AA</symbol> + <description>Alcoa</description> +</quote> +<quote> + <id>32</id> + <symbol>AXP</symbol> + <description>American Express Co.</description> +</quote> +<quote> + <id>34</id> + <symbol>BA</symbol> + <description>The Boeing Co.</description> +</quote> +<quote> + <id>35</id> + <symbol>CAT</symbol> + <description>Caterpillar Inc.</description> +</quote> +<quote> + <id>36</id> + <symbol>C</symbol> + <description>Citigroup, Inc.</description> +</quote> +<quote> + <id>37</id> + <symbol>KO</symbol> + <description>The Coca-Cola Co.</description> +</quote> +<quote> + <id>40</id> + <symbol>EK</symbol> + <description>Eastman Kodak Co.</description> +</quote> +<quote> + <id>43</id> + <symbol>GM</symbol> + <description>General Motors Corp.</description> +</quote> +<quote> + <id>49</id> + <symbol>JNJ</symbol> + <description> Johnson</description> +</quote> +<quote> + <id>50</id> + <symbol>MCD</symbol> + <description>McDonald's Corp.</description> +</quote> +<quote> + <id>51</id> + <symbol>MRK</symbol> + <description>Merck Company, Inc.</description> +</quote> +<quote> + <id>52</id> + <symbol>MMM</symbol> + <description>Manufacturing Co.</description> +</quote> +<quote> + <id>53</id> + <symbol>JPM</symbol> + <description>J.P. Morgan Company Inc.</description> +</quote> +<quote> + <id>57</id> + <symbol>UTX</symbol> + <description>United Technologies Corp.</description> +</quote> +<quote> + <id>58</id> + <symbol>WMT</symbol> + <description>Wal-Mart Stores, Inc.</description> +</quote> +<quote> + <id>104</id> + <symbol>CDWC</symbol> + <description>CDW Computer Centers, Inc.</description> +</quote> +<quote> + <id>116</id> + <symbol>SGA</symbol> + <description>Saga Communications, Inc.</description> +</quote> +<quote> + <id>118</id> + <symbol>MPP</symbol> + <description>Medical Technology System</description> +</quote> +<quote> + <id>119</id> + <symbol>ACU</symbol> + <description>Acme United Corp.</description> +</quote> +<quote> + <id>128</id> + <symbol>BAL</symbol> + <description>Barclays</description> +</quote> +<quote> + <id>141</id> + <symbol>RBS</symbol> + <description>Royal Bank of Scotland</description> +</quote> +<quote> + <id>250</id> + <symbol>BMO</symbol> + <description>Bank of Montreal</description> +</quote> +<quote> + <id>254</id> + <symbol>TRP</symbol> + <description>TransCanada PipeLines Ltd</description> +</quote> +<quote> + <id>329</id> + <symbol>QQQQ</symbol> + <description>TransCanada PipeLines Ltd</description> +</quote> +<quote> + <id>330</id> + <symbol>DIA</symbol> + <description>TransCanada PipeLines Ltd</description> +</quote> +<quote> + <id>332</id> + <symbol>SMH</symbol> + <description>TransCanada PipeLines Ltd</description> +</quote> +<quote> + <id>122</id> + <symbol>DW</symbol> + <description>Drew Industries, Inc.</description> +</quote> +<quote> + <id>123</id> + <symbol>FPU</symbol> + <description>Florida Public Utilities</description> +</quote> +<quote> + <id>280</id> + <symbol>NOK</symbol> + <description>Nokia</description> +</quote> +<quote> + <id>281</id> + <symbol>UPM</symbol> + <description>UPM-Kymmene OYJ</description> +</quote> +<quote> + <id>282</id> + <symbol>SEO</symbol> + <description>Stora Enso OYJ</description> +</quote> +<quote> + <id>287</id> + <symbol>BEAS</symbol> + <description>BEA System INC.</description> +</quote> +<quote> + <id>288</id> + <symbol>BRCD</symbol> + <description>Brocade Communication System Inc.</description> +</quote> +<quote> + <id>291</id> + <symbol>CEPH</symbol> + <description>Cephalon Inc.</description> +</quote> +<quote> + <id>292</id> + <symbol>CIEN</symbol> + <description>Ciena Corp.</description> +</quote> +<quote> + <id>293</id> + <symbol>CHKP</symbol> + <description>Checkpoint Software</description> +</quote> +<quote> + <id>295</id> + <symbol>DISH</symbol> + <description>Echostar Communications</description> +</quote> +<quote> + <id>100</id> + <symbol>MSFT</symbol> + <description>Microsoft Corp.</description> +</quote> +<quote> + <id>95</id> + <symbol>DELL</symbol> + <description>Dell Computer Corp.</description> +</quote> +<quote> + <id>91</id> + <symbol>EBAY</symbol> + <description>eBay Inc.</description> +</quote> +<quote> + <id>88</id> + <symbol>BBBY</symbol> + <description>Beyond Inc.</description> +</quote> +<quote> + <id>87</id> + <symbol>LLTC</symbol> + <description>Linear Technology Corp.</description> +</quote> +<quote> + <id>84</id> + <symbol>IACI</symbol> + <description>USA Interactive</description> +</quote> +<quote> + <id>76</id> + <symbol>KLAC</symbol> + <description>KLA-Tencor Corp.</description> +</quote> +<quote> + <id>70</id> + <symbol>APOL</symbol> + <description>Apollo Group, Inc.</description> +</quote> +<quote> + <id>68</id> + <symbol>TEVA</symbol> + <description>Teva Pharmaceutical Industries Limited</description> +</quote> +<quote> + <id>65</id> + <symbol>ALTR</symbol> + <description>Altera Corp.</description> +</quote> +<quote> + <id>63</id> + <symbol>SYMC</symbol> + <description>Symantec Corp.</description> +</quote> +<quote> + <id>42</id> + <symbol>GE</symbol> + <description>General Electric Co.</description> +</quote> +<quote> + <id>44</id> + <symbol>HPQ</symbol> + <description>Hewlett-Packard Co.</description> +</quote> +<quote> + <id>46</id> + <symbol>HON</symbol> + <description>Honeywell International Inc.</description> +</quote> +<quote> + <id>47</id> + <symbol>IBM</symbol> + <description>International Business Machines Corp.</description> +</quote> +<quote> + <id>54</id> + <symbol>MO</symbol> + <description>Morris Companies, Inc.</description> +</quote> +<quote> + <id>55</id> + <symbol>PG</symbol> + <description>Gamble Co.</description> +</quote> +<quote> + <id>103</id> + <symbol>FLEX</symbol> + <description>Flextronics International Ltd.</description> +</quote> +<quote> + <id>115</id> + <symbol>OHB</symbol> + <description>Orleans Homebuilders</description> +</quote> +<quote> + <id>251</id> + <symbol>BNS</symbol> + <description>Bank of Nova Scotia</description> +</quote> +<quote> + <id>252</id> + <symbol>BCE</symbol> + <description>BCE, Inc.</description> +</quote> +<quote> + <id>331</id> + <symbol>SPY</symbol> + <description>BCE, Inc.</description> +</quote> +<quote> + <id>286</id> + <symbol>AMCC</symbol> + <description>Applied Micro Circuit Corp.</description> +</quote> +<quote> + <id>294</id> + <symbol>CTXS</symbol> + <description>Citrix Systems</description> +</quote> +<quote> + <id>738</id> + <symbol>MCHP</symbol> + <description>Microchip Technology</description> +</quote> +<quote> + <id>747</id> + <symbol>NTE</symbol> + <description>NAM TAI Electronics</description> +</quote> +<quote> + <id>759</id> + <symbol>TTWO</symbol> + <description>Take-Two Interactive Software</description> +</quote> +<quote> + <id>700</id> + <symbol>ADI </symbol> + <description>Analog Devices </description> +</quote> +<quote> + <id>701</id> + <symbol>ADTN</symbol> + <description>Adtran </description> +</quote> +<quote> + <id>702</id> + <symbol>AIG</symbol> + <description>American International Group</description> +</quote> +<quote> + <id>703</id> + <symbol>APA</symbol> + <description>Apache Corp</description> +</quote> +<quote> + <id>704</id> + <symbol>BAC</symbol> + <description>Bank of America Corp</description> +</quote> +<quote> + <id>705</id> + <symbol>BBY</symbol> + <description>Best Buy Co </description> +</quote> +<quote> + <id>706</id> + <symbol>BIIB</symbol> + <description>Biogen Idec </description> +</quote> +<quote> + <id>707</id> + <symbol>BOBJ</symbol> + <description>Business Objects SA</description> +</quote> +<quote> + <id>708</id> + <symbol>BRCM</symbol> + <description>Broadcom Corp</description> +</quote> +<quote> + <id>709</id> + <symbol>CALM</symbol> + <description>Cal-Maine Foods </description> +</quote> +<quote> + <id>710</id> + <symbol>CCU</symbol> + <description>Clear Channel Communications </description> +</quote> +<quote> + <id>711</id> + <symbol>COF</symbol> + <description>Capital One Financial Corp</description> +</quote> +<quote> + <id>714</id> + <symbol>DLTR</symbol> + <description>Dollar Tree Stores </description> +</quote> +<quote> + <id>716</id> + <symbol>FITB</symbol> + <description>Fifth Third Bancorp</description> +</quote> +<quote> + <id>717</id> + <symbol>FNM</symbol> + <description>Fannie Mae</description> +</quote> +<quote> + <id>718</id> + <symbol>FRE</symbol> + <description>Freddie Mac</description> +</quote> +<quote> + <id>719</id> + <symbol>FRX</symbol> + <description>Forest Laboratories </description> +</quote> +<quote> + <id>720</id> + <symbol>GCI</symbol> + <description>Gannett Co </description> +</quote> +<quote> + <id>721</id> + <symbol>GD</symbol> + <description>General Dynamics Corp</description> +</quote> +<quote> + <id>724</id> + <symbol>GS</symbol> + <description>Goldman Sachs Group </description> +</quote> +<quote> + <id>726</id> + <symbol>HOV</symbol> + <description>Hovnanian Enterprises </description> +</quote> +<quote> + <id>727</id> + <symbol>ICOS</symbol> + <description>ICOS Corp</description> +</quote> +<quote> + <id>728</id> + <symbol>IMCL</symbol> + <description>ImClone Systems</description> +</quote> +<quote> + <id>731</id> + <symbol>KSS</symbol> + <description>Kohl's Corp</description> +</quote> +<quote> + <id>732</id> + <symbol>LEH</symbol> + <description>Lehman Brothers Holdings Inc</description> +</quote> +<quote> + <id>734</id> + <symbol>LLY</symbol> + <description> Co</description> +</quote> +<quote> + <id>737</id> + <symbol>LXK</symbol> + <description>Lexmark International</description> +</quote> +<quote> + <id>743</id> + <symbol>NEM</symbol> + <description>Newmont Mining Corp</description> +</quote> +<quote> + <id>744</id> + <symbol>NFLX</symbol> + <description>NetFlix</description> +</quote> +<quote> + <id>745</id> + <symbol>NOC</symbol> + <description>Northrop Grumman Corp</description> +</quote> +<quote> + <id>748</id> + <symbol>NTES</symbol> + <description>Netease.com</description> +</quote> +<quote> + <id>749</id> + <symbol>NVLS</symbol> + <description>Novellus Systems</description> +</quote> +<quote> + <id>750</id> + <symbol>OVTI</symbol> + <description>Omnivision Technologies</description> +</quote> +<quote> + <id>753</id> + <symbol>RMBS</symbol> + <description>Rambus</description> +</quote> +<quote> + <id>755</id> + <symbol>SINA</symbol> + <description>Sina Corp</description> +</quote> +<quote> + <id>756</id> + <symbol>SNDK</symbol> + <description>Sandisk Corp</description> +</quote> +<quote> + <id>757</id> + <symbol>SNPS</symbol> + <description>Synopsys</description> +</quote> +<quote> + <id>758</id> + <symbol>SOHU</symbol> + <description>Sohu.com</description> +</quote> +<quote> + <id>760</id> + <symbol>UTSI</symbol> + <description>Utstarcom</description> +</quote> +<quote> + <id>762</id> + <symbol>WLP</symbol> + <description>WellPoint Health Networks</description> +</quote> +<quote> + <id>763</id> + <symbol>WY</symbol> + <description>Weyerhaeuser Co</description> +</quote> +<quote> + <id>764</id> + <symbol>XMSR</symbol> + <description>XM Satellite Radio Holdings</description> +</quote> +<quote> + <id>765</id> + <symbol>YHOO</symbol> + <description>Yahoo! </description> +</quote> +<quote> + <id>38</id> + <symbol>DIS</symbol> + <description>The Walt Disney Co.</description> +</quote> +<quote> + <id>39</id> + <symbol>DD</symbol> + <description>E.I. duPont de Nemours Co.</description> +</quote> +<quote> + <id>78</id> + <symbol>ERTS</symbol> + <description>Electronic Arts Inc.</description> +</quote> +<quote> + <id>77</id> + <symbol>GENZ</symbol> + <description>Genzyme General</description> +</quote> +<quote> + <id>766</id> + <symbol>GOOGL</symbol> + <description>Google!</description> +</quote> +<quote> + <id>45</id> + <symbol>HD</symbol> + <description>Home Depot Inc.</description> +</quote> +<quote> + <id>48</id> + <symbol>IP</symbol> + <description>International Paper Co.</description> +</quote> +<quote> + <id>121</id> + <symbol>DLA</symbol> + <description>Delta Apparel Inc.</description> +</quote> +<quote> + <id>86</id> + <symbol>AMAT</symbol> + <description>Applied Materials, Inc.</description> +</quote> +<quote> + <id>41</id> + <symbol>XOM</symbol> + <description>Exxon Mobil Corp.</description> +</quote> +<quote> + <id>102</id> + <symbol>AMZN</symbol> + <description>Amazon.com, Inc.</description> +</quote> +<quote> + <id>729</id> + <symbol>IVGN</symbol> + <description>Invitrogen Corp</description> +</quote> +<quote> + <id>736</id> + <symbol>LRCX</symbol> + <description>Lam Research Corp</description> +</quote> +<quote> + <id>712</id> + <symbol>CTSH</symbol> + <description>Cognizant Technology Solutions Corp</description> +</quote> +<quote> + <id>713</id> + <symbol>DHI</symbol> + <description>DR Horton </description> +</quote> +<quote> + <id>740</id> + <symbol>MNST</symbol> + <description>Monster Worldwide</description> +</quote> + + </section> + + + <!--Indices--> + + <section> + <name>Indices</name> + <!--on the basis of US Indices--> + <section> + <name>on the basis of US Indices</name> + +<quote> + <id>22</id> + <symbol>SandP-500</symbol> + <description>P 500</description> +</quote> +<quote> + <id>23</id> + <symbol>NQ-100</symbol> + <description>CFD statistics for Nasdaq 100</description> +</quote> +<quote> + <id>28</id> + <symbol>Nyssee-comp</symbol> + <description>CFD statistics for NYSE Composite</description> +</quote> +<quote> + <id>21</id> + <symbol>D&J-Ind</symbol> + <description>CFD statistics for Dow Jones Industrial Average</description> +</quote> +<quote> + <id>26</id> + <symbol>NQ-comp</symbol> + <description>CFD statistics for Nasdaq Composite</description> +</quote> +<quote> + <id>27</id> + <symbol>AMMEKS</symbol> + <description>CFD statistics for AMEX</description> +</quote> +<quote> + <id>768</id> + <symbol>VIXX</symbol> + <description>Volatility Index</description> +</quote> +<quote> + <id>769</id> + <symbol>10Y note</symbol> + <description>10Y note yield</description> +</quote> +<quote> + <id>770</id> + <symbol>5Y note</symbol> + <description>5Y note yield</description> +</quote> +<quote> + <id>771</id> + <symbol>ST note</symbol> + <description>Short term note yield</description> +</quote> + + </section> + <!--on the basis of European Indices--> + <section> + <name>on the basis of European Indices</name> + +<quote> + <id>24</id> + <symbol>CAAC-40</symbol> + <description>CFD statistics for CAC 40</description> +</quote> +<quote> + <id>25</id> + <symbol>DAAX</symbol> + <description>CFD statistics for XETRA DAX</description> +</quote> +<quote> + <id>225</id> + <symbol>SWMI</symbol> + <description>CFD statistics for SMI</description> +</quote> +<quote> + <id>345</id> + <symbol>Futsee-100</symbol> + <description>CFD statistics for FTSE</description> +</quote> +<quote> + <id>503</id> + <symbol>DJE50XX</symbol> + <description>CFD statistics for DJ Euro Stoxx50</description> +</quote> + + </section> + <!--on the basis of Asian Indices--> + <section> + <name>on the basis of Asian Indices</name> + + <quote> + <id>500</id> + <symbol>N225Jap</symbol> + <description>CFD statistics for Nikkei 225</description> +</quote> +<quote> + <id>501</id> + <symbol>SC-Korea</symbol> + <description>CFD statistics for KOSPI</description> +</quote> +<quote> + <id>502</id> + <symbol>H-Kong</symbol> + <description>CFD statistics for Hang Seng</description> +</quote> + + </section> + </section> + + <!--FOREX--> + <section> + <name>FOREX</name> + <!--Major--> + <section> + <name>Major</name> + + <quote> + <id>3</id> + <symbol>USD/CHF</symbol> + <description>USD/CHF</description> +</quote> +<quote> + <id>9</id> + <symbol>USD/CAD</symbol> + <description>USD/CAD</description> +</quote> +<quote> + <id>10</id> + <symbol>AUD/USD</symbol> + <description>AUD/USD</description> +</quote> +<quote> + <id>11</id> + <symbol>NZD/USD</symbol> + <description>NZD/USD</description> +</quote> +<quote> + <id>1</id> + <symbol>EUR/USD</symbol> + <description>EUR/USD</description> +</quote> +<quote> + <id>2</id> + <symbol>GBP/USD</symbol> + <description>GBP/USD</description> +</quote> + + </section> + <!--Other Currencies--> + <section> + <name>Other Currencies</name> + + +<quote> + <id>12</id> + <symbol>USD/NOK</symbol> + <description>USD/NOK</description> +</quote> +<quote> + <id>13</id> + <symbol>USD/DKK</symbol> + <description>USD/DKK</description> +</quote> +<quote> + <id>14</id> + <symbol>USD/SEK</symbol> + <description>USD/SEK</description> +</quote> +<quote> + <id>15</id> + <symbol>USD/SAR</symbol> + <description>USD/SAR</description> +</quote> +<quote> + <id>507</id> + <symbol>USD/EUR</symbol> + <description>USD/EUR</description> +</quote> +<quote> + <id>508</id> + <symbol>USD/GBP</symbol> + <description>USD/GBP</description> +</quote> +<quote> + <id>512</id> + <symbol>JPY/USD</symbol> + <description>JPY/USD</description> +</quote> +<quote> + <id>513</id> + <symbol>JPY/EUR</symbol> + <description>JPY/EUR</description> +</quote> +<quote> + <id>516</id> + <symbol>GBP/EUR</symbol> + <description>GBP/EUR</description> +</quote> +<quote> + <id>519</id> + <symbol>CHF/USD</symbol> + <description>CHF/USD</description> +</quote> +<quote> + <id>521</id> + <symbol>CHF/JPY</symbol> + <description>CHF/JPY</description> +</quote> +<quote> + <id>514</id> + <symbol>JPY/GBP</symbol> + <description>JPY/GBP</description> +</quote> +<quote> + <id>515</id> + <symbol>JPY/CHF</symbol> + <description>JPY/CHF</description> +</quote> +<quote> + <id>520</id> + <symbol>CHF/EUR</symbol> + <description>CHF/EUR</description> +</quote> +<quote> + <id>522</id> + <symbol>CHF/GBP</symbol> + <description>CHF/GBP</description> +</quote> +<quote> + <id>74</id> + <symbol>USD/ZAR</symbol> + <description>USD/ZAR</description> +</quote> +<quote> + <id>30</id> + <symbol>USD/SGD</symbol> + <description>USD/SGD</description> +</quote> +<quote> + <id>29</id> + <symbol>EUR/SEK</symbol> + <description>EUR/SEK</description> +</quote> + </section> + <!--Crosses--> + <section> + <name>Crosses</name> + + +<quote> + <id>509</id> + <symbol>EUR/JPY</symbol> + <description>EUR/JPY</description> +</quote> +<quote> + <id>510</id> + <symbol>EUR/GBP</symbol> + <description>EUR/GBP</description> +</quote> +<quote> + <id>511</id> + <symbol>EUR/CHF</symbol> + <description>EUR/CHF</description> +</quote> +<quote> + <id>517</id> + <symbol>GBP/JPY</symbol> + <description>GBP/JPY</description> +</quote> +<quote> + <id>518</id> + <symbol>GBP/CHF</symbol> + <description>GBP/CHF</description> +</quote> +<quote> + <id>60</id> + <symbol>AUD/JPY</symbol> + <description>AUD/JPY</description> +</quote> +<quote> + <id>767</id> + <symbol>CAD/JPY</symbol> + <description>CAD/JPY</description> +</quote> + </section> + <!--Other Arab Currencies--> + <section> + <name>Other Arab Currencies</name> + + +<quote> + <id>4</id> + <symbol>USD/JPY</symbol> + <description>USD/JPY</description> +</quote> +<quote> + <id>5</id> + <symbol>USD/EGP</symbol> + <description>USD/EGP</description> +</quote> +<quote> + <id>6</id> + <symbol>USD/JOD</symbol> + <description>USD/JOD</description> +</quote> +<quote> + <id>7</id> + <symbol>USD/QAR</symbol> + <description>USD/QAR</description> +</quote> +<quote> + <id>16</id> + <symbol>USD/TND</symbol> + <description>USD/TND</description> +</quote> +<quote> + <id>17</id> + <symbol>EUR/EGP</symbol> + <description>EUR/EGP</description> +</quote> +<quote> + <id>18</id> + <symbol>EUR/JOD</symbol> + <description>EUR/JOD</description> +</quote> +<quote> + <id>19</id> + <symbol>EUR/QAR</symbol> + <description>EUR/QAR</description> +</quote> +<quote> + <id>59</id> + <symbol>EUR/TND</symbol> + <description>EUR/TND</description> +</quote> +<quote> + <id>523</id> + <symbol>EGP/USD</symbol> + <description>EGP/USD</description> +</quote> +<quote> + <id>524</id> + <symbol>EGP/EUR</symbol> + <description>EGP/EUR</description> +</quote> +<quote> + <id>527</id> + <symbol>EGP/CHF</symbol> + <description>EGP/CHF</description> +</quote> +<quote> + <id>528</id> + <symbol>JOD/USD</symbol> + <description>JOD/USD</description> +</quote> +<quote> + <id>529</id> + <symbol>JOD/EUR</symbol> + <description>JOD/EUR</description> +</quote> +<quote> + <id>530</id> + <symbol>JOD/JPY</symbol> + <description>JOD/JPY</description> +</quote> +<quote> + <id>531</id> + <symbol>JOD/GBP</symbol> + <description>JOD/GBP</description> +</quote> +<quote> + <id>533</id> + <symbol>JOD/CHF</symbol> + <description>JOD/CHF</description> +</quote> +<quote> + <id>534</id> + <symbol>QAR/EUR</symbol> + <description>QAR/EUR</description> +</quote> +<quote> + <id>535</id> + <symbol>QAR/USD</symbol> + <description>QAR/USD</description> +</quote> +<quote> + <id>536</id> + <symbol>QAR/JPY</symbol> + <description>QAR/JPY</description> +</quote> +<quote> + <id>537</id> + <symbol>QAR/GBP</symbol> + <description>QAR/GBP</description> +</quote> +<quote> + <id>538</id> + <symbol>QAR/CHF</symbol> + <description>QAR/CHF</description> +</quote> +<quote> + <id>539</id> + <symbol>SAR/USD</symbol> + <description>SAR/USD</description> +</quote> +<quote> + <id>540</id> + <symbol>SAR/EUR</symbol> + <description>SAR/EUR</description> +</quote> +<quote> + <id>541</id> + <symbol>SAR/JPY</symbol> + <description>SAR/JPY</description> +</quote> +<quote> + <id>542</id> + <symbol>SAR/GBP</symbol> + <description>SAR/GBP</description> +</quote> +<quote> + <id>543</id> + <symbol>GBP/SAR</symbol> + <description>GBP/SAR</description> +</quote> +<quote> + <id>544</id> + <symbol>SAR/CHF</symbol> + <description>SAR/CHF</description> +</quote> +<quote> + <id>545</id> + <symbol>TND/USD</symbol> + <description>TND/USD</description> +</quote> +<quote> + <id>546</id> + <symbol>TND/EUR</symbol> + <description>TND/EUR</description> +</quote> +<quote> + <id>547</id> + <symbol>TND/JPY</symbol> + <description>TND/JPY</description> +</quote> +<quote> + <id>548</id> + <symbol>TND/GBP</symbol> + <description>TND/GBP</description> +</quote> +<quote> + <id>549</id> + <symbol>TND/CHF</symbol> + <description>TND/CHF</description> +</quote> +<quote> + <id>20</id> + <symbol>EUR/SAR</symbol> + <description>EUR/SAR</description> +</quote> +<quote> + <id>525</id> + <symbol>EGP/JPY</symbol> + <description>EGP/JPY</description> +</quote> +<quote> + <id>526</id> + <symbol>EGP/GBP</symbol> + <description>EGP/GBP</description> +</quote> +<quote> + <id>532</id> + <symbol>GBP/JOD</symbol> + <description>GBP/JOD</description> +</quote> + + </section> + </section> + + <!--Asian Stocks--> + <section> + <name>Asian Stocks</name> + + +<quote> + <id>307</id> + <symbol>TSM</symbol> + <description>Taiwan Semiconductor Mfg</description> +</quote> +<quote> + <id>308</id> + <symbol>SNE</symbol> + <description>Sony Corp.</description> +</quote> +<quote> + <id>310</id> + <symbol>MITSY</symbol> + <description>Mitsui Co., Ltd.</description> +</quote> +<quote> + <id>314</id> + <symbol>NSANY</symbol> + <description>Nissan Motor Co., Ltd.</description> +</quote> +<quote> + <id>317</id> + <symbol>CAJ</symbol> + <description>Canon, Inc.</description> +</quote> +<quote> + <id>323</id> + <symbol>CHL</symbol> + <description>China Mobile Limited</description> +</quote> +<quote> + <id>324</id> + <symbol>SNP</symbol> + <description>Chemical Corp.</description> +</quote> +<quote> + <id>313</id> + <symbol>HMC</symbol> + <description>Honda Motor Co., Ltd.</description> +</quote> +<quote> + <id>315</id> + <symbol>MC</symbol> + <description>Matsushita Electric Ind.</description> +</quote> +<quote> + <id>311</id> + <symbol>NTT</symbol> + <description> Telephone</description> +</quote> +<quote> + <id>312</id> + <symbol>HIT</symbol> + <description>Hitachi, Ltd.</description> +</quote> + + </section> + + <!--Commodities--> + <section> + <name>Commodities</name> + + +<quote> + <id>333</id> + <symbol>XAU/USD</symbol> + <description>XAU/USD</description> +</quote> +<quote> + <id>334</id> + <symbol>XAG/USD</symbol> + <description>XAG/USD</description> +</quote> +<quote> + <id>335</id> + <symbol>Platinum</symbol> + <description>Platinum</description> +</quote> +<quote> + <id>336</id> + <symbol>Palladium</symbol> + <description>Palladium</description> +</quote> +<quote> + <id>504</id> + <symbol>Light</symbol> + <description>Light</description> +</quote> +<quote> + <id>505</id> + <symbol>Brent</symbol> + <description>Brent</description> +</quote> +<quote> + <id>506</id> + <symbol>Copper</symbol> + <description>Copper</description> +</quote> + + </section> +</Provider> diff --git a/protocols/Quotes/Utility/Google.py b/protocols/Quotes/Utility/Google.py new file mode 100644 index 0000000000..35653a77f6 --- /dev/null +++ b/protocols/Quotes/Utility/Google.py @@ -0,0 +1,52 @@ +from html.parser import HTMLParser +import sys +from xml.etree.ElementTree import Element, ElementTree, SubElement + +class MyHTMLParser(HTMLParser): + def __init__(self,in_fn,out_fn): + HTMLParser.__init__(self) + f_in = open(in_fn,'r') + self.quote = 0 + self.start = 0 + self.parse_option = 0 + self.elQuote = Element("fake") + elProvider = Element("Provider") + SubElement(elProvider,'name').text = 'Google' + SubElement(elProvider,'ref').text = 'http://www.google.com' + SubElement(elProvider,'url').text = 'http://www.google.com/finance/converter?a=1&' + self.root = SubElement(elProvider,'section') + SubElement(self.root,'name').text = 'Currencies' + self.feed(f_in.read()) + f_in.close() + ElementTree(elProvider).write(out_fn) + + def handle_starttag(self, tag, attrs): + self.start = 1 + if tag == 'select': + if self.parse_option == 0: + for k in attrs: + if k[0] == 'name' and k[1] == 'from': + self.parse_option = 1 + break + else: + self.parse_option == 0 + elif self.parse_option == 1 and tag == 'option': + for k in attrs: + if k[0] == 'value': + self.elQuote = SubElement(self.root,'quote') + SubElement(self.elQuote,'id').text = k[1] + SubElement(self.elQuote,'symbol').text = k[1] + break + + def handle_endtag(self, tag): + self.start = 0 + if tag == 'select': + self.parse_option == 0 + + def handle_data(self, data): + if self.start == 1 and self.parse_option == 1: + SubElement(self.elQuote,'description').text = data + +parser = MyHTMLParser(sys.argv[1],sys.argv[2]) +parser.close() + diff --git a/protocols/Quotes/Utility/GoogleFinance.xml b/protocols/Quotes/Utility/GoogleFinance.xml new file mode 100644 index 0000000000..031afbcdd5 --- /dev/null +++ b/protocols/Quotes/Utility/GoogleFinance.xml @@ -0,0 +1,7 @@ +<?xml version="1.0" encoding="utf-8"?> + +<Provider> + <name>Google Finance</name> + <ref>http://www.google.com</ref> + <url>http://www.google.com/finance</url> +</Provider> \ No newline at end of file diff --git a/protocols/Quotes/Utility/Quotes_Readme.txt b/protocols/Quotes/Utility/Quotes_Readme.txt new file mode 100644 index 0000000000..7c0bf2ca10 --- /dev/null +++ b/protocols/Quotes/Utility/Quotes_Readme.txt @@ -0,0 +1,112 @@ +Quotes version 0.0.24.0 plugin for Miranda + +This plugin displays periodically updated economic quotes, currency exchanges and different economic and financial indexes in Miranda contact list. + +Author: Dioksin. +You can always contact me via email dioksin@ua.fm + +How to install: +unpack zip archive; +copy quotes.dll and Quotes subdirectory from Plugins folder to miranda plugins floder. +copy proto_Quotes.dll from Icons folder to miranda icons folder + +[2011-10-24] Changelog Release 0.0.24.0 +1. Tendency calculation for Yahoo was fixed + +[2011-10-18] Changelog Release 0.0.23.0 +1. Previous Close and Change values were added to YAHOO +2. If there is no xml file corresponding options page is not show in properties window + +[2011-10-14] Changelog Release 0.0.22.0 +1. Supports YAHOO +2. Options location was moved from "Plugins\Quotes" to "Network\Quotes" + +[2011-08-19] Changelog Release 0.0.21.0 +1. Tendency format specification +2. Main icon was changed +3. Currency converter icon was changed +4. Popup plugin support +5. Per-contact options +6. Menu redesign +7. Import/export from/to xml file + +[2011-08-14] Changelog Release 0.0.20.0 +1. Updation of code to use new format of Google finance HTML page + +[2010-09-26] Changelog Release 0.0.19.0 +1. Currency converter shown values in the sientific format +2. Currency converter didn't convert big values +3. Currency converter output is formatted with user-defined locale preferences +4. Swap button in the currency converter has an icon +5. Big icon is set for the currency converter to correct show in ALT+TAB dialog + +[2010-09-19] Changelog Release 0.0.18.0 +1. Thousand separator error for non USA locale in Google Finance + +Changelog Release 0.0.17.0 +1. The percent change with respecto to yesterday close variable was added to the Google Finance +2. The Vietnamese Dong was added to the Currency Converter + +Changelog Release 0.0.16.0 +1. It was impossible to get quotes from google finance on non-USA locale + +Changelog Release 0.0.15.0 +1. Crash if invalid display name format was used + +Changelog Release 0.0.14.0 +1. References to Microsoft's XML parser were removed. + +Changelog Release 0.0.12.0 +1. The Swap button had been added to the Currency Converter + +Changelog Release 0.0.11.0 +1. Google finance is supported +2. Occupied status was made optionally (To use it's necessary to set the 'ExtendedStatus' option in the Miranda's database). + +Changelog Release 0.0.9.981 +1. Currency converter +2. Refresh all Quotes\Rates +3. Refresh particular Quote\Rate +2. Minor fixings to better support national language pack + +Changelog Release 0.0.0.8 +1. Minor changing in logic of status +2. Minor resource modification to better support national language pack + +Changelog Release 0.0.0.7 +1. Status message may be set on per contact basis (second line in contact list) +2. Two new modes were added. Occupied - it's set if error occurred during rate/quote updation. DND - it's set if updation is in progress. +3. Open Log File menu item was added and Quotes related menu items are grouped in Quotes popup menu. +4. Several new variables were added: previous rate, fetch date, fetch time. +5. New empty icon was added. This icon is used when rate/quote was not changed. +6. Quotes\rate info page was changed to show both current and previous rates. +7. Database ForceToAddArrowToNick setting was added. This value governs an up\down arrow appearance in contact name. If it's equal 0 (default value) - arrows will be added only if extraicons were set . It it' equal 1 - arrows will be shown always and if it's equal 2 - arrows will be never shown. + +Changelog Release 0.0.0.6 +1. Change to log and to history only if rate (quote) value changed option has been added +2. Several minor bugs were fixed + +Changelog Release 0.0.0.5 +1. Extraicons supporting +2. Ability to change name in contact list with variables +3. Log to file +4. Log to Miranda's history +5. Proxy server supporting +6. Protocol icons were changes and removed to separate dll + +Changelog Release 0.0.0.4 +1. It is possible to get currency exchange rates from Google site +2. Unicode supporting was improved +3. User info page was modified +4. Option pages were moved under Plugin section + +Changelog Release 0.0.0.3 +1. Fix bug when decimal separator was not dot +2. User info page was added + +Changelog Release 0.0.0.2 +1. The size of plugin was reduced +2. The plugin was statically link with CRT library to resolve some dependencies to system modules +3. The updater plugin is supported now. + + diff --git a/protocols/Quotes/Utility/Yahoo.xml b/protocols/Quotes/Utility/Yahoo.xml new file mode 100644 index 0000000000..1c2a156d89 --- /dev/null +++ b/protocols/Quotes/Utility/Yahoo.xml @@ -0,0 +1,7 @@ +<?xml version="1.0" encoding="utf-8"?> + +<Provider> + <name>Yahoo</name> + <ref>http://finance.yahoo.com/</ref> + <url>http://finance.yahoo.com/d/</url> +</Provider> \ No newline at end of file diff --git a/protocols/Quotes/Utility/google.xml b/protocols/Quotes/Utility/google.xml new file mode 100644 index 0000000000..9363addced --- /dev/null +++ b/protocols/Quotes/Utility/google.xml @@ -0,0 +1,91 @@ +<?xml version="1.0" encoding="utf-8"?> + +<Provider> + <name>Google</name> + <ref>http://www.google.com</ref> + <url>http://www.google.com/finance/converter</url> + +<section> + <name>Currencies</name> + <quote> + <id>AED</id> + <symbol>AED</symbol> + <description>United Arab Emirates Dirham (AED)</description> + </quote> + <quote> + <id>ANG</id><symbol>ANG</symbol><description>Netherlands Antillean Gulden (ANG)</description> + </quote> + <quote> + <id>ARS</id><symbol>ARS</symbol><description>Argentine Peso (ARS)</description> + </quote> + <quote> + <id>AUD</id><symbol>AUD</symbol><description>Australian Dollar (AUD)</description> + </quote> + <quote> + <id>BGN</id><symbol>BGN</symbol><description>Bulgarian Lev (BGN)</description> + </quote> + <quote> + <id>BHD</id><symbol>BHD</symbol><description>Bahraini Dinar (BHD)</description> + </quote> + <quote> + <id>BND</id><symbol>BND</symbol><description>Brunei Dollar (BND)</description> + </quote> + <quote> + <id>BOB</id><symbol>BOB</symbol><description>Bolivian Boliviano (BOB)</description> + </quote> + <quote> + <id>BRL</id><symbol>BRL</symbol><description>Brazilian Real (BRL)</description> + </quote> + <quote> + <id>BWP</id><symbol>BWP</symbol><description>Botswana Pula (BWP)</description> + </quote> + <quote> + <id>CAD</id><symbol>CAD</symbol><description>Canadian Dollar (CAD)</description> + </quote> + <quote> + <id>CHF</id><symbol>CHF</symbol><description>Swiss Franc (CHF)</description> + </quote> + <quote> + <id>CLP</id><symbol>CLP</symbol><description>Chilean Peso (CLP)</description> + </quote> + <quote> + <id>CNY</id><symbol>CNY</symbol><description>Chinese Yuan (renminbi) (CNY)</description> + </quote> + <quote> + <id>COP</id><symbol>COP</symbol><description>Colombian Peso (COP)</description> + </quote> + <quote> + <id>CSD</id><symbol>CSD</symbol><description>Serbian Dinar (CSD)</description> + </quote> + <quote> + <id>CZK</id><symbol>CZK</symbol><description>Czech Koruna (CZK)</description> + </quote> + <quote> + <id>DKK</id><symbol>DKK</symbol><description>Danish Krone (DKK)</description> + </quote> + <quote> + <id>EEK</id><symbol>EEK</symbol><description>Estonian Kroon (EEK)</description> + </quote> + <quote> + <id>EGP</id><symbol>EGP</symbol><description>Egyptian Pound (EGP)</description> + </quote> + <quote> + <id>EUR</id><symbol>EUR</symbol><description>Euro (EUR)</description> + </quote> + <quote> + <id>FJD</id><symbol>FJD</symbol><description>Fijian Dollar (FJD)</description> + </quote> + <quote><id>GBP</id><symbol>GBP</symbol><description>British Pound (GBP)</description></quote><quote><id>HKD</id><symbol>HKD</symbol><description>Hong Kong Dollar (HKD)</description></quote><quote><id>HNL</id><symbol>HNL</symbol><description>Honduran Lempira (HNL)</description></quote><quote><id>HRK</id><symbol>HRK</symbol><description>Croatian Kuna (HRK)</description></quote><quote><id>HUF</id><symbol>HUF</symbol><description>Hungarian Forint (HUF)</description></quote><quote><id>IDR</id><symbol>IDR</symbol><description>Indonesian Rupiah (IDR)</description></quote><quote><id>ILS</id><symbol>ILS</symbol><description>New Israeli Sheqel (ILS)</description></quote><quote><id>INR</id><symbol>INR</symbol><description>Indian Rupee (INR)</description></quote><quote><id>ISK</id><symbol>ISK</symbol><description>Icelandic Króna (ISK)</description></quote><quote><id>JPY</id><symbol>JPY</symbol><description>Japanese Yen (JPY)</description></quote><quote><id>KRW</id><symbol>KRW</symbol><description>South Korean Won (KRW)</description></quote><quote><id>KWD</id><symbol>KWD</symbol><description>Kuwaiti Dinar (KWD)</description></quote><quote><id>KZT</id><symbol>KZT</symbol><description>Kazakhstani Tenge (KZT)</description></quote><quote><id>LKR</id><symbol>LKR</symbol><description>Sri Lankan Rupee (LKR)</description></quote><quote><id>LTL</id><symbol>LTL</symbol><description>Lithuanian Litas (LTL)</description></quote><quote><id>MAD</id><symbol>MAD</symbol><description>Moroccan Dirham (MAD)</description></quote><quote><id>MUR</id><symbol>MUR</symbol><description>Mauritian Rupee (MUR)</description></quote><quote><id>MXN</id><symbol>MXN</symbol><description>Mexican Peso (MXN)</description></quote><quote><id>MYR</id><symbol>MYR</symbol><description>Malaysian Ringgit (MYR)</description></quote><quote><id>NOK</id><symbol>NOK</symbol><description>Norwegian Krone (NOK)</description></quote><quote><id>NPR</id><symbol>NPR</symbol><description>Nepalese Rupee (NPR)</description></quote><quote><id>NZD</id><symbol>NZD</symbol><description>New Zealand Dollar (NZD)</description></quote><quote><id>OMR</id><symbol>OMR</symbol><description>Omani Rial (OMR)</description></quote><quote><id>PEN</id><symbol>PEN</symbol><description>Peruvian Nuevo Sol (PEN)</description></quote><quote><id>PHP</id><symbol>PHP</symbol><description>Philippine Peso (PHP)</description></quote><quote><id>PKR</id><symbol>PKR</symbol><description>Pakistani Rupee (PKR)</description></quote><quote><id>PLN</id><symbol>PLN</symbol><description>Polish Złoty (PLN)</description></quote><quote><id>QAR</id><symbol>QAR</symbol><description>Qatari Riyal (QAR)</description></quote><quote><id>RON</id><symbol>RON</symbol><description>New Romanian Leu (RON)</description></quote> + + <quote> + <id>RUB</id><symbol>RUB</symbol><description>Russian Ruble (RUB)</description> + </quote> + <quote> + <id>SAR</id><symbol>SAR</symbol><description>Saudi Riyal (SAR)</description> + </quote> + <quote><id>SEK</id><symbol>SEK</symbol><description>Swedish Krona (SEK)</description></quote><quote><id>SGD</id><symbol>SGD</symbol><description>Singapore Dollar (SGD)</description></quote><quote><id>SIT</id><symbol>SIT</symbol><description>Slovenian Tolar (SIT)</description></quote><quote><id>SKK</id><symbol>SKK</symbol><description>Slovak Koruna (SKK)</description></quote><quote><id>THB</id><symbol>THB</symbol><description>Thai Baht (THB)</description></quote><quote><id>TRY</id><symbol>TRY</symbol><description>New Turkish Lira (TRY)</description></quote><quote><id>TTD</id><symbol>TTD</symbol><description>Trinidad and Tobago Dollar (TTD)</description></quote><quote><id>TWD</id><symbol>TWD</symbol><description>New Taiwan Dollar (TWD)</description></quote><quote><id>UAH</id><symbol>UAH</symbol><description>Ukrainian Hryvnia (UAH)</description></quote><quote><id>USD</id><symbol>USD</symbol><description>United States Dollar (USD)</description></quote><quote><id>VEB</id><symbol>VEB</symbol><description>Venezuelan Bolívar (VEB)</description></quote><quote><id>ZAR</id><symbol>ZAR</symbol><description>South African Rand (ZAR)</description></quote> + <quote> + <id>VND</id><symbol>VND</symbol><description>Vietnamese Dong (VND)</description> + </quote> +</section> +</Provider> \ No newline at end of file diff --git a/protocols/Quotes/Version.rc b/protocols/Quotes/Version.rc new file mode 100644 index 0000000000..a5fcb30231 --- /dev/null +++ b/protocols/Quotes/Version.rc @@ -0,0 +1,41 @@ +// Microsoft Visual C++ generated resource script. +// +#include "afxres.h" +#include "version.h" + +#ifdef _WIN32 +LANGUAGE LANG_NEUTRAL, SUBLANG_NEUTRAL +#endif //_WIN32 + +VS_VERSION_INFO VERSIONINFO + FILEVERSION __FILEVERSION_STRING + PRODUCTVERSION __FILEVERSION_STRING + FILEFLAGSMASK 0x17L +#ifdef _DEBUG + FILEFLAGS 0x1L +#else + FILEFLAGS 0x0L +#endif + FILEOS 0x4L + FILETYPE 0x0L + FILESUBTYPE 0x0L +BEGIN + BLOCK "StringFileInfo" + BEGIN + BLOCK "000004b0" + BEGIN + VALUE "FileDescription", __DESCRIPTION + VALUE "FileVersion", __FILEVERSION_DOTS + VALUE "InternalName", __PLUGIN_NAME + VALUE "LegalCopyright", __COPYRIGHT + VALUE "OriginalFilename", __FILENAME + VALUE "ProductName", __PLUGIN_NAME + VALUE "ProductVersion", __FILEVERSION_DOTS + VALUE "SpecialBuild", SPECIAL_BUILD_STRING + END + END + BLOCK "VarFileInfo" + BEGIN + VALUE "Translation", 0x0, 1200 + END +END diff --git a/protocols/Quotes/WinCtrlHelper.cpp b/protocols/Quotes/WinCtrlHelper.cpp new file mode 100644 index 0000000000..dba445958e --- /dev/null +++ b/protocols/Quotes/WinCtrlHelper.cpp @@ -0,0 +1,49 @@ +#include "stdafx.h" +#include "QuotesProviderVisitorFormatSpecificator.h" +#include "IQuotesProvider.h" +#include "resource.h" +#include "ModuleInfo.h" + +namespace +{ + INT_PTR CALLBACK VariableListDlgProc(HWND hWnd,UINT msg,WPARAM wp,LPARAM lp) + { + switch(msg) + { + case WM_INITDIALOG: + { + TranslateDialogDefault(hWnd); + const IQuotesProvider* pProvider = reinterpret_cast<const IQuotesProvider*>(lp); + CQuotesProviderVisitorFormatSpecificator visitor; + pProvider->Accept(visitor); + + tostringstream o; + const CQuotesProviderVisitorFormatSpecificator::TFormatSpecificators& raSpec = visitor.GetSpecificators(); + std::for_each(raSpec.begin(),raSpec.end(), + [&o](const CQuotesProviderVisitorFormatSpecificator::CFormatSpecificator& spec) + { + o << spec.m_sSymbol << _T('\t') << spec.m_sDesc << _T("\r\n"); + }); + ::SetDlgItemText(hWnd,IDC_EDIT_VARIABLE,o.str().c_str()); + } + break; + case WM_COMMAND: + if(BN_CLICKED == HIWORD(wp) && (IDOK == LOWORD(wp) || IDCANCEL == LOWORD(wp))) + { + ::EndDialog(hWnd,IDOK); + } + break; + } + + return FALSE; + } +} + +void show_variable_list(HWND hwndParent,const IQuotesProvider* pProvider) +{ + ::DialogBoxParam(CModuleInfo::GetModuleHandle(), + MAKEINTRESOURCE(IDD_DIALOG_VARIABLE_LIST), + hwndParent, + VariableListDlgProc, + reinterpret_cast<LPARAM>(pProvider)); +} diff --git a/protocols/Quotes/WinCtrlHelper.h b/protocols/Quotes/WinCtrlHelper.h new file mode 100644 index 0000000000..d7f8957a86 --- /dev/null +++ b/protocols/Quotes/WinCtrlHelper.h @@ -0,0 +1,37 @@ +#ifndef __a05d6852_4497_4f28_85e1_48a15a170738_WinCtrlHelper_h__ +#define __a05d6852_4497_4f28_85e1_48a15a170738_WinCtrlHelper_h__ + +class IQuotesProvider; + +inline tstring get_window_text(HWND hWnd) +{ + int cBytes = ::GetWindowTextLength(hWnd); + + std::vector<TCHAR> aBuf(cBytes+1); + LPTSTR pBuffer = &*(aBuf.begin()); + ::GetWindowText(hWnd,pBuffer,cBytes+1); + + return tstring(pBuffer); +} + +inline void prepare_edit_ctrl_for_error(HWND hwndEdit) +{ + ::SetFocus(hwndEdit); + ::SendMessage(hwndEdit, EM_SETSEL, 0, -1); + ::SendMessage(hwndEdit, EM_SCROLLCARET, 0, 0); +} + +void show_variable_list(HWND hwndParent,const IQuotesProvider* pProvider); + +inline int Quotes_MessageBox(HWND hWnd,LPCTSTR pszText,UINT nType = MB_OK) +{ + return ::MessageBox(hWnd,pszText,quotes_a2t(MIRANDANAME).c_str(),nType); +} + +inline void spin_set_range(HWND hwndSpin,short nLower,short nUpper) +{ + ::SendMessage(hwndSpin,UDM_SETRANGE,0,MAKELPARAM(nUpper,nLower)); +} + + +#endif //__a05d6852_4497_4f28_85e1_48a15a170738_WinCtrlHelper_h__ diff --git a/protocols/Quotes/WorkingThread.cpp b/protocols/Quotes/WorkingThread.cpp new file mode 100644 index 0000000000..bc4d80b734 --- /dev/null +++ b/protocols/Quotes/WorkingThread.cpp @@ -0,0 +1,15 @@ +#include "StdAfx.h" +#include "WorkingThread.h" + +#include "IQuotesProvider.h" + +void WorkingThread(void* pParam) +{ + IQuotesProvider* pProvider = reinterpret_cast<IQuotesProvider*>(pParam); + assert(pProvider); + + if(pProvider) + { + pProvider->Run(); + } +} diff --git a/protocols/Quotes/WorkingThread.h b/protocols/Quotes/WorkingThread.h new file mode 100644 index 0000000000..a77734bb85 --- /dev/null +++ b/protocols/Quotes/WorkingThread.h @@ -0,0 +1,6 @@ +#ifndef __cd52f1a3_63b2_44f0_a0a9_48c203958fa4_WorkingThread_h__ +#define __cd52f1a3_63b2_44f0_a0a9_48c203958fa4_WorkingThread_h__ + +void WorkingThread(void* pParam); + +#endif //__cd52f1a3_63b2_44f0_a0a9_48c203958fa4_WorkingThread_h__ diff --git a/protocols/Quotes/XMLEngineMI.cpp b/protocols/Quotes/XMLEngineMI.cpp new file mode 100644 index 0000000000..7e2adfb7d9 --- /dev/null +++ b/protocols/Quotes/XMLEngineMI.cpp @@ -0,0 +1,230 @@ +#include "StdAfx.h" +#include "XMLEngineMI.h" + +XML_API xi; + +namespace +{ + class CXMLNodeMI : public IXMLNode, + private boost::noncopyable + { + public: + typedef boost::shared_ptr<IXMLNode> TXMLNodePtr; + + public: + explicit CXMLNodeMI(HXML hXMl,bool bDestroy = false) : m_hXML(hXMl),m_bDestroy(bDestroy) + { + assert(m_hXML); + } + + virtual ~CXMLNodeMI() + { + if(m_bDestroy) + { + xi.destroyNode(m_hXML); + } + } + + virtual size_t GetChildCount()const + { + return xi.getChildCount(m_hXML); + } + + virtual TXMLNodePtr GetChildNode(size_t nIndex)const + { + HXML h = xi.getChild(m_hXML, (int)nIndex); + if(h) + { + return TXMLNodePtr(new CXMLNodeMI(h)); + } + else + { + return TXMLNodePtr(); + } + } + + virtual tstring GetText()const + { + tstring sResult; + LPCTSTR psz = xi.getText(m_hXML); + if(psz) + { + sResult = psz; + } + + return sResult; + } + + virtual tstring GetName()const + { + tstring sResult; + LPCTSTR psz = xi.getName(m_hXML); + if(psz) + { + sResult = psz; + } + + return sResult; + } + + virtual bool AddChild(const TXMLNodePtr& pNode) + { + CXMLNodeMI* pXML = dynamic_cast<CXMLNodeMI*>(pNode.get()); + if(pXML) + { + xi.addChild2(pXML->m_hXML,m_hXML); + pXML->m_bDestroy = false; + return true; + } + else + { + return false; + } + } + + virtual bool AddAttribute(const tstring& rsName,const tstring& rsValue) + { + xi.addAttr(m_hXML,rsName.c_str(),rsValue.c_str()); + return true; + } + + virtual tstring GetAttributeValue(const tstring& rsAttrName) + { + LPCTSTR pszValue = xi.getAttrValue(m_hXML,rsAttrName.c_str()); + return ((NULL != pszValue) ? tstring(pszValue) : tstring()); + } + + virtual void Write(tostream& o)const + { +// struct safe_string +// { +// safe_string(LPTSTR p):m_p(p){} +// ~safe_string(){xi.freeMem(m_p);} +// +// LPTSTR m_p; +// }; +// +// struct mir_safe_string +// { +// mir_safe_string(LPSTR p) : m_p(p){} +// ~mir_safe_string(){mir_free(m_p);} +// +// LPSTR m_p; +// }; + + + safe_string<TCHAR> ss(xi.toString(m_hXML,NULL)); + if(ss.m_p) + { + mir_safe_string<char> mss(mir_utf8encodeT(ss.m_p)); + if(mss.m_p) + { + o << mss.m_p; + } + } + } + + private: + HXML m_hXML; + bool m_bDestroy; + }; +} + +CXMLEngineMI::CXMLEngineMI() +{ +} + +CXMLEngineMI::~CXMLEngineMI() +{ +} + +IXMLNode::TXMLNodePtr CXMLEngineMI::LoadFile(const tstring& rsFileName)const +{ +// struct mir_safe_string +// { +// mir_safe_string(LPTSTR p) : m_p(p){} +// ~mir_safe_string(){mir_free(m_p);} +// +// LPTSTR m_p; +// }; + + + IXMLNode::TXMLNodePtr pResult; + FILE* stream; + if(0 == ::_tfopen_s(&stream,rsFileName.c_str(),_T("r"))) + { + struct _stat st; + if (-1 != ::_fstat(::_fileno(stream),&st)) + { + std::vector<char> aBuffer(st.st_size+1); + char* pBuffer = &*(aBuffer.begin()); + size_t cBytes = ::fread(pBuffer,sizeof(char),st.st_size,stream); + if(cBytes > 0 && cBytes <= static_cast<size_t>(st.st_size)) + { + pBuffer[cBytes] = '\0'; + + int nLen = (int)cBytes; + mir_safe_string<TCHAR> ss(mir_utf8decodeT(pBuffer)); + if(ss.m_p) + { + HXML h = xi.parseString(ss.m_p,&nLen,NULL); + if(h) + { + pResult = IXMLNode::TXMLNodePtr(new CXMLNodeMI(h,true)); + } + } + } + } + ::fclose(stream); + } + + return pResult; +} + +namespace +{ + IXMLNode::TXMLNodePtr create_node(const tstring& rsName,const tstring& rsText,bool bIsDecl) + { + IXMLNode::TXMLNodePtr pResult; + HXML h = xi.createNode(rsName.c_str(),rsText.c_str(),bIsDecl); + if(h) + { + pResult = IXMLNode::TXMLNodePtr(new CXMLNodeMI(h,true)); + } + + return pResult; + } +} + +bool CXMLEngineMI::SaveFile(const tstring& rsFileName,const IXMLNode::TXMLNodePtr& pNode)const +{ + CXMLNodeMI* pXML = dynamic_cast<CXMLNodeMI*>(pNode.get()); + if(pXML) + { + tofstream file(rsFileName.c_str()); + if(file.good()) + { + IXMLNode::TXMLNodePtr pRoot(create_node(_T("xml"),tstring(),true)); + if(pRoot) + { + pRoot->AddAttribute(_T("version"),_T("1.0")); + pRoot->AddAttribute(_T("encoding"),_T("UTF-8")); + file << *pRoot; + } + + if(file.good()) + { + file << *pNode; + } + } + + return file.good(); + } + + return false; +} + +IXMLNode::TXMLNodePtr CXMLEngineMI::CreateNode(const tstring& rsName,const tstring& rsText)const +{ + return create_node(rsName,rsText,false); +} \ No newline at end of file diff --git a/protocols/Quotes/XMLEngineMI.h b/protocols/Quotes/XMLEngineMI.h new file mode 100644 index 0000000000..5e5a51232f --- /dev/null +++ b/protocols/Quotes/XMLEngineMI.h @@ -0,0 +1,17 @@ +#ifndef __0c3d1da4_92b7_431c_83e5_f998cd513f0d_XMLEngineMI_h__ +#define __0c3d1da4_92b7_431c_83e5_f998cd513f0d_XMLEngineMI_h__ + +#include "ixmlengine.h" + +class CXMLEngineMI : public IXMLEngine +{ +public: + CXMLEngineMI(); + ~CXMLEngineMI(); + + virtual IXMLNode::TXMLNodePtr LoadFile(const tstring& rsFileName)const; + virtual bool SaveFile(const tstring& rsFileName,const IXMLNode::TXMLNodePtr& pNode)const; + virtual IXMLNode::TXMLNodePtr CreateNode(const tstring& rsName,const tstring& rsText)const; +}; + +#endif //__0c3d1da4_92b7_431c_83e5_f998cd513f0d_XMLEngineMI_h__ diff --git a/protocols/Quotes/dllmain.cpp b/protocols/Quotes/dllmain.cpp new file mode 100644 index 0000000000..9a1be15de5 --- /dev/null +++ b/protocols/Quotes/dllmain.cpp @@ -0,0 +1,23 @@ +// dllmain.cpp : Defines the entry point for the DLL application. +#include "stdafx.h" +#include "ModuleInfo.h" + +BOOL APIENTRY DllMain( HMODULE hModule, + DWORD ul_reason_for_call, + LPVOID lpReserved + ) +{ + switch (ul_reason_for_call) + { + case DLL_PROCESS_ATTACH: + CModuleInfo::SetModuleHandle(hModule); + break; + case DLL_THREAD_ATTACH: + case DLL_THREAD_DETACH: + case DLL_PROCESS_DETACH: + break; + } + + return TRUE; +} + diff --git a/protocols/Quotes/proto_Quotes/proto_Quotes.rc b/protocols/Quotes/proto_Quotes/proto_Quotes.rc new file mode 100644 index 0000000000..b9ce00b0cd --- /dev/null +++ b/protocols/Quotes/proto_Quotes/proto_Quotes.rc @@ -0,0 +1,122 @@ +//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 DISCARDABLE "../res/proto_online.ico" +105 ICON DISCARDABLE "../res/proto_offline.ico" +131 ICON DISCARDABLE "../res/proto_na.ico" +159 ICON DISCARDABLE "../res/proto_occupied.ico" + +#endif // English (U.S.) resources +///////////////////////////////////////////////////////////////////////////// + +#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_RUS) +#ifdef _WIN32 +LANGUAGE LANG_RUSSIAN, SUBLANG_DEFAULT +#pragma code_page(1251) +#endif //_WIN32 + +#ifdef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// TEXTINCLUDE +// + +1 TEXTINCLUDE +BEGIN + "resource.h\0" +END + +2 TEXTINCLUDE +BEGIN + "#include ""afxres.h""\r\n" + "\0" +END + +3 TEXTINCLUDE +BEGIN + "\r\n" + "\0" +END + +#endif // APSTUDIO_INVOKED + + +///////////////////////////////////////////////////////////////////////////// +// +// Version +// + +VS_VERSION_INFO VERSIONINFO + FILEVERSION 0,0,0,1 + PRODUCTVERSION 0,0,0,15 + FILEFLAGSMASK 0x37L +#ifdef _DEBUG + FILEFLAGS 0x21L +#else + FILEFLAGS 0x20L +#endif + FILEOS 0x4L + FILETYPE 0x2L + FILESUBTYPE 0x0L +BEGIN + BLOCK "StringFileInfo" + BEGIN + BLOCK "000004b0" + BEGIN + VALUE "CompanyName", "Dioksin" + VALUE "FileDescription", "Quotes protocol icons" + VALUE "FileVersion", "0, 0, 0, 1" + VALUE "InternalName", "proto_Quotes" + VALUE "LegalCopyright", "Do not worry!" + VALUE "OriginalFilename", "proto_Quotes.dll" + VALUE "ProductName", "Miranda IM" + VALUE "ProductVersion", "0, 0, 0, 15" + VALUE "SpecialBuild", "3" + END + END + BLOCK "VarFileInfo" + BEGIN + VALUE "Translation", 0x0, 1200 + END +END + +#endif // Russian resources +///////////////////////////////////////////////////////////////////////////// + + + +#ifndef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 3 resource. +// + + +///////////////////////////////////////////////////////////////////////////// +#endif // not APSTUDIO_INVOKED + diff --git a/protocols/Quotes/proto_Quotes/proto_Quotes_10.vcxproj b/protocols/Quotes/proto_Quotes/proto_Quotes_10.vcxproj new file mode 100644 index 0000000000..13a3acc0bc --- /dev/null +++ b/protocols/Quotes/proto_Quotes/proto_Quotes_10.vcxproj @@ -0,0 +1,129 @@ +<?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_Quotes</ProjectName> + <ProjectGuid>{5A0A9761-78E1-4E0F-AD8C-8931A667A5F2}</ProjectGuid> + </PropertyGroup> + <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" /> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration"> + <ConfigurationType>DynamicLibrary</ConfigurationType> + <CharacterSet>Unicode</CharacterSet> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration"> + <ConfigurationType>DynamicLibrary</ConfigurationType> + <CharacterSet>Unicode</CharacterSet> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration"> + <ConfigurationType>DynamicLibrary</ConfigurationType> + <CharacterSet>Unicode</CharacterSet> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration"> + <ConfigurationType>DynamicLibrary</ConfigurationType> + <CharacterSet>Unicode</CharacterSet> + </PropertyGroup> + <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" /> + <ImportGroup Label="ExtensionSettings"> + </ImportGroup> + <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="PropertySheets"> + <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" /> + </ImportGroup> + <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="PropertySheets"> + <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" /> + </ImportGroup> + <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="PropertySheets"> + <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" /> + </ImportGroup> + <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="PropertySheets"> + <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" /> + </ImportGroup> + <PropertyGroup Label="UserMacros" /> + <PropertyGroup> + <_ProjectFileVersion>10.0.30319.1</_ProjectFileVersion> + <OutDir Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">$(SolutionDir)$(Configuration)\Icons\</OutDir> + <OutDir Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">$(SolutionDir)$(Configuration)64\Icons\</OutDir> + <IntDir Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">$(SolutionDir)$(Configuration)\Obj\$(ProjectName)\</IntDir> + <IntDir Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">$(SolutionDir)$(Configuration)64\Obj\$(ProjectName)\</IntDir> + <OutDir Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">$(SolutionDir)$(Configuration)\Icons\</OutDir> + <OutDir Condition="'$(Configuration)|$(Platform)'=='Release|x64'">$(SolutionDir)$(Configuration)64\Icons\</OutDir> + <IntDir Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">$(SolutionDir)$(Configuration)\Obj\$(ProjectName)\</IntDir> + <IntDir Condition="'$(Configuration)|$(Platform)'=='Release|x64'">$(SolutionDir)$(Configuration)64\Obj\$(ProjectName)\</IntDir> + <IgnoreImportLibrary Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</IgnoreImportLibrary> + <IgnoreImportLibrary Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">true</IgnoreImportLibrary> + <IgnoreImportLibrary Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</IgnoreImportLibrary> + <IgnoreImportLibrary Condition="'$(Configuration)|$(Platform)'=='Release|x64'">true</IgnoreImportLibrary> + </PropertyGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"> + <Link> + <NoEntryPoint>true</NoEntryPoint> + <RandomizedBaseAddress>false</RandomizedBaseAddress> + <SubSystem>Windows</SubSystem> + </Link> + <ResourceCompile> + <PreprocessorDefinitions>_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions> + <AdditionalIncludeDirectories>..\..\include\msapi</AdditionalIncludeDirectories> + </ResourceCompile> + </ItemDefinitionGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'"> + <Link> + <NoEntryPoint>true</NoEntryPoint> + <RandomizedBaseAddress>false</RandomizedBaseAddress> + <SubSystem>Windows</SubSystem> + </Link> + <ResourceCompile> + <PreprocessorDefinitions>_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions> + <AdditionalIncludeDirectories>..\..\include\msapi</AdditionalIncludeDirectories> + </ResourceCompile> + </ItemDefinitionGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> + <Link> + <NoEntryPoint>true</NoEntryPoint> + <RandomizedBaseAddress>false</RandomizedBaseAddress> + <SubSystem>Windows</SubSystem> + </Link> + <ResourceCompile> + <PreprocessorDefinitions>NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions> + <AdditionalIncludeDirectories>..\..\include\msapi</AdditionalIncludeDirectories> + </ResourceCompile> + </ItemDefinitionGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'"> + <Link> + <NoEntryPoint>true</NoEntryPoint> + <RandomizedBaseAddress>false</RandomizedBaseAddress> + <SubSystem>Windows</SubSystem> + </Link> + <ResourceCompile> + <PreprocessorDefinitions>NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions> + <AdditionalIncludeDirectories>..\..\include\msapi</AdditionalIncludeDirectories> + </ResourceCompile> + </ItemDefinitionGroup> + <ItemGroup> + <None Include="..\res\proto_na.ico" /> + <None Include="..\res\proto_occupied.ico" /> + <None Include="..\res\proto_offline.ico" /> + <None Include="..\res\proto_online.ico" /> + </ItemGroup> + <ItemGroup> + <ResourceCompile Include="proto_Quotes.rc" /> + </ItemGroup> + <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" /> + <ImportGroup Label="ExtensionTargets"> + </ImportGroup> +</Project> \ No newline at end of file diff --git a/protocols/Quotes/proto_Quotes/proto_Quotes_10.vcxproj.filters b/protocols/Quotes/proto_Quotes/proto_Quotes_10.vcxproj.filters new file mode 100644 index 0000000000..6da0285fe9 --- /dev/null +++ b/protocols/Quotes/proto_Quotes/proto_Quotes_10.vcxproj.filters @@ -0,0 +1,28 @@ +<?xml version="1.0" encoding="utf-8"?> +<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> + <ItemGroup> + <Filter Include="Resource Files"> + <UniqueIdentifier>{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}</UniqueIdentifier> + <Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav</Extensions> + </Filter> + </ItemGroup> + <ItemGroup> + <None Include="..\res\proto_na.ico"> + <Filter>Resource Files</Filter> + </None> + <None Include="..\res\proto_occupied.ico"> + <Filter>Resource Files</Filter> + </None> + <None Include="..\res\proto_offline.ico"> + <Filter>Resource Files</Filter> + </None> + <None Include="..\res\proto_online.ico"> + <Filter>Resource Files</Filter> + </None> + </ItemGroup> + <ItemGroup> + <ResourceCompile Include="proto_Quotes.rc"> + <Filter>Resource Files</Filter> + </ResourceCompile> + </ItemGroup> +</Project> \ No newline at end of file diff --git a/protocols/Quotes/res/CurrencyConverter.ico b/protocols/Quotes/res/CurrencyConverter.ico new file mode 100644 index 0000000000..67ac2095f5 Binary files /dev/null and b/protocols/Quotes/res/CurrencyConverter.ico differ diff --git a/protocols/Quotes/res/Export quotes.ico b/protocols/Quotes/res/Export quotes.ico new file mode 100644 index 0000000000..31c7aa2ba1 Binary files /dev/null and b/protocols/Quotes/res/Export quotes.ico differ diff --git a/protocols/Quotes/res/Import quotes.ico b/protocols/Quotes/res/Import quotes.ico new file mode 100644 index 0000000000..506aa62af3 Binary files /dev/null and b/protocols/Quotes/res/Import quotes.ico differ diff --git a/protocols/Quotes/res/Refresh.ico b/protocols/Quotes/res/Refresh.ico new file mode 100644 index 0000000000..2dbcfd3878 Binary files /dev/null and b/protocols/Quotes/res/Refresh.ico differ diff --git a/protocols/Quotes/res/Section.ico b/protocols/Quotes/res/Section.ico new file mode 100644 index 0000000000..f59105b665 Binary files /dev/null and b/protocols/Quotes/res/Section.ico differ diff --git a/protocols/Quotes/res/down.ico b/protocols/Quotes/res/down.ico new file mode 100644 index 0000000000..9dfe185cbe Binary files /dev/null and b/protocols/Quotes/res/down.ico differ diff --git a/protocols/Quotes/res/main.ico b/protocols/Quotes/res/main.ico new file mode 100644 index 0000000000..4d32e57495 Binary files /dev/null and b/protocols/Quotes/res/main.ico differ diff --git a/protocols/Quotes/res/notchanged.ico b/protocols/Quotes/res/notchanged.ico new file mode 100644 index 0000000000..e1d9ee3a09 Binary files /dev/null and b/protocols/Quotes/res/notchanged.ico differ diff --git a/protocols/Quotes/res/proto_na.ico b/protocols/Quotes/res/proto_na.ico new file mode 100644 index 0000000000..c8888adb80 Binary files /dev/null and b/protocols/Quotes/res/proto_na.ico differ diff --git a/protocols/Quotes/res/proto_occupied.ico b/protocols/Quotes/res/proto_occupied.ico new file mode 100644 index 0000000000..3f54c740d1 Binary files /dev/null and b/protocols/Quotes/res/proto_occupied.ico differ diff --git a/protocols/Quotes/res/proto_offline.ico b/protocols/Quotes/res/proto_offline.ico new file mode 100644 index 0000000000..cd99c072bf Binary files /dev/null and b/protocols/Quotes/res/proto_offline.ico differ diff --git a/protocols/Quotes/res/proto_online.ico b/protocols/Quotes/res/proto_online.ico new file mode 100644 index 0000000000..29e500e2bb Binary files /dev/null and b/protocols/Quotes/res/proto_online.ico differ diff --git a/protocols/Quotes/res/quote.ico b/protocols/Quotes/res/quote.ico new file mode 100644 index 0000000000..832ed12f52 Binary files /dev/null and b/protocols/Quotes/res/quote.ico differ diff --git a/protocols/Quotes/res/swap.ico b/protocols/Quotes/res/swap.ico new file mode 100644 index 0000000000..1bff71b764 Binary files /dev/null and b/protocols/Quotes/res/swap.ico differ diff --git a/protocols/Quotes/res/up.ico b/protocols/Quotes/res/up.ico new file mode 100644 index 0000000000..a75899cd3d Binary files /dev/null and b/protocols/Quotes/res/up.ico differ diff --git a/protocols/Quotes/resource.h b/protocols/Quotes/resource.h new file mode 100644 index 0000000000..50ee0a637b --- /dev/null +++ b/protocols/Quotes/resource.h @@ -0,0 +1,109 @@ +//{{NO_DEPENDENCIES}} +// Microsoft Visual C++ generated include file. +// Used by Forex.rc +// +#define IDD_DIALOG_ECONOMIC_RATES 101 +#define IDI_ICON_MAIN 102 +#define IDD_DIALOG_QUOTE_INFO 102 +#define IDD_DIALOG_OPT_GOOGLE 103 +#define IDI_ICON_SECTION 110 +#define IDI_ICON_QUOTE 111 +#define IDI_ICON_UP 113 +#define IDI_ICON_DOWN 114 +#define IDD_CONTACT_SETTINGS 115 +#define IDI_ICON_NOTCHANGED 116 +#define IDD_CURRENCY_CONVERTER 116 +#define IDI_ICON_CURRENCY_CONVERTER 117 +#define IDD_DUKASCOPY_CHART 117 +#define IDD_CHART 117 +#define IDD_DIALOG_QUOTE_INFO_1 118 +#define IDI_ICON_REFRESH 118 +#define IDD_DIALOG_OPT_FINANCE 119 +#define IDI_ICON_IMPORT 119 +#define IDI_ICON_EXPORT 120 +#define IDD_PROVIDER_ADV_SETTINGS 120 +#define IDI_ICON_SWAP 121 +#define IDD_DIALOG_POPUP 121 +#define IDD_DIALOG_VARIABLE_LIST 123 +#define IDC_TREE_ECONOMIC_RATES 1001 +#define IDC_EDIT_REFRESH_RATE 1002 +#define IDC_SPIN_REFRESH_RATE 1003 +#define IDC_COMBO_REFRESH_RATE 1004 +#define IDC_STATIC_QUOTE_NAME 1008 +#define IDC_SYSLINK_PROVIDER 1009 +#define IDC_STATIC_CHART 1010 +#define IDC_STATIC_QUOTE_CHART 1010 +#define IDC_COMBO_CONVERT_FROM 1011 +#define IDC_COMBO_CONVERT_INTO 1012 +#define IDC_BUTTON_ADD 1013 +#define IDC_LIST_RATES 1014 +#define IDC_BUTTON_REMOVE 1015 +#define IDC_EDIT_RATE 1016 +#define IDC_EDIT_RATE_FETCH_TIME 1017 +#define IDC_EDIT_CONTACT_LIST_FORMAT 1018 +#define IDC_EDIT_PREVIOUS_RATE 1018 +#define IDC_BUTTON_DESCRIPTION 1019 +#define IDC_CHECK_INTERNAL_HISTORY 1020 +#define IDC_EDIT_STATUS_MESSAGE_FORMAT 1020 +#define IDC_CHECK_EXTERNAL_FILE 1021 +#define IDC_EDIT_FILE_NAME 1022 +#define IDC_EDIT_TENDENCY_FORMAT 1022 +#define IDC_BUTTON_BROWSE 1023 +#define IDC_STATIC_SELECT_FILE 1024 +#define IDC_EDIT_NAME 1025 +#define IDC_EDIT_HISTORY_FORMAT 1026 +#define IDC_EDIT_LOG_FILE_FORMAT 1027 +#define IDC_BUTTON_DESCRIPTION2 1028 +#define IDC_BUTTON_LOG_FILE_DESCRIPTION 1028 +#define IDC_STATIC_HISTORY_FORMAT 1029 +#define IDC_BUTTON_HISTORY_DESCRIPTION 1030 +#define IDC_STATIC_LOG_FILE_FORMAT 1031 +#define IDC_CHECK_HISTORY_CONDITION 1032 +#define IDC_CHECK_LOG_CONDITION2 1033 +#define IDC_CHECK_LOG_FILE_CONDITION 1033 +#define IDC_EDIT_VALUE 1033 +#define IDC_BUTTON_CONVERT 1034 +#define IDC_CHECK_SHOW_POPUP_ONLY_VALUE_CHANGED 1034 +#define IDC_STATIC_POPUP_FORMAT 1035 +#define IDC_EDIT_POPUP_FORMAT 1036 +#define IDC_BUTTON_LOG_FILE_DESCRIPTION2 1037 +#define IDC_BUTTON_POPUP_FORMAT_DESCRIPTION 1037 +#define IDC_EDIT_RESULT 1039 +#define IDC_STATIC_IMAGE 1056 +#define IDC_EDIT_QUOTE 1059 +#define IDC_BUTTON_SWAP 1060 +#define IDC_BUTTON_ADVANCED_SETTINGS 1061 +#define IDC_BUTTON_POPUP_SETTINGS 1061 +#define IDC_CHECK_CONTACT_SPECIFIC 1062 +#define IDC_RADIO_DEFAULT_COLOURS 1063 +#define IDC_CHECK_SHOW_POPUP 1064 +#define IDC_RADIO_USER_DEFINED_COLOURS 1064 +#define IDC_MFCCOLORBUTTON1 1066 +#define IDC_CHECK1 1067 +#define IDC_CHECK_DONT_USE_POPUPHISTORY 1067 +#define IDC_COMBO_DATA_SOURCE 1068 +#define IDC_COMBO_FILTER 1069 +#define IDC_EDIT_FROM 1070 +#define IDC_EDIT_FROM2 1071 +#define IDC_EDIT_TO 1071 +#define IDC_STATIC_PROVIDER_NAME 1071 +#define IDC_DELAY 1072 +#define IDC_EDIT1 1072 +#define IDC_EDIT_VARIABLE 1072 +#define IDC_BGCOLOR 1074 +#define IDC_TEXTCOLOR 1075 +#define IDC_PREV 1076 +#define IDC_DELAYFROMPU 1093 +#define IDC_DELAYCUSTOM 1094 +#define IDC_DELAYPERMANENT 1095 + +// Next default values for new objects +// +#ifdef APSTUDIO_INVOKED +#ifndef APSTUDIO_READONLY_SYMBOLS +#define _APS_NEXT_RESOURCE_VALUE 124 +#define _APS_NEXT_COMMAND_VALUE 40001 +#define _APS_NEXT_CONTROL_VALUE 1073 +#define _APS_NEXT_SYMED_VALUE 101 +#endif +#endif diff --git a/protocols/Quotes/stdafx.cpp b/protocols/Quotes/stdafx.cpp new file mode 100644 index 0000000000..e4738d8f60 --- /dev/null +++ b/protocols/Quotes/stdafx.cpp @@ -0,0 +1,8 @@ +// stdafx.cpp : source file that includes just the standard includes +// Forex.pch will be the pre-compiled header +// stdafx.obj will contain the pre-compiled type information + +#include "stdafx.h" + +// TODO: reference any additional headers you need in STDAFX.H +// and not in this file diff --git a/protocols/Quotes/stdafx.h b/protocols/Quotes/stdafx.h new file mode 100644 index 0000000000..19c85a3303 --- /dev/null +++ b/protocols/Quotes/stdafx.h @@ -0,0 +1,165 @@ +// stdafx.h : include file for standard system include files, +// or project specific include files that are used frequently, but +// are changed infrequently +// + +#pragma once + +#include "targetver.h" +#define MIRANDA_VER 0x0800 +#define MIRANDA_CUSTOM_LP +// #define CHART_IMPLEMENT +#define TEST_IMPORT_EXPORT + +#define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers +// Windows Header Files: +#include <windows.h> +#include <tchar.h> +#include <stdio.h> +#include <string> +#include <wininet.h> +#include <atlbase.h> +#include <atlconv.h> +#include <mshtml.h> +#include <atlcomcli.h> +#include <comutil.h> +#include <comdef.h> +#include <commctrl.h> +#include <ShellAPI.h> +#include <msxml2.h> +#include <sys\stat.h> +#include <CommDlg.h> +#include <windowsx.h> +#include <atlenc.h> + + +// Miranda headers +#pragma warning(disable: 4996) +#include <newpluginapi.h> +#include <m_database.h> +#include <m_protocols.h> +#include <m_protomod.h> +#pragma warning(default: 4996) +#include <win2k.h> +#include <m_xml.h> +#include <m_langpack.h> +#include <m_options.h> +#include <m_cluiframes.h> +#include <m_extraicons.h> +#include <m_icolib.h> +#include <m_clist.h> +#include <m_genmenu.h> +#include <m_netlib.h> +#include <m_popup.h> +#include <m_userinfo.h> +#include <m_variables.h> + +// boost headers +#include <boost\shared_ptr.hpp> +#include <boost/bind.hpp> +#include <boost\lexical_cast.hpp> +#include <boost\noncopyable.hpp> +#include <boost\scoped_ptr.hpp> +#include <boost\foreach.hpp> +#include <boost/date_time/gregorian/gregorian.hpp> +#include <boost/date_time/posix_time/posix_time.hpp> +#include <boost\cast.hpp> +#include "boost/date_time/c_local_time_adjustor.hpp" + +// stl headers +#include <string> +#include <vector> +#include <sstream> +#include <iomanip> +#include <fstream> +#include <map> + +#ifdef _UNICODE +typedef std::wstring tstring; +typedef std::wostringstream tostringstream; +typedef std::wistringstream tistringstream; +typedef std::wofstream tofstream; +typedef std::wifstream tifstream; +typedef std::wostream tostream; +typedef std::wistream tistream; +typedef boost::posix_time::wtime_input_facet ttime_input_facet; +typedef boost::posix_time::wtime_facet ttime_facet; +#else +typedef std::string tstring; +typedef std::ostringstream tostringstream; +typedef std::istringstream tistringstream; +typedef std::ofstream tofstream; +typedef std::ifstream tifstream; +typedef std::ostream tostream; +typedef std::istream tistream; +typedef boost::posix_time::time_input_facet ttime_input_facet; +typedef boost::posix_time::time_facet ttime_facet; +#endif + +inline int quotes_stricmp(LPCTSTR p1,LPCTSTR p2) +{ + return _tcsicmp(p1,p2); +} + +inline std::string quotes_t2a(const TCHAR* t) +{ + std::string s; + char* p = mir_t2a(t); + if(p) + { + s = p; + mir_free(p); + } + return s; +} + +inline tstring quotes_a2t(const char* s) +{ + tstring t; + TCHAR* p = mir_a2t(s); + if(p) + { + t = p; + mir_free(p); + } + return t; +} +namespace detail +{ + template<typename T,typename TD> struct safe_string_impl + { + typedef T* PTR; + + safe_string_impl(PTR p) : m_p(p){} + ~safe_string_impl(){TD::dealloc(m_p);} + + PTR m_p; + }; + + template<typename T> struct MirandaFree + { + static void dealloc(T* p){mir_free(p);} + }; + + template<typename T> struct OwnerFree + { + static void dealloc(T* p){::free(p);} + }; +} + +template<typename T> struct mir_safe_string : public detail::safe_string_impl<T,detail::MirandaFree<T>> +{ + mir_safe_string(PTR p) : detail::safe_string_impl<T,detail::MirandaFree<T>>(p){} +}; + +template<typename T> struct safe_string : public detail::safe_string_impl<T,detail::OwnerFree<T>> +{ + safe_string(PTR p) : detail::safe_string_impl<T,detail::OwnerFree<T>>(p){} +}; + + +// #ifdef MIRANDA_VER +// #undef MIRANDA_VER +// #endif + +// TODO: reference additional headers your program requires here diff --git a/protocols/Quotes/targetver.h b/protocols/Quotes/targetver.h new file mode 100644 index 0000000000..f583181dfd --- /dev/null +++ b/protocols/Quotes/targetver.h @@ -0,0 +1,24 @@ +#pragma once + +// The following macros define the minimum required platform. The minimum required platform +// is the earliest version of Windows, Internet Explorer etc. that has the necessary features to run +// your application. The macros work by enabling all features available on platform versions up to and +// including the version specified. + +// Modify the following defines if you have to target a platform prior to the ones specified below. +// Refer to MSDN for the latest info on corresponding values for different platforms. +#ifndef WINVER // Specifies that the minimum required platform is Windows Vista. +#define WINVER 0x0600 // Change this to the appropriate value to target other versions of Windows. +#endif + +#ifndef _WIN32_WINNT // Specifies that the minimum required platform is Windows Vista. +#define _WIN32_WINNT 0x0600 // Change this to the appropriate value to target other versions of Windows. +#endif + +#ifndef _WIN32_WINDOWS // Specifies that the minimum required platform is Windows 98. +#define _WIN32_WINDOWS 0x0410 // Change this to the appropriate value to target Windows Me or later. +#endif + +#ifndef _WIN32_IE // Specifies that the minimum required platform is Internet Explorer 7.0. +#define _WIN32_IE 0x0700 // Change this to the appropriate value to target other versions of IE. +#endif diff --git a/protocols/Quotes/version.h b/protocols/Quotes/version.h new file mode 100644 index 0000000000..956486d4d5 --- /dev/null +++ b/protocols/Quotes/version.h @@ -0,0 +1,25 @@ +#define __MAJOR_VERSION 0 +#define __MINOR_VERSION 0 +#define __RELEASE_NUM 24 +#define __BUILD_NUM 0 + +#define __FILEVERSION_STRING __MAJOR_VERSION,__MINOR_VERSION,__RELEASE_NUM,__BUILD_NUM +#define __FILEVERSION_DOTS __MAJOR_VERSION.__MINOR_VERSION.__RELEASE_NUM.__BUILD_NUM + +#define __STRINGIFY_IMPL(x) #x +#define __STRINGIFY(x) __STRINGIFY_IMPL(x) +#define __VERSION_STRING __STRINGIFY(__FILEVERSION_DOTS) + +#if defined (_UNICODE) +#define __PLUGIN_NAME "Quotes (Unicode)" +#else +#define __PLUGIN_NAME "Quotes" +#endif +#define __INTERNAL_NAME "Quotes" +#define __FILENAME "Quotes.dll" +#define __DESCRIPTION "Show currency rates and economic quotes." +#define __AUTHOR "Dioksin" +#define __AUTHOREMAIL "dioksin@ua.fm" +#define __AUTHORWEB "http://www.miranda-im.org" +#define __COPYRIGHT "Don't worry!" +#define SPECIAL_BUILD_STRING "5388" diff --git a/protocols/Twitter/LICENSE.txt b/protocols/Twitter/LICENSE.txt new file mode 100644 index 0000000000..818433ecc0 --- /dev/null +++ b/protocols/Twitter/LICENSE.txt @@ -0,0 +1,674 @@ + GNU GENERAL PUBLIC LICENSE + Version 3, 29 June 2007 + + Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/> + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The GNU General Public License is a free, copyleft license for +software and other kinds of works. + + The licenses for most software and other practical works are designed +to take away your freedom to share and change the works. By contrast, +the GNU General Public License is intended to guarantee your freedom to +share and change all versions of a program--to make sure it remains free +software for all its users. We, the Free Software Foundation, use the +GNU General Public License for most of our software; it applies also to +any other work released this way by its authors. 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 +them 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 prevent others from denying you +these rights or asking you to surrender the rights. Therefore, you have +certain responsibilities if you distribute copies of the software, or if +you modify it: responsibilities to respect the freedom of others. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must pass on to the recipients the same +freedoms that you received. 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. + + Developers that use the GNU GPL protect your rights with two steps: +(1) assert copyright on the software, and (2) offer you this License +giving you legal permission to copy, distribute and/or modify it. + + For the developers' and authors' protection, the GPL clearly explains +that there is no warranty for this free software. For both users' and +authors' sake, the GPL requires that modified versions be marked as +changed, so that their problems will not be attributed erroneously to +authors of previous versions. + + Some devices are designed to deny users access to install or run +modified versions of the software inside them, although the manufacturer +can do so. This is fundamentally incompatible with the aim of +protecting users' freedom to change the software. The systematic +pattern of such abuse occurs in the area of products for individuals to +use, which is precisely where it is most unacceptable. Therefore, we +have designed this version of the GPL to prohibit the practice for those +products. If such problems arise substantially in other domains, we +stand ready to extend this provision to those domains in future versions +of the GPL, as needed to protect the freedom of users. + + Finally, every program is threatened constantly by software patents. +States should not allow patents to restrict development and use of +software on general-purpose computers, but in those that do, we wish to +avoid the special danger that patents applied to a free program could +make it effectively proprietary. To prevent this, the GPL assures that +patents cannot be used to render the program non-free. + + The precise terms and conditions for copying, distribution and +modification follow. + + TERMS AND CONDITIONS + + 0. Definitions. + + "This License" refers to version 3 of the GNU General Public License. + + "Copyright" also means copyright-like laws that apply to other kinds of +works, such as semiconductor masks. + + "The Program" refers to any copyrightable work licensed under this +License. Each licensee is addressed as "you". "Licensees" and +"recipients" may be individuals or organizations. + + To "modify" a work means to copy from or adapt all or part of the work +in a fashion requiring copyright permission, other than the making of an +exact copy. The resulting work is called a "modified version" of the +earlier work or a work "based on" the earlier work. + + A "covered work" means either the unmodified Program or a work based +on the Program. + + To "propagate" a work means to do anything with it that, without +permission, would make you directly or secondarily liable for +infringement under applicable copyright law, except executing it on a +computer or modifying a private copy. Propagation includes copying, +distribution (with or without modification), making available to the +public, and in some countries other activities as well. + + To "convey" a work means any kind of propagation that enables other +parties to make or receive copies. Mere interaction with a user through +a computer network, with no transfer of a copy, is not conveying. + + An interactive user interface displays "Appropriate Legal Notices" +to the extent that it includes a convenient and prominently visible +feature that (1) displays an appropriate copyright notice, and (2) +tells the user that there is no warranty for the work (except to the +extent that warranties are provided), that licensees may convey the +work under this License, and how to view a copy of this License. If +the interface presents a list of user commands or options, such as a +menu, a prominent item in the list meets this criterion. + + 1. Source Code. + + The "source code" for a work means the preferred form of the work +for making modifications to it. "Object code" means any non-source +form of a work. + + A "Standard Interface" means an interface that either is an official +standard defined by a recognized standards body, or, in the case of +interfaces specified for a particular programming language, one that +is widely used among developers working in that language. + + The "System Libraries" of an executable work include anything, other +than the work as a whole, that (a) is included in the normal form of +packaging a Major Component, but which is not part of that Major +Component, and (b) serves only to enable use of the work with that +Major Component, or to implement a Standard Interface for which an +implementation is available to the public in source code form. A +"Major Component", in this context, means a major essential component +(kernel, window system, and so on) of the specific operating system +(if any) on which the executable work runs, or a compiler used to +produce the work, or an object code interpreter used to run it. + + The "Corresponding Source" for a work in object code form means all +the source code needed to generate, install, and (for an executable +work) run the object code and to modify the work, including scripts to +control those activities. However, it does not include the work's +System Libraries, or general-purpose tools or generally available free +programs which are used unmodified in performing those activities but +which are not part of the work. For example, Corresponding Source +includes interface definition files associated with source files for +the work, and the source code for shared libraries and dynamically +linked subprograms that the work is specifically designed to require, +such as by intimate data communication or control flow between those +subprograms and other parts of the work. + + The Corresponding Source need not include anything that users +can regenerate automatically from other parts of the Corresponding +Source. + + The Corresponding Source for a work in source code form is that +same work. + + 2. Basic Permissions. + + All rights granted under this License are granted for the term of +copyright on the Program, and are irrevocable provided the stated +conditions are met. This License explicitly affirms your unlimited +permission to run the unmodified Program. The output from running a +covered work is covered by this License only if the output, given its +content, constitutes a covered work. This License acknowledges your +rights of fair use or other equivalent, as provided by copyright law. + + You may make, run and propagate covered works that you do not +convey, without conditions so long as your license otherwise remains +in force. You may convey covered works to others for the sole purpose +of having them make modifications exclusively for you, or provide you +with facilities for running those works, provided that you comply with +the terms of this License in conveying all material for which you do +not control copyright. Those thus making or running the covered works +for you must do so exclusively on your behalf, under your direction +and control, on terms that prohibit them from making any copies of +your copyrighted material outside their relationship with you. + + Conveying under any other circumstances is permitted solely under +the conditions stated below. Sublicensing is not allowed; section 10 +makes it unnecessary. + + 3. Protecting Users' Legal Rights From Anti-Circumvention Law. + + No covered work shall be deemed part of an effective technological +measure under any applicable law fulfilling obligations under article +11 of the WIPO copyright treaty adopted on 20 December 1996, or +similar laws prohibiting or restricting circumvention of such +measures. + + When you convey a covered work, you waive any legal power to forbid +circumvention of technological measures to the extent such circumvention +is effected by exercising rights under this License with respect to +the covered work, and you disclaim any intention to limit operation or +modification of the work as a means of enforcing, against the work's +users, your or third parties' legal rights to forbid circumvention of +technological measures. + + 4. Conveying Verbatim Copies. + + You may convey 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; +keep intact all notices stating that this License and any +non-permissive terms added in accord with section 7 apply to the code; +keep intact all notices of the absence of any warranty; and give all +recipients a copy of this License along with the Program. + + You may charge any price or no price for each copy that you convey, +and you may offer support or warranty protection for a fee. + + 5. Conveying Modified Source Versions. + + You may convey a work based on the Program, or the modifications to +produce it from the Program, in the form of source code under the +terms of section 4, provided that you also meet all of these conditions: + + a) The work must carry prominent notices stating that you modified + it, and giving a relevant date. + + b) The work must carry prominent notices stating that it is + released under this License and any conditions added under section + 7. This requirement modifies the requirement in section 4 to + "keep intact all notices". + + c) You must license the entire work, as a whole, under this + License to anyone who comes into possession of a copy. This + License will therefore apply, along with any applicable section 7 + additional terms, to the whole of the work, and all its parts, + regardless of how they are packaged. This License gives no + permission to license the work in any other way, but it does not + invalidate such permission if you have separately received it. + + d) If the work has interactive user interfaces, each must display + Appropriate Legal Notices; however, if the Program has interactive + interfaces that do not display Appropriate Legal Notices, your + work need not make them do so. + + A compilation of a covered work with other separate and independent +works, which are not by their nature extensions of the covered work, +and which are not combined with it such as to form a larger program, +in or on a volume of a storage or distribution medium, is called an +"aggregate" if the compilation and its resulting copyright are not +used to limit the access or legal rights of the compilation's users +beyond what the individual works permit. Inclusion of a covered work +in an aggregate does not cause this License to apply to the other +parts of the aggregate. + + 6. Conveying Non-Source Forms. + + You may convey a covered work in object code form under the terms +of sections 4 and 5, provided that you also convey the +machine-readable Corresponding Source under the terms of this License, +in one of these ways: + + a) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by the + Corresponding Source fixed on a durable physical medium + customarily used for software interchange. + + b) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by a + written offer, valid for at least three years and valid for as + long as you offer spare parts or customer support for that product + model, to give anyone who possesses the object code either (1) a + copy of the Corresponding Source for all the software in the + product that is covered by this License, on a durable physical + medium customarily used for software interchange, for a price no + more than your reasonable cost of physically performing this + conveying of source, or (2) access to copy the + Corresponding Source from a network server at no charge. + + c) Convey individual copies of the object code with a copy of the + written offer to provide the Corresponding Source. This + alternative is allowed only occasionally and noncommercially, and + only if you received the object code with such an offer, in accord + with subsection 6b. + + d) Convey the object code by offering access from a designated + place (gratis or for a charge), and offer equivalent access to the + Corresponding Source in the same way through the same place at no + further charge. You need not require recipients to copy the + Corresponding Source along with the object code. If the place to + copy the object code is a network server, the Corresponding Source + may be on a different server (operated by you or a third party) + that supports equivalent copying facilities, provided you maintain + clear directions next to the object code saying where to find the + Corresponding Source. Regardless of what server hosts the + Corresponding Source, you remain obligated to ensure that it is + available for as long as needed to satisfy these requirements. + + e) Convey the object code using peer-to-peer transmission, provided + you inform other peers where the object code and Corresponding + Source of the work are being offered to the general public at no + charge under subsection 6d. + + A separable portion of the object code, whose source code is excluded +from the Corresponding Source as a System Library, need not be +included in conveying the object code work. + + A "User Product" is either (1) a "consumer product", which means any +tangible personal property which is normally used for personal, family, +or household purposes, or (2) anything designed or sold for incorporation +into a dwelling. In determining whether a product is a consumer product, +doubtful cases shall be resolved in favor of coverage. For a particular +product received by a particular user, "normally used" refers to a +typical or common use of that class of product, regardless of the status +of the particular user or of the way in which the particular user +actually uses, or expects or is expected to use, the product. A product +is a consumer product regardless of whether the product has substantial +commercial, industrial or non-consumer uses, unless such uses represent +the only significant mode of use of the product. + + "Installation Information" for a User Product means any methods, +procedures, authorization keys, or other information required to install +and execute modified versions of a covered work in that User Product from +a modified version of its Corresponding Source. The information must +suffice to ensure that the continued functioning of the modified object +code is in no case prevented or interfered with solely because +modification has been made. + + If you convey an object code work under this section in, or with, or +specifically for use in, a User Product, and the conveying occurs as +part of a transaction in which the right of possession and use of the +User Product is transferred to the recipient in perpetuity or for a +fixed term (regardless of how the transaction is characterized), the +Corresponding Source conveyed under this section must be accompanied +by the Installation Information. But this requirement does not apply +if neither you nor any third party retains the ability to install +modified object code on the User Product (for example, the work has +been installed in ROM). + + The requirement to provide Installation Information does not include a +requirement to continue to provide support service, warranty, or updates +for a work that has been modified or installed by the recipient, or for +the User Product in which it has been modified or installed. Access to a +network may be denied when the modification itself materially and +adversely affects the operation of the network or violates the rules and +protocols for communication across the network. + + Corresponding Source conveyed, and Installation Information provided, +in accord with this section must be in a format that is publicly +documented (and with an implementation available to the public in +source code form), and must require no special password or key for +unpacking, reading or copying. + + 7. Additional Terms. + + "Additional permissions" are terms that supplement the terms of this +License by making exceptions from one or more of its conditions. +Additional permissions that are applicable to the entire Program shall +be treated as though they were included in this License, to the extent +that they are valid under applicable law. If additional permissions +apply only to part of the Program, that part may be used separately +under those permissions, but the entire Program remains governed by +this License without regard to the additional permissions. + + When you convey a copy of a covered work, you may at your option +remove any additional permissions from that copy, or from any part of +it. (Additional permissions may be written to require their own +removal in certain cases when you modify the work.) You may place +additional permissions on material, added by you to a covered work, +for which you have or can give appropriate copyright permission. + + Notwithstanding any other provision of this License, for material you +add to a covered work, you may (if authorized by the copyright holders of +that material) supplement the terms of this License with terms: + + a) Disclaiming warranty or limiting liability differently from the + terms of sections 15 and 16 of this License; or + + b) Requiring preservation of specified reasonable legal notices or + author attributions in that material or in the Appropriate Legal + Notices displayed by works containing it; or + + c) Prohibiting misrepresentation of the origin of that material, or + requiring that modified versions of such material be marked in + reasonable ways as different from the original version; or + + d) Limiting the use for publicity purposes of names of licensors or + authors of the material; or + + e) Declining to grant rights under trademark law for use of some + trade names, trademarks, or service marks; or + + f) Requiring indemnification of licensors and authors of that + material by anyone who conveys the material (or modified versions of + it) with contractual assumptions of liability to the recipient, for + any liability that these contractual assumptions directly impose on + those licensors and authors. + + All other non-permissive additional terms are considered "further +restrictions" within the meaning of section 10. If the Program as you +received it, or any part of it, contains a notice stating that it is +governed by this License along with a term that is a further +restriction, you may remove that term. If a license document contains +a further restriction but permits relicensing or conveying under this +License, you may add to a covered work material governed by the terms +of that license document, provided that the further restriction does +not survive such relicensing or conveying. + + If you add terms to a covered work in accord with this section, you +must place, in the relevant source files, a statement of the +additional terms that apply to those files, or a notice indicating +where to find the applicable terms. + + Additional terms, permissive or non-permissive, may be stated in the +form of a separately written license, or stated as exceptions; +the above requirements apply either way. + + 8. Termination. + + You may not propagate or modify a covered work except as expressly +provided under this License. Any attempt otherwise to propagate or +modify it is void, and will automatically terminate your rights under +this License (including any patent licenses granted under the third +paragraph of section 11). + + However, if you cease all violation of this License, then your +license from a particular copyright holder is reinstated (a) +provisionally, unless and until the copyright holder explicitly and +finally terminates your license, and (b) permanently, if the copyright +holder fails to notify you of the violation by some reasonable means +prior to 60 days after the cessation. + + Moreover, your license from a particular copyright holder is +reinstated permanently if the copyright holder notifies you of the +violation by some reasonable means, this is the first time you have +received notice of violation of this License (for any work) from that +copyright holder, and you cure the violation prior to 30 days after +your receipt of the notice. + + Termination of your rights under this section does not terminate the +licenses of parties who have received copies or rights from you under +this License. If your rights have been terminated and not permanently +reinstated, you do not qualify to receive new licenses for the same +material under section 10. + + 9. Acceptance Not Required for Having Copies. + + You are not required to accept this License in order to receive or +run a copy of the Program. Ancillary propagation of a covered work +occurring solely as a consequence of using peer-to-peer transmission +to receive a copy likewise does not require acceptance. However, +nothing other than this License grants you permission to propagate or +modify any covered work. These actions infringe copyright if you do +not accept this License. Therefore, by modifying or propagating a +covered work, you indicate your acceptance of this License to do so. + + 10. Automatic Licensing of Downstream Recipients. + + Each time you convey a covered work, the recipient automatically +receives a license from the original licensors, to run, modify and +propagate that work, subject to this License. You are not responsible +for enforcing compliance by third parties with this License. + + An "entity transaction" is a transaction transferring control of an +organization, or substantially all assets of one, or subdividing an +organization, or merging organizations. If propagation of a covered +work results from an entity transaction, each party to that +transaction who receives a copy of the work also receives whatever +licenses to the work the party's predecessor in interest had or could +give under the previous paragraph, plus a right to possession of the +Corresponding Source of the work from the predecessor in interest, if +the predecessor has it or can get it with reasonable efforts. + + You may not impose any further restrictions on the exercise of the +rights granted or affirmed under this License. For example, you may +not impose a license fee, royalty, or other charge for exercise of +rights granted under this License, and you may not initiate litigation +(including a cross-claim or counterclaim in a lawsuit) alleging that +any patent claim is infringed by making, using, selling, offering for +sale, or importing the Program or any portion of it. + + 11. Patents. + + A "contributor" is a copyright holder who authorizes use under this +License of the Program or a work on which the Program is based. The +work thus licensed is called the contributor's "contributor version". + + A contributor's "essential patent claims" are all patent claims +owned or controlled by the contributor, whether already acquired or +hereafter acquired, that would be infringed by some manner, permitted +by this License, of making, using, or selling its contributor version, +but do not include claims that would be infringed only as a +consequence of further modification of the contributor version. For +purposes of this definition, "control" includes the right to grant +patent sublicenses in a manner consistent with the requirements of +this License. + + Each contributor grants you a non-exclusive, worldwide, royalty-free +patent license under the contributor's essential patent claims, to +make, use, sell, offer for sale, import and otherwise run, modify and +propagate the contents of its contributor version. + + In the following three paragraphs, a "patent license" is any express +agreement or commitment, however denominated, not to enforce a patent +(such as an express permission to practice a patent or covenant not to +sue for patent infringement). To "grant" such a patent license to a +party means to make such an agreement or commitment not to enforce a +patent against the party. + + If you convey a covered work, knowingly relying on a patent license, +and the Corresponding Source of the work is not available for anyone +to copy, free of charge and under the terms of this License, through a +publicly available network server or other readily accessible means, +then you must either (1) cause the Corresponding Source to be so +available, or (2) arrange to deprive yourself of the benefit of the +patent license for this particular work, or (3) arrange, in a manner +consistent with the requirements of this License, to extend the patent +license to downstream recipients. "Knowingly relying" means you have +actual knowledge that, but for the patent license, your conveying the +covered work in a country, or your recipient's use of the covered work +in a country, would infringe one or more identifiable patents in that +country that you have reason to believe are valid. + + If, pursuant to or in connection with a single transaction or +arrangement, you convey, or propagate by procuring conveyance of, a +covered work, and grant a patent license to some of the parties +receiving the covered work authorizing them to use, propagate, modify +or convey a specific copy of the covered work, then the patent license +you grant is automatically extended to all recipients of the covered +work and works based on it. + + A patent license is "discriminatory" if it does not include within +the scope of its coverage, prohibits the exercise of, or is +conditioned on the non-exercise of one or more of the rights that are +specifically granted under this License. You may not convey a covered +work if you are a party to an arrangement with a third party that is +in the business of distributing software, under which you make payment +to the third party based on the extent of your activity of conveying +the work, and under which the third party grants, to any of the +parties who would receive the covered work from you, a discriminatory +patent license (a) in connection with copies of the covered work +conveyed by you (or copies made from those copies), or (b) primarily +for and in connection with specific products or compilations that +contain the covered work, unless you entered into that arrangement, +or that patent license was granted, prior to 28 March 2007. + + Nothing in this License shall be construed as excluding or limiting +any implied license or other defenses to infringement that may +otherwise be available to you under applicable patent law. + + 12. No Surrender of Others' Freedom. + + If 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 convey a +covered work so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you may +not convey it at all. For example, if you agree to terms that obligate you +to collect a royalty for further conveying from those to whom you convey +the Program, the only way you could satisfy both those terms and this +License would be to refrain entirely from conveying the Program. + + 13. Use with the GNU Affero General Public License. + + Notwithstanding any other provision of this License, you have +permission to link or combine any covered work with a work licensed +under version 3 of the GNU Affero General Public License into a single +combined work, and to convey the resulting work. The terms of this +License will continue to apply to the part which is the covered work, +but the special requirements of the GNU Affero General Public License, +section 13, concerning interaction through a network will apply to the +combination as such. + + 14. Revised Versions of this License. + + The Free Software Foundation may publish revised and/or new versions of +the GNU 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 that a certain numbered version of the GNU General +Public License "or any later version" applies to it, you have the +option of following the terms and conditions either of that numbered +version or of any later version published by the Free Software +Foundation. If the Program does not specify a version number of the +GNU General Public License, you may choose any version ever published +by the Free Software Foundation. + + If the Program specifies that a proxy can decide which future +versions of the GNU General Public License can be used, that proxy's +public statement of acceptance of a version permanently authorizes you +to choose that version for the Program. + + Later license versions may give you additional or different +permissions. However, no additional obligations are imposed on any +author or copyright holder as a result of your choosing to follow a +later version. + + 15. Disclaimer of Warranty. + + 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. + + 16. Limitation of Liability. + + IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS +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. + + 17. Interpretation of Sections 15 and 16. + + If the disclaimer of warranty and limitation of liability provided +above cannot be given local legal effect according to their terms, +reviewing courts shall apply local law that most closely approximates +an absolute waiver of all civil liability in connection with the +Program, unless a warranty or assumption of liability accompanies a +copy of the Program in return for a fee. + + 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 +state 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 3 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, see <http://www.gnu.org/licenses/>. + +Also add information on how to contact you by electronic and paper mail. + + If the program does terminal interaction, make it output a short +notice like this when it starts in an interactive mode: + + <program> Copyright (C) <year> <name of author> + This program 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, your program's commands +might be different; for a GUI interface, you would use an "about box". + + You should also get your employer (if you work as a programmer) or school, +if any, to sign a "copyright disclaimer" for the program, if necessary. +For more information on this, and how to apply and follow the GNU GPL, see +<http://www.gnu.org/licenses/>. + + The GNU 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 Lesser General +Public License instead of this License. But first, please read +<http://www.gnu.org/philosophy/why-not-lgpl.html>. diff --git a/protocols/Twitter/README.txt b/protocols/Twitter/README.txt new file mode 100644 index 0000000000..b229b10796 --- /dev/null +++ b/protocols/Twitter/README.txt @@ -0,0 +1,10 @@ +Miranda-Twitter +--------------- + +Warning! I'm not maintaining this code anymore! It's still around for people who +want to work on it, but that's it; I make no promises that it even works +(indeed, without updates, it almost certainly won't pass Twitter's auth). + +To compile this code, you'll want to check out the Miranda IM header files and +install them into <source>\miranda: +<https://miranda.svn.sourceforge.net/svnroot/miranda/trunk/miranda/include> diff --git a/protocols/Twitter/chat.cpp b/protocols/Twitter/chat.cpp new file mode 100644 index 0000000000..4e659c2aa8 --- /dev/null +++ b/protocols/Twitter/chat.cpp @@ -0,0 +1,206 @@ +/* +Copyright 2009 Jim Porter + +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, see <http://www.gnu.org/licenses/>. +*/ + +#include "common.h" +#include "proto.h" + +#include <set> +#include <ctime> + +void TwitterProto::UpdateChat(const twitter_user &update) +{ + GCDEST gcd = { m_szModuleName }; + gcd.ptszID = const_cast<TCHAR*>(m_tszUserName); + gcd.iType = GC_EVENT_MESSAGE; + + GCEVENT gce = {sizeof(gce)}; + gce.pDest = &gcd; + gce.dwFlags = GC_TCHAR|GCEF_ADDTOLOG; + gce.pDest = &gcd; + gce.ptszUID = mir_a2t( update.username.c_str()); + gce.bIsMe = (update.username == twit_.get_username()); + gce.ptszText = ( TCHAR* )update.status.text.c_str(); + gce.time = static_cast<DWORD>(update.status.time); + + DBVARIANT nick; + HANDLE hContact = UsernameToHContact( _A2T(update.username.c_str())); + if (hContact && !DBGetContactSettingTString(hContact, "CList", "MyHandle", &nick)) { + gce.ptszNick = mir_tstrdup( nick.ptszVal ); + DBFreeVariant(&nick); + } + else gce.ptszNick = mir_a2t( update.username.c_str()); + + CallServiceSync(MS_GC_EVENT, 0, reinterpret_cast<LPARAM>(&gce)); + + mir_free(const_cast<TCHAR*>(gce.ptszNick)); + mir_free(const_cast<TCHAR*>(gce.ptszUID)); + mir_free(const_cast<TCHAR*>(gce.ptszText)); +} + +int TwitterProto::OnChatOutgoing(WPARAM wParam, LPARAM lParam) +{ + GCHOOK *hook = reinterpret_cast<GCHOOK*>(lParam); + if (strcmp(hook->pDest->pszModule, m_szModuleName)) + return 0; + + TCHAR *text; + switch(hook->pDest->iType) { + case GC_USER_MESSAGE: + text = mir_tstrdup(hook->ptszText); + ForkThread(&TwitterProto::SendTweetWorker, this, text); + break; + + case GC_USER_PRIVMESS: + text = mir_tstrdup(hook->ptszUID); + CallService(MS_MSG_SENDMESSAGE, reinterpret_cast<WPARAM>( UsernameToHContact(text)), 0); + mir_free(text); + break; + } + + return 0; +} + +// TODO: remove nick? +void TwitterProto::AddChatContact(const TCHAR *name, const TCHAR *nick) +{ + GCDEST gcd = { m_szModuleName }; + gcd.ptszID = const_cast<TCHAR*>(m_tszUserName); + gcd.iType = GC_EVENT_JOIN; + + GCEVENT gce = {sizeof(gce)}; + gce.pDest = &gcd; + gce.dwFlags = GC_TCHAR; + gce.ptszNick = nick ? nick:name; + gce.ptszUID = name; + gce.bIsMe = false; + gce.ptszStatus = _T("Normal"); + gce.time = static_cast<DWORD>(time(0)); + CallServiceSync(MS_GC_EVENT, 0, reinterpret_cast<LPARAM>(&gce)); +} + +void TwitterProto::DeleteChatContact(const TCHAR *name) +{ + GCDEST gcd = { m_szModuleName }; + gcd.ptszID = const_cast<TCHAR*>(m_tszUserName); + gcd.iType = GC_EVENT_PART; + + GCEVENT gce = {sizeof(gce)}; + gce.pDest = &gcd; + gce.dwFlags = GC_TCHAR; + gce.ptszNick = name; + gce.ptszUID = gce.ptszNick; + gce.time = static_cast<DWORD>(time(0)); + CallServiceSync(MS_GC_EVENT, 0, reinterpret_cast<LPARAM>(&gce)); + + mir_free(const_cast<TCHAR*>(gce.ptszNick)); +} + +int TwitterProto::OnJoinChat(WPARAM, LPARAM suppress) +{ + GCSESSION gcw = {sizeof(gcw)}; + + // ***** Create the group chat session + gcw.dwFlags = GC_TCHAR; + gcw.iType = GCW_CHATROOM; + gcw.pszModule = m_szModuleName; + gcw.ptszName = m_tszUserName; + gcw.ptszID = m_tszUserName; + CallServiceSync(MS_GC_NEWSESSION, 0, (LPARAM)&gcw); + + if (m_iStatus != ID_STATUS_ONLINE) + return 0; + + // ***** Create a group + GCDEST gcd = { m_szModuleName }; + gcd.ptszID = const_cast<TCHAR*>(m_tszUserName); + + GCEVENT gce = {sizeof(gce)}; + gce.pDest = &gcd; + gce.dwFlags = GC_TCHAR; + + gcd.iType = GC_EVENT_ADDGROUP; + gce.ptszStatus = _T("Normal"); + CallServiceSync(MS_GC_EVENT, 0, reinterpret_cast<LPARAM>(&gce)); + + // ***** Hook events + HookProtoEvent(ME_GC_EVENT, &TwitterProto::OnChatOutgoing, this); + + // Note: Initialization will finish up in SetChatStatus, called separately + if (!suppress) + SetChatStatus(m_iStatus); + + in_chat_ = true; + return 0; +} + +int TwitterProto::OnLeaveChat(WPARAM, LPARAM) +{ + in_chat_ = false; + + GCDEST gcd = { m_szModuleName }; + gcd.ptszID = const_cast<TCHAR*>(m_tszUserName); + gcd.iType = GC_EVENT_CONTROL; + + GCEVENT gce = {sizeof(gce)}; + gce.dwFlags = GC_TCHAR; + gce.pDest = &gcd; + + CallServiceSync(MS_GC_EVENT, SESSION_OFFLINE, reinterpret_cast<LPARAM>(&gce)); + CallServiceSync(MS_GC_EVENT, SESSION_TERMINATE, reinterpret_cast<LPARAM>(&gce)); + + return 0; +} + +void TwitterProto::SetChatStatus(int status) +{ + GCDEST gcd = { m_szModuleName }; + gcd.ptszID = const_cast<TCHAR*>(m_tszUserName); + gcd.iType = GC_EVENT_CONTROL; + + GCEVENT gce = {sizeof(gce)}; + gce.dwFlags = GC_TCHAR; + gce.pDest = &gcd; + + if (status == ID_STATUS_ONLINE) { + // Add all friends to contact list + for(HANDLE hContact = (HANDLE)CallService(MS_DB_CONTACT_FINDFIRST, 0, 0); + hContact; + hContact = (HANDLE)CallService(MS_DB_CONTACT_FINDNEXT, (WPARAM)hContact, 0)) + { + if (!IsMyContact(hContact)) + continue; + + DBVARIANT uid, nick; + if ( DBGetContactSettingTString(hContact, m_szModuleName, TWITTER_KEY_UN, &uid)) + continue; + + if ( !DBGetContactSettingTString(hContact, "CList", "MyHandle", &nick)) + AddChatContact(uid.ptszVal, nick.ptszVal); + else + AddChatContact(uid.ptszVal); + + DBFreeVariant(&nick); + DBFreeVariant(&uid); + } + + // For some reason, I have to send an INITDONE message, even if I'm not actually + // initializing the room... + CallServiceSync(MS_GC_EVENT, SESSION_INITDONE, reinterpret_cast<LPARAM>(&gce)); + CallServiceSync(MS_GC_EVENT, SESSION_ONLINE, reinterpret_cast<LPARAM>(&gce)); + } + else CallServiceSync(MS_GC_EVENT, SESSION_OFFLINE, reinterpret_cast<LPARAM>(&gce)); +} \ No newline at end of file diff --git a/protocols/Twitter/common.h b/protocols/Twitter/common.h new file mode 100644 index 0000000000..751c1d22d6 --- /dev/null +++ b/protocols/Twitter/common.h @@ -0,0 +1,80 @@ +/* +Copyright 2009 Jim Porter + +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, see <http://www.gnu.org/licenses/>. +*/ + +#pragma once + +#include <windows.h> + +#include "resource.h" + +#pragma warning(push) +# pragma warning(disable:4312) +#include <newpluginapi.h> +#include <m_avatars.h> +#include <m_button.h> +#include <m_chat.h> +#include <m_clc.h> +#include <m_clist.h> +#include <m_clistint.h> +#include <m_clui.h> +#include <m_database.h> +#include <m_history.h> +#include <m_idle.h> +#include <m_langpack.h> +#include <m_message.h> +#include <m_netlib.h> +#include <m_options.h> +#include <m_popup.h> +#include <m_protocols.h> +#include <m_protomod.h> +#include <m_protosvc.h> +#include <m_skin.h> +#include <statusmodes.h> +#include <m_system.h> +#include <m_system_cpp.h> +#include <m_userinfo.h> +#include <m_addcontact.h> +#include <m_icolib.h> +#include <m_utils.h> +#include <m_system_cpp.h> +#include <m_hotkeys.h> +#include <win2k.h> +#pragma warning(pop) + +extern HINSTANCE g_hInstance; + +#define TWITTER_KEY_UN "Username" +#define TWITTER_KEY_PASS "Password" +#define TWITTER_KEY_BASEURL "BaseURL" +#define TWITTER_KEY_CHATFEED "ChatFeed" +#define TWITTER_KEY_POLLRATE "PollRate" + +#define TWITTER_KEY_POPUP_SHOW "Popup/Show" +#define TWITTER_KEY_POPUP_SIGNON "Popup/Signon" +#define TWITTER_KEY_POPUP_COLBACK "Popup/ColorBack" +#define TWITTER_KEY_POPUP_COLTEXT "Popup/ColorText" +#define TWITTER_KEY_POPUP_TIMEOUT "Popup/Timeout" + +#define TWITTER_KEY_SINCEID "SinceID" +#define TWITTER_KEY_DMSINCEID "DMSinceID" +#define TWITTER_KEY_NEW "NewAcc" + +#define TWITTER_KEY_AV_URL "AvatarURL" + +#define TWITTER_DB_EVENT_TYPE_TWEET 2718 + +#define WM_SETREPLY WM_APP+10 \ No newline at end of file diff --git a/protocols/Twitter/connection.cpp b/protocols/Twitter/connection.cpp new file mode 100644 index 0000000000..83660a8256 --- /dev/null +++ b/protocols/Twitter/connection.cpp @@ -0,0 +1,435 @@ +/* +Copyright 2009 Jim Porter + +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, see <http://www.gnu.org/licenses/>. +*/ + +#include "common.h" +#include "proto.h" + +void CALLBACK TwitterProto::APC_callback(ULONG_PTR p) +{ + reinterpret_cast<TwitterProto*>(p)->LOG("***** Executing APC"); +} + +template<typename T> +inline static T db_pod_get(HANDLE hContact, const char *module, const char *setting, + T errorValue) +{ + DBVARIANT dbv; + DBCONTACTGETSETTING cgs; + + cgs.szModule = module; + cgs.szSetting = setting; + cgs.pValue = &dbv; + if (CallService(MS_DB_CONTACT_GETSETTING, (WPARAM)hContact, (LPARAM)&cgs)) + return errorValue; + + // TODO: remove this, it's just a temporary workaround + if (dbv.type == DBVT_DWORD) + return dbv.dVal; + + if (dbv.cpbVal != sizeof(T)) + return errorValue; + return *reinterpret_cast<T*>(dbv.pbVal); +} + +template<typename T> +inline static INT_PTR db_pod_set(HANDLE hContact, const char *module, const char *setting, + T val) +{ + DBCONTACTWRITESETTING cws; + + cws.szModule = module; + cws.szSetting = setting; + cws.value.type = DBVT_BLOB; + cws.value.cpbVal = sizeof(T); + cws.value.pbVal = reinterpret_cast<BYTE*>(&val); + return CallService(MS_DB_CONTACT_WRITESETTING, (WPARAM)hContact, (LPARAM)&cws); +} + +void TwitterProto::SignOn(void*) +{ + LOG("***** Beginning SignOn process"); + WaitForSingleObject(&signon_lock_, INFINITE); + + // Kill the old thread if it's still around + if (hMsgLoop_) + { + LOG("***** Requesting MessageLoop to exit"); + QueueUserAPC(APC_callback, hMsgLoop_, (ULONG_PTR)this); + LOG("***** Waiting for old MessageLoop to exit"); + WaitForSingleObject(hMsgLoop_, INFINITE); + CloseHandle(hMsgLoop_); + } + if (NegotiateConnection()) // Could this be? The legendary Go Time?? + { + if (!in_chat_ && db_byte_get(0, m_szModuleName, TWITTER_KEY_CHATFEED, 0)) + OnJoinChat(0, true); + + SetAllContactStatuses(ID_STATUS_ONLINE); + hMsgLoop_ = ForkThreadEx(&TwitterProto::MessageLoop, this); + } + + ReleaseMutex(signon_lock_); + LOG("***** SignOn complete"); +} + +bool TwitterProto::NegotiateConnection() +{ + LOG("***** Negotiating connection with Twitter"); + + int old_status = m_iStatus; + std::string user, pass; + DBVARIANT dbv; + + if ( !DBGetContactSettingString(0, m_szModuleName, TWITTER_KEY_UN, &dbv)) { + user = dbv.pszVal; + DBFreeVariant(&dbv); + } + else { + ShowPopup(TranslateT("Please enter a username.")); + return false; + } + + if ( !DBGetContactSettingString(0, m_szModuleName, TWITTER_KEY_PASS, &dbv)) { + CallService(MS_DB_CRYPT_DECODESTRING, strlen(dbv.pszVal)+1, + reinterpret_cast<LPARAM>(dbv.pszVal)); + pass = dbv.pszVal; + DBFreeVariant(&dbv); + } + else { + ShowPopup(TranslateT("Please enter a password.")); + return false; + } + + if ( !DBGetContactSettingString(0, m_szModuleName, TWITTER_KEY_BASEURL, &dbv)) { + ScopedLock s(twitter_lock_); + twit_.set_base_url(dbv.pszVal); + DBFreeVariant(&dbv); + } + + bool success; + { + ScopedLock s(twitter_lock_); + success = twit_.set_credentials(user, pass); + } + + if (!success) { + ShowPopup(TranslateT("Your username/password combination was incorrect.")); + ProtoBroadcastAck(m_szModuleName, 0, ACKTYPE_STATUS, ACKRESULT_FAILED, + (HANDLE)old_status, m_iStatus); + + // Set to offline + old_status = m_iStatus; + m_iDesiredStatus = m_iStatus = ID_STATUS_OFFLINE; + ProtoBroadcastAck(m_szModuleName, 0, ACKTYPE_STATUS, ACKRESULT_SUCCESS, + (HANDLE)old_status, m_iStatus); + + return false; + } + + m_iStatus = m_iDesiredStatus; + ProtoBroadcastAck(m_szModuleName, 0, ACKTYPE_STATUS, ACKRESULT_SUCCESS, (HANDLE)old_status, m_iStatus); + return true; +} + + +void TwitterProto::MessageLoop(void*) +{ + LOG("***** Entering Twitter::MessageLoop"); + + since_id_ = db_pod_get<twitter_id>(0, m_szModuleName, TWITTER_KEY_SINCEID, 0); + dm_since_id_ = db_pod_get<twitter_id>(0, m_szModuleName, TWITTER_KEY_DMSINCEID, 0); + + bool new_account = db_byte_get(0, m_szModuleName, TWITTER_KEY_NEW, 1) != 0; + bool popups = db_byte_get(0, m_szModuleName, TWITTER_KEY_POPUP_SIGNON, 1) != 0; + + int poll_rate = db_dword_get(0, m_szModuleName, TWITTER_KEY_POLLRATE, 80); + + for(unsigned int i=0;;i++) + { + if (m_iStatus != ID_STATUS_ONLINE) + goto exit; + if (i%4 == 0) + UpdateFriends(); + + if (m_iStatus != ID_STATUS_ONLINE) + goto exit; + UpdateStatuses(new_account, popups); + + if (m_iStatus != ID_STATUS_ONLINE) + goto exit; + UpdateMessages(new_account); + + if (new_account) // Not anymore! + { + new_account = false; + DBWriteContactSettingByte(0, m_szModuleName, TWITTER_KEY_NEW, 0); + } + + if (m_iStatus != ID_STATUS_ONLINE) + goto exit; + LOG("***** TwitterProto::MessageLoop going to sleep..."); + if (SleepEx(poll_rate*1000, true) == WAIT_IO_COMPLETION) + goto exit; + LOG("***** TwitterProto::MessageLoop waking up..."); + + popups = true; + } + +exit: + { + ScopedLock s(twitter_lock_); + twit_.set_credentials("", "", false); + } + LOG("***** Exiting TwitterProto::MessageLoop"); +} + +struct update_avatar +{ + update_avatar(HANDLE hContact, const std::string &url) : hContact(hContact), url(url) {} + HANDLE hContact; + std::string url; +}; + +void TwitterProto::UpdateAvatarWorker(void *p) +{ + if (p == 0) + return; + std::auto_ptr<update_avatar> data( static_cast<update_avatar*>(p)); + DBVARIANT dbv; + + if (DBGetContactSettingTString(data->hContact, m_szModuleName, TWITTER_KEY_UN, &dbv)) + return; + + std::string ext = data->url.substr(data->url.rfind('.')); + std::string filename = GetAvatarFolder() + '\\' + dbv.pszVal + ext; + DBFreeVariant(&dbv); + + PROTO_AVATAR_INFORMATION ai = {sizeof(ai)}; + ai.hContact = data->hContact; + ai.format = ext_to_format(ext); + strncpy(ai.filename, filename.c_str(), MAX_PATH); + + LOG("***** Updating avatar: %s", data->url.c_str()); + WaitForSingleObjectEx(avatar_lock_, INFINITE, true); + if (CallService(MS_SYSTEM_TERMINATED, 0, 0)) + { + LOG("***** Terminating avatar update early: %s", data->url.c_str()); + return; + } + + if (save_url(hAvatarNetlib_, data->url, filename)) + { + DBWriteContactSettingString(data->hContact, m_szModuleName, TWITTER_KEY_AV_URL, + data->url.c_str()); + ProtoBroadcastAck(m_szModuleName, data->hContact, ACKTYPE_AVATAR, + ACKRESULT_SUCCESS, &ai, 0); + } + else + ProtoBroadcastAck(m_szModuleName, data->hContact, ACKTYPE_AVATAR, + ACKRESULT_FAILED, &ai, 0); + ReleaseMutex(avatar_lock_); + LOG("***** Done avatar: %s", data->url.c_str()); +} + +void TwitterProto::UpdateAvatar(HANDLE hContact, const std::string &url, bool force) +{ + DBVARIANT dbv; + + if ( !force && + ( !DBGetContactSettingString(hContact, m_szModuleName, TWITTER_KEY_AV_URL, &dbv) && + url == dbv.pszVal)) + { + LOG("***** Avatar already up-to-date: %s", url.c_str()); + } + else + { + // TODO: more defaults (configurable?) + if (url == "http://static.twitter.com/images/default_profile_normal.png") + { + PROTO_AVATAR_INFORMATION ai = {sizeof(ai), hContact}; + + db_string_set(hContact, m_szModuleName, TWITTER_KEY_AV_URL, url.c_str()); + ProtoBroadcastAck(m_szModuleName, hContact, ACKTYPE_AVATAR, + ACKRESULT_SUCCESS, &ai, 0); + } + else + { + ForkThread(&TwitterProto::UpdateAvatarWorker, this, + new update_avatar(hContact, url)); + } + } + + DBFreeVariant(&dbv); +} + +void TwitterProto::UpdateFriends() +{ + try + { + ScopedLock s(twitter_lock_); + std::vector<twitter_user> friends = twit_.get_friends(); + s.Unlock(); + + for(std::vector<twitter_user>::iterator i=friends.begin(); i!=friends.end(); ++i) { + if (i->username == twit_.get_username()) + continue; + + HANDLE hContact = AddToClientList( _A2T(i->username.c_str()), i->status.text.c_str()); + UpdateAvatar(hContact, i->profile_image_url); + } + LOG("***** Friends list updated"); + } + catch(const bad_response &) + { + LOG("***** Bad response from server, signing off"); + SetStatus(ID_STATUS_OFFLINE); + } + catch(const std::exception &e) + { + ShowPopup( (std::string("While updating friends list, an error occurred: ") + +e.what()).c_str()); + LOG("***** Error updating friends list: %s", e.what()); + } + +} + +void TwitterProto::ShowContactPopup(HANDLE hContact, const std::tstring &text) +{ + if (!ServiceExists(MS_POPUP_ADDPOPUPT) || DBGetContactSettingByte(0, m_szModuleName, TWITTER_KEY_POPUP_SHOW, 0) == 0) + return; + + POPUPDATAT popup = {}; + popup.lchContact = hContact; + popup.iSeconds = db_dword_get(0, m_szModuleName, TWITTER_KEY_POPUP_TIMEOUT, 0); + + popup.colorBack = db_dword_get(0, m_szModuleName, TWITTER_KEY_POPUP_COLBACK, 0); + if (popup.colorBack == 0xFFFFFFFF) + popup.colorBack = GetSysColor(COLOR_WINDOW); + popup.colorText = db_dword_get(0, m_szModuleName, TWITTER_KEY_POPUP_COLTEXT, 0); + if (popup.colorBack == 0xFFFFFFFF) + popup.colorBack = GetSysColor(COLOR_WINDOWTEXT); + + DBVARIANT dbv; + if ( !DBGetContactSettingString(hContact, "CList", "MyHandle", &dbv) || + !DBGetContactSettingString(hContact, m_szModuleName, TWITTER_KEY_UN, &dbv)) + { + mbcs_to_tcs(CP_UTF8, dbv.pszVal, popup.lptzContactName, MAX_CONTACTNAME); + DBFreeVariant(&dbv); + } + + CallService(MS_POPUP_ADDPOPUPT, reinterpret_cast<WPARAM>(text.c_str()), 0); +} + +void TwitterProto::UpdateStatuses(bool pre_read, bool popups) +{ + try + { + ScopedLock s(twitter_lock_); + twitter::status_list updates = twit_.get_statuses(200, since_id_); + s.Unlock(); + + if (!updates.empty()) + since_id_ = std::max(since_id_, updates[0].status.id); + + for(twitter::status_list::reverse_iterator i=updates.rbegin(); i!=updates.rend(); ++i) + { + if (!pre_read && in_chat_) + UpdateChat(*i); + + if (i->username == twit_.get_username()) + continue; + + HANDLE hContact = AddToClientList( _A2T(i->username.c_str()), _T("")); + + DBEVENTINFO dbei = {sizeof(dbei)}; + + dbei.pBlob = (BYTE*)(i->status.text.c_str()); + dbei.cbBlob = i->status.text.size()+1; + dbei.eventType = TWITTER_DB_EVENT_TYPE_TWEET; + dbei.flags = DBEF_UTF; + //dbei.flags = DBEF_READ; + dbei.timestamp = static_cast<DWORD>(i->status.time); + dbei.szModule = m_szModuleName; + CallService(MS_DB_EVENT_ADD, (WPARAM)hContact, (LPARAM)&dbei); + + DBWriteContactSettingTString(hContact, "CList", "StatusMsg", i->status.text.c_str()); + + if ( !pre_read && popups ) + ShowContactPopup(hContact, i->status.text); + } + + db_pod_set(0, m_szModuleName, TWITTER_KEY_SINCEID, since_id_); + LOG("***** Status messages updated"); + } + catch(const bad_response &) + { + LOG("***** Bad response from server, signing off"); + SetStatus(ID_STATUS_OFFLINE); + } + catch(const std::exception &e) + { + ShowPopup( (std::string("While updating status messages, an error occurred: ") + +e.what()).c_str()); + LOG("***** Error updating status messages: %s", e.what()); + } +} + +void TwitterProto::UpdateMessages(bool pre_read) +{ + try + { + ScopedLock s(twitter_lock_); + twitter::status_list messages = twit_.get_direct(dm_since_id_); + s.Unlock(); + + if (messages.size()) + dm_since_id_ = std::max(dm_since_id_, messages[0].status.id); + + for(twitter::status_list::reverse_iterator i=messages.rbegin(); i!=messages.rend(); ++i) { + HANDLE hContact = AddToClientList( _A2T(i->username.c_str()), _T("")); + + PROTORECVEVENT recv = {}; + CCSDATA ccs = {}; + + recv.flags = PREF_TCHAR; + if (pre_read) + recv.flags |= PREF_CREATEREAD; + recv.szMessage = ( char* )i->status.text.c_str(); + recv.timestamp = static_cast<DWORD>(i->status.time); + + ccs.hContact = hContact; + ccs.szProtoService = PSR_MESSAGE; + ccs.wParam = ID_STATUS_ONLINE; + ccs.lParam = reinterpret_cast<LPARAM>(&recv); + CallService(MS_PROTO_CHAINRECV, 0, reinterpret_cast<LPARAM>(&ccs)); + } + + db_pod_set(0, m_szModuleName, TWITTER_KEY_DMSINCEID, dm_since_id_); + LOG("***** Direct messages updated"); + } + catch(const bad_response &) + { + LOG("***** Bad response from server, signing off"); + SetStatus(ID_STATUS_OFFLINE); + } + catch(const std::exception &e) + { + ShowPopup( (std::string("While updating direct messages, an error occurred: ") + +e.what()).c_str()); + LOG("***** Error updating direct messages: %s", e.what()); + } +} \ No newline at end of file diff --git a/protocols/Twitter/contacts.cpp b/protocols/Twitter/contacts.cpp new file mode 100644 index 0000000000..03aad22601 --- /dev/null +++ b/protocols/Twitter/contacts.cpp @@ -0,0 +1,288 @@ +/* +Copyright 2009 Jim Porter + +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, see <http://www.gnu.org/licenses/>. +*/ + +#include "common.h" +#include "proto.h" + + +void TwitterProto::AddToListWorker(void *p) +{ + // TODO: what happens if there is an error? + if (p == 0) + return; + TCHAR *name = static_cast<TCHAR*>(p); + + try + { + ScopedLock s(twitter_lock_); + twitter_user user = twit_.add_friend(name); + s.Unlock(); + + HANDLE hContact = UsernameToHContact(name); + UpdateAvatar(hContact, user.profile_image_url); + } + catch(const std::exception &e) + { + ShowPopup((std::string("While adding a friend, an error occurred: ") + +e.what()).c_str()); + LOG("***** Error adding friend: %s", e.what()); + } + mir_free(name); +} + +HANDLE TwitterProto::AddToList(int flags, PROTOSEARCHRESULT *result) +{ + if (m_iStatus != ID_STATUS_ONLINE) + return 0; + + ForkThread(&TwitterProto::AddToListWorker, this, mir_tstrdup(result->nick)); + return AddToClientList(result->nick, _T("")); +} + +// ************************* + +void TwitterProto::UpdateInfoWorker(void *hContact) +{ + twitter_user user; + std::tstring username; + + DBVARIANT dbv; + if ( !DBGetContactSettingTString(hContact, m_szModuleName, TWITTER_KEY_UN, &dbv)) + { + username = dbv.ptszVal; + DBFreeVariant(&dbv); + } + else + return; + + { + ScopedLock s(twitter_lock_); + twit_.get_info(username, &user); + } + + UpdateAvatar(hContact, user.profile_image_url, true); + ProtoBroadcastAck(m_szModuleName, hContact, ACKTYPE_GETINFO, ACKRESULT_SUCCESS, 0, 0); +} + +int TwitterProto::GetInfo(HANDLE hContact, int info_type) +{ + if (m_iStatus != ID_STATUS_ONLINE) + return 1; + + if (!IsMyContact(hContact)) // Do nothing for chat rooms + return 1; + + if (info_type == 0) // From clicking "Update" in the Userinfo dialog + { + ForkThread(&TwitterProto::UpdateInfoWorker, this, hContact); + return 0; + } + + return 1; +} + +// ************************* + +struct search_query +{ + search_query(const std::tstring &query, bool by_email) : query(query), by_email(by_email) + {} + std::tstring query; + bool by_email; +}; + +void TwitterProto::DoSearch(void *p) +{ + if (p == 0) + return; + search_query *query = static_cast<search_query*>(p); + + twitter_user info; + PROTOSEARCHRESULT psr = {sizeof(psr)}; + + bool found; + try + { + ScopedLock s(twitter_lock_); + if (query->by_email) + found = twit_.get_info_by_email(query->query, &info); + else + found = twit_.get_info(query->query, &info); + } + catch(const std::exception &e) + { + ShowPopup( (std::string("While searching for contacts, an error occurred: ") + +e.what()).c_str()); + LOG("***** Error searching for contacts: %s", e.what()); + } + + if (found) + { + psr.nick = ( TCHAR* )info.username. c_str(); + psr.firstName = ( TCHAR* )info.real_name.c_str(); + + ProtoBroadcastAck(m_szModuleName, 0, ACKTYPE_SEARCH, ACKRESULT_DATA, (HANDLE)1, + (LPARAM)&psr); + ProtoBroadcastAck(m_szModuleName, 0, ACKTYPE_SEARCH, ACKRESULT_SUCCESS, (HANDLE)1, 0); + } + else + { + ProtoBroadcastAck(m_szModuleName, 0, ACKTYPE_SEARCH, ACKRESULT_SUCCESS, (HANDLE)1, 0); + } + + delete query; +} + +HANDLE TwitterProto::SearchBasic(const TCHAR *username) +{ + ForkThread(&TwitterProto::DoSearch, this, new search_query(username, false)); + return (HANDLE)1; +} + +HANDLE TwitterProto::SearchByEmail(const TCHAR *email) +{ + ForkThread(&TwitterProto::DoSearch, this, new search_query(email, true)); + return (HANDLE)1; +} + +// ************************* + +void TwitterProto::GetAwayMsgWorker(void *hContact) +{ + if (hContact == 0) + return; + + DBVARIANT dbv; + if ( !DBGetContactSettingTString(hContact, "CList", "StatusMsg", &dbv)) { + ProtoBroadcastAck(m_szModuleName, hContact, ACKTYPE_AWAYMSG, ACKRESULT_SUCCESS, (HANDLE)1, (LPARAM)dbv.ptszVal); + DBFreeVariant(&dbv); + } + else ProtoBroadcastAck(m_szModuleName, hContact, ACKTYPE_AWAYMSG, ACKRESULT_FAILED, (HANDLE)1, 0); +} + +HANDLE TwitterProto::GetAwayMsg(HANDLE hContact) +{ + ForkThread(&TwitterProto::GetAwayMsgWorker, this, hContact); + return (HANDLE)1; +} + +int TwitterProto::OnContactDeleted(WPARAM wParam, LPARAM lParam) +{ + if (m_iStatus != ID_STATUS_ONLINE) + return 0; + + const HANDLE hContact = reinterpret_cast<HANDLE>(wParam); + + if (!IsMyContact(hContact)) + return 0; + + DBVARIANT dbv; + if ( !DBGetContactSettingTString(hContact, m_szModuleName, TWITTER_KEY_UN, &dbv)) { + if ( in_chat_ ) + DeleteChatContact(dbv.ptszVal); + + ScopedLock s(twitter_lock_); + twit_.remove_friend(dbv.ptszVal); // Be careful about this until Miranda is fixed + DBFreeVariant(&dbv); + } + return 0; +} + +// ************************* + +bool TwitterProto::IsMyContact(HANDLE hContact, bool include_chat) +{ + const char *proto = reinterpret_cast<char*>( CallService(MS_PROTO_GETCONTACTBASEPROTO, + reinterpret_cast<WPARAM>(hContact), 0)); + + if (proto && strcmp(m_szModuleName, proto) == 0) + { + if (include_chat) + return true; + else + return DBGetContactSettingByte(hContact, m_szModuleName, "ChatRoom", 0) == 0; + } + else + return false; +} + +HANDLE TwitterProto::UsernameToHContact(const TCHAR *name) +{ + for(HANDLE hContact = (HANDLE)CallService(MS_DB_CONTACT_FINDFIRST, 0, 0); + hContact; + hContact = (HANDLE)CallService(MS_DB_CONTACT_FINDNEXT, (WPARAM)hContact, 0)) + { + if (!IsMyContact(hContact)) + continue; + + DBVARIANT dbv; + if ( !DBGetContactSettingTString(hContact, m_szModuleName, TWITTER_KEY_UN, &dbv)) { + if ( lstrcmp(name, dbv.ptszVal) == 0) { + DBFreeVariant(&dbv); + return hContact; + } + DBFreeVariant(&dbv); + } + } + + return 0; +} + +HANDLE TwitterProto::AddToClientList(const TCHAR *name, const TCHAR *status) +{ + // First, check if this contact exists + HANDLE hContact = UsernameToHContact(name); + if (hContact) + return hContact; + + if (in_chat_) + AddChatContact(name); + + // If not, make a new contact! + hContact = (HANDLE)CallService(MS_DB_CONTACT_ADD, 0, 0); + if (hContact ) { + if (CallService(MS_PROTO_ADDTOCONTACT, (WPARAM)hContact, (LPARAM)m_szModuleName) == 0) { + DBWriteContactSettingTString(hContact, m_szModuleName, TWITTER_KEY_UN, name); + DBWriteContactSettingWord(hContact, m_szModuleName, "Status", ID_STATUS_ONLINE); + DBWriteContactSettingTString(hContact, "CList", "StatusMsg", status); + + std::string url = profile_base_url(twit_.get_base_url()) + http::url_encode((char*)_T2A(name)); + DBWriteContactSettingString(hContact, m_szModuleName, "Homepage", url.c_str()); + + return hContact; + } + + CallService(MS_DB_CONTACT_DELETE, (WPARAM)hContact, 0); + } + + return 0; +} + +void TwitterProto::SetAllContactStatuses(int status) +{ + for(HANDLE hContact = (HANDLE)CallService(MS_DB_CONTACT_FINDFIRST, 0, 0); + hContact; + hContact = (HANDLE)CallService(MS_DB_CONTACT_FINDNEXT, (WPARAM)hContact, 0)) + { + if (!IsMyContact(hContact)) + continue; + + DBWriteContactSettingWord(hContact, m_szModuleName, "Status", status); + } + + SetChatStatus(status); +} \ No newline at end of file diff --git a/protocols/Twitter/http.cpp b/protocols/Twitter/http.cpp new file mode 100644 index 0000000000..63218ca616 --- /dev/null +++ b/protocols/Twitter/http.cpp @@ -0,0 +1,39 @@ +/* +Copyright 2009 Jim Porter + +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, see <http://www.gnu.org/licenses/>. +*/ + +#include "common.h" +#include "http.h" + +std::string http::url_encode(const std::string &s) +{ + char *encoded = (char*)CallService( MS_NETLIB_URLENCODE, 0, ( LPARAM )s.c_str()); + std::string ret = encoded; + HeapFree(GetProcessHeap(),0,encoded); + + return ret; +} + +std::string http::url_encode(const std::wstring &s) +{ + char* data = mir_u2a( s.c_str()); + char *encoded = (char*)CallService( MS_NETLIB_URLENCODE, 0, ( LPARAM )data); + mir_free( data ); + std::string ret = encoded; + HeapFree(GetProcessHeap(),0,encoded); + + return ret; +} diff --git a/protocols/Twitter/http.h b/protocols/Twitter/http.h new file mode 100644 index 0000000000..04f5468b30 --- /dev/null +++ b/protocols/Twitter/http.h @@ -0,0 +1,39 @@ +/* +Copyright 2009 Jim Porter + +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, see <http://www.gnu.org/licenses/>. +*/ + +#pragma once + +#include <string> + +namespace http +{ + enum method + { + get, + post + }; + + struct response + { + response() : code(0) {} + int code; + std::string data; + }; + + std::string url_encode(const std::string &); + std::string url_encode(const std::wstring &); +} \ No newline at end of file diff --git a/protocols/Twitter/icons/twitter.ico b/protocols/Twitter/icons/twitter.ico new file mode 100644 index 0000000000..2b6eaa1eae Binary files /dev/null and b/protocols/Twitter/icons/twitter.ico differ diff --git a/protocols/Twitter/main.cpp b/protocols/Twitter/main.cpp new file mode 100644 index 0000000000..d28cc30b65 --- /dev/null +++ b/protocols/Twitter/main.cpp @@ -0,0 +1,168 @@ +/* +Copyright 2009 Jim Porter + +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, see <http://www.gnu.org/licenses/>. +*/ + +#include "common.h" +#include "version.h" + +#include "proto.h" +#include "theme.h" + +#include "m_updater.h" + +PLUGINLINK *pluginLink; +MD5_INTERFACE md5i; +MM_INTERFACE mmi; +UTF8_INTERFACE utfi; +LIST_INTERFACE li; +int hLangpack = 0; + +CLIST_INTERFACE* pcli; + +HINSTANCE g_hInstance; + +PLUGININFOEX pluginInfo={ + sizeof(PLUGININFOEX), + "Twitter Plugin", + __VERSION_DWORD, + "Provides basic support for Twitter protocol. [Built: "__DATE__" "__TIME__"]", + "dentist", + "", + " 2009-2010 dentist", + "http://github.com/dentist/miranda-twitter", + UNICODE_AWARE, //not transient + 0, //doesn't replace anything built-in + //{BC09A71B-B86E-4d33-B18D-82D30451DD3C} + { 0xbc09a71b, 0xb86e, 0x4d33, { 0xb1, 0x8d, 0x82, 0xd3, 0x4, 0x51, 0xdd, 0x3c } } +}; + +///////////////////////////////////////////////////////////////////////////// +// Protocol instances +static int compare_protos(const TwitterProto *p1, const TwitterProto *p2) +{ + return _tcscmp(p1->m_tszUserName, p2->m_tszUserName); +} + +OBJLIST<TwitterProto> g_Instances(1, compare_protos); + +DWORD WINAPI DllMain(HINSTANCE hInstance,DWORD,LPVOID) +{ + g_hInstance = hInstance; + return TRUE; +} + +extern "C" __declspec(dllexport) PLUGININFOEX* MirandaPluginInfoEx(DWORD mirandaVersion) +{ + return &pluginInfo; +} + +///////////////////////////////////////////////////////////////////////////////////////// +// Interface information + +static const MUUID interfaces[] = {MIID_PROTOCOL, MIID_LAST}; + +extern "C" __declspec(dllexport) const MUUID* MirandaPluginInterfaces(void) +{ + return interfaces; +} + +///////////////////////////////////////////////////////////////////////////////////////// +// Load + +static PROTO_INTERFACE* protoInit(const char *proto_name,const TCHAR *username ) +{ + TwitterProto *proto = new TwitterProto(proto_name,username); + g_Instances.insert(proto); + return proto; +} + +static int protoUninit(PROTO_INTERFACE *proto) +{ + g_Instances.remove(static_cast<TwitterProto*>(proto)); + return 0; +} + +int OnModulesLoaded(WPARAM,LPARAM) +{ + if (ServiceExists(MS_UPDATE_REGISTER)) + { + Update upd = {sizeof(upd)}; + char curr_version[30]; + + upd.szComponentName = pluginInfo.shortName; + + upd.szUpdateURL = UPDATER_AUTOREGISTER; + + upd.szBetaVersionURL = "http://www.teamboxel.com/update/twitter/version"; + upd.szBetaChangelogURL = "http://code.google.com/p/miranda-twitter/wiki/Changes"; + upd.pbBetaVersionPrefix = reinterpret_cast<BYTE*>("Twitter "); + upd.cpbBetaVersionPrefix = strlen(reinterpret_cast<char*>(upd.pbBetaVersionPrefix)); +#ifdef UNICODE + upd.szBetaUpdateURL = "http://www.teamboxel.com/update/twitter"; +#else + upd.szBetaUpdateURL = "http://www.teamboxel.com/update/twitter/ansi"; +#endif + + upd.pbVersion = reinterpret_cast<BYTE*>( CreateVersionStringPlugin( + reinterpret_cast<PLUGININFO*>(&pluginInfo),curr_version)); + upd.cpbVersion = strlen(reinterpret_cast<char*>(upd.pbVersion)); + + CallService(MS_UPDATE_REGISTER,0,(LPARAM)&upd); + } + + return 0; +} + +static HANDLE g_hEvents[1]; + +extern "C" int __declspec(dllexport) Load(PLUGINLINK *link) +{ + pluginLink = link; + mir_getMMI(&mmi); + mir_getMD5I(&md5i); + mir_getUTFI(&utfi); + mir_getLI(&li); + mir_getLP(&pluginInfo); + + pcli = reinterpret_cast<CLIST_INTERFACE*>( CallService( + MS_CLIST_RETRIEVE_INTERFACE,0,reinterpret_cast<LPARAM>(g_hInstance))); + + PROTOCOLDESCRIPTOR pd = {sizeof(pd)}; + pd.szName = "Twitter"; + pd.type = PROTOTYPE_PROTOCOL; + pd.fnInit = protoInit; + pd.fnUninit = protoUninit; + CallService(MS_PROTO_REGISTERMODULE,0,reinterpret_cast<LPARAM>(&pd)); + + g_hEvents[0] = HookEvent(ME_SYSTEM_MODULESLOADED,OnModulesLoaded); + + InitIcons(); + InitContactMenus(); + + return 0; +} + +///////////////////////////////////////////////////////////////////////////////////////// +// Unload + +extern "C" int __declspec(dllexport) Unload(void) +{ + UninitContactMenus(); + for(size_t i=1; i<SIZEOF(g_hEvents); i++) + UnhookEvent(g_hEvents[i]); + + return 0; +} diff --git a/protocols/Twitter/proto.cpp b/protocols/Twitter/proto.cpp new file mode 100644 index 0000000000..44bd6a3ebc --- /dev/null +++ b/protocols/Twitter/proto.cpp @@ -0,0 +1,528 @@ +/* +Copyright 2009 Jim Porter + +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, see <http://www.gnu.org/licenses/>. +*/ + +#include "common.h" +#include "proto.h" + +#include "utility.h" +#include "theme.h" +#include "ui.h" + +#include "m_folders.h" +#include "m_historyevents.h" + +#include <algorithm> +#include <cstdio> +#include <ctime> +#include <direct.h> + +TwitterProto::TwitterProto(const char *proto_name, const TCHAR *username) +{ + m_szProtoName = mir_strdup (proto_name); + m_szModuleName = mir_strdup (proto_name); + m_tszUserName = mir_tstrdup(username); + + CreateProtoService(m_szModuleName, PS_CREATEACCMGRUI, + &TwitterProto::SvcCreateAccMgrUI, this); + CreateProtoService(m_szModuleName, PS_GETNAME, &TwitterProto::GetName, this); + CreateProtoService(m_szModuleName, PS_GETSTATUS, &TwitterProto::GetStatus, this); + + CreateProtoService(m_szModuleName, PS_JOINCHAT, &TwitterProto::OnJoinChat, this); + CreateProtoService(m_szModuleName, PS_LEAVECHAT, &TwitterProto::OnLeaveChat, this); + + CreateProtoService(m_szModuleName, PS_GETMYAVATAR, &TwitterProto::GetAvatar, this); + CreateProtoService(m_szModuleName, PS_SETMYAVATAR, &TwitterProto::SetAvatar, this); + + HookProtoEvent(ME_DB_CONTACT_DELETED, &TwitterProto::OnContactDeleted, this); + HookProtoEvent(ME_CLIST_PREBUILDSTATUSMENU, &TwitterProto::OnBuildStatusMenu, this); + HookProtoEvent(ME_OPT_INITIALISE, &TwitterProto::OnOptionsInit, this); + + char *profile = Utils_ReplaceVars("%miranda_avatarcache%"); + def_avatar_folder_ = std::string(profile)+"\\"+m_szModuleName; + mir_free(profile); + hAvatarFolder_ = FoldersRegisterCustomPath(m_szModuleName, "Avatars", + def_avatar_folder_.c_str()); + + // Initialize hotkeys + char text[512]; + HOTKEYDESC hkd = {sizeof(hkd)}; + hkd.cbSize = sizeof(hkd); + hkd.pszName = text; + hkd.pszService = text; + hkd.pszSection = m_szModuleName; // Section title; TODO: use username? + + mir_snprintf(text, SIZEOF(text), "%s/Tweet", m_szModuleName); + hkd.pszDescription = "Send Tweet"; + CallService(MS_HOTKEY_REGISTER, 0, (LPARAM)&hkd); + + signon_lock_ = CreateMutex(0, false, 0); + avatar_lock_ = CreateMutex(0, false, 0); + twitter_lock_ = CreateMutex(0, false, 0); + + SetAllContactStatuses(ID_STATUS_OFFLINE); // In case we crashed last time +} + +TwitterProto::~TwitterProto() +{ + CloseHandle(twitter_lock_); + CloseHandle(avatar_lock_); + CloseHandle(signon_lock_); + + mir_free(m_szProtoName); + mir_free(m_szModuleName); + mir_free(m_tszUserName); + + if (hNetlib_) + Netlib_CloseHandle(hNetlib_); + if (hAvatarNetlib_) + Netlib_CloseHandle(hAvatarNetlib_); +} + +// ************************* + +DWORD TwitterProto::GetCaps(int type, HANDLE hContact) +{ + switch(type) + { + case PFLAGNUM_1: + return PF1_IM | PF1_MODEMSGRECV | PF1_BASICSEARCH | PF1_SEARCHBYEMAIL | + PF1_SERVERCLIST | PF1_CHANGEINFO; + case PFLAGNUM_2: + return PF2_ONLINE; + case PFLAGNUM_3: + return PF2_ONLINE; + case PFLAGNUM_4: + return PF4_NOCUSTOMAUTH | PF4_IMSENDUTF | PF4_AVATARS; + case PFLAG_MAXLENOFMESSAGE: + return 140; + case PFLAG_UNIQUEIDTEXT: + return (int) "Username"; + case PFLAG_UNIQUEIDSETTING: + return (int) TWITTER_KEY_UN; + } + return 0; +} + +HICON TwitterProto::GetIcon(int index) +{ + if (LOWORD(index) == PLI_PROTOCOL) + { + HICON ico = (HICON)CallService(MS_SKIN2_GETICON, 0, (LPARAM)"Twitter_twitter"); + return CopyIcon(ico); + } + else + return 0; +} + +// ************************* + +int TwitterProto::RecvMsg(HANDLE hContact, PROTORECVEVENT *pre) +{ + CCSDATA ccs = { hContact, PSR_MESSAGE, 0, reinterpret_cast<LPARAM>(pre) }; + return CallService(MS_PROTO_RECVMSG, 0, reinterpret_cast<LPARAM>(&ccs)); +} + +// ************************* + +struct send_direct +{ + send_direct(HANDLE hContact, const std::tstring &msg) : hContact(hContact), msg(msg) {} + HANDLE hContact; + std::tstring msg; +}; + +void TwitterProto::SendSuccess(void *p) +{ + if (p == 0) + return; + send_direct *data = static_cast<send_direct*>(p); + + DBVARIANT dbv; + if ( !DBGetContactSettingTString(data->hContact, m_szModuleName, TWITTER_KEY_UN, &dbv)) + { + ScopedLock s(twitter_lock_); + twit_.send_direct(dbv.ptszVal, data->msg); + + ProtoBroadcastAck(m_szModuleName, data->hContact, ACKTYPE_MESSAGE, ACKRESULT_SUCCESS, + (HANDLE)1, 0); + DBFreeVariant(&dbv); + } + + delete data; +} + +int TwitterProto::SendMsg(HANDLE hContact, int flags, const char *msg) +{ + if (m_iStatus != ID_STATUS_ONLINE) + return 0; + + std::tstring tMsg = _A2T(msg); + ForkThread(&TwitterProto::SendSuccess, this, new send_direct(hContact, tMsg)); + return 1; +} + +// ************************* + +int TwitterProto::SetStatus(int new_status) +{ + int old_status = m_iStatus; + if (new_status == m_iStatus) + return 0; + + m_iDesiredStatus = new_status; + + if (new_status == ID_STATUS_ONLINE) + { + if (old_status == ID_STATUS_CONNECTING) + return 0; + + m_iStatus = ID_STATUS_CONNECTING; + ProtoBroadcastAck(m_szModuleName, 0, ACKTYPE_STATUS, ACKRESULT_SUCCESS, + (HANDLE)old_status, m_iStatus); + + ForkThread(&TwitterProto::SignOn, this); + } + else if (new_status == ID_STATUS_OFFLINE) + { + m_iStatus = m_iDesiredStatus; + SetAllContactStatuses(ID_STATUS_OFFLINE); + + ProtoBroadcastAck(m_szModuleName, 0, ACKTYPE_STATUS, ACKRESULT_SUCCESS, + (HANDLE)old_status, m_iStatus); + } + + return 0; +} + +// ************************* + +int TwitterProto::OnEvent(PROTOEVENTTYPE event, WPARAM wParam, LPARAM lParam) +{ + switch(event) + { + case EV_PROTO_ONLOAD: return OnModulesLoaded(wParam, lParam); + case EV_PROTO_ONEXIT: return OnPreShutdown (wParam, lParam); + case EV_PROTO_ONOPTIONS: return OnOptionsInit (wParam, lParam); + } + + return 1; +} + +// ************************* + +int TwitterProto::SvcCreateAccMgrUI(WPARAM wParam, LPARAM lParam) +{ + return (int)CreateDialogParam(g_hInstance, MAKEINTRESOURCE(IDD_TWITTERACCOUNT), + (HWND)lParam, first_run_dialog, (LPARAM)this ); +} + +int TwitterProto::GetName(WPARAM wParam, LPARAM lParam) +{ + lstrcpynA(reinterpret_cast<char*>(lParam), m_szProtoName, wParam); + return 0; +} + +int TwitterProto::GetStatus(WPARAM wParam, LPARAM lParam) +{ + return m_iStatus; +} + +int TwitterProto::ReplyToTweet(WPARAM wParam, LPARAM lParam) +{ + // TODO: support replying to tweets instead of just users + HANDLE hContact = reinterpret_cast<HANDLE>(wParam); + + HWND hDlg = CreateDialogParam(g_hInstance, MAKEINTRESOURCE(IDD_TWEET), + (HWND)0, tweet_proc, reinterpret_cast<LPARAM>(this)); + + DBVARIANT dbv; + if ( !DBGetContactSettingTString(hContact, m_szModuleName, TWITTER_KEY_UN, &dbv)) { + SendMessage(hDlg, WM_SETREPLY, reinterpret_cast<WPARAM>(dbv.ptszVal), 0); + DBFreeVariant(&dbv); + } + + ShowWindow(hDlg, SW_SHOW); + + return 0; +} + +int TwitterProto::VisitHomepage(WPARAM wParam, LPARAM lParam) +{ + HANDLE hContact = reinterpret_cast<HANDLE>(wParam); + + DBVARIANT dbv; + if ( !DBGetContactSettingString(hContact, m_szModuleName, "Homepage", &dbv)) { + CallService(MS_UTILS_OPENURL, 1, reinterpret_cast<LPARAM>(dbv.pszVal)); + DBFreeVariant(&dbv); + } + else { + // TODO: remove this + if ( !DBGetContactSettingString(hContact, m_szModuleName, TWITTER_KEY_UN, &dbv)) { + std::string url = profile_base_url(twit_.get_base_url()) + http::url_encode(dbv.pszVal); + DBWriteContactSettingString(hContact, m_szModuleName, "Homepage", url.c_str()); + + CallService(MS_UTILS_OPENURL, 1, reinterpret_cast<LPARAM>(url.c_str())); + DBFreeVariant(&dbv); + } + } + + return 0; +} + +// ************************* + +int TwitterProto::OnBuildStatusMenu(WPARAM wParam, LPARAM lParam) +{ + HGENMENU hRoot = pcli->pfnGetProtocolMenu(m_szModuleName); + if (hRoot == NULL) + return 0; + + CLISTMENUITEM mi = {sizeof(mi)}; + + char text[200]; + strcpy(text, m_szModuleName); + char *tDest = text+strlen(text); + mi.pszService = text; + + mi.hParentMenu = hRoot; + mi.flags = CMIF_ICONFROMICOLIB|CMIF_ROOTHANDLE; + mi.position = 1001; + + HANDLE m_hMenuRoot = reinterpret_cast<HGENMENU>( CallService( + MS_CLIST_ADDSTATUSMENUITEM, 0, reinterpret_cast<LPARAM>(&mi))); + + // "Send Tweet..." + CreateProtoService(m_szModuleName, "/Tweet", &TwitterProto::OnTweet, this); + strcpy(tDest, "/Tweet"); + mi.pszName = LPGEN("Send Tweet..."); + mi.popupPosition = 200001; + mi.icolibItem = GetIconHandle("tweet"); + HANDLE m_hMenuBookmarks = reinterpret_cast<HGENMENU>( CallService( + MS_CLIST_ADDSTATUSMENUITEM, 0, reinterpret_cast<LPARAM>(&mi))); + + return 0; +} + +int TwitterProto::OnOptionsInit(WPARAM wParam, LPARAM lParam) +{ + OPTIONSDIALOGPAGE odp = {sizeof(odp)}; + odp.position = 271828; + odp.hInstance = g_hInstance; + odp.ptszGroup = LPGENT("Network"); + odp.ptszTitle = m_tszUserName; + odp.dwInitParam = LPARAM(this); + odp.flags = ODPF_BOLDGROUPS | ODPF_TCHAR; + + odp.ptszTab = LPGENT("Basic"); + odp.pszTemplate = MAKEINTRESOURCEA(IDD_OPTIONS); + odp.pfnDlgProc = options_proc; + CallService(MS_OPT_ADDPAGE, wParam, (LPARAM)&odp); + + if (ServiceExists(MS_POPUP_ADDPOPUPT)) + { + odp.ptszTab = LPGENT("Popups"); + odp.pszTemplate = MAKEINTRESOURCEA(IDD_OPTIONS_POPUPS); + odp.pfnDlgProc = popup_options_proc; + CallService(MS_OPT_ADDPAGE, wParam, (LPARAM)&odp); + } + + return 0; +} + +int TwitterProto::OnTweet(WPARAM wParam, LPARAM lParam) +{ + if (m_iStatus != ID_STATUS_ONLINE) + return 1; + + HWND hDlg = CreateDialogParam(g_hInstance, MAKEINTRESOURCE(IDD_TWEET), + (HWND)0, tweet_proc, reinterpret_cast<LPARAM>(this)); + ShowWindow(hDlg, SW_SHOW); + return 0; +} + +int TwitterProto::OnModulesLoaded(WPARAM wParam, LPARAM lParam) +{ + TCHAR descr[512]; + NETLIBUSER nlu = {sizeof(nlu)}; + nlu.flags = NUF_OUTGOING | NUF_INCOMING | NUF_HTTPCONNS | NUF_TCHAR; + nlu.szSettingsModule = m_szModuleName; + + // Create standard network connection + mir_sntprintf(descr, SIZEOF(descr), TranslateT("%s server connection"), m_tszUserName); + nlu.ptszDescriptiveName = descr; + hNetlib_ = (HANDLE)CallService(MS_NETLIB_REGISTERUSER, 0, (LPARAM)&nlu); + if (hNetlib_ == 0) + MessageBoxA(0, "Unable to get Netlib connection for Twitter", "", 0); + + // Create avatar network connection (TODO: probably remove this) + char module[512]; + mir_snprintf(module, SIZEOF(module), "%sAv", m_szModuleName); + nlu.szSettingsModule = module; + mir_sntprintf(descr, SIZEOF(descr), TranslateT("%s avatar connection"), m_tszUserName); + nlu.ptszDescriptiveName = descr; + hAvatarNetlib_ = (HANDLE)CallService(MS_NETLIB_REGISTERUSER, 0, (LPARAM)&nlu); + if (hAvatarNetlib_ == 0) + MessageBoxA(0, "Unable to get avatar Netlib connection for Twitter", "", 0); + + twit_.set_handle(hNetlib_); + + GCREGISTER gcr = {sizeof(gcr)}; + gcr.pszModule = m_szModuleName; + gcr.pszModuleDispName = m_szModuleName; + gcr.iMaxText = 140; + CallService(MS_GC_REGISTER, 0, reinterpret_cast<LPARAM>(&gcr)); + + if (ServiceExists(MS_HISTORYEVENTS_REGISTER)) + { + HISTORY_EVENT_HANDLER heh = {0}; + heh.cbSize = sizeof(heh); + heh.module = m_szModuleName; + heh.name = "tweet"; + heh.description = "Tweet"; + heh.eventType = TWITTER_DB_EVENT_TYPE_TWEET; + heh.defaultIconName = "Twitter_tweet"; + heh.flags = HISTORYEVENTS_FLAG_SHOW_IM_SRMM + | HISTORYEVENTS_FLAG_EXPECT_CONTACT_NAME_BEFORE +// Not sure: | HISTORYEVENTS_FLAG_FLASH_MSG_WINDOW + | HISTORYEVENTS_REGISTERED_IN_ICOLIB; + CallService(MS_HISTORYEVENTS_REGISTER, (WPARAM) &heh, 0); + } + else + { + DBEVENTTYPEDESCR evt = {sizeof(evt)}; + evt.eventType = TWITTER_DB_EVENT_TYPE_TWEET; + evt.module = m_szModuleName; + evt.descr = "Tweet"; + evt.flags = DETF_HISTORY | DETF_MSGWINDOW; + CallService(MS_DB_EVENT_REGISTERTYPE, 0, reinterpret_cast<LPARAM>(&evt)); + } + + return 0; +} + +int TwitterProto::OnPreShutdown(WPARAM wParam, LPARAM lParam) +{ + Netlib_Shutdown(hNetlib_); + Netlib_Shutdown(hAvatarNetlib_); + return 0; +} + +int TwitterProto::OnPrebuildContactMenu(WPARAM wParam, LPARAM lParam) +{ + HANDLE hContact = reinterpret_cast<HANDLE>(wParam); + if (IsMyContact(hContact)) + ShowContactMenus(true); + + return 0; +} + +void TwitterProto::ShowPopup(const wchar_t *text) +{ + POPUPDATAT popup = {}; + _sntprintf(popup.lptzContactName, MAX_CONTACTNAME, TranslateT("%s Protocol"), m_tszUserName); + wcs_to_tcs(CP_UTF8, text, popup.lptzText, MAX_SECONDLINE); + + if (ServiceExists(MS_POPUP_ADDPOPUPT)) + CallService(MS_POPUP_ADDPOPUPT, reinterpret_cast<WPARAM>(&popup), 0); + else + MessageBox(0, popup.lptzText, popup.lptzContactName, 0); +} + +void TwitterProto::ShowPopup(const char *text) +{ + POPUPDATAT popup = {}; + _sntprintf(popup.lptzContactName, MAX_CONTACTNAME, TranslateT("%s Protocol"), m_tszUserName); + mbcs_to_tcs(CP_UTF8, text, popup.lptzText, MAX_SECONDLINE); + + if (ServiceExists(MS_POPUP_ADDPOPUPT)) + CallService(MS_POPUP_ADDPOPUPT, reinterpret_cast<WPARAM>(&popup), 0); + else + MessageBox(0, popup.lptzText, popup.lptzContactName, 0); +} + +int TwitterProto::LOG(const char *fmt, ...) +{ + va_list va; + char text[1024]; + if (!hNetlib_) + return 0; + + va_start(va, fmt); + mir_vsnprintf(text, sizeof(text), fmt, va); + va_end(va); + + return CallService(MS_NETLIB_LOG, (WPARAM)hNetlib_, (LPARAM)text); +} + +// TODO: the more I think about it, the more I think all twit.* methods should +// be in MessageLoop +void TwitterProto::SendTweetWorker(void *p) +{ + if (p == 0) + return; + + TCHAR *text = static_cast<TCHAR*>(p); + + ScopedLock s(twitter_lock_); + twit_.set_status(text); + + mir_free(text); +} + +void TwitterProto::UpdateSettings() +{ + if (db_byte_get(0, m_szModuleName, TWITTER_KEY_CHATFEED, 0)) + { + if (!in_chat_) + OnJoinChat(0, 0); + } + else + { + if (in_chat_) + OnLeaveChat(0, 0); + + for(HANDLE hContact = (HANDLE)CallService(MS_DB_CONTACT_FINDFIRST, 0, 0); + hContact; + hContact = (HANDLE)CallService(MS_DB_CONTACT_FINDNEXT, (WPARAM)hContact, 0)) + { + if (!IsMyContact(hContact, true)) + continue; + + if (db_byte_get(hContact, m_szModuleName, "ChatRoom", 0)) + CallService(MS_DB_CONTACT_DELETE, reinterpret_cast<WPARAM>(hContact), 0); + } + } +} + +std::string TwitterProto::GetAvatarFolder() +{ + char path[MAX_PATH]; + if (hAvatarFolder_ && FoldersGetCustomPath(hAvatarFolder_, path, sizeof(path), "") == 0) + return path; + else + return def_avatar_folder_; +} + +int TwitterProto::GetAvatar(WPARAM, LPARAM) +{ + return 0; +} + +int TwitterProto::SetAvatar(WPARAM, LPARAM) +{ + return 0; +} \ No newline at end of file diff --git a/protocols/Twitter/proto.h b/protocols/Twitter/proto.h new file mode 100644 index 0000000000..af7a43d321 --- /dev/null +++ b/protocols/Twitter/proto.h @@ -0,0 +1,179 @@ +/* +Copyright 2009 Jim Porter + +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, see <http://www.gnu.org/licenses/>. +*/ + +#pragma once + +#include "utility.h" + +#include <m_protoint.h> + +class TwitterProto : public PROTO_INTERFACE +{ +public: + TwitterProto(const char *, const TCHAR *); + ~TwitterProto(); + + __inline void* operator new(size_t size) + { + return calloc(1, size); + } + __inline void operator delete(void *p) + { + free(p); + } + + inline const char * ModuleName() const + { + return m_szModuleName; + } + + //PROTO_INTERFACE + + virtual HANDLE __cdecl AddToList(int, PROTOSEARCHRESULT *); + virtual HANDLE __cdecl AddToListByEvent(int, int, HANDLE); + + virtual int __cdecl Authorize(HANDLE); + virtual int __cdecl AuthDeny(HANDLE, const TCHAR *); + virtual int __cdecl AuthRecv(HANDLE, PROTORECVEVENT *); + virtual int __cdecl AuthRequest(HANDLE, const TCHAR *); + + virtual HANDLE __cdecl ChangeInfo(int, void *); + + virtual HANDLE __cdecl FileAllow(HANDLE, HANDLE, const TCHAR *); + virtual int __cdecl FileCancel(HANDLE, HANDLE); + virtual int __cdecl FileDeny(HANDLE, HANDLE, const TCHAR *); + virtual int __cdecl FileResume(HANDLE, int *, const TCHAR **); + + virtual DWORD __cdecl GetCaps(int, HANDLE = 0); + virtual HICON __cdecl GetIcon(int); + virtual int __cdecl GetInfo(HANDLE, int); + + virtual HANDLE __cdecl SearchBasic(const TCHAR *); + virtual HANDLE __cdecl SearchByEmail(const TCHAR *); + virtual HANDLE __cdecl SearchByName(const TCHAR *, const TCHAR *, const TCHAR *); + virtual HWND __cdecl SearchAdvanced(HWND); + virtual HWND __cdecl CreateExtendedSearchUI(HWND); + + virtual int __cdecl RecvContacts(HANDLE, PROTORECVEVENT *); + virtual int __cdecl RecvFile(HANDLE, PROTORECVFILET *); + virtual int __cdecl RecvMsg(HANDLE, PROTORECVEVENT *); + virtual int __cdecl RecvUrl(HANDLE, PROTORECVEVENT *); + + virtual int __cdecl SendContacts(HANDLE, int, int, HANDLE *); + virtual HANDLE __cdecl SendFile(HANDLE, const TCHAR *, TCHAR **); + virtual int __cdecl SendMsg(HANDLE, int, const char *); + virtual int __cdecl SendUrl(HANDLE, int, const char *); + + virtual int __cdecl SetApparentMode(HANDLE, int); + virtual int __cdecl SetStatus(int); + + virtual HANDLE __cdecl GetAwayMsg(HANDLE); + virtual int __cdecl RecvAwayMsg(HANDLE, int, PROTORECVEVENT *); + virtual int __cdecl SendAwayMsg(HANDLE, HANDLE, const char *); + virtual int __cdecl SetAwayMsg(int, const TCHAR *); + + virtual int __cdecl UserIsTyping(HANDLE, int); + + virtual int __cdecl OnEvent(PROTOEVENTTYPE, WPARAM, LPARAM); + + void UpdateSettings(); + + // Services + int __cdecl SvcCreateAccMgrUI(WPARAM, LPARAM); + int __cdecl GetName(WPARAM, LPARAM); + int __cdecl GetStatus(WPARAM, LPARAM); + int __cdecl ReplyToTweet(WPARAM, LPARAM); + int __cdecl VisitHomepage(WPARAM, LPARAM); + int __cdecl GetAvatar(WPARAM, LPARAM); + int __cdecl SetAvatar(WPARAM, LPARAM); + + // Events + int __cdecl OnContactDeleted(WPARAM, LPARAM); + int __cdecl OnBuildStatusMenu(WPARAM, LPARAM); + int __cdecl OnOptionsInit(WPARAM, LPARAM); + int __cdecl OnTweet(WPARAM, LPARAM); + int __cdecl OnModulesLoaded(WPARAM, LPARAM); + int __cdecl OnPreShutdown(WPARAM, LPARAM); + int __cdecl OnPrebuildContactMenu(WPARAM, LPARAM); + int __cdecl OnChatOutgoing(WPARAM, LPARAM); + int __cdecl OnJoinChat(WPARAM, LPARAM); + int __cdecl OnLeaveChat(WPARAM, LPARAM); + + void __cdecl SendTweetWorker(void *); +private: + // Worker threads + void __cdecl AddToListWorker(void *p); + void __cdecl SendSuccess(void *); + void __cdecl DoSearch(void *); + void __cdecl SignOn(void *); + void __cdecl MessageLoop(void *); + void __cdecl GetAwayMsgWorker(void *); + void __cdecl UpdateAvatarWorker(void *); + void __cdecl UpdateInfoWorker(void *); + + bool NegotiateConnection(); + void UpdateStatuses(bool pre_read, bool popups); + void UpdateMessages(bool pre_read); + void UpdateFriends(); + void UpdateAvatar(HANDLE, const std::string &, bool force=false); + + void ShowPopup(const wchar_t *); + void ShowPopup(const char *); + void ShowContactPopup(HANDLE, const std::tstring &); + + bool IsMyContact(HANDLE, bool include_chat = false); + HANDLE UsernameToHContact(const TCHAR *); + HANDLE AddToClientList(const TCHAR *, const TCHAR *); + void SetAllContactStatuses(int); + + int LOG(const char *fmt, ...); + static void CALLBACK APC_callback(ULONG_PTR p); + + void UpdateChat(const twitter_user &update); + void AddChatContact(const TCHAR *name, const TCHAR *nick=0); + void DeleteChatContact(const TCHAR *name); + void SetChatStatus(int); + + std::string GetAvatarFolder(); + + HANDLE signon_lock_; + HANDLE avatar_lock_; + HANDLE twitter_lock_; + + HANDLE hNetlib_; + HANDLE hAvatarNetlib_; + HANDLE hMsgLoop_; + mir_twitter twit_; + + twitter_id since_id_; + twitter_id dm_since_id_; + + std::string def_avatar_folder_; + HANDLE hAvatarFolder_; + + bool in_chat_; +}; + +// TODO: remove this +inline std::string profile_base_url(const std::string &url) +{ + size_t x = url.find("://"); + if (x == std::string::npos) + return url.substr(0, url.find('/')+1); + else + return url.substr(0, url.find('/', x+3)+1); +} \ No newline at end of file diff --git a/protocols/Twitter/resource.h b/protocols/Twitter/resource.h new file mode 100644 index 0000000000..21fc21c049 --- /dev/null +++ b/protocols/Twitter/resource.h @@ -0,0 +1,47 @@ +//{{NO_DEPENDENCIES}} +// Microsoft Visual C++ generated include file. +// Used by twitter.rc +// +#define IDD_TWITTERACCOUNT 101 +#define IDI_TWITTER 102 +#define IDD_TWEET 103 +#define IDD_OPTIONS 104 +#define IDD_OPTIONS_POPUPS 107 +#define IDC_NEWACCOUNTLINK 1001 +#define IDC_UN 1002 +#define IDC_PW 1003 +#define IDC_TWEETMSG 1004 +#define IDC_CHARACTERS 1005 +#define IDC_USERDETAILS 1006 +#define IDC_MISC 1007 +#define IDC_CHATFEED 1008 +#define IDC_BASEURL 1009 +#define IDC_POLLRATE 1010 +#define IDC_COLBACK 1011 +#define IDC_COLTEXT 1012 +#define IDC_TIMEOUT_DEFAULT 1013 +#define IDC_TIMEOUT_CUSTOM 1014 +#define IDC_TIMEOUT_SPIN 1015 +#define IDC_TIMEOUT 1016 +#define IDC_TIMEOUT_PERMANENT 1017 +#define IDC_COL_WINDOWS 1018 +#define IDC_COL_POPUP 1019 +#define IDC_COL_CUSTOM 1020 +#define IDC_POPUPS_ENABLE 1021 +#define IDC_SHOWPOPUPS 1021 +#define IDC_PREVIEW 1022 +#define IDC_NOSIGNONPOPUPS 1023 +#define IDC_RECONNECT 1024 +#define IDC_COMBO1 1025 +#define IDC_SERVER 1025 + +// Next default values for new objects +// +#ifdef APSTUDIO_INVOKED +#ifndef APSTUDIO_READONLY_SYMBOLS +#define _APS_NEXT_RESOURCE_VALUE 108 +#define _APS_NEXT_COMMAND_VALUE 40001 +#define _APS_NEXT_CONTROL_VALUE 1026 +#define _APS_NEXT_SYMED_VALUE 101 +#endif +#endif diff --git a/protocols/Twitter/stubs.cpp b/protocols/Twitter/stubs.cpp new file mode 100644 index 0000000000..331a4cdeac --- /dev/null +++ b/protocols/Twitter/stubs.cpp @@ -0,0 +1,140 @@ +/* +Copyright 2009 Jim Porter + +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, see <http://www.gnu.org/licenses/>. +*/ + +#include "common.h" +#include "proto.h" + +HANDLE TwitterProto::AddToListByEvent(int flags,int iContact,HANDLE hDbEvent) +{ + return 0; +} + +int TwitterProto::Authorize(HANDLE hContact) +{ + return 0; +} + +int TwitterProto::AuthDeny(HANDLE hContact,const TCHAR *reason) +{ + return 0; +} + +int TwitterProto::AuthRecv(HANDLE hContact,PROTORECVEVENT *) +{ + return 0; +} + +int TwitterProto::AuthRequest(HANDLE hContact,const TCHAR *message) +{ + return 0; +} + +HANDLE TwitterProto::ChangeInfo(int type,void *info_data) +{ + MessageBoxA(0,"ChangeInfo","",0); + return 0; +} + +HANDLE TwitterProto::FileAllow(HANDLE hContact,HANDLE hTransfer,const TCHAR *path) +{ + return 0; +} + +int TwitterProto::FileCancel(HANDLE hContact,HANDLE hTransfer) +{ + return 0; +} + +int TwitterProto::FileDeny(HANDLE hContact,HANDLE hTransfer,const TCHAR *reason) +{ + return 0; +} + +int TwitterProto::FileResume(HANDLE hTransfer,int *action,const TCHAR **filename) +{ + return 0; +} + +HANDLE TwitterProto::SearchByName(const TCHAR *nick,const TCHAR *first_name, const TCHAR *last_name) +{ + return 0; +} + +HWND TwitterProto::SearchAdvanced(HWND owner) +{ + return 0; +} + +HWND TwitterProto::CreateExtendedSearchUI(HWND owner) +{ + return 0; +} + +int TwitterProto::RecvContacts(HANDLE hContact,PROTORECVEVENT *) +{ + return 0; +} + +int TwitterProto::RecvFile(HANDLE hContact,PROTORECVFILET *) +{ + return 0; +} + +int TwitterProto::RecvUrl(HANDLE hContact,PROTORECVEVENT *) +{ + return 0; +} + +int TwitterProto::SendContacts(HANDLE hContact,int flags,int nContacts,HANDLE *hContactsList) +{ + return 0; +} + +HANDLE TwitterProto::SendFile(HANDLE hContact,const TCHAR *desc, TCHAR **files) +{ + return 0; +} + +int TwitterProto::SendUrl(HANDLE hContact,int flags,const char *url) +{ + return 0; +} + +int TwitterProto::SetApparentMode(HANDLE hContact,int mode) +{ + return 0; +} + +int TwitterProto::RecvAwayMsg(HANDLE hContact,int mode,PROTORECVEVENT *evt) +{ + return 0; +} + +int TwitterProto::SendAwayMsg(HANDLE hContact,HANDLE hProcess,const char *msg) +{ + return 0; +} + +int TwitterProto::SetAwayMsg(int status,const TCHAR *msg) +{ + return 0; +} + +int TwitterProto::UserIsTyping(HANDLE hContact,int type) +{ + return 0; +} \ No newline at end of file diff --git a/protocols/Twitter/theme.cpp b/protocols/Twitter/theme.cpp new file mode 100644 index 0000000000..f35b3a5aa1 --- /dev/null +++ b/protocols/Twitter/theme.cpp @@ -0,0 +1,183 @@ +/* +Copyright 2009 Jim Porter + +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, see <http://www.gnu.org/licenses/>. +*/ + +#include "common.h" +#include "theme.h" +#include "proto.h" + +extern OBJLIST<TwitterProto> g_Instances; + +struct +{ + const char* name; + const char* descr; + int defIconID; + const char* section; +} +static const icons[] = +{ + { "twitter", "Twitter Icon", IDI_TWITTER }, + { "tweet", "Tweet", IDI_TWITTER }, + { "reply", "Reply to Tweet", IDI_TWITTER }, + + { "homepage", "Visit Homepage", 0, "core_main_2" }, +}; + +static HANDLE hIconLibItem[SIZEOF(icons)]; + +// TODO: uninit +void InitIcons(void) +{ + TCHAR szFile[MAX_PATH]; + GetModuleFileName(g_hInstance, szFile, SIZEOF(szFile)); + + char setting_name[100]; + char section_name[100]; + + SKINICONDESC sid = {0}; + sid.cbSize = sizeof(SKINICONDESC); + sid.ptszDefaultFile = szFile; + sid.cx = sid.cy = 16; + sid.pszName = setting_name; + sid.pszSection = section_name; + sid.flags = SIDF_PATH_TCHAR; + + for (int i=0; i<SIZEOF(icons); i++) + { + if (icons[i].defIconID) + { + mir_snprintf(setting_name,sizeof(setting_name),"%s_%s","Twitter",icons[i].name); + + if (icons[i].section) + { + mir_snprintf(section_name,sizeof(section_name),"%s/%s/%s",LPGEN("Protocols"), + LPGEN("Twitter"), icons[i].section); + } + else + { + mir_snprintf(section_name,sizeof(section_name),"%s/%s",LPGEN("Protocols"), + LPGEN("Twitter")); + } + + sid.pszDescription = (char*)icons[i].descr; + sid.iDefaultIndex = -icons[i].defIconID; + hIconLibItem[i] = (HANDLE)CallService(MS_SKIN2_ADDICON,0,(LPARAM)&sid); + } + else // External icons + { + hIconLibItem[i] = (HANDLE)CallService(MS_SKIN2_GETICONHANDLE,0, + (LPARAM)icons[i].section); + } + } +} + +HANDLE GetIconHandle(const char* name) +{ + for(size_t i=0; i<SIZEOF(icons); i++) + { + if (strcmp(icons[i].name,name) == 0) + return hIconLibItem[i]; + } + return 0; +} + + + +// Contact List menu stuff +static HANDLE g_hMenuItems[2]; +static HANDLE g_hMenuEvts[3]; + +// Helper functions +static TwitterProto * GetInstanceByHContact(HANDLE hContact) +{ + char *proto = reinterpret_cast<char*>( CallService(MS_PROTO_GETCONTACTBASEPROTO, + reinterpret_cast<WPARAM>(hContact),0)); + if (!proto) + return 0; + + for(int i=0; i<g_Instances.getCount(); i++) + if (!strcmp(proto,g_Instances[i].m_szModuleName)) + return &g_Instances[i]; + + return 0; +} + +template<int (__cdecl TwitterProto::*Fcn)(WPARAM,LPARAM)> +int GlobalService(WPARAM wParam,LPARAM lParam) +{ + TwitterProto *proto = GetInstanceByHContact(reinterpret_cast<HANDLE>(wParam)); + return proto ? (proto->*Fcn)(wParam,lParam) : 0; +} + +static int PrebuildContactMenu(WPARAM wParam,LPARAM lParam) +{ + ShowContactMenus(false); + + TwitterProto *proto = GetInstanceByHContact(reinterpret_cast<HANDLE>(wParam)); + return proto ? proto->OnPrebuildContactMenu(wParam,lParam) : 0; +} + +void InitContactMenus() +{ + g_hMenuEvts[0] = HookEvent(ME_CLIST_PREBUILDCONTACTMENU, + PrebuildContactMenu); + + CLISTMENUITEM mi = {sizeof(mi)}; + mi.flags = CMIF_NOTOFFLINE | CMIF_ICONFROMICOLIB; + + mi.position=-2000006000; + mi.icolibItem = GetIconHandle("reply"); + mi.pszName = LPGEN("Reply..."); + mi.pszService = "Twitter/ReplyToTweet"; + g_hMenuEvts[1] = CreateServiceFunction(mi.pszService, + GlobalService<&TwitterProto::ReplyToTweet>); + g_hMenuItems[0] = reinterpret_cast<HANDLE>( + CallService(MS_CLIST_ADDCONTACTMENUITEM,0,(LPARAM)&mi)); + + mi.position=-2000006000; + mi.icolibItem = GetIconHandle("homepage"); + mi.pszName = LPGEN("Visit Homepage"); + mi.pszService = "Twitter/VisitHomepage"; + g_hMenuEvts[2] = CreateServiceFunction(mi.pszService, + GlobalService<&TwitterProto::VisitHomepage>); + g_hMenuItems[1] = reinterpret_cast<HANDLE>( + CallService(MS_CLIST_ADDCONTACTMENUITEM,0,(LPARAM)&mi)); +} + +void UninitContactMenus() +{ + for(size_t i=0; i<SIZEOF(g_hMenuItems); i++) + CallService(MS_CLIST_REMOVECONTACTMENUITEM,(WPARAM)g_hMenuItems[i],0); + + UnhookEvent(g_hMenuEvts[0]); + for(size_t i=1; i<SIZEOF(g_hMenuEvts); i++) + DestroyServiceFunction(g_hMenuEvts[i]); +} + +void ShowContactMenus(bool show) +{ + for(size_t i=0; i<SIZEOF(g_hMenuItems); i++) + { + CLISTMENUITEM item = { sizeof(item) }; + item.flags = CMIM_FLAGS | CMIF_NOTOFFLINE; + if (!show) + item.flags |= CMIF_HIDDEN; + + CallService(MS_CLIST_MODIFYMENUITEM,reinterpret_cast<WPARAM>(g_hMenuItems[i]), + reinterpret_cast<LPARAM>(&item)); + } +} \ No newline at end of file diff --git a/protocols/Twitter/theme.h b/protocols/Twitter/theme.h new file mode 100644 index 0000000000..e74f5da2e3 --- /dev/null +++ b/protocols/Twitter/theme.h @@ -0,0 +1,25 @@ +/* +Copyright 2009 Jim Porter + +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, see <http://www.gnu.org/licenses/>. +*/ + +#pragma once + +void InitIcons(void); +HANDLE GetIconHandle(const char *name); + +void InitContactMenus(void); +void UninitContactMenus(void); +void ShowContactMenus(bool show); \ No newline at end of file diff --git a/protocols/Twitter/tinyjson.hpp b/protocols/Twitter/tinyjson.hpp new file mode 100644 index 0000000000..19e1210d84 --- /dev/null +++ b/protocols/Twitter/tinyjson.hpp @@ -0,0 +1,586 @@ +/* + * TinyJson 1.3.0 + * A Minimalistic JSON Reader Based On Boost.Spirit, Boost.Any, and Boost.Smart_Ptr. + * + * Copyright (c) 2008 Thomas Jansen (thomas@beef.de) + * + * Distributed under the Boost Software License, Version 1.0. (See accompanying + * file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + * + * See http://blog.beef.de/projects/tinyjson/ for documentation. + * + * (view source with tab-size = 3) + * + * 16 Mar 2009 - allow root of JSON to be array (Jim Porter) + * 29 Mar 2008 - use strict_real_p for number parsing, small cleanup (Thomas Jansen) + * 26 Mar 2008 - made json::grammar a template (Boris Schaeling) + * 20 Mar 2008 - optimized by using boost::shared_ptr (Thomas Jansen) + * 29 Jan 2008 - Small bugfixes (Thomas Jansen) + * 04 Jan 2008 - Released to the public (Thomas Jansen) + * 13 Nov 2007 - initial release (Thomas Jansen) * + * + * 29 Mar 2008 + */ + + +#ifndef TINYJSON_HPP +#define TINYJSON_HPP + +#include <boost/shared_ptr.hpp> +#include <boost/any.hpp> +#include <boost/spirit/core.hpp> +#include <boost/spirit/utility/loops.hpp> +#include <boost/lexical_cast.hpp> + +#include <string> +#include <stack> +#include <utility> +#include <deque> +#include <map> + + +namespace json +{ + boost::spirit::int_parser<long long> const + longlong_p = boost::spirit::int_parser<long long>(); + + // ========================================================================================================== + // === U N I C O D E _ C O N V E R T === + // ========================================================================================================== + + template< typename Char > + struct unicodecvt + { + static std::basic_string< Char > convert(int iUnicode) + { + return std::basic_string< Char >(1, static_cast< Char >(iUnicode)); + } + }; + + + // ---[ TEMPLATE SPECIALIZATION FOR CHAR ]-------------------------------------------------------------------- + + template<> + struct unicodecvt< char > + { + static std::string convert(int iUnicode) + { + std::string strString; + + if (iUnicode < 0x0080) + { + // character 0x0000 - 0x007f... + + strString.push_back(0x00 | ((iUnicode & 0x007f) >> 0)); + } + else if (iUnicode < 0x0800) + { + // character 0x0080 - 0x07ff... + + strString.push_back(0xc0 | ((iUnicode & 0x07c0) >> 6)); + strString.push_back(0x80 | ((iUnicode & 0x003f) >> 0)); + } + else + { + // character 0x0800 - 0xffff... + + strString.push_back(0xe0 | ((iUnicode & 0x00f000) >> 12)); + strString.push_back(0x80 | ((iUnicode & 0x000fc0) >> 6)); + strString.push_back(0x80 | ((iUnicode & 0x00003f) >> 0)); + } + + return strString; + } + }; + + + // ========================================================================================================== + // === T H E J S O N G R A M M A R === + // ========================================================================================================== + + template< typename Char > + class grammar : public boost::spirit::grammar< grammar< Char > > + { + public: + + // ---[ TYPEDEFINITIONS ]--------------------------------------------------------------------------------- + + typedef boost::shared_ptr< boost::any > variant; // pointer to a shared variant + + typedef std::stack< variant > stack; // a stack of json variants + typedef std::pair< std::basic_string< Char >, variant > pair; // a pair as it appears in json + + typedef std::deque< variant > array; // an array of json variants + typedef std::map< std::basic_string< Char >, variant > object; // an object with json pairs + + protected: + + // ---[ SEMANTIC ACTION: PUSH A STRING ON THE STACK (AND ENCODE AS UTF-8) ]------------------------------- + + struct push_string + { + stack & m_stack; + push_string(stack & stack) : m_stack(stack) { } + + template <typename Iterator> + void operator() (Iterator szStart, Iterator szEnd) const + { + // 1: skip the quotes... + + ++szStart; + --szEnd; + + // 2: traverse through the original string and check for escape codes.. + + std::basic_string< typename Iterator::value_type > strString; + + while(szStart < szEnd) + { + // 2.1: if it's no escape code, just append to the resulting string... + + if (*szStart != static_cast< typename Iterator::value_type >('\\')) + { + // 2.1.1: append the character... + + strString.push_back(*szStart); + } + else + { + // 2.1.2: otherwise, check the escape code... + + ++szStart; + + switch(*szStart) + { + default: + + strString.push_back(*szStart); + break; + + case 'b': + + strString.push_back(static_cast< typename Iterator::value_type >('\b')); + break; + + case 'f': + + strString.push_back(static_cast< typename Iterator::value_type >('\f')); + break; + + case 'n': + + strString.push_back(static_cast< typename Iterator::value_type >('\n')); + break; + + case 'r': + + strString.push_back(static_cast< typename Iterator::value_type >('\r')); + break; + + case 't': + + strString.push_back(static_cast< typename Iterator::value_type >('\t')); + break; + + case 'u': + { + // 2.1.2.1: convert the following hex value into an int... + + int iUnicode; + std::basic_istringstream< Char >(std::basic_string< typename Iterator::value_type >(&szStart[1], 4)) >> std::hex >> iUnicode; + + szStart += 4; + + // 2.1.2.2: append the unicode int... + + strString.append(unicodecvt< typename Iterator::value_type >::convert(iUnicode)); + } + } + } + + // 2.2: go on with the next character... + + ++szStart; + } + + // 3: finally, push the string on the stack... + + m_stack.push(variant(new boost::any(strString))); + } + }; + + + // ---[ SEMANTIC ACTION: PUSH A REAL ON THE STACK ]------------------------------------------------------- + + struct push_double + { + stack & m_stack; + push_double(stack & stack) : m_stack(stack) { } + + void operator() (double dValue) const + { + m_stack.push(variant(new boost::any(dValue))); + } + }; + + + // ---[ SEMANTIC ACTION: PUSH AN INT ON THE STACK ]------------------------------------------------------- + + struct push_int + { + stack & m_stack; + push_int(stack & stack) : m_stack(stack) { } + + void operator() (long long iValue) const + { + m_stack.push(variant(new boost::any(iValue))); + } + }; + + + // ---[ SEMANTIC ACTION: PUSH A BOOLEAN ON THE STACK ]---------------------------------------------------- + + struct push_boolean + { + stack & m_stack; + push_boolean(stack & stack) : m_stack(stack) { } + + template <typename Iterator> + void operator() (Iterator szStart, Iterator /* szEnd */ ) const + { + // 1: push a boolean that is "true" if the string starts with 't' and "false" otherwise... + + m_stack.push(variant(new boost::any(*szStart == static_cast< typename Iterator::value_type >('t')))); + } + }; + + + // ---[ SEMANTIC ACTION: PUSH A NULL VALUE ON THE STACK ]------------------------------------------------- + + struct push_null + { + stack & m_stack; + push_null(stack & stack) : m_stack(stack) { } + + template <typename Iterator> + void operator() (Iterator /* szStart */ , Iterator /* szEnd */ ) const + { + m_stack.push(variant(new boost::any())); + } + }; + + + // ---[ SEMANTIC ACTION: CREATE A "JSON PAIR" ON THE STACK ]---------------------------------------------- + + struct create_pair + { + stack & m_stack; + create_pair(stack & stack) : m_stack(stack) { } + + template <typename Iterator> + void operator() (Iterator /* szStart */, Iterator /* szEnd */ ) const + { + // 1: get the variant from the stack... + + variant var = m_stack.top(); + m_stack.pop(); + + // 2: get the name from the stack... + + std::basic_string< typename Iterator::value_type > strName; + + try + { + strName = boost::any_cast< std::basic_string< typename Iterator::value_type > >(*m_stack.top()); + } + catch(boost::bad_any_cast &) { /* NOTHING */ } + + m_stack.pop(); + + // 3: push a pair of both on the stack... + + m_stack.push(variant(new boost::any(pair(strName, var)))); + } + }; + + + // ---[ SEMANTIC ACTION: BEGIN AN ARRAY ]----------------------------------------------------------------- + + class array_delimiter { /* EMPTY CLASS */ }; + + struct begin_array + { + stack & m_stack; + begin_array(stack & stack) : m_stack(stack) { } + + template <typename Iterator> + void operator() (Iterator /* cCharacter */) const + { + m_stack.push(variant(new boost::any(array_delimiter()))); + } + }; + + + // ---[ SEMANTIC ACTION: CREATE AN ARRAY FROM THE VALUES ON THE STACK ]----------------------------------- + + struct end_array + { + stack & m_stack; + end_array(stack & stack) : m_stack(stack) { } + + // - -[ functional operator ] - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + template <typename Iterator> + void operator() (Iterator /* cCharacter */) const + { + // 1: create an array object and push everything in it, that's on the stack... + + variant varArray(new boost::any(array())); + + while(!m_stack.empty()) + { + // 1.1: get the top most variant of the stack... + + variant var = m_stack.top(); + m_stack.pop(); + + // 1.2: is it the end of the array? if yes => break the loop... + + if (boost::any_cast< array_delimiter >(var.get()) != NULL) + { + break; + } + + // 1.3: otherwise, add to the array... + + boost::any_cast< array >(varArray.get())->push_front(var); + } + + // 2: finally, push the array at the end of the stack... + + m_stack.push(varArray); + } + }; + + + // ---[ SEMANTIC ACTION: BEGIN AN OBJECT ]---------------------------------------------------------------- + + class object_delimiter { /* EMPTY CLASS */ }; + + struct begin_object + { + stack & m_stack; + begin_object(stack & stack) : m_stack(stack) { } + + template <typename Iterator> + void operator() (Iterator /* cCharacter */) const + { + m_stack.push(variant(new boost::any(object_delimiter()))); + } + }; + + + // ---[ SEMANTIC ACTION: CREATE AN OBJECT FROM THE VALUES ON THE STACK ]---------------------------------- + + struct end_object + { + stack & m_stack; + end_object(stack & stack) : m_stack(stack) { } + + template <typename Iterator> + void operator() (Iterator /* cCharacter */) const + { + // 1: create an array object and push everything in it, that's on the stack... + + variant varObject(new boost::any(object())); + + while(!m_stack.empty()) + { + // 1.1: get the top most variant of the stack... + + variant var = m_stack.top(); + m_stack.pop(); + + // 1.2: is it the end of the array? if yes => break the loop... + + if (boost::any_cast< object_delimiter >(var.get()) != NULL) + { + break; + } + + // 1.3: if this is not a pair, we have a problem... + + pair * pPair = boost::any_cast< pair >(var.get()); + if (!pPair) + { + /* BIG PROBLEM!! */ + + continue; + } + + // 1.4: set the child of this object... + + boost::any_cast< object >(varObject.get())->insert(std::make_pair(pPair->first, pPair->second)); + } + + // 2: finally, push the array at the end of the stack... + + m_stack.push(varObject); + } + }; + + public: + + stack & m_stack; + grammar(stack & stack) : m_stack(stack) { } + + // ---[ THE ACTUAL GRAMMAR DEFINITION ]------------------------------------------------------------------- + + template <typename SCANNER> + class definition + { + boost::spirit::rule< SCANNER > m_start; + boost::spirit::rule< SCANNER > m_object; + boost::spirit::rule< SCANNER > m_array; + boost::spirit::rule< SCANNER > m_pair; + boost::spirit::rule< SCANNER > m_value; + boost::spirit::rule< SCANNER > m_string; + boost::spirit::rule< SCANNER > m_number; + boost::spirit::rule< SCANNER > m_boolean; + boost::spirit::rule< SCANNER > m_null; + + public: + + boost::spirit::rule< SCANNER > const & start() const { return m_start; } + + // - -[ create the definition ] - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + definition(grammar const & self) + { + using namespace boost::spirit; + + // 0: JSON can either be an object or an array + + m_start + = m_object + | m_array; + + // 1: an object is an unordered set of pairs (seperated by commas)... + + m_object + = ch_p('{') [ begin_object(self.m_stack) ] >> + !(m_pair >> *(ch_p(',') >> m_pair)) >> + ch_p('}') [ end_object (self.m_stack) ]; + + // 2: an array is an ordered collection of values (seperated by commas)... + + m_array + = ch_p('[') [ begin_array(self.m_stack) ] >> + !(m_value >> *(ch_p(',') >> m_value)) >> + ch_p(']') [ end_array (self.m_stack) ]; + + // 3: a pair is given by a name and a value... + + m_pair + = ( m_string >> ch_p(':') >> m_value ) + [ create_pair(self.m_stack) ] + ; + + // 4: a value can be a string in double quotes, a number, a boolean, an object or an array. + + m_value + = m_string + | m_number + | m_object + | m_array + | m_boolean + | m_null + ; + + // 5: a string is a collection of zero or more unicode characters, wrapped in double quotes... + + m_string + = lexeme_d + [ + ( ch_p('"') >> *( + ( (anychar_p - (ch_p('"') | ch_p('\\'))) + | ch_p('\\') >> + ( ch_p('\"') + | ch_p('\\') + | ch_p('/') + | ch_p('b') + | ch_p('f') + | ch_p('n') + | ch_p('r') + | ch_p('t') + | (ch_p('u') >> repeat_p(4)[ xdigit_p ]) + ) + )) >> ch_p('"') + ) + [ push_string(self.m_stack) ] + ] + ; + + // 6: a number is very much like a C or java number... + + m_number + = strict_real_p [ push_double(self.m_stack) ] + | longlong_p [ push_int (self.m_stack) ] + ; + + // 7: a boolean can be "true" or "false"... + + m_boolean + = ( str_p("true") + | str_p("false") + ) + [ push_boolean(self.m_stack) ] + ; + + // 8: finally, a value also can be a 'null', i.e. an empty item... + + m_null + = str_p("null") + [ push_null(self.m_stack) ] + ; + } + }; + }; + + + // ========================================================================================================== + // === T H E F I N A L P A R S I N G R O U T I N E === + // ========================================================================================================== + + template <typename Iterator> + typename json::grammar< typename Iterator::value_type >::variant parse(Iterator const & szFirst, Iterator const & szEnd) + { + // 1: parse the input... + + json::grammar< typename Iterator::value_type >::stack st; + json::grammar< typename Iterator::value_type > gr(st); + + boost::spirit::parse_info<Iterator> pi = boost::spirit::parse(szFirst, szEnd, gr, boost::spirit::space_p); + + // 2: skip any spaces at the end of the parsed section... + + while((pi.stop != szEnd) && (*pi.stop == static_cast< typename Iterator::value_type >(' '))) + { + ++pi.stop; + } + + // 3: if the input's end wasn't reached or if there is more than one object on the stack => cancel... + + if ((pi.stop != szEnd) || (st.size() != 1)) + { + return json::grammar< typename Iterator::value_type >::variant(new boost::any()); + } + + // 4: otherwise, return the result... + + return st.top(); + } +}; + + +#endif // TINYJSON_HPP diff --git a/protocols/Twitter/twitter.cpp b/protocols/Twitter/twitter.cpp new file mode 100644 index 0000000000..9512292707 --- /dev/null +++ b/protocols/Twitter/twitter.cpp @@ -0,0 +1,380 @@ +/* +Copyright 2009 Jim Porter + +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, see <http://www.gnu.org/licenses/>. +*/ + +//#include "common.h" + +#include <windows.h> +#include <cstring> +#include <sstream> +#include <ctime> + +#include "twitter.h" + +#include "tinyjson.hpp" +#include <boost/lexical_cast.hpp> + +typedef json::grammar<char> js; + +// utility functions + +template <typename T> +static T cast_and_decode(boost::any &a,bool allow_null) +{ + if (allow_null && a.type() == typeid(void)) + return T(); + return boost::any_cast<T>(a); +} + +template <> +static std::string cast_and_decode<std::string>(boost::any &a,bool allow_null) +{ + if (allow_null && a.type() == typeid(void)) + return std::string(); + std::string s = boost::any_cast<std::string>(a); + + // Twitter *only* encodes < and >, so decode them + size_t off; + while( (off = s.find("<")) != std::string::npos) + s.replace(off,4,"<"); + while( (off = s.find(">")) != std::string::npos) + s.replace(off,4,">"); + + return s; +} + +template <typename T> +static T retrieve(const js::object &o,const std::string &key,bool allow_null = false) +{ + using boost::any_cast; + + js::object::const_iterator i = o.find(key); + if (i == o.end()) + throw std::exception( ("unable to retrieve key '"+key+"'").c_str()); + try + { + return cast_and_decode<T>(*i->second,allow_null); + } + catch(const boost::bad_any_cast &) + { + throw std::exception( ("unable to cast key '"+key+"' to target type").c_str()); + } +} + + + +twitter::twitter() : base_url_("https://twitter.com/") +{} + +bool twitter::set_credentials(const std::string &username,const std::string &password, + bool test) +{ + username_ = username; + password_ = password; + + if (test) + return slurp(base_url_+"account/verify_credentials.json",http::get).code == 200; + else + return true; +} + +void twitter::set_base_url(const std::string &base_url) +{ + base_url_ = base_url; +} + +const std::string & twitter::get_username() const +{ + return username_; +} + +const std::string & twitter::get_base_url() const +{ + return base_url_; +} + +std::vector<twitter_user> twitter::get_friends() +{ + std::vector<twitter_user> friends; + http::response resp = slurp(base_url_+"statuses/friends.json",http::get); + + if (resp.code != 200) + throw bad_response(); + + const js::variant var = json::parse( resp.data.begin(),resp.data.end()); + if (var->type() != typeid(js::array)) + throw std::exception("unable to parse response"); + + const js::array &list = boost::any_cast<js::array>(*var); + for(js::array::const_iterator i=list.begin(); i!=list.end(); ++i) + { + if ((*i)->type() == typeid(js::object)) + { + const js::object &one = boost::any_cast<js::object>(**i); + + twitter_user user; + user.username = retrieve<std::string>(one,"screen_name"); + user.real_name = retrieve<std::tstring>(one,"name",true); + user.profile_image_url = retrieve<std::string>(one,"profile_image_url",true); + + if (one.find("status") != one.end()) + { + js::object &status = retrieve<js::object>(one,"status"); + user.status.text = retrieve<std::tstring>(status,"text"); + + user.status.id = retrieve<long long>(status,"id"); + + std::string timestr = retrieve<std::string>(status,"created_at"); + user.status.time = parse_time(timestr); + } + + friends.push_back(user); + } + } + + return friends; +} + +bool twitter::get_info(const std::tstring &name,twitter_user *info) +{ + if (!info) + return false; + + std::string url = base_url_+"users/show/"+http::url_encode(name)+".json"; + + http::response resp = slurp(url,http::get); + if (resp.code != 200) + throw bad_response(); + + const js::variant var = json::parse( resp.data.begin(),resp.data.end()); + if (var->type() == typeid(js::object)) + { + const js::object &user_info = boost::any_cast<js::object>(*var); + if (user_info.find("error") != user_info.end()) + return false; + + info->username = retrieve<std::string>(user_info,"screen_name"); + info->real_name = retrieve<std::tstring>(user_info,"name",true); + info->profile_image_url = retrieve<std::string>(user_info,"profile_image_url",true); + + return true; + } + else + return false; +} + +bool twitter::get_info_by_email(const std::tstring &email,twitter_user *info) +{ + if (!info) + return false; + + std::string url = base_url_+"users/show.json?email="+http::url_encode(email); + + http::response resp = slurp(url,http::get); + if (resp.code != 200) + throw bad_response(); + + js::variant var = json::parse( resp.data.begin(),resp.data.end()); + if (var->type() == typeid(js::object)) + { + const js::object &user_info = boost::any_cast<js::object>(*var); + if (user_info.find("error") != user_info.end()) + return false; + + info->username = retrieve<std::string>(user_info,"screen_name"); + info->real_name = retrieve<std::tstring>(user_info,"name",true); + info->profile_image_url = retrieve<std::string>(user_info,"profile_image_url",true); + + return true; + } + else + return false; +} + +twitter_user twitter::add_friend(const std::tstring &name) +{ + std::string url = base_url_+"friendships/create/"+http::url_encode(name)+".json"; + + twitter_user ret; + http::response resp = slurp(url,http::post); + if (resp.code != 200) + throw bad_response(); + + js::variant var = json::parse( resp.data.begin(),resp.data.end()); + if (var->type() != typeid(js::object)) + throw std::exception("unable to parse response"); + + const js::object &user_info = boost::any_cast<js::object>(*var); + ret.username = retrieve<std::string>(user_info,"screen_name"); + ret.real_name = retrieve<std::tstring>(user_info,"name",true); + ret.profile_image_url = retrieve<std::string>(user_info,"profile_image_url",true); + + if (user_info.find("status") != user_info.end()) + { + // TODO: fill in more fields + const js::object &status = retrieve<js::object>(user_info,"status"); + ret.status.text = retrieve<std::tstring>(status,"text"); + } + + return ret; +} + +void twitter::remove_friend(const std::tstring &name) +{ + std::string url = base_url_+"friendships/destroy/"+http::url_encode(name)+".json"; + + slurp(url,http::post); +} + +void twitter::set_status(const std::tstring &text) +{ + if (text.size()) + { + slurp(base_url_+"statuses/update.json",http::post, + "status="+http::url_encode(text)+ + "&source=mirandaim"); + } +} + +void twitter::send_direct(const std::tstring &name,const std::tstring &text) +{ + slurp(base_url_+"direct_messages/new.json",http::post, + "user=" +http::url_encode(name)+ + "&text="+http::url_encode(text)); +} + +std::vector<twitter_user> twitter::get_statuses(int count,twitter_id id) +{ + using boost::lexical_cast; + std::vector<twitter_user> statuses; + + std::string url = base_url_+"statuses/friends_timeline.json?count="+ + lexical_cast<std::string>(count); + if (id != 0) + url += "&since_id="+boost::lexical_cast<std::string>(id); + + http::response resp = slurp(url,http::get); + if (resp.code != 200) + throw bad_response(); + + js::variant var = json::parse( resp.data.begin(),resp.data.end()); + if (var->type() != typeid(js::array)) + throw std::exception("unable to parse response"); + + const js::array &list = boost::any_cast<js::array>(*var); + for(js::array::const_iterator i=list.begin(); i!=list.end(); ++i) + { + if ((*i)->type() == typeid(js::object)) + { + const js::object &one = boost::any_cast<js::object>(**i); + const js::object &user = retrieve<js::object>(one,"user"); + + twitter_user u; + u.username = retrieve<std::string>(user,"screen_name"); + + u.status.text = retrieve<std::tstring>(one,"text"); + u.status.id = retrieve<long long>(one,"id"); + std::string timestr = retrieve<std::string>(one,"created_at"); + u.status.time = parse_time(timestr); + + statuses.push_back(u); + } + } + + + return statuses; +} + +std::vector<twitter_user> twitter::get_direct(twitter_id id) +{ + std::vector<twitter_user> messages; + + std::string url = base_url_+"direct_messages.json"; + if (id != 0) + url += "?since_id="+boost::lexical_cast<std::string>(id); + + http::response resp = slurp(url,http::get); + if (resp.code != 200) + throw bad_response(); + + js::variant var = json::parse( resp.data.begin(),resp.data.end()); + if (var->type() != typeid(js::array)) + throw std::exception("unable to parse response"); + + const js::array &list = boost::any_cast<js::array>(*var); + for(js::array::const_iterator i=list.begin(); i!=list.end(); ++i) + { + if ((*i)->type() == typeid(js::object)) + { + const js::object &one = boost::any_cast<js::object>(**i); + + twitter_user u; + u.username = retrieve<std::string>(one,"sender_screen_name"); + + u.status.text = retrieve<std::tstring>(one,"text"); + u.status.id = retrieve<long long>(one,"id"); + std::string timestr = retrieve<std::string>(one,"created_at"); + u.status.time = parse_time(timestr); + + messages.push_back(u); + } + } + + + return messages; +} + +// Some Unices get this, now we do too! +time_t timegm(struct tm *t) +{ + _tzset(); + t->tm_sec -= _timezone; + t->tm_isdst = 0; + + return mktime(t); +} + +static char *month_names[] = { "Jan","Feb","Mar","Apr","May","Jun", + "Jul","Aug","Sep","Oct","Nov","Dec" }; + +int parse_month(const char *m) +{ + for(size_t i=0; i<12; i++) + { + if (strcmp(month_names[i],m) == 0) + return i; + } + return -1; +} + +time_t parse_time(const std::string &s) +{ + struct tm t; + char day[4],month[4]; + char plus; + int zone; + if (sscanf(s.c_str(),"%3s %3s %d %d:%d:%d %c%d %d", + day,month,&t.tm_mday,&t.tm_hour,&t.tm_min,&t.tm_sec, + &plus,&zone,&t.tm_year) == 9) + { + t.tm_year -= 1900; + t.tm_mon = parse_month(month); + if (t.tm_mon == -1) + return 0; + return timegm(&t); + } + return 0; +} \ No newline at end of file diff --git a/protocols/Twitter/twitter.h b/protocols/Twitter/twitter.h new file mode 100644 index 0000000000..06f8aca954 --- /dev/null +++ b/protocols/Twitter/twitter.h @@ -0,0 +1,96 @@ +/* +Copyright 2009 Jim Porter + +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, see <http://www.gnu.org/licenses/>. +*/ + +#pragma once + +#include <map> +#include <vector> +#include <string> + +#include "http.h" +#include <tchar.h> + +#if !defined(tstring) + #ifdef _UNICODE + #define tstring wstring + #else + #define tstring string + #endif +#endif + +typedef unsigned long long twitter_id; + +struct twitter_status +{ + std::tstring text; + twitter_id id; + time_t time; +}; + +struct twitter_user +{ + std::string username; + std::tstring real_name; + std::string profile_image_url; + twitter_status status; +}; + +time_t parse_time(const std::string &); + +class bad_response : public std::exception +{ +public: + virtual const char * what() const + { + return "bad http response"; + } +}; + +class twitter +{ +public: + typedef std::vector<twitter_user> status_list; + typedef std::map<std::tstring,status_list> status_map; + + twitter(); + + bool set_credentials(const std::string &username,const std::string &password, bool test = true); + void set_base_url(const std::string &base_url); + + const std::string & get_username() const; + const std::string & get_base_url() const; + + bool get_info(const std::tstring &name,twitter_user *); + bool get_info_by_email(const std::tstring &email,twitter_user *); + std::vector<twitter_user> get_friends(); + + twitter_user add_friend(const std::tstring &name); + void remove_friend(const std::tstring &name); + + void set_status(const std::tstring &text); + std::vector<twitter_user> get_statuses(int count=20,twitter_id id=0); + + void send_direct(const std::tstring &name,const std::tstring &text); + std::vector<twitter_user> get_direct(twitter_id id=0); + +protected: + virtual http::response slurp(const std::string &,http::method, const std::string & = "") = 0; + + std::string username_; + std::string password_; + std::string base_url_; +}; \ No newline at end of file diff --git a/protocols/Twitter/twitter.rc b/protocols/Twitter/twitter.rc new file mode 100644 index 0000000000..0c32e19b59 --- /dev/null +++ b/protocols/Twitter/twitter.rc @@ -0,0 +1,224 @@ +// Microsoft Visual C++ generated resource script. +// +#include "resource.h" + +#define APSTUDIO_READONLY_SYMBOLS +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 2 resource. +// +#include "afxres.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 + +#ifdef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// TEXTINCLUDE +// + +1 TEXTINCLUDE +BEGIN + "resource.h\0" +END + +2 TEXTINCLUDE +BEGIN + "#include ""afxres.h""\r\n" + "\0" +END + +3 TEXTINCLUDE +BEGIN + "\r\n" + "\0" +END + +#endif // APSTUDIO_INVOKED + + +///////////////////////////////////////////////////////////////////////////// +// +// Dialog +// + +IDD_TWITTERACCOUNT DIALOGEX 0, 0, 186, 134 +STYLE DS_SETFONT | DS_FIXEDSYS | WS_CHILD +EXSTYLE WS_EX_CONTROLPARENT +FONT 8, "MS Shell Dlg", 0, 0, 0x0 +BEGIN + LTEXT "Username:",IDC_STATIC,0,0,53,12 + EDITTEXT IDC_UN,54,0,131,12,ES_AUTOHSCROLL + LTEXT "Password:",IDC_STATIC,0,16,53,12 + EDITTEXT IDC_PW,54,16,131,12,ES_PASSWORD | ES_AUTOHSCROLL + LTEXT "Server:",IDC_STATIC,0,32,53,12 + COMBOBOX IDC_SERVER,54,32,131,12,CBS_DROPDOWN | WS_VSCROLL | WS_TABSTOP + CONTROL "Create a new Twitter account",IDC_NEWACCOUNTLINK, + "Hyperlink",WS_TABSTOP,0,57,174,12 +END + +IDD_TWEET DIALOGEX 0, 0, 186, 64 +STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | DS_CENTER | WS_POPUP | WS_CAPTION | WS_SYSMENU +CAPTION "Send Tweet" +FONT 8, "MS Shell Dlg", 400, 0, 0x1 +BEGIN + EDITTEXT IDC_TWEETMSG,7,7,172,30,ES_MULTILINE | ES_AUTOVSCROLL | ES_WANTRETURN | WS_VSCROLL + DEFPUSHBUTTON "Send",IDOK,71,43,50,14 + PUSHBUTTON "Cancel",IDCANCEL,129,43,50,14 + LTEXT "",IDC_CHARACTERS,7,47,19,10 +END + +IDD_OPTIONS DIALOGEX 0, 0, 305, 217 +STYLE DS_SETFONT | DS_FIXEDSYS | WS_CHILD +EXSTYLE WS_EX_CONTROLPARENT +FONT 8, "MS Shell Dlg", 400, 0, 0x1 +BEGIN + GROUPBOX "User Details",IDC_USERDETAILS,7,7,152,51 + LTEXT "Username:",IDC_STATIC,15,20,41,8 + EDITTEXT IDC_UN,62,18,89,14,ES_AUTOHSCROLL + LTEXT "Password:",IDC_STATIC,15,37,41,8 + EDITTEXT IDC_PW,62,35,89,14,ES_PASSWORD | ES_AUTOHSCROLL + GROUPBOX "Misc. Options",IDC_MISC,7,67,152,65 + CONTROL "Use group chat for Twitter feed",IDC_CHATFEED,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,15,81,133,10 + LTEXT "Base URL:",IDC_STATIC,15,96,41,8 + COMBOBOX IDC_BASEURL,62,94,89,30,CBS_DROPDOWN | CBS_AUTOHSCROLL | WS_VSCROLL | WS_TABSTOP + LTEXT "Polling rate:",IDC_STATIC,15,113,41,8 + LTEXT "Once every",IDC_STATIC,62,113,40,8 + EDITTEXT IDC_POLLRATE,103,111,30,14,ES_AUTOHSCROLL | ES_NUMBER + LTEXT "sec",IDC_STATIC,138,113,19,8 + LTEXT "Please cycle your connection for these changes to take effect",IDC_RECONNECT,53,202,199,8,NOT WS_VISIBLE +END + +IDD_OPTIONS_POPUPS DIALOGEX 0, 0, 305, 217 +STYLE DS_SETFONT | DS_FIXEDSYS | WS_CHILD +EXSTYLE WS_EX_CONTROLPARENT +FONT 8, "MS Shell Dlg", 400, 0, 0x1 +BEGIN + CONTROL "Enable popup notifications for Tweets",IDC_SHOWPOPUPS, + "Button",BS_AUTOCHECKBOX | WS_TABSTOP,16,7,137,10 + GROUPBOX "Colors",IDC_STATIC,6,32,164,59 + CONTROL "Use Windows colors",IDC_COL_WINDOWS,"Button",BS_AUTORADIOBUTTON | WS_GROUP | WS_TABSTOP,16,46,79,10 + CONTROL "Use Popup colors",IDC_COL_POPUP,"Button",BS_AUTORADIOBUTTON | WS_TABSTOP,16,60,71,10 + CONTROL "Use custom colors",IDC_COL_CUSTOM,"Button",BS_AUTORADIOBUTTON | WS_TABSTOP,16,74,73,10 + LTEXT "Back",IDC_STATIC,103,64,16,8 + LTEXT "Text",IDC_STATIC,136,64,16,8 + CONTROL "",IDC_COLBACK,"ColourPicker",WS_TABSTOP,99,73,24,13 + CONTROL "",IDC_COLTEXT,"ColourPicker",WS_TABSTOP,132,73,24,13 + GROUPBOX "Timeouts",IDC_STATIC,184,32,115,59 + CONTROL "Use default",IDC_TIMEOUT_DEFAULT,"Button",BS_AUTORADIOBUTTON | WS_GROUP | WS_TABSTOP,196,46,53,10 + CONTROL "Custom",IDC_TIMEOUT_CUSTOM,"Button",BS_AUTORADIOBUTTON | WS_TABSTOP,196,60,40,10 + EDITTEXT IDC_TIMEOUT,249,58,40,14,ES_AUTOHSCROLL + CONTROL "",IDC_TIMEOUT_SPIN,"msctls_updown32",UDS_SETBUDDYINT | UDS_ALIGNRIGHT | UDS_AUTOBUDDY | UDS_ARROWKEYS,279,58,10,14 + CONTROL "Permanent",IDC_TIMEOUT_PERMANENT,"Button",BS_AUTORADIOBUTTON | WS_TABSTOP,196,74,51,10 + PUSHBUTTON "Preview",IDC_PREVIEW,184,99,50,14 + CONTROL "But not during sign-on",IDC_NOSIGNONPOPUPS,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,27,19,87,10 +END + + +///////////////////////////////////////////////////////////////////////////// +// +// Icon +// + +// Icon with lowest ID value placed first to ensure application icon +// remains consistent on all systems. +IDI_TWITTER ICON "icons\\twitter.ico" + +///////////////////////////////////////////////////////////////////////////// +// +// DESIGNINFO +// + +#ifdef APSTUDIO_INVOKED +GUIDELINES DESIGNINFO +BEGIN + IDD_TWEET, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 179 + TOPMARGIN, 7 + BOTTOMMARGIN, 57 + END + + IDD_OPTIONS, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 298 + TOPMARGIN, 7 + BOTTOMMARGIN, 210 + END + + IDD_OPTIONS_POPUPS, DIALOG + BEGIN + LEFTMARGIN, 6 + RIGHTMARGIN, 299 + VERTGUIDE, 184 + TOPMARGIN, 7 + BOTTOMMARGIN, 210 + END +END +#endif // APSTUDIO_INVOKED + + +///////////////////////////////////////////////////////////////////////////// +// +// Version +// + +VS_VERSION_INFO VERSIONINFO + FILEVERSION 0,0,8,4 + PRODUCTVERSION 0,0,8,4 + FILEFLAGSMASK 0x17L +#ifdef _DEBUG + FILEFLAGS 0x1L +#else + FILEFLAGS 0x0L +#endif + FILEOS 0x4L + FILETYPE 0x2L + FILESUBTYPE 0x0L +BEGIN + BLOCK "StringFileInfo" + BEGIN + BLOCK "040904b0" + BEGIN + VALUE "FileDescription", "Twitter protocol plugin for Miranda IM" + VALUE "FileVersion", "0, 0, 8, 4" + VALUE "InternalName", "twitter" + VALUE "LegalCopyright", "Copyright 2009" + VALUE "OriginalFilename", "twitter.dll" + VALUE "ProductName", "Miranda-Twitter" + VALUE "ProductVersion", "0, 0, 8, 4" + END + END + BLOCK "VarFileInfo" + BEGIN + VALUE "Translation", 0x409, 1200 + END +END + +#endif // English (U.S.) resources +///////////////////////////////////////////////////////////////////////////// + + + +#ifndef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 3 resource. +// + + +///////////////////////////////////////////////////////////////////////////// +#endif // not APSTUDIO_INVOKED + diff --git a/protocols/Twitter/twitter.sln b/protocols/Twitter/twitter.sln new file mode 100644 index 0000000000..af7c8278cd --- /dev/null +++ b/protocols/Twitter/twitter.sln @@ -0,0 +1,26 @@ + +Microsoft Visual Studio Solution File, Format Version 9.00 +# Visual Studio 2005 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "twitter", "twitter.vcproj", "{DADE9455-DC28-465A-9604-2CA28052B9FB}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug ANSI|Win32 = Debug ANSI|Win32 + Debug|Win32 = Debug|Win32 + Release ANSI|Win32 = Release ANSI|Win32 + Release|Win32 = Release|Win32 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {DADE9455-DC28-465A-9604-2CA28052B9FB}.Debug ANSI|Win32.ActiveCfg = Debug ANSI|Win32 + {DADE9455-DC28-465A-9604-2CA28052B9FB}.Debug ANSI|Win32.Build.0 = Debug ANSI|Win32 + {DADE9455-DC28-465A-9604-2CA28052B9FB}.Debug|Win32.ActiveCfg = Debug|Win32 + {DADE9455-DC28-465A-9604-2CA28052B9FB}.Debug|Win32.Build.0 = Debug|Win32 + {DADE9455-DC28-465A-9604-2CA28052B9FB}.Release ANSI|Win32.ActiveCfg = Release ANSI|Win32 + {DADE9455-DC28-465A-9604-2CA28052B9FB}.Release ANSI|Win32.Build.0 = Release ANSI|Win32 + {DADE9455-DC28-465A-9604-2CA28052B9FB}.Release|Win32.ActiveCfg = Release|Win32 + {DADE9455-DC28-465A-9604-2CA28052B9FB}.Release|Win32.Build.0 = Release|Win32 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/protocols/Twitter/twitter.vcxproj b/protocols/Twitter/twitter.vcxproj new file mode 100644 index 0000000000..d529d1dcbb --- /dev/null +++ b/protocols/Twitter/twitter.vcxproj @@ -0,0 +1,127 @@ +<?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="Release|Win32"> + <Configuration>Release</Configuration> + <Platform>Win32</Platform> + </ProjectConfiguration> + </ItemGroup> + <PropertyGroup Label="Globals"> + <ProjectGuid>{DADE9455-DC28-465A-9604-2CA28052B9FB}</ProjectGuid> + <RootNamespace>twitter</RootNamespace> + <Keyword>Win32Proj</Keyword> + </PropertyGroup> + <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" /> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration"> + <ConfigurationType>DynamicLibrary</ConfigurationType> + <CharacterSet>Unicode</CharacterSet> + <WholeProgramOptimization>true</WholeProgramOptimization> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration"> + <ConfigurationType>DynamicLibrary</ConfigurationType> + <CharacterSet>Unicode</CharacterSet> + </PropertyGroup> + <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" /> + <ImportGroup Label="ExtensionSettings"> + </ImportGroup> + <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="PropertySheets"> + <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" /> + </ImportGroup> + <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="PropertySheets"> + <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" /> + </ImportGroup> + <PropertyGroup Label="UserMacros" /> + <PropertyGroup> + <_ProjectFileVersion>10.0.40219.1</_ProjectFileVersion> + <OutDir Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">$(SolutionDir)$(Configuration)\Plugins\</OutDir> + <IntDir Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">$(SolutionDir)$(Configuration)\Obj\$(ProjectName)\</IntDir> + <LinkIncremental Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</LinkIncremental> + <OutDir Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">$(SolutionDir)$(Configuration)\Plugins\</OutDir> + <IntDir Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">$(SolutionDir)$(Configuration)\Obj\$(ProjectName)\</IntDir> + <LinkIncremental Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">false</LinkIncremental> + </PropertyGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"> + <ClCompile> + <Optimization>Disabled</Optimization> + <AdditionalIncludeDirectories>..\..\include;..\..\..\boost_1_49_0;..\plugins\ExternalAPI;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> + <PreprocessorDefinitions>WIN32;_WINDOWS;_USRDLL;TWITTER_EXPORTS;_CRT_SECURE_NO_WARNINGS;NOMINMAX;%(PreprocessorDefinitions)</PreprocessorDefinitions> + <MinimalRebuild>true</MinimalRebuild> + <BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks> + <RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary> + <PrecompiledHeader>Use</PrecompiledHeader> + <WarningLevel>Level3</WarningLevel> + <DebugInformationFormat>EditAndContinue</DebugInformationFormat> + <PrecompiledHeaderFile>common.h</PrecompiledHeaderFile> + </ClCompile> + <Link> + <GenerateDebugInformation>true</GenerateDebugInformation> + <SubSystem>Windows</SubSystem> + <TargetMachine>MachineX86</TargetMachine> + </Link> + </ItemDefinitionGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> + <ClCompile> + <AdditionalIncludeDirectories>..\..\include;..\..\..\boost_1_49_0;..\plugins\ExternalAPI;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> + <PreprocessorDefinitions>WIN32;NDEBUG;_WINDOWS;_USRDLL;TWITTER_EXPORTS;_CRT_SECURE_NO_WARNINGS;NOMINMAX;%(PreprocessorDefinitions)</PreprocessorDefinitions> + <RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary> + <PrecompiledHeader>Use</PrecompiledHeader> + <WarningLevel>Level3</WarningLevel> + <DebugInformationFormat>ProgramDatabase</DebugInformationFormat> + <Optimization>Full</Optimization> + <FavorSizeOrSpeed>Size</FavorSizeOrSpeed> + <StringPooling>true</StringPooling> + <PrecompiledHeaderFile>common.h</PrecompiledHeaderFile> + </ClCompile> + <Link> + <GenerateDebugInformation>true</GenerateDebugInformation> + <SubSystem>Windows</SubSystem> + <OptimizeReferences>true</OptimizeReferences> + <EnableCOMDATFolding>true</EnableCOMDATFolding> + <TargetMachine>MachineX86</TargetMachine> + </Link> + </ItemDefinitionGroup> + <ItemGroup> + <ClCompile Include="chat.cpp" /> + <ClCompile Include="connection.cpp" /> + <ClCompile Include="contacts.cpp" /> + <ClCompile Include="http.cpp" /> + <ClCompile Include="main.cpp"> + <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">Create</PrecompiledHeader> + <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">Create</PrecompiledHeader> + </ClCompile> + <ClCompile Include="proto.cpp" /> + <ClCompile Include="stubs.cpp" /> + <ClCompile Include="theme.cpp" /> + <ClCompile Include="twitter.cpp"> + <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">NotUsing</PrecompiledHeader> + <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">NotUsing</PrecompiledHeader> + </ClCompile> + <ClCompile Include="ui.cpp" /> + <ClCompile Include="utility.cpp" /> + </ItemGroup> + <ItemGroup> + <ClInclude Include="common.h" /> + <ClInclude Include="http.h" /> + <ClInclude Include="proto.h" /> + <ClInclude Include="resource.h" /> + <ClInclude Include="theme.h" /> + <ClInclude Include="tinyjson.hpp" /> + <ClInclude Include="twitter.h" /> + <ClInclude Include="ui.h" /> + <ClInclude Include="utility.h" /> + <ClInclude Include="version.h" /> + </ItemGroup> + <ItemGroup> + <None Include="icons\twitter.ico" /> + </ItemGroup> + <ItemGroup> + <ResourceCompile Include="twitter.rc" /> + </ItemGroup> + <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" /> + <ImportGroup Label="ExtensionTargets"> + </ImportGroup> +</Project> \ No newline at end of file diff --git a/protocols/Twitter/twitter.vcxproj.filters b/protocols/Twitter/twitter.vcxproj.filters new file mode 100644 index 0000000000..70ac860513 --- /dev/null +++ b/protocols/Twitter/twitter.vcxproj.filters @@ -0,0 +1,94 @@ +<?xml version="1.0" encoding="utf-8"?> +<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> + <ItemGroup> + <Filter Include="Source Files"> + <UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier> + <Extensions>cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx</Extensions> + </Filter> + <Filter Include="Header Files"> + <UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier> + <Extensions>h;hpp;hxx;hm;inl;inc;xsd</Extensions> + </Filter> + <Filter Include="Resource Files"> + <UniqueIdentifier>{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}</UniqueIdentifier> + <Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav</Extensions> + </Filter> + </ItemGroup> + <ItemGroup> + <ClCompile Include="chat.cpp"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="connection.cpp"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="contacts.cpp"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="http.cpp"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="main.cpp"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="proto.cpp"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="stubs.cpp"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="theme.cpp"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="twitter.cpp"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="ui.cpp"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="utility.cpp"> + <Filter>Source Files</Filter> + </ClCompile> + </ItemGroup> + <ItemGroup> + <ClInclude Include="common.h"> + <Filter>Header Files</Filter> + </ClInclude> + <ClInclude Include="http.h"> + <Filter>Header Files</Filter> + </ClInclude> + <ClInclude Include="proto.h"> + <Filter>Header Files</Filter> + </ClInclude> + <ClInclude Include="resource.h"> + <Filter>Header Files</Filter> + </ClInclude> + <ClInclude Include="theme.h"> + <Filter>Header Files</Filter> + </ClInclude> + <ClInclude Include="tinyjson.hpp"> + <Filter>Header Files</Filter> + </ClInclude> + <ClInclude Include="twitter.h"> + <Filter>Header Files</Filter> + </ClInclude> + <ClInclude Include="ui.h"> + <Filter>Header Files</Filter> + </ClInclude> + <ClInclude Include="utility.h"> + <Filter>Header Files</Filter> + </ClInclude> + <ClInclude Include="version.h"> + <Filter>Header Files</Filter> + </ClInclude> + </ItemGroup> + <ItemGroup> + <None Include="icons\twitter.ico"> + <Filter>Resource Files</Filter> + </None> + </ItemGroup> + <ItemGroup> + <ResourceCompile Include="twitter.rc"> + <Filter>Resource Files</Filter> + </ResourceCompile> + </ItemGroup> +</Project> \ No newline at end of file diff --git a/protocols/Twitter/ui.cpp b/protocols/Twitter/ui.cpp new file mode 100644 index 0000000000..b3e68542df --- /dev/null +++ b/protocols/Twitter/ui.cpp @@ -0,0 +1,529 @@ +/* +Copyright 2009 Jim Porter + +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, see <http://www.gnu.org/licenses/>. +*/ + +#include "common.h" +#include "ui.h" + +#include <cstdio> +#include <commctrl.h> + +#include "proto.h" +#include "twitter.h" + +static const TCHAR *sites[] = { + _T("https://twitter.com/"), + _T("https://identi.ca/api/") +}; + +INT_PTR CALLBACK first_run_dialog(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam) +{ + TwitterProto *proto; + + switch(msg) + { + case WM_INITDIALOG: + TranslateDialogDefault(hwndDlg); + + proto = reinterpret_cast<TwitterProto*>(lParam); + SetWindowLong(hwndDlg, GWL_USERDATA, lParam); + + DBVARIANT dbv; + if ( !DBGetContactSettingTString(0, proto->ModuleName(), TWITTER_KEY_UN, &dbv)) { + SetDlgItemText(hwndDlg, IDC_UN, dbv.ptszVal); + DBFreeVariant(&dbv); + } + + if ( !DBGetContactSettingString(0, proto->ModuleName(), TWITTER_KEY_PASS, &dbv)) { + CallService(MS_DB_CRYPT_DECODESTRING, strlen(dbv.pszVal)+1, + reinterpret_cast<LPARAM>(dbv.pszVal)); + SetDlgItemTextA(hwndDlg, IDC_PW, dbv.pszVal); + DBFreeVariant(&dbv); + } + + for(size_t i=0; i<SIZEOF(sites); i++) + { + SendDlgItemMessage(hwndDlg, IDC_SERVER, CB_ADDSTRING, 0, + reinterpret_cast<LPARAM>(sites[i])); + } + if ( !DBGetContactSettingString(0, proto->ModuleName(), TWITTER_KEY_BASEURL, &dbv)) + { + SetDlgItemTextA(hwndDlg, IDC_SERVER, dbv.pszVal); + DBFreeVariant(&dbv); + } + else + { + SendDlgItemMessage(hwndDlg, IDC_SERVER, CB_SETCURSEL, 0, 0); + } + + return true; + case WM_COMMAND: + if (LOWORD(wParam) == IDC_NEWACCOUNTLINK) + { + CallService(MS_UTILS_OPENURL, 1, reinterpret_cast<LPARAM> + ("http://twitter.com/signup")); + return true; + } + + if (GetWindowLong(hwndDlg, GWL_USERDATA)) // Window is done initializing + { + switch(HIWORD(wParam)) + { + case EN_CHANGE: + case CBN_EDITCHANGE: + case CBN_SELCHANGE: + SendMessage(GetParent(hwndDlg), PSM_CHANGED, 0, 0); + } + } + break; + + case WM_NOTIFY: + if (reinterpret_cast<NMHDR*>(lParam)->code == PSN_APPLY) + { + proto = reinterpret_cast<TwitterProto*>(GetWindowLong(hwndDlg, GWL_USERDATA)); + char str[128]; + + GetDlgItemTextA(hwndDlg, IDC_UN, str, sizeof(str)); + DBWriteContactSettingString(0, proto->ModuleName(), TWITTER_KEY_UN, str); + + GetDlgItemTextA(hwndDlg, IDC_PW, str, sizeof(str)); + CallService(MS_DB_CRYPT_ENCODESTRING, sizeof(str), reinterpret_cast<LPARAM>(str)); + DBWriteContactSettingString(0, proto->ModuleName(), TWITTER_KEY_PASS, str); + + GetDlgItemTextA(hwndDlg, IDC_SERVER, str, sizeof(str)-1); + if (str[strlen(str)-1] != '/') + strncat(str, "/", sizeof(str)); + DBWriteContactSettingString(0, proto->ModuleName(), TWITTER_KEY_BASEURL, str); + + return true; + } + break; + } + + return false; +} + +INT_PTR CALLBACK tweet_proc(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam) +{ + TwitterProto *proto; + + switch(msg) + { + case WM_INITDIALOG: + TranslateDialogDefault(hwndDlg); + + proto = reinterpret_cast<TwitterProto*>(lParam); + SetWindowLong(hwndDlg, GWL_USERDATA, lParam); + SendDlgItemMessage(hwndDlg, IDC_TWEETMSG, EM_LIMITTEXT, 140, 0); + SetDlgItemText(hwndDlg, IDC_CHARACTERS, _T("140")); + + // Set window title + TCHAR title[512]; + mir_sntprintf(title, SIZEOF(title), _T("Send Tweet for %s"), proto->m_tszUserName); + SendMessage(hwndDlg, WM_SETTEXT, 0, (LPARAM)title); + + return true; + case WM_COMMAND: + if (LOWORD(wParam) == IDOK) + { + TCHAR msg[141]; + proto = reinterpret_cast<TwitterProto*>(GetWindowLong(hwndDlg, GWL_USERDATA)); + + GetDlgItemText(hwndDlg, IDC_TWEETMSG, msg, SIZEOF(msg)); + ShowWindow(hwndDlg, SW_HIDE); + + char *narrow = mir_t2a_cp(msg, CP_UTF8); + ForkThread(&TwitterProto::SendTweetWorker, proto, narrow); + + EndDialog(hwndDlg, wParam); + return true; + } + else if (LOWORD(wParam) == IDCANCEL) + { + EndDialog(hwndDlg, wParam); + return true; + } + else if (LOWORD(wParam) == IDC_TWEETMSG && HIWORD(wParam) == EN_CHANGE) + { + size_t len = SendDlgItemMessage(hwndDlg, IDC_TWEETMSG, WM_GETTEXTLENGTH, 0, 0); + char str[4]; + _snprintf(str, sizeof(str), "%d", 140-len); + SetDlgItemTextA(hwndDlg, IDC_CHARACTERS, str); + + return true; + } + + break; + case WM_SETREPLY: + { + char foo[512]; + _snprintf(foo, sizeof(foo), "@%s ", (char*)wParam); + size_t len = strlen(foo); + + SetDlgItemTextA(hwndDlg, IDC_TWEETMSG, foo); + SendDlgItemMessage(hwndDlg, IDC_TWEETMSG, EM_SETSEL, len, len); + + char str[4]; + _snprintf(str, sizeof(str), "%d", 140-len); + SetDlgItemTextA(hwndDlg, IDC_CHARACTERS, str); + + return true; + } + break; + } + + return false; +} + +INT_PTR CALLBACK options_proc(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam) +{ + TwitterProto *proto; + + switch(msg) + { + case WM_INITDIALOG: + TranslateDialogDefault(hwndDlg); + + proto = reinterpret_cast<TwitterProto*>(lParam); + + DBVARIANT dbv; + if ( !DBGetContactSettingString(0, proto->ModuleName(), TWITTER_KEY_UN, &dbv)) + { + SetDlgItemTextA(hwndDlg, IDC_UN, dbv.pszVal); + DBFreeVariant(&dbv); + } + + if ( !DBGetContactSettingString(0, proto->ModuleName(), TWITTER_KEY_PASS, &dbv)) + { + CallService(MS_DB_CRYPT_DECODESTRING, strlen(dbv.pszVal)+1, + reinterpret_cast<LPARAM>(dbv.pszVal)); + SetDlgItemTextA(hwndDlg, IDC_PW, dbv.pszVal); + DBFreeVariant(&dbv); + } + + CheckDlgButton(hwndDlg, IDC_CHATFEED, DBGetContactSettingByte(0, + proto->ModuleName(), TWITTER_KEY_CHATFEED, 0)); + + for(size_t i=0; i<SIZEOF(sites); i++) + { + SendDlgItemMessage(hwndDlg, IDC_BASEURL, CB_ADDSTRING, 0, + reinterpret_cast<LPARAM>(sites[i])); + } + + if ( !DBGetContactSettingString(0, proto->ModuleName(), TWITTER_KEY_BASEURL, &dbv)) + { + SetDlgItemTextA(hwndDlg, IDC_BASEURL, dbv.pszVal); + DBFreeVariant(&dbv); + } + else + { + SendDlgItemMessage(hwndDlg, IDC_BASEURL, CB_SETCURSEL, 0, 0); + } + + char pollrate_str[32]; + mir_snprintf(pollrate_str, sizeof(pollrate_str), "%d", + DBGetContactSettingDword(0, proto->ModuleName(), TWITTER_KEY_POLLRATE, 80)); + SetDlgItemTextA(hwndDlg, IDC_POLLRATE, pollrate_str); + + + // Do this last so that any events propagated by pre-filling the form don't + // instigate a PSM_CHANGED message + SetWindowLong(hwndDlg, GWL_USERDATA, lParam); + + break; + case WM_COMMAND: + if (GetWindowLong(hwndDlg, GWL_USERDATA)) // Window is done initializing + { + switch(HIWORD(wParam)) + { + case EN_CHANGE: + case BN_CLICKED: + case CBN_EDITCHANGE: + case CBN_SELCHANGE: + switch(LOWORD(wParam)) + { + case IDC_UN: + case IDC_PW: + case IDC_BASEURL: + ShowWindow(GetDlgItem(hwndDlg, IDC_RECONNECT), SW_SHOW); + } + SendMessage(GetParent(hwndDlg), PSM_CHANGED, 0, 0); + } + } + + break; + case WM_NOTIFY: + if (reinterpret_cast<NMHDR*>(lParam)->code == PSN_APPLY) + { + proto = reinterpret_cast<TwitterProto*>(GetWindowLong(hwndDlg, GWL_USERDATA)); + char str[128]; + + GetDlgItemTextA(hwndDlg, IDC_UN, str, sizeof(str)); + DBWriteContactSettingString(0, proto->ModuleName(), TWITTER_KEY_UN, str); + + GetDlgItemTextA(hwndDlg, IDC_PW, str, sizeof(str)); + CallService(MS_DB_CRYPT_ENCODESTRING, sizeof(str), reinterpret_cast<LPARAM>(str)); + DBWriteContactSettingString(0, proto->ModuleName(), TWITTER_KEY_PASS, str); + + GetDlgItemTextA(hwndDlg, IDC_BASEURL, str, sizeof(str)-1); + if (str[strlen(str)-1] != '/') + strncat(str, "/", sizeof(str)); + DBWriteContactSettingString(0, proto->ModuleName(), TWITTER_KEY_BASEURL, str); + + DBWriteContactSettingByte(0, proto->ModuleName(), TWITTER_KEY_CHATFEED, + IsDlgButtonChecked(hwndDlg, IDC_CHATFEED)); + + GetDlgItemTextA(hwndDlg, IDC_POLLRATE, str, sizeof(str)); + int rate = atoi(str); + if (rate == 0) + rate = 80; + DBWriteContactSettingDword(0, proto->ModuleName(), TWITTER_KEY_POLLRATE, rate); + + proto->UpdateSettings(); + return true; + } + } + + return false; +} + +namespace popup_options +{ + static int get_timeout(HWND hwndDlg) + { + if (IsDlgButtonChecked(hwndDlg, IDC_TIMEOUT_PERMANENT)) + return -1; + else if (IsDlgButtonChecked(hwndDlg, IDC_TIMEOUT_CUSTOM)) + { + char str[32]; + GetDlgItemTextA(hwndDlg, IDC_TIMEOUT, str, sizeof(str)); + return atoi(str); + } + else // Default checked (probably) + return 0; + } + + static COLORREF get_text_color(HWND hwndDlg, bool for_db) + { + if (IsDlgButtonChecked(hwndDlg, IDC_COL_WINDOWS)) + { + if (for_db) + return -1; + else + return GetSysColor(COLOR_WINDOWTEXT); + } + else if (IsDlgButtonChecked(hwndDlg, IDC_COL_CUSTOM)) + return SendDlgItemMessage(hwndDlg, IDC_COLTEXT, CPM_GETCOLOUR, 0, 0); + else // Default checked (probably) + return 0; + } + + static COLORREF get_back_color(HWND hwndDlg, bool for_db) + { + if (IsDlgButtonChecked(hwndDlg, IDC_COL_WINDOWS)) + { + if (for_db) + return -1; + else + return GetSysColor(COLOR_WINDOW); + } + else if (IsDlgButtonChecked(hwndDlg, IDC_COL_CUSTOM)) + return SendDlgItemMessage(hwndDlg, IDC_COLBACK, CPM_GETCOLOUR, 0, 0); + else // Default checked (probably) + return 0; + } + + struct + { + TCHAR *name; + TCHAR *text; + } const quotes[] = { + { _T("Dorothy Parker"), _T("If, with the literate, I am\n") + _T("Impelled to try an epigram, \n") + _T("I never seek to take the credit;\n") + _T("We all assume that Oscar said it.") }, + { _T("Steve Ballmer"), _T("I have never, honestly, thrown a chair in my life.") }, + { _T("James Joyce"), _T("I think I would know Nora's fart anywhere. I think ") + _T("I could pick hers out in a roomful of farting women.") }, + { _T("Brooke Shields"), _T("Smoking kills. If you're killed, you've lost a very ") + _T("important part of your life.") }, + { _T("Yogi Berra"), _T("Always go to other peoples' funerals, otherwise ") + _T("they won't go to yours.") }, + }; + + static void preview(HWND hwndDlg) + { + POPUPDATAT popup = {}; + + // Pick a random contact + HANDLE hContact = 0; + int n_contacts = CallService(MS_DB_CONTACT_GETCOUNT, 0, 0); + + if (n_contacts != 0) + { + int contact = rand() % n_contacts; + hContact = (HANDLE)CallService(MS_DB_CONTACT_FINDFIRST, 0, 0); + for(int i=0; i<contact; i++) + hContact = (HANDLE)CallService(MS_DB_CONTACT_FINDNEXT, (WPARAM)hContact, 0); + } + + // Pick a random quote + int q = rand() % SIZEOF(quotes); + _tcsncpy(popup.lptzContactName, quotes[q].name, MAX_CONTACTNAME); + _tcsncpy(popup.lptzText, quotes[q].text, MAX_SECONDLINE); + + popup.lchContact = hContact; + popup.iSeconds = get_timeout(hwndDlg); + popup.colorText = get_text_color(hwndDlg, false); + popup.colorBack = get_back_color(hwndDlg, false); + + CallService(MS_POPUP_ADDPOPUPT, reinterpret_cast<WPARAM>(&popup), 0); + } +} + +void CheckAndUpdateDlgButton(HWND hWnd, int button, BOOL check) +{ + CheckDlgButton(hWnd, button, check); + SendMessage(hWnd, WM_COMMAND, MAKELONG(button, BN_CLICKED), + (LPARAM)GetDlgItem(hWnd, button)); +} + +INT_PTR CALLBACK popup_options_proc(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam) +{ + using namespace popup_options; + TwitterProto *proto; + + int text_color, back_color, timeout; + + switch(msg) + { + case WM_INITDIALOG: + TranslateDialogDefault(hwndDlg); + + proto = reinterpret_cast<TwitterProto*>(lParam); + + CheckAndUpdateDlgButton(hwndDlg, IDC_SHOWPOPUPS, + db_byte_get(0, proto->ModuleName(), TWITTER_KEY_POPUP_SHOW, 0)); + CheckDlgButton(hwndDlg, IDC_NOSIGNONPOPUPS, + !db_byte_get(0, proto->ModuleName(), TWITTER_KEY_POPUP_SIGNON, 0)); + + + // ***** Get color information + back_color = db_dword_get(0, proto->ModuleName(), TWITTER_KEY_POPUP_COLBACK, 0); + text_color = db_dword_get(0, proto->ModuleName(), TWITTER_KEY_POPUP_COLTEXT, 0); + + SendDlgItemMessage(hwndDlg, IDC_COLBACK, CPM_SETCOLOUR, 0, RGB(255, 255, 255)); + SendDlgItemMessage(hwndDlg, IDC_COLTEXT, CPM_SETCOLOUR, 0, RGB( 0, 0, 0)); + + if (back_color == -1 && text_color == -1) // Windows defaults + CheckAndUpdateDlgButton(hwndDlg, IDC_COL_WINDOWS, true); + else if (back_color == 0 && text_color == 0) // Popup defaults + CheckAndUpdateDlgButton(hwndDlg, IDC_COL_POPUP, true); + else // Custom colors + { + CheckAndUpdateDlgButton(hwndDlg, IDC_COL_CUSTOM, true); + SendDlgItemMessage(hwndDlg, IDC_COLBACK, CPM_SETCOLOUR, 0, back_color); + SendDlgItemMessage(hwndDlg, IDC_COLTEXT, CPM_SETCOLOUR, 0, text_color); + } + + // ***** Get timeout information + timeout = db_dword_get(0, proto->ModuleName(), TWITTER_KEY_POPUP_TIMEOUT, 0); + SetDlgItemTextA(hwndDlg, IDC_TIMEOUT, "5"); + + if (timeout == 0) + CheckAndUpdateDlgButton(hwndDlg, IDC_TIMEOUT_DEFAULT, true); + else if (timeout < 0) + CheckAndUpdateDlgButton(hwndDlg, IDC_TIMEOUT_PERMANENT, true); + else + { + char str[32]; + _snprintf(str, sizeof(str), "%d", timeout); + SetDlgItemTextA(hwndDlg, IDC_TIMEOUT, str); + CheckAndUpdateDlgButton(hwndDlg, IDC_TIMEOUT_CUSTOM, true); + } + + SendDlgItemMessage(hwndDlg, IDC_TIMEOUT_SPIN, UDM_SETRANGE32, 1, INT_MAX); + SetWindowLong(hwndDlg, GWL_USERDATA, lParam); + + return true; + case WM_COMMAND: + switch(HIWORD(wParam)) + { + case BN_CLICKED: + switch(LOWORD(wParam)) + { + case IDC_SHOWPOPUPS: + EnableWindow(GetDlgItem(hwndDlg, IDC_NOSIGNONPOPUPS), + IsDlgButtonChecked(hwndDlg, IDC_SHOWPOPUPS)); + break; + + case IDC_COL_CUSTOM: + EnableWindow(GetDlgItem(hwndDlg, IDC_COLBACK), true); + EnableWindow(GetDlgItem(hwndDlg, IDC_COLTEXT), true); + break; + case IDC_COL_WINDOWS: + case IDC_COL_POPUP: + EnableWindow(GetDlgItem(hwndDlg, IDC_COLBACK), false); + EnableWindow(GetDlgItem(hwndDlg, IDC_COLTEXT), false); + break; + + case IDC_TIMEOUT_CUSTOM: + EnableWindow(GetDlgItem(hwndDlg, IDC_TIMEOUT), true); + EnableWindow(GetDlgItem(hwndDlg, IDC_TIMEOUT_SPIN), true); + break; + case IDC_TIMEOUT_DEFAULT: + case IDC_TIMEOUT_PERMANENT: + EnableWindow(GetDlgItem(hwndDlg, IDC_TIMEOUT), false); + EnableWindow(GetDlgItem(hwndDlg, IDC_TIMEOUT_SPIN), false); + break; + + case IDC_PREVIEW: + preview(hwndDlg); + break; + } + + case EN_CHANGE: + if (GetWindowLong(hwndDlg, GWL_USERDATA)) // Window is done initializing + SendMessage(GetParent(hwndDlg), PSM_CHANGED, 0, 0); + } + break; + case WM_NOTIFY: + if (reinterpret_cast<NMHDR*>(lParam)->code == PSN_APPLY) + { + proto = reinterpret_cast<TwitterProto*>(GetWindowLong(hwndDlg, GWL_USERDATA)); + + DBWriteContactSettingByte(0, proto->ModuleName(), TWITTER_KEY_POPUP_SHOW, + IsDlgButtonChecked(hwndDlg, IDC_SHOWPOPUPS)); + DBWriteContactSettingByte(0, proto->ModuleName(), TWITTER_KEY_POPUP_SIGNON, + !IsDlgButtonChecked(hwndDlg, IDC_NOSIGNONPOPUPS)); + + // ***** Write color settings + DBWriteContactSettingDword(0, proto->ModuleName(), TWITTER_KEY_POPUP_COLBACK, + get_back_color(hwndDlg, true)); + DBWriteContactSettingDword(0, proto->ModuleName(), TWITTER_KEY_POPUP_COLTEXT, + get_text_color(hwndDlg, true)); + + // ***** Write timeout setting + DBWriteContactSettingDword(0, proto->ModuleName(), TWITTER_KEY_POPUP_TIMEOUT, + get_timeout(hwndDlg)); + + return true; + } + break; + } + + return false; +} diff --git a/protocols/Twitter/ui.h b/protocols/Twitter/ui.h new file mode 100644 index 0000000000..f036f8d55d --- /dev/null +++ b/protocols/Twitter/ui.h @@ -0,0 +1,25 @@ +/* +Copyright 2009 Jim Porter + +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, see <http://www.gnu.org/licenses/>. +*/ + +#pragma once + +#include <windows.h> + +INT_PTR CALLBACK first_run_dialog(HWND hwndDlg,UINT msg,WPARAM wParam,LPARAM lParam); +INT_PTR CALLBACK tweet_proc(HWND hwndDlg,UINT msg,WPARAM wParam,LPARAM lParam); +INT_PTR CALLBACK options_proc(HWND hwndDlg,UINT msg,WPARAM wParam,LPARAM lParam); +INT_PTR CALLBACK popup_options_proc(HWND hwndDlg,UINT msg,WPARAM wParam,LPARAM lParam); \ No newline at end of file diff --git a/protocols/Twitter/utility.cpp b/protocols/Twitter/utility.cpp new file mode 100644 index 0000000000..221e413253 --- /dev/null +++ b/protocols/Twitter/utility.cpp @@ -0,0 +1,133 @@ +/* +Copyright 2009 Jim Porter + +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, see <http://www.gnu.org/licenses/>. +*/ + +#include "common.h" +#include "utility.h" + +#include <io.h> + +std::string b64encode(const std::string &s) +{ + NETLIBBASE64 encode; + encode.cbDecoded = s.length(); + encode.pbDecoded = (BYTE*)s.c_str(); + encode.cchEncoded = Netlib_GetBase64EncodedBufferSize(encode.cbDecoded); + encode.pszEncoded = new char[encode.cchEncoded+1]; + CallService(MS_NETLIB_BASE64ENCODE,0,(LPARAM)&encode); + std::string ret = encode.pszEncoded; + delete[] encode.pszEncoded; + + return ret; +} + +http::response mir_twitter::slurp(const std::string &url, http::method meth, const std::string &post_data) +{ + NETLIBHTTPREQUEST req = {sizeof(req)}; + NETLIBHTTPREQUEST *resp; + req.requestType = (meth == http::get) ? REQUEST_GET:REQUEST_POST; + req.szUrl = ( char* )url.c_str(); + + // probably not super-efficient to do this every time, but I don't really care + std::string auth = "Basic " + b64encode(username_) + ":" + password_; + + NETLIBHTTPHEADER hdr[2]; + hdr[0].szName = "Authorization"; + hdr[0].szValue = (char*)( auth.c_str()); + + req.headers = hdr; + req.headersCount = 1; + + if (meth == http::post) + { + hdr[1].szName = "Content-Type"; + hdr[1].szValue = "application/x-www-form-urlencoded"; + + req.headersCount = 2; + req.dataLength = post_data.size(); + req.pData = ( char* )post_data.c_str(); + } + + http::response resp_data; + + resp = reinterpret_cast<NETLIBHTTPREQUEST*>(CallService( MS_NETLIB_HTTPTRANSACTION, + reinterpret_cast<WPARAM>(handle_), reinterpret_cast<LPARAM>(&req))); + + if (resp) + { + resp_data.code = resp->resultCode; + resp_data.data = resp->pData ? resp->pData:""; + + CallService(MS_NETLIB_FREEHTTPREQUESTSTRUCT,0,(LPARAM)resp); + } + + return resp_data; +} + + + +bool save_url(HANDLE hNetlib,const std::string &url,const std::string &filename) +{ + NETLIBHTTPREQUEST req = {sizeof(req)}; + NETLIBHTTPREQUEST *resp; + req.requestType = REQUEST_GET; + req.szUrl = const_cast<char*>(url.c_str()); + + resp = reinterpret_cast<NETLIBHTTPREQUEST*>(CallService( MS_NETLIB_HTTPTRANSACTION, + reinterpret_cast<WPARAM>(hNetlib), reinterpret_cast<LPARAM>(&req))); + + if (resp) + { + // Create folder if necessary + std::string dir = filename.substr(0,filename.rfind('\\')); + if (_access(dir.c_str(),0)) + CallService(MS_UTILS_CREATEDIRTREE, 0, (LPARAM)dir.c_str()); + + // Write to file + FILE *f = fopen(filename.c_str(),"wb"); + fwrite(resp->pData,1,resp->dataLength,f); + fclose(f); + + CallService(MS_NETLIB_FREEHTTPREQUESTSTRUCT,0,(LPARAM)resp); + return true; + } + else + return false; +} + +static const struct +{ + char *ext; + int fmt; +} formats[] = { + { ".png", PA_FORMAT_PNG }, + { ".jpg", PA_FORMAT_JPEG }, + { ".jpeg", PA_FORMAT_JPEG }, + { ".ico", PA_FORMAT_ICON }, + { ".bmp", PA_FORMAT_BMP }, + { ".gif", PA_FORMAT_GIF }, +}; + +int ext_to_format(const std::string &ext) +{ + for(size_t i=0; i<SIZEOF(formats); i++) + { + if (ext == formats[i].ext) + return formats[i].fmt; + } + + return PA_FORMAT_UNKNOWN; +} \ No newline at end of file diff --git a/protocols/Twitter/utility.h b/protocols/Twitter/utility.h new file mode 100644 index 0000000000..b68a4fcb9d --- /dev/null +++ b/protocols/Twitter/utility.h @@ -0,0 +1,107 @@ +/* +Copyright 2009 Jim Porter + +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, see <http://www.gnu.org/licenses/>. +*/ + +#pragma once + +#include "http.h" +#include "twitter.h" + +template<typename T> +void CreateProtoService(const char *module,const char *service, + int (__cdecl T::*serviceProc)(WPARAM,LPARAM),T *self) +{ + char temp[MAX_PATH*2]; + + mir_snprintf(temp,sizeof(temp),"%s%s",module,service); + CreateServiceFunctionObj(temp,( MIRANDASERVICEOBJ )*(void**)&serviceProc, self ); +} + +template<typename T> +void HookProtoEvent(const char* evt, int (__cdecl T::*eventProc)(WPARAM,LPARAM), T *self) +{ + ::HookEventObj(evt,(MIRANDAHOOKOBJ)*(void**)&eventProc,self); +} + +template<typename T> +HANDLE ForkThreadEx(void (__cdecl T::*thread)(void*),T *self,void *data = 0) +{ + return reinterpret_cast<HANDLE>( mir_forkthreadowner( + (pThreadFuncOwner)*(void**)&thread,self,data,0)); +} + +template<typename T> +void ForkThread(void (__cdecl T::*thread)(void*),T *self,void *data = 0) +{ + CloseHandle(ForkThreadEx(thread,self,data)); +} + +std::string b64encode(const std::string &s); + +class mir_twitter : public twitter +{ +public: + void set_handle(HANDLE h) + { + handle_ = h; + } +protected: + http::response slurp(const std::string &,http::method,const std::string &); + HANDLE handle_; +}; + +inline void mbcs_to_tcs(UINT code_page,const char *mbstr,TCHAR *tstr,int tlen) +{ +#ifdef UNICODE + MultiByteToWideChar(code_page,0,mbstr,-1,tstr,tlen); +#else + strncpy(tstr,mbstr,tlen); +#endif +} + +inline void wcs_to_tcs(UINT code_page,const wchar_t *wstr,TCHAR *tstr,int tlen) +{ +#ifdef UNICODE + wcsncpy(tstr,wstr,tlen); +#else + WideCharToMultiByte(code_page,0,wstr,-1,tstr,tlen,0,0); +#endif +} + +class ScopedLock +{ +public: + ScopedLock(HANDLE h) : handle_(h) + { + WaitForSingleObject(handle_,INFINITE); + } + ~ScopedLock() + { + if (handle_) + ReleaseMutex(handle_); + } + + void Unlock() + { + ReleaseMutex(handle_); + handle_ = 0; + } +private: + HANDLE handle_; +}; + +int ext_to_format(const std::string &ext); +bool save_url(HANDLE hNetlib,const std::string &url,const std::string &filename); \ No newline at end of file diff --git a/protocols/Twitter/version.h b/protocols/Twitter/version.h new file mode 100644 index 0000000000..b27c53811e --- /dev/null +++ b/protocols/Twitter/version.h @@ -0,0 +1,20 @@ +/* +Copyright 2009 Jim Porter + +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, see <http://www.gnu.org/licenses/>. +*/ + +#pragma once + +#define __VERSION_DWORD PLUGIN_MAKE_VERSION(0, 0, 8, 4) \ No newline at end of file diff --git a/protocols/YAMN/ChangeLog.txt b/protocols/YAMN/ChangeLog.txt new file mode 100644 index 0000000000..6a85810ab2 --- /dev/null +++ b/protocols/YAMN/ChangeLog.txt @@ -0,0 +1,243 @@ +0.1.2.5 +======= +! fix many memory leaks patch by Merlin +* x64 support by Merlin +* Resource patch by mataes (for translations) + +0.1.2.4 +======= +* Only show popup tab if popup plugin is present +! Wrong time displayed in mailbrower (fix by y_b) + +0.1.2.3 +======= +* New design for the options pages (Thanks Eyecue) + +0.1.2.2 +======= +* using, with updater, the correct file id in file listing (yamn 2in1) ++ added folders plugin support ++ Support for miranda 0.8 + +0.1.2.1 +======= +! Don't close MailBrowser when e-mails are updated if it is manually open ++ Discard the new Event when message is shown or is deleted from the server ++ Option to disable the CList events per account ++ Contact status change also happens when e-mail are being deleted + +0.1.2.0 +======= +! patch by TioDuke for icolib and status and status icons handling. Thanks! +! code cleaning (properly destroy services and hooks) ++ Contact status changes accordingly the action (Ready, Working, Error) + +0.1.1.0 +======= ++ Show message is open in new thread ++ Click on individual new e-mail popups shows the message window + +0.1.0.2 +============ ++ Pressing "Space" key will show the selected message +! Delete message is done by DELETE key, not by '.' +! removed some repeated code +! "Ok" and "Select All" buttons in mail browser are translatable + +0.1.0.1 +============ ++ Message body shown in separate edit box. ++ Support for Content-transfer-encoding: Quoted-Printable and base64 ++ Recursive Content-type: multipart/ support ++ Option to auto retrieve body + +0.0.1.11 +============ ++ Option to use yamn as a protocol. +* Patch by Tioduke (code cleaning) +! Fixed the crash parsing invalid "Date" header (SPAMs or silly e-mail client) (y_b) +! ShowMessage dialog follows Content-type header to chose the codepage (y_b) ++ Only supported codepages are shown in the options (y_b) ++ Enhance codepages support (y_b) + +0.0.1.10 +============ +! Icons are based on single bitmap image (y_b) +* Show full feaders on double click in mailbrowser (y_b) +* Dates are shown localized and sorted correctly (y_b) +* To show long/short date and seconds (y_b) +! Solved a rare/random crash on unstable connection (y_b) +! Enabled tabstop on new tabcontrol and reordered tabstop in option pages (y_b) +* Enable TAB selection in mailbrowser dialog (patch by -pv-) ++ introducing 2in1 build - can be used both in win9x and NT/XP +* Options redesign. + +0.0.1.9 +============ +* Patch by Perf (visual patch) + +0.0.1.8 +============ ++ add ctr-A to select all mails ++ del key delete selected mail ++ add a select all button + +0.0.1.7 +============ +* Change options dialog (use tabsrmm uxtheme) +! Invert back and text color for no new mail popup in option page. +* New default icon reworked by Faith Healer. + +0.0.1.6 +============ +* Try to update all icons when changing in icolib. +! Allow scrolling in list of email account. (Patch by Jazzy) +! Memory leak in stls fix (y_b) + +0.0.1.5 +============ +! Bug fix with help.dll problem. (Patch by Jazzy) + (http://developer.berlios.de/bugs/?func=detailbug&bug_id=6692&group_id=3292) +! Remove merge in agressiveoptimize.h + +0.0.1.4 +============ +! Option page bug (patch by y_b) +* Allow to edit the application text + +0.0.1.3 +============ +! Bug fix with new icolib + +0.0.1.2 +============ +! Bug fix with updater and stable version ++ Using new m_icolib.h ++ New context menu entry to launch application ++ Patch by y_b +{ + + Start TLS support + + Better icolib support + + SSL Logging +} + +0.0.1.1 +============ +! Bug fix on left click popup. + +0.0.1.0 +============ +Time for release. + +0.0.0.18 +============ +! Visual bug in option page +! Recompilation for win 9x users. + +0.0.0.17 +============ +* Redesign option page to have only one entry in plugins options +! Bug fix when there is no date set in the header (spam mails) (Thx Egres) + +0.0.0.16 +============ +* Right click on error popup close the popup. +! Missing break; in nonewmail popup in switch. ++ Add option to rename contact according to new mail. +! Patch by pescuma on delete accounts + +0.0.0.15 +============ +! Fixed dismiss event by right click on new mail popup crash +* Change string for the status choose button +! use CallServiceSync() instead of CallService() for adding clistevent (now icon blinks) + +0.0.0.14 +============ +! Tooltip on the clist event will now show correct text +! Remove the messagebox on double clik on mail +* Change options dialog add dialog for status choose. + +0.0.0.13 +============ ++ Use of event count for the keyboard flashing + +0.0.0.12 +============ +- Remove message body retrieving due to bug. + +0.0.0.11 +============ ++ Add a function to retrieve the whole mail source. ++ Show the mail source when double clicking on it in mail browser. ++ Add a version resource. + +0.0.0.10 +============ ++ Now able to pass hContact handle to popup so can show avatar if set. +* Change folder structure in svn SDK\import replace by include + +0.0.0.9 +============ ++ Sorting asc and desc of the mail browser listview ++ Use the format yyyy-mm-dd hh:mm:ss for date comparaison in sorting ++ Doubleclick on list view to show the mail body but it seems to be empty :( + +0.0.0.8 +============ ++ Add date field in mail browser +* Modify the tooltip text for the clist event (add account name) +* Rename Contact member of CAccount by hContact since it is an HANDLE ++ Updater support for BETA +* Using the right headers (no more the one in SDK) + +0.0.0.7 +============ ++ Added changelog txt file. ++ Check presence of icolib to choose the right icon to show in clist ++ Status message will show all message pending in mail box (until they get retrieve by your email client) + +0.0.0.6 +============ +* Options page redesign. ++ Right click on popup close the clist event too. ++ Update status message if no new mail. ++ Right click on popup^with no new mail close the popup. +* No more delete of contact (avoid group affectation bug). + +0.0.0.5 +============ ++ Add contact context menu entry to check for new mail. ++ Catch double click event on contact to shown the mail browser. + +0.0.0.4 +============ ++ Add per account option to be show as contact or not. ++ Gestion de la suppression d'un compte ++ Use of the status message for showing number of emails. ++ Refresh yamn contact on the click on apply in options dialog. +* Better condition for the ^contact loop (ouuppsss) + +0.0.0.3 +============ ++ Now account are shown as a contact. ++ Source code modification and use of yamn.h ++ Wait the event moduleloaded before loading the icons (support icolib). + +0.0.0.2 +============ ++ Use of patch by Q (From file listing) (Memory cleaning, empty mail browser even if there are mails, yamn freeze sometime) ++ Use of thread access function. ++ Possibility to change toptoolbar icons via icolib. ++ Icon in main menu entry (Asked by a7) ++ New Icons set by Manudevil. ++ Change version number to be compatible with updater plugin + +0.01 +============ + ++ icolib support. ++ keyboard flash support (just 10 sec) (thx TioDuke) needs Keyboard Notify Ext. 1.5.4.4 ++ list of email can be sorted. +* left click on popup shows email list. +* better toptoolbar support. \ No newline at end of file diff --git a/protocols/YAMN/YAMN_10.sln b/protocols/YAMN/YAMN_10.sln new file mode 100644 index 0000000000..77f7c38c95 --- /dev/null +++ b/protocols/YAMN/YAMN_10.sln @@ -0,0 +1,26 @@ + +Microsoft Visual Studio Solution File, Format Version 11.00 +# Visual Studio 2010 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Yamn", "YAMN_10.vcxproj", "{C5A87409-F08C-4A07-A8F9-1F5D52BA6D72}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Win32 = Debug|Win32 + Debug|x64 = Debug|x64 + Release|Win32 = Release|Win32 + Release|x64 = Release|x64 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {C5A87409-F08C-4A07-A8F9-1F5D52BA6D72}.Debug|Win32.ActiveCfg = Debug|Win32 + {C5A87409-F08C-4A07-A8F9-1F5D52BA6D72}.Debug|Win32.Build.0 = Debug|Win32 + {C5A87409-F08C-4A07-A8F9-1F5D52BA6D72}.Debug|x64.ActiveCfg = Debug|x64 + {C5A87409-F08C-4A07-A8F9-1F5D52BA6D72}.Debug|x64.Build.0 = Debug|x64 + {C5A87409-F08C-4A07-A8F9-1F5D52BA6D72}.Release|Win32.ActiveCfg = Release|Win32 + {C5A87409-F08C-4A07-A8F9-1F5D52BA6D72}.Release|Win32.Build.0 = Release|Win32 + {C5A87409-F08C-4A07-A8F9-1F5D52BA6D72}.Release|x64.ActiveCfg = Release|x64 + {C5A87409-F08C-4A07-A8F9-1F5D52BA6D72}.Release|x64.Build.0 = Release|x64 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/protocols/YAMN/YAMN_10.vcxproj b/protocols/YAMN/YAMN_10.vcxproj new file mode 100644 index 0000000000..37e0d9f984 --- /dev/null +++ b/protocols/YAMN/YAMN_10.vcxproj @@ -0,0 +1,222 @@ +<?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>YAMN</ProjectName> + <ProjectGuid>{C5A87409-F08C-4A07-A8F9-1F5D52BA6D72}</ProjectGuid> + </PropertyGroup> + <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" /> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration"> + <ConfigurationType>DynamicLibrary</ConfigurationType> + <CharacterSet>Unicode</CharacterSet> + <WholeProgramOptimization>true</WholeProgramOptimization> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration"> + <ConfigurationType>DynamicLibrary</ConfigurationType> + <CharacterSet>Unicode</CharacterSet> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration"> + <ConfigurationType>DynamicLibrary</ConfigurationType> + <CharacterSet>Unicode</CharacterSet> + <WholeProgramOptimization>true</WholeProgramOptimization> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration"> + <ConfigurationType>DynamicLibrary</ConfigurationType> + <CharacterSet>Unicode</CharacterSet> + </PropertyGroup> + <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" /> + <ImportGroup Label="ExtensionSettings"> + </ImportGroup> + <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="PropertySheets"> + <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" /> + </ImportGroup> + <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="PropertySheets"> + <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" /> + </ImportGroup> + <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="PropertySheets"> + <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" /> + </ImportGroup> + <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="PropertySheets"> + <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" /> + </ImportGroup> + <PropertyGroup Label="UserMacros" /> + <PropertyGroup> + <_ProjectFileVersion>10.0.30319.1</_ProjectFileVersion> + <OutDir Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">$(SolutionDir)$(Configuration)\Plugins\</OutDir> + <IntDir Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">$(SolutionDir)$(Configuration)\Obj\$(ProjectName)\</IntDir> + <OutDir Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">$(SolutionDir)$(Configuration)\Plugins\</OutDir> + <IntDir Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">$(SolutionDir)$(Configuration)\Obj\$(ProjectName)\</IntDir> + <OutDir Condition="'$(Configuration)|$(Platform)'=='Release|x64'">$(SolutionDir)$(Configuration)64\Plugins\</OutDir> + <IntDir Condition="'$(Configuration)|$(Platform)'=='Release|x64'">$(SolutionDir)$(Configuration)64\Obj\$(ProjectName)\</IntDir> + <OutDir Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">$(SolutionDir)$(Configuration)64\Plugins\</OutDir> + <IntDir Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">$(SolutionDir)$(Configuration)64\Obj\$(ProjectName)\</IntDir> + <IgnoreImportLibrary Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</IgnoreImportLibrary> + <IgnoreImportLibrary Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">true</IgnoreImportLibrary> + <IgnoreImportLibrary Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</IgnoreImportLibrary> + <IgnoreImportLibrary Condition="'$(Configuration)|$(Platform)'=='Release|x64'">true</IgnoreImportLibrary> + </PropertyGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"> + <ClCompile> + <Optimization>Disabled</Optimization> + <AdditionalIncludeDirectories>..\..\include;..\plugins\ExternalAPI;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> + <PreprocessorDefinitions>WIN32;_DEBUG;_WINDOWS;_USRDLL;%(PreprocessorDefinitions)</PreprocessorDefinitions> + <BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks> + <RuntimeLibrary>MultiThreadedDebugDLL</RuntimeLibrary> + <WarningLevel>Level3</WarningLevel> + <DebugInformationFormat>EditAndContinue</DebugInformationFormat> + <DisableSpecificWarnings>4996;%(DisableSpecificWarnings)</DisableSpecificWarnings> + </ClCompile> + <ResourceCompile> + <PreprocessorDefinitions>_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions> + <AdditionalIncludeDirectories>..\..\include\msapi</AdditionalIncludeDirectories> + </ResourceCompile> + <Link> + <AdditionalDependencies>comctl32.lib;ws2_32.lib;%(AdditionalDependencies)</AdditionalDependencies> + <GenerateDebugInformation>true</GenerateDebugInformation> + <BaseAddress>0x60010000</BaseAddress> + <RandomizedBaseAddress>false</RandomizedBaseAddress> + <ImportLibrary>$(IntDir)$(TargetName).lib</ImportLibrary> + <SubSystem>Windows</SubSystem> + </Link> + </ItemDefinitionGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> + <ClCompile> + <Optimization>Full</Optimization> + <InlineFunctionExpansion>OnlyExplicitInline</InlineFunctionExpansion> + <FavorSizeOrSpeed>Size</FavorSizeOrSpeed> + <AdditionalIncludeDirectories>..\..\include;..\plugins\ExternalAPI;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> + <PreprocessorDefinitions>WIN32;NDEBUG;_WINDOWS;_USRDLL;%(PreprocessorDefinitions)</PreprocessorDefinitions> + <StringPooling>true</StringPooling> + <FunctionLevelLinking>true</FunctionLevelLinking> + <WarningLevel>Level3</WarningLevel> + <DisableSpecificWarnings>4996;%(DisableSpecificWarnings)</DisableSpecificWarnings> + </ClCompile> + <ResourceCompile> + <PreprocessorDefinitions>NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions> + <AdditionalIncludeDirectories>..\..\include\msapi</AdditionalIncludeDirectories> + </ResourceCompile> + <Link> + <AdditionalDependencies>comctl32.lib;ws2_32.lib;%(AdditionalDependencies)</AdditionalDependencies> + <OptimizeReferences>true</OptimizeReferences> + <EnableCOMDATFolding>true</EnableCOMDATFolding> + <BaseAddress>0x60010000</BaseAddress> + <RandomizedBaseAddress>false</RandomizedBaseAddress> + <ImportLibrary>$(IntDir)$(TargetName).lib</ImportLibrary> + <GenerateDebugInformation>true</GenerateDebugInformation> + <SubSystem>Windows</SubSystem> + </Link> + </ItemDefinitionGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'"> + <ClCompile> + <Optimization>Full</Optimization> + <InlineFunctionExpansion>OnlyExplicitInline</InlineFunctionExpansion> + <AdditionalIncludeDirectories>..\..\include;..\plugins\ExternalAPI;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> + <PreprocessorDefinitions>WIN64;NDEBUG;_WINDOWS;_USRDLL;%(PreprocessorDefinitions)</PreprocessorDefinitions> + <StringPooling>true</StringPooling> + <FunctionLevelLinking>true</FunctionLevelLinking> + <WarningLevel>Level3</WarningLevel> + <DisableSpecificWarnings>4996;%(DisableSpecificWarnings)</DisableSpecificWarnings> + <FavorSizeOrSpeed>Size</FavorSizeOrSpeed> + </ClCompile> + <ResourceCompile> + <PreprocessorDefinitions>NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions> + <AdditionalIncludeDirectories>..\..\include\msapi</AdditionalIncludeDirectories> + </ResourceCompile> + <Link> + <AdditionalDependencies>comctl32.lib;ws2_32.lib;%(AdditionalDependencies)</AdditionalDependencies> + <GenerateDebugInformation>true</GenerateDebugInformation> + <BaseAddress>0x60010000</BaseAddress> + <RandomizedBaseAddress>false</RandomizedBaseAddress> + <ImportLibrary>$(IntDir)$(TargetName).lib</ImportLibrary> + <SubSystem>Windows</SubSystem> + <OptimizeReferences>true</OptimizeReferences> + <EnableCOMDATFolding>true</EnableCOMDATFolding> + </Link> + </ItemDefinitionGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'"> + <ClCompile> + <Optimization>Disabled</Optimization> + <AdditionalIncludeDirectories>..\..\include;..\plugins\ExternalAPI;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> + <PreprocessorDefinitions>WIN64;_DEBUG;_WINDOWS;_USRDLL;%(PreprocessorDefinitions)</PreprocessorDefinitions> + <MinimalRebuild>true</MinimalRebuild> + <BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks> + <RuntimeLibrary>MultiThreadedDebugDLL</RuntimeLibrary> + <WarningLevel>Level3</WarningLevel> + <DisableSpecificWarnings>4996;%(DisableSpecificWarnings)</DisableSpecificWarnings> + </ClCompile> + <ResourceCompile> + <PreprocessorDefinitions>_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions> + <AdditionalIncludeDirectories>..\..\include\msapi</AdditionalIncludeDirectories> + </ResourceCompile> + <Link> + <AdditionalDependencies>comctl32.lib;ws2_32.lib;%(AdditionalDependencies)</AdditionalDependencies> + <GenerateDebugInformation>true</GenerateDebugInformation> + <BaseAddress>0x60010000</BaseAddress> + <RandomizedBaseAddress>false</RandomizedBaseAddress> + <ImportLibrary>$(IntDir)$(TargetName).lib</ImportLibrary> + <SubSystem>Windows</SubSystem> + </Link> + </ItemDefinitionGroup> + <ItemGroup> + <ClCompile Include="account.cpp" /> + <ClCompile Include="debug.cpp" /> + <ClCompile Include="filterplugin.cpp" /> + <ClCompile Include="main.cpp" /> + <ClCompile Include="protoplugin.cpp" /> + <ClCompile Include="services.cpp" /> + <ClCompile Include="synchro.cpp" /> + <ClCompile Include="yamn.cpp" /> + <ClCompile Include="browser\badconnect.cpp" /> + <ClCompile Include="browser\mailbrowser.cpp" /> + <ClCompile Include="mails\decode.cpp" /> + <ClCompile Include="mails\mails.cpp" /> + <ClCompile Include="mails\mime.cpp" /> + <ClCompile Include="proto\md5.c" /> + <ClCompile Include="proto\netlib.cpp" /> + <ClCompile Include="proto\pop3\pop3.cpp" /> + <ClCompile Include="proto\pop3\pop3comm.cpp" /> + <ClCompile Include="proto\pop3\pop3opt.cpp" /> + </ItemGroup> + <ItemGroup> + <None Include="resources\iconeutral.ico" /> + <None Include="resources\iconttbdown.ico" /> + <None Include="resources\icooffline.ico" /> + <None Include="resources\icoyamn3.ico" /> + <None Include="resources\yamn.bmp" /> + <None Include="ChangeLog.txt" /> + </ItemGroup> + <ItemGroup> + <ClInclude Include="resources\resource.h" /> + <ClInclude Include="debug.h" /> + <ClInclude Include="main.h" /> + <ClInclude Include="proto\pop3\pop3.h" /> + <ClInclude Include="proto\pop3\pop3comm.h" /> + <ClInclude Include="proto\pop3\pop3opt.h" /> + <ClInclude Include="yamn.h" /> + <ClInclude Include="version.h" /> + </ItemGroup> + <ItemGroup> + <ResourceCompile Include="resources\YAMN.rc" /> + <ResourceCompile Include="resources\yamn_ver.rc" /> + </ItemGroup> + <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" /> + <ImportGroup Label="ExtensionTargets"> + </ImportGroup> +</Project> \ No newline at end of file diff --git a/protocols/YAMN/YAMN_10.vcxproj.filters b/protocols/YAMN/YAMN_10.vcxproj.filters new file mode 100644 index 0000000000..9ad0a75aab --- /dev/null +++ b/protocols/YAMN/YAMN_10.vcxproj.filters @@ -0,0 +1,131 @@ +<?xml version="1.0" encoding="utf-8"?> +<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> + <ItemGroup> + <Filter Include="Source Files"> + <UniqueIdentifier>{30eb0c8d-5383-47ff-8a05-4b9793d26d50}</UniqueIdentifier> + <Extensions>cpp;c;cxx;rc;def;r;odl;idl;hpj;bat</Extensions> + </Filter> + <Filter Include="Source Files\Mail browser, dialogs"> + <UniqueIdentifier>{6b01a00c-f1f9-4958-b89a-2721d5bdd229}</UniqueIdentifier> + </Filter> + <Filter Include="Source Files\Mails"> + <UniqueIdentifier>{4743640f-ca6b-4518-8ead-525bea367ec0}</UniqueIdentifier> + </Filter> + <Filter Include="Source Files\POP3 plugin"> + <UniqueIdentifier>{0189ff00-aae9-40fd-847b-a81dca9496bd}</UniqueIdentifier> + </Filter> + <Filter Include="Resource Files"> + <UniqueIdentifier>{daef8d66-0947-4a6c-ad55-4e1b2bf26d86}</UniqueIdentifier> + <Extensions>ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe</Extensions> + </Filter> + <Filter Include="Header Files"> + <UniqueIdentifier>{c58708cc-53b7-4db2-b19e-4d6291665e8b}</UniqueIdentifier> + </Filter> + </ItemGroup> + <ItemGroup> + <ClCompile Include="account.cpp"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="debug.cpp"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="filterplugin.cpp"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="main.cpp"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="protoplugin.cpp"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="services.cpp"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="synchro.cpp"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="yamn.cpp"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="browser\badconnect.cpp"> + <Filter>Source Files\Mail browser, dialogs</Filter> + </ClCompile> + <ClCompile Include="browser\mailbrowser.cpp"> + <Filter>Source Files\Mail browser, dialogs</Filter> + </ClCompile> + <ClCompile Include="mails\decode.cpp"> + <Filter>Source Files\Mails</Filter> + </ClCompile> + <ClCompile Include="mails\mails.cpp"> + <Filter>Source Files\Mails</Filter> + </ClCompile> + <ClCompile Include="mails\mime.cpp"> + <Filter>Source Files\Mails</Filter> + </ClCompile> + <ClCompile Include="proto\md5.c"> + <Filter>Source Files\POP3 plugin</Filter> + </ClCompile> + <ClCompile Include="proto\netlib.cpp"> + <Filter>Source Files\POP3 plugin</Filter> + </ClCompile> + <ClCompile Include="proto\pop3\pop3.cpp"> + <Filter>Source Files\POP3 plugin</Filter> + </ClCompile> + <ClCompile Include="proto\pop3\pop3comm.cpp"> + <Filter>Source Files\POP3 plugin</Filter> + </ClCompile> + <ClCompile Include="proto\pop3\pop3opt.cpp"> + <Filter>Source Files\POP3 plugin</Filter> + </ClCompile> + </ItemGroup> + <ItemGroup> + <None Include="resources\iconeutral.ico"> + <Filter>Resource Files</Filter> + </None> + <None Include="resources\iconttbdown.ico"> + <Filter>Resource Files</Filter> + </None> + <None Include="resources\icooffline.ico"> + <Filter>Resource Files</Filter> + </None> + <None Include="resources\icoyamn3.ico"> + <Filter>Resource Files</Filter> + </None> + <None Include="resources\yamn.bmp"> + <Filter>Resource Files</Filter> + </None> + <None Include="ChangeLog.txt" /> + </ItemGroup> + <ItemGroup> + <ClInclude Include="resources\resource.h"> + <Filter>Resource Files</Filter> + </ClInclude> + <ClInclude Include="debug.h"> + <Filter>Header Files</Filter> + </ClInclude> + <ClInclude Include="main.h"> + <Filter>Header Files</Filter> + </ClInclude> + <ClInclude Include="proto\pop3\pop3.h"> + <Filter>Header Files</Filter> + </ClInclude> + <ClInclude Include="proto\pop3\pop3comm.h"> + <Filter>Header Files</Filter> + </ClInclude> + <ClInclude Include="proto\pop3\pop3opt.h"> + <Filter>Header Files</Filter> + </ClInclude> + <ClInclude Include="yamn.h"> + <Filter>Header Files</Filter> + </ClInclude> + <ClInclude Include="version.h" /> + </ItemGroup> + <ItemGroup> + <ResourceCompile Include="resources\YAMN.rc"> + <Filter>Resource Files</Filter> + </ResourceCompile> + <ResourceCompile Include="resources\yamn_ver.rc"> + <Filter>Resource Files</Filter> + </ResourceCompile> + </ItemGroup> +</Project> \ No newline at end of file diff --git a/protocols/YAMN/YAMNopts.cpp b/protocols/YAMN/YAMNopts.cpp new file mode 100644 index 0000000000..99a8091366 --- /dev/null +++ b/protocols/YAMN/YAMNopts.cpp @@ -0,0 +1,2 @@ + + diff --git a/protocols/YAMN/account.cpp b/protocols/YAMN/account.cpp new file mode 100644 index 0000000000..d1de8b8e4c --- /dev/null +++ b/protocols/YAMN/account.cpp @@ -0,0 +1,1309 @@ +/* + * This code implements manipulation with accounts + * such as reading accounts from file, writing them to file, + * finding account by name etc. + * + * (c) majvan 2002-2004 + */ + +#include "yamn.h" +#include "m_mails.h" +#if defined(DEBUG_FILEREAD) || defined(DEBUG_FILEREADMESSAGES) || defined(DEBUG_SYNCHRO) + #include <stdio.h> +#endif + +//Account status CS +//When we check some account, thread should change status of account to idle, connecting etc. +//So if we want to read status, we have to successfully write and then read. +CRITICAL_SECTION AccountStatusCS; + +//File Writing CS +//When 2 threads want to write to file... +CRITICAL_SECTION FileWritingCS; + +struct CExportedFunctions AccountExportedFcn[]= +{ + {YAMN_GETSTATUSID,(void *)GetStatusFcn}, + {YAMN_SETSTATUSID,(void *)SetStatusFcn}, +}; + +struct CExportedServices AccountExportedSvc[]= +{ + {MS_YAMN_CREATEPLUGINACCOUNT,CreatePluginAccountSvc}, + {MS_YAMN_DELETEPLUGINACCOUNT,DeletePluginAccountSvc}, + {MS_YAMN_FINDACCOUNTBYNAME,FindAccountByNameSvc}, + {MS_YAMN_GETNEXTFREEACCOUNT,GetNextFreeAccountSvc}, + {MS_YAMN_DELETEACCOUNT,DeletePluginAccountSvc}, + {MS_YAMN_READACCOUNTS,AddAccountsFromFileSvc}, + {MS_YAMN_WRITEACCOUNTS,WriteAccountsToFileSvc}, +}; + +//-------------------------------------------------------------------------------------------------- +//-------------------------------------------------------------------------------------------------- + +INT_PTR CreatePluginAccountSvc(WPARAM wParam,LPARAM lParam) +{ + HYAMNPROTOPLUGIN Plugin=(HYAMNPROTOPLUGIN)wParam; + DWORD AccountVersion=(DWORD)lParam; + HACCOUNT NewAccount; + +//test if we are going to initialize members of suitable structure (structures of plugin and YAMN must match) + if (AccountVersion!=YAMN_ACCOUNTVERSION) + return NULL; + + if (Plugin!=NULL) + { + if (Plugin->Fcn->NewAccountFcnPtr!=NULL) + { +//Let plugin create its own structure, which can be derived from CAccount structure + NewAccount=Plugin->Fcn->NewAccountFcnPtr(Plugin,YAMN_ACCOUNTVERSION); + NewAccount->Plugin=Plugin; + } + else + { +//We suggest plugin uses standard CAccount structure, so we create it + NewAccount=new struct CAccount; + NewAccount->Plugin=Plugin; + } +//If not created successfully + if (NewAccount==NULL) + return NULL; +//Init every members of structure, used by YAMN + InitAccount(NewAccount); + + return (INT_PTR)NewAccount; + } + return NULL; +} + +INT_PTR DeletePluginAccountSvc(WPARAM wParam,LPARAM) +{ + HACCOUNT OldAccount=(HACCOUNT)wParam; + + if (OldAccount->Plugin->Fcn!=NULL) + { +//Deinit every members and allocated fields of structure used by YAMN + DeInitAccount(OldAccount); + if (OldAccount->Plugin->Fcn->DeleteAccountFcnPtr!=NULL) + { +//Let plugin delete its own CAccount derived structure + OldAccount->Plugin->Fcn->DeleteAccountFcnPtr(OldAccount); + } + else + { +#ifdef DEBUG_SYNCHRO + DebugLog(SynchroFile,"DeletePluginAccountSvc:delete OldAccount\n"); +#endif + delete OldAccount; //consider account as standard YAMN HACCOUNT and use its own destructor + } + return 1; + } + delete OldAccount; //consider account as standard YAMN HACCOUNT, not initialized before and use its own destructor + return 1; +} + +int InitAccount(HACCOUNT Which) +{ +//initialize synchronizing objects + Which->AccountAccessSO=new SWMRG; + SWMRGInitialize(Which->AccountAccessSO,NULL); + Which->MessagesAccessSO=new SWMRG; + SWMRGInitialize(Which->MessagesAccessSO,NULL); + Which->UsingThreads=new SCOUNTER; + SWMRGInitialize(Which->MessagesAccessSO,NULL); + +//zero memory, where timestamps are stored + ZeroMemory(&Which->LastChecked,sizeof(Which->LastChecked)); + ZeroMemory(&Which->LastSChecked,sizeof(Which->LastSChecked)); + ZeroMemory(&Which->LastSynchronised,sizeof(Which->LastSynchronised)); + ZeroMemory(&Which->LastMail,sizeof(Which->LastMail)); + + Which->Name=NULL; + Which->Mails=NULL; + Which->Interval=0; + Which->Flags=0; + Which->StatusFlags=0; + Which->Next=NULL; + + Which->Server=new struct CServer; + Which->AbleToWork=TRUE; + + return 1; +} + +void DeInitAccount(HACCOUNT Which) +{ +//delete YAMN allocated fields + if (Which->Name!=NULL) + delete[] Which->Name; + if (Which->Server->Name!=NULL) + delete[] Which->Server->Name; + if (Which->Server->Login!=NULL) + delete[] Which->Server->Login; + if (Which->Server->Passwd!=NULL) + delete[] Which->Server->Passwd; + if (Which->Server!=NULL) + delete[] Which->Server; + + SWMRGDelete(Which->AccountAccessSO); + delete Which->AccountAccessSO; + SWMRGDelete(Which->MessagesAccessSO); + delete Which->MessagesAccessSO; + delete Which->UsingThreads; + DeleteMessagesToEndFcn(Which,(HYAMNMAIL)Which->Mails); +} + +void StopSignalFcn(HACCOUNT Which) +//set event that we are going to delete account +{ +#ifdef DEBUG_SYNCHRO + DebugLog(SynchroFile,"\tStopSignalFcn:stop account: %x\n",Which); +#endif + Which->AbleToWork=FALSE; +//do not use synchronizing objects anymore +//any access to these objects then ends with WAIT_FAILED + SetEvent(Which->AccountAccessSO->hFinishEV); + SetEvent(Which->MessagesAccessSO->hFinishEV); +} + +void CodeDecodeString(char *Dest,BOOL Encrypt) +{ + TCHAR Code=STARTCODEPSW; + + if (Dest==NULL) + return; + + for (;*Dest!=(TCHAR)0;Dest++) + { + if (Encrypt) + *Dest=*Dest+Code; + else + *Dest=*Dest-Code; + Code+=(TCHAR)ADDCODEPSW; + } +} + +static DWORD PostFileToMemory(HANDLE File,char **MemFile,char **End) +{ + DWORD FileSize,ReadBytes; + if (!(FileSize=GetFileSize(File,NULL))) { + CloseHandle(File); + return EACC_FILESIZE; + } + + //allocate space in memory, where we copy the whole file + if (NULL==(*MemFile = new char[FileSize])) + { + CloseHandle(File); + return EACC_ALLOC; + } + + //copy file to memory + if (!ReadFile(File,(LPVOID)*MemFile,FileSize,&ReadBytes,NULL)) + { + CloseHandle(File); + delete[] *MemFile; + return EACC_SYSTEM; + } + CloseHandle(File); + *End = *MemFile + FileSize; + return 0; +} + +DWORD FileToMemory(TCHAR *FileName,char **MemFile,char **End) +{ + HANDLE hFile = CreateFile(FileName, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); + if (hFile == INVALID_HANDLE_VALUE) + return EACC_SYSTEM; + + return PostFileToMemory(hFile, MemFile, End); +} + +#if defined(DEBUG_FILEREAD) || defined(DEBUG_FILEREADMESSAGES) +DWORD ReadStringFromMemory(char **Parser,TCHAR *End,char **StoreTo,TCHAR *DebugString) +{ +//This is the debug version of ReadStringFromMemory function. This version shows MessageBox where +//read string is displayed + TCHAR *Dest,*Finder; + DWORD Size; + TCHAR Debug[65536]; + + Finder=*Parser; + while((*Finder!=(TCHAR)0) && (Finder<=End)) Finder++; + _stprintf(Debug,_T("%s: %s,length is %d, remaining %d chars"),DebugString,*Parser,Finder-*Parser,End-Finder); + MessageBox(NULL,Debug,_T("debug"),MB_OK); + if (Finder>=End) + return EACC_FILECOMPATIBILITY; + if (Size=Finder-*Parser) + { + if (NULL==(Dest=*StoreTo=new TCHAR[Size+1])) + return EACC_ALLOC; + for (;*Parser<=Finder;(*Parser)++,Dest++) + *Dest=**Parser; + } + else + { + *StoreTo=NULL; + (*Parser)++; + } + return 0; +} +#endif + +DWORD ReadStringFromMemory(char **Parser,char *End,char **StoreTo) +{ + char *Dest,*Finder; + DWORD Size; + + Finder=*Parser; + while((*Finder!=(TCHAR)0) && (Finder<=End)) Finder++; + if (Finder>=End) + return EACC_FILECOMPATIBILITY; + if (Size=Finder-*Parser) + { + if (NULL==(Dest=*StoreTo=new char[Size+1])) + return EACC_ALLOC; + for (;*Parser<=Finder;(*Parser)++,Dest++) + *Dest=**Parser; + } + else + { + *StoreTo=NULL; + (*Parser)++; + } + return 0; +} + + #if defined(DEBUG_FILEREAD) || defined(DEBUG_FILEREADMESSAGES) +DWORD ReadStringFromMemoryW(WCHAR **Parser,TCHAR *End,WCHAR **StoreTo,WCHAR *DebugString) +{ +//This is the debug version of ReadStringFromMemoryW function. This version shows MessageBox where +//read string is displayed + WCHAR *Dest,*Finder; + DWORD Size; + WCHAR Debug[65536]; + + Finder=*Parser; + while((*Finder!=(WCHAR)0) && (Finder<=(WCHAR *)End)) Finder++; + swprintf(Debug,L"%s: %s,length is %d, remaining %d chars",DebugString,*Parser,Finder-*Parser,(WCHAR *)End-Finder); + MessageBoxW(NULL,Debug,L"debug",MB_OK); + if (Finder>=(WCHAR *)End) + return EACC_FILECOMPATIBILITY; + if (Size=Finder-*Parser) + { + if (NULL==(Dest=*StoreTo=new WCHAR[Size+1])) + return EACC_ALLOC; + for (;*Parser<=Finder;(*Parser)++,Dest++) + *Dest=**Parser; + } + else + { + *StoreTo=NULL; + (*Parser)++; + } + return 0; +} + #endif //if defined(DEBUG...) + +DWORD ReadStringFromMemoryW(WCHAR **Parser,WCHAR *End,WCHAR **StoreTo) +{ + WCHAR *Dest,*Finder; + DWORD Size; + + Finder=*Parser; + while((*Finder!=(WCHAR)0) && (Finder<=(WCHAR *)End)) Finder++; + if (Finder>=(WCHAR *)End) + return EACC_FILECOMPATIBILITY; + if (Size=Finder-*Parser) + { + if (NULL==(Dest=*StoreTo=new WCHAR[Size+1])) + return EACC_ALLOC; + for (;*Parser<=Finder;(*Parser)++,Dest++) + *Dest=**Parser; + } + else + { + *StoreTo=NULL; + (*Parser)++; + } + return 0; +} + +static DWORD ReadNotificationFromMemory(char **Parser,char *End,YAMN_NOTIFICATION *Which) +{ + DWORD Stat; +#ifdef DEBUG_FILEREAD + TCHAR Debug[65536]; +#endif + + Which->Flags=*(DWORD *)(*Parser); + (*Parser)+=sizeof(DWORD); + if (*Parser>=End) + return EACC_FILECOMPATIBILITY; +#ifdef DEBUG_FILEREAD + _stprintf(Debug,_T("NFlags: %04x, remaining %d chars"),Which->Flags,End-*Parser); + MessageBox(NULL,Debug,_T("debug"),MB_OK); +#endif + + Which->PopUpB=*(COLORREF *)(*Parser); + (*Parser)+=sizeof(COLORREF); + if (*Parser>=End) + return EACC_FILECOMPATIBILITY; +#ifdef DEBUG_FILEREAD + _stprintf(Debug,_T("PopUpB: %04x, remaining %d chars"),Which->PopUpB,End-*Parser); + MessageBox(NULL,Debug,_T("debug"),MB_OK); +#endif + Which->PopUpT=*(COLORREF *)(*Parser); + (*Parser)+=sizeof(COLORREF); + if (*Parser>=End) + return EACC_FILECOMPATIBILITY; +#ifdef DEBUG_FILEREAD + _stprintf(Debug,_T("PopUpT: %04x, remaining %d chars"),Which->PopUpT,End-*Parser); + MessageBox(NULL,Debug,_T("debug"),MB_OK); +#endif + Which->PopUpTime=*(DWORD *)(*Parser); + (*Parser)+=sizeof(DWORD); + if (*Parser>=End) + return EACC_FILECOMPATIBILITY; +#ifdef DEBUG_FILEREAD + _stprintf(Debug,_T("PopUpTime: %04x, remaining %d chars"),Which->PopUpTime,End-*Parser); + MessageBox(NULL,Debug,_T("debug"),MB_OK); +#endif + +#ifdef DEBUG_FILEREAD + if (Stat=ReadStringFromMemoryW((WCHAR **)Parser,(WCHAR*)End,&Which->App,L"App")) +#else + if (Stat=ReadStringFromMemoryW((WCHAR **)Parser,(WCHAR*)End,&Which->App)) +#endif + return Stat; +#ifdef DEBUG_FILEREAD + if (Stat=ReadStringFromMemoryW((WCHAR **)Parser,(WCHAR*)End,&Which->AppParam,L"AppParam")) +#else + if (Stat=ReadStringFromMemoryW((WCHAR **)Parser,(WCHAR*)End,&Which->AppParam)) +#endif + return Stat; + return 0; +} + +DWORD ReadMessagesFromMemory(HACCOUNT Which,char **Parser,char *End) +{ + char *Finder; + DWORD Size,Stat; + HYAMNMAIL ActualMail=NULL; + struct CMimeItem *items; + char *ReadString; + +#ifdef DEBUG_FILEREAD + MessageBox(NULL,_T("going to read messages, if any..."),_T("debug"),MB_OK); +#endif + do + { + Finder=*Parser; + while((*Finder!=(TCHAR)0) && (Finder<=End)) Finder++; + if (Finder>=End) + return EACC_FILECOMPATIBILITY; + if (Size=Finder-*Parser) + { + if (Which->Mails==NULL) //First message in queue + { + if (NULL==(Which->Mails=ActualMail=CreateAccountMail(Which))) + return EACC_ALLOC; + } + else + { + if (NULL==(ActualMail->Next=CreateAccountMail(Which))) { + return EACC_ALLOC; + } + ActualMail=ActualMail->Next; + } + items=NULL; +#ifdef DEBUG_FILEREADMESSAGES + if (Stat=ReadStringFromMemory(Parser,End,&ActualMail->ID,_T("ID"))) +#else + if (Stat=ReadStringFromMemory(Parser,End,&ActualMail->ID)) +#endif + return Stat; +// ActualMail->MailData=new MAILDATA; !!! mem leake !!! this is alloc by CreateAccountMail, no need for doubble alloc !!!! + + ActualMail->MailData->Size=*(DWORD *)(*Parser); + (*Parser)+=sizeof(DWORD); + if (*Parser>=End) + return EACC_FILECOMPATIBILITY; + ActualMail->Flags=*(DWORD *)(*Parser); + (*Parser)+=sizeof(DWORD); + if (*Parser>=End) + return EACC_FILECOMPATIBILITY; + ActualMail->Number=*(DWORD *)(*Parser); + (*Parser)+=sizeof(DWORD); + if (*Parser>=End) + return EACC_FILECOMPATIBILITY; + + if ((NULL!=Which->Plugin->MailFcn) && (NULL!=Which->Plugin->MailFcn->ReadMailOptsFcnPtr)) + Which->Plugin->MailFcn->ReadMailOptsFcnPtr(ActualMail,Parser,End); //read plugin mail settings from file + + do + { +#if defined(DEBUG_FILEREADMESSAGES) || defined(DEBUG_FILEREAD) + if (Stat=ReadStringFromMemory(Parser,End,&ReadString,_T("Name"))) +#else + if (Stat=ReadStringFromMemory(Parser,End,&ReadString)) +#endif + return Stat; + if (ReadString==NULL) + break; + +#ifdef DEBUG_DECODE + DebugLog(DecodeFile,"<read name>%s</read name>",ReadString); +#endif + + if (items==NULL) + items=ActualMail->MailData->TranslatedHeader=new struct CMimeItem; + else + { + items->Next=new struct CMimeItem; + items=items->Next; + } + if (items==NULL) + return EACC_ALLOC; + items->name=ReadString; + +#ifdef DEBUG_FILEREADMESSAGES + if (Stat=ReadStringFromMemory(Parser,End,&ReadString,_T("Value"))) +#else + if (Stat=ReadStringFromMemory(Parser,End,&ReadString)) +#endif + return Stat; + items->value=ReadString; +#ifdef DEBUG_DECODE + DebugLog(DecodeFile,"<read value>%s</read value>\n",ReadString); +#endif + }while(1); + } + else + break; //no next messages, new account! + + }while(1); + (*Parser)++; + return 0; +} + +DWORD ReadAccountFromMemory(HACCOUNT Which,char **Parser,char *End) +{ + DWORD Stat; +#ifdef DEBUG_FILEREAD + TCHAR Debug[65536]; +#endif + //Read name of account + +#ifdef DEBUG_FILEREAD + if (Stat=ReadStringFromMemory(Parser,End,&Which->Name,_T("Name"))) +#else + if (Stat=ReadStringFromMemory(Parser,End,&Which->Name)) +#endif + return Stat; + if (Which->Name==NULL) + return EACC_FILECOMPATIBILITY; + + //Read server parameters +#ifdef DEBUG_FILEREAD + if (Stat=ReadStringFromMemory(Parser,End,&Which->Server->Name,_T("Server"))) +#else + if (Stat=ReadStringFromMemory(Parser,End,&Which->Server->Name)) +#endif + return Stat; + Which->Server->Port=*(WORD *)(*Parser); + (*Parser)+=sizeof(WORD); + if (*Parser>=End) + return EACC_FILECOMPATIBILITY; +#ifdef DEBUG_FILEREAD + _stprintf(Debug,_T("Port: %d, remaining %d chars"),Which->Server->Port,End-*Parser); + MessageBox(NULL,Debug,_T("debug"),MB_OK); +#endif +#ifdef DEBUG_FILEREAD + if (Stat=ReadStringFromMemory(Parser,End,&Which->Server->Login,_T("Login"))) +#else + if (Stat=ReadStringFromMemory(Parser,End,&Which->Server->Login)) +#endif + return Stat; +#ifdef DEBUG_FILEREAD + if (Stat=ReadStringFromMemory(Parser,End,&Which->Server->Passwd,_T("Password"))) +#else + if (Stat=ReadStringFromMemory(Parser,End,&Which->Server->Passwd)) +#endif + return Stat; + CodeDecodeString(Which->Server->Passwd,FALSE); + + //Read account flags + Which->Flags=*(DWORD *)(*Parser); + (*Parser)+=sizeof(DWORD); + if (*Parser>=End) + return EACC_FILECOMPATIBILITY; +#ifdef DEBUG_FILEREAD + _stprintf(Debug,_T("Flags: %04x, remaining %d chars"),Which->Flags,End-*Parser); + MessageBox(NULL,Debug,_T("debug"),MB_OK); +#endif + Which->StatusFlags=*(DWORD *)(*Parser); + (*Parser)+=sizeof(DWORD); +#ifdef DEBUG_FILEREAD + _stprintf(Debug,_T("STFlags: %04x, remaining %d chars"),Which->StatusFlags,End-*Parser); + MessageBox(NULL,Debug,_T("debug"),MB_OK); +#endif + Which->PluginFlags=*(DWORD *)(*Parser); + (*Parser)+=sizeof(DWORD); +#ifdef DEBUG_FILEREAD + _stprintf(Debug,_T("PFlags: %04x, remaining %d chars"),Which->PluginFlags,End-*Parser); + MessageBox(NULL,Debug,_T("debug"),MB_OK); +#endif + + //Read account miscellaneous parameters + Which->Interval=*(WORD *)(*Parser); + Which->TimeLeft=Which->Interval; //check on loading + (*Parser)+=sizeof(WORD); + if (*Parser>=End) + return EACC_FILECOMPATIBILITY; +#ifdef DEBUG_FILEREAD + _stprintf(Debug,_T("Interval: %d, remaining %d chars"),Which->Interval,End-*Parser); + MessageBox(NULL,Debug,_T("debug"),MB_OK); +#endif + + //Read notification parameters + if (Stat=ReadNotificationFromMemory(Parser,End,&Which->NewMailN)) + return Stat; + if (Stat=ReadNotificationFromMemory(Parser,End,&Which->NoNewMailN)) + return Stat; + if (Stat=ReadNotificationFromMemory(Parser,End,&Which->BadConnectN)) + return Stat; + + //Let plugin read its own data stored in file + if (Which->Plugin->Fcn!=NULL && Which->Plugin->Fcn->ReadPluginOptsFcnPtr!=NULL) + if (Stat=Which->Plugin->Fcn->ReadPluginOptsFcnPtr(Which,Parser,End)) + return Stat; + //Read mails +#ifdef DEBUG_SYNCHRO + DebugLog(SynchroFile,"ReadAccountFromMemory:ActualAccountMsgsSO-write wait\n"); +#endif + WaitToWriteFcn(Which->MessagesAccessSO); +#ifdef DEBUG_SYNCHRO + DebugLog(SynchroFile,"ReadAccountFromMemory:ActualAccountMsgsSO-write enter\n"); +#endif + if (Stat=ReadMessagesFromMemory(Which,Parser,End)) + { +#ifdef DEBUG_SYNCHRO + DebugLog(SynchroFile,"ReadAccountFromMemory:ActualAccountMsgsSO-write done\n"); +#endif + WriteDoneFcn(Which->MessagesAccessSO); + return Stat; + } +#ifdef DEBUG_SYNCHRO + DebugLog(SynchroFile,"ReadAccountFromMemory:ActualAccountMsgsSO-write done\n"); +#endif + WriteDoneFcn(Which->MessagesAccessSO); + + //Read timestamps + Which->LastChecked=*(SYSTEMTIME *)(*Parser); + (*Parser)+=sizeof(SYSTEMTIME); + if (*Parser>=End) + return EACC_FILECOMPATIBILITY; +#ifdef DEBUG_FILEREAD + _stprintf(Debug,_T("LastChecked: %04x, remaining %d chars"),Which->LastChecked,End-*Parser); + MessageBox(NULL,Debug,_T("debug"),MB_OK); +#endif + Which->LastSChecked=*(SYSTEMTIME *)(*Parser); + (*Parser)+=sizeof(SYSTEMTIME); + if (*Parser>=End) + return EACC_FILECOMPATIBILITY; +#ifdef DEBUG_FILEREAD + _stprintf(Debug,_T("LastSChecked: %04x, remaining %d chars"),Which->LastSChecked,End-*Parser); + MessageBox(NULL,Debug,_T("debug"),MB_OK); +#endif + Which->LastSynchronised=*(SYSTEMTIME *)(*Parser); + (*Parser)+=sizeof(SYSTEMTIME); + if (*Parser>=End) + return EACC_FILECOMPATIBILITY; +#ifdef DEBUG_FILEREAD + _stprintf(Debug,_T("LastSynchronised: %04x, remaining %d chars"),Which->LastSynchronised,End-*Parser); + MessageBox(NULL,Debug,_T("debug"),MB_OK); +#endif + Which->LastMail=*(SYSTEMTIME *)(*Parser); + (*Parser)+=sizeof(SYSTEMTIME); + if (*Parser>End) //WARNING! There's only > at the end of testing + return EACC_FILECOMPATIBILITY; +#ifdef DEBUG_FILEREAD + _stprintf(Debug,_T("LastMail: %04x, remaining %d chars"),Which->LastMail,End-*Parser); + MessageBox(NULL,Debug,_T("debug"),MB_OK); +#endif + if (*Parser==End) + return EACC_ENDOFFILE; + return 0; + +} + +static INT_PTR PerformAccountReading(HYAMNPROTOPLUGIN Plugin,char *MemFile,char *End) +{ + //Retrieve info for account from memory + char *Parser; + DWORD Ver,Stat; + + HACCOUNT ActualAccount,FirstAllocatedAccount; + + Ver=*(DWORD *)MemFile; + if (Ver>YAMN_ACCOUNTFILEVERSION) + { + delete[] MemFile; + return EACC_FILEVERSION; + } + Parser=MemFile+sizeof(Ver); + +#ifdef DEBUG_SYNCHRO + DebugLog(SynchroFile,"AddAccountsFromFile:AccountBrowserSO-write wait\n"); +#endif + SWMRGWaitToWrite(Plugin->AccountBrowserSO,INFINITE); +#ifdef DEBUG_SYNCHRO + DebugLog(SynchroFile,"AddAccountsFromFile:AccountBrowserSO-write enter\n"); +#endif + if (NULL==(ActualAccount=(HACCOUNT)CallService(MS_YAMN_GETNEXTFREEACCOUNT,(WPARAM)Plugin,(LPARAM)YAMN_ACCOUNTVERSION))) + { +#ifdef DEBUG_SYNCHRO + DebugLog(SynchroFile,"AddAccountsFromFile:AccountBrowserSO-write done\n"); +#endif + SWMRGDoneWriting(Plugin->AccountBrowserSO); + delete[] MemFile; + return EACC_ALLOC; + } + FirstAllocatedAccount=ActualAccount; + + do + { + HACCOUNT Temp; + +#ifdef DEBUG_SYNCHRO + DebugLog(SynchroFile,"AddAccountsFromFile:ActualAccountSO-write wait\n"); +#endif + WaitToWriteFcn(ActualAccount->AccountAccessSO); +#ifdef DEBUG_SYNCHRO + DebugLog(SynchroFile,"AddAccountsFromFile:ActualAccountSO-write enter\n"); +#endif + Stat=ReadAccountFromMemory(ActualAccount,&Parser,End); + + if (ActualAccount->StatusFlags & (YAMN_ACC_STARTA | YAMN_ACC_STARTS)) + ActualAccount->TimeLeft=1; //check on loading + + if (Stat && (Stat!=EACC_ENDOFFILE)) + { + for (ActualAccount=FirstAllocatedAccount;ActualAccount!=NULL;ActualAccount=Temp) + { + Temp=ActualAccount->Next; + delete ActualAccount; + } + delete[] MemFile; + if (Plugin->FirstAccount==FirstAllocatedAccount) + Plugin->FirstAccount=NULL; +#ifdef DEBUG_SYNCHRO + DebugLog(SynchroFile,"AddAccountsFromFile:ActualAccountSO-write done\n"); +#endif + SWMRGDoneWriting(Plugin->AccountBrowserSO); + return (INT_PTR)Stat; + } + +#ifdef DEBUG_SYNCHRO + DebugLog(SynchroFile,"AddAccountsFromFile:ActualAccountSO-write done\n"); +#endif + WriteDoneFcn(ActualAccount->AccountAccessSO); + + if ((Stat!=EACC_ENDOFFILE) && (NULL==(ActualAccount=(HACCOUNT)CallService(MS_YAMN_GETNEXTFREEACCOUNT,(WPARAM)Plugin,(LPARAM)YAMN_ACCOUNTVERSION)))) + { + for (ActualAccount=FirstAllocatedAccount;ActualAccount!=NULL;ActualAccount=Temp) + { + Temp=ActualAccount->Next; + delete ActualAccount; + } + delete[] MemFile; + if (Plugin->FirstAccount==FirstAllocatedAccount) + Plugin->FirstAccount=NULL; +#ifdef DEBUG_SYNCHRO + DebugLog(SynchroFile,"AddAccountsFromFile:AccountBrowserSO-write done\n"); +#endif + SWMRGDoneWriting(Plugin->AccountBrowserSO); + return EACC_ALLOC; + } + }while(Stat!=EACC_ENDOFFILE); + +#ifdef DEBUG_SYNCHRO + DebugLog(SynchroFile,"AddAccountsFromFile:AccountBrowserSO-write done\n"); +#endif + SWMRGDoneWriting(Plugin->AccountBrowserSO); + delete[] MemFile; + + return 0; +} + +// Add accounts from file to memory +INT_PTR AddAccountsFromFileSvc(WPARAM wParam,LPARAM lParam) +{ + char *MemFile,*End; + DWORD Stat = FileToMemory(( TCHAR* )lParam, &MemFile, &End); + if ( Stat != NO_ERROR ) + return (INT_PTR)Stat; + + return PerformAccountReading((HYAMNPROTOPLUGIN)wParam,MemFile,End); +} + +DWORD WriteStringToFile(HANDLE File,char *Source) +{ + DWORD Length,WrittenBytes; + char null = 0; + + if ((Source==NULL) || !(Length=(DWORD)strlen(Source))) { + if (!WriteFile(File,&null,1,&WrittenBytes,NULL)) { + CloseHandle(File); + return EACC_SYSTEM; + } + } + else if (!WriteFile(File,Source,(Length+1),&WrittenBytes,NULL)) { + CloseHandle(File); + return EACC_SYSTEM; + } + return 0; +} + +DWORD WriteStringToFileW(HANDLE File,WCHAR *Source) +{ + DWORD Length,WrittenBytes; + WCHAR null=(WCHAR)0; + + if ((Source==NULL) || !(Length=(DWORD)wcslen(Source))) + { + if (!WriteFile(File,&null,sizeof(WCHAR),&WrittenBytes,NULL)) + { + CloseHandle(File); + return EACC_SYSTEM; + } + } + else if (!WriteFile(File,Source,(Length+1)*sizeof(WCHAR),&WrittenBytes,NULL)) + return EACC_SYSTEM; + return 0; +} + +DWORD WriteMessagesToFile(HANDLE File,HACCOUNT Which) +{ + DWORD WrittenBytes,Stat; + HYAMNMAIL ActualMail=(HYAMNMAIL)Which->Mails; + struct CMimeItem *items; + + while(ActualMail!=NULL) + { + if (Stat=WriteStringToFile(File,ActualMail->ID)) + return Stat; + if (!WriteFile(File,(char *)&ActualMail->MailData->Size,sizeof(ActualMail->MailData->Size),&WrittenBytes,NULL) || + !WriteFile(File,(char *)&ActualMail->Flags,sizeof(ActualMail->Flags),&WrittenBytes,NULL) || + !WriteFile(File,(char *)&ActualMail->Number,sizeof(ActualMail->Number),&WrittenBytes,NULL)) + return EACC_SYSTEM; + if ((NULL!=Which->Plugin->MailFcn) && (NULL!=Which->Plugin->MailFcn->WriteMailOptsFcnPtr)) + Which->Plugin->MailFcn->WriteMailOptsFcnPtr(File,ActualMail); //write plugin mail options to file + for (items=ActualMail->MailData->TranslatedHeader;items!=NULL;items=items->Next) + { + if (Stat=WriteStringToFile(File,items->name)) + return Stat; + if (Stat=WriteStringToFile(File,items->value)) + return Stat; + } + if (Stat=WriteStringToFile(File,"")) + return Stat; + ActualMail=ActualMail->Next; + } + if (Stat=WriteStringToFile(File,"")) + return Stat; + return 0; +} + +static INT_PTR PerformAccountWriting(HYAMNPROTOPLUGIN Plugin,HANDLE File) +{ + DWORD WrittenBytes,Stat; + HACCOUNT ActualAccount; + DWORD Ver=YAMN_ACCOUNTFILEVERSION; + BOOL Writed=FALSE; + DWORD ReturnValue=0,EnterCode; + +#ifdef DEBUG_SYNCHRO + DebugLog(SynchroFile,"WriteAccountsToFile:AccountBrowserSO-read wait\n"); +#endif + SWMRGWaitToRead(Plugin->AccountBrowserSO,INFINITE); +#ifdef DEBUG_SYNCHRO + DebugLog(SynchroFile,"WriteAccountsToFile:AccountBrowserSO-read enter\n"); +#endif + try + { + for (ActualAccount=Plugin->FirstAccount;ActualAccount!=NULL;ActualAccount=ActualAccount->Next) + { +/* TCHAR DEBUG[100]; + Beep(3000,100);Sleep(200); + _stprintf(DEBUG,_T("Browsing account %s"),ActualAccount->Name==NULL ? _T("(null)") : ActualAccount->Name); + MessageBox(NULL,DEBUG,_T("debug- WriteAccount..."),MB_OK); +*/ +#ifdef DEBUG_SYNCHRO + DebugLog(SynchroFile,"WriteAccountsToFile:ActualAccountSO-read wait\n"); +#endif + EnterCode=WaitToReadFcn(ActualAccount->AccountAccessSO); + if (EnterCode==WAIT_FINISH) //account is about to delete + { +#ifdef DEBUG_SYNCHRO + DebugLog(SynchroFile,"WriteAccountsToFile:ActualAccountSO-read wait failed\n"); +#endif + ActualAccount=ActualAccount->Next; + continue; + } + if (EnterCode==WAIT_FAILED) //account is deleted + break; +#ifdef DEBUG_SYNCHRO + DebugLog(SynchroFile,"WriteAccountsToFile:ActualAccountSO-read enter\n"); +#endif + if ((ActualAccount->Name==NULL) || (*ActualAccount->Name==(TCHAR)0)) + { +#ifdef DEBUG_SYNCHRO + DebugLog(SynchroFile,"WriteAccountsToFile:ActualAccountSO-read done\n"); +#endif + ReadDoneFcn(ActualAccount->AccountAccessSO); + continue; + } + + if (!Writed && !WriteFile(File,&Ver,sizeof(Ver),&WrittenBytes,NULL)) + throw (DWORD)EACC_SYSTEM; + Writed=TRUE; + + if (Stat=WriteStringToFile(File,ActualAccount->Name)) + throw (DWORD)Stat; + + if (Stat=WriteStringToFile(File,ActualAccount->Server->Name)) + throw (DWORD)Stat; + + if (!WriteFile(File,(char *)&ActualAccount->Server->Port,2,&WrittenBytes,NULL)) + throw (DWORD)EACC_SYSTEM; + + if ((Stat=WriteStringToFile(File,ActualAccount->Server->Login))) + throw (DWORD)Stat; + + CodeDecodeString(ActualAccount->Server->Passwd,TRUE); + + if (Stat=WriteStringToFile(File,ActualAccount->Server->Passwd)) + { + CodeDecodeString(ActualAccount->Server->Passwd,FALSE); + throw (DWORD)Stat; + } + CodeDecodeString(ActualAccount->Server->Passwd,FALSE); + + if ((!WriteFile(File,(char *)&ActualAccount->Flags,sizeof(DWORD),&WrittenBytes,NULL) || + (!WriteFile(File,(char *)&ActualAccount->StatusFlags,sizeof(DWORD),&WrittenBytes,NULL)) || + (!WriteFile(File,(char *)&ActualAccount->PluginFlags,sizeof(DWORD),&WrittenBytes,NULL)))) + throw (DWORD)EACC_SYSTEM; + + if (!WriteFile(File,(char *)&ActualAccount->Interval,sizeof(WORD),&WrittenBytes,NULL)) + throw (DWORD)EACC_SYSTEM; + + if ((!WriteFile(File,(char *)&ActualAccount->NewMailN.Flags,sizeof(DWORD),&WrittenBytes,NULL)) || + (!WriteFile(File,(char *)&ActualAccount->NewMailN.PopUpB,sizeof(COLORREF),&WrittenBytes,NULL)) || + (!WriteFile(File,(char *)&ActualAccount->NewMailN.PopUpT,sizeof(COLORREF),&WrittenBytes,NULL)) || + (!WriteFile(File,(char *)&ActualAccount->NewMailN.PopUpTime,sizeof(DWORD),&WrittenBytes,NULL))) + throw (DWORD)EACC_SYSTEM; + + if ((Stat=WriteStringToFileW(File,ActualAccount->NewMailN.App)) || + (Stat=WriteStringToFileW(File,ActualAccount->NewMailN.AppParam))) + throw (DWORD)Stat; + + if ((!WriteFile(File,(char *)&ActualAccount->NoNewMailN.Flags,sizeof(DWORD),&WrittenBytes,NULL)) || + (!WriteFile(File,(char *)&ActualAccount->NoNewMailN.PopUpB,sizeof(COLORREF),&WrittenBytes,NULL)) || + (!WriteFile(File,(char *)&ActualAccount->NoNewMailN.PopUpT,sizeof(COLORREF),&WrittenBytes,NULL)) || + (!WriteFile(File,(char *)&ActualAccount->NoNewMailN.PopUpTime,sizeof(DWORD),&WrittenBytes,NULL))) + throw (DWORD)EACC_SYSTEM; + + if ((Stat=WriteStringToFileW(File,ActualAccount->NoNewMailN.App)) || + (Stat=WriteStringToFileW(File,ActualAccount->NoNewMailN.AppParam))) + throw (DWORD)Stat; + + if ((!WriteFile(File,(char *)&ActualAccount->BadConnectN.Flags,sizeof(DWORD),&WrittenBytes,NULL)) || + (!WriteFile(File,(char *)&ActualAccount->BadConnectN.PopUpB,sizeof(COLORREF),&WrittenBytes,NULL)) || + (!WriteFile(File,(char *)&ActualAccount->BadConnectN.PopUpT,sizeof(COLORREF),&WrittenBytes,NULL)) || + (!WriteFile(File,(char *)&ActualAccount->BadConnectN.PopUpTime,sizeof(DWORD),&WrittenBytes,NULL))) + throw (DWORD)EACC_SYSTEM; + + if ((Stat=WriteStringToFileW(File,ActualAccount->BadConnectN.App)) || + (Stat=WriteStringToFileW(File,ActualAccount->BadConnectN.AppParam))) + throw (DWORD)Stat; + +//Let plugin write its own values into file + if (ActualAccount->Plugin->Fcn!=NULL && ActualAccount->Plugin->Fcn->WritePluginOptsFcnPtr!=NULL) + if (Stat=ActualAccount->Plugin->Fcn->WritePluginOptsFcnPtr(File,ActualAccount)) + throw (DWORD)Stat; +#ifdef DEBUG_SYNCHRO + DebugLog(SynchroFile,"WriteAccountsToFile:ActualAccountMsgsSO-read wait\n"); +#endif + WaitToReadFcn(ActualAccount->MessagesAccessSO); +#ifdef DEBUG_SYNCHRO + DebugLog(SynchroFile,"WriteAccountsToFile:ActualAccountMsgsSO-read enter\n"); +#endif + if (Stat=WriteMessagesToFile(File,ActualAccount)) + { +#ifdef DEBUG_SYNCHRO + DebugLog(SynchroFile,"WriteAccountsToFile:ActualAccountMsgsSO-read done\n"); +#endif + ReadDoneFcn(ActualAccount->MessagesAccessSO); + throw (DWORD)Stat; + } +#ifdef DEBUG_SYNCHRO + DebugLog(SynchroFile,"WriteAccountsToFile:ActualAccountMsgsSO-read done\n"); +#endif + ReadDoneFcn(ActualAccount->MessagesAccessSO); + + if ((!WriteFile(File,(char *)&ActualAccount->LastChecked,sizeof(SYSTEMTIME),&WrittenBytes,NULL)) || + (!WriteFile(File,(char *)&ActualAccount->LastSChecked,sizeof(SYSTEMTIME),&WrittenBytes,NULL)) || + (!WriteFile(File,(char *)&ActualAccount->LastSynchronised,sizeof(SYSTEMTIME),&WrittenBytes,NULL)) || + (!WriteFile(File,(char *)&ActualAccount->LastMail,sizeof(SYSTEMTIME),&WrittenBytes,NULL))) + throw (DWORD)Stat; + +#ifdef DEBUG_SYNCHRO + DebugLog(SynchroFile,"WriteAccountsToFile:ActualAccountSO-read done\n"); +#endif + ReadDoneFcn(ActualAccount->AccountAccessSO); + } + } + catch(DWORD ErrorCode) + { +#ifdef DEBUG_SYNCHRO + DebugLog(SynchroFile,"WriteAccountsToFile:ActualAccountSO-read done\n"); +#endif + ReadDoneFcn(ActualAccount->AccountAccessSO); + ReturnValue=ErrorCode; + } +#ifdef DEBUG_SYNCHRO + DebugLog(SynchroFile,"WriteAccountsToFile:AccountBrowserSO-read done\n"); +#endif + SWMRGDoneReading(Plugin->AccountBrowserSO); + CloseHandle(File); + return 0; +} + +//Writes accounts to file +INT_PTR WriteAccountsToFileSvc(WPARAM wParam,LPARAM lParam) +{ + HYAMNPROTOPLUGIN Plugin = ( HYAMNPROTOPLUGIN )wParam; + TCHAR* tszFileName = ( TCHAR* )lParam; + + EnterCriticalSection( &FileWritingCS ); + HANDLE hFile = CreateFile(tszFileName, GENERIC_WRITE, FILE_SHARE_WRITE, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL ); + if ( hFile == INVALID_HANDLE_VALUE ) { + LeaveCriticalSection(&FileWritingCS); + return EACC_SYSTEM; + } + + INT_PTR rv = PerformAccountWriting(Plugin, hFile); + LeaveCriticalSection(&FileWritingCS); + + return rv; +} + +INT_PTR FindAccountByNameSvc(WPARAM wParam,LPARAM lParam) +{ + HYAMNPROTOPLUGIN Plugin=(HYAMNPROTOPLUGIN)wParam; + char *SearchedAccount=(char *)lParam; + HACCOUNT Finder; + +#ifdef DEBUG_SYNCHRO + DebugLog(SynchroFile,"FindAccountByName:AccountBrowserSO-read wait\n"); +#endif + SWMRGWaitToRead(Plugin->AccountBrowserSO,INFINITE); +#ifdef DEBUG_SYNCHRO + DebugLog(SynchroFile,"FindAccountByName:AccountBrowserSO-read enter\n"); +#endif + for (Finder=Plugin->FirstAccount;Finder!=NULL;Finder=Finder->Next) + if ((Finder->Name!=NULL) && (0 == strcmp(SearchedAccount,Finder->Name))) + break; +#ifdef DEBUG_SYNCHRO + DebugLog(SynchroFile,"FindAccountByName:AccountBrowserSO-read done\n"); +#endif + SWMRGDoneReading(Plugin->AccountBrowserSO); + return (INT_PTR)Finder; +} + +INT_PTR GetNextFreeAccountSvc(WPARAM wParam,LPARAM lParam) +{ + HYAMNPROTOPLUGIN Plugin=(HYAMNPROTOPLUGIN)wParam; + HACCOUNT Finder; + + if (Plugin->FirstAccount==NULL) + { + Plugin->FirstAccount=(HACCOUNT)CallService(MS_YAMN_CREATEPLUGINACCOUNT,wParam,lParam); + return (INT_PTR)Plugin->FirstAccount; + } + for (Finder=Plugin->FirstAccount;Finder->Next!=NULL;Finder=Finder->Next); + Finder->Next=(HACCOUNT)CallService(MS_YAMN_CREATEPLUGINACCOUNT,wParam,lParam); + return (INT_PTR)Finder->Next; +} + +/* +int FindPluginAccount(WPARAM wParam,LPARAM lParam) +{ + HYAMNPROTOPLUGIN Plugin=(HYAMNPROTOPLUGIN)wParam; + HACCOUNT Finder=(HACCOUNT)lParam; + + if (Finder=NULL) Finder=Plugin->FirstAccount; + +// for (;Finder!=NULL && Finder->PluginID!=Plugin->PluginInfo->PluginID;Finder=(HACCOUNT)Finder->Next); + return (int)Finder; +} +*/ +INT_PTR DeleteAccountSvc(WPARAM wParam,LPARAM lParam) +{ +//Deleting account works on these steps: +//1. set signal that account should stop activity (set event) +// setting this event we achieve, that any access to account is failed, +// so threads do not start any work with accounts (better saying threads of plugins should not start) +//2. wait to get write access to chained list of accounts +//3. we can write to chained list, so we change chain not to show to actual account +// now, any thread browsing list of accounts does not browse through actual account +// actual account seems to be hidden (it exists, but it is not in accounts chained list (chained list=queue)) +//Now, we should delete account from memory, BUT!!! +// Any thread can still be waked up and start asking account synchronizing object +// If account is deleted, asking about access to read account can throw memory exception (reading for +// a synchronizing object from memory, that was deleted) +//So, we cannot now delete account. We have to wait until we are sure no thread will be using account anymore +// (or to the end of Miranda, but problem is in allocated memory- it is allocated and Miranda is SMALLER, faster, easier, isn't it?) +// This deleting is achieved in 2 ways: +// We have event in UsingThreads synchronization objects. This event signals that no thread will use actual account +// 1. Any thread using account first increment UsingThread, so we know that account is used +// 2. If thread is about to close, it should decrement UsingThread +// 3. If thread creates another thread, that will use account, caller has to wait until the new thread does not +// increment UsingThreads (imagine that caller ends before the new thread set it: if no other thread is using +// account, account is automaticaly (decreasing UsingThreads) signaled as "not used" and we delete it. But then +// new thread is going to read account...). +//4. wait until UsingThread Event is signaled +//5. delete account from memory + + HYAMNPROTOPLUGIN Plugin=(HYAMNPROTOPLUGIN)wParam; + HACCOUNT Which=(HACCOUNT)lParam; + HACCOUNT Finder; + DWORD tid; + +//1. set stop signal + StopSignalFcn(Which); + WindowList_BroadcastAsync(YAMNVar.MessageWnds,WM_YAMN_STOPACCOUNT,(WPARAM)Which,(LPARAM)0); + if (Plugin->Fcn->StopAccountFcnPtr!=NULL) + Plugin->Fcn->StopAccountFcnPtr(Which); + +//2. wait to get write access +#ifdef DEBUG_SYNCHRO + DebugLog(SynchroFile,"DeleteAccount:AccountBrowserSO-write wait\n"); +#endif + SWMRGWaitToWrite(Plugin->AccountBrowserSO,INFINITE); +#ifdef DEBUG_SYNCHRO + DebugLog(SynchroFile,"DeleteAccount:AccountBrowserSO-write enter\n"); +#endif + +//3. remove from queue (chained list) + if (Plugin->FirstAccount==NULL) + { +#ifdef DEBUG_SYNCHRO + DebugLog(SynchroFile,"DeleteAccount:AccountBrowserSO-write done\n"); +#endif + SWMRGDoneWriting(Plugin->AccountBrowserSO); + return 0; + } + if (Plugin->FirstAccount==Which) + { + Finder=Plugin->FirstAccount->Next; + Plugin->FirstAccount=Finder; + } + else + { + for (Finder=Plugin->FirstAccount;Which!=Finder->Next;Finder=Finder->Next); + Finder->Next=Finder->Next->Next; + } +//leave write access +#ifdef DEBUG_SYNCHRO + DebugLog(SynchroFile,"DeleteAccount:AccountBrowserSO-write done\n"); +#endif + SWMRGDoneWriting(Plugin->AccountBrowserSO); + +//4. wait while event "UsingThread" is not signaled +// And what to do, if this event will be signaled in 1 hour? (Although it's paranoia, because we have sent "delete signal", so +// other threads do not start any new work with actual account) We will wait in blocked state? +// No, of course not. We will create new thread, that will wait and additionally remove our thread in background. +//5. So, the last point (deleting from memory) is performed in new DeleteAccountInBackground thread + + if ((Plugin->Fcn!=NULL) && (Plugin->Fcn->WriteAccountsFcnPtr!=NULL)) + Plugin->Fcn->WriteAccountsFcnPtr(); + CloseHandle(CreateThread(NULL,0,DeleteAccountInBackground,(LPVOID)Which,0,&tid)); + +//Now, plugin can consider account as deleted, but plugin really can achieve deleting this account from memory when using +//event UsingThreads. + return 1; +} + +DWORD WINAPI DeleteAccountInBackground(LPVOID Value) +{ + HACCOUNT Which=(HACCOUNT)Value; + WaitForSingleObject(Which->UsingThreads->Event,INFINITE); + CallService(MS_YAMN_DELETEPLUGINACCOUNT,(WPARAM)Which,(LPARAM)0); + return 0; +} + +int StopAccounts(HYAMNPROTOPLUGIN Plugin) +{ + HACCOUNT Finder; + +//1. wait to get write access +#ifdef DEBUG_SYNCHRO + DebugLog(SynchroFile,"StopAccounts:AccountBrowserSO-write wait\n"); +#endif + SWMRGWaitToWrite(Plugin->AccountBrowserSO,INFINITE); +#ifdef DEBUG_SYNCHRO + DebugLog(SynchroFile,"StopAccounts:AccountBrowserSO-write enter\n"); +#endif + for (Finder=Plugin->FirstAccount;Finder!=NULL;Finder=Finder->Next) + { +//2. set stop signal + StopSignalFcn(Finder); + WindowList_BroadcastAsync(YAMNVar.MessageWnds,WM_YAMN_STOPACCOUNT,(WPARAM)Finder,(LPARAM)0); + if (Plugin->Fcn->StopAccountFcnPtr!=NULL) + Plugin->Fcn->StopAccountFcnPtr(Finder); + } + +//leave write access +#ifdef DEBUG_SYNCHRO + DebugLog(SynchroFile,"StopAccounts:AccountBrowserSO-write done\n"); +#endif + SWMRGDoneWriting(Plugin->AccountBrowserSO); + +//Now, account is stopped. It can be removed from memory... + return 1; +} + +int WaitForAllAccounts(HYAMNPROTOPLUGIN Plugin,BOOL GetAccountBrowserAccess) +{ + HACCOUNT Finder; + + if (GetAccountBrowserAccess) + { +//1. wait to get write access +#ifdef DEBUG_SYNCHRO + DebugLog(SynchroFile,"WaitForAllAccounts:AccountBrowserSO-write wait\n"); +#endif + SWMRGWaitToWrite(Plugin->AccountBrowserSO,INFINITE); +#ifdef DEBUG_SYNCHRO + DebugLog(SynchroFile,"WaitForAllAccounts:AccountBrowserSO-write enter\n"); +#endif + } + for (Finder=Plugin->FirstAccount;Finder!=NULL;Finder=Finder->Next) + { +//2. wait for signal that account is not in use +#ifdef DEBUG_SYNCHRO + DebugLog(SynchroFile,"WaitForAllAccounts:waiting for UsingThreadEV %x (account %x)\n",Finder->UsingThreads,Finder); +#endif + WaitForSingleObject(Finder->UsingThreads->Event,INFINITE); + SetEvent(Finder->UsingThreads->Event); +#ifdef DEBUG_SYNCHRO + DebugLog(SynchroFile,"WaitForAllAccounts:UsingThreadEV signaled\n"); +#endif + } + if (GetAccountBrowserAccess) + { +//leave write access +#ifdef DEBUG_SYNCHRO + DebugLog(SynchroFile,"WaitForAllAccounts:AccountBrowserSO-write done\n"); +#endif + SWMRGDoneWriting(Plugin->AccountBrowserSO); + } + + return 1; +} + +int DeleteAccounts(HYAMNPROTOPLUGIN Plugin) +{ + HACCOUNT Finder; + + //1. wait to get write access + #ifdef DEBUG_SYNCHRO + DebugLog(SynchroFile,"DeleteAccounts:AccountBrowserSO-write wait\n"); + #endif + SWMRGWaitToWrite(Plugin->AccountBrowserSO,INFINITE); + #ifdef DEBUG_SYNCHRO + DebugLog(SynchroFile,"DeleteAccounts:AccountBrowserSO-write enter\n"); + #endif + + WaitForAllAccounts(Plugin,FALSE); + + for (Finder=Plugin->FirstAccount;Finder!=NULL;) + { + HACCOUNT Next = Finder->Next; + DeletePluginAccountSvc((WPARAM)Finder,(LPARAM)0); + Finder = Next; + } + + //leave write access + #ifdef DEBUG_SYNCHRO + DebugLog(SynchroFile,"DeleteAccounts:AccountBrowserSO-write done\n"); + #endif + SWMRGDoneWriting(Plugin->AccountBrowserSO); + + return 1; +} + +void WINAPI GetStatusFcn(HACCOUNT Which,TCHAR *Value) +{ + if (Which==NULL) + return; + +#ifdef DEBUG_SYNCHRO + DebugLog(SynchroFile,"\tGetStatus:AccountStatusCS-cs wait\n"); +#endif + EnterCriticalSection(&AccountStatusCS); +#ifdef DEBUG_SYNCHRO + DebugLog(SynchroFile,"\tGetStatus:AccountStatusCS-cs enter\n"); +#endif + lstrcpy(Value,Which->Status); +#ifdef DEBUG_SYNCHRO + DebugLog(SynchroFile,"\tGetStatus:AccountStatusCS-cs done\n"); +#endif + LeaveCriticalSection(&AccountStatusCS); + return; +} + +void WINAPI SetStatusFcn(HACCOUNT Which,TCHAR *Value) +{ + if (Which==NULL) + return; + +#ifdef DEBUG_SYNCHRO + DebugLog(SynchroFile,"\tSetStatus:AccountStatusCS-cs wait\n"); +#endif + EnterCriticalSection(&AccountStatusCS); +#ifdef DEBUG_SYNCHRO + DebugLog(SynchroFile,"\tSetStatus:AccountStatusCS-cs enter\n"); +#endif + lstrcpy(Which->Status,Value); + WindowList_BroadcastAsync(YAMNVar.MessageWnds,WM_YAMN_CHANGESTATUS,(WPARAM)Which,(LPARAM)0); +#ifdef DEBUG_SYNCHRO + DebugLog(SynchroFile,"\tSetStatus:AccountStatusCS-cs done\n"); +#endif + LeaveCriticalSection(&AccountStatusCS); +} + +/* +#ifdef DEBUG_ACCOUNTS +int GetAccounts() +{ + HACCOUNT Finder; + int cnt=0; + + for (Finder=Account;Finder!=NULL;Finder=Finder->Next) + cnt++; + return cnt; +} + +void WriteAccounts() +{ + HACCOUNT Finder; + + for (Finder=Account;Finder!=NULL;Finder=Finder->Next) + MessageBoxA(NULL,Finder->Name,"Browsing account",MB_OK); +} +#endif +*/ diff --git a/protocols/YAMN/browser/badconnect.cpp b/protocols/YAMN/browser/badconnect.cpp new file mode 100644 index 0000000000..cb3de50c5d --- /dev/null +++ b/protocols/YAMN/browser/badconnect.cpp @@ -0,0 +1,345 @@ +/* + * This code implements window handling (connection error) + * + * (c) majvan 2002,2004 + */ + +#include "../yamn.h" +#include "../main.h" + +#define BADCONNECTTITLE "%s - connection error" +#define BADCONNECTMSG "An error occured. Error code: %d" + +//-------------------------------------------------------------------------------------------------- + +LRESULT CALLBACK BadConnectPopUpProc(HWND hWnd,UINT msg,WPARAM wParam,LPARAM lParam) +{ + DWORD PluginParam; + switch(msg) + { + case WM_COMMAND: + if ((HIWORD(wParam)==STN_CLICKED) && (CallService(MS_POPUP_GETPLUGINDATA,(WPARAM)hWnd,(LPARAM)&PluginParam))) //if clicked and it's new mail popup window + { + PROCESS_INFORMATION pi; + STARTUPINFOW si; + HACCOUNT ActualAccount; + + ZeroMemory(&si,sizeof(si)); + si.cb=sizeof(si); + ActualAccount=(HACCOUNT)CallService(MS_POPUP_GETCONTACT,(WPARAM)hWnd,(LPARAM)0); +#ifdef DEBUG_SYNCHRO + DebugLog(SynchroFile,"PopUpProc:LEFTCLICK:ActualAccountSO-read wait\n"); +#endif + if (WAIT_OBJECT_0==WaitToReadFcn(ActualAccount->AccountAccessSO)) + { +#ifdef DEBUG_SYNCHRO + DebugLog(SynchroFile,"PopUpProc:LEFTCLICK:ActualAccountSO-read enter\n"); +#endif + if (ActualAccount->BadConnectN.App!=NULL) + { + WCHAR *Command; + if (ActualAccount->BadConnectN.AppParam!=NULL) + Command=new WCHAR[wcslen(ActualAccount->BadConnectN.App)+wcslen(ActualAccount->BadConnectN.AppParam)+6]; + else + Command=new WCHAR[wcslen(ActualAccount->BadConnectN.App)+6]; + + if (Command!=NULL) + { + lstrcpyW(Command,L"\""); + lstrcatW(Command,ActualAccount->BadConnectN.App); + lstrcatW(Command,L"\" "); + if (ActualAccount->BadConnectN.AppParam!=NULL) + lstrcatW(Command,ActualAccount->BadConnectN.AppParam); + CreateProcessW(NULL,Command,NULL,NULL,FALSE,NORMAL_PRIORITY_CLASS,NULL,NULL,&si,&pi); + delete[] Command; + } + } +#ifdef DEBUG_SYNCHRO + DebugLog(SynchroFile,"PopUpProc:LEFTCLICK:ActualAccountSO-read done\n"); +#endif + ReadDoneFcn(ActualAccount->AccountAccessSO); + } +#ifdef DEBUG_SYNCHRO + else + DebugLog(SynchroFile,"PopUpProc:LEFTCLICK:ActualAccountSO-read enter failed\n"); +#endif + SendMessage(hWnd,UM_DESTROYPOPUP,0,0); + } + break; + case UM_FREEPLUGINDATA: + //Here we'd free our own data, if we had it. + return FALSE; + case UM_INITPOPUP: + //This is the equivalent to WM_INITDIALOG you'd get if you were the maker of dialog popups. + break; + case WM_CONTEXTMENU: + SendMessage(hWnd,UM_DESTROYPOPUP,0,0); + break; + case WM_NOTIFY: +/* switch(((LPNMHDR)lParam)->code) + { + case NM_CLICK: + { + } + } + break; +*/ default: + break; + } + return DefWindowProc(hWnd,msg,wParam,lParam); +} + +LRESULT CALLBACK DlgProcYAMNBadConnection(HWND hDlg,UINT msg,WPARAM wParam,LPARAM lParam) +{ + switch(msg) + { + case WM_INITDIALOG: + { + BOOL ShowPopUp,ShowMsg,ShowIco; + HACCOUNT ActualAccount; + DWORD ErrorCode; + char* TitleStrA; + char *Message1A=NULL; + TCHAR *Message1W=NULL; + POPUPDATAT BadConnectPopUp; + + ActualAccount=((struct BadConnectionParam *)lParam)->account; + ErrorCode=((struct BadConnectionParam *)lParam)->errcode; +#ifdef DEBUG_SYNCHRO + DebugLog(SynchroFile,"BadConnect:ActualAccountSO-read wait\n"); +#endif + if (WAIT_OBJECT_0!=WaitToReadFcn(ActualAccount->AccountAccessSO)) + { +#ifdef DEBUG_SYNCHRO + DebugLog(SynchroFile,"BadConnect:ActualAccountSO-read wait failed\n"); +#endif + return FALSE; + } +#ifdef DEBUG_SYNCHRO + DebugLog(SynchroFile,"BadConnect:ActualAccountSO-read enter\n"); +#endif + TitleStrA = new char[strlen(ActualAccount->Name)+strlen(Translate(BADCONNECTTITLE))]; + wsprintfA(TitleStrA,Translate(BADCONNECTTITLE),ActualAccount->Name); + + ShowPopUp=ActualAccount->BadConnectN.Flags & YAMN_ACC_POP; + ShowMsg=ActualAccount->BadConnectN.Flags & YAMN_ACC_MSG; + ShowIco=ActualAccount->BadConnectN.Flags & YAMN_ACC_ICO; + + if (ShowPopUp) + { + BadConnectPopUp.lchContact=ActualAccount; + BadConnectPopUp.lchIcon=g_LoadIconEx(3); + BadConnectPopUp.colorBack=ActualAccount->BadConnectN.Flags & YAMN_ACC_POPC ? ActualAccount->BadConnectN.PopUpB : GetSysColor(COLOR_BTNFACE); + BadConnectPopUp.colorText=ActualAccount->BadConnectN.Flags & YAMN_ACC_POPC ? ActualAccount->BadConnectN.PopUpT : GetSysColor(COLOR_WINDOWTEXT); + BadConnectPopUp.iSeconds=ActualAccount->BadConnectN.PopUpTime; + + BadConnectPopUp.PluginWindowProc=(WNDPROC)BadConnectPopUpProc; + BadConnectPopUp.PluginData=0; //it's bad connect popup + lstrcpyn(BadConnectPopUp.lptzContactName,_A2T(ActualAccount->Name),SIZEOF(BadConnectPopUp.lptzContactName)); + } + + if (ActualAccount->Plugin->Fcn!=NULL && ActualAccount->Plugin->Fcn->GetErrorStringWFcnPtr!=NULL) + { + Message1W=ActualAccount->Plugin->Fcn->GetErrorStringWFcnPtr(ErrorCode); + SetDlgItemText(hDlg,IDC_STATICMSG,Message1W); + lstrcpyn(BadConnectPopUp.lptzText,Message1W,sizeof(BadConnectPopUp.lptzText)); + if (ShowPopUp) + PUAddPopUpT(&BadConnectPopUp); + } + else if (ActualAccount->Plugin->Fcn!=NULL && ActualAccount->Plugin->Fcn->GetErrorStringAFcnPtr!=NULL) + { + Message1W=ActualAccount->Plugin->Fcn->GetErrorStringWFcnPtr(ErrorCode); + SetDlgItemText(hDlg,IDC_STATICMSG,Message1W); + lstrcpyn(BadConnectPopUp.lptzText,Message1W,sizeof(BadConnectPopUp.lptzText)); + if (ShowPopUp) + PUAddPopUpT(&BadConnectPopUp); + } + else + { + Message1W=TranslateT("Unknown error"); + SetDlgItemText(hDlg,IDC_STATICMSG,Message1W); + lstrcpyn(BadConnectPopUp.lptzText,Message1W,sizeof(BadConnectPopUp.lptzText)); + if (ShowPopUp) + PUAddPopUpT(&BadConnectPopUp); + } + + if (!ShowMsg && !ShowIco) + DestroyWindow(hDlg); +#ifdef DEBUG_SYNCHRO + DebugLog(SynchroFile,"BadConnect:ActualAccountSO-read done\n"); +#endif + ReadDoneFcn(ActualAccount->AccountAccessSO); + + SetWindowTextA(hDlg, TitleStrA); + delete[] TitleStrA; + if (Message1A!=NULL) + delete[] Message1A; + if (ActualAccount->Plugin->Fcn!=NULL && ActualAccount->Plugin->Fcn->DeleteErrorStringFcnPtr!=NULL && Message1A!=NULL) + ActualAccount->Plugin->Fcn->DeleteErrorStringFcnPtr(Message1A); + if (ActualAccount->Plugin->Fcn!=NULL && ActualAccount->Plugin->Fcn->DeleteErrorStringFcnPtr!=NULL && Message1W!=NULL) + ActualAccount->Plugin->Fcn->DeleteErrorStringFcnPtr(Message1W); + return 0; + } + case WM_DESTROY: + { + NOTIFYICONDATA nid; + + ZeroMemory(&nid,sizeof(NOTIFYICONDATA)); + nid.cbSize=sizeof(NOTIFYICONDATA); + nid.hWnd=hDlg; + nid.uID=0; + Shell_NotifyIcon(NIM_DELETE,&nid); + PostQuitMessage(0); + break; + } + case WM_YAMN_NOTIFYICON: + switch (lParam) + { + case WM_LBUTTONDBLCLK: + ShowWindow(hDlg,SW_SHOWNORMAL); + SetForegroundWindow(hDlg); + break; + } + return 0; + case WM_CHAR: + switch((TCHAR)wParam) + { + case 27: + case 13: + DestroyWindow(hDlg); + break; + } + break; + case WM_SYSCOMMAND: + switch(wParam) + { + case SC_CLOSE: + DestroyWindow(hDlg); + break; + } + case WM_COMMAND: + { + WORD wNotifyCode = HIWORD(wParam); + switch(LOWORD(wParam)) + { + case IDC_BTNOK: + DestroyWindow(hDlg); + break; + } + break; + } + } + return 0; +} + +DWORD WINAPI BadConnection(LPVOID Param) +{ + MSG msg; + HWND hBadConnect; + HACCOUNT ActualAccount; + struct BadConnectionParam MyParam; + NOTIFYICONDATA nid; + char *NotIconText = Translate(" - connection error"), *src; + TCHAR *dest; + int i; + + MyParam=*(struct BadConnectionParam *)Param; + ActualAccount=MyParam.account; +#ifdef DEBUG_SYNCHRO + DebugLog(SynchroFile,"BadConnect:Incrementing \"using threads\" %x (account %x)\n",ActualAccount->UsingThreads,ActualAccount); +#endif + SCIncFcn(ActualAccount->UsingThreads); + +// we will not use params in stack anymore + SetEvent(MyParam.ThreadRunningEV); + + __try + { + hBadConnect=CreateDialogParam(YAMNVar.hInst,MAKEINTRESOURCE(IDD_DLGBADCONNECT),NULL,(DLGPROC)DlgProcYAMNBadConnection,(LPARAM)&MyParam); + SendMessage(hBadConnect,WM_SETICON,ICON_BIG,(LPARAM)g_LoadIconEx(3)); + SendMessage(hBadConnect,WM_SETICON,ICON_SMALL,(LPARAM)g_LoadIconEx(3)); + + ZeroMemory(&nid,sizeof(nid)); + nid.cbSize=sizeof(NOTIFYICONDATA); + nid.hWnd=hBadConnect; + nid.hIcon=g_LoadIconEx(3); + nid.uID=0; + nid.uFlags=NIF_ICON | NIF_MESSAGE | NIF_TIP; + nid.uCallbackMessage=WM_YAMN_NOTIFYICON; + +#ifdef DEBUG_SYNCHRO + DebugLog(SynchroFile,"BadConnect:ActualAccountSO-read wait\n"); +#endif + if (WAIT_OBJECT_0!=WaitToReadFcn(ActualAccount->AccountAccessSO)) + { +#ifdef DEBUG_SYNCHRO + DebugLog(SynchroFile,"BadConnect:ActualAccountSO-read wait failed\n"); +#endif + return 0; + } +#ifdef DEBUG_SYNCHRO + DebugLog(SynchroFile,"BadConnect:ActualAccountSO-read enter\n"); +#endif + for (src=ActualAccount->Name,dest=nid.szTip,i=0;(*src!=(TCHAR)0) && (i+1<sizeof(nid.szTip));*dest++=*src++); + for (src=NotIconText;(*src!=(TCHAR)0) && (i+1<sizeof(nid.szTip));*dest++=*src++); + *dest=(TCHAR)0; + + if (ActualAccount->BadConnectN.Flags & YAMN_ACC_SND) + CallService(MS_SKIN_PLAYSOUND,0,(LPARAM)YAMN_CONNECTFAILSOUND); + if (ActualAccount->BadConnectN.Flags & YAMN_ACC_MSG) + ShowWindow(hBadConnect,SW_SHOWNORMAL); + if (ActualAccount->BadConnectN.Flags & YAMN_ACC_ICO) + Shell_NotifyIcon(NIM_ADD,&nid); +#ifdef DEBUG_SYNCHRO + DebugLog(SynchroFile,"BadConnect:ActualAccountSO-read done\n"); +#endif + ReadDoneFcn(ActualAccount->AccountAccessSO); + + UpdateWindow(hBadConnect); + while(GetMessage(&msg,NULL,0,0)) + { + TranslateMessage(&msg); + DispatchMessage(&msg); + } + +// now, write to file. Why? Because we want to write when was new mail last checked + if ((ActualAccount->Plugin->Fcn!=NULL) && (ActualAccount->Plugin->Fcn->WriteAccountsFcnPtr!=NULL) && ActualAccount->AbleToWork) + ActualAccount->Plugin->Fcn->WriteAccountsFcnPtr(); + } + __finally + { +#ifdef DEBUG_SYNCHRO + DebugLog(SynchroFile,"BadConnect:Decrementing \"using threads\" %x (account %x)\n",ActualAccount->UsingThreads,ActualAccount); +#endif + SCDecFcn(ActualAccount->UsingThreads); + } + return 0; +} + + +INT_PTR RunBadConnectionSvc(WPARAM wParam,LPARAM lParam) +{ + DWORD tid; +//an event for successfull copy parameters to which point a pointer in stack for new thread + HANDLE ThreadRunningEV; + PYAMN_BADCONNECTIONPARAM Param=(PYAMN_BADCONNECTIONPARAM)wParam; + + if ((DWORD)lParam!=YAMN_BADCONNECTIONVERSION) + return 0; + + if (NULL!=(ThreadRunningEV=CreateEvent(NULL,FALSE,FALSE,NULL))) + { + HANDLE NewThread; + + Param->ThreadRunningEV=ThreadRunningEV; + if (NULL!=(NewThread=CreateThread(NULL,0,BadConnection,Param,0,&tid))) + { + WaitForSingleObject(ThreadRunningEV,INFINITE); + CloseHandle(NewThread); + } + CloseHandle(ThreadRunningEV); + + return 1; + } + return 0; +} diff --git a/protocols/YAMN/browser/m_browser.h b/protocols/YAMN/browser/m_browser.h new file mode 100644 index 0000000000..8b05e3d84a --- /dev/null +++ b/protocols/YAMN/browser/m_browser.h @@ -0,0 +1,42 @@ +#ifndef __MAILBROWSER_H +#define __MAILBROWSER_H + +#include "m_account.h" +#include "../debug.h" + +typedef struct MailBrowserWinParam +{ +#define YAMN_MAILBROWSERVERSION 1 + HANDLE ThreadRunningEV; + HACCOUNT account; + DWORD nflags; //flags YAMN_ACC_??? when new mails + DWORD nnflags; //flags YAMN_ACC_??? when no new mails + void *Param; +} YAMN_MAILBROWSERPARAM,*PYAMN_MAILBROWSERPARAM; + +typedef struct MailShowMsgWinParam +{ + HANDLE ThreadRunningEV; + HACCOUNT account; + HYAMNMAIL mail; +} YAMN_MAILSHOWPARAM, *PYAMN_MAILSHOWPARAM; + +typedef struct NoNewMailParam +{ +#define YAMN_NONEWMAILVERSION 1 + HANDLE ThreadRunningEV; + HACCOUNT account; + DWORD flags; + void *Param; +} YAMN_NONEWMAILPARAM,*PYAMN_NONEWMAILPARAM; + +typedef struct BadConnectionParam +{ +#define YAMN_BADCONNECTIONVERSION 1 + HANDLE ThreadRunningEV; + HACCOUNT account; + UINT_PTR errcode; + void *Param; +} YAMN_BADCONNECTIONPARAM,*PYAMN_BADCONNECTIONPARAM; + +#endif diff --git a/protocols/YAMN/browser/mailbrowser.cpp b/protocols/YAMN/browser/mailbrowser.cpp new file mode 100644 index 0000000000..82f4d7eac0 --- /dev/null +++ b/protocols/YAMN/browser/mailbrowser.cpp @@ -0,0 +1,2605 @@ +/* + * This code implements window handling (new mail) + * + * (c) majvan 2002-2004 + */ +/* There can be problems when compiling this file, because in this file + * we are using both unicode and no-unicode functions and compiler does not + * like it in one file + * When you got errors, try to comment the #define <stdio.h> and compile, then + * put it back to uncommented and compile again :) + */ +#ifndef _WIN32_IE + #define _WIN32_IE 0x0400 +#endif +#ifndef _WIN32_WINNT + #define _WIN32_WINNT 0x0501 +#endif + +#include "../yamn.h" +#include "../main.h" + +#define TIMER_FLASHING 0x09061979 +#define MAILBROWSER_MINXSIZE 200 //min size of mail browser window +#define MAILBROWSER_MINYSIZE 130 + +//-------------------------------------------------------------------------------------------------- +//-------------------------------------------------------------------------------------------------- +char* s_MonthNames[] = { "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" }; +bool bDate = false,bSub=false,bSize=false,bFrom=false; +int PosX=0,PosY=0,SizeX=460,SizeY=100; +int HeadSizeX = 0x2b2, HeadSizeY = 0x0b5, HeadPosX = 100, HeadPosY = 100; +int HeadSplitPos=250; // per-mils of the size +static int FromWidth=250,SubjectWidth=280,SizeWidth=50,SizeDate=205; +unsigned char optDateTime = (SHOWDATELONG | SHOWDATENOTODAY); + +static WNDPROC OldListViewSubclassProc; + +struct CMailNumbersSub +{ + int Total; //any mail + int New; //uses YAMN_MSG_NEW flag + int UnSeen; //uses YAMN_MSG_UNSEEN flag +// int Browser; //uses YAMN_MSG_BROWSER flag + int BrowserUC; //uses YAMN_MSG_BROWSER flag and YAMN_MSG_UNSEEN flag + int Display; //uses YAMN_MSG_DISPLAY flag + int DisplayTC; //uses YAMN_MSG_DISPLAY flag and YAMN_MSG_DISPLAYC flag + int DisplayUC; //uses YAMN_MSG_DISPLAY flag and YAMN_MSG_DISPLAYC flag and YAMN_MSG_UNSEEN flag + int PopUp; //uses YAMN_MSG_POPUP flag + int PopUpTC; //uses YAMN_MSG_POPUPC flag + int PopUpNC; //uses YAMN_MSG_POPUPC flag and YAMN_MSG_NEW flag + int PopUpRun; //uses YAMN_MSG_POPUP flag and YAMN_MSG_NEW flag + int PopUpSL2NC; //uses YAMN_MSG_SPAML2 flag and YAMN_MSG_NEW flag + int PopUpSL3NC; //uses YAMN_MSG_SPAML3 flag and YAMN_MSG_NEW flag +// int SysTray; //uses YAMN_MSG_SYSTRAY flag + int SysTrayUC; //uses YAMN_MSG_SYSTRAY flag and YAMN_MSG_UNSEEN flag +// int Sound; //uses YAMN_MSG_SOUND flag + int SoundNC; //uses YAMN_MSG_SOUND flag and YAMN_MSG_NEW flag +// int App; //uses YAMN_MSG_APP flag + int AppNC; //uses YAMN_MSG_APP flag and YAMN_MSG_NEW flag + int EventNC; //uses YAMN_MSG_NEVENT flag and YAMN_MSG_NEW flag +}; + +struct CMailNumbers +{ + struct CMailNumbersSub Real; + struct CMailNumbersSub Virtual; +}; + +struct CMailWinUserInfo +{ + HACCOUNT Account; + int TrayIconState; + BOOL UpdateMailsMessagesAccess; + BOOL Seen; + BOOL RunFirstTime; +}; + +struct CChangeContent +{ + DWORD nflags; + DWORD nnflags; +}; + +struct CUpdateMails +{ + struct CChangeContent *Flags; + BOOL Waiting; + HANDLE Copied; +}; +struct CSortList +{ + HWND hDlg; + int iSubItem; +}; + +//Retrieves HACCOUNT, whose mails are displayed in ListMails +// hLM- handle of dialog window +// returns handle of account +inline HACCOUNT GetWindowAccount(HWND hDialog); + +//Looks to mail flags and increment mail counter (e.g. if mail is new, increments the new mail counter +// msgq- mail, which increments the counters +// MN- counnters structure +void IncrementMailCounters(HYAMNMAIL msgq,struct CMailNumbers *MN); + +enum +{ + UPDATE_FAIL=0, //function failed + UPDATE_NONE, //none update has been performed + UPDATE_OK, //some changes occured, update performed +}; +//Just looks for mail changes in account and update the mail browser window +// hDlg- dialog handle +// ActualAccount- account handle +// nflags- flags what to do when new mail arrives +// nnflags- flags what to do when no new mail arrives +// returns one of UPDATE_XXX value(not implemented yet) +int UpdateMails(HWND hDlg,HACCOUNT ActualAccount,DWORD nflags,DWORD nnflags); + +//When new mail occurs, shows window, plays sound, runs application... +// hDlg- dialog handle. Dialog of mailbrowser is already created and actions are performed over this window +// ActualAccount- handle of account, whose mails are to be notified +// MN- statistics of mails in account +// nflags- what to do or not to do (e.g. to show mailbrowser window or prohibit to show) +// nflags- flags what to do when new mail arrives +// nnflags- flags what to do when no new mail arrives +void DoMailActions(HWND hDlg,HACCOUNT ActualAccount,struct CMailNumbers *MN,DWORD nflags,DWORD nnflags); + +//Looks for items in mailbrowser and if they were deleted, delete them from browser window +// hListView- handle of listview window +// ActualAccount- handle of account, whose mails are show +// MailNumbers- pointer to structure, in which function stores numbers of mails with some property +// returns one of UPDATE_XXX value (not implemented yet) +int ChangeExistingMailStatus(HWND hListView,HACCOUNT ActualAccount,struct CMailNumbers *MN); + +//Adds new mails to ListView and if any new, shows multi popup (every new message is new popup window created by popup plugin) +// hListView- handle of listview window +// ActualAccount- handle of account, whose mails are show +// NewMailPopUp- pointer to prepared structure for popup plugin, can be NULL if no popup show +// MailNumbers- pointer to structure, in which function stores numbers of mails with some property +// nflags- flags what to do when new mail arrives +// returns one of UPDATE_XXX value (not implemented yet) +int AddNewMailsToListView(HWND hListView,HACCOUNT ActualAccount,struct CMailNumbers *MailNumbers,DWORD nflags); + +//Window callback procedure for popup window (created by popup plugin) +LRESULT CALLBACK NewMailPopUpProc(HWND hWnd,UINT msg,WPARAM wParam,LPARAM lParam); + +//Window callback procedure for popup window (created by popup plugin) +LRESULT CALLBACK NoNewMailPopUpProc(HWND hWnd,UINT msg,WPARAM wParam,LPARAM lParam); + +//Dialog callback procedure for mail browser +BOOL CALLBACK DlgProcYAMNMailBrowser(HWND hDlg,UINT msg,WPARAM wParam,LPARAM lParam); + +//MailBrowser thread function creates window if needed, tray icon and plays sound +DWORD WINAPI MailBrowser(LPVOID Param); + +LRESULT CALLBACK ListViewSubclassProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam); + +//Runs mail browser in new thread +INT_PTR RunMailBrowserSvc(WPARAM,LPARAM); + +#define YAMN_BROWSER_SHOWPOPUP 0x01 + + // list view items' order criteria + #define LVORDER_NOORDER -1 + #define LVORDER_STRING 0 + #define LVORDER_NUMERIC 1 + #define LVORDER_DATETIME 2 + + // list view order direction + #define LVORDER_ASCENDING 1 + #define LVORDER_NONE 0 + #define LVORDER_DESCENDING -1 + + // list view sort type + #define LVSORTPRIORITY_NONE -1 + + // List view column info. + typedef struct _SAMPLELISTVIEWCOLUMN + { + UINT uCXCol; // index + int nSortType; // sorting type (STRING = 0, NUMERIC, DATE, DATETIME) + int nSortOrder; // sorting order (ASCENDING = -1, NONE, DESCENDING) + int nPriority; // sort priority (-1 for none, 0, 1, ..., nColumns - 1 maximum) + TCHAR lpszName[128]; // column name + } SAMPLELISTVIEWCOLUMN; + + // Compare priority + typedef struct _LVCOMPAREINFO + { + int iIdx; // Index + int iPriority; // Priority + } LVCOMPAREINFO, *LPLVCOMPAREINFO; + +//-------------------------------------------------------------------------------------------------- +//-------------------------------------------------------------------------------------------------- + +LPARAM readItemLParam(HWND hwnd,DWORD iItem) +{ + LVITEM item; + + item.mask = LVIF_PARAM; + item.iItem = iItem; + item.iSubItem = 0; + SendMessage(hwnd,LVM_GETITEM,0,(LPARAM)&item); + return item.lParam; +} + +inline HACCOUNT GetWindowAccount(HWND hDlg) +{ + struct CMailWinUserInfo *mwui; + + if (NULL==(mwui=(struct CMailWinUserInfo *)GetWindowLongPtr(hDlg,DWLP_USER))) + return NULL; + return mwui->Account; +} + +void IncrementMailCounters(HYAMNMAIL msgq,struct CMailNumbers *MN) +{ + if (msgq->Flags & YAMN_MSG_VIRTUAL) + MN->Virtual.Total++; + else + MN->Real.Total++; + + if (msgq->Flags & YAMN_MSG_NEW) + if (msgq->Flags & YAMN_MSG_VIRTUAL) + MN->Virtual.New++; + else + MN->Real.New++; + if (msgq->Flags & YAMN_MSG_UNSEEN) + if (msgq->Flags & YAMN_MSG_VIRTUAL) + MN->Virtual.UnSeen++; + else + MN->Real.UnSeen++; + if ((msgq->Flags & (YAMN_MSG_UNSEEN | YAMN_MSG_BROWSER)) == (YAMN_MSG_UNSEEN | YAMN_MSG_BROWSER)) + if (msgq->Flags & YAMN_MSG_VIRTUAL) + MN->Virtual.BrowserUC++; + else + MN->Real.BrowserUC++; + if (msgq->Flags & YAMN_MSG_DISPLAY) + if (msgq->Flags & YAMN_MSG_VIRTUAL) + MN->Virtual.Display++; + else + MN->Real.Display++; + if ((msgq->Flags & (YAMN_MSG_DISPLAYC | YAMN_MSG_DISPLAY)) == (YAMN_MSG_DISPLAYC | YAMN_MSG_DISPLAY)) + if (msgq->Flags & YAMN_MSG_VIRTUAL) + MN->Virtual.DisplayTC++; + else + MN->Real.DisplayTC++; + if ((msgq->Flags & (YAMN_MSG_UNSEEN | YAMN_MSG_DISPLAYC | YAMN_MSG_DISPLAY)) == (YAMN_MSG_UNSEEN | YAMN_MSG_DISPLAYC | YAMN_MSG_DISPLAY)) + if (msgq->Flags & YAMN_MSG_VIRTUAL) + MN->Virtual.DisplayUC++; + else + MN->Real.DisplayUC++; + if (msgq->Flags & YAMN_MSG_POPUP) + if (msgq->Flags & YAMN_MSG_VIRTUAL) + MN->Virtual.PopUp++; + else + MN->Real.PopUp++; + if ((msgq->Flags & YAMN_MSG_POPUPC) == YAMN_MSG_POPUPC) + if (msgq->Flags & YAMN_MSG_VIRTUAL) + MN->Virtual.PopUpTC++; + else + MN->Real.PopUpTC++; + if ((msgq->Flags & (YAMN_MSG_NEW | YAMN_MSG_POPUPC)) == (YAMN_MSG_NEW | YAMN_MSG_POPUPC)) + if (msgq->Flags & YAMN_MSG_VIRTUAL) + MN->Virtual.PopUpNC++; + else + MN->Real.PopUpNC++; + if ((msgq->Flags & (YAMN_MSG_NEW | YAMN_MSG_POPUP)) == (YAMN_MSG_NEW | YAMN_MSG_POPUP)) + if (msgq->Flags & YAMN_MSG_VIRTUAL) + MN->Virtual.PopUpRun++; + else + MN->Real.PopUpRun++; + if ((msgq->Flags & YAMN_MSG_NEW) && YAMN_MSG_SPAML(msgq->Flags,YAMN_MSG_SPAML2)) + if (msgq->Flags & YAMN_MSG_VIRTUAL) + MN->Virtual.PopUpSL2NC++; + else + MN->Real.PopUpSL2NC++; + if ((msgq->Flags & YAMN_MSG_NEW) && YAMN_MSG_SPAML(msgq->Flags,YAMN_MSG_SPAML3)) + if (msgq->Flags & YAMN_MSG_VIRTUAL) + MN->Virtual.PopUpSL3NC++; + else + MN->Real.PopUpSL3NC++; +/* if (msgq->MailData->Flags & YAMN_MSG_SYSTRAY) + if (msgq->Flags & YAMN_MSG_VIRTUAL) + MN->Virtual.SysTray++; + else + MN->Real.SysTray++; +*/ if ((msgq->Flags & (YAMN_MSG_UNSEEN | YAMN_MSG_SYSTRAY)) == (YAMN_MSG_UNSEEN|YAMN_MSG_SYSTRAY)) + if (msgq->Flags & YAMN_MSG_VIRTUAL) + MN->Virtual.SysTrayUC++; + else + MN->Real.SysTrayUC++; +/* if (msgq->MailData->Flags & YAMN_MSG_SOUND) + if (msgq->Flags & YAMN_MSG_VIRTUAL) + MN->Virtual.Sound++; + else + MN->Real.Sound++; +*/ if ((msgq->Flags & (YAMN_MSG_NEW|YAMN_MSG_SOUND)) == (YAMN_MSG_NEW|YAMN_MSG_SOUND)) + if (msgq->Flags & YAMN_MSG_VIRTUAL) + MN->Virtual.SoundNC++; + else + MN->Real.SoundNC++; +/* if (msgq->MailData->Flags & YAMN_MSG_APP) + if (msgq->Flags & YAMN_MSG_VIRTUAL) + MN->Virtual.App++; + else + MN->Real.App++; +*/ if ((msgq->Flags & (YAMN_MSG_NEW|YAMN_MSG_APP)) == (YAMN_MSG_NEW|YAMN_MSG_APP)) + if (msgq->Flags & YAMN_MSG_VIRTUAL) + MN->Virtual.AppNC++; + else + MN->Real.AppNC++; + if ((msgq->Flags & (YAMN_MSG_NEW|YAMN_MSG_NEVENT)) == (YAMN_MSG_NEW|YAMN_MSG_NEVENT)) + if (msgq->Flags & YAMN_MSG_VIRTUAL) + MN->Virtual.EventNC++; + else + MN->Real.EventNC++; +} + +int UpdateMails(HWND hDlg,HACCOUNT ActualAccount,DWORD nflags,DWORD nnflags) +{ +#define MAILBROWSERTITLE "%s - %d new mail messages, %d total" + + struct CMailWinUserInfo *mwui; + struct CMailNumbers MN; + + HYAMNMAIL msgq; + BOOL Loaded; + BOOL RunMailBrowser,RunPopUps; + + mwui=(struct CMailWinUserInfo *)GetWindowLongPtr(hDlg,DWLP_USER); + //now we ensure read access for account and write access for its mails + #ifdef DEBUG_SYNCHRO + DebugLog(SynchroFile,"UpdateMails:ActualAccountSO-read wait\n"); + #endif + if (WAIT_OBJECT_0!=WaitToReadFcn(ActualAccount->AccountAccessSO)) + { + #ifdef DEBUG_SYNCHRO + DebugLog(SynchroFile,"UpdateMails:ActualAccountSO-read wait failed\n"); + #endif + PostMessage(hDlg,WM_DESTROY,(WPARAM)0,(LPARAM)0); + + return UPDATE_FAIL; + } + #ifdef DEBUG_SYNCHRO + DebugLog(SynchroFile,"UpdateMails:ActualAccountSO-read enter\n"); + #endif + + #ifdef DEBUG_SYNCHRO + DebugLog(SynchroFile,"UpdateMails:ActualAccountMsgsSO-write wait\n"); + #endif + if (WAIT_OBJECT_0!=WaitToWriteFcn(ActualAccount->MessagesAccessSO)) + { + #ifdef DEBUG_SYNCHRO + DebugLog(SynchroFile,"UpdateMails:ActualAccountMsgsSO-write wait failed\n"); + DebugLog(SynchroFile,"UpdateMails:ActualAccountSO-read done\n"); + #endif + ReadDoneFcn(ActualAccount->AccountAccessSO); + + PostMessage(hDlg,WM_DESTROY,(WPARAM)0,(LPARAM)0); + return UPDATE_FAIL; + } + #ifdef DEBUG_SYNCHRO + DebugLog(SynchroFile,"UpdateMails:ActualAccountMsgsSO-write enter\n"); + #endif + + ZeroMemory(&MN,sizeof(MN)); + + for (msgq=(HYAMNMAIL)ActualAccount->Mails;msgq!=NULL;msgq=msgq->Next) + { + if (!LoadedMailData(msgq)) //check if mail is already in memory + { + Loaded=false; + if (NULL==LoadMailData(msgq)) //if we could not load mail to memory, consider this mail deleted and do not display it + continue; + } + else + Loaded=true; + + IncrementMailCounters(msgq,&MN); + + if (!Loaded) + UnloadMailData(msgq); //do not keep data for mail in memory + } + + if (mwui!=NULL) + mwui->UpdateMailsMessagesAccess=TRUE; + + //Now we are going to check if extracting data from mail headers are needed. + //If popups will be displayed or mailbrowser window + if ((((mwui!=NULL) && !(mwui->RunFirstTime)) && + ( + ((nnflags & YAMN_ACC_MSGP) && !(MN.Real.BrowserUC+MN.Virtual.BrowserUC)) || + ((nflags & YAMN_ACC_MSGP) && (MN.Real.BrowserUC+MN.Virtual.BrowserUC)) + ) + ) || //if mail window was displayed before and flag YAMN_ACC_MSGP is set + ((nnflags & YAMN_ACC_MSG) && !(MN.Real.BrowserUC+MN.Virtual.BrowserUC)) || //if needed to run mailbrowser when no unseen and no unseen mail found + ((nflags & YAMN_ACC_MSG) && (MN.Real.BrowserUC+MN.Virtual.BrowserUC)) || //if unseen mails found, we sure run mailbrowser + ((nflags & YAMN_ACC_ICO) && (MN.Real.SysTrayUC+MN.Virtual.SysTrayUC)) + ) //if needed to run systray + RunMailBrowser=TRUE; + else RunMailBrowser=FALSE; + + if ( (nflags & YAMN_ACC_POP) && + (ActualAccount->Flags & YAMN_ACC_POPN) && + (MN.Real.PopUpNC+MN.Virtual.PopUpNC) ) //if some popups with mails are needed to show + RunPopUps=TRUE; + else RunPopUps=FALSE; + + if (RunMailBrowser) + ChangeExistingMailStatus(GetDlgItem(hDlg,IDC_LISTMAILS),ActualAccount,&MN); + if (RunMailBrowser || RunPopUps) + AddNewMailsToListView(hDlg==NULL ? NULL : GetDlgItem(hDlg,IDC_LISTMAILS),ActualAccount,&MN,nflags); + + if (RunMailBrowser) + { + size_t len = strlen(ActualAccount->Name)+strlen(Translate(MAILBROWSERTITLE))+10; //+10 chars for numbers + char *TitleStrA=new char[len]; + WCHAR *TitleStrW=new WCHAR[len]; + + sprintf(TitleStrA,Translate(MAILBROWSERTITLE),ActualAccount->Name,MN.Real.DisplayUC+MN.Virtual.DisplayUC,MN.Real.Display+MN.Virtual.Display); + MultiByteToWideChar(CP_ACP,MB_USEGLYPHCHARS,TitleStrA,-1,TitleStrW,(int)strlen(TitleStrA)+1); + SendMessageW(hDlg,WM_SETTEXT,(WPARAM)0,(LPARAM)TitleStrW); + delete[] TitleStrA; + delete[] TitleStrW; + } + + #ifdef DEBUG_SYNCHRO + DebugLog(SynchroFile,"UpdateMails:Do mail actions\n"); + #endif + + DoMailActions(hDlg,ActualAccount,&MN,nflags,nnflags); + + #ifdef DEBUG_SYNCHRO + DebugLog(SynchroFile,"UpdateMails:Do mail actions done\n"); + #endif + + SetRemoveFlagsInQueueFcn((HYAMNMAIL)ActualAccount->Mails,YAMN_MSG_NEW,0,YAMN_MSG_NEW,YAMN_FLAG_REMOVE); //rempve the new flag + if (!RunMailBrowser) + SetRemoveFlagsInQueueFcn((HYAMNMAIL)ActualAccount->Mails,YAMN_MSG_UNSEEN,YAMN_MSG_STAYUNSEEN,YAMN_MSG_UNSEEN,YAMN_FLAG_REMOVE); //remove the unseen flag when it was not displayed and it has not "stay unseen" flag set + + if (mwui!=NULL) + { + mwui->UpdateMailsMessagesAccess=FALSE; + mwui->RunFirstTime=FALSE; + } + #ifdef DEBUG_SYNCHRO + DebugLog(SynchroFile,"UpdateMails:ActualAccountMsgsSO-write done\n"); + DebugLog(SynchroFile,"UpdateMails:ActualAccountSO-read done\n"); + #endif + WriteDoneFcn(ActualAccount->MessagesAccessSO); + ReadDoneFcn(ActualAccount->AccountAccessSO); + + if (RunMailBrowser) + UpdateWindow(GetDlgItem(hDlg,IDC_LISTMAILS)); + else if (hDlg!=NULL) + DestroyWindow(hDlg); + + return 1; +} + +int ChangeExistingMailStatus(HWND hListView,HACCOUNT ActualAccount,struct CMailNumbers *MN) +{ + int i,in; + LVITEMW item; + HYAMNMAIL mail,msgq; + + in=ListView_GetItemCount(hListView); + item.mask=LVIF_PARAM; + + for (i=0;i<in;i++) + { + item.iItem=i; + item.iSubItem=0; + if (TRUE==ListView_GetItem(hListView,&item)) + mail=(HYAMNMAIL)item.lParam; + else + continue; + for (msgq=(HYAMNMAIL)ActualAccount->Mails;(msgq!=NULL)&&(msgq!=mail);msgq=msgq->Next); //found the same mail in account queue + if (msgq==NULL) //if mail was not found + if (TRUE==ListView_DeleteItem(hListView,i)) + { + in--;i--; + continue; + } + } + + return TRUE; +} + +void MimeDateToLocalizedDateTime(char *datein, WCHAR *dateout, int lendateout); +int AddNewMailsToListView(HWND hListView,HACCOUNT ActualAccount,struct CMailNumbers *MN,DWORD nflags) +{ + HYAMNMAIL msgq; + POPUPDATAT NewMailPopUp = {0}; + + WCHAR *FromStr; + WCHAR SizeStr[20]; + WCHAR LocalDateStr[128]; + + LVITEMW item; + LVFINDINFO fi; + + int foundi,lfoundi; + struct CHeader UnicodeHeader; + BOOL Loaded,Extracted,FromStrNew=FALSE; + + ZeroMemory(&item,sizeof(item)); + ZeroMemory(&UnicodeHeader,sizeof(UnicodeHeader)); + + if (hListView!=NULL) + { + item.mask=LVIF_TEXT | LVIF_PARAM; + item.iItem=0; + ZeroMemory(&fi,sizeof(fi)); + fi.flags=LVFI_PARAM; //let's go search item by lParam number + lfoundi=0; + } + + NewMailPopUp.lchContact=(ActualAccount->hContact != NULL) ? ActualAccount->hContact : ActualAccount; + NewMailPopUp.lchIcon=g_LoadIconEx(2); + NewMailPopUp.colorBack=nflags & YAMN_ACC_POPC ? ActualAccount->NewMailN.PopUpB : GetSysColor(COLOR_BTNFACE); + NewMailPopUp.colorText=nflags & YAMN_ACC_POPC ? ActualAccount->NewMailN.PopUpT : GetSysColor(COLOR_WINDOWTEXT); + NewMailPopUp.iSeconds=ActualAccount->NewMailN.PopUpTime; + + NewMailPopUp.PluginWindowProc=(WNDPROC)NewMailPopUpProc; + NewMailPopUp.PluginData=(void *)0; //it's new mail popup + + for (msgq=(HYAMNMAIL)ActualAccount->Mails;msgq!=NULL;msgq=msgq->Next,lfoundi++) + { +// now we hide mail pointer to item's lParam member. We can later use it to retrieve mail datas + + Extracted=FALSE;FromStr=NULL;FromStrNew=FALSE; + + if (hListView!=NULL) + { + fi.lParam=(LPARAM)msgq; + if (-1!=(foundi=ListView_FindItem(hListView,-1,&fi))) //if mail is already in window + { + lfoundi=foundi; + continue; //do not insert any item + } + + item.iItem=lfoundi; //insert after last found item + item.lParam=(LPARAM)msgq; + } + + if (!LoadedMailData(msgq)) //check if mail is already in memory + { + Loaded=false; + if (NULL==LoadMailData(msgq)) //if we could not load mail to memory, consider this mail deleted and do not display it + continue; + } + else + Loaded=true; + + if (((hListView!=NULL) && (msgq->Flags & YAMN_MSG_DISPLAY)) || + ((nflags & YAMN_ACC_POP) && (ActualAccount->Flags & YAMN_ACC_POPN) && (msgq->Flags & YAMN_MSG_POPUP) && (msgq->Flags & YAMN_MSG_NEW))) + { + + if (!Extracted) ExtractHeader(msgq->MailData->TranslatedHeader,msgq->MailData->CP,&UnicodeHeader); + Extracted=TRUE; + + if ((UnicodeHeader.From!=NULL) && (UnicodeHeader.FromNick!=NULL)) + { + FromStr=new WCHAR[wcslen(UnicodeHeader.From)+wcslen(UnicodeHeader.FromNick)+4]; + swprintf(FromStr,L"%s <%s>",UnicodeHeader.FromNick,UnicodeHeader.From); + FromStrNew=TRUE; + } + else if (UnicodeHeader.From!=NULL) + FromStr=UnicodeHeader.From; + else if (UnicodeHeader.FromNick!=NULL) + FromStr=UnicodeHeader.FromNick; + else if (UnicodeHeader.ReturnPath!=NULL) + FromStr=UnicodeHeader.ReturnPath; + + if (NULL==FromStr) + { + FromStr=L""; + FromStrNew=FALSE; + } + } + + + if ((hListView!=NULL) && (msgq->Flags & YAMN_MSG_DISPLAY)) + { + item.iSubItem=0; + item.pszText=FromStr; + item.iItem=SendMessageW(hListView,LVM_INSERTITEMW,(WPARAM)0,(LPARAM)&item); + + item.iSubItem=1; + item.pszText=(NULL!=UnicodeHeader.Subject ? UnicodeHeader.Subject : (WCHAR*)L""); + SendMessageW(hListView,LVM_SETITEMTEXTW,(WPARAM)item.iItem,(LPARAM)&item); + + item.iSubItem=2; + swprintf(SizeStr,L"%d kB",msgq->MailData->Size/1024); + item.pszText=SizeStr; + SendMessageW(hListView,LVM_SETITEMTEXTW,(WPARAM)item.iItem,(LPARAM)&item); + + item.iSubItem=3; + item.pszText=L""; + { CMimeItem *heads; + for (heads=msgq->MailData->TranslatedHeader;heads!=NULL;heads=heads->Next) { + if (!_stricmp(heads->name,"Date")) { + MimeDateToLocalizedDateTime(heads->value,LocalDateStr,128); + item.pszText=LocalDateStr; + break; + } } } + SendMessageW(hListView,LVM_SETITEMTEXTW,(WPARAM)item.iItem,(LPARAM)&item); + } + + if ((nflags & YAMN_ACC_POP) && (ActualAccount->Flags & YAMN_ACC_POPN) && (msgq->Flags & YAMN_MSG_POPUP) && (msgq->Flags & YAMN_MSG_NEW)) + { + WideCharToMultiByte(CP_ACP,0,FromStr,-1,(char *)NewMailPopUp.lptzContactName,sizeof(NewMailPopUp.lptzContactName),NULL,NULL); + if (!WideCharToMultiByte(CP_ACP,0,UnicodeHeader.Subject,-1,(char *)NewMailPopUp.lptzText,sizeof(NewMailPopUp.lptzText),NULL,NULL)) + NewMailPopUp.lptzText[0]=0; + PYAMN_MAILSHOWPARAM MailParam = (PYAMN_MAILSHOWPARAM)malloc(sizeof(YAMN_MAILSHOWPARAM)); + if (MailParam) { + MailParam->account = ActualAccount; + MailParam->mail = msgq; + MailParam->ThreadRunningEV = 0; + NewMailPopUp.PluginData=MailParam; + PUAddPopUpT(&NewMailPopUp); + } + } + + if ((msgq->Flags & YAMN_MSG_UNSEEN) && (ActualAccount->NewMailN.Flags & YAMN_ACC_KBN)) + CallService(MS_KBDNOTIFY_EVENTSOPENED,(WPARAM)1,NULL); + + if (FromStrNew) + delete[] FromStr; + + if (Extracted) + { + DeleteHeaderContent(&UnicodeHeader); + ZeroMemory(&UnicodeHeader,sizeof(UnicodeHeader)); + } + + if (!Loaded) + { + SaveMailData(msgq); + UnloadMailData(msgq); //do not keep data for mail in memory + } + } + + return TRUE; +} + +void DoMailActions(HWND hDlg,HACCOUNT ActualAccount,struct CMailNumbers *MN,DWORD nflags,DWORD nnflags) +{ + char *NotIconText = Translate("- new mail message(s)"); + NOTIFYICONDATA nid; + + ZeroMemory(&nid,sizeof(nid)); + + if (MN->Real.EventNC+MN->Virtual.EventNC) + NotifyEventHooks(hNewMailHook,0,0); + + if ((nflags & YAMN_ACC_KBN) && (MN->Real.PopUpRun+MN->Virtual.PopUpRun)) + { + CallService(MS_KBDNOTIFY_STARTBLINK,(WPARAM)MN->Real.PopUpNC+MN->Virtual.PopUpNC,NULL); + } + + if ((nflags & YAMN_ACC_CONT) && (MN->Real.PopUpRun+MN->Virtual.PopUpRun)) + { + char sMsg[250]; + _snprintf(sMsg,249,Translate("%s : %d new mail message(s), %d total"),ActualAccount->Name,MN->Real.PopUpNC+MN->Virtual.PopUpNC,MN->Real.PopUpTC+MN->Virtual.PopUpTC); + if (!(nflags & YAMN_ACC_CONTNOEVENT)) { + CLISTEVENT cEvent; + cEvent.cbSize = sizeof(CLISTEVENT); + cEvent.hContact = ActualAccount->hContact; + cEvent.hIcon = g_LoadIconEx(2); + cEvent.hDbEvent = (HANDLE)ActualAccount->hContact; + cEvent.lParam = (LPARAM) ActualAccount->hContact; + cEvent.pszService = MS_YAMN_CLISTDBLCLICK; + cEvent.pszTooltip = sMsg; + cEvent.flags = 0; + CallServiceSync(MS_CLIST_ADDEVENT, 0,(LPARAM)&cEvent); + } + DBWriteContactSettingString(ActualAccount->hContact, "CList", "StatusMsg", sMsg); + + if (nflags & YAMN_ACC_CONTNICK) + { + DBWriteContactSettingString(ActualAccount->hContact, YAMN_DBMODULE, "Nick",sMsg); + } + } + + if ((nflags & YAMN_ACC_POP) && + !(ActualAccount->Flags & YAMN_ACC_POPN) && + (MN->Real.PopUpRun+MN->Virtual.PopUpRun)) + { + POPUPDATAT NewMailPopUp ={0}; + + NewMailPopUp.lchContact=(ActualAccount->hContact != NULL) ? ActualAccount->hContact : ActualAccount; + NewMailPopUp.lchIcon=g_LoadIconEx(2); + NewMailPopUp.colorBack=nflags & YAMN_ACC_POPC ? ActualAccount->NewMailN.PopUpB : GetSysColor(COLOR_BTNFACE); + NewMailPopUp.colorText=nflags & YAMN_ACC_POPC ? ActualAccount->NewMailN.PopUpT : GetSysColor(COLOR_WINDOWTEXT); + NewMailPopUp.iSeconds=ActualAccount->NewMailN.PopUpTime; + + NewMailPopUp.PluginWindowProc=(WNDPROC)NewMailPopUpProc; + NewMailPopUp.PluginData=(void *)0; //multiple popups + + lstrcpyn(NewMailPopUp.lptzContactName, _A2T(ActualAccount->Name),SIZEOF(NewMailPopUp.lptzContactName)); + wsprintf(NewMailPopUp.lptzText,TranslateT("%d new mail message(s), %d total"),MN->Real.PopUpNC+MN->Virtual.PopUpNC,MN->Real.PopUpTC+MN->Virtual.PopUpTC); + PUAddPopUpT(&NewMailPopUp); + } + + //destroy tray icon if no new mail + if ((MN->Real.SysTrayUC+MN->Virtual.SysTrayUC==0) && (hDlg!=NULL)) + { + nid.hWnd=hDlg; + nid.uID=0; + Shell_NotifyIcon(NIM_DELETE,&nid); + } + + //and remove the event + if ((nflags & YAMN_ACC_CONT) && (!(nflags & YAMN_ACC_CONTNOEVENT)) && (MN->Real.UnSeen + MN->Virtual.UnSeen==0)) { + CallService(MS_CLIST_REMOVEEVENT,(WPARAM)ActualAccount->hContact,(LPARAM)ActualAccount->hContact); + } + + if ((MN->Real.BrowserUC+MN->Virtual.BrowserUC==0) && (hDlg!=NULL)) + { + if (!IsWindowVisible(hDlg) && !(nflags & YAMN_ACC_MSG)) + PostMessage(hDlg,WM_DESTROY,(WPARAM)0,(LPARAM)0); //destroy window if no new mail and window is not visible + if (nnflags & YAMN_ACC_MSG) //if no new mail and msg should be executed + { + SetForegroundWindow(hDlg); + ShowWindow(hDlg,SW_SHOWNORMAL); + } + } + else + if (hDlg!=NULL) //else insert icon and set window if new mails + { + SendMessageW(GetDlgItem(hDlg,IDC_LISTMAILS),LVM_SCROLL,(WPARAM)0,(LPARAM)0x7ffffff); + + if ((nflags & YAMN_ACC_ICO) && (MN->Real.SysTrayUC+MN->Virtual.SysTrayUC)) + { + char* src; + TCHAR *dest; + int i; + + for (src=ActualAccount->Name,dest=nid.szTip,i=0;(*src!=(TCHAR)0) && (i+1<sizeof(nid.szTip));*dest++=*src++); + for (src=NotIconText;(*src!=(TCHAR)0) && (i+1<sizeof(nid.szTip));*dest++=*src++); + *dest=(TCHAR)0; + nid.cbSize=sizeof(NOTIFYICONDATA); + nid.hWnd=hDlg; + nid.hIcon=g_LoadIconEx(2); + nid.uID=0; + nid.uFlags=NIF_ICON | NIF_MESSAGE | NIF_TIP; + nid.uCallbackMessage=WM_YAMN_NOTIFYICON; + Shell_NotifyIcon(NIM_ADD,&nid); + SetTimer(hDlg,TIMER_FLASHING,500,NULL); + } + if (nflags & YAMN_ACC_MSG) //if no new mail and msg should be executed + ShowWindow(hDlg,SW_SHOWNORMAL); + } + + if (MN->Real.AppNC+MN->Virtual.AppNC!=0) + { + if (nflags & YAMN_ACC_APP) + { + PROCESS_INFORMATION pi; + STARTUPINFOW si; + ZeroMemory(&si,sizeof(si)); + si.cb=sizeof(si); + + if (ActualAccount->NewMailN.App!=NULL) + { + WCHAR *Command; + if (ActualAccount->NewMailN.AppParam!=NULL) + Command=new WCHAR[wcslen(ActualAccount->NewMailN.App)+wcslen(ActualAccount->NewMailN.AppParam)+6]; + else + Command=new WCHAR[wcslen(ActualAccount->NewMailN.App)+6]; + + if (Command!=NULL) + { + lstrcpyW(Command,L"\""); + lstrcatW(Command,ActualAccount->NewMailN.App); + lstrcatW(Command,L"\" "); + if (ActualAccount->NewMailN.AppParam!=NULL) + lstrcatW(Command,ActualAccount->NewMailN.AppParam); + CreateProcessW(NULL,Command,NULL,NULL,FALSE,NORMAL_PRIORITY_CLASS,NULL,NULL,&si,&pi); + delete[] Command; + } + } + } + } + + if (MN->Real.SoundNC+MN->Virtual.SoundNC!=0) + if (nflags & YAMN_ACC_SND) + CallService(MS_SKIN_PLAYSOUND,0,(LPARAM)YAMN_NEWMAILSOUND); + + if ((nnflags & YAMN_ACC_POP) && (MN->Real.PopUpRun+MN->Virtual.PopUpRun==0)) + { + POPUPDATAT NoNewMailPopUp; + + NoNewMailPopUp.lchContact=(ActualAccount->hContact != NULL) ? ActualAccount->hContact : ActualAccount; + NoNewMailPopUp.lchIcon=g_LoadIconEx(1); + NoNewMailPopUp.colorBack=ActualAccount->NoNewMailN.Flags & YAMN_ACC_POPC ? ActualAccount->NoNewMailN.PopUpB : GetSysColor(COLOR_BTNFACE); + NoNewMailPopUp.colorText=ActualAccount->NoNewMailN.Flags & YAMN_ACC_POPC ? ActualAccount->NoNewMailN.PopUpT : GetSysColor(COLOR_WINDOWTEXT); + NoNewMailPopUp.iSeconds=ActualAccount->NoNewMailN.PopUpTime; + + NoNewMailPopUp.PluginWindowProc=(WNDPROC)NoNewMailPopUpProc; + NoNewMailPopUp.PluginData=(void *)0; //it's not new mail popup + + lstrcpyn(NoNewMailPopUp.lptzContactName,_A2T(ActualAccount->Name),SIZEOF(NoNewMailPopUp.lptzContactName)); + if (MN->Real.PopUpSL2NC+MN->Virtual.PopUpSL2NC) + wsprintf(NoNewMailPopUp.lptzText,TranslateT("No new mail message, %d spam(s)"),MN->Real.PopUpSL2NC+MN->Virtual.PopUpSL2NC); + else + lstrcpyn(NoNewMailPopUp.lptzText,TranslateT("No new mail message"),SIZEOF(NoNewMailPopUp.lptzText)); + PUAddPopUpT(&NoNewMailPopUp); + } + + if ((nflags & YAMN_ACC_CONT) && (MN->Real.PopUpRun+MN->Virtual.PopUpRun==0)) + { + if (ActualAccount->hContact != NULL) + { + if (MN->Real.PopUpTC+MN->Virtual.PopUpTC) + { + char tmp[255]; + sprintf(tmp,Translate("%d new mail message(s), %d total"),MN->Real.PopUpNC+MN->Virtual.PopUpNC,MN->Real.PopUpTC+MN->Virtual.PopUpTC); + DBWriteContactSettingString(ActualAccount->hContact, "CList", "StatusMsg", tmp); + } + else + DBWriteContactSettingString(ActualAccount->hContact, "CList", "StatusMsg", Translate("No new mail message")); + + if (nflags & YAMN_ACC_CONTNICK) + { + DBWriteContactSettingString(ActualAccount->hContact, YAMN_DBMODULE, "Nick", ActualAccount->Name); + } + } + } + return; +} + +DWORD WINAPI ShowEmailThread(LPVOID Param); +LRESULT CALLBACK NewMailPopUpProc(HWND hWnd,UINT msg,WPARAM wParam,LPARAM lParam) +{ + INT_PTR PluginParam=0; + switch(msg) + { + case WM_COMMAND: + //if clicked and it's new mail popup window + if ((HIWORD(wParam)==STN_CLICKED) && (-1!=(PluginParam=CallService(MS_POPUP_GETPLUGINDATA,(WPARAM)hWnd,(LPARAM)&PluginParam)))) + { + HANDLE hContact = 0; + HACCOUNT Account; + if (PluginParam){ + PYAMN_MAILSHOWPARAM MailParam = new YAMN_MAILSHOWPARAM; + memcpy(MailParam,(PINT_PTR)PluginParam,sizeof(YAMN_MAILSHOWPARAM)); + hContact = MailParam->account->hContact; + Account = MailParam->account; + if (NULL!=(MailParam->ThreadRunningEV=CreateEvent(NULL,FALSE,FALSE,NULL))) { + HANDLE NewThread; + if (NULL!=(NewThread=CreateThread(NULL,0,ShowEmailThread,(LPVOID)MailParam,0,NULL))) + { + CloseHandle(NewThread); + } + CloseHandle(MailParam->ThreadRunningEV); + } + //delete MailParam; + } else { + DBVARIANT dbv; + + hContact=(HANDLE)CallService(MS_POPUP_GETCONTACT,(WPARAM)hWnd,(LPARAM)0); + + if (!DBGetContactSetting((HANDLE) hContact,YAMN_DBMODULE,"Id",&dbv)) + { + Account=(HACCOUNT) CallService(MS_YAMN_FINDACCOUNTBYNAME,(WPARAM)POP3Plugin,(LPARAM)dbv.pszVal); + DBFreeVariant(&dbv); + } + else + Account = (HACCOUNT) hContact; //???? + + + #ifdef DEBUG_SYNCHRO + DebugLog(SynchroFile,"PopUpProc:LEFTCLICK:ActualAccountSO-read wait\n"); + #endif + if (WAIT_OBJECT_0==WaitToReadFcn(Account->AccountAccessSO)) + { + #ifdef DEBUG_SYNCHRO + DebugLog(SynchroFile,"PopUpProc:LEFTCLICK:ActualAccountSO-read enter\n"); + #endif + switch(msg) + { + case WM_COMMAND: + { + YAMN_MAILBROWSERPARAM Param={(HANDLE)0,Account, + (Account->NewMailN.Flags & ~YAMN_ACC_POP) | YAMN_ACC_MSGP | YAMN_ACC_MSG, + (Account->NoNewMailN.Flags & ~YAMN_ACC_POP) | YAMN_ACC_MSGP | YAMN_ACC_MSG}; + + RunMailBrowserSvc((WPARAM)&Param,(LPARAM)YAMN_MAILBROWSERVERSION); + } + break; + } + #ifdef DEBUG_SYNCHRO + DebugLog(SynchroFile,"PopUpProc:LEFTCLICK:ActualAccountSO-read done\n"); + #endif + ReadDoneFcn(Account->AccountAccessSO); + } + #ifdef DEBUG_SYNCHRO + else + DebugLog(SynchroFile,"PopUpProc:LEFTCLICK:ActualAccountSO-read enter failed\n"); + #endif + } + if ((Account->NewMailN.Flags & YAMN_ACC_CONT) && !(Account->NewMailN.Flags & YAMN_ACC_CONTNOEVENT)) { + CallService(MS_CLIST_REMOVEEVENT,(WPARAM)hContact,(LPARAM)hContact); + } + } + // fall through + case WM_CONTEXTMENU: + SendMessageW(hWnd,UM_DESTROYPOPUP,0,0); + break; + case UM_FREEPLUGINDATA:{ + PYAMN_MAILSHOWPARAM mpd = (PYAMN_MAILSHOWPARAM)PUGetPluginData(hWnd); + HANDLE hContact = 0; + if ((mpd) && (INT_PTR)mpd!=-1)free(mpd); + return FALSE; + } + case UM_INITPOPUP: + //This is the equivalent to WM_INITDIALOG you'd get if you were the maker of dialog popups. + WindowList_Add(YAMNVar.MessageWnds,hWnd,NULL); + break; + case UM_DESTROYPOPUP: + WindowList_Remove(YAMNVar.MessageWnds,hWnd); + break; + case WM_YAMN_STOPACCOUNT: + { + HACCOUNT ActualAccount; + HANDLE hContact; + DBVARIANT dbv; + + hContact=(HANDLE)CallService(MS_POPUP_GETCONTACT,(WPARAM)hWnd,(LPARAM)0); + + if (!DBGetContactSetting((HANDLE) hContact,YAMN_DBMODULE,"Id",&dbv)) + { + ActualAccount=(HACCOUNT) CallService(MS_YAMN_FINDACCOUNTBYNAME,(WPARAM)POP3Plugin,(LPARAM)dbv.pszVal); + DBFreeVariant(&dbv); + } + else + ActualAccount = (HACCOUNT) hContact; + + if ((HACCOUNT)wParam!=ActualAccount) + break; + DestroyWindow(hWnd); + return 0; + } + case WM_NOTIFY: + default: + break; + } + return DefWindowProc(hWnd,msg,wParam,lParam); +} + +LRESULT CALLBACK NoNewMailPopUpProc(HWND hWnd,UINT msg,WPARAM wParam,LPARAM lParam) +{ + switch(msg) + { + case WM_COMMAND: + if ((HIWORD(wParam)==STN_CLICKED) && (msg==WM_COMMAND)) + { + HACCOUNT ActualAccount; + HANDLE hContact; + DBVARIANT dbv; + + hContact=(HANDLE)CallService(MS_POPUP_GETCONTACT,(WPARAM)hWnd,(LPARAM)0); + + if (!DBGetContactSetting((HANDLE) hContact,YAMN_DBMODULE,"Id",&dbv)) + { + ActualAccount=(HACCOUNT) CallService(MS_YAMN_FINDACCOUNTBYNAME,(WPARAM)POP3Plugin,(LPARAM)dbv.pszVal); + DBFreeVariant(&dbv); + } + else + ActualAccount = (HACCOUNT) hContact; + + #ifdef DEBUG_SYNCHRO + DebugLog(SynchroFile,"PopUpProc:LEFTCLICK:ActualAccountSO-read wait\n"); + #endif + if (WAIT_OBJECT_0==WaitToReadFcn(ActualAccount->AccountAccessSO)) + { + #ifdef DEBUG_SYNCHRO + DebugLog(SynchroFile,"PopUpProc:LEFTCLICK:ActualAccountSO-read enter\n"); + #endif + switch(msg) + { + case WM_COMMAND: + { + YAMN_MAILBROWSERPARAM Param={(HANDLE)0,ActualAccount,ActualAccount->NewMailN.Flags,ActualAccount->NoNewMailN.Flags,0}; + + Param.nnflags=Param.nnflags | YAMN_ACC_MSG; //show mails in account even no new mail in account + Param.nnflags=Param.nnflags & ~YAMN_ACC_POP; + + Param.nflags=Param.nflags | YAMN_ACC_MSG; //show mails in account even no new mail in account + Param.nflags=Param.nflags & ~YAMN_ACC_POP; + + RunMailBrowserSvc((WPARAM)&Param,(LPARAM)YAMN_MAILBROWSERVERSION); + } + break; + } + #ifdef DEBUG_SYNCHRO + DebugLog(SynchroFile,"PopUpProc:LEFTCLICK:ActualAccountSO-read done\n"); + #endif + ReadDoneFcn(ActualAccount->AccountAccessSO); + } + #ifdef DEBUG_SYNCHRO + else + DebugLog(SynchroFile,"PopUpProc:LEFTCLICK:ActualAccountSO-read enter failed\n"); + #endif + SendMessageW(hWnd,UM_DESTROYPOPUP,0,0); + } + break; + + case WM_CONTEXTMENU: + SendMessageW(hWnd,UM_DESTROYPOPUP,0,0); + break; + + case UM_FREEPLUGINDATA: + //Here we'd free our own data, if we had it. + return FALSE; + case UM_INITPOPUP: + //This is the equivalent to WM_INITDIALOG you'd get if you were the maker of dialog popups. + WindowList_Add(YAMNVar.MessageWnds,hWnd,NULL); + break; + case UM_DESTROYPOPUP: + WindowList_Remove(YAMNVar.MessageWnds,hWnd); + break; + case WM_YAMN_STOPACCOUNT: + { + HACCOUNT ActualAccount; + HANDLE hContact; + DBVARIANT dbv; + + hContact=(HANDLE)CallService(MS_POPUP_GETCONTACT,(WPARAM)hWnd,(LPARAM)0); + + if (!DBGetContactSetting((HANDLE) hContact,YAMN_DBMODULE,"Id",&dbv)) + { + ActualAccount=(HACCOUNT) CallService(MS_YAMN_FINDACCOUNTBYNAME,(WPARAM)POP3Plugin,(LPARAM)dbv.pszVal); + DBFreeVariant(&dbv); + } + else + ActualAccount = (HACCOUNT) hContact; + + if ((HACCOUNT)wParam!=ActualAccount) + break; + + DestroyWindow(hWnd); + return 0; + } + case WM_NOTIFY: +/* switch(((LPNMHDR)lParam)->code) + { + case NM_CLICK: + { + } + } + break; +*/ default: + break; + } + return DefWindowProc(hWnd,msg,wParam,lParam); +} + +#ifdef __GNUC__ +//number of 100 ns periods between FILETIME 0 (1601/01/01 00:00:00.0000000) and TIMESTAMP 0 (1970/01/01 00:00:00) +#define NUM100NANOSEC 116444736000000000ULL +//The biggest time Get[Date|Time]Format can handle (Fri, 31 Dec 30827 23:59:59.9999999) +#define MAXFILETIME 0x7FFF35F4F06C7FFFULL +#else +#define NUM100NANOSEC 116444736000000000 +#define MAXFILETIME 0x7FFF35F4F06C7FFF +#endif + +ULONGLONG MimeDateToFileTime(char *datein) +{ + char *day=0, *month=0, *year=0, *time=0, *shift=0; + SYSTEMTIME st; + ULONGLONG res=0; + int wShiftSeconds = CallService(MS_DB_TIME_TIMESTAMPTOLOCAL,0,0); + GetLocalTime(&st); + //datein = "Xxx, 1 Jan 2060 5:29:1 +0530 XXX"; + //datein = "Xxx, 1 Jan 2060 05:29:10 "; + //datein = " ManySpaces 1.5 Jan 2060 05::"; + //datein = "Xxx, 35 February 20 :29:10 "; + //datein = "01.12.2007 (22:38:17)"; // + if (datein){ + char tmp [64]; + while ( datein[0]==' ') datein++; // eat leading spaces + strncpy(tmp,datein,63); tmp [63]=0; + if (atoi(tmp)) { // Parseable integer on DayOfWeek field? Buggy mime date. + day = tmp; + } else { + int i = 0; + while (tmp[i]==' ')i++; if (day = strchr(&tmp[i],' ')){day[0]=0; day++;} + } + if (day) {while ( day[0]==' ') day++;if (month= strchr(day, ' ')){month[0]=0; month++;}} + if (month) {while (month[0]==' ')month++;if (year = strchr(month,' ')) { year[0]=0; year++;}} + if (year) {while ( year[0]==' ') year++;if (time = strchr(year, ' ')) { time[0]=0; time++;}} + if (time) {while ( time[0]==' ') time++;if (shift= strchr(time, ' ')){shift[0]=0; shift++;shift[5]=0;}} + + if (year){ + st.wYear = atoi(year); + if (strlen(year)<4) if (st.wYear<70)st.wYear += 2000; else st.wYear += 1900; + }; + if (month) for (int i=0;i<12;i++) if (strncmp(month,s_MonthNames[i],3)==0) {st.wMonth = i + 1; break;} + if (day) st.wDay = atoi(day); + if (time) { + char *h, *m, *s; + h = time; + if (m = strchr(h,':')) { + m[0]=0; m++; + if (s = strchr(m,':')){s[0] = 0; s++;} + } else s=0; + st.wHour = atoi(h); + st.wMinute = m?atoi(m):0; + st.wSecond = s?atoi(s):0; + } else {st.wHour=st.wMinute=st.wSecond=0;} + + if (shift){ + if (strlen(shift)<4) { + //has only hour + wShiftSeconds = (atoi(shift))*3600; + } else { + char *smin = shift + strlen(shift)-2; + int ismin = atoi(smin); + smin[0] = 0; + int ishour = atoi(shift); + wShiftSeconds = (ishour*60+(ishour<0?-1:1)*ismin)*60; + } + } + } // if (datein) + FILETIME ft; + if (SystemTimeToFileTime(&st,&ft)) { + res = ((ULONGLONG)ft.dwHighDateTime<<32)|((ULONGLONG)ft.dwLowDateTime); + LONGLONG w100nano = Int32x32To64((DWORD)wShiftSeconds,10000000); + res -= w100nano; + }else{ + res=0; + } + return res; +} + +void FileTimeToLocalizedDateTime(LONGLONG filetime, WCHAR *dateout, int lendateout){ + int localeID = CallService(MS_LANGPACK_GETLOCALE,0,0); + //int localeID = MAKELCID(LANG_URDU, SORT_DEFAULT); + if (localeID==CALLSERVICE_NOTFOUND) localeID=LOCALE_USER_DEFAULT; + if (filetime>MAXFILETIME) filetime = MAXFILETIME; + else if (filetime<=0) { + wcsncpy(dateout,TranslateW(L"Invalid"),lendateout); + return; + } + SYSTEMTIME st; + WORD wTodayYear, wTodayMonth, wTodayDay; + FILETIME ft; + BOOL willShowDate = !(optDateTime&SHOWDATENOTODAY); + if (!willShowDate){ + GetLocalTime(&st); + wTodayYear = st.wYear; + wTodayMonth = st.wMonth; + wTodayDay = st.wDay; + } + ft.dwLowDateTime = (DWORD)filetime; + ft.dwHighDateTime = (DWORD)(filetime >> 32); + FILETIME localft; + if (!FileTimeToLocalFileTime(&ft,&localft)) { + // this should never happen + wcsncpy(dateout,L"Incorrect FileTime",lendateout); + } else { + if (!FileTimeToSystemTime(&localft,&st)) { + // this should never happen + wcsncpy(dateout,L"Incorrect LocalFileTime",lendateout); + } else { + dateout[lendateout-1]=0; + int templen = 0; + if (!willShowDate) willShowDate = (wTodayYear!=st.wYear)||(wTodayMonth!=st.wMonth)||(wTodayDay!=st.wDay); + if (willShowDate){ + templen = GetDateFormatW(localeID,(optDateTime&SHOWDATELONG)?DATE_LONGDATE:DATE_SHORTDATE,&st,NULL,dateout,lendateout-2); + dateout[templen-1] = ' '; + } + if (templen<(lendateout-1)) { + GetTimeFormatW(localeID,(optDateTime&SHOWDATENOSECONDS)?TIME_NOSECONDS:0,&st,NULL,&dateout[templen],lendateout-templen-1); + } + } + } +} + +void MimeDateToLocalizedDateTime(char *datein, WCHAR *dateout, int lendateout) +{ + ULONGLONG ft = MimeDateToFileTime(datein); + FileTimeToLocalizedDateTime(ft,dateout,lendateout); +} + +int CALLBACK ListViewCompareProc(LPARAM lParam1, LPARAM lParam2,LPARAM lParamSort ) { + if (lParam1 == NULL || lParam2 == NULL) + return 0; + + int nResult = 0; + char *str1; + char *str2; + HYAMNMAIL email1 = (HYAMNMAIL)lParam1; + HYAMNMAIL email2 = (HYAMNMAIL)lParam2; + struct CShortHeader Header1; + struct CShortHeader Header2; + ZeroMemory(&Header1,sizeof(Header1)); + ZeroMemory(&Header2,sizeof(Header2)); + + try { + ExtractShortHeader(email1->MailData->TranslatedHeader,&Header1); + ExtractShortHeader(email2->MailData->TranslatedHeader,&Header2); + + switch((int)lParamSort) + { + case 0: //From + if (Header1.FromNick == NULL) + str1 = Header1.From; + else str1 = Header1.FromNick; + + if (Header2.FromNick == NULL) + str2 = Header2.From; + else str2 = Header2.FromNick; + + nResult = strcmp(str1, str2); + + if (bFrom) nResult = -nResult; + break; + case 1: //Subject + if (Header1.Subject == NULL) + str1 = " "; + else str1 = Header1.Subject; + + if (Header2.Subject == NULL) + str2 = " "; + else str2 = Header2.Subject; + + nResult = strcmp(str1, str2); + + if (bSub) nResult = -nResult; + break; + case 2: //Size + if (email1->MailData->Size == email2->MailData->Size) nResult = 0; + if (email1->MailData->Size > email2->MailData->Size) nResult = 1; + if (email1->MailData->Size < email2->MailData->Size) nResult = -1; + + if (bSize) nResult = -nResult; + break; + + case 3: //Date + { + ULONGLONG ts1 = 0, ts2 = 0; + ts1 = MimeDateToFileTime(Header1.Date); + ts2 = MimeDateToFileTime(Header2.Date); + if (ts1 > ts2) nResult = 1; + else if (ts1 < ts2) nResult = -1; + else nResult = 0; + } + if (bDate) nResult = -nResult; + break; + + default: + if (Header1.Subject == NULL) str1 = " "; + else str1 = Header1.Subject; + + if (Header2.Subject == NULL) str2 = " "; + else str2 = Header2.Subject; + + nResult = strcmp(str1, str2); + break; + } + //MessageBox(NULL,str1,str2,0); + } + catch( ... ) + { + } + + //free mem + DeleteShortHeaderContent(&Header1); + DeleteShortHeaderContent(&Header2); + return nResult; + +} + +HCURSOR hCurSplitNS, hCurSplitWE; +static WNDPROC OldSplitterProc; +#define DM_SPLITTERMOVED (WM_USER+15) +static LRESULT CALLBACK SplitterSubclassProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) +{ + switch (msg) { + case WM_NCHITTEST: + return HTCLIENT; + case WM_SETCURSOR: + { + SetCursor(hCurSplitNS); + return TRUE; + } + case WM_LBUTTONDOWN: + SetCapture(hwnd); + return 0; + case WM_MOUSEMOVE: + if (GetCapture() == hwnd) { + RECT rc; + GetClientRect(hwnd, &rc); + SendMessage(GetParent(hwnd), DM_SPLITTERMOVED, (short) HIWORD(GetMessagePos()) + rc.bottom / 2, (LPARAM) hwnd); + } + return 0; + case WM_LBUTTONUP: + ReleaseCapture(); + return 0; + } + return CallWindowProc(OldSplitterProc, hwnd, msg, wParam, lParam); +} + + +void ConvertCodedStringToUnicode(char *stream,WCHAR **storeto,DWORD cp,int mode); +int ConvertStringToUnicode(char *stream,unsigned int cp,WCHAR **out); +INT_PTR CALLBACK DlgProcYAMNShowMessage(HWND hDlg,UINT msg,WPARAM wParam,LPARAM lParam) +{ + switch(msg) + { + case WM_INITDIALOG: + { +// HIMAGELIST hIcons; + PYAMN_MAILSHOWPARAM MailParam = (PYAMN_MAILSHOWPARAM)lParam; + WCHAR *iHeaderW=NULL; + WCHAR *iValueW=NULL; + int StrLen; + HWND hListView = GetDlgItem(hDlg,IDC_LISTHEADERS); + OldSplitterProc = (WNDPROC) SetWindowLongPtr(GetDlgItem(hDlg, IDC_SPLITTER), GWLP_WNDPROC, (LONG_PTR) SplitterSubclassProc); + SetWindowLongPtr(hDlg,DWLP_USER,(LONG_PTR)MailParam); + SendMessageW(hDlg,WM_SETICON,(WPARAM)ICON_BIG,(LPARAM)g_LoadIconEx(2, true)); + SendMessageW(hDlg,WM_SETICON,(WPARAM)ICON_SMALL,(LPARAM)g_LoadIconEx(2)); + + ListView_SetUnicodeFormat(hListView,TRUE); + ListView_SetExtendedListViewStyle(hListView,LVS_EX_FULLROWSELECT); + + StrLen=MultiByteToWideChar(CP_ACP,MB_USEGLYPHCHARS,Translate("Header"),-1,NULL,0); + iHeaderW=new WCHAR[StrLen+1]; + MultiByteToWideChar(CP_ACP,MB_USEGLYPHCHARS,Translate("Header"),-1,iHeaderW,StrLen); + + StrLen=MultiByteToWideChar(CP_ACP,MB_USEGLYPHCHARS,Translate("Value"),-1,NULL,0); + iValueW=new WCHAR[StrLen+1]; + MultiByteToWideChar(CP_ACP,MB_USEGLYPHCHARS,Translate("Value"),-1,iValueW,StrLen); + + LVCOLUMNW lvc0={LVCF_FMT | LVCF_TEXT | LVCF_WIDTH,LVCFMT_LEFT,130,iHeaderW,0,0}; + LVCOLUMNW lvc1={LVCF_FMT | LVCF_TEXT | LVCF_WIDTH,LVCFMT_LEFT,400,iValueW,0,0}; + SendMessageW(hListView,LVM_INSERTCOLUMNW,(WPARAM)0,(LPARAM)&lvc0); + SendMessageW(hListView,LVM_INSERTCOLUMNW,(WPARAM)1,(LPARAM)&lvc1); + if (NULL!=iHeaderW) + delete[] iHeaderW; + if (NULL!=iValueW) + delete[] iValueW; + + //WindowList_Add(YAMNVar.MessageWnds,hDlg,NULL); + //WindowList_Add(YAMNVar.NewMailAccountWnd,hDlg,ActualAccount); + SendMessage(hDlg,WM_YAMN_CHANGECONTENT,0,(LPARAM)MailParam); + MoveWindow(hDlg,HeadPosX,HeadPosY,HeadSizeX,HeadSizeY,0); + ShowWindow(hDlg,SW_SHOWNORMAL); + break; + } + case WM_YAMN_CHANGECONTENT: + { + PYAMN_MAILSHOWPARAM MailParam = (PYAMN_MAILSHOWPARAM) + (lParam?lParam:GetWindowLongPtr(hDlg,DWLP_USER)); + HWND hListView = GetDlgItem(hDlg,IDC_LISTHEADERS); + HWND hEdit = GetDlgItem(hDlg,IDC_EDITBODY); + //do not redraw + SendMessage(hListView, WM_SETREDRAW, 0, 0); + ListView_DeleteAllItems(hListView); + struct CMimeItem *Header; + LVITEMW item; + item.mask=LVIF_TEXT | LVIF_PARAM; + WCHAR *From=0,*Subj=0; + char *contentType=0, *transEncoding=0, *body=0; //should not be delete[]-ed + for (Header=MailParam->mail->MailData->TranslatedHeader;Header!=NULL;Header=Header->Next) + { + WCHAR *str1 = 0; + WCHAR *str2 = 0; + if (!body) if (!_stricmp(Header->name,"Body")) {body = Header->value; continue;} + if (!contentType) if (!_stricmp(Header->name,"Content-Type")) contentType = Header->value; + if (!transEncoding) if (!_stricmp(Header->name,"Content-Transfer-Encoding")) transEncoding = Header->value; + //ConvertCodedStringToUnicode(Header->name,&str1,MailParam->mail->MailData->CP,1); + { + int streamsize = MultiByteToWideChar(20127,0,Header->name,-1,NULL,0); + str1 = new WCHAR[streamsize+1]; + MultiByteToWideChar(20127,0,Header->name,-1,str1,streamsize);//US-ASCII + } + ConvertCodedStringToUnicode(Header->value,&str2,MailParam->mail->MailData->CP,1); + if (!str2) { str2 = (WCHAR *)malloc(2); str2[0] = 0; }// the header value may be NULL + if (!From) if (!_stricmp(Header->name,"From")) { + From =new WCHAR[wcslen(str2)+1]; + wcscpy(From,str2); + } + if (!Subj) if (!_stricmp(Header->name,"Subject")) { + Subj =new WCHAR[wcslen(str2)+1]; + wcscpy(Subj,str2); + } + //if (!hasBody) if (!strcmp(Header->name,"Body")) hasBody = true; + int count = 0; WCHAR **split=0; + if (str2){ + int ofs = 0; + while (str2[ofs]) { + if ((str2[ofs]==0x266A)||(str2[ofs]==0x25D9)||(str2[ofs]==0x25CB)|| + (str2[ofs]==0x09)||(str2[ofs]==0x0A)||(str2[ofs]==0x0D))count++; + ofs++; + } + split=new WCHAR*[count+1]; + count=0; ofs=0; + split[0]=str2; + while (str2[ofs]) { + if ((str2[ofs]==0x266A)||(str2[ofs]==0x25D9)||(str2[ofs]==0x25CB)|| + (str2[ofs]==0x09)||(str2[ofs]==0x0A)||(str2[ofs]==0x0D)) { + if (str2[ofs-1]) { + count++; + } + split[count]=(WCHAR *)(str2+ofs+1); + str2[ofs]=0; + } + ofs++; + }; + } + if (!_stricmp(Header->name,"From")||!_stricmp(Header->name,"To")||!_stricmp(Header->name,"Date")||!_stricmp(Header->name,"Subject")) + item.iItem = 0; + else + item.iItem = 999; + for (int i=0;i<=count;i++) { + item.iSubItem=0; + if (i==0) + item.pszText=str1; + else { + item.iItem++; + item.pszText=0; + } + item.iItem=SendMessageW(hListView,LVM_INSERTITEMW,(WPARAM)0,(LPARAM)&item); + item.iSubItem=1; + item.pszText=str2?split[i]:0; + SendMessageW(hListView,LVM_SETITEMTEXTW,(WPARAM)item.iItem,(LPARAM)&item); + } + if (split)delete[] split; + + if (str1) free(str1); + if (str2) free(str2); + } + if (body){ + WCHAR *bodyDecoded = 0; + char *localBody=0; + if (contentType) { + if (!_strnicmp(contentType,"text",4)) { + if (transEncoding){ + if (!_stricmp(transEncoding,"base64")) { + int size = (int)strlen(body)*3/4+5; + localBody = new char[size+1]; + DecodeBase64(body,localBody,size); + } else if (!_stricmp(transEncoding,"quoted-printable")) { + int size = (int)strlen(body)+2; + localBody = new char[size+1]; + DecodeQuotedPrintable(body,localBody,size,FALSE); + } + } + } else if (!_strnicmp(contentType,"multipart/",10)) { + char *bondary=NULL; + if (NULL!=(bondary=ExtractFromContentType(contentType,"boundary="))) + { + bodyDecoded = ParseMultipartBody(body,bondary); + delete[] bondary; + } + } + } + if (!bodyDecoded)ConvertStringToUnicode(localBody?localBody:body,MailParam->mail->MailData->CP,&bodyDecoded); + SendMessageW(hEdit,WM_SETTEXT,(WPARAM)0,(LPARAM)bodyDecoded); + delete[] bodyDecoded; + if (localBody) delete[] localBody; + SetFocus(hEdit); + } + if (!(MailParam->mail->Flags & YAMN_MSG_BODYRECEIVED)) { + MailParam->mail->Flags |= YAMN_MSG_BODYREQUESTED; + CallService(MS_YAMN_ACCOUNTCHECK,(WPARAM)MailParam->account,0); + } else { + if (MailParam->mail->Flags & YAMN_MSG_UNSEEN){ + MailParam->mail->Flags&=~YAMN_MSG_UNSEEN; //mark the message as seen + HWND hMailBrowser; + if (hMailBrowser=WindowList_Find(YAMNVar.NewMailAccountWnd,MailParam->account)) { + struct CChangeContent Params={MailParam->account->NewMailN.Flags|YAMN_ACC_MSGP,MailParam->account->NoNewMailN.Flags|YAMN_ACC_MSGP}; + SendMessageW(hMailBrowser,WM_YAMN_CHANGECONTENT,(WPARAM)MailParam->account,(LPARAM)&Params); + } else { + UpdateMails(NULL,MailParam->account,MailParam->account->NewMailN.Flags,MailParam->account->NoNewMailN.Flags); + } + } + } + ShowWindow(GetDlgItem(hDlg, IDC_SPLITTER),(MailParam->mail->Flags & YAMN_MSG_BODYRECEIVED)?SW_SHOW:SW_HIDE); + ShowWindow(hEdit,(MailParam->mail->Flags & YAMN_MSG_BODYRECEIVED)?SW_SHOW:SW_HIDE); + WCHAR *title=0; + title = new WCHAR[(From?wcslen(From):0)+(Subj?wcslen(Subj):0)+4]; + if (From&&Subj) wsprintfW(title,L"%s (%s)",Subj,From); + else if (From)wsprintfW(title,L"%s",From); + else if (Subj)wsprintfW(title,L"%s",Subj); + else wsprintfW(title,L"none"); + if (Subj) delete[] Subj; + if (From) delete[] From; + SendMessageW(hDlg,WM_SETTEXT,(WPARAM)0,(LPARAM)title); + delete[] title; + // turn on redrawing + SendMessage(hListView, WM_SETREDRAW, 1, 0); + SendMessage(hDlg, WM_SIZE, 0, HeadSizeY<<16|HeadSizeX); + } break; + case WM_YAMN_STOPACCOUNT: + { + PYAMN_MAILSHOWPARAM MailParam = (PYAMN_MAILSHOWPARAM) + (lParam?lParam:GetWindowLongPtr(hDlg,DWLP_USER)); + + if (NULL==MailParam) + break; + if ((HACCOUNT)wParam!=MailParam->account) + break; + #ifdef DEBUG_SYNCHRO + DebugLog(SynchroFile,"ShowMessage:STOPACCOUNT:sending destroy msg\n"); + #endif + DestroyWindow(hDlg); + } + return 1; + case WM_CTLCOLORSTATIC: + //here should be check if this is our edittext control. + //but we have only one static control (for now); + SetBkColor((HDC)wParam, GetSysColor(COLOR_WINDOW)); + SetTextColor((HDC)wParam, GetSysColor(COLOR_WINDOWTEXT)); + return (INT_PTR)GetSysColorBrush(COLOR_WINDOW);; + case WM_DESTROY: + { + RECT coord; + if (GetWindowRect(hDlg,&coord)) + { + HeadPosX=coord.left; + HeadSizeX=coord.right-coord.left; + HeadPosY=coord.top; + HeadSizeY=coord.bottom-coord.top; + } + + PostQuitMessage(1); + } + break; + case WM_SYSCOMMAND: + { + switch(wParam) + { + case SC_CLOSE: + DestroyWindow(hDlg); + break; + } + } + break; + case WM_MOVE: + HeadPosX=LOWORD(lParam); //((LPRECT)lParam)->right-((LPRECT)lParam)->left; + HeadPosY=HIWORD(lParam); //((LPRECT)lParam)->bottom-((LPRECT)lParam)->top; + return 0; + case DM_SPLITTERMOVED: + { + if ((HWND) lParam == GetDlgItem(hDlg, IDC_SPLITTER)) { + POINT pt; + pt.x = 0; + pt.y = wParam; + ScreenToClient(hDlg, &pt); + HeadSplitPos = (pt.y*1000)/HeadSizeY;//+rc.bottom-rc.top; + if (HeadSplitPos>=1000) HeadSplitPos = 999; + else if (HeadSplitPos<=0) HeadSplitPos = 1; + else SendMessage(hDlg, WM_SIZE, 0, HeadSizeY<<16|HeadSizeX); + } + return 0; + } + case WM_SIZE: + if (wParam==SIZE_RESTORED) + { + HWND hList = GetDlgItem(hDlg,IDC_LISTHEADERS); + HWND hEdit = GetDlgItem(hDlg,IDC_EDITBODY); + BOOL changeX = LOWORD(lParam)!=HeadSizeX; + BOOL isBodyShown = ((PYAMN_MAILSHOWPARAM)(GetWindowLongPtr(hDlg,DWLP_USER)))->mail->Flags & YAMN_MSG_BODYRECEIVED; + HeadSizeX=LOWORD(lParam); //((LPRECT)lParam)->right-((LPRECT)lParam)->left; + HeadSizeY=HIWORD(lParam); //((LPRECT)lParam)->bottom-((LPRECT)lParam)->top; + int localSplitPos = (HeadSplitPos*HeadSizeY)/1000; + int localSizeX; + RECT coord; + MoveWindow(GetDlgItem(hDlg,IDC_SPLITTER),5,localSplitPos,HeadSizeX-10,2,TRUE); + MoveWindow(hEdit,5,localSplitPos+6,HeadSizeX-10,HeadSizeY-localSplitPos-11,TRUE); //where to put text window while resizing + MoveWindow(hList, 5 ,5 ,HeadSizeX-10 ,(isBodyShown?localSplitPos:HeadSizeY)-10,TRUE); //where to put headers list window while resizing + //if (changeX){ + if (GetClientRect(hList,&coord)) { + localSizeX=coord.right-coord.left; + } else localSizeX=HeadSizeX; + LONG iNameWidth = ListView_GetColumnWidth(hList,0); + ListView_SetColumnWidth(hList,1,(localSizeX<=iNameWidth)?0:(localSizeX-iNameWidth)); + //} + } +// break; + return 0; + case WM_CONTEXTMENU: + { + if ( GetWindowLongPtr(( HWND )wParam, GWLP_ID ) == IDC_LISTHEADERS) { + //MessageBox(0,"LISTHEADERS","Debug",0); + HWND hList = GetDlgItem( hDlg, IDC_LISTHEADERS ); + POINT pt = { (signed short)LOWORD( lParam ), (signed short)HIWORD( lParam ) }; + HTREEITEM hItem = 0; + if (pt.x==-1) pt.x = 0; + if (pt.y==-1) pt.y = 0; + if (int numRows = ListView_GetItemCount(hList)) { + HMENU hMenu = CreatePopupMenu(); + AppendMenu(hMenu, MF_STRING, (UINT_PTR)1, TranslateT("Copy Selected")); + AppendMenu(hMenu, MF_STRING, (UINT_PTR)2, TranslateT("Copy All")); + AppendMenu(hMenu, MF_SEPARATOR, 0, NULL); + AppendMenu(hMenu, MF_STRING, (UINT_PTR)0, TranslateT("Cancel")); + int nReturnCmd = TrackPopupMenu( hMenu, TPM_RETURNCMD, pt.x, pt.y, 0, hDlg, NULL ); + DestroyMenu( hMenu ); + if (nReturnCmd>0){ + int courRow=0; + size_t sizeNeeded = 0; + TCHAR headname[64]={0}, headvalue[256]={0}; + for (courRow=0; courRow < numRows; courRow++) { + if ((nReturnCmd==1) && (ListView_GetItemState(hList, courRow, LVIS_SELECTED)==0)) continue; + ListView_GetItemText(hList, courRow, 0, headname, SIZEOF(headname)); + ListView_GetItemText(hList, courRow, 1, headvalue, SIZEOF(headvalue)); + size_t headnamelen = _tcslen(headname); + if (headnamelen) sizeNeeded += 1 + headnamelen; + sizeNeeded += 3 + _tcslen(headvalue); + } + if (sizeNeeded && OpenClipboard(hDlg)) { + EmptyClipboard(); + HGLOBAL hData = GlobalAlloc(GMEM_MOVEABLE,(sizeNeeded+1)*sizeof(TCHAR)); + TCHAR *buff = ( TCHAR* )GlobalLock(hData); + int courPos = 0; + for (courRow=0;courRow<numRows;courRow++) { + if ((nReturnCmd==1) && (ListView_GetItemState(hList, courRow, LVIS_SELECTED)==0)) continue; + ListView_GetItemText(hList, courRow, 0, headname, SIZEOF(headname)); + ListView_GetItemText(hList, courRow, 1, headvalue, SIZEOF(headvalue)); + if ( _tcslen(headname)) courPos += _stprintf(&buff[courPos], _T("%s:\t%s\r\n"), headname, headvalue); + else courPos += _stprintf( &buff[courPos], _T("\t%s\r\n"), headvalue); + } + GlobalUnlock(hData); + #if defined( _UNICODE ) + SetClipboardData(CF_UNICODETEXT,hData); + #else + SetClipboardData(CF_TEXT,hData); + #endif + CloseClipboard(); + } + } + } + } } + break; // just in case + } + return 0; +} + +DWORD WINAPI ShowEmailThread(LPVOID Param){ + struct MailShowMsgWinParam MyParam; + MyParam=*(struct MailShowMsgWinParam *)Param; + + #ifdef DEBUG_SYNCHRO + DebugLog(SynchroFile,"ShowMessage:Incrementing \"using threads\" %x (account %x)\n",MyParam.account->UsingThreads,MyParam.account); + #endif + SCIncFcn(MyParam.account->UsingThreads); + SetEvent(MyParam.ThreadRunningEV); + if (MyParam.mail->MsgWindow){ + //if (!BringWindowToTop(MyParam.mail->MsgWindow)) { + if (!SetForegroundWindow(MyParam.mail->MsgWindow)) { + SendMessage(MyParam.mail->MsgWindow,WM_DESTROY,0,0); + MyParam.mail->MsgWindow = 0; + goto CREADTEVIEWMESSAGEWINDOW; + }else{ + if (IsIconic(MyParam.mail->MsgWindow)) { + OpenIcon(MyParam.mail->MsgWindow); + } + } + } else { +CREADTEVIEWMESSAGEWINDOW: + MyParam.mail->MsgWindow = CreateDialogParamW(YAMNVar.hInst,MAKEINTRESOURCEW(IDD_DLGSHOWMESSAGE),NULL,(DLGPROC)DlgProcYAMNShowMessage,(LPARAM)&MyParam); + WindowList_Add(YAMNVar.MessageWnds,MyParam.mail->MsgWindow,NULL); + MSG msg; + while(GetMessage(&msg,NULL,0,0)) { + if (!IsDialogMessage(MyParam.mail->MsgWindow, &msg)) { + TranslateMessage(&msg); + DispatchMessage(&msg); + } } + WindowList_Remove(YAMNVar.MessageWnds,MyParam.mail->MsgWindow); + MyParam.mail->MsgWindow = NULL; + } + #ifdef DEBUG_SYNCHRO + DebugLog(SynchroFile,"ShowMessage:Decrementing \"using threads\" %x (account %x)\n",MyParam.account->UsingThreads,MyParam.account); + #endif + SCDecFcn(MyParam.account->UsingThreads); + delete Param; + return 1; +} + +BOOL CALLBACK DlgProcYAMNMailBrowser(HWND hDlg,UINT msg,WPARAM wParam,LPARAM lParam) +{ + switch(msg) + { + case WM_INITDIALOG: + { + HACCOUNT ActualAccount; + struct MailBrowserWinParam *MyParam=(struct MailBrowserWinParam *)lParam; + struct CMailWinUserInfo *mwui; + + ListView_SetUnicodeFormat(GetDlgItem(hDlg,IDC_LISTMAILS),TRUE); + ListView_SetExtendedListViewStyle(GetDlgItem(hDlg,IDC_LISTMAILS),LVS_EX_FULLROWSELECT); + + ActualAccount=MyParam->account; + mwui=new struct CMailWinUserInfo; + mwui->Account=ActualAccount; + mwui->TrayIconState=0; + mwui->UpdateMailsMessagesAccess=FALSE; + mwui->Seen=FALSE; + mwui->RunFirstTime=TRUE; + + SetWindowLongPtr(hDlg,DWLP_USER,(LONG_PTR)mwui); + #ifdef DEBUG_SYNCHRO + DebugLog(SynchroFile,"MailBrowser:INIT:ActualAccountSO-read wait\n"); + #endif + if (WAIT_OBJECT_0!=WaitToReadFcn(ActualAccount->AccountAccessSO)) + { + #ifdef DEBUG_SYNCHRO + DebugLog(SynchroFile,"MailBrowser:INIT:ActualAccountSO-read enter failed\n"); + #endif + DestroyWindow(hDlg); + return FALSE; + } + #ifdef DEBUG_SYNCHRO + DebugLog(SynchroFile,"MailBrowser:INIT:ActualAccountSO-read enter\n"); + #endif + + SendMessageW(GetDlgItem(hDlg,IDC_BTNAPP),WM_SETTEXT,(WPARAM)0,(LPARAM)TranslateW(L"Run application")); + SendMessageW(GetDlgItem(hDlg,IDC_BTNDEL),WM_SETTEXT,(WPARAM)0,(LPARAM)TranslateW(L"Delete selected")); + SendMessageW(GetDlgItem(hDlg,IDC_BTNCHECKALL),WM_SETTEXT,(WPARAM)0,(LPARAM)TranslateW(L"Select All")); + SendMessageW(GetDlgItem(hDlg,IDC_BTNOK),WM_SETTEXT,(WPARAM)0,(LPARAM)TranslateW(L"OK")); + + LVCOLUMNW lvc0={LVCF_FMT | LVCF_TEXT | LVCF_WIDTH,LVCFMT_LEFT,FromWidth,TranslateW(L"From"),0,0}; + LVCOLUMNW lvc1={LVCF_FMT | LVCF_TEXT | LVCF_WIDTH,LVCFMT_LEFT,SubjectWidth,TranslateW(L"Subject"),0,0}; + LVCOLUMNW lvc2={LVCF_FMT | LVCF_TEXT | LVCF_WIDTH,LVCFMT_LEFT,SizeWidth,TranslateW(L"Size"),0,0}; + LVCOLUMNW lvc3={LVCF_FMT | LVCF_TEXT | LVCF_WIDTH,LVCFMT_LEFT,SizeDate,TranslateW(L"Date"),0,0}; + SendMessageW(GetDlgItem(hDlg,IDC_LISTMAILS),LVM_INSERTCOLUMNW,(WPARAM)0,(LPARAM)&lvc0); + SendMessageW(GetDlgItem(hDlg,IDC_LISTMAILS),LVM_INSERTCOLUMNW,(WPARAM)1,(LPARAM)&lvc1); + SendMessageW(GetDlgItem(hDlg,IDC_LISTMAILS),LVM_INSERTCOLUMNW,(WPARAM)2,(LPARAM)&lvc2); + SendMessageW(GetDlgItem(hDlg,IDC_LISTMAILS),LVM_INSERTCOLUMNW,(WPARAM)3,(LPARAM)&lvc3); + + if ((ActualAccount->NewMailN.App!=NULL) && (wcslen(ActualAccount->NewMailN.App))) + EnableWindow(GetDlgItem(hDlg,IDC_BTNAPP),(WPARAM)TRUE); + else + EnableWindow(GetDlgItem(hDlg,IDC_BTNAPP),(WPARAM)FALSE); + #ifdef DEBUG_SYNCHRO + DebugLog(SynchroFile,"MailBrowser:INIT:ActualAccountSO-read done\n"); + #endif + ReadDoneFcn(ActualAccount->AccountAccessSO); + + WindowList_Add(YAMNVar.MessageWnds,hDlg,NULL); + WindowList_Add(YAMNVar.NewMailAccountWnd,hDlg,ActualAccount); + + { + TCHAR accstatus[512]; + GetStatusFcn(ActualAccount,accstatus); + SetDlgItemText(hDlg,IDC_STSTATUS,accstatus); + } + SetTimer(hDlg,TIMER_FLASHING,500,NULL); + + if (ActualAccount->hContact != NULL) + { + CallService(MS_CLIST_REMOVEEVENT,(WPARAM)ActualAccount->hContact,(LPARAM)"yamn new mail message"); + } + + OldListViewSubclassProc = (WNDPROC) SetWindowLongPtr(GetDlgItem(hDlg, IDC_LISTMAILS), GWLP_WNDPROC, (LONG_PTR) ListViewSubclassProc); + + break; + } + case WM_DESTROY: + { + HACCOUNT ActualAccount; + RECT coord; + LVCOLUMNW ColInfo; + NOTIFYICONDATA nid; + HYAMNMAIL Parser; + struct CMailWinUserInfo *mwui; + + mwui=(struct CMailWinUserInfo *)GetWindowLongPtr(hDlg,DWLP_USER); + if (NULL==(ActualAccount=GetWindowAccount(hDlg))) + break; + ColInfo.mask=LVCF_WIDTH; + if (ListView_GetColumn(GetDlgItem(hDlg,IDC_LISTMAILS),0,&ColInfo)) + FromWidth=ColInfo.cx; + if (ListView_GetColumn(GetDlgItem(hDlg,IDC_LISTMAILS),1,&ColInfo)) + SubjectWidth=ColInfo.cx; + if (ListView_GetColumn(GetDlgItem(hDlg,IDC_LISTMAILS),2,&ColInfo)) + SizeWidth=ColInfo.cx; + if (ListView_GetColumn(GetDlgItem(hDlg,IDC_LISTMAILS),3,&ColInfo)) + SizeDate=ColInfo.cx; + + #ifdef DEBUG_SYNCHRO + DebugLog(SynchroFile,"MailBrowser:DESTROY:save window position\n"); + #endif + if (!YAMNVar.Shutdown && GetWindowRect(hDlg,&coord)) //the YAMNVar.Shutdown testing is because M<iranda strange functionality at shutdown phase, when call to DBWriteContactSetting freezes calling thread + { + PosX=coord.left; + SizeX=coord.right-coord.left; + PosY=coord.top; + SizeY=coord.bottom-coord.top; + DBWriteContactSettingDword(NULL,YAMN_DBMODULE,YAMN_DBPOSX,PosX); + DBWriteContactSettingDword(NULL,YAMN_DBMODULE,YAMN_DBPOSY,PosY); + DBWriteContactSettingDword(NULL,YAMN_DBMODULE,YAMN_DBSIZEX,SizeX); + DBWriteContactSettingDword(NULL,YAMN_DBMODULE,YAMN_DBSIZEY,SizeY); + } + KillTimer(hDlg,TIMER_FLASHING); + + #ifdef DEBUG_SYNCHRO + DebugLog(SynchroFile,"MailBrowser:DESTROY:remove window from list\n"); + #endif + WindowList_Remove(YAMNVar.NewMailAccountWnd,hDlg); + WindowList_Remove(YAMNVar.MessageWnds,hDlg); + + #ifdef DEBUG_SYNCHRO + DebugLog(SynchroFile,"MailBrowser:DESTROY:ActualAccountMsgsSO-write wait\n"); + #endif + if (WAIT_OBJECT_0!=WaitToWriteFcn(ActualAccount->MessagesAccessSO)) + { + #ifdef DEBUG_SYNCHRO + DebugLog(SynchroFile,"MailBrowser:DESTROY:ActualAccountMsgsSO-write wait failed\n"); + #endif + break; + } + #ifdef DEBUG_SYNCHRO + DebugLog(SynchroFile,"MailBrowser:DESTROY:ActualAccountMsgsSO-write enter\n"); + #endif + //delete mails from queue, which are deleted from server (spam level 3 mails e.g.) + for (Parser=(HYAMNMAIL)ActualAccount->Mails;Parser!=NULL;Parser=Parser->Next) + { + if ((Parser->Flags & YAMN_MSG_DELETED) && YAMN_MSG_SPAML(Parser->Flags,YAMN_MSG_SPAML3) && mwui->Seen) //if spaml3 was already deleted and user knows about it + { + DeleteMessageFromQueueFcn((HYAMNMAIL *)&ActualAccount->Mails,Parser,1); + CallService(MS_YAMN_DELETEACCOUNTMAIL,(WPARAM)ActualAccount->Plugin,(LPARAM)Parser); + } + } + + //mark mails as read (remove "new" and "unseen" flags) + if (mwui->Seen) + SetRemoveFlagsInQueueFcn((HYAMNMAIL)ActualAccount->Mails,YAMN_MSG_DISPLAY,0,YAMN_MSG_NEW | YAMN_MSG_UNSEEN,0); + #ifdef DEBUG_SYNCHRO + DebugLog(SynchroFile,"MailBrowser:DESTROY:ActualAccountMsgsSO-write done\n"); + #endif + WriteDoneFcn(ActualAccount->MessagesAccessSO); + + ZeroMemory(&nid,sizeof(NOTIFYICONDATA)); + + delete mwui; + SetWindowLongPtr(hDlg,DWLP_USER,(LONG_PTR)NULL); + + nid.cbSize=sizeof(NOTIFYICONDATA); + nid.hWnd=hDlg; + nid.uID=0; + Shell_NotifyIcon(NIM_DELETE,&nid); + PostQuitMessage(0); + } + break; + case WM_SHOWWINDOW: + { + struct CMailWinUserInfo *mwui; + + if (NULL==(mwui=(struct CMailWinUserInfo *)GetWindowLongPtr(hDlg,DWLP_USER))) + return 0; + mwui->Seen=TRUE; + } + case WM_YAMN_CHANGESTATUS: + { + HACCOUNT ActualAccount; + if (NULL==(ActualAccount=GetWindowAccount(hDlg))) + break; + + if ((HACCOUNT)wParam!=ActualAccount) + break; + + TCHAR accstatus[512]; + GetStatusFcn(ActualAccount,accstatus); + SetDlgItemText(hDlg,IDC_STSTATUS,accstatus); + } + return 1; + case WM_YAMN_CHANGECONTENT: + { + struct CUpdateMails UpdateParams; + BOOL ThisThreadWindow=(GetCurrentThreadId()==GetWindowThreadProcessId(hDlg,NULL)); + + if (NULL==(UpdateParams.Copied=CreateEvent(NULL,FALSE,FALSE,NULL))) + { + DestroyWindow(hDlg); + return 0; + } + UpdateParams.Flags=(struct CChangeContent *)lParam; + UpdateParams.Waiting=!ThisThreadWindow; + + #ifdef DEBUG_SYNCHRO + DebugLog(SynchroFile,"MailBrowser:CHANGECONTENT:posting UPDATEMAILS\n"); + #endif + if (ThisThreadWindow) + { + if (!UpdateMails(hDlg,(HACCOUNT)wParam,UpdateParams.Flags->nflags,UpdateParams.Flags->nnflags)) + DestroyWindow(hDlg); + } + else if (PostMessage(hDlg,WM_YAMN_UPDATEMAILS,wParam,(LPARAM)&UpdateParams)) //this ensures UpdateMails will execute the thread who created the browser window + { + if (!ThisThreadWindow) + { + #ifdef DEBUG_SYNCHRO + DebugLog(SynchroFile,"MailBrowser:CHANGECONTENT:waiting for event\n"); + #endif + WaitForSingleObject(UpdateParams.Copied,INFINITE); + #ifdef DEBUG_SYNCHRO + DebugLog(SynchroFile,"MailBrowser:CHANGECONTENT:event signaled\n"); + #endif + } + } + + CloseHandle(UpdateParams.Copied); + } + return 1; + case WM_YAMN_UPDATEMAILS: + { + HACCOUNT ActualAccount; + + struct CUpdateMails *um=(struct CUpdateMails *)lParam; + DWORD nflags,nnflags; + + #ifdef DEBUG_SYNCHRO + DebugLog(SynchroFile,"MailBrowser:UPDATEMAILS\n"); + #endif + + if (NULL==(ActualAccount=GetWindowAccount(hDlg))) + return 0; + if ((HACCOUNT)wParam!=ActualAccount) + return 0; + + nflags=um->Flags->nflags; + nnflags=um->Flags->nnflags; + + if (um->Waiting) + SetEvent(um->Copied); + + if (!UpdateMails(hDlg,ActualAccount,nflags,nnflags)) + DestroyWindow(hDlg); + } + return 1; + case WM_YAMN_STOPACCOUNT: + { + HACCOUNT ActualAccount; + + if (NULL==(ActualAccount=GetWindowAccount(hDlg))) + break; + if ((HACCOUNT)wParam!=ActualAccount) + break; + #ifdef DEBUG_SYNCHRO + DebugLog(SynchroFile,"MailBrowser:STOPACCOUNT:sending destroy msg\n"); + #endif + PostQuitMessage(0); + } + return 1; + case WM_YAMN_NOTIFYICON: + { + HACCOUNT ActualAccount; + if (NULL==(ActualAccount=GetWindowAccount(hDlg))) + break; + + switch(lParam) + { + case WM_LBUTTONDBLCLK: + #ifdef DEBUG_SYNCHRO + DebugLog(SynchroFile,"MailBrowser:DBLCLICKICON:ActualAccountSO-read wait\n"); + #endif + if (WAIT_OBJECT_0!=WaitToReadFcn(ActualAccount->AccountAccessSO)) + { + #ifdef DEBUG_SYNCHRO + DebugLog(SynchroFile,"MailBrowser:DBLCLICKICON:ActualAccountSO-read wait failed\n"); + #endif + return 0; + } + #ifdef DEBUG_SYNCHRO + DebugLog(SynchroFile,"MailBrowser:DBLCLICKICON:ActualAccountSO-read enter\n"); + #endif + if (ActualAccount->AbilityFlags & YAMN_ACC_BROWSE) + { + ShowWindow(hDlg,SW_SHOWNORMAL); + SetForegroundWindow(hDlg); + } + else + DestroyWindow(hDlg); + #ifdef DEBUG_SYNCHRO + DebugLog(SynchroFile,"MailBrowser:DBLCLICKICON:ActualAccountSO-read done\n"); + #endif + ReadDoneFcn(ActualAccount->AccountAccessSO); + break; + } + break; + } + case WM_YAMN_SHOWSELECTED: + { + int iSelect; + iSelect=SendMessage(GetDlgItem(hDlg,IDC_LISTMAILS),LVM_GETNEXTITEM,-1,MAKELPARAM((UINT)LVNI_FOCUSED,0)); // return item selected + + if (iSelect!=-1) + { + LV_ITEMW item; + HYAMNMAIL ActualMail; + + item.iItem=iSelect; + item.iSubItem=0; + item.mask=LVIF_PARAM | LVIF_STATE; + item.stateMask=0xFFFFFFFF; + ListView_GetItem(GetDlgItem(hDlg,IDC_LISTMAILS),&item); + ActualMail=(HYAMNMAIL)item.lParam; + if (NULL!=ActualMail) + { + //ShowEmailThread + PYAMN_MAILSHOWPARAM MailParam = new YAMN_MAILSHOWPARAM; + MailParam->account = GetWindowAccount(hDlg); + MailParam->mail = ActualMail; + if (NULL!=(MailParam->ThreadRunningEV=CreateEvent(NULL,FALSE,FALSE,NULL))) { + HANDLE NewThread; + if (NULL!=(NewThread=CreateThread(NULL,0,ShowEmailThread,MailParam,0,NULL))) + { + //WaitForSingleObject(MailParam->ThreadRunningEV,INFINITE); + CloseHandle(NewThread); + } + CloseHandle(MailParam->ThreadRunningEV); + } + //delete MailParam; + } + } + } break; + case WM_SYSCOMMAND: + { + HACCOUNT ActualAccount; + + if (NULL==(ActualAccount=GetWindowAccount(hDlg))) + break; + switch(wParam) + { + case SC_CLOSE: + DestroyWindow(hDlg); + break; + } + } + break; + + case WM_COMMAND: + { + HACCOUNT ActualAccount; + int Items; + + if (NULL==(ActualAccount=GetWindowAccount(hDlg))) + break; + + switch(LOWORD(wParam)) + { + case IDC_BTNCHECKALL: + ListView_SetItemState(GetDlgItem(hDlg,IDC_LISTMAILS), -1, 0, LVIS_SELECTED); // deselect all items + ListView_SetItemState(GetDlgItem(hDlg,IDC_LISTMAILS),-1, LVIS_SELECTED ,LVIS_SELECTED); + Items = ListView_GetItemCount(GetDlgItem(hDlg,IDC_LISTMAILS)); + ListView_RedrawItems(GetDlgItem(hDlg,IDC_LISTMAILS), 0, Items); + UpdateWindow(GetDlgItem(hDlg,IDC_LISTMAILS)); + SetFocus(GetDlgItem(hDlg,IDC_LISTMAILS)); + break; + + case IDC_BTNOK: + DestroyWindow(hDlg); + break; + + case IDC_BTNAPP: + { + PROCESS_INFORMATION pi; + STARTUPINFOW si; + + ZeroMemory(&si,sizeof(si)); + si.cb=sizeof(si); + + #ifdef DEBUG_SYNCHRO + DebugLog(SynchroFile,"MailBrowser:BTNAPP:ActualAccountSO-read wait\n"); + #endif + if (WAIT_OBJECT_0==WaitToReadFcn(ActualAccount->AccountAccessSO)) + { + #ifdef DEBUG_SYNCHRO + DebugLog(SynchroFile,"MailBrowser:BTNAPP:ActualAccountSO-read enter\n"); + #endif + if (ActualAccount->NewMailN.App!=NULL) + { + WCHAR *Command; + if (ActualAccount->NewMailN.AppParam!=NULL) + Command=new WCHAR[wcslen(ActualAccount->NewMailN.App)+wcslen(ActualAccount->NewMailN.AppParam)+6]; + else + Command=new WCHAR[wcslen(ActualAccount->NewMailN.App)+6]; + + if (Command!=NULL) + { + lstrcpyW(Command,L"\""); + lstrcatW(Command,ActualAccount->NewMailN.App); + lstrcatW(Command,L"\" "); + if (ActualAccount->NewMailN.AppParam!=NULL) + lstrcatW(Command,ActualAccount->NewMailN.AppParam); + CreateProcessW(NULL,Command,NULL,NULL,FALSE,NORMAL_PRIORITY_CLASS,NULL,NULL,&si,&pi); + delete[] Command; + } + } + + #ifdef DEBUG_SYNCHRO + DebugLog(SynchroFile,"MailBrowser:BTNAPP:ActualAccountSO-read done\n"); + #endif + ReadDoneFcn(ActualAccount->AccountAccessSO); + } + #ifdef DEBUG_SYNCHRO + else + DebugLog(SynchroFile,"MailBrowser:BTNAPP:ActualAccountSO-read enter failed\n"); + #endif + if (!(GetKeyState(VK_SHIFT) & 0x8000) && !(GetKeyState(VK_CONTROL) & 0x8000)) + DestroyWindow(hDlg); + + } + break; + case IDC_BTNDEL: + { + LVITEMW item; + HYAMNMAIL FirstMail=NULL,ActualMail; + HANDLE ThreadRunningEV; + DWORD tid,Total=0; + + // we use event to signal, that running thread has all needed stack parameters copied + if (NULL==(ThreadRunningEV=CreateEvent(NULL,FALSE,FALSE,NULL))) + break; + int Items=ListView_GetItemCount(GetDlgItem(hDlg,IDC_LISTMAILS)); + + item.stateMask=0xFFFFFFFF; + #ifdef DEBUG_SYNCHRO + DebugLog(SynchroFile,"MailBrowser:BTNDEL:ActualAccountMsgsSO-write wait\n"); + #endif + if (WAIT_OBJECT_0==WaitToWriteFcn(ActualAccount->MessagesAccessSO)) + { + #ifdef DEBUG_SYNCHRO + DebugLog(SynchroFile,"MailBrowser:BTNDEL:ActualAccountMsgsSO-write enter\n"); + #endif + for (int i=0;i<Items;i++) + { + item.iItem=i; + item.iSubItem=0; + item.mask=LVIF_PARAM | LVIF_STATE; + item.stateMask=0xFFFFFFFF; + ListView_GetItem(GetDlgItem(hDlg,IDC_LISTMAILS),&item); + ActualMail=(HYAMNMAIL)item.lParam; + if (NULL==ActualMail) + break; + if (item.state & LVIS_SELECTED) + { + ActualMail->Flags|=YAMN_MSG_USERDELETE; //set to mail we are going to delete it + Total++; + } + } + + // Enable write-access to mails + #ifdef DEBUG_SYNCHRO + DebugLog(SynchroFile,"MailBrowser:BTNDEL:ActualAccountMsgsSO-write done\n"); + #endif + WriteDoneFcn(ActualAccount->MessagesAccessSO); + + if (Total) + { + TCHAR DeleteMsg[1024]; + + wsprintf(DeleteMsg,TranslateT("Do you really want to delete %d selected mails?"),Total); + if (IDOK==MessageBox(hDlg,DeleteMsg,TranslateT("Delete confirmation"),MB_OKCANCEL | MB_ICONWARNING)) + { + struct DeleteParam ParamToDeleteMails={YAMN_DELETEVERSION,ThreadRunningEV,ActualAccount,NULL}; + + // Find if there's mail marked to delete, which was deleted before + #ifdef DEBUG_SYNCHRO + DebugLog(SynchroFile,"MailBrowser:BTNDEL:ActualAccountMsgsSO-write wait\n"); + #endif + if (WAIT_OBJECT_0==WaitToWriteFcn(ActualAccount->MessagesAccessSO)) + { + #ifdef DEBUG_SYNCHRO + DebugLog(SynchroFile,"MailBrowser:BTNDEL:ActualAccountMsgsSO-write enter\n"); + #endif + for (ActualMail=(HYAMNMAIL)ActualAccount->Mails;ActualMail!=NULL;ActualMail=ActualMail->Next) + { + if ((ActualMail->Flags & YAMN_MSG_DELETED) && ((ActualMail->Flags & YAMN_MSG_USERDELETE))) //if selected mail was already deleted + { + DeleteMessageFromQueueFcn((HYAMNMAIL *)&ActualAccount->Mails,ActualMail,1); + CallService(MS_YAMN_DELETEACCOUNTMAIL,(WPARAM)ActualAccount->Plugin,(LPARAM)ActualMail); //delete it from memory + continue; + } + } + // Set flag to marked mails that they can be deleted + SetRemoveFlagsInQueueFcn((HYAMNMAIL)ActualAccount->Mails,YAMN_MSG_DISPLAY | YAMN_MSG_USERDELETE,0,YAMN_MSG_DELETEOK,1); + // Create new thread which deletes marked mails. + HANDLE NewThread; + + if (NULL!=(NewThread=CreateThread(NULL,0,(LPTHREAD_START_ROUTINE)ActualAccount->Plugin->Fcn->DeleteMailsFcnPtr,(LPVOID)&ParamToDeleteMails,0,&tid))) + { + WaitForSingleObject(ThreadRunningEV,INFINITE); + CloseHandle(NewThread); + } + // Enable write-access to mails + #ifdef DEBUG_SYNCHRO + DebugLog(SynchroFile,"MailBrowser:BTNDEL:ActualAccountMsgsSO-write done\n"); + #endif + WriteDoneFcn(ActualAccount->MessagesAccessSO); + } + } + else + //else mark messages that they are not to be deleted + SetRemoveFlagsInQueueFcn((HYAMNMAIL)ActualAccount->Mails,YAMN_MSG_DISPLAY | YAMN_MSG_USERDELETE,0,YAMN_MSG_USERDELETE,0); + } + } + CloseHandle(ThreadRunningEV); + if (DBGetContactSettingByte(NULL, YAMN_DBMODULE, YAMN_CLOSEDELETE, 0)) + DestroyWindow(hDlg); + + } + break; + } + } + break; + case WM_SIZE: + if (wParam==SIZE_RESTORED) + { + LONG x=LOWORD(lParam); //((LPRECT)lParam)->right-((LPRECT)lParam)->left; + LONG y=HIWORD(lParam); //((LPRECT)lParam)->bottom-((LPRECT)lParam)->top; + MoveWindow(GetDlgItem(hDlg,IDC_BTNDEL), 5 ,y-5-25,(x-20)/3,25,TRUE); //where to put DELETE button while resizing + MoveWindow(GetDlgItem(hDlg,IDC_BTNCHECKALL),10+ (x-20)/3,y-5-25,(x-20)/6,25,TRUE); //where to put CHECK ALL button while resizing + MoveWindow(GetDlgItem(hDlg,IDC_BTNAPP), 15+ (x-20)/3 + (x-20)/6,y-5-25,(x-20)/3,25,TRUE); //where to put RUN APP button while resizing + MoveWindow(GetDlgItem(hDlg,IDC_BTNOK), 20+2*(x-20)/3 + (x-20)/6 ,y-5-25,(x-20)/6,25,TRUE); //where to put OK button while resizing + MoveWindow(GetDlgItem(hDlg,IDC_LISTMAILS), 5 ,5 ,x-10 ,y-55,TRUE); //where to put list mail window while resizing + MoveWindow(GetDlgItem(hDlg,IDC_STSTATUS), 5 ,y-5-45 ,x-10 ,15,TRUE); //where to put account status text while resizing + } +// break; + return 0; + case WM_GETMINMAXINFO: + ((LPMINMAXINFO)lParam)->ptMinTrackSize.x=MAILBROWSER_MINXSIZE; + ((LPMINMAXINFO)lParam)->ptMinTrackSize.y=MAILBROWSER_MINYSIZE; + return 0; + case WM_TIMER: + { + NOTIFYICONDATA nid; + struct CMailWinUserInfo *mwui=(struct CMailWinUserInfo *)GetWindowLongPtr(hDlg,DWLP_USER); + + ZeroMemory(&nid,sizeof(nid)); + nid.cbSize=sizeof(NOTIFYICONDATA); + nid.hWnd=hDlg; + nid.uID=0; + nid.uFlags=NIF_ICON; + if (mwui->TrayIconState==0) + nid.hIcon=g_LoadIconEx(0); + else + nid.hIcon=g_LoadIconEx(2); + Shell_NotifyIcon(NIM_MODIFY,&nid); + mwui->TrayIconState=!mwui->TrayIconState; +// UpdateWindow(hDlg); + } + break; + case WM_NOTIFY: + switch(((LPNMHDR)lParam)->idFrom) + { + + case IDC_LISTMAILS: + { + + switch(((LPNMHDR)lParam)->code) + { + case NM_DBLCLK: + SendMessage(hDlg,WM_YAMN_SHOWSELECTED,0,0); + break; + case LVN_COLUMNCLICK: + HACCOUNT ActualAccount; + if (NULL!=(ActualAccount=GetWindowAccount(hDlg))) { + NM_LISTVIEW* pNMListView = (NM_LISTVIEW*)lParam; + if (WAIT_OBJECT_0==WaitToReadFcn(ActualAccount->AccountAccessSO)) + { + #ifdef DEBUG_SYNCHRO + DebugLog(SynchroFile,"MailBrowser:COLUMNCLICK:ActualAccountSO-read enter\n"); + #endif + switch((int)pNMListView->iSubItem) + { + case 0: + bFrom = !bFrom; + break; + case 1: + bSub = !bSub; + break; + case 2: + bSize = !bSize; + break; + case 3: + bDate = !bDate; + break; + default: + break; + } + ListView_SortItems(pNMListView->hdr.hwndFrom,ListViewCompareProc,pNMListView->iSubItem); + #ifdef DEBUG_SYNCHRO + DebugLog(SynchroFile,"MailBrowser:BTNAPP:ActualAccountSO-read done\n"); + #endif + ReadDoneFcn(ActualAccount->AccountAccessSO); + } } + break; + + case NM_CUSTOMDRAW: + { + HACCOUNT ActualAccount; + LPNMLVCUSTOMDRAW cd=(LPNMLVCUSTOMDRAW)lParam; + LONG_PTR PaintCode; + + if (NULL==(ActualAccount=GetWindowAccount(hDlg))) + break; + + switch(cd->nmcd.dwDrawStage) + { + case CDDS_PREPAINT: + PaintCode=CDRF_NOTIFYITEMDRAW; + break; + case CDDS_ITEMPREPAINT: + PaintCode=CDRF_NOTIFYSUBITEMDRAW; + break; + case CDDS_ITEMPREPAINT | CDDS_SUBITEM: + { +// COLORREF crText, crBkgnd; +// crText= RGB(128,128,255); + HYAMNMAIL ActualMail; + BOOL umma; + + { + struct CMailWinUserInfo *mwui; + mwui=(struct CMailWinUserInfo *)GetWindowLongPtr(hDlg,DWLP_USER); + umma= mwui->UpdateMailsMessagesAccess; + } + ActualMail=(HYAMNMAIL)cd->nmcd.lItemlParam; + if (!ActualMail) + ActualMail=(HYAMNMAIL)readItemLParam(cd->nmcd.hdr.hwndFrom,cd->nmcd.dwItemSpec); + #ifdef DEBUG_SYNCHRO + DebugLog(SynchroFile,"MailBrowser:DRAWITEM:ActualAccountMsgsSO-read wait\n"); + #endif + if (!umma) + if (WAIT_OBJECT_0!=WaitToReadFcn(ActualAccount->MessagesAccessSO)) + { + #ifdef DEBUG_SYNCHRO + DebugLog(SynchroFile,"MailBrowser:DRAWITEM:ActualAccountMsgsSO-read wait failed\n"); + #endif + return 0; + } + #ifdef DEBUG_SYNCHRO + DebugLog(SynchroFile,"MailBrowser:DRAWITEM:ActualAccountMsgsSO-read enter\n"); + #endif + switch(ActualMail->Flags & YAMN_MSG_SPAMMASK) + { + case YAMN_MSG_SPAML1: + case YAMN_MSG_SPAML2: + cd->clrText=RGB(150,150,150); + break; + case YAMN_MSG_SPAML3: + cd->clrText=RGB(200,200,200); + cd->clrTextBk=RGB(160,160,160); + break; + case 0: + if (cd->nmcd.dwItemSpec & 1) + cd->clrTextBk=RGB(230,230,230); + break; + default: + break; + } + if (ActualMail->Flags & YAMN_MSG_UNSEEN) + cd->clrTextBk=RGB(220,235,250); + PaintCode=CDRF_DODEFAULT; + + if (!umma) + { + #ifdef DEBUG_SYNCHRO + DebugLog(SynchroFile,"MailBrowser:DRAWITEM:ActualAccountMsgsSO-read done\n"); + #endif + ReadDoneFcn(ActualAccount->MessagesAccessSO); + } + + break; + } + } + SetWindowLongPtr(hDlg,DWLP_MSGRESULT,PaintCode); + return 1; + } + } + } + } + break; + case WM_CONTEXTMENU: + { + if ( GetWindowLongPtr(( HWND )wParam, GWLP_ID ) == IDC_LISTMAILS) { + //MessageBox(0,"LISTHEADERS","Debug",0); + HWND hList = GetDlgItem( hDlg, IDC_LISTMAILS ); + POINT pt = { (signed short)LOWORD( lParam ), (signed short)HIWORD( lParam ) }; + HTREEITEM hItem = 0; + if (pt.x==-1) pt.x = 0; + if (pt.y==-1) pt.y = 0; + if (int numRows = ListView_GetItemCount(hList)) { + HMENU hMenu = CreatePopupMenu(); + AppendMenu(hMenu, MF_STRING, (UINT_PTR)1, TranslateT("Copy Selected")); + AppendMenu(hMenu, MF_STRING, (UINT_PTR)2, TranslateT("Copy All")); + AppendMenu(hMenu, MF_SEPARATOR, 0, NULL); + AppendMenu(hMenu, MF_STRING, (UINT_PTR)0, TranslateT("Cancel")); + int nReturnCmd = TrackPopupMenu( hMenu, TPM_RETURNCMD, pt.x, pt.y, 0, hDlg, NULL ); + DestroyMenu( hMenu ); + if (nReturnCmd>0){ + int courRow=0; + size_t sizeNeeded = 0; + TCHAR from[128]={0}, subject[256]={0}, size[16]={0}, date[64]={0}; + for (courRow=0;courRow<numRows;courRow++) { + if ((nReturnCmd==1) && (ListView_GetItemState(hList, courRow, LVIS_SELECTED)==0)) continue; + ListView_GetItemText(hList, courRow, 0, from, SIZEOF(from)); + ListView_GetItemText(hList, courRow, 1, subject, SIZEOF(subject)); + ListView_GetItemText(hList, courRow, 2, size, SIZEOF(size)); + ListView_GetItemText(hList, courRow, 3, date, SIZEOF(date)); + sizeNeeded += 5+_tcslen(from)+_tcslen(subject)+_tcslen(size)+_tcslen(date); + } + if (sizeNeeded && OpenClipboard(hDlg)) { + EmptyClipboard(); + HGLOBAL hData = GlobalAlloc(GMEM_MOVEABLE,(sizeNeeded+1)*sizeof(TCHAR)); + TCHAR *buff = (TCHAR *)GlobalLock(hData); + int courPos = 0; + for (courRow=0; courRow < numRows; courRow++) { + if ((nReturnCmd==1) && (ListView_GetItemState(hList, courRow, LVIS_SELECTED)==0)) continue; + ListView_GetItemText(hList, courRow, 0, from, SIZEOF(from)); + ListView_GetItemText(hList, courRow, 1, subject, SIZEOF(subject)); + ListView_GetItemText(hList, courRow, 2, size, SIZEOF(size)); + ListView_GetItemText(hList, courRow, 3, date, SIZEOF(date)); + courPos += _stprintf(&buff[courPos], _T("%s\t%s\t%s\t%s\r\n"), from, subject, size, date); + } + GlobalUnlock(hData); + #if defined( _UNICODE ) + SetClipboardData(CF_UNICODETEXT,hData); + #else + SetClipboardData(CF_TEXT,hData); + #endif + CloseClipboard(); + } + } + } + } } + break; // just in case + default: + return 0; + } +// return DefWindowProc(hDlg,msg,wParam,lParam); + return 0; +} + +LRESULT CALLBACK ListViewSubclassProc(HWND hDlg, UINT msg, WPARAM wParam, LPARAM lParam) +{ + HWND hwndParent = GetParent(hDlg); + + switch(msg) { + case WM_GETDLGCODE : + { + LPMSG lpmsg; + if ( ( lpmsg = (LPMSG)lParam ) != NULL ) { + if ( lpmsg->message == WM_KEYDOWN + && lpmsg->wParam == VK_RETURN) + return DLGC_WANTALLKEYS; + } + break; + } + case WM_KEYDOWN: + { + + BOOL isCtrl = GetKeyState(VK_CONTROL) & 0x8000; + BOOL isShift = GetKeyState(VK_SHIFT) & 0x8000; + BOOL isAlt = GetKeyState(VK_MENU) & 0x8000; + + switch (wParam) + { + case 'A': // ctrl-a + if (!isAlt && !isShift && isCtrl) SendMessage(hwndParent,WM_COMMAND,IDC_BTNCHECKALL,0); + break; + case VK_RETURN: + case VK_SPACE: + if (!isAlt && !isShift && !isCtrl) SendMessage(hwndParent,WM_YAMN_SHOWSELECTED,0,0); + break; + case VK_DELETE: + SendMessage(hwndParent,WM_COMMAND,IDC_BTNDEL,0); + break; + } + + break; + + } + } + return CallWindowProc(OldListViewSubclassProc, hDlg, msg, wParam, lParam); +} + +DWORD WINAPI MailBrowser(LPVOID Param) +{ + MSG msg; + + HWND hMailBrowser; + BOOL WndFound=FALSE; + HACCOUNT ActualAccount; + struct MailBrowserWinParam MyParam; + + MyParam=*(struct MailBrowserWinParam *)Param; + ActualAccount=MyParam.account; + #ifdef DEBUG_SYNCHRO + DebugLog(SynchroFile,"MailBrowser:Incrementing \"using threads\" %x (account %x)\n",ActualAccount->UsingThreads,ActualAccount); + #endif + SCIncFcn(ActualAccount->UsingThreads); + +// we will not use params in stack anymore + SetEvent(MyParam.ThreadRunningEV); + + __try + { + #ifdef DEBUG_SYNCHRO + DebugLog(SynchroFile,"MailBrowser:ActualAccountSO-read wait\n"); + #endif + if (WAIT_OBJECT_0!=WaitToReadFcn(ActualAccount->AccountAccessSO)) + { + #ifdef DEBUG_SYNCHRO + DebugLog(SynchroFile,"MailBrowser:ActualAccountSO-read wait failed\n"); + #endif + return 0; + } + #ifdef DEBUG_SYNCHRO + DebugLog(SynchroFile,"MailBrowser:ActualAccountSO-read enter\n"); + #endif + if (!(ActualAccount->AbilityFlags & YAMN_ACC_BROWSE)) + { + MyParam.nflags=MyParam.nflags & ~YAMN_ACC_MSG; + MyParam.nnflags=MyParam.nnflags & ~YAMN_ACC_MSG; + } + if (!(ActualAccount->AbilityFlags & YAMN_ACC_POPUP)) + MyParam.nflags=MyParam.nflags & ~YAMN_ACC_POP; + #ifdef DEBUG_SYNCHRO + DebugLog(SynchroFile,"MailBrowser:ActualAccountSO-read done\n"); + #endif + ReadDoneFcn(ActualAccount->AccountAccessSO); + + if (NULL!=(hMailBrowser=WindowList_Find(YAMNVar.NewMailAccountWnd,ActualAccount))) + WndFound=TRUE; + if ((hMailBrowser==NULL) && ((MyParam.nflags & YAMN_ACC_MSG) || (MyParam.nflags & YAMN_ACC_ICO) || (MyParam.nnflags & YAMN_ACC_MSG))) + { + hMailBrowser=CreateDialogParamW(YAMNVar.hInst,MAKEINTRESOURCEW(IDD_DLGVIEWMESSAGES),NULL,(DLGPROC)DlgProcYAMNMailBrowser,(LPARAM)&MyParam); + SendMessageW(hMailBrowser,WM_SETICON,(WPARAM)ICON_BIG,(LPARAM)g_LoadIconEx(2,true)); + SendMessageW(hMailBrowser,WM_SETICON,(WPARAM)ICON_SMALL,(LPARAM)g_LoadIconEx(2)); + MoveWindow(hMailBrowser,PosX,PosY,SizeX,SizeY,TRUE); + } + + if (hMailBrowser!=NULL) + { + struct CChangeContent Params={MyParam.nflags,MyParam.nnflags}; //if this thread created window, just post message to update mails + + SendMessageW(hMailBrowser,WM_YAMN_CHANGECONTENT,(WPARAM)ActualAccount,(LPARAM)&Params); //we ensure this will do the thread who created the browser window + } + else + UpdateMails(NULL,ActualAccount,MyParam.nflags,MyParam.nnflags); //update mails without displaying or refreshing any window + + if ((hMailBrowser!=NULL) && !WndFound) //we process message loop only for thread that created window + { + while(GetMessage(&msg,NULL,0,0)) + { + if (!IsDialogMessage(hMailBrowser, &msg)) + { + TranslateMessage(&msg); + DispatchMessage(&msg); + } + } + } + + if ((!WndFound) && (ActualAccount->Plugin->Fcn!=NULL) && (ActualAccount->Plugin->Fcn->WriteAccountsFcnPtr!=NULL) && ActualAccount->AbleToWork) + ActualAccount->Plugin->Fcn->WriteAccountsFcnPtr(); + } + __finally + { + #ifdef DEBUG_SYNCHRO + DebugLog(SynchroFile,"MailBrowser:Decrementing \"using threads\" %x (account %x)\n",ActualAccount->UsingThreads,ActualAccount); + #endif + SCDecFcn(ActualAccount->UsingThreads); + } + return 1; +} + +INT_PTR RunMailBrowserSvc(WPARAM wParam,LPARAM lParam) +{ + DWORD tid; + //an event for successfull copy parameters to which point a pointer in stack for new thread + HANDLE ThreadRunningEV; + PYAMN_MAILBROWSERPARAM Param=(PYAMN_MAILBROWSERPARAM)wParam; + + if ((DWORD)lParam!=YAMN_MAILBROWSERVERSION) + return 0; + + if (NULL!=(ThreadRunningEV=CreateEvent(NULL,FALSE,FALSE,NULL))) + { + HANDLE NewThread; + + Param->ThreadRunningEV=ThreadRunningEV; + if (NULL!=(NewThread=CreateThread(NULL,0,MailBrowser,Param,0,&tid))) + { + WaitForSingleObject(ThreadRunningEV,INFINITE); + CloseHandle(NewThread); + } + CloseHandle(ThreadRunningEV); + return 1; + } + return 0; +} diff --git a/protocols/YAMN/debug.cpp b/protocols/YAMN/debug.cpp new file mode 100644 index 0000000000..9b9793a965 --- /dev/null +++ b/protocols/YAMN/debug.cpp @@ -0,0 +1,139 @@ +/* + * YAMN plugin main file + * Miranda homepage: http://miranda-icq.sourceforge.net/ + * + * Debug functions used in DEBUG release (you need to global #define DEBUG to get debug version) + * + * (c) majvan 2002-2004 + */ + +#include "yamn.h" +#include "debug.h" +#ifdef YAMN_DEBUG +#include "version.h" + +#if defined (WIN9X) + #define YAMN_VER "YAMN " YAMN_VERSION_C " (Win9x)" +#elif defined(WIN2IN1) + #define YAMN_VER "YAMN " YAMN_VERSION_C " (2in1)" +#else + #define YAMN_VER "YAMN " YAMN_VERSION_C " (WinNT)" +#endif + +//-------------------------------------------------------------------------------------------------- +//-------------------------------------------------------------------------------------------------- + +TCHAR DebugUserDirectory[MAX_PATH] = _T("."); +LPCRITICAL_SECTION FileAccessCS; + +#ifdef DEBUG_SYNCHRO +TCHAR DebugSynchroFileName2[]=_T("%s\\yamn-debug.synchro.log"); +HANDLE SynchroFile; +#endif + +#ifdef DEBUG_COMM +TCHAR DebugCommFileName2[]=_T("%s\\yamn-debug.comm.log"); +HANDLE CommFile; +#endif + +#ifdef DEBUG_DECODE +TCHAR DebugDecodeFileName2[]=_T("%s\\yamn-debug.decode.log"); +HANDLE DecodeFile; +#endif + +//-------------------------------------------------------------------------------------------------- +//-------------------------------------------------------------------------------------------------- + +void InitDebug() +{ +#if defined (DEBUG_SYNCHRO) || defined (DEBUG_COMM) || defined (DEBUG_DECODE) + TCHAR DebugFileName[MAX_PATH]; +#endif + if (FileAccessCS==NULL) + { + FileAccessCS=new CRITICAL_SECTION; + InitializeCriticalSection(FileAccessCS); + } + +#ifdef DEBUG_SYNCHRO + _stprintf(DebugFileName,DebugSynchroFileName2,DebugUserDirectory); + + SynchroFile=CreateFile(DebugFileName,GENERIC_WRITE,FILE_SHARE_WRITE|FILE_SHARE_READ,NULL,CREATE_ALWAYS,0,NULL); + DebugLog(SynchroFile,"Synchro debug file created by %s\n",YAMN_VER); +#endif + +#ifdef DEBUG_COMM + _stprintf(DebugFileName,DebugCommFileName2,DebugUserDirectory); + + CommFile=CreateFile(DebugFileName,GENERIC_WRITE,FILE_SHARE_WRITE|FILE_SHARE_READ,NULL,CREATE_ALWAYS,0,NULL); + DebugLog(CommFile,"Communication debug file created by %s\n",YAMN_VER); +#endif + +#ifdef DEBUG_DECODE + _stprintf(DebugFileName,DebugDecodeFileName2,DebugUserDirectory); + + DecodeFile=CreateFile(DebugFileName,GENERIC_WRITE,FILE_SHARE_WRITE|FILE_SHARE_READ,NULL,CREATE_ALWAYS,0,NULL); + DebugLog(DecodeFile,"Decoding kernel debug file created by %s\n",YAMN_VER); +#endif +} + +void UnInitDebug() +{ +#ifdef DEBUG_SYNCHRO + DebugLog(SynchroFile,"File is being closed normally."); + CloseHandle(SynchroFile); +#endif +#ifdef DEBUG_COMM + DebugLog(CommFile,"File is being closed normally."); + CloseHandle(CommFile); +#endif +#ifdef DEBUG_DECODE + DebugLog(DecodeFile,"File is being closed normally."); + CloseHandle(DecodeFile); +#endif +} + + +void DebugLog(HANDLE File,const char *fmt,...) +{ + char *str; + char tids[32]; + va_list vararg; + int strsize; + DWORD Written; + + va_start(vararg,fmt); + str=(char *)malloc(strsize=65536); + mir_snprintf(tids, SIZEOF(tids), "[%x]",GetCurrentThreadId()); + while(_vsnprintf(str,strsize,fmt,vararg)==-1) + str=(char *)realloc(str,strsize+=65536); + va_end(vararg); + EnterCriticalSection(FileAccessCS); + WriteFile(File,tids,(DWORD)strlen(tids),&Written,NULL); + WriteFile(File,str,(DWORD)strlen(str),&Written,NULL); + LeaveCriticalSection(FileAccessCS); + free(str); +} + +void DebugLogW(HANDLE File,const WCHAR *fmt,...) +{ + WCHAR *str; + char tids[32]; + va_list vararg; + int strsize; + DWORD Written; + + va_start(vararg,fmt); + str=(WCHAR *)malloc((strsize=65536)*sizeof(WCHAR)); + mir_snprintf(tids, SIZEOF(tids), "[%x]",GetCurrentThreadId()); + while(_vsnwprintf(str,strsize,fmt,vararg)==-1) + str=(WCHAR *)realloc(str,(strsize+=65536)*sizeof(WCHAR)); + va_end(vararg); + EnterCriticalSection(FileAccessCS); + WriteFile(File,tids,(DWORD)strlen(tids),&Written,NULL); + WriteFile(File,str,(DWORD)wcslen(str)*sizeof(WCHAR),&Written,NULL); + LeaveCriticalSection(FileAccessCS); + free(str); +} + +#endif //ifdef DEBUG \ No newline at end of file diff --git a/protocols/YAMN/debug.h b/protocols/YAMN/debug.h new file mode 100644 index 0000000000..d2b6764406 --- /dev/null +++ b/protocols/YAMN/debug.h @@ -0,0 +1,71 @@ +#ifndef __DEBUG_H +#define __DEBUG_H + +// #define YAMN_DEBUG + +//#define YAMN_VER_BETA +//#define YAMN_VER_BETA_CRASHONLY + +#ifdef YAMN_DEBUG + +//#pragma comment(lib, "th32.lib") + +#if !defined(_WIN32_WINNT) +#define _WIN32_WINNT 0x0501 // WinXP only +#endif +#define VC_EXTRALEAN +#include <windows.h> +#include <tlhelp32.h> +#include <stdio.h> +#include <shlwapi.h> + +//#define DEBUG_SYNCHRO //debug synchro to a file +//#define DEBUG_COMM //debug communiation to a file +//#define DEBUG_DECODE //debug header decoding to a file +//#define DEBUG_DECODECODEPAGE //add info about codepage used in conversion +//#define DEBUG_DECODEBASE64 //add info about base64 result +//#define DEBUG_DECODEQUOTED //add info about quoted printable result +//#define DEBUG_FILEREAD //debug file reading to message boxes +//#define DEBUG_FILEREADMESSAGES //debug file reading messages to message boxes + +void DebugLog(HANDLE,const char *fmt,...); +void DebugLogW(HANDLE File,const WCHAR *fmt,...); + +#ifdef DEBUG_SYNCHRO +// Used for synchronization debug +extern HANDLE SynchroFile; +#endif + +#ifdef DEBUG_COMM +// Used for communication debug +extern HANDLE CommFile; +#endif + +#ifdef DEBUG_DECODE +// Used for decoding debug +extern HANDLE DecodeFile; +#endif + +#if defined(DEBUG_FILEREAD) || defined(DEBUG_FILEREADMESSAGES) +DWORD ReadStringFromMemory(char **Parser,char *End,char **StoreTo,char *DebugString); + #ifndef UNICODE +#define ReadStringFromMemoryW ReadStringFromMemory + #else +DWORD ReadStringFromMemoryW(char **Parser,TCHAR *End,char **StoreTo,TCHAR *DebugString); + #endif +#else +DWORD ReadStringFromMemory(char **Parser,char *End,char **StoreTo); + #ifndef UNICODE +#define ReadStringFromMemoryW ReadStringFromMemory + #else +DWORD ReadStringFromMemoryW(WCHAR **Parser,WCHAR *End,WCHAR **StoreTo); + #endif +#endif + +//#ifdef DEBUG_ACCOUNTS +//int GetAccounts(); +//void WriteAccounts(); +//#endif + +#endif //YAMN_DEBUG +#endif //_DEBUG_H diff --git a/protocols/YAMN/docs/InstallScript.xml b/protocols/YAMN/docs/InstallScript.xml new file mode 100644 index 0000000000..33d8ac9dfd --- /dev/null +++ b/protocols/YAMN/docs/InstallScript.xml @@ -0,0 +1,49 @@ +<?xml version="1.0" encoding="ISO-8859-1"?> +<installscript> + <info> + <name>Yet Another Mail Notifier</name> + <author>majvan</author> + <version>0.2.4.7</version> + <type>Plugin</type> + </info> + + <packageinfo> + <title>Plugin + YAMN.dll + + + + + Documentation + YAMN-Readme.txt + YAMN-License.txt + + + + + + Developers Information + YAMN-Readme.developers.txt + + + + + + Simple filter plugin + YAMN\simple.dll + YAMN\simple-readme.txt + + + + + Base filter plugin + YAMN\base.dll + YAMN\base-readme.txt + + + + YAMN-Readme.txt + + + + diff --git a/protocols/YAMN/docs/YAMN-License.txt b/protocols/YAMN/docs/YAMN-License.txt new file mode 100644 index 0000000000..7f1161073d --- /dev/null +++ b/protocols/YAMN/docs/YAMN-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. + + + Copyright (C) 19yy + + 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) 19yy 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. + + , 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/YAMN/docs/YAMN-Readme.developers.txt b/protocols/YAMN/docs/YAMN-Readme.developers.txt new file mode 100644 index 0000000000..fdb338707c --- /dev/null +++ b/protocols/YAMN/docs/YAMN-Readme.developers.txt @@ -0,0 +1,205 @@ +================================================================================== += YAMN plugin for Miranda (short readme for developers) = +================================================================================== +Hello developer! :) +I hope YAMN will give you what you find, but you can also improve YAMN. + +This readme gives you some info about YAMN. Please read it first before you are +going to look at YAMN sources. + +YAMN provides two types of plugins now: protocol plugins and filter plugins. + + +1. What do you need to make your protocol plugin cooperating with YAMN + ------------------------------------------------------------------- + + If you want to cooperate with YAMN, you have to do some things. YAMN offers you some services, + so your work is easier, but YAMN needs some things to be done for proper work. These limits go + according thread synchronization and memory mutual exclusion. + + YAMN offers you two types of services. Exported functions and Miranda services. Miranda + services are described in header files, exported functions are described in cpp files. All + exported functions in YAMN have the suffix Fcn, so you can easy get if the function is + exported. Using exported functions is more difficult than using miranda services, but after + solving some definitions, the work with exported functions is more clear and easier. Miranda + services from YAMN are for miscellaneus functions. The fact Miranda service uses only two + parameters and therefore is sometimes very unsuitable leads us to make exported functions. + Exported functions are divided in several parts: synchronizing functions (used for thread + and account synchronization) and MIME functions (used to work with MIME + messages). + + Miranda services are used through Miranda CallService function. YAMN exported functions are avialable + when registering plugin. Then YAMN gives you its table of exported functions. + + How to write write your protocol plugin for YAMN? The best way for you is to look at + internal POP3 protocol, where all info about this is written. At start, you need to register + plugin (it is done in two steps- registering and inserting to YAMN), then get pointers to + YAMN's exported functions (using Miranda's service MS_YAMN_GETFCN) you will need in your + protocol plugin. These are the first steps you should do when implementing some plugin to + YAMN. Next, you should know how YAMN is stuctured. Structures of YAMN are described in + chapter 2. And, at the end, you should know something about account synchronizing and some + limitations you have to achieve, if you want your plugin works well. + + +2. YAMN structures and memory organization + --------------------------------------- + + YAMN uses its own structures, that can change in the future. The problem with change is, + that there can occur some incomapatibilities between YAMN and plugins written for old YAMN + versions. To avoid problems, YAMN defines versions for services or exported/imported + functions, where strucutre version information is passed to/from plugins. + + +2.1. Structures of protcol plugin queue + + (PYAMN_PROTOPLUGINQUEUE)FirstPlugin---> =(HYAMNPROTOPLUGIN)= ---> =(HYAMNPROTOPLUGIN)= ---> =(HYAMNPROTOPLUGIN)= ---> NULL + | | | | | | | | | + | . | | | . | | | . | | + | . | | | . | | | . | | + | . | | | . | | | . | | + -------------------- | |------------------| | |------------------| | + | Next |--| | Next |--| | Next |--| + ==================== ==================== ==================== + + This structure is not needed if you only create protocol plugin for YAMN. YAMN plugin does + not see and it is not important for it how YAMN works with plugins and how it stores plugins + data. For plugin is important only handle for its own plugin, returned from + MS_YAMN_REGISTERPLUGIN service. + + +2.2. Structure of accounts + + Every account in YAMN belongs to exact plugin and its members are allocated with + MS_YAMN_CREATEPLUGINACCOUNT service. This service cooperates with your function, which is + defined in your function import table. In your function (if you have defined it), you should + create the whole account. It is because YAMN cannot know which members in structure did you + add. So you create the whole derived structure. If your fcn is not implemented (NULL in + import table), YAMN creates standard account structure. + + This structure contains information (members) related to YAMN, to plugin and members shared + between both (plugin and YAMN). Therefore it is needed to synchronize access to members (see + Ch. 3). Standard YAMN account is defined in m_account.h header file. There's also + description for every member how it is synchronised. YAMN creates two synchronizing objects + (SO) to synchronise access to members. In m_synchro.h file, there are definitions for easy + work with these SO. + + Accounts are queued in plugin: + + =(HYAMNPLUGIN)= ---> ===(HACCOUNT)=== ---> ===(HACCOUNT)=== ---> ===(HACCOUNT)=== ---> NULL + | | | | | | | | | | | | + | | | | | | | | | | | | + | . | | | | | | | | | | | + | . | | | | | | | | | | | + | . | | | | | | | | | | | + | | | |--------------| | |--------------| | |--------------| | + | (HACCOUNT) | | | Next |--| | Next |--| | Next |--| + | FirstAccount|--| ================ ================ ================ + |-------------| + | | + =============== + + Every account has its own back pointer to (HYAMNPLUGIN) in Plugin member, so you can easy + look at first account, when you have any other account (see m_account.h). + + +2.3. Structure of mails + + Account has a pointer to mails. Account's pointer to mails is pointer to first mail in fact + and mails are queued too: + + ==(HACCOUNT)== ---> ==(HYAMNMAIL)== ---> ==(HYAMNMAIL)== ---> ==(HYAMNMAIL)== ---> NULL + | | | | | | | | | | | | + | . | | | | | | | | | | | + | . | | | | | | | | | | | + | . | | | | | | | | | | | + | | | |-------------| | |-------------| | |-------------| | + | (HYAMNMAIL)| | | Next |--| | Next |--| | Next |--| + | Mails|--| =============== =============== =============== + |------------| + | | + ============== + + Standard MIME mail is defined in mails/m_mails.h file. + + Plugin can work with accounts in its own way, but note it is needed to synchronize access. + For better work, YAMN offers you some services and exports functions. Description of + exported functions is in its declartation; for accounts functions see account.cpp, for mails + functions see mails/mails.cpp and so on. + + +3. YAMN thread synchronization + --------------------------- + + Because YAMN is multithreaded, more than one thread can access to any member of account + structure. Therefore access to these members should be synchronised. YAMN offers two types + of synchronization objects (SO): SCOUNTER (Synchronized Counter) and SWMRG (Single + Writer/Multiple Readers Guard). To use these objects, you can use exported functions: + + SWMRG: WaitToWriteSO, WaitToWriteSOEx, WriteDoneSO, WaitToReadSO, WaitToReadSOEx, ReadDoneSO + SCOUNTER: SCGetNumber, SCInc, SCDec + + To see description for these functions, see m_synchro.h header file and synchro.cpp. Note + that in HACCOUNT structure, there are 3 synchronizing members, which you have to use if you + want to access to any member of account structure. All access techniques (writing to members + and read from members) are used in POP3 protocol plugin. Now, it is important what we have + to do when we want to make our plugin be synchronized with YAMN (in POP3 protocol it is + described too). + + 1. We have to use ThreadRunningEV event when YAMN calls our checking/deleting function. This + parameter is to stop YAMN called thread until we do not have copied datas from stack. After + that, we SetEvent(ThreadRunningEvent) to unblock YAMN to continue in its work. + + 2. We have to use UsingThreads account's member. This is only for YAMN account deleting + prevention. We use this counter to set number of threads using account. If no thread is just + using account, account is signaled, that it can be deleted (and is deleted when needed). + This leads us to do some things: We use SCInc(UsingThreads) as the first thing we can do. We + cannot omit, that called thread finished before we call this function. UsingThreads should + have "continuous" value greater than zero when using account. E.g. if YAMN creates thread + for plugin that checks account for new mail, YAMN waits until we set ThreadRunningEV (see + point 1). After setting this event to signal, that YAMN can continue in its work, we + increase SCInc(UsingThreads), so we ensure that another thread uses account before YAMN + thread, that uses this account ends. And SCDec(UsingThreads) should be the last thing we do + in our thread. If we run another thread in our thread, we should wait until it does not + SCInc(UsingThreads) and after that we should continue (just like YAMN creates and calls our + thread). + + 3. If we use account's SWMRG (AccountAccessSO, MessagesAccessSO), we should test what our + function returned. Use the same methods as POP3 protocol does while testing and accessing + critical section. Note that we cannot use WaitToWriteSO(MyAccount->AccountAccessSO), but in + easy way we can WaitToWrite(AccountAccess) and for mails + WaitToWriteSO(MyAccount->MessagesAccessSO) use MsgsWaitToWrite(AccountAccess) and so on. See + export.h file for these definitions. + + 4. Deleting account is quite easy, but in YAMN, it is very problematic operation. If you use + MS_YAMN_DELETEACCOUNT service, it is the best way to avoid any problem. These problems raise + from the facts desribed in the point 2. + + 5. You should use ctritical sections only for short time not to block other threads. You can + imagine that users can't browse through mails, because account is blocked by your thread... + + All needed infos in POP3 internal protocol plugin (see proto/pop3/pop3comm.cpp), are + described. + + +4. What do you need to make your filter plugin cooperating with YAMN + ----------------------------------------------------------------- + + Filter plugins are very easy to write in its own way, it much more easier than protocol + plugin. But some things are common: you have to register your plugin and insert to YAMN + (these are 2 steps, see sources of some filter plugin), You have to import to YAMN your + filter function. Filter function can do anything with mails, but the most important is, that + it can set Flags member of mail (see mails/m_mails.h file) to one of YAMN_MSG_SPAMLx. + Note Mail is in write-access, so your plugin can do anything with mail and avoid the + synchronization problem. + + Now YAMN recognizes 4 spam levels: + 1. Notifies about this mail, but shows it in mailbrowser with other color than normally + 2. Does not notify about this mail, shows it in mailbrowser with other color than normally + 3. Deletes mail from server (depends on protocol), does not notify and shows "this spam was + deleted" + 4. Deletes mail from server (depends on protocol), does not notify, does not show in + mailbrowser + + Your plugin can set data for mail in the TranslatedHeader structure, inserting it to the + queue. This information is stored, so it is reloaded after protocol read mails from book + file. diff --git a/protocols/YAMN/docs/YAMN-Readme.txt b/protocols/YAMN/docs/YAMN-Readme.txt new file mode 100644 index 0000000000..901ad22f73 --- /dev/null +++ b/protocols/YAMN/docs/YAMN-Readme.txt @@ -0,0 +1,79 @@ +========================================================= += YAMN plugin for Miranda readme = +========================================================= +Yet Another Mail Notifier +Checks pop3 accounts for new mail + +Advantages: +- quite small +- structured in two parts: notifier and protocols +- unlimited number of accounts +- international support in Unicode +- open-source (GNU-GPL) +POP3: +- many switches for each account +- support for MIME standard +- support for Base64 and Quoted-Printable +- 100% detection of new mail based on unique message ID +- multithreaded checking (also with hotkey) +- deleting mail from server +- connecting through Miranda proxy +- secure password authentification +- SSL support through OpenSSL + +WIN9X SUPPORT +------------- +Win9x users, use unicows.dll library, download it at: +http://libunicows.sf.net (whole package) +or just visit http://www.majvan.host.sk/Projekty/YAMN +and download zip-ed unicows.dll +All you need is to copy unicows.dll to Windows system32 +directory (or to Miranda home directory). Use Win9x +version of YAMN, not WinNT version. + +SSL SUPPORT +----------- +If you want to use SSL features, you have to download +OpenSSL libraries on YAMN homepage +http://www.majvan.host.sk/Projekty/YAMN +or the latest (stable) version with installer on +http://www.slproweb.com/products/Win32OpenSSL.html +Copy *.dll files to Windows system32 directory (or to +Miranda home directory). + +LATEST STABLE +------------- +Version of YAMN has following structure: w.x.y.z +z- only some bug fixed or some changes +y- some new feature added +x- big feature added +w- if this changes, YAMN becomes better than Outlook ;-) +Latest stable plugin is always present to download from YAMN +homepage. + +BETA +---- +* YAMN-beta version is intended only for testing purposes. +* Author waits for stability reports. Sometimes author waits not +only for crash reports, but also for success reports (you are +informed by message box on startup, if success reports are also +needed). This is because he has no resources for testing. +* Please do not send reports if newer beta version is available. +* Please do not send reports without describing problem detailed. +* Beta version produces debug files (yamn-debug.*.log) located +in Miranda home directory (like every YAMN debug release). These +files are usefull for author to locate the bug (although not +100%). After Miranda restart, log files are rewritten. Log files +can become very large (more than 10MB). Sometimes they can be +cut at the end (contact author). +IMPORTANT FOR BETA: yamn-debug.comm.log file contains your plain +password. You should rewrite it. +Thank you for comprehension. + +========================================================= + Do you want some FAQ? Visit HOMEPAGE: + http://www.majvan.host.sk/Projekty/YAMN + Still don't know answer? Write question to guestbook. + + majvan +========================================================= diff --git a/protocols/YAMN/docs/language.pop3.txt b/protocols/YAMN/docs/language.pop3.txt new file mode 100644 index 0000000000..03fb78ec79 --- /dev/null +++ b/protocols/YAMN/docs/language.pop3.txt @@ -0,0 +1,118 @@ +; +; YAMN-POP3 0.2.4.7 translation file +; +;-------------------------------- +; NEW in 0.2.4.7 +;-------------------------------- + +;-------------------------------- +; CHANGED in 0.2.4.7 +;-------------------------------- + +;-------------------------------- +; OLD in 0.2.4.7 +;-------------------------------- +; +; Main +; +[Found new version of account book, not compatible with this version of YAMN.] +[Error reading account file. Account file corrupted.] +[Memory allocation error while data reading] +[Reading file error. File already in use?] +[Error while copying data to disk occured. File in use?] +[YAMN (internal POP3) read error] +[POP3 plugin- write file error] +[Error %d-%d-%d-%d:] +[Memory allocation error.] +[Account is about to be stopped.] +[Cannot connect to POP3 server.] +[Cannot allocate memory for received data.] +[Cannot login to POP3 server.] +[Bad user or password.] +[Server does not support APOP authorization.] +[Error while executing POP3 command.] +[Cannot connect to server with NetLib.] +[Cannot send data.] +[Cannot receive data.] +[Cannot allocate memory for received data.] +[OpenSSL not loaded.] +[Windows socket 2.0 init failed.] +[DNS lookup error.] +[Error while creating base socket.] +[Error connecting to server with socket.] +[Error while creating SSL structure.] +[Error connecting socket with SSL.] +[Server rejected connection with SSL.] +[Cannot write SSL data.] +[Cannot read SSL data.] +[Cannot allocate memory for received data.] + +; +; Options +; +[Please wait while account is in use.] +[Please wait while no account is in use.] +[Time left to next check [s]: %d] +[Select executable used for notification] +[Input error] +[This is not a valid number value] +[At least one mail notification event must be checked] +[Please select application to run] +[Delete] +[Check this account] +[Server:] +[Port:] +[User:] +[Password:] +[APOP auth] +[Check interval [min]:] +[Sound notification] +[Message notification] +[Tray icon notification] +[Application execution:] +[Persistant message] +[Sound notification if failed] +[Message notification if failed] +[Tray icon notification if failed] +[Default codepage:] +[Check while:] +;[Offline] +;[Online] +;[Away] +;[N/A] +;[Occupied] +;[DND] +;[Free for chat] +;[Invisible] +;[On the phone] +;[Out to lunch] +[Startup check] +[Default] +[Reset counter] +[Account Test] +[Account Test (failed)] +[Account Test] +[You have N new mails] +[Connection failed message] +[Popup notification] +[Popup if no mail] +[Single popup] +[Multi popup] +[Popup notification if failed] +[Check from menu] +[New mail notifications] +[No new mail notifications] +[Connection failure notifications] +[Connecting to server] +[Reading new mails (%d%% done)] +[Disconnected] +[Entering POP3 account] +[Searching for new mail] +[Deleting requested mails] +[Deleting spam] +[Delete account confirmation] +[Do you really want to delete this account?] + +;-------------------------------- +; REMOVED in 0.2.4.7 +;-------------------------------- \ No newline at end of file diff --git a/protocols/YAMN/docs/language.txt b/protocols/YAMN/docs/language.txt new file mode 100644 index 0000000000..72d1fcda8b --- /dev/null +++ b/protocols/YAMN/docs/language.txt @@ -0,0 +1,75 @@ +; +; YAMN 0.2.4.7 translation file +; +;-------------------------------- +; NEW in 0.2.4.7 +;-------------------------------- + +;-------------------------------- +; CHANGED in 0.2.4.7 +;-------------------------------- + +;-------------------------------- +; OLD in 0.2.4.7 +;-------------------------------- +; +; Main +; +[YAMN: new mail] +[YAMN: connect failed] +[No new mail, %d spam(s)] +[No new mail] +[YAMN uninstalling] +[Do you also want to remove native YAMN plugins settings?] + +; +; Menu +; +[Check &mail (YAMN)] +[Check mail] ;for TopToolBar plugin + +; +; Options +; +[Hotkey for mail check:] +[TopToolBar button "Check mail"] +[Installed plugins] +[Version:] +[Description:] +[Copyright:] +[Contact:] +[WWW:] + +; +; Mail browser +; +[%s - %d new mails, %d total] +[ - new mail(s)] +[From] +[Subject] +[Size] +[Run application] +[Delete selected] +[Delete confirmation] +[Do you really want to delete %d selected mails?] + +; +; Bad connection dialog +; +[ - connection error] +[Cannot allocate memory for received data] +[Bad user name or error while logging] +[Bad user or password or error while logging] +[Cannot get number of messages] +[Cannot resolve message signatures] +[Cannot get sizes of messages] +[Cannot find server] +[Cannot connect to server] +[System error occured] +[Cannot send data] +[Cannot receive data] +[Unknown error] + +;-------------------------------- +; REMOVED in 0.2.4.7 +;-------------------------------- \ No newline at end of file diff --git a/protocols/YAMN/filter/Base/AggressiveOptimize.h b/protocols/YAMN/filter/Base/AggressiveOptimize.h new file mode 100644 index 0000000000..1bf0e19c2c --- /dev/null +++ b/protocols/YAMN/filter/Base/AggressiveOptimize.h @@ -0,0 +1,168 @@ + +////////////////////////////// +// Version 1.40 +// October 22nd, 2002 - .NET (VC7, _MSC_VER=1300) support! +// Version 1.30 +// Nov 24th, 2000 +// Version 1.20 +// Jun 9th, 2000 +// Version 1.10 +// Jan 23rd, 2000 +// Version 1.00 +// May 20th, 1999 +// Todd C. Wilson, Fresh Ground Software +// (todd@nopcode.com) +// This header file will kick in settings for Visual C++ 5 and 6 that will (usually) +// result in smaller exe's. +// The "trick" is to tell the compiler to not pad out the function calls; this is done +// by not using the /O1 or /O2 option - if you do, you implicitly use /Gy, which pads +// out each and every function call. In one single 500k dll, I managed to cut out 120k +// by this alone! +// The other two "tricks" are telling the Linker to merge all data-type segments together +// in the exe file. The relocation, read-only (constants) data, and code section (.text) +// sections can almost always be merged. Each section merged can save 4k in exe space, +// since each section is padded out to 4k chunks. This is very noticeable with smaller +// exes, since you could have only 700 bytes of data, 300 bytes of code, 94 bytes of +// strings - padded out, this could be 12k of runtime, for 1094 bytes of stuff! For larger +// programs, this is less overall, but can save at least 4k. +// Note that if you're using MFC static or some other 3rd party libs, you may get poor +// results with merging the readonly (.rdata) section - the exe may grow larger. +// To use this feature, define _MERGE_DATA_ in your project or before this header is used. +// With Visual C++ 5, the program uses a file alignment of 512 bytes, which results +// in a small exe. Under VC6, the program instead uses 4k, which is the same as the +// section size. The reason (from what I understand) is that 4k is the chunk size of +// the virtual memory manager, and that WinAlign (an end-user tuning tool for Win98) +// will re-align the programs on this boundary. The problem with this is that all of +// Microsoft's system exes and dlls are *NOT* tuned like this, and using 4k causes serious +// exe bloat. This is very noticeable for smaller programs. +// The "trick" for this is to use the undocumented FILEALIGN linker parm to change the +// padding from 4k to 1/2k, which results in a much smaller exe - anywhere from 20%-75% +// depending on the size. Note that this is the same as using /OPT:NOWIN98, which *is* +// a previously documented switch, but was left out of the docs for some reason in VC6 and +// all of the current MSDN's - see KB:Q235956 for more information. +// Microsoft does say that using the 4k alignment will "speed up process loading", +// but I've been unable to notice a difference, even on my P180, with a very large (4meg) exe. +// Please note, however, that this will probably not change the size of the COMPRESSED +// file (either in a .zip file or in an install archive), since this 4k is all zeroes and +// gets compressed away. +// Also, the /ALIGN:4096 switch will "magically" do the same thing, even though this is the +// default setting for this switch. Apparently this sets the same values as the above two +// switches do. We do not use this in this header, since it smacks of a bug and not a feature. +// Thanks to Michael Geary for some additional tips! +// +// Notes about using this header in .NET +// First off, VC7 does not allow a lot of the linker command options in pragma's. There is no +// honest or good reason why Microsoft decided to make this change, it just doesn't. +// So that is why there are a lot of <1300 #if's in the header. +// If you want to take full advantage of the VC7 linker options, you will need to do it on a +// PER PROJECT BASIS; you can no longer use a global header file like this to make it better. +// Items I strongly suggest putting in all your VC7 project linker options command line settings: +// /ignore:4078 /RELEASE +// Compiler options: +// /GL (Whole Program Optimization) +// If you're making an .EXE and not a .DLL, consider adding in: +// /GA (Optimize for Windows Application) +// Some items to consider using in your VC7 projects (not VC6): +// Link-time Code Generation - whole code optimization. Put this in your exe/dll project link settings. +// /LTCG:NOSTATUS +// The classic no-padding and no-bloat compiler C/C++ switch: +// /opt:nowin98 +// +// (C++ command line options: /GL /opt:nowin98 and /GA for .exe files) +// (Link command line options: /ignore:4078 /RELEASE /LTCG:NOSTATUS) +// +// Now, notes on using these options in VC7 vs VC6. +// VC6 consistently, for me, produces smaller code from C++ the exact same sources, +// with or without this header. On average, VC6 produces 5% smaller binaries compared +// to VC7 compiling the exact same project, *without* this header. With this header, VC6 +// will make a 13k file, while VC7 will make a 64k one. VC7 is just bloaty, pure and +// simple - all that managed/unmanaged C++ runtimes, and the CLR stuff must be getting +// in the way of code generation. However, template support is better, so there. +// Both VC6 and VC7 show the same end kind of end result savings - larger binary output +// will shave about 2% off, where as smaller projects (support DLL's, cpl's, +// activex controls, ATL libs, etc) get the best result, since the padding is usually +// more than the actual usable code. But again, VC7 does not compile down as small as VC6. +// +// The argument can be made that doing this is a waste of time, since the "zero bytes" +// will be compressed out in a zip file or install archive. Not really - it doesn't matter +// if the data is a string of zeroes or ones or 85858585 - it will still take room (20 bytes +// in a zip file, 29 bytes if only *4* of them 4k bytes are not the same) and time to +// compress that data and decompress it. Also, 20k of zeros is NOT 20k on disk - it's the +// size of the cluster slop- for Fat32 systems, 20k can be 32k, NTFS could make it 24k if you're +// just 1 byte over (round up). Most end users do not have the dual P4 Xeon systems with +// two gigs of RDram and a Raid 0+1 of Western Digital 120meg Special Editions that all +// worthy developers have (all six of us), so they will need any space and LOADING TIME +// savings they will need; taking an extra 32k or more out of your end user's 64megs of +// ram on Windows 98 is Not a Good Thing. +// +// Now, as a ADDED BONUS at NO EXTRA COST TO YOU! Under VC6, using the /merge:.text=.data +// pragma will cause the output file to be un-disassembleable! (is that a word?) At least, +// with the normal tools - WinDisam, DumpBin, and the like will not work. Try it - use the +// header, compile release, and then use DUMPBIN /DISASM filename.exe - no code! +// Thanks to Gzim Pani for discovering this gem - for a full writeup on +// this issue and the ramifactions of it, visit www.nopcode.com for the Aggressive Optimize +// article. + +#ifndef _AGGRESSIVEOPTIMIZE_H_ +#define _AGGRESSIVEOPTIMIZE_H_ + +#pragma warning(disable:4711) + +#ifdef NDEBUG +// /Og (global optimizations), /Os (favor small code), /Oy (no frame pointers) +#pragma optimize("gsy",on) + +#if (_MSC_VER<1300) + #pragma comment(linker,"/RELEASE") +#endif + +/* +// Note that merging the .rdata section will result in LARGER exe's if you using +// MFC (esp. static link). If this is desirable, define _MERGE_RDATA_ in your project. +#ifdef _MERGE_RDATA_ +#pragma comment(linker,"/merge:.rdata=.data") +#endif // _MERGE_RDATA_ + +#pragma comment(linker,"/merge:.text=.data") +#if (_MSC_VER<1300) + // In VC7, this causes problems with the relocation and data tables, so best to not merge them + #pragma comment(linker,"/merge:.reloc=.data") +#endif +*/ + +// Merging sections with different attributes causes a linker warning, so +// turn off the warning. From Michael Geary. Undocumented, as usual! +#if (_MSC_VER<1300) + // In VC7, you will need to put this in your project settings + #pragma comment(linker,"/ignore:4078") +#endif + +// With Visual C++ 5, you already get the 512-byte alignment, so you will only need +// it for VC6, and maybe later. +#if _MSC_VER >= 1000 + +// Option #1: use /filealign +// Totally undocumented! And if you set it lower than 512 bytes, the program crashes. +// Either leave at 0x200 or 0x1000 +//#pragma comment(linker,"/FILEALIGN:0x200") + +// Option #2: use /opt:nowin98 +// See KB:Q235956 or the READMEVC.htm in your VC directory for info on this one. +// This is our currently preferred option, since it is fully documented and unlikely +// to break in service packs and updates. +#if (_MSC_VER<1300) + // In VC7, you will need to put this in your project settings + #pragma comment(linker,"/opt:nowin98") +#else + +// Option #3: use /align:4096 +// A side effect of using the default align value is that it turns on the above switch. +// Does nothing under Vc7 that /opt:nowin98 doesn't already give you +// #pragma comment(linker,"/ALIGN:512") +#endif + +#endif // _MSC_VER >= 1000 + +#endif // NDEBUG + +#endif // _AGGRESSIVEOPTIMIZE_H_ diff --git a/protocols/YAMN/filter/Base/Base.dsp b/protocols/YAMN/filter/Base/Base.dsp new file mode 100644 index 0000000000..7231712a74 --- /dev/null +++ b/protocols/YAMN/filter/Base/Base.dsp @@ -0,0 +1,108 @@ +# Microsoft Developer Studio Project File - Name="Base" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 6.00 +# ** NICHT BEARBEITEN ** + +# TARGTYPE "Win32 (x86) Dynamic-Link Library" 0x0102 + +CFG=Base - Win32 Release +!MESSAGE Dies ist kein gltiges Makefile. Zum Erstellen dieses Projekts mit NMAKE +!MESSAGE verwenden Sie den Befehl "Makefile exportieren" und fhren Sie den Befehl +!MESSAGE +!MESSAGE NMAKE /f "Base.mak". +!MESSAGE +!MESSAGE Sie knnen beim Ausfhren von NMAKE eine Konfiguration angeben +!MESSAGE durch Definieren des Makros CFG in der Befehlszeile. Zum Beispiel: +!MESSAGE +!MESSAGE NMAKE /f "Base.mak" CFG="Base - Win32 Release" +!MESSAGE +!MESSAGE Fr die Konfiguration stehen zur Auswahl: +!MESSAGE +!MESSAGE "Base - Win32 Release" (basierend auf "Win32 (x86) Dynamic-Link Library") +!MESSAGE "Base - Win32 Debug" (basierend auf "Win32 (x86) Dynamic-Link Library") +!MESSAGE + +# Begin Project +# PROP AllowPerConfigDependencies 0 +# PROP Scc_ProjName "" +# PROP Scc_LocalPath "" +CPP=cl.exe +MTL=midl.exe +RSC=rc.exe + +!IF "$(CFG)" == "Base - Win32 Release" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "Release" +# PROP BASE Intermediate_Dir "Release" +# PROP BASE Ignore_Export_Lib 1 +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "Release" +# PROP Intermediate_Dir "Release" +# PROP Ignore_Export_Lib 1 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /G4 /Zp4 /MD /W3 /GX /O1 /Ob0 /I "../../../../include" /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /YX /FD /c +# ADD CPP /nologo /G4 /Zp4 /MD /W3 /GX /Zi /O1 /Ob0 /I "../../../../include" /I "../../../../include/msapi" /I "../../../../include_API" /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /YX /FD /c +# ADD BASE RSC /l 0x417 /d "NDEBUG" +# ADD RSC /l 0x417 /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib /nologo /dll /machine:I386 /out:"../../../../bin/release/plugins/YAMN-filter/Base.dll" /filealign:512 +# ADD LINK32 kernel32.lib user32.lib /nologo /dll /pdb:"../../../../bin/Release/plugins/YAMN/base.pdb" /debug /machine:I386 /out:"../../../../bin/Release/plugins/YAMN/base.dll" /filealign:512 + +!ELSEIF "$(CFG)" == "Base - Win32 Debug" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "Debug" +# PROP BASE Intermediate_Dir "Debug" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "Debug" +# PROP Intermediate_Dir "Debug" +# PROP Ignore_Export_Lib 1 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /G4 /Zp4 /MDd /W3 /Gm /Gi /GX /ZI /Od /I "../../../../include" /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /FR /YX /FD /GZ /c +# ADD CPP /nologo /G4 /Zp4 /MDd /W3 /Gm /Gi /GX /ZI /Od /I "../../../../include" /I "../../../../include/msapi" /I "../../../../include_API" /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /FR /YX /FD /GZ /c +# ADD BASE RSC /l 0x417 /d "_DEBUG" +# ADD RSC /l 0x417 /d "_DEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib /nologo /dll /debug /machine:I386 /out:"../../../../bin/Debug/plugins/YAMN-filter/Base.dll" +# ADD LINK32 kernel32.lib user32.lib /nologo /dll /pdb:"../../../../bin/Debug/plugins/YAMN/base.pdb" /debug /machine:I386 /out:"../../../../bin/Debug/plugins/YAMN/base.dll" /pdbtype:sept + +!ENDIF + +# Begin Target + +# Name "Base - Win32 Release" +# Name "Base - Win32 Debug" +# Begin Group "Source Files" + +# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat" +# Begin Source File + +SOURCE=.\debug.cpp +# End Source File +# Begin Source File + +SOURCE=.\maindll.cpp +# End Source File +# End Group +# Begin Group "Header Files" + +# PROP Default_Filter "h;hpp;hxx;hm;inl" +# End Group +# Begin Group "Resource Files" + +# PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe" +# End Group +# End Target +# End Project diff --git a/protocols/YAMN/filter/Base/Base.mak b/protocols/YAMN/filter/Base/Base.mak new file mode 100644 index 0000000000..75ec59db8a --- /dev/null +++ b/protocols/YAMN/filter/Base/Base.mak @@ -0,0 +1,229 @@ +# Microsoft Developer Studio Generated NMAKE File, Based on Base.dsp +!IF "$(CFG)" == "" +CFG=Base - Win32 Release +!MESSAGE No configuration specified. Defaulting to Base - Win32 Release. +!ENDIF + +!IF "$(CFG)" != "Base - Win32 Release" && "$(CFG)" != "Base - Win32 Debug" +!MESSAGE Invalid configuration "$(CFG)" specified. +!MESSAGE You can specify a configuration when running NMAKE +!MESSAGE by defining the macro CFG on the command line. For example: +!MESSAGE +!MESSAGE NMAKE /f "Base.mak" CFG="Base - Win32 Release" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "Base - Win32 Release" (based on "Win32 (x86) Dynamic-Link Library") +!MESSAGE "Base - Win32 Debug" (based on "Win32 (x86) Dynamic-Link Library") +!MESSAGE +!ERROR An invalid configuration is specified. +!ENDIF + +!IF "$(OS)" == "Windows_NT" +NULL= +!ELSE +NULL=nul +!ENDIF + +!IF "$(CFG)" == "Base - Win32 Release" + +OUTDIR=.\Release +INTDIR=.\Release + +ALL : "..\..\..\..\bin\release\plugins\YAMN-filter\base.dll" + + +CLEAN : + -@erase "$(INTDIR)\debug.obj" + -@erase "$(INTDIR)\maindll.obj" + -@erase "$(INTDIR)\vc60.idb" + -@erase "$(OUTDIR)\base.exp" + -@erase "..\..\..\..\bin\release\plugins\YAMN-filter\base.dll" + +"$(OUTDIR)" : + if not exist "$(OUTDIR)/$(NULL)" mkdir "$(OUTDIR)" + +CPP=cl.exe +CPP_PROJ=/nologo /G4 /Zp4 /MD /W3 /GX /O1 /Ob0 /I "../../../../include" /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /Fp"$(INTDIR)\Base.pch" /YX /Fo"$(INTDIR)\\" /Fd"$(INTDIR)\\" /FD /c + +.c{$(INTDIR)}.obj:: + $(CPP) @<< + $(CPP_PROJ) $< +<< + +.cpp{$(INTDIR)}.obj:: + $(CPP) @<< + $(CPP_PROJ) $< +<< + +.cxx{$(INTDIR)}.obj:: + $(CPP) @<< + $(CPP_PROJ) $< +<< + +.c{$(INTDIR)}.sbr:: + $(CPP) @<< + $(CPP_PROJ) $< +<< + +.cpp{$(INTDIR)}.sbr:: + $(CPP) @<< + $(CPP_PROJ) $< +<< + +.cxx{$(INTDIR)}.sbr:: + $(CPP) @<< + $(CPP_PROJ) $< +<< + +MTL=midl.exe +MTL_PROJ= +RSC=rc.exe +BSC32=bscmake.exe +BSC32_FLAGS=/nologo /o"$(OUTDIR)\Base.bsc" +BSC32_SBRS= \ + +LINK32=link.exe +LINK32_FLAGS=kernel32.lib user32.lib /nologo /dll /incremental:no /pdb:"$(OUTDIR)\base.pdb" /machine:I386 /out:"../../../../bin/release/plugins/YAMN-filter/base.dll" /implib:"$(OUTDIR)\base.lib" /filealign:512 +LINK32_OBJS= \ + "$(INTDIR)\debug.obj" \ + "$(INTDIR)\maindll.obj" + +"..\..\..\..\bin\release\plugins\YAMN-filter\base.dll" : "$(OUTDIR)" $(DEF_FILE) $(LINK32_OBJS) + $(LINK32) @<< + $(LINK32_FLAGS) $(LINK32_OBJS) +<< + +!ELSEIF "$(CFG)" == "Base - Win32 Debug" + +OUTDIR=.\Debug +INTDIR=.\Debug +# Begin Custom Macros +OutDir=.\Debug +# End Custom Macros + +ALL : "..\..\..\..\bin\Debug\plugins\YAMN-filter\Base.dll" "$(OUTDIR)\Base.bsc" + + +CLEAN : + -@erase "$(INTDIR)\debug.obj" + -@erase "$(INTDIR)\debug.sbr" + -@erase "$(INTDIR)\maindll.obj" + -@erase "$(INTDIR)\maindll.sbr" + -@erase "$(INTDIR)\vc60.idb" + -@erase "$(INTDIR)\vc60.pdb" + -@erase "$(OUTDIR)\Base.bsc" + -@erase "$(OUTDIR)\Base.exp" + -@erase "$(OUTDIR)\Base.pdb" + -@erase "..\..\..\..\bin\Debug\plugins\YAMN-filter\Base.dll" + -@erase "..\..\..\..\bin\Debug\plugins\YAMN-filter\Base.ilk" + +"$(OUTDIR)" : + if not exist "$(OUTDIR)/$(NULL)" mkdir "$(OUTDIR)" + +CPP=cl.exe +CPP_PROJ=/nologo /G4 /Zp4 /MDd /W3 /Gm /Gi /GX /ZI /Od /I "../../../../include" /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /FR"$(INTDIR)\\" /Fp"$(INTDIR)\Base.pch" /YX /Fo"$(INTDIR)\\" /Fd"$(INTDIR)\\" /FD /GZ /c + +.c{$(INTDIR)}.obj:: + $(CPP) @<< + $(CPP_PROJ) $< +<< + +.cpp{$(INTDIR)}.obj:: + $(CPP) @<< + $(CPP_PROJ) $< +<< + +.cxx{$(INTDIR)}.obj:: + $(CPP) @<< + $(CPP_PROJ) $< +<< + +.c{$(INTDIR)}.sbr:: + $(CPP) @<< + $(CPP_PROJ) $< +<< + +.cpp{$(INTDIR)}.sbr:: + $(CPP) @<< + $(CPP_PROJ) $< +<< + +.cxx{$(INTDIR)}.sbr:: + $(CPP) @<< + $(CPP_PROJ) $< +<< + +MTL=midl.exe +MTL_PROJ= +RSC=rc.exe +BSC32=bscmake.exe +BSC32_FLAGS=/nologo /o"$(OUTDIR)\Base.bsc" +BSC32_SBRS= \ + "$(INTDIR)\debug.sbr" \ + "$(INTDIR)\maindll.sbr" + +"$(OUTDIR)\Base.bsc" : "$(OUTDIR)" $(BSC32_SBRS) + $(BSC32) @<< + $(BSC32_FLAGS) $(BSC32_SBRS) +<< + +LINK32=link.exe +LINK32_FLAGS=kernel32.lib user32.lib /nologo /dll /incremental:yes /pdb:"$(OUTDIR)\Base.pdb" /debug /machine:I386 /out:"../../../../bin/Debug/plugins/YAMN-filter/Base.dll" /implib:"$(OUTDIR)\Base.lib" +LINK32_OBJS= \ + "$(INTDIR)\debug.obj" \ + "$(INTDIR)\maindll.obj" + +"..\..\..\..\bin\Debug\plugins\YAMN-filter\Base.dll" : "$(OUTDIR)" $(DEF_FILE) $(LINK32_OBJS) + $(LINK32) @<< + $(LINK32_FLAGS) $(LINK32_OBJS) +<< + +!ENDIF + + +!IF "$(NO_EXTERNAL_DEPS)" != "1" +!IF EXISTS("Base.dep") +!INCLUDE "Base.dep" +!ELSE +!MESSAGE Warning: cannot find "Base.dep" +!ENDIF +!ENDIF + + +!IF "$(CFG)" == "Base - Win32 Release" || "$(CFG)" == "Base - Win32 Debug" +SOURCE=.\debug.cpp + +!IF "$(CFG)" == "Base - Win32 Release" + + +"$(INTDIR)\debug.obj" : $(SOURCE) "$(INTDIR)" + + +!ELSEIF "$(CFG)" == "Base - Win32 Debug" + + +"$(INTDIR)\debug.obj" "$(INTDIR)\debug.sbr" : $(SOURCE) "$(INTDIR)" + + +!ENDIF + +SOURCE=.\maindll.cpp + +!IF "$(CFG)" == "Base - Win32 Release" + + +"$(INTDIR)\maindll.obj" : $(SOURCE) "$(INTDIR)" + + +!ELSEIF "$(CFG)" == "Base - Win32 Debug" + + +"$(INTDIR)\maindll.obj" "$(INTDIR)\maindll.sbr" : $(SOURCE) "$(INTDIR)" + + +!ENDIF + + +!ENDIF + diff --git a/protocols/YAMN/filter/Base/debug.cpp b/protocols/YAMN/filter/Base/debug.cpp new file mode 100644 index 0000000000..654ece7b57 --- /dev/null +++ b/protocols/YAMN/filter/Base/debug.cpp @@ -0,0 +1,73 @@ +/* + * Copied from YAMN plugin + * + * (c) majvan 2002-2004 + */ +#ifdef DEBUG_FILTER + +#include +#include +#include + + +//-------------------------------------------------------------------------------------------------- +//-------------------------------------------------------------------------------------------------- + +TCHAR DebugUserDirectory[MAX_PATH]="."; +LPCRITICAL_SECTION FileAccessCS; + +void DebugLog(HANDLE File,const char *fmt,...); + +#ifdef DEBUG_FILTER +TCHAR DebugFilterFileName2[]=_T("%s\\yamn-debug.basefilter.log"); +HANDLE FilterFile=INVALID_HANDLE_VALUE; +#endif + +//-------------------------------------------------------------------------------------------------- +//-------------------------------------------------------------------------------------------------- + +void InitDebug() +{ + TCHAR DebugFileName[MAX_PATH]; + + if(FileAccessCS==NULL) + { + FileAccessCS=new CRITICAL_SECTION; + InitializeCriticalSection(FileAccessCS); + } + + _stprintf(DebugFileName,DebugFilterFileName2,DebugUserDirectory); + + FilterFile=CreateFile(DebugFileName,GENERIC_WRITE,FILE_SHARE_WRITE,NULL,CREATE_ALWAYS,0,NULL); + + DebugLog(FilterFile,"Base filter plugin for YAMN - debug file\n"); +} + +void UnInitDebug() +{ + DebugLog(FilterFile,"File is being closed normally."); + CloseHandle(FilterFile); +} + +void DebugLog(HANDLE File,const char *fmt,...) +{ + char *str; + char tids[32]; + va_list vararg; + int strsize; + DWORD Written; + + va_start(vararg,fmt); + str=(char *)malloc(strsize=65536); + _stprintf(tids,_T("[%x]"),GetCurrentThreadId()); + while(_vsnprintf(str,strsize,fmt,vararg)==-1) + str=(char *)realloc(str,strsize+=65536); + va_end(vararg); + EnterCriticalSection(FileAccessCS); + WriteFile(File,tids,(DWORD)strlen(tids),&Written,NULL); + WriteFile(File,str,(DWORD)strlen(str),&Written,NULL); + LeaveCriticalSection(FileAccessCS); + free(str); +} + +#endif //ifdef DEBUG \ No newline at end of file diff --git a/protocols/YAMN/filter/Base/docs/base-readme.txt b/protocols/YAMN/filter/Base/docs/base-readme.txt new file mode 100644 index 0000000000..2e79bbbdd8 --- /dev/null +++ b/protocols/YAMN/filter/Base/docs/base-readme.txt @@ -0,0 +1,63 @@ +======================== += Base Filter for YAMN = +======================== + +Q: What??? +A: YAMN filter to classify incoming email. + +Q: How? +A: Finding occurency of defiend MIME header item and its value from blacklist file. + +Q: Blacklist file? +A: Yes. It is created by yourself and located in Miranda directory with name 'basefilterdeny.txt' + +Q: Created by myself? +A: Just create the file and write there your header MIME items and its values. + +Q: What do you mean "header MIME items" and "its values"? +A: Every mail has header consisting of MIME items like "Subject" or "Return-Path". + +Q: So I need to understand how the header looks like... +A: Yes, if you want to use this filter, you should. Header MIME is defined in RFC822 standard. + +Q: Ok, I've just studied it. So how to set filter (write some rules to the blacklist file)? +A: Each line is one rule: write the exact item, press , press the substring of value needed to be found, press , define spamlevel and then press . + +Q: Spamlevel? +A: Yes. + 0=do not notify + 1=notify, display with another color in mailbrowser + 2=do not notify, display with another color in mailbrowser + 3=delete, display in mailbrowser about deleted mail + 4=delete, do not display (mail's quick death, hehe) + +Q: So the rule has 3 parameters, that's it? +A: Yes. This is the example: +<------ start of file ------> +From CrazyMail 1 +X-Importance low 0 +Subject LinuxMailList 0 +Return-Path cheapsoftware@junkmails.net 2 +X-TextClassification spam 3 +<------ end of file -------> + +Q: Wait while. Ok, but it does not work. +A: Check if you have this plugin listed in Miranda/Options/Plugins/YAMN item + +Q: No, it is not listed in YAMN plugins. +A: Then check if the dll residents in Plugins/YAMN direcotry. + +Q: This directory does not exists. +A: Create it and put the dll there. Restart Miranda. + +Q: Hmmm, ok. But it is not still listed. +A: Your version of YAMN and filter does not match. + +Q: And? +A: Try to look to http://www.majvan.host.sk/Projekty/YAMN for updates. + +Q: Now, it is listed, but does not work anyway. +A: Try to download debug version from YAMN homepage, if you are not using it (the name of filter must contain the word "debug") + +Q: What does debug version do? +A: It creates debug log file in Miranda home directory where you can browse how does filter mark mails. \ No newline at end of file diff --git a/protocols/YAMN/filter/Base/maindll.cpp b/protocols/YAMN/filter/Base/maindll.cpp new file mode 100644 index 0000000000..d6a645bd14 --- /dev/null +++ b/protocols/YAMN/filter/Base/maindll.cpp @@ -0,0 +1,238 @@ +//--------------------------------------------------------------------------- +#include +#include +#include +#include +#include +#include +#include +#include +#include "../../m_filterplugin.h" +#if !defined(_WIN64) + #include "aggressiveoptimize.h" +#endif + +typedef INT_PTR(* MIRANDASERVICE)(WPARAM,LPARAM); + +DWORD WINAPI FilterMail(HACCOUNT Account,DWORD AccountVer,HYAMNMAIL Mail,DWORD MailVer);//Function marks mail as spam when it is spam... +DWORD WINAPI UnLoadFilter(LPVOID); + +int LoadRules(); //Load rules from file +int findsubstr(char *original,char *pattern); //finds if original contains substring + +YAMN_FILTERIMPORTFCN FilterFunctions= //we set for YAMN which is our filter function +{ + FilterMail, + UnLoadFilter, +}; + +struct cFilterTable +{ + char account[256]; + char name[256]; + char value[256]; + unsigned char sl; +} *ft=NULL; +int fts=0; + +YAMN_FILTERREGISTRATION FilterRegistration= //classical YAMN registration +{ +#ifdef DEBUG_FILTER + "Base filter plugin for YAMN (debug)", +#else + "Base filter plugin for YAMN", +#endif + __DATE__, + " majvan", + "Classifies mails using the rules stored in file", + "om3tn@psg.sk", + "http://www.majvan.host.sk/Projekty/YAMN?fm=soft", +}; + +char *FilterPath=NULL; + +struct YAMNExportedFcn +{ + YAMN_SETFILTERPLUGINFCNIMPORTFCN SetFilterPluginFcnImportFcn; + MIRANDASERVICE RegisterFilterPlugin; +} YAMNFcn,*pYAMNFcn; //exported functions from YAMN we will use + +HYAMNFILTERPLUGIN POPFilePlugin; //handle of this plugin for YAMN +HINSTANCE hInst; //handle of this DLL for Windows + +#ifdef DEBUG_FILTER +extern void InitDebug(); +extern void UnInitDebug(); +extern void DebugLog(HANDLE File,const char *fmt,...); +extern HANDLE FilterFile; +#endif + +extern "C" BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fwdreason, LPVOID lpvReserved) +{ + hInst=hinstDLL; + return true; +} + +extern "C" int __declspec(dllexport) LoadFilter(MIRANDASERVICE GetYAMNFcnPtr) +{ + FilterPath=new char[MAX_PATH]; + char *delim; + pYAMNFcn=&YAMNFcn; + + GetModuleFileName(GetModuleHandle(NULL),FilterPath,MAX_PATH); + if(NULL!=(delim=strrchr(FilterPath,'\\'))) + *delim=0; + lstrcat(FilterPath,"\\basefilterdeny.txt"); +#ifdef DEBUG_FILTER + InitDebug(); +#endif + + if (!LoadRules()) + return 0; + + pYAMNFcn->RegisterFilterPlugin=(MIRANDASERVICE)GetYAMNFcnPtr((WPARAM)MS_YAMN_REGISTERFILTERPLUGIN,(LPARAM)0); + pYAMNFcn->SetFilterPluginFcnImportFcn=(YAMN_SETFILTERPLUGINFCNIMPORTFCN)GetYAMNFcnPtr((WPARAM)YAMN_SETFILTERPLUGINFCNIMPORTID,(LPARAM)0); +//Register our filter plugin to YAMN + if(NULL==(POPFilePlugin=(HYAMNFILTERPLUGIN)pYAMNFcn->RegisterFilterPlugin((WPARAM)&FilterRegistration,(LPARAM)YAMN_FILTERREGISTRATIONVERSION))) + return 0; +//And add our imported functions for YAMN + if (!pYAMNFcn->SetFilterPluginFcnImportFcn(POPFilePlugin,0xb0000000,&FilterFunctions,YAMN_FILTERIMPORTFCNVERSION)) + return 0; + return 1; //Load luccess +} + +DWORD WINAPI UnLoadFilter(LPVOID) +{ +#ifdef DEBUG_FILTER + UnInitDebug(); +#endif + if(FilterPath!=NULL) + delete[] FilterPath; + FilterPath=NULL; + + return 0; +} + +extern "C" int __declspec(dllexport) UninstallFilter() +{ + if(FilterPath==NULL) + MessageBox(NULL,"Cannot delete blacklist file when Base Filter is not loaded. Please do it manually.","Base Filter uninstalling",MB_OK|MB_ICONWARNING); + else + DeleteFile(FilterPath); + return 0; +} + + +//And this is main filter function. +DWORD WINAPI FilterMail(HACCOUNT Account,DWORD AccountVer,HYAMNMAIL Mail,DWORD MailVer) +{ + struct CMimeItem *Browser; + + if(MailVer!=YAMN_MAILVERSION) //we test if we work with the right YAMNMAIL + return 0; + if(Mail->MailData==NULL) //MailData should be available + return 0; + +#ifdef DEBUG_FILTER + DebugLog(FilterFile,"\n"); +#endif + if (!(Mail->Flags & YAMN_MSG_VIRTUAL)) + for(Browser=Mail->MailData->TranslatedHeader;Browser!=NULL;Browser=Browser->Next) //we browse all header stored in Mail->TranslatedHeader + { +#ifdef DEBUG_FILTER + DebugLog(FilterFile,"\n",Browser->name,Browser->value); +#endif + for(int i=0;iname,ft[i].name)) + { +#ifdef DEBUG_FILTER + DebugLog(FilterFile,"\t\t\n",Browser->name); +#endif + if(findsubstr(Browser->value,ft[i].value)) //and if we find + { + if ((ft[i].sl==0) && ((Mail->Flags & YAMN_MSG_SPAMMASK)==0)) + { + Mail->Flags&=~(YAMN_MSG_POPUP | YAMN_MSG_SYSTRAY | YAMN_MSG_BROWSER | YAMN_MSG_SOUND | YAMN_MSG_APP | YAMN_MSG_NEVENT); +#ifdef DEBUG_FILTER + DebugLog(FilterFile,"\t\tSetting individual flags not to notify mail, but does not consider as spam."); +#endif + } + else if ((Mail->Flags & YAMN_MSG_SPAMMASK) < ft[i].sl) //if some filter plugin set higher level of spam, we do nothing + { + Mail->Flags=(Mail->Flags & ~YAMN_MSG_SPAMMASK)+ft[i].sl; //else we set spam level 2 (clearing spam bits and then settting them to level 2 +#ifdef DEBUG_FILTER + DebugLog(FilterFile,"\t\tMail marked to be spam #%d\n",Mail->Flags & YAMN_MSG_SPAMMASK); +#endif + } + } +#ifdef DEBUG_FILTER + DebugLog(FilterFile,"\t\t\n"); +#endif + } +#ifdef DEBUG_FILTER + DebugLog(FilterFile,"\n"); +#endif + } +#ifdef DEBUG_FILTER + DebugLog(FilterFile,"\n\n"); +#endif + return 1; +} + +int LoadRules() +{ + char *account=NULL; + char name[256]; + char value[256]; + char BadCompiler[512+5]; + unsigned char sl; + FILE *fp; + +#ifdef DEBUG_FILTER + DebugLog(FilterFile,"\n",FilterPath); +#endif + + fp=fopen(FilterPath,"rt"); + if(fp==NULL) + return 0; + + while(!feof(fp)) + { + if(fscanf(fp,"%255s",name) && !feof(fp) && (name[0]!=0)) + { + if(fscanf(fp,"%255s",value) && !feof(fp) && (value[0]!=0)) + { + if(fscanf(fp,"%d",&sl)) + { + fts++; + ft=(struct cFilterTable *)realloc((void *)ft,sizeof(cFilterTable)*fts); + lstrcpy(ft[fts-1].name,name); + lstrcpy(ft[fts-1].value,value); + ft[fts-1].sl=sl; + + sprintf(BadCompiler,"%s %s %d",name,value,sl); +#ifdef DEBUG_FILTER + DebugLog(FilterFile,"\t%s%s%d\n",name,value,sl); +#endif + } + } + } + } + + fclose(fp); +#ifdef DEBUG_FILTER + DebugLog(FilterFile,"\n"); +#endif + return 1; +} + +int findsubstr(char *original,char *pattern) +{ + int ol=lstrlen(original); + int pl=lstrlen(pattern); + + for(int i=0;(i+pl)<=ol;i++) + if (!_strnicmp(original+i,pattern,pl)) + return 1; + return 0; +} \ No newline at end of file diff --git a/protocols/YAMN/filter/Simple/AggressiveOptimize.h b/protocols/YAMN/filter/Simple/AggressiveOptimize.h new file mode 100644 index 0000000000..1bf0e19c2c --- /dev/null +++ b/protocols/YAMN/filter/Simple/AggressiveOptimize.h @@ -0,0 +1,168 @@ + +////////////////////////////// +// Version 1.40 +// October 22nd, 2002 - .NET (VC7, _MSC_VER=1300) support! +// Version 1.30 +// Nov 24th, 2000 +// Version 1.20 +// Jun 9th, 2000 +// Version 1.10 +// Jan 23rd, 2000 +// Version 1.00 +// May 20th, 1999 +// Todd C. Wilson, Fresh Ground Software +// (todd@nopcode.com) +// This header file will kick in settings for Visual C++ 5 and 6 that will (usually) +// result in smaller exe's. +// The "trick" is to tell the compiler to not pad out the function calls; this is done +// by not using the /O1 or /O2 option - if you do, you implicitly use /Gy, which pads +// out each and every function call. In one single 500k dll, I managed to cut out 120k +// by this alone! +// The other two "tricks" are telling the Linker to merge all data-type segments together +// in the exe file. The relocation, read-only (constants) data, and code section (.text) +// sections can almost always be merged. Each section merged can save 4k in exe space, +// since each section is padded out to 4k chunks. This is very noticeable with smaller +// exes, since you could have only 700 bytes of data, 300 bytes of code, 94 bytes of +// strings - padded out, this could be 12k of runtime, for 1094 bytes of stuff! For larger +// programs, this is less overall, but can save at least 4k. +// Note that if you're using MFC static or some other 3rd party libs, you may get poor +// results with merging the readonly (.rdata) section - the exe may grow larger. +// To use this feature, define _MERGE_DATA_ in your project or before this header is used. +// With Visual C++ 5, the program uses a file alignment of 512 bytes, which results +// in a small exe. Under VC6, the program instead uses 4k, which is the same as the +// section size. The reason (from what I understand) is that 4k is the chunk size of +// the virtual memory manager, and that WinAlign (an end-user tuning tool for Win98) +// will re-align the programs on this boundary. The problem with this is that all of +// Microsoft's system exes and dlls are *NOT* tuned like this, and using 4k causes serious +// exe bloat. This is very noticeable for smaller programs. +// The "trick" for this is to use the undocumented FILEALIGN linker parm to change the +// padding from 4k to 1/2k, which results in a much smaller exe - anywhere from 20%-75% +// depending on the size. Note that this is the same as using /OPT:NOWIN98, which *is* +// a previously documented switch, but was left out of the docs for some reason in VC6 and +// all of the current MSDN's - see KB:Q235956 for more information. +// Microsoft does say that using the 4k alignment will "speed up process loading", +// but I've been unable to notice a difference, even on my P180, with a very large (4meg) exe. +// Please note, however, that this will probably not change the size of the COMPRESSED +// file (either in a .zip file or in an install archive), since this 4k is all zeroes and +// gets compressed away. +// Also, the /ALIGN:4096 switch will "magically" do the same thing, even though this is the +// default setting for this switch. Apparently this sets the same values as the above two +// switches do. We do not use this in this header, since it smacks of a bug and not a feature. +// Thanks to Michael Geary for some additional tips! +// +// Notes about using this header in .NET +// First off, VC7 does not allow a lot of the linker command options in pragma's. There is no +// honest or good reason why Microsoft decided to make this change, it just doesn't. +// So that is why there are a lot of <1300 #if's in the header. +// If you want to take full advantage of the VC7 linker options, you will need to do it on a +// PER PROJECT BASIS; you can no longer use a global header file like this to make it better. +// Items I strongly suggest putting in all your VC7 project linker options command line settings: +// /ignore:4078 /RELEASE +// Compiler options: +// /GL (Whole Program Optimization) +// If you're making an .EXE and not a .DLL, consider adding in: +// /GA (Optimize for Windows Application) +// Some items to consider using in your VC7 projects (not VC6): +// Link-time Code Generation - whole code optimization. Put this in your exe/dll project link settings. +// /LTCG:NOSTATUS +// The classic no-padding and no-bloat compiler C/C++ switch: +// /opt:nowin98 +// +// (C++ command line options: /GL /opt:nowin98 and /GA for .exe files) +// (Link command line options: /ignore:4078 /RELEASE /LTCG:NOSTATUS) +// +// Now, notes on using these options in VC7 vs VC6. +// VC6 consistently, for me, produces smaller code from C++ the exact same sources, +// with or without this header. On average, VC6 produces 5% smaller binaries compared +// to VC7 compiling the exact same project, *without* this header. With this header, VC6 +// will make a 13k file, while VC7 will make a 64k one. VC7 is just bloaty, pure and +// simple - all that managed/unmanaged C++ runtimes, and the CLR stuff must be getting +// in the way of code generation. However, template support is better, so there. +// Both VC6 and VC7 show the same end kind of end result savings - larger binary output +// will shave about 2% off, where as smaller projects (support DLL's, cpl's, +// activex controls, ATL libs, etc) get the best result, since the padding is usually +// more than the actual usable code. But again, VC7 does not compile down as small as VC6. +// +// The argument can be made that doing this is a waste of time, since the "zero bytes" +// will be compressed out in a zip file or install archive. Not really - it doesn't matter +// if the data is a string of zeroes or ones or 85858585 - it will still take room (20 bytes +// in a zip file, 29 bytes if only *4* of them 4k bytes are not the same) and time to +// compress that data and decompress it. Also, 20k of zeros is NOT 20k on disk - it's the +// size of the cluster slop- for Fat32 systems, 20k can be 32k, NTFS could make it 24k if you're +// just 1 byte over (round up). Most end users do not have the dual P4 Xeon systems with +// two gigs of RDram and a Raid 0+1 of Western Digital 120meg Special Editions that all +// worthy developers have (all six of us), so they will need any space and LOADING TIME +// savings they will need; taking an extra 32k or more out of your end user's 64megs of +// ram on Windows 98 is Not a Good Thing. +// +// Now, as a ADDED BONUS at NO EXTRA COST TO YOU! Under VC6, using the /merge:.text=.data +// pragma will cause the output file to be un-disassembleable! (is that a word?) At least, +// with the normal tools - WinDisam, DumpBin, and the like will not work. Try it - use the +// header, compile release, and then use DUMPBIN /DISASM filename.exe - no code! +// Thanks to Gzim Pani for discovering this gem - for a full writeup on +// this issue and the ramifactions of it, visit www.nopcode.com for the Aggressive Optimize +// article. + +#ifndef _AGGRESSIVEOPTIMIZE_H_ +#define _AGGRESSIVEOPTIMIZE_H_ + +#pragma warning(disable:4711) + +#ifdef NDEBUG +// /Og (global optimizations), /Os (favor small code), /Oy (no frame pointers) +#pragma optimize("gsy",on) + +#if (_MSC_VER<1300) + #pragma comment(linker,"/RELEASE") +#endif + +/* +// Note that merging the .rdata section will result in LARGER exe's if you using +// MFC (esp. static link). If this is desirable, define _MERGE_RDATA_ in your project. +#ifdef _MERGE_RDATA_ +#pragma comment(linker,"/merge:.rdata=.data") +#endif // _MERGE_RDATA_ + +#pragma comment(linker,"/merge:.text=.data") +#if (_MSC_VER<1300) + // In VC7, this causes problems with the relocation and data tables, so best to not merge them + #pragma comment(linker,"/merge:.reloc=.data") +#endif +*/ + +// Merging sections with different attributes causes a linker warning, so +// turn off the warning. From Michael Geary. Undocumented, as usual! +#if (_MSC_VER<1300) + // In VC7, you will need to put this in your project settings + #pragma comment(linker,"/ignore:4078") +#endif + +// With Visual C++ 5, you already get the 512-byte alignment, so you will only need +// it for VC6, and maybe later. +#if _MSC_VER >= 1000 + +// Option #1: use /filealign +// Totally undocumented! And if you set it lower than 512 bytes, the program crashes. +// Either leave at 0x200 or 0x1000 +//#pragma comment(linker,"/FILEALIGN:0x200") + +// Option #2: use /opt:nowin98 +// See KB:Q235956 or the READMEVC.htm in your VC directory for info on this one. +// This is our currently preferred option, since it is fully documented and unlikely +// to break in service packs and updates. +#if (_MSC_VER<1300) + // In VC7, you will need to put this in your project settings + #pragma comment(linker,"/opt:nowin98") +#else + +// Option #3: use /align:4096 +// A side effect of using the default align value is that it turns on the above switch. +// Does nothing under Vc7 that /opt:nowin98 doesn't already give you +// #pragma comment(linker,"/ALIGN:512") +#endif + +#endif // _MSC_VER >= 1000 + +#endif // NDEBUG + +#endif // _AGGRESSIVEOPTIMIZE_H_ diff --git a/protocols/YAMN/filter/Simple/docs/simple-readme.txt b/protocols/YAMN/filter/Simple/docs/simple-readme.txt new file mode 100644 index 0000000000..34c0842c87 --- /dev/null +++ b/protocols/YAMN/filter/Simple/docs/simple-readme.txt @@ -0,0 +1,51 @@ +========================== += Simple Filter for YAMN = +========================== + +Q: What??? +A: YAMN filter to classify incoming email. + +Q: How? +A: Regarding what the email is from and finding it in the blacklist email file. + +Q: Blacklist email file? +A: Yes. It is created by yourself and located in Miranda directory with name 'simplefilterdeny.txt' + +Q: Created by myself? +A: Just create the file and write there your blacklist mails in every line. + +Q: That's all? +A: Yes and no. You can specify spamlevel for each mail. + +Q: Spamlevel? +A: Yes. + 1=notify, display with another color in mailbrowser + 2=do not notify, display with another color in mailbrowser + 3=delete, display in mailbrowser about deleted mail + 4=delete, do not display (mail's quick death, hehe) + +Q: How to specify it? +A: After email press and write number 1-4. Note this is optional. If not defined, level 2 is default. + +Q: Ok, that's easy. +A: Yes, this is the example: +<------ start of file ------> +nigeria@spamserver.com 2 +cheapsoftware@junkmails.net 3 +learnenglish@commercial.org +<------ end of file -------> + +Q: Wait while. Ok, but it does not work. +A: Check if you have this plugin listed in Miranda/Options/Plugins/YAMN item as YAMN plugin. + +Q: No, it is not listed in YAMN plugins. +A: Then check if the dll residents in Plugins/YAMN direcotry. + +Q: This directory does not exists. +A: Create it and put the dll there. Restart Miranda. + +Q: Hmmm, ok. But it is not still listed. +A: Your version of YAMN and filter does not match. + +Q: And? +A: Try to look to http://www.majvan.host.sk/Projekty/YAMN for updates. \ No newline at end of file diff --git a/protocols/YAMN/filter/Simple/maindll.cpp b/protocols/YAMN/filter/Simple/maindll.cpp new file mode 100644 index 0000000000..62aa87b28d --- /dev/null +++ b/protocols/YAMN/filter/Simple/maindll.cpp @@ -0,0 +1,132 @@ +//--------------------------------------------------------------------------- +#include +#include +#include +#include +#include +#include +#include +#include +#include "../../m_filterplugin.h" +#if !defined(_WIN64) + #include "aggressiveoptimize.h" +#endif + +typedef INT_PTR(* MIRANDASERVICE)(WPARAM,LPARAM); + +DWORD WINAPI FilterMail(HACCOUNT Account,DWORD AccountVer,HYAMNMAIL Mail,DWORD MailVer);//Function marks mail as spam when it is spam... +DWORD WINAPI UnLoadFilter(LPVOID); + +YAMN_FILTERIMPORTFCN FilterFunctions= //we set for YAMN which is our filter function +{ + FilterMail, + UnLoadFilter, //No unloading +}; + +YAMN_FILTERREGISTRATION FilterRegistration= //classical YAMN registration +{ + "Simple filter plugin for YAMN", + __DATE__, + " porter+ majvan", + "Classifies mails using the blacklist emails stored in file", + "porterbox@hotmail.com", + "http://www.majvan.host.sk/Projekty/YAMN?fm=soft", +}; + +char *FilterPath=NULL; + +struct YAMNExportedFcn +{ + YAMN_SETFILTERPLUGINFCNIMPORTFCN SetFilterPluginFcnImportFcn; + MIRANDASERVICE RegisterFilterPlugin; +} YAMNFcn,*pYAMNFcn; //exported functions from YAMN we will use + +HYAMNFILTERPLUGIN POPFilePlugin; //handle of this plugin for YAMN +HINSTANCE hInst; //handle of this DLL for Windows + +extern "C" BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fwdreason, LPVOID lpvReserved) +{ + hInst=hinstDLL; + return true; +} + +extern "C" int __declspec(dllexport) LoadFilter(MIRANDASERVICE GetYAMNFcnPtr) +{ + FilterPath=new char[MAX_PATH]; + char *delim; + pYAMNFcn=&YAMNFcn; + + GetModuleFileName(GetModuleHandle(NULL),FilterPath,MAX_PATH); + if(NULL!=(delim=strrchr(FilterPath,'\\'))) + *delim=0; + lstrcat(FilterPath,"\\simplefilterdeny.txt"); + + pYAMNFcn->RegisterFilterPlugin=(MIRANDASERVICE)GetYAMNFcnPtr((WPARAM)MS_YAMN_REGISTERFILTERPLUGIN,(LPARAM)0); + pYAMNFcn->SetFilterPluginFcnImportFcn=(YAMN_SETFILTERPLUGINFCNIMPORTFCN)GetYAMNFcnPtr((WPARAM)YAMN_SETFILTERPLUGINFCNIMPORTID,(LPARAM)0); +//Register our filter plugin to YAMN + if(NULL==(POPFilePlugin=(HYAMNFILTERPLUGIN)pYAMNFcn->RegisterFilterPlugin((WPARAM)&FilterRegistration,(LPARAM)YAMN_FILTERREGISTRATIONVERSION))) + return 0; +//And add our imported functions for YAMN + if (!pYAMNFcn->SetFilterPluginFcnImportFcn(POPFilePlugin,0xb0000000,&FilterFunctions,YAMN_FILTERIMPORTFCNVERSION)) + return 0; + return 1; //Load luccess +} + +DWORD WINAPI UnLoadFilter(LPVOID) +{ + if(FilterPath!=NULL) + delete[] FilterPath; + FilterPath=NULL; + + return 0; +} + +extern "C" int __declspec(dllexport) UninstallFilter() +{ + if(FilterPath==NULL) + MessageBox(NULL,"Cannot delete blacklist file when Simple Filter is not loaded. Please do it manually.","Simple Filter uninstalling",MB_OK|MB_ICONWARNING); + else + DeleteFile(FilterPath); + return 0; +} + + +//And this is main filter function. +DWORD WINAPI FilterMail(HACCOUNT Account,DWORD AccountVer,HYAMNMAIL Mail,DWORD MailVer) +{ + FILE *fp; + char EmailSpam[256]; + unsigned char spamLevel; + struct CMimeItem *Browser; + + if(MailVer!=YAMN_MAILVERSION) //we test if we work with the right YAMNMAIL + return 0; + if(Mail->MailData==NULL) //MailData should be available + return 0; + fp=fopen(FilterPath,"rt"); + if(fp != NULL) { + if (!(Mail->Flags & YAMN_MSG_VIRTUAL)) + for(Browser=Mail->MailData->TranslatedHeader;Browser!=NULL;Browser=Browser->Next) { //we browse all header stored in Mail->TranslatedHeader + if ((!lstrcmp(Browser->name,"Return-Path")) || (!lstrcmp(Browser->name,"From"))) { //and if we find + fseek(fp, 0L, SEEK_SET); + while(!feof(fp)) { + if(fscanf(fp, "%255s", EmailSpam) != 0) { + if (!feof(fp)) + if(fscanf(fp, "%d", &spamLevel)==0) + spamLevel=2; + if(spamLevel>4) + spamLevel=2; + if(strstr(Browser->value,EmailSpam)!=NULL) { + if ((Mail->Flags & (YAMN_MSG_SPAMMASK==0)) && (spamLevel==0)) + Mail->Flags&=~(YAMN_MSG_SOUND | YAMN_MSG_APP | YAMN_MSG_POPUP | YAMN_MSG_SYSTRAY | YAMN_MSG_BROWSER); + else if ((Mail->Flags & YAMN_MSG_SPAMMASK) < spamLevel) //if some filter plugin set higher level of spam, we do nothing + Mail->Flags=(Mail->Flags & ~YAMN_MSG_SPAMMASK)+spamLevel; //else we set spam level 2 (clearing spam bits and then settting them to level 2 + } + } + } + } + } + fclose(fp); + } + return 1; +} diff --git a/protocols/YAMN/filter/Simple/simple.dsp b/protocols/YAMN/filter/Simple/simple.dsp new file mode 100644 index 0000000000..dc6d52e6c1 --- /dev/null +++ b/protocols/YAMN/filter/Simple/simple.dsp @@ -0,0 +1,105 @@ +# Microsoft Developer Studio Project File - Name="simple" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 6.00 +# ** NICHT BEARBEITEN ** + +# TARGTYPE "Win32 (x86) Dynamic-Link Library" 0x0102 + +CFG=simple - Win32 Release +!MESSAGE Dies ist kein gltiges Makefile. Zum Erstellen dieses Projekts mit NMAKE +!MESSAGE verwenden Sie den Befehl "Makefile exportieren" und fhren Sie den Befehl +!MESSAGE +!MESSAGE NMAKE /f "simple.mak". +!MESSAGE +!MESSAGE Sie knnen beim Ausfhren von NMAKE eine Konfiguration angeben +!MESSAGE durch Definieren des Makros CFG in der Befehlszeile. Zum Beispiel: +!MESSAGE +!MESSAGE NMAKE /f "simple.mak" CFG="simple - Win32 Release" +!MESSAGE +!MESSAGE Fr die Konfiguration stehen zur Auswahl: +!MESSAGE +!MESSAGE "simple - Win32 Release" (basierend auf "Win32 (x86) Dynamic-Link Library") +!MESSAGE "simple - Win32 Debug" (basierend auf "Win32 (x86) Dynamic-Link Library") +!MESSAGE + +# Begin Project +# PROP AllowPerConfigDependencies 0 +# PROP Scc_ProjName "" +# PROP Scc_LocalPath "" +CPP=cl.exe +MTL=midl.exe +RSC=rc.exe + +!IF "$(CFG)" == "simple - Win32 Release" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "Release" +# PROP BASE Intermediate_Dir "Release" +# PROP BASE Ignore_Export_Lib 1 +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "Release" +# PROP Intermediate_Dir "Release" +# PROP Ignore_Export_Lib 1 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /G4 /Zp4 /MD /W3 /GX /O1 /Ob0 /I "../../../../include" /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /YX /FD /c +# ADD CPP /nologo /G4 /Zp4 /MD /W3 /GX /Zi /O1 /Ob0 /I "../../../../include" /I "../../../../include/msapi" /I "../../../../include_API" /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /YX /FD /c +# ADD BASE RSC /l 0x417 /d "NDEBUG" +# ADD RSC /l 0x417 /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib /nologo /dll /machine:I386 /out:"../../../../bin/release/plugins/YAMN-filter/simple.dll" /filealign:512 +# ADD LINK32 kernel32.lib user32.lib /nologo /dll /pdb:"../../../../bin/Release/plugins/YAMN/simple.pdb" /debug /machine:I386 /out:"../../../../bin/Release/plugins/YAMN/simple.dll" /filealign:512 + +!ELSEIF "$(CFG)" == "simple - Win32 Debug" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "Debug" +# PROP BASE Intermediate_Dir "Debug" +# PROP BASE Ignore_Export_Lib 1 +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "Debug" +# PROP Intermediate_Dir "Debug" +# PROP Ignore_Export_Lib 1 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /G4 /Zp4 /MDd /W3 /Gm /Gi /GX /ZI /Od /I "../../../../include" /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /FR /YX /FD /GZ /c +# ADD CPP /nologo /G4 /Zp4 /MDd /W3 /Gm /Gi /GX /ZI /Od /I "../../../../include" /I "../../../../include/msapi" /I "../../../../include_API" /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /FR /YX /FD /GZ /c +# ADD BASE RSC /l 0x417 /d "_DEBUG" +# ADD RSC /l 0x417 /d "_DEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib /nologo /dll /debug /machine:I386 /out:"../../../../bin/Debug/plugins/YAMN-filter/simple.dll" +# ADD LINK32 kernel32.lib user32.lib /nologo /dll /pdb:"../../../../bin/Debug/plugins/YAMN/simple.pdb" /debug /machine:I386 /out:"../../../../bin/Debug/plugins/YAMN/simple.dll" /pdbtype:sept + +!ENDIF + +# Begin Target + +# Name "simple - Win32 Release" +# Name "simple - Win32 Debug" +# Begin Group "Source Files" + +# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat" +# Begin Source File + +SOURCE=.\maindll.cpp +# End Source File +# End Group +# Begin Group "Header Files" + +# PROP Default_Filter "h;hpp;hxx;hm;inl" +# End Group +# Begin Group "Resource Files" + +# PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe" +# End Group +# End Target +# End Project diff --git a/protocols/YAMN/filter/Simple/simple.mak b/protocols/YAMN/filter/Simple/simple.mak new file mode 100644 index 0000000000..085dc22e33 --- /dev/null +++ b/protocols/YAMN/filter/Simple/simple.mak @@ -0,0 +1,207 @@ +# Microsoft Developer Studio Generated NMAKE File, Based on simple.dsp +!IF "$(CFG)" == "" +CFG=simple - Win32 Release +!MESSAGE No configuration specified. Defaulting to simple - Win32 Release. +!ENDIF + +!IF "$(CFG)" != "simple - Win32 Release" && "$(CFG)" != "simple - Win32 Debug" +!MESSAGE Invalid configuration "$(CFG)" specified. +!MESSAGE You can specify a configuration when running NMAKE +!MESSAGE by defining the macro CFG on the command line. For example: +!MESSAGE +!MESSAGE NMAKE /f "simple.mak" CFG="simple - Win32 Release" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "simple - Win32 Release" (based on "Win32 (x86) Dynamic-Link Library") +!MESSAGE "simple - Win32 Debug" (based on "Win32 (x86) Dynamic-Link Library") +!MESSAGE +!ERROR An invalid configuration is specified. +!ENDIF + +!IF "$(OS)" == "Windows_NT" +NULL= +!ELSE +NULL=nul +!ENDIF + +!IF "$(CFG)" == "simple - Win32 Release" + +OUTDIR=.\Release +INTDIR=.\Release + +ALL : "..\..\..\..\bin\release\plugins\YAMN-filter\simple.dll" + + +CLEAN : + -@erase "$(INTDIR)\maindll.obj" + -@erase "$(INTDIR)\vc60.idb" + -@erase "$(OUTDIR)\simple.exp" + -@erase "..\..\..\..\bin\release\plugins\YAMN-filter\simple.dll" + +"$(OUTDIR)" : + if not exist "$(OUTDIR)/$(NULL)" mkdir "$(OUTDIR)" + +CPP=cl.exe +CPP_PROJ=/nologo /G4 /Zp4 /MD /W3 /GX /O1 /Ob0 /I "../../../../include" /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /Fp"$(INTDIR)\simple.pch" /YX /Fo"$(INTDIR)\\" /Fd"$(INTDIR)\\" /FD /c + +.c{$(INTDIR)}.obj:: + $(CPP) @<< + $(CPP_PROJ) $< +<< + +.cpp{$(INTDIR)}.obj:: + $(CPP) @<< + $(CPP_PROJ) $< +<< + +.cxx{$(INTDIR)}.obj:: + $(CPP) @<< + $(CPP_PROJ) $< +<< + +.c{$(INTDIR)}.sbr:: + $(CPP) @<< + $(CPP_PROJ) $< +<< + +.cpp{$(INTDIR)}.sbr:: + $(CPP) @<< + $(CPP_PROJ) $< +<< + +.cxx{$(INTDIR)}.sbr:: + $(CPP) @<< + $(CPP_PROJ) $< +<< + +MTL=midl.exe +MTL_PROJ= +RSC=rc.exe +BSC32=bscmake.exe +BSC32_FLAGS=/nologo /o"$(OUTDIR)\simple.bsc" +BSC32_SBRS= \ + +LINK32=link.exe +LINK32_FLAGS=kernel32.lib user32.lib /nologo /dll /incremental:no /pdb:"$(OUTDIR)\simple.pdb" /machine:I386 /out:"../../../../bin/release/plugins/YAMN-filter/simple.dll" /implib:"$(OUTDIR)\simple.lib" /filealign:512 +LINK32_OBJS= \ + "$(INTDIR)\maindll.obj" + +"..\..\..\..\bin\release\plugins\YAMN-filter\simple.dll" : "$(OUTDIR)" $(DEF_FILE) $(LINK32_OBJS) + $(LINK32) @<< + $(LINK32_FLAGS) $(LINK32_OBJS) +<< + +!ELSEIF "$(CFG)" == "simple - Win32 Debug" + +OUTDIR=.\Debug +INTDIR=.\Debug +# Begin Custom Macros +OutDir=.\Debug +# End Custom Macros + +ALL : "..\..\..\..\bin\Debug\plugins\YAMN-filter\simple.dll" "$(OUTDIR)\simple.bsc" + + +CLEAN : + -@erase "$(INTDIR)\maindll.obj" + -@erase "$(INTDIR)\maindll.sbr" + -@erase "$(INTDIR)\vc60.idb" + -@erase "$(INTDIR)\vc60.pdb" + -@erase "$(OUTDIR)\simple.bsc" + -@erase "$(OUTDIR)\simple.exp" + -@erase "$(OUTDIR)\simple.pdb" + -@erase "..\..\..\..\bin\Debug\plugins\YAMN-filter\simple.dll" + -@erase "..\..\..\..\bin\Debug\plugins\YAMN-filter\simple.ilk" + +"$(OUTDIR)" : + if not exist "$(OUTDIR)/$(NULL)" mkdir "$(OUTDIR)" + +CPP=cl.exe +CPP_PROJ=/nologo /G4 /Zp4 /MDd /W3 /Gm /Gi /GX /ZI /Od /I "../../../../include" /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /FR"$(INTDIR)\\" /Fp"$(INTDIR)\simple.pch" /YX /Fo"$(INTDIR)\\" /Fd"$(INTDIR)\\" /FD /GZ /c + +.c{$(INTDIR)}.obj:: + $(CPP) @<< + $(CPP_PROJ) $< +<< + +.cpp{$(INTDIR)}.obj:: + $(CPP) @<< + $(CPP_PROJ) $< +<< + +.cxx{$(INTDIR)}.obj:: + $(CPP) @<< + $(CPP_PROJ) $< +<< + +.c{$(INTDIR)}.sbr:: + $(CPP) @<< + $(CPP_PROJ) $< +<< + +.cpp{$(INTDIR)}.sbr:: + $(CPP) @<< + $(CPP_PROJ) $< +<< + +.cxx{$(INTDIR)}.sbr:: + $(CPP) @<< + $(CPP_PROJ) $< +<< + +MTL=midl.exe +MTL_PROJ= +RSC=rc.exe +BSC32=bscmake.exe +BSC32_FLAGS=/nologo /o"$(OUTDIR)\simple.bsc" +BSC32_SBRS= \ + "$(INTDIR)\maindll.sbr" + +"$(OUTDIR)\simple.bsc" : "$(OUTDIR)" $(BSC32_SBRS) + $(BSC32) @<< + $(BSC32_FLAGS) $(BSC32_SBRS) +<< + +LINK32=link.exe +LINK32_FLAGS=kernel32.lib user32.lib /nologo /dll /incremental:yes /pdb:"$(OUTDIR)\simple.pdb" /debug /machine:I386 /out:"../../../../bin/Debug/plugins/YAMN-filter/simple.dll" /implib:"$(OUTDIR)\simple.lib" +LINK32_OBJS= \ + "$(INTDIR)\maindll.obj" + +"..\..\..\..\bin\Debug\plugins\YAMN-filter\simple.dll" : "$(OUTDIR)" $(DEF_FILE) $(LINK32_OBJS) + $(LINK32) @<< + $(LINK32_FLAGS) $(LINK32_OBJS) +<< + +!ENDIF + + +!IF "$(NO_EXTERNAL_DEPS)" != "1" +!IF EXISTS("simple.dep") +!INCLUDE "simple.dep" +!ELSE +!MESSAGE Warning: cannot find "simple.dep" +!ENDIF +!ENDIF + + +!IF "$(CFG)" == "simple - Win32 Release" || "$(CFG)" == "simple - Win32 Debug" +SOURCE=.\maindll.cpp + +!IF "$(CFG)" == "simple - Win32 Release" + + +"$(INTDIR)\maindll.obj" : $(SOURCE) "$(INTDIR)" + + +!ELSEIF "$(CFG)" == "simple - Win32 Debug" + + +"$(INTDIR)\maindll.obj" "$(INTDIR)\maindll.sbr" : $(SOURCE) "$(INTDIR)" + + +!ENDIF + + +!ENDIF + diff --git a/protocols/YAMN/filter/readme.txt b/protocols/YAMN/filter/readme.txt new file mode 100644 index 0000000000..a46db0236a --- /dev/null +++ b/protocols/YAMN/filter/readme.txt @@ -0,0 +1 @@ +This folder contains filter plugin sources for YAMN. \ No newline at end of file diff --git a/protocols/YAMN/filterplugin.cpp b/protocols/YAMN/filterplugin.cpp new file mode 100644 index 0000000000..8f61003293 --- /dev/null +++ b/protocols/YAMN/filterplugin.cpp @@ -0,0 +1,204 @@ +/* + * YAMN plugin export functions for filtering + * + * (c) majvan 2002-2004 + */ + +#include "yamn.h" + +//-------------------------------------------------------------------------------------------------- +//-------------------------------------------------------------------------------------------------- + +PYAMN_FILTERPLUGINQUEUE FirstFilterPlugin=NULL; + +INT_PTR RegisterFilterPluginSvc(WPARAM,LPARAM); + +//Removes plugin from queue and deletes its structures +INT_PTR UnregisterFilterPlugin(HYAMNFILTERPLUGIN Plugin); + +INT_PTR UnregisterFilterPluginSvc(WPARAM wParam,LPARAM lParam); + +//Removes all filter plugins +INT_PTR UnregisterFilterPlugins(); + +INT_PTR FilterMailSvc(WPARAM,LPARAM); + +//Sets imported functions for an plugin and therefore it starts plugin to be registered and running +// Plugin- plugin, which wants to set its functions +// Importance- importance of plugin (see m_filterplugin.h) +// YAMNFilterFcn- pointer to imported functions +// YAMNfilterFcnVer- version of YAMN_FILTERIMPORTFCN, use YAMN_FILTERIMPORTFCNVERSION +// returns nonzero if success +int WINAPI SetFilterPluginFcnImportFcn(HYAMNFILTERPLUGIN Plugin,DWORD Importance,PYAMN_FILTERIMPORTFCN YAMNFilterFcn,DWORD YAMNFilterFcnVer); + +struct CExportedFunctions FilterPluginExportedFcn[]= +{ + {YAMN_SETFILTERPLUGINFCNIMPORTID,(void *)SetFilterPluginFcnImportFcn}, +}; + +struct CExportedServices FilterPluginExportedSvc[]= +{ + {MS_YAMN_REGISTERFILTERPLUGIN,RegisterFilterPluginSvc}, + {MS_YAMN_UNREGISTERFILTERPLUGIN,UnregisterFilterPluginSvc}, +}; + +//-------------------------------------------------------------------------------------------------- +//-------------------------------------------------------------------------------------------------- + +INT_PTR RegisterFilterPluginSvc(WPARAM wParam,LPARAM lParam) +{ + PYAMN_FILTERREGISTRATION Registration=(PYAMN_FILTERREGISTRATION)wParam; + HYAMNFILTERPLUGIN Plugin; + + if (lParam!=YAMN_FILTERREGISTRATIONVERSION) + return 0; + if ((Registration->Name==NULL) || (Registration->Ver==NULL)) + return NULL; + if (NULL==(Plugin=new YAMN_FILTERPLUGIN)) + return NULL; + + Plugin->PluginInfo=Registration; + + Plugin->FilterFcn=NULL; + +#ifdef DEBUG_SYNCHRO + DebugLog(SynchroFile,"::: YAMN- new filter registered: %0x (%s) :::\n",Plugin,Registration->Name); +#endif + return (INT_PTR)Plugin; +} + +INT_PTR UnregisterFilterPlugin(HYAMNFILTERPLUGIN Plugin) +{ + PYAMN_FILTERPLUGINQUEUE Parser,Found; + + if (FirstFilterPlugin->Plugin==Plugin) + { + Found=FirstFilterPlugin; + FirstFilterPlugin=FirstFilterPlugin->Next; + } + else + { + for (Parser=FirstFilterPlugin;(Parser->Next!=NULL) && (Plugin!=Parser->Next->Plugin);Parser=Parser->Next); + if (Parser->Next!=NULL) + { + Found=Parser->Next; + Parser->Next=Parser->Next->Next; + } + else + Found=NULL; + } + if (Found!=NULL) + { + if (Plugin->FilterFcn->UnLoadFcn!=NULL) + Plugin->FilterFcn->UnLoadFcn((void *)0); + + delete Found->Plugin; + delete Found; +#ifdef DEBUG_SYNCHRO + DebugLog(SynchroFile,"::: YAMN- filter %0x unregistered :::\n",Plugin); +#endif + } + else + return 0; + return 1; +} + +INT_PTR UnregisterFilterPluginSvc(WPARAM wParam,LPARAM lParam) +{ + HYAMNFILTERPLUGIN Plugin=(HYAMNFILTERPLUGIN)wParam; + + EnterCriticalSection(&PluginRegCS); + UnregisterFilterPlugin(Plugin); + LeaveCriticalSection(&PluginRegCS); + return 1; +} + +INT_PTR UnregisterFilterPlugins() +{ + EnterCriticalSection(&PluginRegCS); +//We remove protocols from the protocol list + while(FirstFilterPlugin!=NULL) + UnregisterFilterPlugin(FirstFilterPlugin->Plugin); + LeaveCriticalSection(&PluginRegCS); + return 1; +} + +int WINAPI SetFilterPluginFcnImportFcn(HYAMNFILTERPLUGIN Plugin,DWORD Importance,PYAMN_FILTERIMPORTFCN YAMNFilterFcn,DWORD YAMNFilterFcnVer) +{ + PYAMN_FILTERPLUGINQUEUE Parser,Previous; + + if (YAMNFilterFcnVer!=YAMN_FILTERIMPORTFCNVERSION) + return 0; + if (YAMNFilterFcn==NULL) + return 0; + +#ifdef DEBUG_SYNCHRO + DebugLog(SynchroFile,"::: YAMN- filter %0x import succeed :::\n",Plugin); +#endif + Plugin->Importance=Importance; + Plugin->FilterFcn=YAMNFilterFcn; + + EnterCriticalSection(&PluginRegCS); +//We add protocol to the protocol list + for (Previous=NULL,Parser=FirstFilterPlugin;Parser!=NULL && Parser->Next!=NULL && Parser->Plugin->Importance<=Importance;Previous=Parser,Parser=Parser->Next); + if (Previous==NULL) //insert to the beginnig of queue + { + FirstFilterPlugin=new YAMN_FILTERPLUGINQUEUE; + FirstFilterPlugin->Plugin=Plugin; + FirstFilterPlugin->Next=Parser; + } + else + { + Previous->Next=new YAMN_FILTERPLUGINQUEUE; + Previous=Previous->Next; //leave previous, go to actual plugin + Previous->Plugin=Plugin; + Previous->Next=Parser; //and in actual plugin set, that next plugin is the one we insert in front of + } + + LeaveCriticalSection(&PluginRegCS); + return 1; +} + +INT_PTR FilterMailSvc(WPARAM wParam,LPARAM lParam) +{ + HACCOUNT Account=(HACCOUNT)wParam; + HYAMNMAIL Mail=(HYAMNMAIL)lParam; + PYAMN_FILTERPLUGINQUEUE ActualPlugin; + + EnterCriticalSection(&PluginRegCS); +#ifdef DEBUG_SYNCHRO + DebugLog(SynchroFile,"FilterMail:ActualAccountMsgsSO-write wait\n"); +#endif + WaitToWriteFcn(Account->MessagesAccessSO); +#ifdef DEBUG_SYNCHRO + DebugLog(SynchroFile,"FilterMail:ActualAccountMsgsSO-write enter\n"); +#endif + for (ActualPlugin=FirstFilterPlugin;ActualPlugin!=NULL;ActualPlugin=ActualPlugin->Next) + { + if (ActualPlugin->Plugin->FilterFcn->FilterMailFcnPtr!=NULL) + { +#ifdef DEBUG_SYNCHRO + DebugLog(SynchroFile,"\tFiltering Mail, running plugin %0x to filter mail\n",ActualPlugin->Plugin); +#endif + ActualPlugin->Plugin->FilterFcn->FilterMailFcnPtr(Account,YAMN_ACCOUNTVERSION,Mail,YAMN_MAILVERSION); +#ifdef DEBUG_SYNCHRO + DebugLog(SynchroFile,"\tFiltering Mail done\n"); +#endif + } + } + Mail->Flags|=YAMN_MSG_FILTERED; + +//Set mail flags according to spamlevel settings + if ((Mail->Flags & YAMN_MSG_SPAMMASK) > YAMN_MSG_SPAML1) + Mail->Flags=Mail->Flags & ~(YAMN_MSG_BROWSER | YAMN_MSG_POPUP | YAMN_MSG_SYSTRAY | YAMN_MSG_SOUND | YAMN_MSG_APP | YAMN_MSG_NEVENT); + if (YAMN_MSG_SPAML(Mail->Flags,YAMN_MSG_SPAML3) || YAMN_MSG_SPAML(Mail->Flags,YAMN_MSG_SPAML4)) + Mail->Flags=Mail->Flags | (YAMN_MSG_AUTODELETE | YAMN_MSG_DELETEOK); //set message to delete + if (YAMN_MSG_SPAML(Mail->Flags,YAMN_MSG_SPAML3)) + Mail->Flags=Mail->Flags & ~(YAMN_MSG_MEMDELETE); //set message not to delete it immidiatelly from memory +#ifdef DEBUG_SYNCHRO + DebugLog(SynchroFile,"FilterMail:ActualAccountMsgsSO-write done\n"); +#endif + WriteDoneFcn(Account->MessagesAccessSO); + LeaveCriticalSection(&PluginRegCS); + return 1; +} diff --git a/protocols/YAMN/icons/iconttbup.ico b/protocols/YAMN/icons/iconttbup.ico new file mode 100644 index 0000000000..ad18c56822 Binary files /dev/null and b/protocols/YAMN/icons/iconttbup.ico differ diff --git a/protocols/YAMN/icons/icoyamn1.ico b/protocols/YAMN/icons/icoyamn1.ico new file mode 100644 index 0000000000..d3959b4fd7 Binary files /dev/null and b/protocols/YAMN/icons/icoyamn1.ico differ diff --git a/protocols/YAMN/icons/icoyamn2.ico b/protocols/YAMN/icons/icoyamn2.ico new file mode 100644 index 0000000000..dfada56b5f Binary files /dev/null and b/protocols/YAMN/icons/icoyamn2.ico differ diff --git a/protocols/YAMN/icons/proto_YAMN.rc b/protocols/YAMN/icons/proto_YAMN.rc new file mode 100644 index 0000000000..e20bd50bda --- /dev/null +++ b/protocols/YAMN/icons/proto_YAMN.rc @@ -0,0 +1,19 @@ +#include "resource.h" + + +///////////////////////////////////////////////////////////////////////////// +// +// Icon +// + +// Icon with lowest ID value placed first to ensure application icon +// remains consistent on all systems. + +IDI_ONLINE ICON DISCARDABLE "../resources/iconeutral.ico" +IDI_ICOYAMN1 ICON DISCARDABLE "icoyamn1.ico" +IDI_ICOYAMN2 ICON DISCARDABLE "icoyamn2.ico" +IDI_ICOTTBUP ICON DISCARDABLE "iconttbup.ico" + +IDI_OFFLINE ICON DISCARDABLE "../resources/icooffline.ico" +IDI_NA ICON DISCARDABLE "../resources/icoyamn3.ico" +IDI_OCCUPIED ICON DISCARDABLE "../resources/iconttbdown.ico" diff --git a/protocols/YAMN/icons/proto_YAMN_10.vcxproj b/protocols/YAMN/icons/proto_YAMN_10.vcxproj new file mode 100644 index 0000000000..a2f1f3c3af --- /dev/null +++ b/protocols/YAMN/icons/proto_YAMN_10.vcxproj @@ -0,0 +1,145 @@ + + + + + Debug + Win32 + + + Debug + x64 + + + Release + Win32 + + + Release + x64 + + + + Proto_YAMN + {C1CDB82C-6BBF-496E-88F4-CC57E60B0CA9} + + + + DynamicLibrary + Unicode + + + DynamicLibrary + Unicode + + + DynamicLibrary + Unicode + + + DynamicLibrary + Unicode + + + + + + + + + + + + + + + + + + + + + + + <_ProjectFileVersion>10.0.30319.1 + $(SolutionDir)$(Configuration)\Icons\ + $(SolutionDir)$(Configuration)64\Icons\ + $(SolutionDir)$(Configuration)\Obj\$(ProjectName)\ + $(SolutionDir)$(Configuration)64\Obj\$(ProjectName)\ + $(SolutionDir)$(Configuration)\Icons\ + $(SolutionDir)$(Configuration)64\Icons\ + $(SolutionDir)$(Configuration)\Obj\$(ProjectName)\ + $(SolutionDir)$(Configuration)64\Obj\$(ProjectName)\ + true + true + true + true + + + + NDEBUG;%(PreprocessorDefinitions) + ..\..\include\msapi + + + Windows + true + false + true + true + + + + + NDEBUG;%(PreprocessorDefinitions) + ..\..\include\msapi + + + Windows + true + false + true + true + + + + + _DEBUG;%(PreprocessorDefinitions) + ..\..\include\msapi + + + Windows + true + false + + + + + _DEBUG;%(PreprocessorDefinitions) + ..\..\include\msapi + + + Windows + true + false + + + + + + + + + + + + + + %(PreprocessorDefinitions) + %(PreprocessorDefinitions) + %(PreprocessorDefinitions) + %(PreprocessorDefinitions) + + + + + + \ No newline at end of file diff --git a/protocols/YAMN/icons/proto_YAMN_10.vcxproj.filters b/protocols/YAMN/icons/proto_YAMN_10.vcxproj.filters new file mode 100644 index 0000000000..ae56e318a4 --- /dev/null +++ b/protocols/YAMN/icons/proto_YAMN_10.vcxproj.filters @@ -0,0 +1,37 @@ + + + + + {4726e1d1-39cd-435a-bd59-51fdb6745f46} + ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe + + + + + Resource Files + + + Resource Files + + + Resource Files + + + Resource Files + + + Resource Files + + + Resource Files + + + Resource Files + + + + + Resource Files + + + \ No newline at end of file diff --git a/protocols/YAMN/icons/resource.h b/protocols/YAMN/icons/resource.h new file mode 100644 index 0000000000..af36adfdae --- /dev/null +++ b/protocols/YAMN/icons/resource.h @@ -0,0 +1,2 @@ +#include "../resources/resource.h" + diff --git a/protocols/YAMN/include/IcoLib.h b/protocols/YAMN/include/IcoLib.h new file mode 100644 index 0000000000..a911ba571d --- /dev/null +++ b/protocols/YAMN/include/IcoLib.h @@ -0,0 +1,26 @@ +typedef struct { + int cbSize; + char *pszSection; //section name used to group icons + char *pszDescription; //description for options dialog + char *pszName; //name to refer to icon when playing and in db + char *pszDefaultFile; //default icon file to use + int iDefaultIndex; +} SKINICONDESC; + +// +// Add a icon into options UI +// NB! pszName should be unique, e.g.: clistmw_apply, tabsrmm_history +// +// wParam = (WPARAM)0 +// lParam = (LPARAM)(SKINICONDESC*)sid; +// +#define MS_SKIN2_ADDICON "Skin2/Icons/AddIcon" +// +// Retrieve HICON with name specified in lParam +// Returned HICON SHOULDN'T be destroyed, it managed by IcoLib +// +#define MS_SKIN2_GETICON "Skin2/Icons/GetIcon" +// +// Icons change notification +// +#define ME_SKIN2_ICONSCHANGED "Skin2/IconsChanged" diff --git a/protocols/YAMN/mails/decode.cpp b/protocols/YAMN/mails/decode.cpp new file mode 100644 index 0000000000..867ed7ff25 --- /dev/null +++ b/protocols/YAMN/mails/decode.cpp @@ -0,0 +1,558 @@ +/* + * This code implements decoding encoded MIME header in style + * =?iso-8859-2?Q? "User using email in central Europe characters such as =E9" ?= + * + * (c) majvan 2002-2004 + */ +#include "../yamn.h" +//-------------------------------------------------------------------------------------------------- +//-------------------------------------------------------------------------------------------------- + +struct _tcptable CodePageNamesAll[]= +{ + { "ANSI", "",TRUE,CP_ACP}, + { "WINDOWS-1", "250",0,1250}, + { "WINDOWS-1", "251",0,1251}, + { "WINDOWS-1", "252",0,1252}, + { "WINDOWS-1", "253",0,1253}, + { "WINDOWS-1", "254",0,1254}, + { "WINDOWS-1", "255",0,1255}, + { "WINDOWS-1", "256",0,1256}, + { "WINDOWS-1", "257",0,1257}, + { "WINDOWS-1", "258",0,1258}, + { "CP1", "250",0,1250}, + { "CP1", "251",0,1251}, + { "CP1", "252",0,1252}, + { "CP1", "253",0,1253}, + { "CP1", "254",0,1254}, + { "CP1", "255",0,1255}, + { "CP1", "256",0,1256}, + { "CP1", "257",0,1257}, + { "CP1", "258",0,1258}, + { "ANSI-1", "250",0,1250}, + { "ANSI-1", "251",0,1251}, + { "ANSI-1", "252",0,1252}, + { "ANSI-1", "253",0,1253}, + { "ANSI-1", "254",0,1254}, + { "ANSI-1", "255",0,1255}, + { "ANSI-1", "256",0,1256}, + { "ANSI-1", "257",0,1257}, + { "ANSI-1", "258",0,1258}, + { "KOI8", "-R",0,20866}, + { "KOI8", "",0,20866}, + { "KOI8", "-U",0,21866}, + { "KOI8", "-RU",0,21866}, + { "US-", "ASCII",0,20127}, + { "CP", "367",0,20127}, + { "ASCII", "",0,20127}, + { "ASCII", "7",0,20127}, + { "ISO-8859", "-1",0,28591}, + { "ISO-8859", "-2",0,28592}, + { "ISO-8859", "-3",0,28593}, + { "ISO-8859", "-4",0,28594}, + { "ISO-8859", "-5",0,28595}, + { "ISO-8859", "-6",0,28596}, + { "ISO-8859", "-7",0,28597}, + { "ISO-8859", "-8",0,28598}, + { "ISO-8859", "-9",0,28599}, + { "ISO-8859", "-15",0,28605}, + { "ISO_8859", "-1",0,28591}, + { "ISO_8859", "-2",0,28592}, + { "ISO_8859", "-3",0,28593}, + { "ISO_8859", "-4",0,28594}, + { "ISO_8859", "-5",0,28595}, + { "ISO_8859", "-6",0,28596}, + { "ISO_8859", "-7",0,28597}, + { "ISO_8859", "-8",0,28598}, + { "ISO_8859", "-9",0,28599}, + { "ISO_8859", "-15",0,28605}, + { "ISO-", "10646-USC2",0,1200}, + { "ISO-2022", "/2-JP",0,50220}, + { "ISO-2022", "-JP",0,50221}, + { "ISO-2022", "/JIS-JP",0,50222}, + { "ISO-2022", "-KR",0,50225}, + { "ISO-2022", "-CH(SP)",0,50227}, + { "ISO-2022", "-CH(TR)",0,50229}, + { "UTF-", "7",0,65000}, + { "UTF-", "8",0,65001}, + { "ARAB-", "TRANSPARENT",0,710}, + { "ASMO-", "TRANSPARENT",0,720}, + { "ASMO-", "449",0,709}, + { "ASMO-", "708",0,708}, + { "BIG5", "",0,950}, + { "EUC-", "CH(SP)",0,51936}, + { "EUC-", "CH(TR)",0,51950}, + { "EUC-", "JP",0,51932}, + { "EUC-", "KR",0,51949}, + { "GB-", "2312",0,20936}, + { "GB", "2312",0,20936}, + { "HZGB-", "2312",0,52936}, + { "IBM-", "037",0,37}, + { "IBM-", "290",0,290}, + { "IBM-", "437",0,437}, + { "IBM-", "500",0,500}, + { "IBM-", "775",0,775}, + { "IBM-", "850",0,850}, + { "IBM-", "852",0,852}, + { "IBM-", "855",0,855}, + { "IBM-", "857",0,857}, + { "IBM-", "860",0,860}, + { "IBM-", "861",0,861}, + { "IBM-", "862",0,862}, + { "IBM-", "863",0,863}, + { "IBM-", "864",0,864}, + { "IBM-", "865",0,865}, + { "IBM-", "866",0,866}, + { "IBM-", "869",0,869}, + { "IBM-", "870",0,870}, + { "IBM-", "875",0,875}, + { "IBM-", "1026",0,1026}, + { "IBM-", "273",0,20273}, + { "IBM-", "277",0,20277}, + { "IBM-", "278",0,20278}, + { "IBM-", "280",0,20280}, + { "IBM-", "284",0,20284}, + { "IBM-", "285",0,20285}, + { "IBM-", "290",0,20290}, + { "IBM-", "297",0,20297}, + { "IBM-", "420",0,20420}, + { "IBM-", "423",0,20423}, + { "IBM-", "871",0,20871}, + { "IBM-", "880",0,20880}, + { "IBM-", "905",0,20905}, + { "IBM-", "THAI",0,20838}, + { "ISCII-", "DEVANAGARI",0,57002}, + { "ISCII-", "BENGALI",0,57003}, + { "ISCII-", "TAMIL",0,57004}, + { "ISCII-", "TELUGU",0,57005}, + { "ISCII-", "ASSAMESE",0,57006}, + { "ISCII-", "ORIYA",0,57007}, + { "ISCII-", "KANNADA",0,57008}, + { "ISCII-", "MALAYALAM",0,57009}, + { "ISCII-", "GUJARATI",0,57010}, + { "ISCII-", "PUNJABI",0,57011}, + { "KOR-", "JOHAB",0,1361}, + { "KSC-", "5601",0,1361}, + { "MAC-", "ROMAN",0,10000}, + { "MAC-", "JP",0,10001}, + { "MAC-", "CH(SP)(BIG5)",0,10002}, + { "MAC-", "KR",0,10003}, + { "MAC-", "AR",0,10004}, + { "MAC-", "HW",0,10005}, + { "MAC-", "GR",0,10006}, + { "MAC-", "CY",0,10007}, + { "MAC-", "CH(SP)(GB2312)",0,10008}, + { "MAC-", "ROMANIA",0,10010}, + { "MAC-", "UA",0,10017}, + { "MAC-", "TH",0,10021}, + { "MAC-", "LAT2",0,10029}, + { "MAC-", "ICE",0,10079}, + { "MAC-", "TR",0,10081}, + { "MAC-", "CR",0,10082} +}; + +int CPLENALL = (sizeof(CodePageNamesAll)/sizeof(CodePageNamesAll[0])); +struct _tcptable *CodePageNamesSupp; +int CPLENSUPP = 1; + +//Gets codepage ID from string representing charset such as "iso-8859-1" +// input- the string +// size- max length of input string +int GetCharsetFromString(char *input,size_t size); + +//HexValue to DecValue ('a' to 10) +// HexValue- hexa value ('a') +// DecValue- poiner where to store dec value +// returns 0 if not success +int FromHexa(char HexValue,char *DecValue); + +//Decodes a char from Base64 +// Base64Value- input char in Base64 +// DecValue- pointer where to store the result +// returns 0 if not success +int FromBase64(char Base64Value,char *DecValue); + +//Decodes string in quoted printable +// Src- input string +// Dst- where to store output string +// DstLen- how max long should be output string +// isQ- if is "Q-encoding" modification. should be TRUE in headers +// always returns 1 +int DecodeQuotedPrintable(char *Src,char *Dst,int DstLen, BOOL isQ); + +//Decodes string in base64 +// Src- input string +// Dst- where to store output string +// DstLen- how max long should be output string +// returns 0 if string was not properly decoded +int DecodeBase64(char *Src,char *Dst,int DstLen); + +//Converts string to unicode from string with specified codepage +// stream- input string +// cp- codepage of input string +// out- pointer to new allocated memory that contains unicode string +int ConvertStringToUnicode(char *stream,unsigned int cp,WCHAR **out); + +//Converts string from MIME header to unicode +// stream- input string +// cp- codepage of input string +// storeto- pointer to memory that contains unicode string +// mode- MIME_PLAIN or MIME_MAIL (MIME_MAIL deletes '"' from start and end of string) +void ConvertCodedStringToUnicode(char *stream,WCHAR **storeto,DWORD cp,int mode); + +//-------------------------------------------------------------------------------------------------- +//-------------------------------------------------------------------------------------------------- + +int GetCharsetFromString(char *input,size_t size) +//"ISO-8859-1" to ID from table +{ + char *pin=input; + char *pout,*parser; + + if ((size<1) || (parser=pout=new char[size+1])==NULL) + return -1; + while((*pin!=0) && (pin-input< (INT_PTR)size)) + { + if ((*pin>='a') && (*pin<='z')) + *parser++=*(pin++)-('a'-'A'); // make it capital + //else if (*pin=='\"') // this is already done in ExtractFromContentType + // *pin++; //skip the quotes if any + else + *parser++=*pin++; + } + + *parser=(char)0; + +#ifdef DEBUG_DECODECODEPAGE + DebugLog(DecodeFile,"%s",pout); +#endif + for (int i=0;i='0' && HexValue<='9') + { + *DecValue=HexValue-'0'; + return 1; + } + if (HexValue>='A' && HexValue<='F') + { + *DecValue=HexValue-'A'+10; + return 1; + } + if (HexValue>='a' && HexValue<='f') + { + *DecValue=HexValue-'a'+10; + return 1; + } + return 0; +} + +int FromBase64(char Base64Value,char *DecValue) +{ + if (Base64Value>='A' && Base64Value<='Z') + { + *DecValue=Base64Value-'A'; + return 1; + } + if (Base64Value>='a' && Base64Value<='z') + { + *DecValue=Base64Value-'a'+26; + return 1; + } + if (Base64Value>='0' && Base64Value<='9') + { + *DecValue=Base64Value-'0'+52; + return 1; + } + if (Base64Value=='+') + { + *DecValue=Base64Value-'+'+62; + return 1; + } + if (Base64Value=='/') + { + *DecValue=Base64Value-'/'+63; + return 1; + } + if (Base64Value=='=') + { + *DecValue=0; + return 1; + } + return 0; +} + +int DecodeQuotedPrintable(char *Src,char *Dst,int DstLen, BOOL isQ) +{ +#ifdef DEBUG_DECODEQUOTED + char *DstTemp=Dst; + DebugLog(DecodeFile,"%s",Src); +#endif + for (int Counter=0;((char)*Src!=0) && DstLen && (Counter++%s",DstTemp); +#endif + return 1; +} + +int DecodeBase64(char *Src,char *Dst,int DstLen) +{ + int Result=0; + char Locator=0,MiniResult[4]; + char *End=Dst+DstLen; + + MiniResult[0]=MiniResult[1]=MiniResult[2]=MiniResult[3]=0; + +#ifdef DEBUG_DECODEBASE64 + char *DstTemp=Dst; + DebugLog(DecodeFile,"\n%s\n\n",Src); +#endif + while(*Src!=0 && DstLen && Dst!=End) + { + if ((*Src==0x0D)||(*Src==0x0A)) { + Src++; + continue; + } + if ((!(Result=FromBase64(*Src,MiniResult+Locator)) && (*Src==0)) || Locator++==3) //end_of_str || end_of_4_bytes + { + Locator=0; //next write to the first byte + *Dst++=(char)((MiniResult[0]<<2) | (MiniResult[1]>>4)); + if (Dst==End) goto end; //DstLen exceeded? + *Dst++=(char)((MiniResult[1]<<4) | (MiniResult[2]>>2)); + if (Dst==End) goto end; //someones don't like goto, but not me + *Dst++=(char)((MiniResult[2]<<6) | MiniResult[3]); + if (!Result && (*Src==0)) goto end; //end of string? + MiniResult[0]=MiniResult[1]=MiniResult[2]=MiniResult[3]=0; //zero 4byte buffer for next loop + } + if (!Result) return 0; //unrecognised character occured + Src++; + } +end: + *Dst=0; +#ifdef DEBUG_DECODEBASE64 + DebugLog(DecodeFile,"\n%s\n",DstTemp); +#endif + return 1; +} + + + +int ConvertStringToUnicode(char *stream,unsigned int cp,WCHAR **out) +{ + CPINFO CPInfo; + WCHAR *temp,*src=*out,*dest; + size_t outlen; + int streamlen,Index; + + //codepages, which require to have set 0 in dwFlags parameter when calling MultiByteToWideChar + DWORD CodePagesZeroFlags[]={50220,50221,50222,50225,50227,50229,52936,54936,57002,57003,57004,57005,57006,57007,57008,57009,57010,57011,65000,65001}; + + if ((cp!=CP_ACP) && (cp!=CP_OEMCP) && (cp!=CP_MACCP) && (cp!=CP_THREAD_ACP) && (cp!=CP_SYMBOL) && (cp!=CP_UTF7) && (cp!=CP_UTF8) && !GetCPInfo(cp,&CPInfo)) + cp=CP_ACP; +#ifdef DEBUG_DECODECODEPAGE + DebugLog(DecodeFile,"%d",cp); +#endif + + for (Index=0;Index tempstoreLength) break; + start++; + } + } + tempstore[outind] = 0; + *storeto = tempstore; +} diff --git a/protocols/YAMN/mails/m_decode.h b/protocols/YAMN/mails/m_decode.h new file mode 100644 index 0000000000..e6d2b52fae --- /dev/null +++ b/protocols/YAMN/mails/m_decode.h @@ -0,0 +1,25 @@ +#ifndef __DECODE_H +#define __DECODE_H + +#include "../debug.h" + +#define DOTLINE(s) ((((s)[-2]=='\r') || ((s)[-2]=='\n')) && ((s)[-1]=='.') && (((s)[0]=='\r') || ((s)[0]=='\n') || ((s)[0]=='\0'))) // be careful, it's different to ESR's pop3.c ;-) +#define ENDLINE(s) (((s)[0]=='\r') || ((s)[0]=='\n')) //endline +#define WS(s) (((s)[0]==' ') || ((s)[0]=='\t')) //whitespace +#define ENDLINEWS(s) ((((s)[0]=='\r') || ((s)[0]=='\n')) && (((((s)[1]=='\r') || ((s)[1]=='\n')) && (((s)[2]==' ') || ((s)[2]=='\t'))) || (((s)[1]==' ') || ((s)[1]=='\t')))) //endline+whitespace: enters(CR or LF and their combinations) followed by space or tab +#define EOS(s) ((s)[0]==0) //end of string (stream) + +#define CODES(s) ((s[0]=='=') && (s[1]=='?')) //start of coded string +#define CODEE(s) ((s[0]=='?') && (s[1]=='=')) //end of coded string +#define CODED(s) (s[0]=='?') //code delimiter + +#define MIME_PLAIN 1 +#define MIME_MAIL 2 + +struct cptable +{ + char *name; + unsigned int ID; +}; + +#endif diff --git a/protocols/YAMN/mails/mails.cpp b/protocols/YAMN/mails/mails.cpp new file mode 100644 index 0000000000..af0f3d2329 --- /dev/null +++ b/protocols/YAMN/mails/mails.cpp @@ -0,0 +1,499 @@ +/* + * This code implements retrieving info from MIME header + * + * (c) majvan 2002-2004 + */ + +#pragma warning( disable : 4290 ) +#include "../yamn.h" + +//-------------------------------------------------------------------------------------------------- +//-------------------------------------------------------------------------------------------------- + +// SMALL INTRO +// Mails are queued in a queue (chained list). Pointer to first mail is pointed from Account structure +// member called Mails. +// Mail queue is ended with NULL- pointered mail (NULL handle) + +//Creates new mail for plugin (calling plugin's constructor, when plugin imported to YAMN) +INT_PTR CreateAccountMailSvc(WPARAM wParam,LPARAM lParam); + +//Deletes mail for plugin (calling plugin's destructor, when plugin imported to YAMN) +INT_PTR DeleteAccountMailSvc(WPARAM wParam,LPARAM lParam); + +//Loads mail data from standard storage to memory +INT_PTR LoadMailDataSvc(WPARAM wParam,LPARAM lParam); + +//Deletes mail data from memory +INT_PTR UnloadMailDataSvc(WPARAM wParam,LPARAM); + +//Saves mail data from memory to standard storage +INT_PTR SaveMailDataSvc(WPARAM wParam,LPARAM lParam); + +//Appends second MIME mail queue to the first one +//Only finds the end of first queue and its Next memember repoints to second one +void WINAPI AppendQueueFcn(HYAMNMAIL first,HYAMNMAIL second); + +//Synchronizes two accounts +//Function finds, if there were some mails deleted from mailbox and deletes (depends on RemovedOld param) them from OldQueue +//Next finds, if there are new mails. Mails that are still on mailbox are deleted (depends on RemovedNew param) from NewQueue +//After this, OldQueue is pointer to mails that are on mailbox, but not new mails +//and NewQueue contains new mails in account +//New accounts can be then appended to account mails queue, but they have set the New flag +// +//Two mails equals if they have the same ID +// +// hPlugin- handle of plugin going to delete mails +// OldQueue- queue of mails that we found on mailbox last time, after function finishes queue contains all mails except new ones +// RemovedOld- queue of mails where to store removed mails from OldQueue, if NULL deletes mails from OldQueue +// NewQueue- queue of mails that we found on mailbox (all mails), after function finishes queue contains only new mails +// RemovedNew- queue of mails where to store removed mails from NewQueue, if NULL deletes mails from NewQueue +//So function works like: +//1. delete (or move to RemovedOld queue if RemovedOld is not NULL) all mails from OldQueue not found in NewQueue +//2. delete (or move to RemovedNew queue if RemovedNew is not NULL) all mails from NewQueue found in OldQueue +void WINAPI SynchroMessagesFcn(HACCOUNT Account,HYAMNMAIL *OldQueue,HYAMNMAIL *RemovedOld,HYAMNMAIL *NewQueue,HYAMNMAIL *RemovedNew); + +//Deletes messages from mail From to the end +// Account- account who owns mails +// From- first mail in queue, which is going to delete +void WINAPI DeleteMessagesToEndFcn(HACCOUNT Account,HYAMNMAIL From); + +//Removes message from queue, does not delete from memory +// From- queue pointer +// Which- mail to delete +// mode- nonzero if you want to decrement numbers in messages that are bigger than the one in Which mail, 0 if not +void WINAPI DeleteMessageFromQueueFcn(HYAMNMAIL *From,HYAMNMAIL Which,int mode); + +//Finds message in queue that has the same ID number +// From- message queue +// ID- pointer to ID +// returns pointer to found message, NULL if not found +HYAMNMAIL WINAPI FindMessageByIDFcn(HYAMNMAIL From,char *ID); + +//Translate header from text to queue of CMimeItem structures +//This means that new queue will contain all info about headers +// stream- pointer to text containing header (can be ended with zero) +// len- length of stream +// head- function fills this pointer to first header item in queue +void WINAPI TranslateHeaderFcn(char *stream,int len,struct CMimeItem **head); + +//Creates new mail queue, copying only these mails, that have set flag for deleting +// From- message queue, whose mail with given flag are duplicated +// returns new mail queue (or NULL when no mail with flag is in From queue) +//Function does not copy the whole mails, it copies only ID string. And ID is copied as string, so +//you can use this fcn only if you have your ID as pointer to char string ended with zero character +HYAMNMAIL WINAPI CreateNewDeleteQueueFcn(HYAMNMAIL From); + +//Sets/removes flags from specific mails +// From- pointer to first message +// FlagsSet- mail must have set these flags... +// FlagsNotSet- ...and must not have set these flags... +// FlagsToSetRemove- ...to set/remove these flags (see mode) +// mode- nonzero to set, else remove +void WINAPI SetRemoveFlagsInQueueFcn(HYAMNMAIL From,DWORD FlagsSet,DWORD FlagsNotSet,DWORD FlagsToSetRemove,int mode); + +struct CExportedFunctions MailExportedFcn[]= +{ + {YAMN_SYNCHROMIMEMSGSID,(void *)SynchroMessagesFcn}, + {YAMN_TRANSLATEHEADERID,(void *)TranslateHeaderFcn}, + {YAMN_APPENDQUEUEID,(void *)AppendQueueFcn}, + {YAMN_DELETEMIMEQUEUEID,(void *)DeleteMessagesToEndFcn}, + {YAMN_DELETEMIMEMESSAGEID,(void *)DeleteMessageFromQueueFcn}, + {YAMN_FINDMIMEMESSAGEID,(void *)FindMessageByIDFcn}, + {YAMN_CREATENEWDELETEQUEUEID,(void *)CreateNewDeleteQueueFcn}, + {YAMN_SETREMOVEQUEUEFLAGSID,(void *)SetRemoveFlagsInQueueFcn}, +}; + +struct CExportedServices MailExportedSvc[]= +{ + {MS_YAMN_CREATEACCOUNTMAIL,CreateAccountMailSvc}, + {MS_YAMN_DELETEACCOUNTMAIL,DeleteAccountMailSvc}, + {MS_YAMN_LOADMAILDATA,LoadMailDataSvc}, + {MS_YAMN_UNLOADMAILDATA,UnloadMailDataSvc}, + {MS_YAMN_SAVEMAILDATA,SaveMailDataSvc}, +}; + + +//-------------------------------------------------------------------------------------------------- +//-------------------------------------------------------------------------------------------------- + +INT_PTR CreateAccountMailSvc(WPARAM wParam,LPARAM lParam) +{ + HACCOUNT Account=(HACCOUNT)wParam; + DWORD MailVersion=(DWORD)lParam; + HYAMNMAIL NewMail; + +//test if we are going to initialize members of suitable structure (structures of plugin and YAMN must match) + if (MailVersion!=YAMN_MAILVERSION) + return NULL; + + if (Account->Plugin!=NULL) + { + if (Account->Plugin->MailFcn->NewMailFcnPtr!=NULL) + { +//Let plugin create its own structure, which can be derived from CAccount structure + if (NULL==(NewMail=Account->Plugin->MailFcn->NewMailFcnPtr(Account,YAMN_MAILVERSION))) + return NULL; + } + else + { +//We suggest plugin uses standard CAccount structure, so we create it + if (NULL==(NewMail=new YAMNMAIL)) +//If not created successfully + return NULL; + NewMail->MailData=NULL; + } +//Init every members of structure, used by YAMN + return (INT_PTR)NewMail; + } + return NULL; +} + +INT_PTR DeleteAccountMailSvc(WPARAM wParam,LPARAM lParam) +{ + HYAMNPROTOPLUGIN Plugin=(HYAMNPROTOPLUGIN)wParam; + HYAMNMAIL OldMail=(HYAMNMAIL)lParam; + struct CMimeItem *TH; + + if (Plugin->MailFcn!=NULL){ + if (Plugin->MailFcn->DeleteMailFcnPtr!=NULL) { + //Let plugin delete its own CMimeMsgQueue derived structure + Plugin->MailFcn->DeleteMailFcnPtr(OldMail); + return 1; + } + } + if (OldMail->MailData!=NULL) { + if (OldMail->MailData->Body!=NULL) + delete[] OldMail->MailData->Body; + if ((TH=OldMail->MailData->TranslatedHeader)!=NULL) + for (;OldMail->MailData->TranslatedHeader!=NULL;) { + TH=TH->Next; + if (OldMail->MailData->TranslatedHeader->name!=NULL) + delete[] OldMail->MailData->TranslatedHeader->name; + if (OldMail->MailData->TranslatedHeader->value!=NULL) + delete[] OldMail->MailData->TranslatedHeader->value; + delete OldMail->MailData->TranslatedHeader; + OldMail->MailData->TranslatedHeader=TH; + } + delete OldMail->MailData; + } + if (OldMail->ID!=NULL) + delete[] OldMail->ID; + + delete OldMail; //consider mail as standard HYAMNMAIL, not initialized before and use its own destructor + return 1; +} + + +void WINAPI AppendQueueFcn(HYAMNMAIL first,HYAMNMAIL second) +{ + HYAMNMAIL Finder=first; + while(Finder->Next!=NULL) Finder=Finder->Next; + Finder->Next=second; +} + +INT_PTR LoadMailDataSvc(WPARAM wParam,LPARAM lParam) +{ + HYAMNMAIL Mail=(HYAMNMAIL)wParam; + DWORD MailVersion=(DWORD)lParam; + + if (MailVersion!=YAMN_MAILDATAVERSION) + return NULL; + +//now we have all data to memory persisting, so no loading is needed + return (INT_PTR)Mail->MailData; +} + +INT_PTR UnloadMailDataSvc(WPARAM wParam,LPARAM) +{ + HYAMNMAIL Mail=(HYAMNMAIL)wParam; + +//now we should delete structure from memory, but it will be made in future YAMN version + return 1; +} + +INT_PTR SaveMailDataSvc(WPARAM wParam,LPARAM lParam) +{ + HYAMNMAIL Mail=(HYAMNMAIL)wParam; + DWORD MailVersion=(DWORD)lParam; + + if (MailVersion!=YAMN_MAILDATAVERSION) + return (INT_PTR)-1; + +//now we have all data to memory persisting, so no saving is needed + return (INT_PTR)0; +} + +void WINAPI SynchroMessagesFcn(HACCOUNT Account,HYAMNMAIL *OldQueue,HYAMNMAIL *RemovedOld,HYAMNMAIL *NewQueue,HYAMNMAIL *RemovedNew) +//deletes messages from new queue, if they are old +//it also deletes messages from old queue, if they are not in mailbox anymore +//"YAMN_MSG_DELETED" messages in old queue remain in old queue (are never removed, although they are not in new queue) +//"YAMN_MSG_DELETED" messages in new queue remain in new queue (are never removed, although they can be in old queue) +{ + HYAMNMAIL Finder,FinderPrev; + HYAMNMAIL Parser,ParserPrev; + HYAMNMAIL RemovedOldParser =NULL; + HYAMNMAIL RemovedNewParser =NULL; + if (RemovedOld!=NULL) *RemovedOld=NULL; + if (RemovedNew!=NULL) *RemovedNew=NULL; + + for (FinderPrev=NULL,Finder=*OldQueue;Finder!=NULL;) + { + if (Finder->Flags & YAMN_MSG_DELETED) //if old queue contains deleted mail + { + FinderPrev=Finder; + Finder=Finder->Next; //get next message in old queue for testing + continue; + } + for (ParserPrev=NULL,Parser=*NewQueue;Parser!=NULL;ParserPrev=Parser,Parser=Parser->Next) + { + if (Parser->Flags & YAMN_MSG_DELETED) + continue; + + if (Parser->ID==NULL) //simply ignore the message, that has not filled its ID + continue; + + if (0==strcmp(Parser->ID,Finder->ID)) //search for equal message in new queue + break; + } + if (Parser!=NULL) //found equal message in new queue + { + if (Parser==*NewQueue) + *NewQueue=(*NewQueue)->Next; + else + ParserPrev->Next=Parser->Next; + Finder->Number=Parser->Number; //rewrite the number of current message in old queue + + if (RemovedNew==NULL) //delete from new queue + DeleteAccountMailSvc((WPARAM)Account->Plugin,(LPARAM)Parser); + else //or move to RemovedNew + { + if (RemovedNewParser==NULL) //if it is first mail removed from NewQueue + *RemovedNew=Parser; //set RemovedNew queue to point to first message in removed queue + else + RemovedNewParser->Next=Parser; //else don't forget to show to next message in RemovedNew queue + RemovedNewParser=Parser; //follow RemovedNew queue + RemovedNewParser->Next=NULL; + } + FinderPrev=Finder; + Finder=Finder->Next; //get next message in old queue for testing + } + else //a message was already deleted from mailbox + { + if (Finder==*OldQueue) //if we are at the first item in OldQueue + { + *OldQueue=(*OldQueue)->Next; //set OldQueue to next item + if (RemovedOld==NULL) //delete from old queue + DeleteAccountMailSvc((WPARAM)Account->Plugin,(LPARAM)Finder); + else //or move to RemovedOld + { + if (RemovedOldParser==NULL) //if it is first mail removed from OldQueue + *RemovedOld=Finder; //set RemovedOld queue to point to first message in removed queue + else + RemovedOldParser->Next=Finder; //else don't forget to show to next message in RemovedNew queue + RemovedOldParser=Finder; //follow RemovedOld queue + RemovedOldParser->Next=NULL; + } + Finder=*OldQueue; + } + else + { + FinderPrev->Next=Finder->Next; + if (RemovedOld==NULL) //delete from old queue + DeleteAccountMailSvc((WPARAM)Account->Plugin,(LPARAM)Finder); + else //or move to RemovedOld + { + if (RemovedOldParser==NULL) //if it is first mail removed from OldQueue + *RemovedOld=Finder; //set RemovedOld queue to point to first message in removed queue + else + RemovedOldParser->Next=Finder; //else don't forget to show to next message in RemovedNew queue + RemovedOldParser=Finder; //follow RemovedOld queue + RemovedOldParser->Next=NULL; + } + Finder=FinderPrev->Next; + } + } + } +} + +void WINAPI DeleteMessagesToEndFcn(HACCOUNT Account,HYAMNMAIL From) +{ + HYAMNMAIL Temp; + while(From!=NULL) + { + Temp=From; + From=From->Next; + DeleteAccountMailSvc((WPARAM)Account->Plugin,(LPARAM)Temp); + } +} + +void WINAPI DeleteMessageFromQueueFcn(HYAMNMAIL *From,HYAMNMAIL Which,int mode=0) +{ + DWORD Number=Which->Number; + HYAMNMAIL Parser; + + if (*From==Which) + { + Parser=Which->Next; + *From=Parser; + } + else + { + for (Parser=*From;Which!=Parser->Next;Parser=Parser->Next) + if (mode && (Parser->Number>Number)) Parser->Number--; + if (mode && (Parser->Number>Number)) Parser->Number--; + Parser->Next=Parser->Next->Next; + Parser=Which->Next; + } + if (mode) + for (;Parser!=NULL;Parser=Parser->Next) + if (Parser->Number>Number) Parser->Number--; +} + +void DeleteMessagesFromQueue(HYAMNMAIL *From,HYAMNMAIL Which,int mode=0) +{ + HYAMNMAIL Parser; + + for (Parser=Which;Parser!=NULL;Parser=Parser->Next) + DeleteMessageFromQueueFcn(From,Parser,mode); +} + +HYAMNMAIL WINAPI FindMessageByIDFcn(HYAMNMAIL From,char *ID) +{ + HYAMNMAIL Browser; + + for (Browser=From;Browser!=NULL;Browser=Browser->Next) + if (0==lstrcmpA(Browser->ID,ID)) + break; + return Browser; +} + +void WINAPI TranslateHeaderFcn(char *stream,int len,struct CMimeItem **head) +{ + try + { + char *finder=stream; + char *prev1,*prev2,*prev3; + struct CMimeItem *Item=NULL; + + while(finder<=(stream+len)) + { + while(ENDLINEWS(finder)) finder++; + + //at the start of line + if (DOTLINE(finder+1)) //at the end of stream + break; + + prev1=finder; + + while(*finder!=':' && !EOS(finder)) finder++; + if (!EOS(finder)) + prev2=finder++; + else + break; + + while(WS(finder) && !EOS(finder)) finder++; + if (!EOS(finder)) + prev3=finder; + else + break; + + do + { + if (ENDLINEWS(finder)) finder+=2; //after endline information continues + while(!ENDLINE(finder) && !EOS(finder)) finder++; + }while(ENDLINEWS(finder)); + + if (Item!=NULL) + { + if (NULL==(Item->Next=new struct CMimeItem)) + break; + Item=Item->Next; + } + else + { + Item = new CMimeItem; + *head = Item; + } + + Item->Next=NULL; + Item->name=new char [prev2-prev1+1]; + lstrcpynA(Item->name,prev1,prev2-prev1+1); + Item->value=new char [finder-prev3+1]; + lstrcpynA(Item->value,prev3,finder-prev3+1); + + if (EOS(finder)) + break; + finder++; + if (ENDLINE(finder)) { + finder++; + if (ENDLINE(finder)) { + // end of headers. message body begins + finder++; + if (ENDLINE(finder))finder++; + prev1 = finder; + while (!DOTLINE(finder+1))finder++; + if (ENDLINE(finder))finder--; + prev2 = finder; + if (prev2>prev1){ // yes, we have body + if (NULL==(Item->Next=new struct CMimeItem)) break; // Cant create new item?! + Item=Item->Next; + Item->Next=NULL;//just in case; + Item->name=new char[5]; strncpy(Item->name,"Body",5); + Item->value=new char [prev2-prev1]; + lstrcpynA(Item->value,prev1,prev2-prev1-1); + } + break; // there is nothing else + } + } + } + } + catch(...) + { + MessageBoxA(NULL,"Translate header error","",0); + } +} + +HYAMNMAIL WINAPI CreateNewDeleteQueueFcn(HYAMNMAIL From) +{ + HYAMNMAIL FirstMail,Browser; + + for (FirstMail=NULL;From!=NULL;From=From->Next) + { + if ((From->Flags & (YAMN_MSG_USERDELETE | YAMN_MSG_AUTODELETE)) && !(From->Flags & YAMN_MSG_DELETED)) + { + if (FirstMail==NULL) + { + FirstMail=Browser=new YAMNMAIL; + if (FirstMail==NULL) + break; + } + else + { + Browser->Next=new YAMNMAIL; + Browser=Browser->Next; + } + Browser->ID=new char[strlen(From->ID)+1]; + strcpy(Browser->ID,From->ID); + Browser->Number=From->Number; + Browser->Flags=From->Flags; + } + } + return FirstMail; +} + +void WINAPI SetRemoveFlagsInQueueFcn(HYAMNMAIL From,DWORD FlagsSet,DWORD FlagsNotSet,DWORD FlagsToSetRemove,int mode) +{ + HYAMNMAIL msgq; + + for (msgq=(HYAMNMAIL)From;msgq!=NULL;msgq=msgq->Next) + { + if ((FlagsSet==(msgq->Flags & FlagsSet)) && (0==(msgq->Flags & FlagsNotSet))) + { + if (mode) + msgq->Flags=msgq->Flags | FlagsToSetRemove; + else + msgq->Flags=msgq->Flags & ~FlagsToSetRemove; + } + } +} diff --git a/protocols/YAMN/mails/mime.cpp b/protocols/YAMN/mails/mime.cpp new file mode 100644 index 0000000000..2a66b80e2b --- /dev/null +++ b/protocols/YAMN/mails/mime.cpp @@ -0,0 +1,732 @@ +/* + * This code implements retrieving info from MIME header + * + * (c) majvan 2002-2004 + */ + +#pragma warning( disable : 4290 ) +#include "../yamn.h" + +//- imported --------------------------------------------------------------------------------------- +//-------------------------------------------------------------------------------------------------- + +extern SWMRG *AccountBrowserSO; +extern struct WndHandles *MessageWnd; + +extern int GetCharsetFromString(char *input,size_t size); +extern void SendMsgToRecepients(struct WndHandles *FirstWin,UINT msg,WPARAM wParam,LPARAM lParam); +extern void ConvertCodedStringToUnicode(char *stream,WCHAR **storeto,DWORD cp,int mode); +extern DWORD WINAPI MailBrowser(LPVOID Param); +extern DWORD WINAPI NoNewMailProc(LPVOID Param); +extern DWORD WINAPI BadConnection(LPVOID Param); + +//-------------------------------------------------------------------------------------------------- +//-------------------------------------------------------------------------------------------------- + +//Copies one string to another +// srcstart- source string +// srcend- address to the end of source string +// dest- pointer that stores new allocated string that contains copy of source string +// mode- MIME_PLAIN or MIME_MAIL (MIME_MAIL deletes '"' characters (or '<' and '>') if they are at start and end of source string +void CopyToHeader(char *srcstart,char *srcend,char **dest,int mode); + +//Extracts email address (finds nick name and mail and then stores them to strings) +// finder- source string +// storeto- pointer that receives address of mail string +// storetonick- pointer that receives address of nickname +void ExtractAddressFromLine(char *finder,char **storeto,char **storetonick); + +//Extracts simple text from string +// finder- source string +// storeto- pointer that receives address of string +void ExtractStringFromLine(char *finder,char **storeto); + +//Extracts some item from content-type string +//Example: ContentType string: "TEXT/PLAIN; charset=US-ASCII", item:"charset=", returns: "US-ASCII" +// ContetType- content-type string +// value- string item +// returns extracted string (or NULL when not found) +char *ExtractFromContentType(char *ContentType,char *value); + +//Extracts info from header text into header members +//Note that this function as well as struct CShortHeadwer can be always changed, because there are many items to extract +//(e.g. the X-Priority and Importance and so on) +// items- translated header (see TranslateHeaderFcn) +// head- header to be filled with values extracted from items +void ExtractShortHeader(struct CMimeItem *items,struct CShortHeader *head); + +//Extracts header to mail using ExtractShortHeader fcn. +// items- translated header (see TranslateHeaderFcn) +// CP- codepage used when no default found +// head- header to be filled with values extracted from items, in unicode (wide char) +void ExtractHeader(struct CMimeItem *items,int &CP,struct CHeader *head); + +//Deletes items in CShortHeader structure +// head- structure whose items are deleted +void DeleteShortHeaderContent(struct CShortHeader *head); + +//Deletes list of YAMN_MIMENAMES structures +// Names- pointer to first item of list +void DeleteNames(PYAMN_MIMENAMES Names); + +//Deletes list of YAMN_MIMESHORTNAMES structures +// Names- pointer to first item of list +void DeleteShortNames(PYAMN_MIMESHORTNAMES Names); + +//Makes a string lowercase +// string- string to be lowercased +void inline ToLower(char *string); + +//-------------------------------------------------------------------------------------------------- +//-------------------------------------------------------------------------------------------------- + +void CopyToHeader(char *srcstart,char *srcend,char **dest,int mode) +{ + char *dst; + + if (dest==NULL) + return; + if (srcstart>=srcend) + return; + + if ((mode==MIME_MAIL) && (((*srcstart=='"') && (*(srcend-1)=='"')) || ((*srcstart=='<') && (*(srcend-1)=='>')))) + { + srcstart++; + srcend--; + } + + if (srcstart>=srcend) + return; + + if (NULL!=*dest) + delete[] *dest; + if (NULL==(*dest=new char[srcend-srcstart+1])) + return; + + dst=*dest; + + for (;srcstart' at the end of line + CopyToHeader(finder,finderend+1,storeto,MIME_MAIL); + else //at the end of line, there's '>' + { + char *finder2=finderend; + while((*finder2!='<') && (finder2>finder)) finder2--; //go to matching '<' or to the start + CopyToHeader(finder2,finderend+1,storeto,MIME_MAIL); + if (*finder2=='<') //if we found '<', the rest copy as from nick + { + finder2--; + while(WS(finder2) || ENDLINE(finder2)) finder2--; //parse whitespace + CopyToHeader(finder,finder2+1,storetonick,MIME_MAIL); //and store nickname + } + } + } + else + { + char *finderend=finder+1; + do + { + if (ENDLINEWS(finderend)) //after endline information continues + finderend+=2; + while(!ENDLINE(finderend) && (*finderend!='>') && !EOS(finderend)) finderend++; //seek to the matching < or to the end of line or to the end of string + }while(ENDLINEWS(finderend)); + CopyToHeader(finder,finderend+1,storeto,MIME_MAIL); //go to first '>' or to the end and copy + finder=finderend+1; + while(WS(finder)) finder++; //parse whitespace + if (!ENDLINE(finder) && !EOS(finder)) //if there are chars yet, it's nick + { + finderend=finder+1; + while(!ENDLINE(finderend) && !EOS(finderend)) finderend++; //seek to the end of line or to the end of string + finderend--; + while(WS(finderend)) finderend--; //find the end of line, no whitespace + CopyToHeader(finder,finderend+1,storetonick,MIME_MAIL); + } + } +} + +void ExtractStringFromLine(char *finder,char **storeto) +{ + if (finder==NULL) + { + *storeto=NULL; + return; + } + while(WS(finder)) finder++; + char *finderend=finder; + + do + { + if (ENDLINEWS(finderend)) finderend++; //after endline information continues + while(!ENDLINE(finderend) && !EOS(finderend)) finderend++; + }while(ENDLINEWS(finderend)); + finderend--; + while(WS(finderend)) finderend--; //find the end of line, no whitespace + CopyToHeader(finder,finderend+1,storeto,MIME_PLAIN); +} + +char *ExtractFromContentType(char *ContentType,char *value) +{ + char *lowered = _strdup(ContentType); + ToLower(lowered); + char *finder=strstr(lowered,value); + if (finder==NULL){ + free (lowered); + return NULL; + } + finder = finder-lowered+ContentType; + free (lowered); + + char *temp,*copier; + char *CopiedString; + + temp=finder-1; + while((temp>ContentType) && WS(temp)) temp--; //now we have to find, if the word "Charset=" is located after ';' like "; Charset=" + if (*temp!=';' && !ENDLINE(temp) && temp!=ContentType) + return NULL; + finder=finder+strlen(value); //jump over value string + + while(WS(finder)) finder++; //jump over whitespaces + temp=finder; + while(*temp!=0 && *temp!=';') temp++; //jump to the end of setting (to the next ;) + temp--; + while(WS(temp)) temp--; //remove whitespaces from the end + if (*finder=='\"') { //remove heading and tailing quotes + finder++; + if (*temp=='\"') temp--; + } + if (NULL==(CopiedString=new char[++temp-finder+1])) + return NULL; + for (copier=CopiedString;finder!=temp;*copier++=*finder++); //copy string + *copier=0; //and end it with zero character + + return CopiedString; +} + +void ExtractShortHeader(struct CMimeItem *items,struct CShortHeader *head) +{ + for (;items!=NULL;items=items->Next) + { + //at the start of line + //MessageBox(NULL,items->value,items->name,0); + if (0==_strnicmp(items->name,"From",4)) + { + if (items->value==NULL) + continue; + #ifdef DEBUG_DECODE + DebugLog(DecodeFile,""); + #endif + ExtractAddressFromLine(items->value,&head->From,&head->FromNick); + #ifdef DEBUG_DECODE + DebugLog(DecodeFile,"\n"); + #endif + } + else if (0==_strnicmp(items->name,"Return-Path",11)) + { + if (items->value==NULL) + continue; + #ifdef DEBUG_DECODE + DebugLog(DecodeFile,""); + #endif + ExtractAddressFromLine(items->value,&head->ReturnPath,&head->ReturnPathNick); + #ifdef DEBUG_DECODE + DebugLog(DecodeFile,"\n"); + #endif + } + else if (0==_strnicmp(items->name,"Subject",7)) + { + if (items->value==NULL) + continue; + #ifdef DEBUG_DECODE + DebugLog(DecodeFile,""); + #endif + ExtractStringFromLine(items->value,&head->Subject); + #ifdef DEBUG_DECODE + DebugLog(DecodeFile,"\n"); + #endif + } + else if (0==_strnicmp(items->name,"Body",4)) + { + if (items->value==NULL) + continue; + #ifdef DEBUG_DECODE + DebugLog(DecodeFile,""); + #endif + ExtractStringFromLine(items->value,&head->Body); + #ifdef DEBUG_DECODE + DebugLog(DecodeFile,"\n"); + #endif + } + else if (0==_strnicmp(items->name,"Date",4)) + { + if (items->value==NULL) + continue; + #ifdef DEBUG_DECODE + DebugLog(DecodeFile,""); + #endif + ExtractStringFromLine(items->value,&head->Date); + #ifdef DEBUG_DECODE + DebugLog(DecodeFile,"\n"); + #endif + } + else if (0==_strnicmp(items->name,"Content-Type",12)) + { + if (items->value==NULL) + continue; + + char *ContentType=NULL,*CharSetStr; + #ifdef DEBUG_DECODE + DebugLog(DecodeFile,""); + #endif + ExtractStringFromLine(items->value,&ContentType); + #ifdef DEBUG_DECODE + DebugLog(DecodeFile,"\n"); + #endif + ToLower(ContentType); + if (NULL!=(CharSetStr=ExtractFromContentType(ContentType,"charset="))) + { + head->CP=GetCharsetFromString(CharSetStr,strlen(CharSetStr)); + delete[] CharSetStr; + } + delete[] ContentType; + } + else if (0==_strnicmp(items->name,"Importance",10)) + { + if (items->value==NULL) + continue; + #ifdef DEBUG_DECODE + DebugLog(DecodeFile,""); + #endif + if (head->Priority!=-1) + { + if (0==strncmp(items->value,"low",3)) + head->Priority=5; + else if (0==strncmp(items->value,"normal",6)) + head->Priority=3; + else if (0==strncmp(items->value,"high",4)) + head->Priority=1; + } + #ifdef DEBUG_DECODE + DebugLog(DecodeFile,"\n"); + #endif + } + else if (0==_strnicmp(items->name,"X-Priority",10)) + { + if (items->value==NULL) + continue; + #ifdef DEBUG_DECODE + DebugLog(DecodeFile,""); + #endif + if ((*items->value>='1') && (*items->value<='5')) + head->Priority=*items->value-'0'; + #ifdef DEBUG_DECODE + DebugLog(DecodeFile,"\n"); + #endif + } + + } +} + +void ExtractHeader(struct CMimeItem *items,int &CP,struct CHeader *head) +{ + struct CShortHeader ShortHeader; + + ZeroMemory(&ShortHeader,sizeof(struct CShortHeader)); + ShortHeader.Priority=ShortHeader.CP=-1; + #ifdef DEBUG_DECODE + DebugLog(DecodeFile,"\n"); + #endif + ExtractShortHeader(items,&ShortHeader); + + head->Priority=ShortHeader.Priority==-1 ? 3 : ShortHeader.Priority; + CP=ShortHeader.CP==-1 ? CP : ShortHeader.CP; + #ifdef DEBUG_DECODE + if (NULL!=ShortHeader.From) + DebugLog(DecodeFile,"%s%s%s%s%s%s\n"); + DebugLog(DecodeFile,"\n"); + #endif + + ConvertCodedStringToUnicode(ShortHeader.From,&head->From,CP,MIME_PLAIN); + + #ifdef DEBUG_DECODE + if (NULL!=head->From) + DebugLogW(DecodeFile,L"%s\n",head->From); + #endif + ConvertCodedStringToUnicode(ShortHeader.FromNick,&head->FromNick,CP,MIME_MAIL); + #ifdef DEBUG_DECODE + if (NULL!=head->FromNick) + DebugLogW(DecodeFile,L"%s\n",head->FromNick); + #endif + ConvertCodedStringToUnicode(ShortHeader.ReturnPath,&head->ReturnPath,CP,MIME_PLAIN); + #ifdef DEBUG_DECODE + if (NULL!=head->ReturnPath) + DebugLogW(DecodeFile,L"%s\n",head->ReturnPath); + #endif + ConvertCodedStringToUnicode(ShortHeader.ReturnPathNick,&head->ReturnPathNick,CP,MIME_MAIL); + #ifdef DEBUG_DECODE + if (NULL!=head->ReturnPathNick) + DebugLogW(DecodeFile,L"%s\n",head->ReturnPathNick); + #endif + ConvertCodedStringToUnicode(ShortHeader.Subject,&head->Subject,CP,MIME_PLAIN); + #ifdef DEBUG_DECODE + if (NULL!=head->Subject) + DebugLogW(DecodeFile,L"%s\n",head->Subject); + #endif + ConvertCodedStringToUnicode(ShortHeader.Date,&head->Date,CP,MIME_PLAIN); + #ifdef DEBUG_DECODE + if (NULL!=head->Date) + DebugLogW(DecodeFile,L"%s\n",head->Date); + #endif + + ConvertCodedStringToUnicode(ShortHeader.Body,&head->Body,CP,MIME_PLAIN); + #ifdef DEBUG_DECODE + if (NULL!=head->Body) + DebugLogW(DecodeFile,L"%s\n",head->Body); + #endif + + #ifdef DEBUG_DECODE + DebugLog(DecodeFile,"\n"); + #endif + + DeleteShortHeaderContent(&ShortHeader); + +// head->From=L"Frommmm"; +// head->Subject=L"Subject"; + return; +} + +void DeleteShortHeaderContent(struct CShortHeader *head) +{ + if (head->From!=NULL) delete[] head->From; + if (head->FromNick!=NULL) delete[] head->FromNick; + if (head->ReturnPath!=NULL) delete[] head->ReturnPath; + if (head->ReturnPathNick!=NULL) delete[] head->ReturnPathNick; + if (head->Subject!=NULL) delete[] head->Subject; + if (head->Date!=NULL) delete[] head->Date; + if (head->To!=NULL) DeleteShortNames(head->To); + if (head->Cc!=NULL) DeleteShortNames(head->Cc); + if (head->Bcc!=NULL) DeleteShortNames(head->Bcc); + if (head->Body!=NULL) delete[] head->Body; +} + +void DeleteHeaderContent(struct CHeader *head) +{ + if (head->From!=NULL) delete[] head->From; + if (head->FromNick!=NULL) delete[] head->FromNick; + if (head->ReturnPath!=NULL) delete[] head->ReturnPath; + if (head->ReturnPathNick!=NULL) delete[] head->ReturnPathNick; + if (head->Subject!=NULL) delete[] head->Subject; + if (head->Date!=NULL) delete[] head->Date; + if (head->Body!=NULL) delete[] head->Body; + if (head->To!=NULL) DeleteNames(head->To); + if (head->Cc!=NULL) DeleteNames(head->Cc); + if (head->Bcc!=NULL) DeleteNames(head->Bcc); +} + +void DeleteNames(PYAMN_MIMENAMES Names) +{ + PYAMN_MIMENAMES Parser=Names,Old; + for (;Parser!=NULL;Parser=Parser->Next) + { + if (Parser->Value!=NULL) + delete[] Parser->Value; + if (Parser->ValueNick!=NULL) + delete[] Parser->ValueNick; + Old=Parser; + Parser=Parser->Next; + delete Old; + } +} + +void DeleteShortNames(PYAMN_MIMESHORTNAMES Names) +{ + PYAMN_MIMESHORTNAMES Parser=Names,Old; + for (;Parser!=NULL;Parser=Parser->Next) + { + if (Parser->Value!=NULL) + delete[] Parser->Value; + if (Parser->ValueNick!=NULL) + delete[] Parser->ValueNick; + Old=Parser; + Parser=Parser->Next; + delete Old; + } +} + + +void inline ToLower(char *string) +{ + for (;*string!=0;string++) + if (*string>='A' && *string<='Z') *string=*string-'A'+'a'; +} + +#define TE_UNKNOWN +#define TE_QUOTEDPRINTABLE 1 +#define TE_BASE64 2 +struct APartDataType +{ + char *Src;//Input + char *ContType; + int CodePage; + char *TransEnc; + BYTE TransEncType; //TE_something + char *body; + int bodyLen; + WCHAR *wBody; +}; + + +void ParseAPart(APartDataType *data) +{ + size_t len = strlen(data->Src); + try + { + char *finder=data->Src; + char *prev1,*prev2,*prev3; + + while(finder<=(data->Src+len)) + { + while(ENDLINEWS(finder)) finder++; + + //at the start of line + if (finder>data->Src){ + if (*(finder-2)=='\r' || *(finder-2)=='\n') + *(finder-2)=0; + if (*(finder-1)=='\r' || *(finder-1)=='\n') + *(finder-1)=0; + } + prev1=finder; + + while(*finder!=':' && !EOS(finder) && !ENDLINE(finder)) finder++; + if (ENDLINE(finder)||EOS(finder)) { + // no ":" in the line? here the body begins; + data->body = prev1; + break; + } + prev2=finder++; + + while(WS(finder) && !EOS(finder)) finder++; + if (!EOS(finder)) + prev3=finder; + else + break; + + do + { + if (ENDLINEWS(finder)) finder+=2; //after endline information continues + while(!ENDLINE(finder) && !EOS(finder)) finder++; + }while(ENDLINEWS(finder)); + + if (!_strnicmp(prev1,"Content-type",prev2-prev1)) { + data->ContType = prev3; + } else if (!_strnicmp(prev1,"Content-Transfer-Encoding",prev2-prev1)) { + data->TransEnc = prev3; + } + + if (EOS(finder)) + break; + finder++; + if (ENDLINE(finder)) { + finder++; + if (ENDLINE(finder)) { + // end of headers. message body begins + if (finder>data->Src){ + if (*(finder-2)=='\r' || *(finder-2)=='\n') + *(finder-2)=0; + if (*(finder-1)=='\r' || *(finder-1)=='\n') + *(finder-1)=0; + } + finder++; + if (ENDLINE(finder))finder++; + prev1 = finder; + while (!EOS(finder+1))finder++; + if (ENDLINE(finder))finder--; + prev2 = finder; + if (prev2>prev1){ // yes, we have body + data->body = prev1; + } + break; // there is nothing else + } + } + } + } + catch(...) + { + MessageBox(NULL,_T("Translate header error"),_T(""),0); + } + if (data->body) data->bodyLen = (int)strlen(data->body); +} + +//from decode.cpp +int DecodeQuotedPrintable(char *Src,char *Dst,int DstLen, BOOL isQ); +int DecodeBase64(char *Src,char *Dst,int DstLen); +int ConvertStringToUnicode(char *stream,unsigned int cp,WCHAR **out); + +WCHAR *ParseMultipartBody(char *src, char *bond) +{ + char *srcback = _strdup(src); + size_t sizebond = strlen(bond); + int numparts = 1; + int i; + char *courbond = srcback; + WCHAR *dest; + for (;(courbond=strstr(courbond,bond));numparts++,courbond+=sizebond); + APartDataType *partData = new APartDataType[numparts]; + memset(partData, 0, sizeof(APartDataType)*numparts); + partData[0].Src = courbond = srcback; + for (i=1;(courbond=strstr(courbond,bond));i++,courbond+=sizebond){ + *(courbond-2) = 0; + partData[i].Src = courbond+sizebond; + while (ENDLINE(partData[i].Src)) partData[i].Src++; + } + size_t resultSize=0; + for (i=0;i +Delivered-To: pablo@decode.com.ar +Received: (qmail 5438 invoked by uid 618); 5 Sep 2003 19:49:16 -0000 +Mailing-List: contact foromundial-help@decode.com.ar; run by ezmlm +Precedence: bulk +X-No-Archive: yes +List-Post: +List-Help: +List-Unsubscribe: +List-Subscribe: +X-Seq: 1047 +Delivered-To: mailing list foromundial@decode.com.ar +Received: (qmail 5432 invoked by uid 618); 5 Sep 2003 19:49:15 -0000 +X-Spam-Status: No, hits=3.9 required=7.5 +Message-Id: <4.2.1.20030905163128.00a998a0@mail.labsem.cetuc.puc-rio.br> +X-Sender: sandra@mail.labsem.cetuc.puc-rio.br +X-Mailer: QUALCOMM Windows Eudora Pro Version 4.2.1 +Date: Fri, 05 Sep 2003 16:48:12 -0300 +To: foromundial@decode.com.ar +From: "Sandra M. Landi" +Mime-Version: 1.0 +Content-Type: multipart/alternative; + boundary="=====================_4293080==_.ALT" +X-Antirelay: Good relay from local net2 139.82.127.0/26 +Subject: [foromundial-1047] frases para un viernes + + +. diff --git a/protocols/YAMN/mails/test/header2.txt b/protocols/YAMN/mails/test/header2.txt new file mode 100644 index 0000000000..3ba81a2bd0 --- /dev/null +++ b/protocols/YAMN/mails/test/header2.txt @@ -0,0 +1,97 @@ +Return-Path: +Received: [from megami.sprintserve.net (megami.sprintserve.net [207.142.136.160]) + by mail2.ba.psg.sk with ESMTP id i4FHNUY6018585 + for ; Sat, 15 May 2004 19:23:31 +0200] +X-Envelope-To: +Received: from miranda by megami.sprintserve.net with local (Exim 4.34) + id 1BP2sS-0006W6-MS + for om3tn@psg.sk; Sat, 15 May 2004 13:23:12 -0400 +To: Undisclosed-recipients:; +Subject: Upozornn na odpov v tmatu - YAMN problem +Reply-to: forum@miranda-im.org +From: forum@miranda-im.org: +Message-ID: +MIME-Version: 1.0 +Content-type: text/plain; charset=Windows-1250 +Content-transfer-encoding: 8bit +Date: Sat, 15 May 2004 13:23:12 -0400 +X-Priority: 3 +X-MSMail-Priority: Normal +X-Mailer: PHP +X-MimeOLE: Produced By phpBB2 +X-MailScanner-Information: Please contact the ISP for more information +X-MailScanner: Found to be clean +X-AntiAbuse: This header was added to track abuse, please include it with any abuse report +X-AntiAbuse: Primary Hostname - megami.sprintserve.net +X-AntiAbuse: Original Domain - psg.sk +X-AntiAbuse: Originator/Caller UID/GID - [32110 32110] / [47 12] +X-AntiAbuse: Sender Address Domain - megami.sprintserve.net +X-Source: +X-Source-Args: +X-Source-Dir: +. + +Subject: Upozornn na odpov v tmatu - YAMN problem + +Return-Path: +Received: [from megami.sprintserve.net (megami.sprintserve.net [207.142.136.160]) + by mail2.ba.psg.sk with ESMTP id i4FHX2Y6020695 + for ; Sat, 15 May 2004 19:33:03 +0200] +X-Envelope-To: +Received: from miranda by megami.sprintserve.net with local (Exim 4.34) + id 1BP31h-0001cs-Ai + for om3tn@psg.sk; Sat, 15 May 2004 13:32:45 -0400 +To: Undisclosed-recipients:; +Subject: Upozornn na odpov v tmatu - YAMN problem +Reply-to: forum@miranda-im.org +From: forum@miranda-im.org +Message-ID: <0873b36d0931479c4ebe23ba71ff4810@forums.miranda-im.org> +MIME-Version: 1.0 +Content-type: text/plain; charset=Windows-1250 +Content-transfer-encoding: 8bit +Date: Sat, 15 May 2004 13:32:45 -0400 +X-Priority: 3 +X-MSMail-Priority: Normal +X-Mailer: PHP +X-MimeOLE: Produced By phpBB2 +X-MailScanner-Information: Please contact the ISP for more information +X-MailScanner: Found to be clean +X-AntiAbuse: This header was added to track abuse, please include it with any abuse report +X-AntiAbuse: Primary Hostname - megami.sprintserve.net +X-AntiAbuse: Original Domain - psg.sk +X-AntiAbuse: Originator/Caller UID/GID - [32110 32110] / [47 12] +X-AntiAbuse: Sender Address Domain - megami.sprintserve.net +X-Source: +X-Source-Args: +X-Source-Dir: + +. + +Received: by hplm (mbox om3tn) + (with POP3 daemon cucipop (v1.31 1998/05/13) Tue May 27 18:42:20 2003) +X-From_: HMF@hotbox.ru Tue May 20 18:11:44 2003 +Return-Path: +Received: from ns1.slovanet.net (ns1.slovanet.net [195.28.64.119]) + by hplm.psg.sk (8.12.9/8.12.7) with SMTP id h4KGBfxJ003732 + for ; Tue, 20 May 2003 18:11:44 +0200 +X-Envelope-To: +Received: (qmail 6339 invoked from network); 20 May 2003 18:11:45 +0200 +Received: from unknown (HELO ??+???) (61.33.134.106) + by ns1.slovanet.net with SMTP; 20 May 2003 18:11:45 +0200 +Received: by london.com (Postfix, from userid 302) + id WTS; Tue, 20 May 2003 20:13:19 +Received: from +⌥ (+⌥ [61.33.134.106]) + by mill.co.uk (Postfix) with ESMTP id 613 + for ; Tue, 20 May 2003 20:13:19 +Subject: . . 0,8 , ! 20:13:19 +From: +To: OM3TN +Reply-To: <> +X-Mailer: AOL 7.0 for Windows UK sub 52 +X-Priority: 1 +X-MSMail-Priority: High +Mime-Version: 1.0 +Content-Type: text/html; charset="Windows-1251" +Content-Transfer-Encoding: 7bit +Date: Tue, 20 May 2003 20:13:21 +Message-Id: \ No newline at end of file diff --git a/protocols/YAMN/mails/test/readme.txt b/protocols/YAMN/mails/test/readme.txt new file mode 100644 index 0000000000..35a30b255a --- /dev/null +++ b/protocols/YAMN/mails/test/readme.txt @@ -0,0 +1,4 @@ +This is project for testing mime encoding/decoding. It +is very usefull for developers, when some problems with +non-standard headers occured. You can use it to step through +MIME decoding functions. diff --git a/protocols/YAMN/mails/test/test.cpp b/protocols/YAMN/mails/test/test.cpp new file mode 100644 index 0000000000..f8dcd14e89 --- /dev/null +++ b/protocols/YAMN/mails/test/test.cpp @@ -0,0 +1,42 @@ +/* + * This file is for testing purposes. Save in header.txt your problem header and you can + * browse through functions to get result + * + * (c) majvan 2002-2004 + */ + +#include +#include "../m_mails.h" + +extern void WINAPI TranslateHeaderFcn(char *stream,int len,struct CMimeItem **head); +extern void ExtractHeader(struct CMimeItem *items,int CP,struct CHeader *head); + +void main() +{ + char Buffer[8192]; //we do not suppose longer header + FILE *fp; + YAMNMAIL *Mail; + PMAILDATA *MailData; + CMimeItem *head; + + struct CHeader ExtractedHeader; + + if(NULL==(fp=fopen("header2.txt","r"))) + return; + fread(Buffer,sizeof(Buffer),1,fp); + if(ferror(fp)) + { + fclose(fp); + return; + } + fclose(fp); + Mail = new YAMNMAIL; + MailData = new PMAILDATA; + head = new CMimeItem; + Mail->MailData = *MailData; + Mail->MailData->TranslatedHeader = head; + + TranslateHeaderFcn(Buffer,strlen(Buffer), &Mail->MailData->TranslatedHeader); + ExtractHeader(Mail->MailData->TranslatedHeader,CP_ACP,&ExtractedHeader); + return; +} \ No newline at end of file diff --git a/protocols/YAMN/mails/test/test.dsp b/protocols/YAMN/mails/test/test.dsp new file mode 100644 index 0000000000..6d01b3669a --- /dev/null +++ b/protocols/YAMN/mails/test/test.dsp @@ -0,0 +1,112 @@ +# Microsoft Developer Studio Project File - Name="test" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 6.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Console Application" 0x0103 + +CFG=test - Win32 Debug +!MESSAGE This is not a valid makefile. To build this project using NMAKE, +!MESSAGE use the Export Makefile command and run +!MESSAGE +!MESSAGE NMAKE /f "test.mak". +!MESSAGE +!MESSAGE You can specify a configuration when running NMAKE +!MESSAGE by defining the macro CFG on the command line. For example: +!MESSAGE +!MESSAGE NMAKE /f "test.mak" CFG="test - Win32 Debug" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "test - Win32 Release" (based on "Win32 (x86) Console Application") +!MESSAGE "test - Win32 Debug" (based on "Win32 (x86) Console Application") +!MESSAGE + +# Begin Project +# PROP AllowPerConfigDependencies 0 +# PROP Scc_ProjName "" +# PROP Scc_LocalPath "" +CPP=cl.exe +RSC=rc.exe + +!IF "$(CFG)" == "test - Win32 Release" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "Release" +# PROP BASE Intermediate_Dir "Release" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "Release" +# PROP Intermediate_Dir "Release" +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c +# ADD CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c +# ADD BASE RSC /l 0x405 /d "NDEBUG" +# ADD RSC /l 0x405 /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386 +# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386 + +!ELSEIF "$(CFG)" == "test - Win32 Debug" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "Debug" +# PROP BASE Intermediate_Dir "Debug" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "Debug" +# PROP Intermediate_Dir "Debug" +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ /c +# ADD CPP /nologo /W3 /Gm /GX /ZI /Od /I "../../../../include" /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /FR /YX /FD /GZ /c +# ADD BASE RSC /l 0x405 /d "_DEBUG" +# ADD RSC /l 0x405 /d "_DEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept +# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept + +!ENDIF + +# Begin Target + +# Name "test - Win32 Release" +# Name "test - Win32 Debug" +# Begin Group "Source Files" + +# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat" +# Begin Source File + +SOURCE=..\decode.cpp +# End Source File +# Begin Source File + +SOURCE=..\mails.cpp +# End Source File +# Begin Source File + +SOURCE=..\mime.cpp +# End Source File +# Begin Source File + +SOURCE=.\test.cpp +# End Source File +# End Group +# Begin Group "Header Files" + +# PROP Default_Filter "h;hpp;hxx;hm;inl" +# End Group +# Begin Group "Resource Files" + +# PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe" +# End Group +# End Target +# End Project diff --git a/protocols/YAMN/mails/test/test.dsw b/protocols/YAMN/mails/test/test.dsw new file mode 100644 index 0000000000..e25096d17d --- /dev/null +++ b/protocols/YAMN/mails/test/test.dsw @@ -0,0 +1,29 @@ +Microsoft Developer Studio Workspace File, Format Version 6.00 +# WARNING: DO NOT EDIT OR DELETE THIS WORKSPACE FILE! + +############################################################################### + +Project: "test"=.\test.dsp - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ +}}} + +############################################################################### + +Global: + +Package=<5> +{{{ +}}} + +Package=<3> +{{{ +}}} + +############################################################################### + diff --git a/protocols/YAMN/main.cpp b/protocols/YAMN/main.cpp new file mode 100644 index 0000000000..6076a49c51 --- /dev/null +++ b/protocols/YAMN/main.cpp @@ -0,0 +1,566 @@ +/* + * YAMN plugin main file + * Miranda homepage: http://miranda-icq.sourceforge.net/ + * YAMN homepage: http://www.majvan.host.sk/Projekty/YAMN + * + * initializes all variables for further work + * + * (c) majvan 2002-2004 + */ + + +#include "yamn.h" +#include "main.h" +#include "resources/resource.h" +#include + +#include "m_hotkeys.h" + +//-------------------------------------------------------------------------------------------------- + +TCHAR ProfileName[MAX_PATH]; +TCHAR UserDirectory[MAX_PATH]; + +TCHAR szMirandaDir[MAX_PATH]; +TCHAR szProfileDir[MAX_PATH]; + +int YAMN_STATUS; + +BOOL UninstallPlugins; + +HANDLE hAccountFolder; + +HINSTANCE *hDllPlugins; +static int iDllPlugins = 0; + +PLUGINLINK *pluginLink; +YAMN_VARIABLES YAMNVar; + +int hLangpack; +MM_INTERFACE mmi; + +PLUGININFOEX pluginInfo = { + sizeof(PLUGININFOEX), + YAMN_SHORTNAME, + YAMN_VERSION, + "Mail notifier and browser for Miranda IM. Included POP3 protocol.", + "y_b tweety (majvan)", + "francois.mean@skynet.be", + " (2002-2004 majvan) 2005-2007 tweety y_b Miranda community", + "http://www.miranda-im.org/download/details.php?action = viewfile&id = 3411", //"http://www.majvan.host.sk/Projekty/YAMN?fm = soft", + UNICODE_AWARE, + 0, //doesn't replace anything built-in + { 0xb047a7e5, 0x27a, 0x4cfc, { 0x8b, 0x18, 0xed, 0xa8, 0x34, 0x5d, 0x27, 0x90 } } // {B047A7E5-027A-4cfc-8B18-EDA8345D2790} + +}; + +SKINSOUNDDESC NewMailSound = +{ + sizeof(SKINSOUNDDESC), + YAMN_NEWMAILSOUND, //name to refer to sound when playing and in db + YAMN_NEWMAILSNDDESC, //description for options dialog + "", //default sound file to use, without path +}; + +SKINSOUNDDESC ConnectFailureSound = +{ + sizeof(SKINSOUNDDESC), + YAMN_CONNECTFAILSOUND, //name to refer to sound when playing and in db + YAMN_CONNECTFAILSNDDESC, //description for options dialog + "", //default sound file to use, without path +}; + +HANDLE hNewMailHook; +HANDLE NoWriterEV; +HANDLE hTTButton, hTButton; + +UINT SecTimer; + +HANDLE hMenuItemMain = 0; +HANDLE hMenuItemCont = 0; +HANDLE hMenuItemContApp = 0; + +HMODULE hUxTheme = 0; +BOOL (WINAPI *MyEnableThemeDialogTexture)(HANDLE, DWORD) = 0; + +// function pointers, use typedefs for casting to shut up the compiler when using GetProcAddress() + +typedef BOOL (WINAPI *PITA)(); +typedef HANDLE (WINAPI *POTD)(HWND, LPCWSTR); +typedef UINT (WINAPI *PDTB)(HANDLE, HDC, int, int, RECT *, RECT *); +typedef UINT (WINAPI *PCTD)(HANDLE); +typedef UINT (WINAPI *PDTT)(HANDLE, HDC, int, int, LPCWSTR, int, DWORD, DWORD, RECT *); + +PITA pfnIsThemeActive = 0; +POTD pfnOpenThemeData = 0; +PDTB pfnDrawThemeBackground = 0; +PCTD pfnCloseThemeData = 0; +PDTT pfnDrawThemeText = 0; + +#define FIXED_TAB_SIZE 100 // default value for fixed width tabs + +/* + * visual styles support (XP+) + * returns 0 on failure + */ + +int InitVSApi() +{ + if ((hUxTheme = LoadLibraryA("uxtheme.dll")) == 0) + return 0; + + pfnIsThemeActive = (PITA)GetProcAddress(hUxTheme, "IsThemeActive"); + pfnOpenThemeData = (POTD)GetProcAddress(hUxTheme, "OpenThemeData"); + pfnDrawThemeBackground = (PDTB)GetProcAddress(hUxTheme, "DrawThemeBackground"); + pfnCloseThemeData = (PCTD)GetProcAddress(hUxTheme, "CloseThemeData"); + pfnDrawThemeText = (PDTT)GetProcAddress(hUxTheme, "DrawThemeText"); + + MyEnableThemeDialogTexture = (BOOL (WINAPI *)(HANDLE, DWORD))GetProcAddress(hUxTheme, "EnableThemeDialogTexture"); + if (pfnIsThemeActive != 0 && pfnOpenThemeData != 0 && pfnDrawThemeBackground != 0 && pfnCloseThemeData != 0 && pfnDrawThemeText != 0) + return 1; + + return 0; +} + +/* + * unload uxtheme.dll + */ + +int FreeVSApi() +{ + if (hUxTheme != 0) + FreeLibrary(hUxTheme); + return 0; +} + +//-------------------------------------------------------------------------------------------------- + +static void GetProfileDirectory(TCHAR *szPath, int cbPath) +//This is copied from Miranda's sources. In 0.2.1.0 it is needed, in newer vesions of Miranda use MS_DB_GETPROFILEPATH service +{ + if (ServiceExists(MS_DB_GETPROFILEPATH)) + if (!CallService(MS_DB_GETPROFILEPATHT, (WPARAM)cbPath, (LPARAM)szPath)) { + lstrcpy(szProfileDir, szPath); + return; //success + } + + TCHAR szMirandaIni[MAX_PATH], szExpandedProfileDir[MAX_PATH]; + DWORD dwAttributes; + + lstrcpy(szMirandaIni, szMirandaDir); + lstrcat(szMirandaIni, _T("\\mirandaboot.ini")); + GetPrivateProfileString( _T("Database"), _T("ProfileDir"), _T("."), szProfileDir, sizeof(szProfileDir), szMirandaIni); + ExpandEnvironmentStrings(szProfileDir, szExpandedProfileDir, sizeof(szExpandedProfileDir)); + _tchdir(szMirandaDir); + if (!_tfullpath(szPath, szExpandedProfileDir, cbPath)) + lstrcpyn(szPath, szMirandaDir, cbPath); + if (szPath[lstrlen(szPath)-1] == '\\') szPath[lstrlen(szPath)-1] = '\0'; + if ((dwAttributes = GetFileAttributes(szPath))!=0xffffffff&&dwAttributes&FILE_ATTRIBUTE_DIRECTORY) return; + CreateDirectory(szPath, NULL); +} + +///////////////////////////////////////////////////////////////////////////////////////// + +extern "C" BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved) +{ + YAMNVar.hInst = hinstDLL; + return TRUE; +} + +///////////////////////////////////////////////////////////////////////////////////////// + +extern "C" __declspec(dllexport) PLUGININFOEX* MirandaPluginInfoEx(DWORD mirandaVersion) +{ + return &pluginInfo; +} + +///////////////////////////////////////////////////////////////////////////////////////// + +static const MUUID interfaces[] = {MUUID_YAMN_FORCECHECK, MIID_LAST}; + +extern "C" __declspec(dllexport) const MUUID * MirandaPluginInterfaces(void) +{ + return interfaces; +} + +///////////////////////////////////////////////////////////////////////////////////////// + +#ifdef YAMN_DEBUG +static char unknownCP[1500] = {0}; +#endif +// The callback function +BOOL CALLBACK EnumSystemCodePagesProc(LPTSTR cpStr) +{ + //Convert code page string to number + UINT cp = _ttoi(cpStr); + if (!IsValidCodePage(cp)) + return TRUE; + + //Get Code Page name + CPINFOEX info; + if (GetCPInfoEx(cp, 0, &info)) { + #ifdef YAMN_DEBUG + BOOLEAN found = FALSE; + #endif + for (int i = 1;iYAMN 2in1 "; + update.szBetaUpdateURL = szUrl; + update.szBetaVersionURL = "http://www.miranda-fr.net/tweety/yamn/yamn_beta.html"; + update.pbBetaVersionPrefix = (BYTE *)"YAMN version "; + update.cpbVersionPrefix = (int)strlen((char *)update.pbVersionPrefix); + update.cpbBetaVersionPrefix = (int)strlen((char *)update.pbBetaVersionPrefix); + CallService(MS_UPDATE_REGISTER, 0, (WPARAM)&update); + } + + if (ServiceExists(MS_FOLDERS_GET_PATH)) { + hAccountFolder = FoldersRegisterCustomPathT(YAMN_DBMODULE, YAMN_DBMODULE" Account Folder", UserDirectory); + FoldersGetCustomPathT(hAccountFolder, UserDirectory, MAX_PATH, UserDirectory); + } + + RegisterPOP3Plugin(0, 0); + return 0; +} + +///////////////////////////////////////////////////////////////////////////////////////// + +struct TIconListItem +{ + char* szDescr; + char* szName; + int defIconID; + HANDLE hIcon; +}; + +static TIconListItem iconList[] = +{ + { LPGEN("Neutral"), "YAMN_Neutral", IDI_ONLINE, 0 }, + { LPGEN("YAMN"), "YAMN", IDI_ICOYAMN1, 0 }, + { LPGEN("New Mail"), "YAMN_NewMail", IDI_ICOYAMN2, 0 }, + { LPGEN("Connect Fail"), "YAMN_ConnectFail", IDI_NA, 0 }, + { LPGEN("Launch Application"), "YAMN_ApplExec", IDI_OCCUPIED, 0 }, + { LPGEN("TopToolBar UP"), "YAMN_TopToolBarUp", IDI_ICOTTBUP, 0 }, + { LPGEN("TopToolBar Down"), "YAMN_TopToolBarDown", IDI_OCCUPIED, 0 }, + { LPGEN("Offline"), "YAMN_Offline", IDI_OFFLINE, 0 } +}; + +static void LoadIcons() +{ + HIMAGELIST CSImages = ImageList_Create(16, 16, ILC_COLOR8|ILC_MASK, 0, 3); + { + HBITMAP hScrBM = (HBITMAP)LoadImage(YAMNVar.hInst, MAKEINTRESOURCE(IDB_ICONS), IMAGE_BITMAP, 0, 0, LR_SHARED); + ImageList_AddMasked(CSImages, hScrBM, RGB( 255, 0, 255 )); + DeleteObject(hScrBM); + } + + char szFile[MAX_PATH]; + GetModuleFileNameA(YAMNVar.hInst, szFile, MAX_PATH); + + SKINICONDESC sid = {0}; + sid.cbSize = sizeof(SKINICONDESC); + sid.pszDefaultFile = szFile; + sid.pszSection = "YAMN"; + + for (int i = 0, k = 0; i < ICONSNUMBER; i++) { + switch (i){ + case 1: case 2: case 5: + sid.hDefaultIcon = ImageList_ExtractIcon(NULL, CSImages, k); k++; + break; + default: + sid.hDefaultIcon = LoadIcon(YAMNVar.hInst, MAKEINTRESOURCE(iconList[i].defIconID)); break; + } + sid.pszName = iconList[i].szName; + sid.pszDescription = iconList[i].szDescr; + sid.iDefaultIndex = -iconList[i].defIconID; + iconList[i].hIcon = ( HANDLE )CallService(MS_SKIN2_ADDICON, 0, (LPARAM)&sid); +} } + +HANDLE WINAPI g_GetIconHandle( int idx ) +{ + if ( idx >= SIZEOF(iconList)) + return NULL; + return iconList[idx].hIcon; +} + +HICON WINAPI g_LoadIconEx( int idx, bool big ) +{ + if ( idx >= SIZEOF(iconList)) + return NULL; + return ( HICON )CallService(MS_SKIN2_GETICON, big, (LPARAM)iconList[idx].szName); +} + +void WINAPI g_ReleaseIcon( HICON hIcon ) +{ + if ( hIcon ) CallService(MS_SKIN2_RELEASEICON, (WPARAM)hIcon, 0); +} + +static void LoadPlugins() +{ + HANDLE hFind; + WIN32_FIND_DATA fd; + TCHAR szSearchPath[MAX_PATH]; + TCHAR szPluginPath[MAX_PATH]; + lstrcpy(szSearchPath, szMirandaDir); + lstrcat(szSearchPath, _T("\\Plugins\\YAMN\\*.dll")); + typedef INT_PTR (*LOADFILTERFCN)(MIRANDASERVICE GetYAMNFcn); + + hDllPlugins = NULL; + + if (INVALID_HANDLE_VALUE!=(hFind = FindFirstFile(szSearchPath, &fd))) { + do { + //rewritten from Miranda sources... Needed because Win32 API has a bug in FindFirstFile, search is done for *.dlllllll... too + TCHAR *dot = _tcsrchr(fd.cFileName, '.'); + if (dot == NULL ) + continue; + + // we have a dot + int len = (int)lstrlen(fd.cFileName); // find the length of the string + TCHAR* end = fd.cFileName+len; // get a pointer to the NULL + int safe = (end-dot)-1; // figure out how many chars after the dot are "safe", not including NULL + + if ((safe!=3) || (lstrcmpi(dot+1, _T("dll"))!=0)) //not bound, however the "dll" string should mean only 3 chars are compared + continue; + + HINSTANCE hDll; + LOADFILTERFCN LoadFilter; + + lstrcpy(szPluginPath, szMirandaDir); + lstrcat(szPluginPath, _T("\\Plugins\\YAMN\\")); + lstrcat(szPluginPath, fd.cFileName); + if ((hDll = LoadLibrary(szPluginPath)) == NULL) continue; + LoadFilter = (LOADFILTERFCN)GetProcAddress(hDll, "LoadFilter"); + if (NULL == LoadFilter) { + FreeLibrary(hDll); + hDll = NULL; + continue; + } + + if (!(*LoadFilter)(GetFcnPtrSvc)) { + FreeLibrary(hDll); + hDll = NULL; + } + + if (hDll != NULL) { + hDllPlugins = (HINSTANCE *)realloc((void *)hDllPlugins, (iDllPlugins+1)*sizeof(HINSTANCE)); + hDllPlugins[iDllPlugins++] = hDll; + } + } + while(FindNextFile(hFind, &fd)); + + FindClose(hFind); + } +} + +extern "C" int __declspec(dllexport) Load(PLUGINLINK *link) +{ + int i, k; + + pluginLink = link; + mir_getLP(&pluginInfo); + mir_getMMI(&mmi); + + YAMN_STATUS = ID_STATUS_OFFLINE; + + // we get the Miranda Root Path + if (ServiceExists(MS_UTILS_PATHTOABSOLUTET)) + CallService(MS_UTILS_PATHTOABSOLUTET, (WPARAM)_T("."), (LPARAM)szMirandaDir); + else { + GetModuleFileName(GetModuleHandle(NULL), szMirandaDir, MAX_PATH); + TCHAR* str2 = _tcsrchr(szMirandaDir, '\\'); + if (str2!=NULL) *str2 = 0; + } + + // we get the user path where our yamn-account.book.ini is stored from mirandaboot.ini file + GetProfileDirectory(UserDirectory, SIZEOF(UserDirectory)); + + // Enumerate all the code pages available for the System Locale + EnumSystemCodePages(EnumSystemCodePagesProc, CP_INSTALLED); + CodePageNamesSupp = new _tcptable[CPLENSUPP]; + for (i = 0, k = 0; i < CPLENALL; i++) { + if (CodePageNamesAll[i].isValid){ + CodePageNamesSupp[k] = CodePageNamesAll[i]; + k++; + } } + + // Registering YAMN as protocol + PROTOCOLDESCRIPTOR pd = {0}; + pd.cbSize = PROTOCOLDESCRIPTOR_V3_SIZE; + pd.szName = YAMN_DBMODULE; + pd.type = PROTOTYPE_PROTOCOL; + CallService(MS_PROTO_REGISTERMODULE, 0, (LPARAM)&pd); + + CallService(MS_DB_GETPROFILENAMET, (WPARAM)SIZEOF(ProfileName), (LPARAM)ProfileName); //not to pass entire array to fcn + TCHAR *fc = _tcsrchr(ProfileName, '.'); + if ( fc != NULL ) *fc = 0; + + InitializeCriticalSection(&AccountStatusCS); + InitializeCriticalSection(&FileWritingCS); + InitializeCriticalSection(&PluginRegCS); + + if (NULL == (NoWriterEV = CreateEvent(NULL, TRUE, TRUE, NULL))) + return 1; + if (NULL == (WriteToFileEV = CreateEvent(NULL, FALSE, FALSE, NULL))) + return 1; + if (NULL == (ExitEV = CreateEvent(NULL, TRUE, FALSE, NULL))) + return 1; + + NewMailSound.pszDescription = Translate(YAMN_NEWMAILSNDDESC); + ConnectFailureSound.pszDescription = Translate(YAMN_CONNECTFAILSNDDESC); + + PosX = DBGetContactSettingDword(NULL, YAMN_DBMODULE, YAMN_DBPOSX, 0); + PosY = DBGetContactSettingDword(NULL, YAMN_DBMODULE, YAMN_DBPOSY, 0); + SizeX = DBGetContactSettingDword(NULL, YAMN_DBMODULE, YAMN_DBSIZEX, 800); + SizeY = DBGetContactSettingDword(NULL, YAMN_DBMODULE, YAMN_DBSIZEY, 200); + + HeadPosX = DBGetContactSettingDword(NULL, YAMN_DBMODULE, YAMN_DBMSGPOSX, 0); + HeadPosY = DBGetContactSettingDword(NULL, YAMN_DBMODULE, YAMN_DBMSGPOSY, 0); + HeadSizeX = DBGetContactSettingDword(NULL, YAMN_DBMODULE, YAMN_DBMSGSIZEX, 690); + HeadSizeY = DBGetContactSettingDword(NULL, YAMN_DBMODULE, YAMN_DBMSGSIZEY, 300); + HeadSplitPos = DBGetContactSettingWord(NULL, YAMN_DBMODULE, YAMN_DBMSGPOSSPLIT, 250); + + optDateTime = DBGetContactSettingByte(NULL, YAMN_DBMODULE, YAMN_DBTIMEOPTIONS, optDateTime); + + // Create new window queues for broadcast messages + YAMNVar.MessageWnds = (HANDLE)CallService(MS_UTILS_ALLOCWINDOWLIST, 0, 0); + YAMNVar.NewMailAccountWnd = (HANDLE)CallService(MS_UTILS_ALLOCWINDOWLIST, 0, 0); + YAMNVar.Shutdown = FALSE; + + hCurSplitNS = LoadCursor(NULL, IDC_SIZENS); + hCurSplitWE = LoadCursor(NULL, IDC_SIZEWE); + +#ifdef YAMN_DEBUG + InitDebug(); +#endif + + CreateServiceFunctions(); + + CallService(MS_SKIN_ADDNEWSOUND, 0, (LPARAM)&NewMailSound); + CallService(MS_SKIN_ADDNEWSOUND, 0, (LPARAM)&ConnectFailureSound); + + HookEvents(); + + LoadIcons(); + LoadPlugins(); + InitVSApi(); + + HOTKEYDESC hkd = {0}; + hkd.cbSize = sizeof(hkd); + hkd.pszService = MS_YAMN_FORCECHECK; + hkd.pszSection = YAMN_DBMODULE; + hkd.pszDescription = LPGEN("Check mail"); + hkd.DefHotKey = HOTKEYCODE(HOTKEYF_CONTROL, VK_F11); + CallService(MS_HOTKEY_REGISTER, 0, (LPARAM)&hkd); + + //Create thread that will be executed every second + if (!(SecTimer = SetTimer(NULL, 0, 1000, (TIMERPROC)TimerProc))) + return 1; + + return 0; +} + +///////////////////////////////////////////////////////////////////////////////////////// + +static void UnloadPlugins() +{ + for (int i = iDllPlugins-1;i>=0;i--) { + if (FreeLibrary(hDllPlugins[i])) { + hDllPlugins[i] = NULL; //for safety + iDllPlugins --; + } + } + if (hDllPlugins){ + free((void *)hDllPlugins); + hDllPlugins = NULL; + } +} + +extern "C" int __declspec(dllexport) Unload(void) +{ +#ifdef YAMN_DEBUG + UnInitDebug(); +#endif + DestroyCursor(hCurSplitNS); + DestroyCursor(hCurSplitWE); + + CloseHandle(NoWriterEV); + CloseHandle(WriteToFileEV); + CloseHandle(ExitEV); + + FreeVSApi(); + + DeleteCriticalSection(&AccountStatusCS); + DeleteCriticalSection(&FileWritingCS); + DeleteCriticalSection(&PluginRegCS); + + UnhookEvents(); + DestroyServiceFunctions(); + + UnloadPlugins(); + + delete [] CodePageNamesSupp; + return 0; +} diff --git a/protocols/YAMN/main.h b/protocols/YAMN/main.h new file mode 100644 index 0000000000..1ec690873d --- /dev/null +++ b/protocols/YAMN/main.h @@ -0,0 +1,61 @@ +#ifndef __MAIN_H +#define __MAIN_H + +#ifdef __GNUC__ + #define __try + #define __except(x) if (0) /* don't execute handler */ + #define __finally + #define _try __try + #define _except __except + #define _finally __finally +#endif +//For updater +//#define YAMN_9x +#ifndef WIN2IN1 +#ifdef YAMN_9x + #define YAMN_SHORTNAME "YAMN tweety win9x" + #define YAMN_FILENAME "yamn_9x" +#else + #define YAMN_SHORTNAME "YAMN tweety" + #define YAMN_FILENAME "yamn" +#endif +#else + #define YAMN_SHORTNAME "YAMN tweety 2in1" + #define YAMN_FILENAME "yamn" +#endif //WIN2IN1 + +#include "version.h" +#define YAMN_NEWMAILSNDDESC "YAMN: new mail message" +#define YAMN_CONNECTFAILSNDDESC "YAMN: connect failed" +#define YAMN_CONNECTFAILSOUND "YAMN/Sound/ConnectFail" +#define YAMN_NEWMAILSOUND "YAMN/Sound/NewMail" + +#define YAMN_DBMODULE "YAMN" +#define YAMN_DBPOSX "MailBrowserWinX" +#define YAMN_DBPOSY "MailBrowserWinY" +#define YAMN_DBSIZEX "MailBrowserWinW" +#define YAMN_DBSIZEY "MailBrowserWinH" +#define YAMN_DBMSGPOSX "MailMessageWinX" +#define YAMN_DBMSGPOSY "MailMessageWinY" +#define YAMN_DBMSGSIZEX "MailMessageWinW" +#define YAMN_DBMSGSIZEY "MailMessageWinH" +#define YAMN_DBMSGPOSSPLIT "MailMessageSplitY" +#define YAMN_TTBFCHECK "ForceCheckTTB" +#define YAMN_SHOWMAINMENU "ShowMainMenu" +#define YAMN_CLOSEDELETE "CloseOnDelete" +#define YAMN_SHOWASPROTO "ShowAsProtcol" +#define YAMN_DBTIMEOPTIONS "MailBrowserTimeOpts" + +#define YAMN_DEFAULTHK MAKEWORD(VK_F11,MOD_CONTROL) + +#define SHOWDATELONG 0x01 +#define SHOWDATENOTODAY 0x02 +#define SHOWDATENOSECONDS 0x04 + +extern unsigned char optDateTime; + +// Loading Icon and checking for icolib +void LoadIcons(); + +#endif + diff --git a/protocols/YAMN/mingw/base.dev b/protocols/YAMN/mingw/base.dev new file mode 100644 index 0000000000..42e2fab4f2 --- /dev/null +++ b/protocols/YAMN/mingw/base.dev @@ -0,0 +1,69 @@ +[Project] +FileName=base.dev +Name=base +Ver=1 +IsCpp=1 +Type=3 +Compiler=-D__GNUWIN32__ -mcpu=i486 -D_M_IX86=400 -W -fno-inline -DWIN32 -DNDEBUG -D_WINDOWS_@@_ +CppCompiler=-D__GNUWIN32__ -mcpu=i486 -D_M_IX86=400 -W -fno-inline -DWIN32 -DNDEBUG -D_WINDOWS_@@_ +Includes=../../../include +Linker=-lkernel32 -luser32_@@_ +Libs= +UnitCount=2 +Folders="Header Files","Resource Files","Source Files" +ObjFiles= +PrivateResource= +ResourceIncludes= +MakeIncludes= +Icon= +ExeOutput=binfilter +ObjectOutput=objbase +OverrideOutput=0 +OverrideOutputName=base.dll +HostApplication= +CommandLine= +UseCustomMakefile=1 +CustomMakefile=base.win +IncludeVersionInfo=0 +SupportXPThemes=0 +CompilerSet=0 +CompilerSettings=0010000001001000000100 + +[Unit1] +FileName=..\filter\base\maindll.cpp +Folder="Source Files" +Compile=1 +CompileCpp=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit2] +FileName=..\filter\base\debug.cpp +Folder="Source Files" +Compile=1 +CompileCpp=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[VersionInfo] +Major=0 +Minor=1 +Release=1 +Build=1 +LanguageID=1033 +CharsetID=1252 +CompanyName= +FileVersion=0.1 +FileDescription=Developed using the Dev-C++ IDE +InternalName= +LegalCopyright= +LegalTrademarks= +OriginalFilename=base.dll +ProductName=base +ProductVersion=0.1 +AutoIncBuildNr=0 + diff --git a/protocols/YAMN/mingw/base.win b/protocols/YAMN/mingw/base.win new file mode 100644 index 0000000000..3af9e7aa60 --- /dev/null +++ b/protocols/YAMN/mingw/base.win @@ -0,0 +1,38 @@ +# Project: base +# Makefile created by Dev-C++ 4.9.9.2 + +CPP = g++.exe +CC = gcc.exe +WINDRES = windres.exe +RES = +OBJ = objbase/maindll.o objbase/debug.o $(RES) +LINKOBJ = objbase/maindll.o objbase/debug.o $(RES) +LIBS = -lkernel32 -luser32 -s +INCS = -I"../../../include" +CXXINCS = -I"../../../include" +BIN = binfilter/base.dll +CXXFLAGS = $(CXXINCS) -D__GNUWIN32__ -W -fno-inline -DWIN32 -DNDEBUG -D_WINDOWS -w -fweb -frename-registers -Os +CFLAGS = $(INCS) -D__GNUWIN32__ -W -fno-inline -DWIN32 -DNDEBUG -D_WINDOWS -w -fweb -frename-registers -Os +RM = rm -f + +.PHONY: all all-before all-after clean clean-custom + +all: all-before binfilter/base.dll all-after + + +clean: clean-custom + ${RM} $(OBJ) $(BIN) + +DLLWRAP=dllwrap.exe +DEFFILE=objbase/libbase.def +STATICLIB=objbase/libbase.a + +$(BIN): $(LINKOBJ) +# $(DLLWRAP) --output-def $(DEFFILE) --driver-name c++ --implib $(STATICLIB) $(LINKOBJ) $(LIBS) -o $(BIN) + $(CPP) $(LINKOBJ) $(LIBS) -o $(BIN) -mdll + +objbase/maindll.o: ../filter/base/maindll.cpp + $(CPP) -c ../filter/base/maindll.cpp -o objbase/maindll.o $(CXXFLAGS) + +objbase/debug.o: ../filter/base/debug.cpp + $(CPP) -c ../filter/base/debug.cpp -o objbase/debug.o $(CXXFLAGS) diff --git a/protocols/YAMN/mingw/simple.dev b/protocols/YAMN/mingw/simple.dev new file mode 100644 index 0000000000..617324b551 --- /dev/null +++ b/protocols/YAMN/mingw/simple.dev @@ -0,0 +1,59 @@ +[Project] +FileName=simple.dev +Name=simple +Ver=1 +IsCpp=1 +Type=3 +Compiler=-D__GNUWIN32__ -mcpu=i486 -D_M_IX86=400 -W -fno-inline -DWIN32 -DNDEBUG -D_WINDOWS_@@_ +CppCompiler=-D__GNUWIN32__ -mcpu=i486 -D_M_IX86=400 -W -fno-inline -DWIN32 -DNDEBUG -D_WINDOWS_@@_ +Includes=../../../include +Linker=-lkernel32 -luser32_@@_ +Libs= +UnitCount=1 +Folders="Header Files","Resource Files","Source Files" +ObjFiles= +PrivateResource= +ResourceIncludes= +MakeIncludes= +Icon= +ExeOutput=binfilter +ObjectOutput=objsimple +OverrideOutput=0 +OverrideOutputName=simple.dll +HostApplication= +CommandLine= +UseCustomMakefile=1 +CustomMakefile=simple.win +IncludeVersionInfo=0 +SupportXPThemes=0 +CompilerSet=0 +CompilerSettings=0010000001001000000100 + +[Unit1] +FileName=..\filter\Simple\maindll.cpp +Folder="Source Files" +Compile=1 +CompileCpp=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[VersionInfo] +Major=0 +Minor=1 +Release=1 +Build=1 +LanguageID=1033 +CharsetID=1252 +CompanyName= +FileVersion=0.1 +FileDescription=Developed using the Dev-C++ IDE +InternalName= +LegalCopyright= +LegalTrademarks= +OriginalFilename=simple.dll +ProductName=simple +ProductVersion=0.1 +AutoIncBuildNr=0 + diff --git a/protocols/YAMN/mingw/simple.win b/protocols/YAMN/mingw/simple.win new file mode 100644 index 0000000000..fc9e3c611e --- /dev/null +++ b/protocols/YAMN/mingw/simple.win @@ -0,0 +1,35 @@ +# Project: simple +# Makefile created by Dev-C++ 4.9.9.2 + +CPP = g++.exe +CC = gcc.exe +WINDRES = windres.exe +RES = +OBJ = objsimple/maindll.o $(RES) +LINKOBJ = objsimple/maindll.o $(RES) +LIBS = -lkernel32 -luser32 -s +INCS = -I"../../../include" +CXXINCS = -I"../../../include" +BIN = binfilter/simple.dll +CXXFLAGS = $(CXXINCS) -D__GNUWIN32__ -W -fno-inline -DWIN32 -DNDEBUG -D_WINDOWS -w -fweb -frename-registers -Os +CFLAGS = $(INCS) -D__GNUWIN32__ -W -fno-inline -DWIN32 -DNDEBUG -D_WINDOWS -w -fweb -frename-registers -Os +RM = rm -f + +.PHONY: all all-before all-after clean clean-custom + +all: all-before binfilter/simple.dll all-after + + +clean: clean-custom + ${RM} $(OBJ) $(BIN) + +DLLWRAP=dllwrap.exe +DEFFILE=objsimple/libsimple.def +STATICLIB=objsimple/libsimple.a + +$(BIN): $(LINKOBJ) +# $(DLLWRAP) --output-def $(DEFFILE) --driver-name c++ --implib $(STATICLIB) $(LINKOBJ) $(LIBS) -o $(BIN) + $(CPP) $(LINKOBJ) $(LIBS) -o $(BIN) -mdll + +objsimple/maindll.o: ../filter/Simple/maindll.cpp + $(CPP) -c ../filter/Simple/maindll.cpp -o objsimple/maindll.o $(CXXFLAGS) diff --git a/protocols/YAMN/mingw/yamn-2in1.dev b/protocols/YAMN/mingw/yamn-2in1.dev new file mode 100644 index 0000000000..615e63f7ac --- /dev/null +++ b/protocols/YAMN/mingw/yamn-2in1.dev @@ -0,0 +1,469 @@ +[Project] +FileName=yamn-2in1.dev +Name=YAMN +Ver=1 +IsCpp=1 +Type=3 +Compiler=-D__GNUWIN32__ -W -DWIN32 -DNDEBUG -D_WINDOWS -DWIN2IN1 +CppCompiler=-D__GNUWIN32__ -W -DWIN32 -DNDEBUG -D_WINDOWS -DWIN2IN1 +Includes=../../../include +Linker=-lunicows -lkernel32 -luser32 -lshell32 -lmsvcrt -lcomctl32 -lcomdlg32 -lgdi32 -lwsock32 --image-base "0x60010000" +Libs=../libs +UnitCount=36 +Folders=Documentation,"Resource Files",YAMN,YAMN/Header,YAMN/include,"YAMN/Mail browser, dialogs",YAMN/Mails,"YAMN/POP3 plugin" +ObjFiles= +PrivateResource=YAMN_private.rc +ResourceIncludes=../resources +MakeIncludes= +Icon= +ExeOutput=bin2in1 +ObjectOutput=objs2in1 +OverrideOutput=1 +OverrideOutputName=YAMN.dll +HostApplication= +CommandLine= +UseCustomMakefile=1 +CustomMakefile=yamn-2in1.win +IncludeVersionInfo=0 +SupportXPThemes=0 +CompilerSet=0 +CompilerSettings=0010000001001000000100 + +[Unit1] +FileName=..\browser\badconnect.cpp +Folder=YAMN/Mail browser, dialogs +Compile=1 +CompileCpp=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit2] +FileName=..\browser\mailbrowser.cpp +Folder=YAMN/Mail browser, dialogs +Compile=1 +CompileCpp=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit3] +FileName=..\mails\decode.cpp +Folder=YAMN/Mails +Compile=1 +CompileCpp=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit4] +FileName=..\mails\mails.cpp +Folder=YAMN/Mails +Compile=1 +CompileCpp=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit5] +FileName=..\mails\mime.cpp +Folder=YAMN/Mails +Compile=1 +CompileCpp=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit6] +FileName=..\proto\md5.c +Folder=YAMN/POP3 plugin +Compile=1 +CompileCpp=0 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit7] +FileName=..\proto\netlib.cpp +Folder=YAMN/POP3 plugin +Compile=1 +CompileCpp=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit8] +FileName=..\proto\pop3\pop3.cpp +Folder=YAMN/POP3 plugin +Compile=1 +CompileCpp=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit9] +FileName=..\proto\pop3\pop3comm.cpp +Folder=YAMN/POP3 plugin +Compile=1 +CompileCpp=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit10] +FileName=..\proto\pop3\pop3opt.cpp +Folder=YAMN/POP3 plugin +Compile=1 +CompileCpp=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit11] +FileName=..\proto\ssl.cpp +Folder=YAMN/POP3 plugin +Compile=1 +CompileCpp=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit12] +FileName=..\debug.h +Folder=YAMN/Header +Compile=1 +CompileCpp=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit13] +FileName=..\main.h +Folder=YAMN/Header +Compile=1 +CompileCpp=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit14] +FileName=..\proto\pop3\pop3.h +Folder=YAMN/Header +Compile=1 +CompileCpp=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit15] +FileName=..\proto\pop3\pop3comm.h +Folder=YAMN/Header +Compile=1 +CompileCpp=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit16] +FileName=..\proto\pop3\pop3opt.h +Folder=YAMN/Header +Compile=1 +CompileCpp=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit17] +FileName=..\yamn.h +Folder=YAMN/Header +Compile=1 +CompileCpp=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit18] +FileName=..\include\m_kbdnotify.h +Folder=YAMN/include +Compile=1 +CompileCpp=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit19] +FileName=..\include\m_popup.h +Folder=YAMN/include +Compile=1 +CompileCpp=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit20] +FileName=..\include\m_toptoolbar.h +Folder=YAMN/include +Compile=1 +CompileCpp=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit21] +FileName=..\include\m_uninstaller.h +Folder=YAMN/include +Compile=1 +CompileCpp=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit22] +FileName=..\include\m_updater.h +Folder=YAMN/include +Compile=1 +CompileCpp=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit23] +FileName=..\account.cpp +Folder=YAMN +Compile=1 +CompileCpp=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit24] +FileName=..\ChangeLog.txt +Folder=Documentation +Compile=0 +CompileCpp=1 +Link=0 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit25] +FileName=..\debug.cpp +Folder=YAMN +Compile=1 +CompileCpp=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit26] +FileName=..\filterplugin.cpp +Folder=YAMN +Compile=1 +CompileCpp=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit27] +FileName=..\main.cpp +Folder=YAMN +Compile=1 +CompileCpp=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit28] +FileName=..\protoplugin.cpp +Folder=YAMN +Compile=1 +CompileCpp=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit29] +FileName=..\services.cpp +Folder=YAMN +Compile=1 +CompileCpp=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit30] +FileName=..\synchro.cpp +Folder=YAMN +Compile=1 +CompileCpp=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit31] +FileName=..\yamn.cpp +Folder=YAMN +Compile=1 +CompileCpp=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit32] +FileName=..\resources\ttbfcheck.bmp +Folder=Resource Files +Compile=0 +CompileCpp=1 +Link=0 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit33] +FileName=..\resources\YAMN.rc +Folder=Resource Files +Compile=1 +CompileCpp=0 +Link=0 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit34] +FileName=..\docs\language.pop3.txt +Folder=Documentation +Compile=0 +CompileCpp=0 +Link=0 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit35] +FileName=..\docs\language.txt +Folder=Documentation +Compile=0 +CompileCpp=0 +Link=0 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit36] +FileName=..\m_messages.h +Folder=YAMN/include +Compile=1 +CompileCpp=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit37] +FileName=..\resources\icoyamn2.ico +Folder=Resource Files +Compile=0 +CompileCpp=0 +Link=0 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit38] +FileName=..\resources\icoyamn3.ico +Folder=Resource Files +Compile=0 +CompileCpp=0 +Link=0 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit39] +FileName=..\resources\ttbfcheck.bmp +Folder=Resource Files +Compile=0 +CompileCpp=0 +Link=0 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit40] +FileName=..\resources\YAMN.rc +Folder=Resource Files +Compile=1 +CompileCpp=1 +Link=0 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit41] +FileName=..\docs\language.pop3.txt +Folder=Documentation +Compile=0 +CompileCpp=0 +Link=0 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit42] +FileName=..\docs\language.txt +Folder=Documentation +Compile=0 +CompileCpp=0 +Link=0 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[VersionInfo] +Major=0 +Minor=1 +Release=1 +Build=1 +LanguageID=1033 +CharsetID=1252 +CompanyName= +FileVersion=0.1 +FileDescription=Developed using the Dev-C++ IDE +InternalName= +LegalCopyright= +LegalTrademarks= +OriginalFilename=YAMN.exe +ProductName=YAMN +ProductVersion=0.1 +AutoIncBuildNr=0 + diff --git a/protocols/YAMN/mingw/yamn-2in1.win b/protocols/YAMN/mingw/yamn-2in1.win new file mode 100644 index 0000000000..5b90f86916 --- /dev/null +++ b/protocols/YAMN/mingw/yamn-2in1.win @@ -0,0 +1,92 @@ +# Project: YAMN +# Makefile created by Dev-C++ 4.9.9.2 + +CPP = g++.exe +CC = gcc.exe +WINDRES = windres.exe +RES = objs2in1/YAMN.res +OBJ = objs2in1/badconnect.o objs2in1/mailbrowser.o objs2in1/decode.o objs2in1/mails.o objs2in1/mime.o objs2in1/md5.o objs2in1/netlib.o objs2in1/pop3.o objs2in1/pop3comm.o objs2in1/pop3opt.o objs2in1/ssl.o objs2in1/account.o objs2in1/debug.o objs2in1/filterplugin.o objs2in1/main.o objs2in1/protoplugin.o objs2in1/services.o objs2in1/synchro.o objs2in1/yamn.o $(RES) +LINKOBJ = objs2in1/badconnect.o objs2in1/mailbrowser.o objs2in1/decode.o objs2in1/mails.o objs2in1/mime.o objs2in1/md5.o objs2in1/netlib.o objs2in1/pop3.o objs2in1/pop3comm.o objs2in1/pop3opt.o objs2in1/ssl.o objs2in1/account.o objs2in1/debug.o objs2in1/filterplugin.o objs2in1/main.o objs2in1/protoplugin.o objs2in1/services.o objs2in1/synchro.o objs2in1/yamn.o $(RES) +LIBS = -L"../libs" -lunicows -lkernel32 -luser32 -lshell32 -lmsvcrt -lcomctl32 -lcomdlg32 -lgdi32 -lwsock32 -s +INCS = -I"../../../include" +CXXINCS = -I"../../../include" +BIN = bin2in1/yamn.dll +CXXFLAGS = $(CXXINCS) -D__GNUWIN32__ -W -fno-inline -DWIN32 -DNDEBUG -D_WINDOWS -DWIN2IN1 -w -fweb -frename-registers -Os +CFLAGS = $(INCS) -D__GNUWIN32__ -W -fno-inline -DWIN32 -DNDEBUG -D_WINDOWS -DWIN2IN1 -w -fweb -frename-registers -Os +RM = rm -f + +.PHONY: all all-before all-after clean clean-custom + +all: all-before bin2in1/yamn.dll all-after + + +clean: clean-custom + ${RM} $(OBJ) $(BIN) + +DLLWRAP=dllwrap.exe +DEFFILE=bin2in1/libYAMN.def +STATICLIB=bin2in1/libYAMN.a + +$(BIN): $(LINKOBJ) +# $(DLLWRAP) --output-def $(DEFFILE) --driver-name c++ --implib $(STATICLIB) $(LINKOBJ) $(LIBS) -o $(BIN) + $(CPP) $(LINKOBJ) $(LIBS) -o $(BIN) -mdll + +objs2in1/badconnect.o: ../browser/badconnect.cpp + $(CPP) -c ../browser/badconnect.cpp -o objs2in1/badconnect.o $(CXXFLAGS) + +objs2in1/mailbrowser.o: ../browser/mailbrowser.cpp + $(CPP) -c ../browser/mailbrowser.cpp -o objs2in1/mailbrowser.o $(CXXFLAGS) + +objs2in1/decode.o: ../mails/decode.cpp + $(CPP) -c ../mails/decode.cpp -o objs2in1/decode.o $(CXXFLAGS) + +objs2in1/mails.o: ../mails/mails.cpp + $(CPP) -c ../mails/mails.cpp -o objs2in1/mails.o $(CXXFLAGS) + +objs2in1/mime.o: ../mails/mime.cpp + $(CPP) -c ../mails/mime.cpp -o objs2in1/mime.o $(CXXFLAGS) + +objs2in1/md5.o: ../proto/md5.c + $(CC) -c ../proto/md5.c -o objs2in1/md5.o $(CFLAGS) + +objs2in1/netlib.o: ../proto/netlib.cpp + $(CPP) -c ../proto/netlib.cpp -o objs2in1/netlib.o $(CXXFLAGS) + +objs2in1/pop3.o: ../proto/pop3/pop3.cpp + $(CPP) -c ../proto/pop3/pop3.cpp -o objs2in1/pop3.o $(CXXFLAGS) + +objs2in1/pop3comm.o: ../proto/pop3/pop3comm.cpp + $(CPP) -c ../proto/pop3/pop3comm.cpp -o objs2in1/pop3comm.o $(CXXFLAGS) + +objs2in1/pop3opt.o: ../proto/pop3/pop3opt.cpp + $(CPP) -c ../proto/pop3/pop3opt.cpp -o objs2in1/pop3opt.o $(CXXFLAGS) + +objs2in1/ssl.o: ../proto/ssl.cpp + $(CPP) -c ../proto/ssl.cpp -o objs2in1/ssl.o $(CXXFLAGS) + +objs2in1/account.o: ../account.cpp + $(CPP) -c ../account.cpp -o objs2in1/account.o $(CXXFLAGS) + +objs2in1/debug.o: ../debug.cpp + $(CPP) -c ../debug.cpp -o objs2in1/debug.o $(CXXFLAGS) + +objs2in1/filterplugin.o: ../filterplugin.cpp + $(CPP) -c ../filterplugin.cpp -o objs2in1/filterplugin.o $(CXXFLAGS) + +objs2in1/main.o: ../main.cpp + $(CPP) -c ../main.cpp -o objs2in1/main.o $(CXXFLAGS) + +objs2in1/protoplugin.o: ../protoplugin.cpp + $(CPP) -c ../protoplugin.cpp -o objs2in1/protoplugin.o $(CXXFLAGS) + +objs2in1/services.o: ../services.cpp + $(CPP) -c ../services.cpp -o objs2in1/services.o $(CXXFLAGS) + +objs2in1/synchro.o: ../synchro.cpp + $(CPP) -c ../synchro.cpp -o objs2in1/synchro.o $(CXXFLAGS) + +objs2in1/yamn.o: ../yamn.cpp + $(CPP) -c ../yamn.cpp -o objs2in1/yamn.o $(CXXFLAGS) + +objs2in1/YAMN.res: ../resources/YAMN.rc + $(WINDRES) -i ../resources/YAMN.rc --input-format=rc -o objs2in1/YAMN.res -O coff --include-dir ../resources diff --git a/protocols/YAMN/mingw/yamn-w9x.dev b/protocols/YAMN/mingw/yamn-w9x.dev new file mode 100644 index 0000000000..b652000edf --- /dev/null +++ b/protocols/YAMN/mingw/yamn-w9x.dev @@ -0,0 +1,469 @@ +[Project] +FileName=yamn-w9x.dev +Name=YAMN +Ver=1 +IsCpp=1 +Type=3 +Compiler=-D__GNUWIN32__ -W -DWIN32 -DNDEBUG -D_WINDOWS -DWIN9X +CppCompiler=-D__GNUWIN32__ -W -DWIN32 -DNDEBUG -D_WINDOWS -DWIN9X +Includes=../../../include +Linker=-lunicows -lkernel32 -luser32 -lshell32 -lmsvcrt -lcomctl32 -lcomdlg32 -lgdi32 -lwsock32 --image-base "0x60010000" +Libs=../libs +UnitCount=36 +Folders=Documentation,"Resource Files",YAMN,YAMN/Header,YAMN/include,"YAMN/Mail browser, dialogs",YAMN/Mails,"YAMN/POP3 plugin" +ObjFiles= +PrivateResource=YAMN_private.rc +ResourceIncludes=../resources +MakeIncludes= +Icon= +ExeOutput=bin9x +ObjectOutput=objs9x +OverrideOutput=1 +OverrideOutputName=YAMN.dll +HostApplication= +CommandLine= +UseCustomMakefile=1 +CustomMakefile=yamn-w9x.win +IncludeVersionInfo=0 +SupportXPThemes=0 +CompilerSet=0 +CompilerSettings=0010000001001000000100 + +[Unit1] +FileName=..\browser\badconnect.cpp +Folder=YAMN/Mail browser, dialogs +Compile=1 +CompileCpp=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit2] +FileName=..\browser\mailbrowser.cpp +Folder=YAMN/Mail browser, dialogs +Compile=1 +CompileCpp=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit3] +FileName=..\mails\decode.cpp +Folder=YAMN/Mails +Compile=1 +CompileCpp=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit4] +FileName=..\mails\mails.cpp +Folder=YAMN/Mails +Compile=1 +CompileCpp=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit5] +FileName=..\mails\mime.cpp +Folder=YAMN/Mails +Compile=1 +CompileCpp=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit6] +FileName=..\proto\md5.c +Folder=YAMN/POP3 plugin +Compile=1 +CompileCpp=0 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit7] +FileName=..\proto\netlib.cpp +Folder=YAMN/POP3 plugin +Compile=1 +CompileCpp=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit8] +FileName=..\proto\pop3\pop3.cpp +Folder=YAMN/POP3 plugin +Compile=1 +CompileCpp=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit9] +FileName=..\proto\pop3\pop3comm.cpp +Folder=YAMN/POP3 plugin +Compile=1 +CompileCpp=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit10] +FileName=..\proto\pop3\pop3opt.cpp +Folder=YAMN/POP3 plugin +Compile=1 +CompileCpp=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit11] +FileName=..\proto\ssl.cpp +Folder=YAMN/POP3 plugin +Compile=1 +CompileCpp=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit12] +FileName=..\debug.h +Folder=YAMN/Header +Compile=1 +CompileCpp=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit13] +FileName=..\main.h +Folder=YAMN/Header +Compile=1 +CompileCpp=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit14] +FileName=..\proto\pop3\pop3.h +Folder=YAMN/Header +Compile=1 +CompileCpp=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit15] +FileName=..\proto\pop3\pop3comm.h +Folder=YAMN/Header +Compile=1 +CompileCpp=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit16] +FileName=..\proto\pop3\pop3opt.h +Folder=YAMN/Header +Compile=1 +CompileCpp=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit17] +FileName=..\yamn.h +Folder=YAMN/Header +Compile=1 +CompileCpp=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit18] +FileName=..\include\m_kbdnotify.h +Folder=YAMN/include +Compile=1 +CompileCpp=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit19] +FileName=..\include\m_popup.h +Folder=YAMN/include +Compile=1 +CompileCpp=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit20] +FileName=..\include\m_toptoolbar.h +Folder=YAMN/include +Compile=1 +CompileCpp=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit21] +FileName=..\include\m_uninstaller.h +Folder=YAMN/include +Compile=1 +CompileCpp=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit22] +FileName=..\include\m_updater.h +Folder=YAMN/include +Compile=1 +CompileCpp=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit23] +FileName=..\account.cpp +Folder=YAMN +Compile=1 +CompileCpp=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit24] +FileName=..\ChangeLog.txt +Folder=Documentation +Compile=0 +CompileCpp=1 +Link=0 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit25] +FileName=..\debug.cpp +Folder=YAMN +Compile=1 +CompileCpp=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit26] +FileName=..\filterplugin.cpp +Folder=YAMN +Compile=1 +CompileCpp=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit27] +FileName=..\main.cpp +Folder=YAMN +Compile=1 +CompileCpp=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit28] +FileName=..\protoplugin.cpp +Folder=YAMN +Compile=1 +CompileCpp=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit29] +FileName=..\services.cpp +Folder=YAMN +Compile=1 +CompileCpp=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit30] +FileName=..\synchro.cpp +Folder=YAMN +Compile=1 +CompileCpp=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit31] +FileName=..\yamn.cpp +Folder=YAMN +Compile=1 +CompileCpp=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit32] +FileName=..\resources\ttbfcheck.bmp +Folder=Resource Files +Compile=0 +CompileCpp=1 +Link=0 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit33] +FileName=..\resources\YAMN.rc +Folder=Resource Files +Compile=1 +CompileCpp=0 +Link=0 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit34] +FileName=..\docs\language.pop3.txt +Folder=Documentation +Compile=0 +CompileCpp=0 +Link=0 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit35] +FileName=..\docs\language.txt +Folder=Documentation +Compile=0 +CompileCpp=0 +Link=0 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit36] +FileName=..\m_messages.h +Folder=YAMN/include +Compile=1 +CompileCpp=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit37] +FileName=..\resources\icoyamn2.ico +Folder=Resource Files +Compile=0 +CompileCpp=0 +Link=0 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit38] +FileName=..\resources\icoyamn3.ico +Folder=Resource Files +Compile=0 +CompileCpp=0 +Link=0 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit39] +FileName=..\resources\ttbfcheck.bmp +Folder=Resource Files +Compile=0 +CompileCpp=0 +Link=0 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit40] +FileName=..\resources\YAMN.rc +Folder=Resource Files +Compile=1 +CompileCpp=1 +Link=0 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit41] +FileName=..\docs\language.pop3.txt +Folder=Documentation +Compile=0 +CompileCpp=0 +Link=0 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit42] +FileName=..\docs\language.txt +Folder=Documentation +Compile=0 +CompileCpp=0 +Link=0 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[VersionInfo] +Major=0 +Minor=1 +Release=1 +Build=1 +LanguageID=1033 +CharsetID=1252 +CompanyName= +FileVersion=0.1 +FileDescription=Developed using the Dev-C++ IDE +InternalName= +LegalCopyright= +LegalTrademarks= +OriginalFilename=YAMN.exe +ProductName=YAMN +ProductVersion=0.1 +AutoIncBuildNr=0 + diff --git a/protocols/YAMN/mingw/yamn-w9x.win b/protocols/YAMN/mingw/yamn-w9x.win new file mode 100644 index 0000000000..0e741d564e --- /dev/null +++ b/protocols/YAMN/mingw/yamn-w9x.win @@ -0,0 +1,92 @@ +# Project: YAMN +# Makefile created by Dev-C++ 4.9.9.2 + +CPP = g++.exe +CC = gcc.exe +WINDRES = windres.exe +RES = objs9x/YAMN.res +OBJ = objs9x/badconnect.o objs9x/mailbrowser.o objs9x/decode.o objs9x/mails.o objs9x/mime.o objs9x/md5.o objs9x/netlib.o objs9x/pop3.o objs9x/pop3comm.o objs9x/pop3opt.o objs9x/ssl.o objs9x/account.o objs9x/debug.o objs9x/filterplugin.o objs9x/main.o objs9x/protoplugin.o objs9x/services.o objs9x/synchro.o objs9x/yamn.o $(RES) +LINKOBJ = objs9x/badconnect.o objs9x/mailbrowser.o objs9x/decode.o objs9x/mails.o objs9x/mime.o objs9x/md5.o objs9x/netlib.o objs9x/pop3.o objs9x/pop3comm.o objs9x/pop3opt.o objs9x/ssl.o objs9x/account.o objs9x/debug.o objs9x/filterplugin.o objs9x/main.o objs9x/protoplugin.o objs9x/services.o objs9x/synchro.o objs9x/yamn.o $(RES) +LIBS = -L"../libs" -lunicows -lkernel32 -luser32 -lshell32 -lmsvcrt -lcomctl32 -lcomdlg32 -lgdi32 -lwsock32 -s +INCS = -I"../../../include" +CXXINCS = -I"../../../include" +BIN = bin9x/yamn.dll +CXXFLAGS = $(CXXINCS) -D__GNUWIN32__ -W -DWIN32 -DNDEBUG -D_WINDOWS -DWIN9X -w -fweb -frename-registers -Os +CFLAGS = $(INCS) -D__GNUWIN32__ -W -DWIN32 -DNDEBUG -D_WINDOWS -DWIN9X -w -fweb -frename-registers -Os +RM = rm -f + +.PHONY: all all-before all-after clean clean-custom + +all: all-before bin9x/yamn.dll all-after + + +clean: clean-custom + ${RM} $(OBJ) $(BIN) + +DLLWRAP=dllwrap.exe +DEFFILE=bin9x/libYAMN.def +STATICLIB=bin9x/libYAMN.a + +$(BIN): $(LINKOBJ) +# $(DLLWRAP) --output-def $(DEFFILE) --driver-name c++ --implib $(STATICLIB) $(LINKOBJ) $(LIBS) -o $(BIN) + $(CPP) $(LINKOBJ) $(LIBS) -o $(BIN) -mdll + +objs9x/badconnect.o: ../browser/badconnect.cpp + $(CPP) -c ../browser/badconnect.cpp -o objs9x/badconnect.o $(CXXFLAGS) + +objs9x/mailbrowser.o: ../browser/mailbrowser.cpp + $(CPP) -c ../browser/mailbrowser.cpp -o objs9x/mailbrowser.o $(CXXFLAGS) + +objs9x/decode.o: ../mails/decode.cpp + $(CPP) -c ../mails/decode.cpp -o objs9x/decode.o $(CXXFLAGS) + +objs9x/mails.o: ../mails/mails.cpp + $(CPP) -c ../mails/mails.cpp -o objs9x/mails.o $(CXXFLAGS) + +objs9x/mime.o: ../mails/mime.cpp + $(CPP) -c ../mails/mime.cpp -o objs9x/mime.o $(CXXFLAGS) + +objs9x/md5.o: ../proto/md5.c + $(CC) -c ../proto/md5.c -o objs9x/md5.o $(CFLAGS) + +objs9x/netlib.o: ../proto/netlib.cpp + $(CPP) -c ../proto/netlib.cpp -o objs9x/netlib.o $(CXXFLAGS) + +objs9x/pop3.o: ../proto/pop3/pop3.cpp + $(CPP) -c ../proto/pop3/pop3.cpp -o objs9x/pop3.o $(CXXFLAGS) + +objs9x/pop3comm.o: ../proto/pop3/pop3comm.cpp + $(CPP) -c ../proto/pop3/pop3comm.cpp -o objs9x/pop3comm.o $(CXXFLAGS) + +objs9x/pop3opt.o: ../proto/pop3/pop3opt.cpp + $(CPP) -c ../proto/pop3/pop3opt.cpp -o objs9x/pop3opt.o $(CXXFLAGS) + +objs9x/ssl.o: ../proto/ssl.cpp + $(CPP) -c ../proto/ssl.cpp -o objs9x/ssl.o $(CXXFLAGS) + +objs9x/account.o: ../account.cpp + $(CPP) -c ../account.cpp -o objs9x/account.o $(CXXFLAGS) + +objs9x/debug.o: ../debug.cpp + $(CPP) -c ../debug.cpp -o objs9x/debug.o $(CXXFLAGS) + +objs9x/filterplugin.o: ../filterplugin.cpp + $(CPP) -c ../filterplugin.cpp -o objs9x/filterplugin.o $(CXXFLAGS) + +objs9x/main.o: ../main.cpp + $(CPP) -c ../main.cpp -o objs9x/main.o $(CXXFLAGS) + +objs9x/protoplugin.o: ../protoplugin.cpp + $(CPP) -c ../protoplugin.cpp -o objs9x/protoplugin.o $(CXXFLAGS) + +objs9x/services.o: ../services.cpp + $(CPP) -c ../services.cpp -o objs9x/services.o $(CXXFLAGS) + +objs9x/synchro.o: ../synchro.cpp + $(CPP) -c ../synchro.cpp -o objs9x/synchro.o $(CXXFLAGS) + +objs9x/yamn.o: ../yamn.cpp + $(CPP) -c ../yamn.cpp -o objs9x/yamn.o $(CXXFLAGS) + +objs9x/YAMN.res: ../resources/YAMN.rc + $(WINDRES) -i ../resources/YAMN.rc --input-format=rc -o objs9x/YAMN.res -O coff --include-dir ../resources diff --git a/protocols/YAMN/mingw/yamn.dev b/protocols/YAMN/mingw/yamn.dev new file mode 100644 index 0000000000..d726894665 --- /dev/null +++ b/protocols/YAMN/mingw/yamn.dev @@ -0,0 +1,469 @@ +[Project] +FileName=yamn.dev +Name=YAMN +Ver=1 +IsCpp=1 +Type=3 +Compiler=-D__GNUWIN32__ -W -DWIN32 -DNDEBUG -D_WINDOWS +CppCompiler=-D__GNUWIN32__ -W -DWIN32 -DNDEBUG -D_WINDOWS +Includes=../../../include +Linker=-lkernel32 -luser32 -lshell32 -lmsvcrt -lcomctl32 -lcomdlg32 -lgdi32 -lwsock32 --image-base "0x60010000" +Libs= +UnitCount=36 +Folders=Documentation,"Resource Files",YAMN,YAMN/Header,YAMN/include,"YAMN/Mail browser, dialogs",YAMN/Mails,"YAMN/POP3 plugin" +ObjFiles= +PrivateResource=YAMN_private.rc +ResourceIncludes=../resources +MakeIncludes= +Icon= +ExeOutput=bin +ObjectOutput=objs +OverrideOutput=0 +OverrideOutputName=YAMN.dll +HostApplication= +CommandLine= +UseCustomMakefile=1 +CustomMakefile=yamn.win +IncludeVersionInfo=0 +SupportXPThemes=0 +CompilerSet=0 +CompilerSettings=0000000001001000000100 + +[Unit1] +FileName=..\browser\badconnect.cpp +Folder=YAMN/Mail browser, dialogs +Compile=1 +CompileCpp=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit2] +FileName=..\browser\mailbrowser.cpp +Folder=YAMN/Mail browser, dialogs +Compile=1 +CompileCpp=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit3] +FileName=..\mails\decode.cpp +Folder=YAMN/Mails +Compile=1 +CompileCpp=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit4] +FileName=..\mails\mails.cpp +Folder=YAMN/Mails +Compile=1 +CompileCpp=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit5] +FileName=..\mails\mime.cpp +Folder=YAMN/Mails +Compile=1 +CompileCpp=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit6] +FileName=..\proto\md5.c +Folder=YAMN/POP3 plugin +Compile=1 +CompileCpp=0 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit7] +FileName=..\proto\netlib.cpp +Folder=YAMN/POP3 plugin +Compile=1 +CompileCpp=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit8] +FileName=..\proto\pop3\pop3.cpp +Folder=YAMN/POP3 plugin +Compile=1 +CompileCpp=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit9] +FileName=..\proto\pop3\pop3comm.cpp +Folder=YAMN/POP3 plugin +Compile=1 +CompileCpp=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit10] +FileName=..\proto\pop3\pop3opt.cpp +Folder=YAMN/POP3 plugin +Compile=1 +CompileCpp=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit11] +FileName=..\proto\ssl.cpp +Folder=YAMN/POP3 plugin +Compile=1 +CompileCpp=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit12] +FileName=..\debug.h +Folder=YAMN/Header +Compile=1 +CompileCpp=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit13] +FileName=..\main.h +Folder=YAMN/Header +Compile=1 +CompileCpp=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit14] +FileName=..\proto\pop3\pop3.h +Folder=YAMN/Header +Compile=1 +CompileCpp=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit15] +FileName=..\proto\pop3\pop3comm.h +Folder=YAMN/Header +Compile=1 +CompileCpp=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit16] +FileName=..\proto\pop3\pop3opt.h +Folder=YAMN/Header +Compile=1 +CompileCpp=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit17] +FileName=..\yamn.h +Folder=YAMN/Header +Compile=1 +CompileCpp=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit18] +FileName=..\include\m_kbdnotify.h +Folder=YAMN/include +Compile=1 +CompileCpp=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit19] +FileName=..\include\m_popup.h +Folder=YAMN/include +Compile=1 +CompileCpp=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit20] +FileName=..\include\m_toptoolbar.h +Folder=YAMN/include +Compile=1 +CompileCpp=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit21] +FileName=..\include\m_uninstaller.h +Folder=YAMN/include +Compile=1 +CompileCpp=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit22] +FileName=..\include\m_updater.h +Folder=YAMN/include +Compile=1 +CompileCpp=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit23] +FileName=..\account.cpp +Folder=YAMN +Compile=1 +CompileCpp=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit24] +FileName=..\ChangeLog.txt +Folder=Documentation +Compile=0 +CompileCpp=1 +Link=0 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit25] +FileName=..\debug.cpp +Folder=YAMN +Compile=1 +CompileCpp=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit26] +FileName=..\filterplugin.cpp +Folder=YAMN +Compile=1 +CompileCpp=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit27] +FileName=..\main.cpp +Folder=YAMN +Compile=1 +CompileCpp=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit28] +FileName=..\protoplugin.cpp +Folder=YAMN +Compile=1 +CompileCpp=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit29] +FileName=..\services.cpp +Folder=YAMN +Compile=1 +CompileCpp=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit30] +FileName=..\synchro.cpp +Folder=YAMN +Compile=1 +CompileCpp=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit31] +FileName=..\yamn.cpp +Folder=YAMN +Compile=1 +CompileCpp=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit32] +FileName=..\resources\ttbfcheck.bmp +Folder=Resource Files +Compile=0 +CompileCpp=1 +Link=0 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit33] +FileName=..\resources\YAMN.rc +Folder=Resource Files +Compile=1 +CompileCpp=0 +Link=0 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit34] +FileName=..\docs\language.pop3.txt +Folder=Documentation +Compile=0 +CompileCpp=0 +Link=0 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit35] +FileName=..\docs\language.txt +Folder=Documentation +Compile=0 +CompileCpp=0 +Link=0 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit36] +FileName=..\m_messages.h +Folder=YAMN/include +Compile=1 +CompileCpp=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit37] +FileName=..\resources\icoyamn2.ico +Folder=Resource Files +Compile=0 +CompileCpp=0 +Link=0 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit38] +FileName=..\resources\icoyamn3.ico +Folder=Resource Files +Compile=0 +CompileCpp=0 +Link=0 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit39] +FileName=..\resources\ttbfcheck.bmp +Folder=Resource Files +Compile=0 +CompileCpp=0 +Link=0 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit40] +FileName=..\resources\YAMN.rc +Folder=Resource Files +Compile=1 +CompileCpp=1 +Link=0 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit41] +FileName=..\docs\language.pop3.txt +Folder=Documentation +Compile=0 +CompileCpp=0 +Link=0 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit42] +FileName=..\docs\language.txt +Folder=Documentation +Compile=0 +CompileCpp=0 +Link=0 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[VersionInfo] +Major=0 +Minor=1 +Release=1 +Build=1 +LanguageID=1033 +CharsetID=1252 +CompanyName= +FileVersion=0.1 +FileDescription=Developed using the Dev-C++ IDE +InternalName= +LegalCopyright= +LegalTrademarks= +OriginalFilename=YAMN.exe +ProductName=YAMN +ProductVersion=0.1 +AutoIncBuildNr=0 + diff --git a/protocols/YAMN/mingw/yamn.win b/protocols/YAMN/mingw/yamn.win new file mode 100644 index 0000000000..d396e45fca --- /dev/null +++ b/protocols/YAMN/mingw/yamn.win @@ -0,0 +1,92 @@ +# Project: YAMN +# Makefile created by Dev-C++ 4.9.9.2 + +CPP = g++.exe +CC = gcc.exe +WINDRES = windres.exe +RES = objs/YAMN.res +OBJ = objs/badconnect.o objs/mailbrowser.o objs/decode.o objs/mails.o objs/mime.o objs/md5.o objs/netlib.o objs/pop3.o objs/pop3comm.o objs/pop3opt.o objs/ssl.o objs/account.o objs/debug.o objs/filterplugin.o objs/main.o objs/protoplugin.o objs/services.o objs/synchro.o objs/yamn.o $(RES) +LINKOBJ = objs/badconnect.o objs/mailbrowser.o objs/decode.o objs/mails.o objs/mime.o objs/md5.o objs/netlib.o objs/pop3.o objs/pop3comm.o objs/pop3opt.o objs/ssl.o objs/account.o objs/debug.o objs/filterplugin.o objs/main.o objs/protoplugin.o objs/services.o objs/synchro.o objs/yamn.o $(RES) +LIBS = -lkernel32 -luser32 -lshell32 -lmsvcrt -lcomctl32 -lcomdlg32 -lgdi32 -lwsock32 -s +INCS = -I"../../../include" +CXXINCS = -I"../../../include" +BIN = bin/yamn.dll +CXXFLAGS = $(CXXINCS) -D__GNUWIN32__ -W -DWIN32 -DNDEBUG -D_WINDOWS -w -fweb -frename-registers -Os +CFLAGS = $(INCS) -D__GNUWIN32__ -W -DWIN32 -DNDEBUG -D_WINDOWS -w -fweb -frename-registers -Os +RM = rm -f + +.PHONY: all all-before all-after clean clean-custom + +all: all-before bin/yamn.dll all-after + + +clean: clean-custom + ${RM} $(OBJ) $(BIN) + +DLLWRAP=dllwrap.exe +DEFFILE=bin/libyamn.def +STATICLIB=bin/libyamn.a + +$(BIN): $(LINKOBJ) +# $(DLLWRAP) --output-def $(DEFFILE) --driver-name c++ --implib $(STATICLIB) $(LINKOBJ) $(LIBS) -o $(BIN) + $(CPP) $(LINKOBJ) $(LIBS) -o $(BIN) -mdll + +objs/badconnect.o: ../browser/badconnect.cpp + $(CPP) -c ../browser/badconnect.cpp -o objs/badconnect.o $(CXXFLAGS) + +objs/mailbrowser.o: ../browser/mailbrowser.cpp + $(CPP) -c ../browser/mailbrowser.cpp -o objs/mailbrowser.o $(CXXFLAGS) + +objs/decode.o: ../mails/decode.cpp + $(CPP) -c ../mails/decode.cpp -o objs/decode.o $(CXXFLAGS) + +objs/mails.o: ../mails/mails.cpp + $(CPP) -c ../mails/mails.cpp -o objs/mails.o $(CXXFLAGS) + +objs/mime.o: ../mails/mime.cpp + $(CPP) -c ../mails/mime.cpp -o objs/mime.o $(CXXFLAGS) + +objs/md5.o: ../proto/md5.c + $(CC) -c ../proto/md5.c -o objs/md5.o $(CFLAGS) + +objs/netlib.o: ../proto/netlib.cpp + $(CPP) -c ../proto/netlib.cpp -o objs/netlib.o $(CXXFLAGS) + +objs/pop3.o: ../proto/pop3/pop3.cpp + $(CPP) -c ../proto/pop3/pop3.cpp -o objs/pop3.o $(CXXFLAGS) + +objs/pop3comm.o: ../proto/pop3/pop3comm.cpp + $(CPP) -c ../proto/pop3/pop3comm.cpp -o objs/pop3comm.o $(CXXFLAGS) + +objs/pop3opt.o: ../proto/pop3/pop3opt.cpp + $(CPP) -c ../proto/pop3/pop3opt.cpp -o objs/pop3opt.o $(CXXFLAGS) + +objs/ssl.o: ../proto/ssl.cpp + $(CPP) -c ../proto/ssl.cpp -o objs/ssl.o $(CXXFLAGS) + +objs/account.o: ../account.cpp + $(CPP) -c ../account.cpp -o objs/account.o $(CXXFLAGS) + +objs/debug.o: ../debug.cpp + $(CPP) -c ../debug.cpp -o objs/debug.o $(CXXFLAGS) + +objs/filterplugin.o: ../filterplugin.cpp + $(CPP) -c ../filterplugin.cpp -o objs/filterplugin.o $(CXXFLAGS) + +objs/main.o: ../main.cpp + $(CPP) -c ../main.cpp -o objs/main.o $(CXXFLAGS) + +objs/protoplugin.o: ../protoplugin.cpp + $(CPP) -c ../protoplugin.cpp -o objs/protoplugin.o $(CXXFLAGS) + +objs/services.o: ../services.cpp + $(CPP) -c ../services.cpp -o objs/services.o $(CXXFLAGS) + +objs/synchro.o: ../synchro.cpp + $(CPP) -c ../synchro.cpp -o objs/synchro.o $(CXXFLAGS) + +objs/yamn.o: ../yamn.cpp + $(CPP) -c ../yamn.cpp -o objs/yamn.o $(CXXFLAGS) + +objs/YAMN.res: ../resources/YAMN.rc + $(WINDRES) -i ../resources/YAMN.rc --input-format=rc -o objs/YAMN.res -O coff --include-dir ../resources diff --git a/protocols/YAMN/proto/md5.c b/protocols/YAMN/proto/md5.c new file mode 100644 index 0000000000..25546d2a65 --- /dev/null +++ b/protocols/YAMN/proto/md5.c @@ -0,0 +1,260 @@ +/* + * This code implements the MD5 message-digest algorithm. + * The algorithm is due to Ron Rivest. This code was + * written by Colin Plumb in 1993, no copyright is claimed. + * This code is in the public domain; do with it what you wish. + * + * Equivalent code is available from RSA Data Security, Inc. + * This code has been tested against that, and is equivalent, + * except that you don't need to include two pages of legalese + * with every copy. + * + * To compute the message digest of a chunk of bytes, declare an + * MD5Context structure, pass it to MD5Init, call MD5Update as + * needed on buffers full of bytes, and then call MD5Final, which + * will fill a supplied 16-byte array with the digest. + */ +//#include /* for memcpy() */ +#if defined(_WIN64) + typedef unsigned __int64 size_t; +#else + typedef unsigned int size_t; + #include "../filter/simple/AggressiveOptimize.h" +#endif +void * __cdecl memcpy(void *, const void *, size_t); +void * __cdecl memset(void *, int, size_t); +#include "md5.h" + +#ifndef HIGHFIRST +#define byteReverse(buf, len) /* Nothing */ +#else +void byteReverse(unsigned char *buf, unsigned longs); + +#ifndef ASM_MD5 +/* + * Note: this code is harmless on little-endian machines. + */ +void byteReverse(unsigned char *buf, unsigned longs) +{ + uint32 t; + do { + t = (uint32) ((unsigned) buf[3] << 8 | buf[2]) << 16 | + ((unsigned) buf[1] << 8 | buf[0]); + *(uint32 *) buf = t; + buf += 4; + } while (--longs); +} +#endif +#endif + +/* + * Start MD5 accumulation. Set bit count to 0 and buffer to mysterious + * initialization constants. + */ +void MD5Init(struct MD5Context *ctx) +{ + ctx->buf[0] = 0x67452301; + ctx->buf[1] = 0xefcdab89; + ctx->buf[2] = 0x98badcfe; + ctx->buf[3] = 0x10325476; + + ctx->bits[0] = 0; + ctx->bits[1] = 0; +} + +/* + * Update context to reflect the concatenation of another buffer full + * of bytes. + */ +void MD5Update(struct MD5Context *ctx, unsigned char const *buf, unsigned len) +{ + uint32 t; + + /* Update bitcount */ + + t = ctx->bits[0]; + if ((ctx->bits[0] = t + ((uint32) len << 3)) < t) + ctx->bits[1]++; /* Carry from low to high */ + ctx->bits[1] += len >> 29; + + t = (t >> 3) & 0x3f; /* Bytes already in shsInfo->data */ + + /* Handle any leading odd-sized chunks */ + + if (t) { + unsigned char *p = (unsigned char *) ctx->in + t; + + t = 64 - t; + if (len < t) { + memcpy(p, buf, len); + return; + } + memcpy(p, buf, t); + byteReverse(ctx->in, 16); + MD5Transform(ctx->buf, (uint32 *) ctx->in); + buf += t; + len -= t; + } + /* Process data in 64-byte chunks */ + + while (len >= 64) { + memcpy(ctx->in, buf, 64); + byteReverse(ctx->in, 16); + MD5Transform(ctx->buf, (uint32 *) ctx->in); + buf += 64; + len -= 64; + } + + /* Handle any remaining bytes of data. */ + + memcpy(ctx->in, buf, len); +} + +/* + * Final wrapup - pad to 64-byte boundary with the bit pattern + * 1 0* (64-bit count of bits processed, MSB-first) + */ +void MD5Final(unsigned char digest[16], struct MD5Context *ctx) +{ + unsigned count; + unsigned char *p; + + /* Compute number of bytes mod 64 */ + count = (ctx->bits[0] >> 3) & 0x3F; + + /* Set the first char of padding to 0x80. This is safe since there is + always at least one byte free */ + p = ctx->in + count; + *p++ = 0x80; + + /* Bytes of padding needed to make 64 bytes */ + count = 64 - 1 - count; + + /* Pad out to 56 mod 64 */ + if (count < 8) { + /* Two lots of padding: Pad the first block to 64 bytes */ + memset(p, 0, count); + byteReverse(ctx->in, 16); + MD5Transform(ctx->buf, (uint32 *) ctx->in); + + /* Now fill the next block with 56 bytes */ + memset(ctx->in, 0, 56); + } else { + /* Pad block to 56 bytes */ + memset(p, 0, count - 8); + } + byteReverse(ctx->in, 14); + + /* Append length in bits and transform */ + ((uint32 *) ctx->in)[14] = ctx->bits[0]; + ((uint32 *) ctx->in)[15] = ctx->bits[1]; + + MD5Transform(ctx->buf, (uint32 *) ctx->in); + byteReverse((unsigned char *) ctx->buf, 4); + memcpy(digest, ctx->buf, 16); + memset(ctx, 0, sizeof(ctx)); /* In case it's sensitive */ +} + +#ifndef ASM_MD5 + +/* The four core functions - F1 is optimized somewhat */ + +/* #define F1(x, y, z) (x & y | ~x & z) */ +#define F1(x, y, z) (z ^ (x & (y ^ z))) +#define F2(x, y, z) F1(z, x, y) +#define F3(x, y, z) (x ^ y ^ z) +#define F4(x, y, z) (y ^ (x | ~z)) + +/* This is the central step in the MD5 algorithm. */ +#define MD5STEP(f, w, x, y, z, data, s) \ + ( w += f(x, y, z) + data, w = w<>(32-s), w += x ) + +/* + * The core of the MD5 algorithm, this alters an existing MD5 hash to + * reflect the addition of 16 longwords of new data. MD5Update blocks + * the data and converts bytes into longwords for this routine. + */ +void MD5Transform(uint32 buf[4], uint32 const in[16]) +{ + register uint32 a, b, c, d; + + a = buf[0]; + b = buf[1]; + c = buf[2]; + d = buf[3]; + + MD5STEP(F1, a, b, c, d, in[0] + 0xd76aa478, 7); + MD5STEP(F1, d, a, b, c, in[1] + 0xe8c7b756, 12); + MD5STEP(F1, c, d, a, b, in[2] + 0x242070db, 17); + MD5STEP(F1, b, c, d, a, in[3] + 0xc1bdceee, 22); + MD5STEP(F1, a, b, c, d, in[4] + 0xf57c0faf, 7); + MD5STEP(F1, d, a, b, c, in[5] + 0x4787c62a, 12); + MD5STEP(F1, c, d, a, b, in[6] + 0xa8304613, 17); + MD5STEP(F1, b, c, d, a, in[7] + 0xfd469501, 22); + MD5STEP(F1, a, b, c, d, in[8] + 0x698098d8, 7); + MD5STEP(F1, d, a, b, c, in[9] + 0x8b44f7af, 12); + MD5STEP(F1, c, d, a, b, in[10] + 0xffff5bb1, 17); + MD5STEP(F1, b, c, d, a, in[11] + 0x895cd7be, 22); + MD5STEP(F1, a, b, c, d, in[12] + 0x6b901122, 7); + MD5STEP(F1, d, a, b, c, in[13] + 0xfd987193, 12); + MD5STEP(F1, c, d, a, b, in[14] + 0xa679438e, 17); + MD5STEP(F1, b, c, d, a, in[15] + 0x49b40821, 22); + + MD5STEP(F2, a, b, c, d, in[1] + 0xf61e2562, 5); + MD5STEP(F2, d, a, b, c, in[6] + 0xc040b340, 9); + MD5STEP(F2, c, d, a, b, in[11] + 0x265e5a51, 14); + MD5STEP(F2, b, c, d, a, in[0] + 0xe9b6c7aa, 20); + MD5STEP(F2, a, b, c, d, in[5] + 0xd62f105d, 5); + MD5STEP(F2, d, a, b, c, in[10] + 0x02441453, 9); + MD5STEP(F2, c, d, a, b, in[15] + 0xd8a1e681, 14); + MD5STEP(F2, b, c, d, a, in[4] + 0xe7d3fbc8, 20); + MD5STEP(F2, a, b, c, d, in[9] + 0x21e1cde6, 5); + MD5STEP(F2, d, a, b, c, in[14] + 0xc33707d6, 9); + MD5STEP(F2, c, d, a, b, in[3] + 0xf4d50d87, 14); + MD5STEP(F2, b, c, d, a, in[8] + 0x455a14ed, 20); + MD5STEP(F2, a, b, c, d, in[13] + 0xa9e3e905, 5); + MD5STEP(F2, d, a, b, c, in[2] + 0xfcefa3f8, 9); + MD5STEP(F2, c, d, a, b, in[7] + 0x676f02d9, 14); + MD5STEP(F2, b, c, d, a, in[12] + 0x8d2a4c8a, 20); + + MD5STEP(F3, a, b, c, d, in[5] + 0xfffa3942, 4); + MD5STEP(F3, d, a, b, c, in[8] + 0x8771f681, 11); + MD5STEP(F3, c, d, a, b, in[11] + 0x6d9d6122, 16); + MD5STEP(F3, b, c, d, a, in[14] + 0xfde5380c, 23); + MD5STEP(F3, a, b, c, d, in[1] + 0xa4beea44, 4); + MD5STEP(F3, d, a, b, c, in[4] + 0x4bdecfa9, 11); + MD5STEP(F3, c, d, a, b, in[7] + 0xf6bb4b60, 16); + MD5STEP(F3, b, c, d, a, in[10] + 0xbebfbc70, 23); + MD5STEP(F3, a, b, c, d, in[13] + 0x289b7ec6, 4); + MD5STEP(F3, d, a, b, c, in[0] + 0xeaa127fa, 11); + MD5STEP(F3, c, d, a, b, in[3] + 0xd4ef3085, 16); + MD5STEP(F3, b, c, d, a, in[6] + 0x04881d05, 23); + MD5STEP(F3, a, b, c, d, in[9] + 0xd9d4d039, 4); + MD5STEP(F3, d, a, b, c, in[12] + 0xe6db99e5, 11); + MD5STEP(F3, c, d, a, b, in[15] + 0x1fa27cf8, 16); + MD5STEP(F3, b, c, d, a, in[2] + 0xc4ac5665, 23); + + MD5STEP(F4, a, b, c, d, in[0] + 0xf4292244, 6); + MD5STEP(F4, d, a, b, c, in[7] + 0x432aff97, 10); + MD5STEP(F4, c, d, a, b, in[14] + 0xab9423a7, 15); + MD5STEP(F4, b, c, d, a, in[5] + 0xfc93a039, 21); + MD5STEP(F4, a, b, c, d, in[12] + 0x655b59c3, 6); + MD5STEP(F4, d, a, b, c, in[3] + 0x8f0ccc92, 10); + MD5STEP(F4, c, d, a, b, in[10] + 0xffeff47d, 15); + MD5STEP(F4, b, c, d, a, in[1] + 0x85845dd1, 21); + MD5STEP(F4, a, b, c, d, in[8] + 0x6fa87e4f, 6); + MD5STEP(F4, d, a, b, c, in[15] + 0xfe2ce6e0, 10); + MD5STEP(F4, c, d, a, b, in[6] + 0xa3014314, 15); + MD5STEP(F4, b, c, d, a, in[13] + 0x4e0811a1, 21); + MD5STEP(F4, a, b, c, d, in[4] + 0xf7537e82, 6); + MD5STEP(F4, d, a, b, c, in[11] + 0xbd3af235, 10); + MD5STEP(F4, c, d, a, b, in[2] + 0x2ad7d2bb, 15); + MD5STEP(F4, b, c, d, a, in[9] + 0xeb86d391, 21); + + buf[0] += a; + buf[1] += b; + buf[2] += c; + buf[3] += d; +} + +#endif diff --git a/protocols/YAMN/proto/md5.h b/protocols/YAMN/proto/md5.h new file mode 100644 index 0000000000..e264f686db --- /dev/null +++ b/protocols/YAMN/proto/md5.h @@ -0,0 +1,27 @@ +#ifndef MD5_H +#define MD5_H + +#ifdef __alpha +typedef unsigned int uint32; +#else +typedef unsigned long uint32; +#endif + +struct MD5Context { + uint32 buf[4]; + uint32 bits[2]; + unsigned char in[64]; +}; + +void MD5Init(struct MD5Context *context); +void MD5Update(struct MD5Context *context, unsigned char const *buf, + unsigned len); +void MD5Final(unsigned char digest[16], struct MD5Context *context); +void MD5Transform(uint32 buf[4], uint32 const in[16]); + +/* + * This is needed to make RSAREF happy on some MS-DOS compilers. + */ +typedef struct MD5Context MD5_CTX; + +#endif /* !MD5_H */ diff --git a/protocols/YAMN/proto/netclient.h b/protocols/YAMN/proto/netclient.h new file mode 100644 index 0000000000..2414dbdef1 --- /dev/null +++ b/protocols/YAMN/proto/netclient.h @@ -0,0 +1,22 @@ +#ifndef __CLIENT_H +#define __CLIENT_H + +class CNetClient +{ +public: + CNetClient(): Stopped(FALSE) {} + virtual void Connect(const char* servername,const int port)=0; + virtual void Send(const char *query)=0; + virtual char* Recv(char *buf=NULL,int buflen=65536)=0; + virtual void Disconnect()=0; + virtual BOOL Connected()=0; + virtual void SSLify()=0; + + BOOL Stopped; + int Rcv; + DWORD NetworkError; + DWORD SystemError; + BOOL ifTLSed; +}; + +#endif diff --git a/protocols/YAMN/proto/netlib.cpp b/protocols/YAMN/proto/netlib.cpp new file mode 100644 index 0000000000..b7c1864ffa --- /dev/null +++ b/protocols/YAMN/proto/netlib.cpp @@ -0,0 +1,271 @@ +/* + * This code implements communication based on Miranda netlib library + * + * (c) majvan 2002-2004 + */ + +#include "..\yamn.h" +#include "m_netlib.h" +#include "netlib.h" + +//-------------------------------------------------------------------------------------------------- +//-------------------------------------------------------------------------------------------------- + +BOOL SSLLoaded=FALSE; +HANDLE hNetlibUser=NULL; + +extern PVOID TLSCtx; +extern PVOID SSLCtx; + +void __stdcall SSL_DebugLog(const char *fmt, ...) +{ + char str[ 4096 ]; + va_list vararg; + + va_start( vararg, fmt ); + int tBytes = _vsnprintf( str, sizeof(str)-1, fmt, vararg ); + if ( tBytes == 0 ) + return; + + if ( tBytes > 0 ) + str[ tBytes ] = 0; + else + str[ sizeof(str)-1 ] = 0; + + CallService(MS_NETLIB_LOG, (WPARAM)hNetlibUser, (LPARAM)str); + va_end( vararg ); +} + +HANDLE RegisterNLClient(const char *name) +{ + static NETLIBUSER nlu={0}; + char desc[128]; + + sprintf(desc, Translate("%s connection"),name); + +#ifdef DEBUG_COMM + DebugLog(CommFile,""); +#endif + nlu.cbSize = sizeof(nlu); + nlu.flags = NUF_OUTGOING | NUF_HTTPCONNS; + nlu.szDescriptiveName=desc; + nlu.szSettingsModule=(char *)name; + hNetlibUser=(HANDLE)CallService(MS_NETLIB_REGISTERUSER,0,(LPARAM)&nlu); + +#ifdef DEBUG_COMM + if (NULL==hNetlibUser) + DebugLog(CommFile,"\n"); + else + DebugLog(CommFile,"\n"); +#endif + return hNetlibUser; +} + +//Move connection to SSL +void CNLClient::SSLify() throw(DWORD){ +#ifdef DEBUG_COMM + SSL_DebugLog("Staring SSL..."); +#endif + int socket = CallService(MS_NETLIB_GETSOCKET, (WPARAM)hConnection, 0); + if (socket != INVALID_SOCKET) + { +#ifdef DEBUG_COMM + SSL_DebugLog("Staring netlib core SSL"); +#endif + if (CallService(MS_NETLIB_STARTSSL, (WPARAM)hConnection, 0)) + { +#ifdef DEBUG_COMM + SSL_DebugLog("Netlib core SSL started"); +#endif + isTLSed = true; + SSLLoaded = TRUE; + return; + } + } + + //ssl could not be created + throw NetworkError = (DWORD)ESSL_CREATESSL; +} + +//Connects to the server through the sock +//if not success, exception is throwed +void CNLClient::Connect(const char* servername,const int port) throw(DWORD) +{ + NETLIBOPENCONNECTION nloc; + + NetworkError=SystemError=0; + isTLSed = false; + +#ifdef DEBUG_COMM + DebugLog(CommFile,"\n"); +#endif + try + { + nloc.cbSize=sizeof(NETLIBOPENCONNECTION); + nloc.szHost=servername; + nloc.wPort=port; + nloc.flags=0; + if (NULL==(hConnection=(HANDLE)CallService(MS_NETLIB_OPENCONNECTION,(WPARAM)hNetlibUser,(LPARAM)&nloc))) + { + SystemError=WSAGetLastError(); + throw NetworkError=(DWORD)ENL_CONNECT; + } +#ifdef DEBUG_COMM + DebugLog(CommFile,"\n"); +#endif + return; + } + catch(...) + { +#ifdef DEBUG_COMM + DebugLog(CommFile,"\n"); +#endif + throw; + } +} + +//Performs a simple query +// query- command to send +int CNLClient::LocalNetlib_Send(HANDLE hConn,const char *buf,int len,int flags) { + if (isTLSed) + { +#ifdef DEBUG_COMM + SSL_DebugLog("SSL send: %s", buf); +#endif + } + + NETLIBBUFFER nlb={(char*)buf,len,flags}; + return CallService(MS_NETLIB_SEND,(WPARAM)hConn,(LPARAM)&nlb); +} + +void CNLClient::Send(const char *query) throw(DWORD) +{ + unsigned int Sent; + + if (NULL==query) + return; + if (hConnection==NULL) + return; +#ifdef DEBUG_COMM + DebugLog(CommFile,"%s",query); +#endif + try + { + if ((SOCKET_ERROR==(Sent=LocalNetlib_Send(hConnection,query,(int)strlen(query),MSG_DUMPASTEXT))) || Sent!=(unsigned int)strlen(query)) + { + SystemError=WSAGetLastError(); + throw NetworkError=(DWORD)ENL_SEND; + } +#ifdef DEBUG_COMM + DebugLog(CommFile,"\n"); +#endif + } + catch(...) + { +#ifdef DEBUG_COMM + DebugLog(CommFile,"\n"); +#endif + throw; + } +} + +//Reads data from socket +// buf- buffer where to store max. buflen of received characters +// if buf is NULL, creates buffer of buflen size +// buf is NULL by default +//You need free() returned buffer, which can be allocated in this function +//if not success, exception is throwed + +int CNLClient::LocalNetlib_Recv(HANDLE hConn,char *buf,int len,int flags) { + NETLIBBUFFER nlb={buf,len,flags}; + int iReturn = CallService(MS_NETLIB_RECV,(WPARAM)hConn,(LPARAM)&nlb); + if (isTLSed) + { +#ifdef DEBUG_COMM + SSL_DebugLog("SSL recv: %s", buf); +#endif + } + + return iReturn; +} + +char* CNLClient::Recv(char *buf,int buflen) throw(DWORD) +{ +#ifdef DEBUG_COMM + DebugLog(CommFile,""); +#endif + try + { + if (buf==NULL) + buf=(char *)malloc(sizeof(char)*(buflen+1)); + if (buf==NULL) + throw NetworkError=(DWORD)ENL_RECVALLOC; + + if (!isTLSed) + { + NETLIBSELECT nls; + memset(&nls, 0, sizeof(NETLIBSELECT)); + nls.cbSize = sizeof(NETLIBSELECT); + nls.dwTimeout = 60000; + nls.hReadConns[0] = hConnection; + switch (CallService(MS_NETLIB_SELECT, 0, (LPARAM) &nls)) + { + case SOCKET_ERROR: + free(buf); + SystemError=WSAGetLastError(); + throw NetworkError = (DWORD) ENL_RECV; + case 0: // time out! + free(buf); + throw NetworkError = (DWORD) ENL_TIMEOUT; + } + } + + ZeroMemory(buf,buflen); + if (SOCKET_ERROR==(Rcv=LocalNetlib_Recv(hConnection,buf,buflen,MSG_DUMPASTEXT))) + { + free(buf); + SystemError=WSAGetLastError(); + throw NetworkError=(DWORD)ENL_RECV; + } + if (!Rcv) + { + free(buf); + SystemError=WSAGetLastError(); + throw NetworkError=(DWORD)ENL_RECV; + } +#ifdef DEBUG_COMM + *(buf+Rcv)=0; //end the buffer to write it to file + DebugLog(CommFile,"%s",buf); + DebugLog(CommFile,"\n"); +#endif + return(buf); + } + catch(...) + { +#ifdef DEBUG_COMM + DebugLog(CommFile,"\n"); +#endif + throw; + } +} + +//Closes netlib connection +void CNLClient::Disconnect() +{ + Netlib_CloseHandle(hConnection); + hConnection=(HANDLE)NULL; +} + +//Uninitializes netlib library +void UnregisterNLClient() +{ +#ifdef DEBUG_COMM + DebugLog(CommFile,""); +#endif + + Netlib_CloseHandle(hNetlibUser); + hNetlibUser=(HANDLE)NULL; +#ifdef DEBUG_COMM + DebugLog(CommFile,"\n"); +#endif +} diff --git a/protocols/YAMN/proto/netlib.h b/protocols/YAMN/proto/netlib.h new file mode 100644 index 0000000000..90ad3613a5 --- /dev/null +++ b/protocols/YAMN/proto/netlib.h @@ -0,0 +1,55 @@ +#ifndef __NETLIB_H +#define __NETLIB_H + +#include "netclient.h" + +#pragma warning( disable : 4290 ) + +class CNLClient: public CNetClient +{ +public: + CNLClient(): hConnection(NULL) {} + void Connect(const char* servername,const int port) throw(DWORD); + void Send(const char *query) throw(DWORD); + char* Recv(char *buf=NULL,int buflen=65536) throw(DWORD); + void Disconnect(); + void SSLify()throw(DWORD); + + inline BOOL Connected() {return hConnection!=NULL;} + +protected: + HANDLE hConnection; + BOOL isTLSed; + int LocalNetlib_Send(HANDLE hConn,const char *buf,int len,int flags); + int LocalNetlib_Recv(HANDLE hConn,char *buf,int len,int flags); +}; + +void SSL_DebugLog(const char *fmt, ...); + +enum +{ + ENL_WINSOCKINIT=1, //error initializing socket //only wsock + ENL_GETHOSTBYNAME, //DNS error //only wsock + ENL_CREATESOCKET, //error creating socket //only wsock + ENL_CONNECT, //cannot connect to server + ENL_SEND, //cannot send data + ENL_RECV, //cannot receive data + ENL_RECVALLOC, //cannot allocate memory for received data + ENL_TIMEOUT, //timed out during recv +}; + +enum +{ + ESSL_NOTLOADED=1, //OpenSSL is not loaded + ESSL_WINSOCKINIT, //WinSock 2.0 init failed + ESSL_GETHOSTBYNAME, //DNS error + ESSL_CREATESOCKET, //error creating socket + ESSL_SOCKETCONNECT, //error connecting with socket + ESSL_CREATESSL, //error creating SSL session structure + ESSL_SETSOCKET, //error connect socket with SSL session for bidirect I/O space + ESSL_CONNECT, //cannot connect to server + ESSL_SEND, //cannot send data + ESSL_RECV, //cannot receive data + ESSL_RECVALLOC, //cannot allocate memory for received data +}; +#endif diff --git a/protocols/YAMN/proto/pop3/pop3.cpp b/protocols/YAMN/proto/pop3/pop3.cpp new file mode 100644 index 0000000000..05e85d7156 --- /dev/null +++ b/protocols/YAMN/proto/pop3/pop3.cpp @@ -0,0 +1,370 @@ +/* + * This code implements basics of POP3 protocol + * + * (c) majvan 2002-2004 + */ +/* This was made from the libspopc project + * copyright c 2002 Benoit Rouits + * released under the terms of GNU LGPL + * (GNU Lesser General Public Licence). + * libspopc offers simple API for a pop3 client (MTA). + * See RFC 1725 for pop3 specifications. + * more information on http://brouits.free.fr/libspopc/ + */ +/* + * This file is not original and is changed by majvan + * for mail checker purpose. Please see original web page to + * obtain the original. I rewrote it in C++, but good ideas were, + * I think, unchanged. + * + * Note that this file was not designed to work under Unix. It's + * needed to add Unix-specific features. I was interested only in + * Windows for my project. majvan + * + */ + +#pragma warning( disable : 4290 ) + +#include "..\..\yamn.h" +#include "pop3.h" + +extern "C" { +#include "../md5.h" +} + +extern void __stdcall SSL_DebugLog( const char *fmt, ... ); + +//-------------------------------------------------------------------------------------------------- +//-------------------------------------------------------------------------------------------------- + +//Connects to the server through the netlib +//if not success, exception is throwed +//returns welcome string returned by server +//sets AckFlag +char *CPop3Client::Connect(const char* servername,const int port,BOOL UseSSL, BOOL NoTLS) +{ + char *temp = 0; + if (Stopped) //check if we can work with this POP3 client session + throw POP3Error=(DWORD)EPOP3_STOPPED; + + if (NetClient!=NULL) + delete NetClient; + SSL=UseSSL; + NetClient=new CNLClient; + +#ifdef DEBUG_DECODE + DebugLog(DecodeFile,"Connect:servername: %s port:%d\n",servername,port); +#endif + POP3Error=EPOP3_CONNECT; + NetClient->Connect(servername,port); + POP3Error=0; + + if (SSL) + { + try { NetClient->SSLify(); } + catch (...) + { + NetClient->Disconnect(); + return NULL; + } + } + + temp = RecvRest(NetClient->Recv(),POP3_SEARCHACK); + extern BOOL SSLLoaded; + if (!NoTLS & !(SSL)) { + if (NetClient->Stopped) //check if we can work with this POP3 client session + throw POP3Error=(DWORD)EPOP3_STOPPED; + NetClient->Send("STLS\r\n"); + free(temp); + temp=RecvRest(NetClient->Recv(),POP3_SEARCHACK); + if (AckFlag==POP3_FOK){ // Ok, we are going to tls + try { + NetClient->SSLify(); + } catch (...) { + NetClient->Disconnect(); + return NULL; + } +// temp = RecvRest(NetClient->Recv(),POP3_SEARCHACK); + } + } +// SSL_DebugLog("Received: %s",temp); + return temp; +} + +//Receives data to the end of packet +// prev- previous data read (appends to this string next received data) +// mode- mode of packet. +// Packet can end with ack state (+OK or -ERR): set mode to POP3_SEARCHACK +// If packet ends with '.' (end of string), set mode to POP3_SEARCHDOT +// size- received data are stored to memory, but if length of data is more than allocated memory, function allocates +// new memory. New allocated memory has allocated size more bytes +// This value can be selectable: if you think it is better to reallocate by 1kB size, select size to 1024, +// default is 128. You do not need to use this parameter +char* CPop3Client::RecvRest(char* prev,int mode,int size) +{ + int SizeRead=0; + int SizeLeft=size-NetClient->Rcv; + int RcvAll=NetClient->Rcv; + char *LastString,*PrevString=prev; + + AckFlag=0; + + while(((mode==POP3_SEARCHDOT) && !SearchFromEnd(PrevString+RcvAll-1,RcvAll-3,POP3_SEARCHDOT) && !SearchFromStart(PrevString,2,POP3_SEARCHERR)) || //we are looking for dot or -err phrase + ((mode==POP3_SEARCHACK) && (!SearchFromStart(PrevString,RcvAll-3,mode) || !((RcvAll>3) && SearchFromEnd(PrevString+RcvAll-1,1,POP3_SEARCHNL))))) //we are looking for +ok or -err phrase ended with newline + { //if not found + if (NetClient->Stopped) //check if we can work with this POP3 client session + { + if (PrevString!=NULL) + free(PrevString); + throw POP3Error=(DWORD)EPOP3_STOPPED; + } + if (SizeLeft==0) //if block is full + { + SizeRead+=size; + SizeLeft=size; + LastString=NetClient->Recv(NULL,SizeLeft); + PrevString=(char *)realloc(PrevString,sizeof(char)*(SizeRead+size)); + if (PrevString==NULL) + throw POP3Error=(DWORD)EPOP3_RESTALLOC; + memcpy(PrevString+SizeRead,LastString,size); + free(LastString); + } + else + NetClient->Recv(PrevString+RcvAll,SizeLeft); //to Rcv stores received bytes + SizeLeft=SizeLeft-NetClient->Rcv; + RcvAll+=NetClient->Rcv; +// printf("[Read: %s]\n",PrevString); + } + NetClient->Rcv=RcvAll; //at the end, store the number of all bytes, no the number of last received bytes + return PrevString; +} + +// CPop3Client::SearchFromEnd +// returns 1 if substring DOTLINE or ENDLINE found from end in bs bytes +// if you need to add condition for mode, insert it into switch statement +BOOL CPop3Client::SearchFromEnd(char *end,int bs,int mode) +{ + while(bs>=0) + { + switch(mode) + { + case POP3_SEARCHDOT: + if (DOTLINE(end)) + return 1; + break; + case POP3_SEARCHNL: + if (ENDLINE(end)) + return 1; + break; + } + end--; + bs--; + } + return 0; +} + +//Finds for a occurence of some pattern in string +// returns 1 if substring OKLINE, ERRLINE or any of them found from start in bs bytes +//call only this function to retrieve ack status (+OK or -ERR), because it sets flag AckFlag +//if you need to add condition for mode, insert it into switch statement +BOOL CPop3Client::SearchFromStart(char *start,int bs,int mode) +{ + while(bs>=0) + { + switch(mode) + { + case POP3_SEARCHOK: + if (OKLINE(start)) + { + AckFlag=POP3_FOK; + return 1; + } + break; + case POP3_SEARCHERR: + if (ERRLINE(start)) + { + AckFlag=POP3_FERR; + return 1; + } + break; + case POP3_SEARCHACK: + if (ACKLINE(start)) + { + OKLINE(start) ? AckFlag=POP3_FOK : AckFlag=POP3_FERR; + return 1; + } + break; + } + start++; + bs--; + } + return 0; +} + +//Performs "USER" pop query and returns server response +//sets AckFlag +char* CPop3Client::User(char* name) +{ + if (NetClient->Stopped) //check if we can work with this POP3 client session + throw POP3Error=(DWORD)EPOP3_STOPPED; + + char query[128]; + char *Result; + + sprintf(query,"USER %s\r\n",name); + NetClient->Send(query); + Result=RecvRest(NetClient->Recv(),POP3_SEARCHACK); + if (AckFlag==POP3_FERR) + throw POP3Error=(DWORD)EPOP3_BADUSER; + POP3Error=0; + return Result; +} + +//Performs "PASS" pop query and returns server response +//sets AckFlag +char* CPop3Client::Pass(char* pw) +{ + if (NetClient->Stopped) //check if we can work with this POP3 client session + throw POP3Error=(DWORD)EPOP3_STOPPED; + + char query[128]; + char *Result; + + sprintf(query,"PASS %s\r\n",pw); + NetClient->Send(query); + Result=RecvRest(NetClient->Recv(),POP3_SEARCHACK); + if (AckFlag==POP3_FERR) + throw POP3Error=(DWORD)EPOP3_BADPASS; + return Result; +} + +//Performs "APOP" pop query and returns server response +//sets AckFlag +char* CPop3Client::APOP(char* name, char* pw, char* timestamp) +{ + if (NetClient->Stopped) //check if we can work with this POP3 client session + throw POP3Error=(DWORD)EPOP3_STOPPED; + + char query[512]; + char *Result; + unsigned char digest[16]; + char hexdigest[40]; + + if (timestamp==NULL) + throw POP3Error=(DWORD)EPOP3_APOP; + MD5Context ctx; + MD5Init(&ctx); + MD5Update(&ctx,(const unsigned char *)timestamp,(unsigned int)strlen(timestamp)); + MD5Update(&ctx,(const unsigned char *)pw,(unsigned int)strlen(pw)); + MD5Final(digest,&ctx); + hexdigest[0]='\0'; + for (int i=0; i<16; i++) { + char tmp[4]; + sprintf(tmp, "%02x", digest[i]); + strcat(hexdigest, tmp); + } + sprintf(query,"APOP %s %s\r\n",name, hexdigest); + NetClient->Send(query); + Result=RecvRest(NetClient->Recv(),POP3_SEARCHACK); + if (AckFlag==POP3_FERR) + throw POP3Error=(DWORD)EPOP3_BADUSER; + return Result; +} + +//Performs "QUIT" pop query and returns server response +//sets AckFlag +char* CPop3Client::Quit() +{ + char query[]="QUIT\r\n"; + + NetClient->Send(query); + return RecvRest(NetClient->Recv(),POP3_SEARCHACK); +} + +//Performs "STAT" pop query and returns server response +//sets AckFlag +char* CPop3Client::Stat() +{ + if (NetClient->Stopped) //check if we can work with this POP3 client session + throw POP3Error=(DWORD)EPOP3_STOPPED; + + char query[]="STAT\r\n"; + + NetClient->Send(query); + return RecvRest(NetClient->Recv(),POP3_SEARCHACK); +} + +//Performs "LIST" pop query and returns server response +//sets AckFlag +char* CPop3Client::List() +{ + if (NetClient->Stopped) //check if we can work with this POP3 client session + throw POP3Error=(DWORD)EPOP3_STOPPED; + + char query[]="LIST\r\n"; + + NetClient->Send(query); + return RecvRest(NetClient->Recv(),POP3_SEARCHDOT); +} + +//Performs "TOP" pop query and returns server response +//sets AckFlag +char* CPop3Client::Top(int nr, int lines) +{ + if (NetClient->Stopped) //check if we can work with this POP3 client session + throw POP3Error=(DWORD)EPOP3_STOPPED; + + char query[128]; + + sprintf(query,"TOP %d %d\r\n",nr,lines); + NetClient->Send(query); + return RecvRest(NetClient->Recv(),POP3_SEARCHDOT); +} + +//Performs "UIDL" pop query and returns server response +//sets AckFlag +char* CPop3Client::Uidl(int nr) +{ + if (NetClient->Stopped) //check if we can work with this POP3 client session + throw POP3Error=(DWORD)EPOP3_STOPPED; + + char query[128]; + + if (nr) + { + sprintf(query,"UIDL %d\r\n",nr); + NetClient->Send(query); + return RecvRest(NetClient->Recv(),POP3_SEARCHACK); + } + sprintf(query,"UIDL\r\n"); + NetClient->Send(query); + return RecvRest(NetClient->Recv(),POP3_SEARCHDOT); +} + +//Performs "DELE" pop query and returns server response +//sets AckFlag +char* CPop3Client::Dele(int nr) +{ + if (NetClient->Stopped) //check if we can work with this POP3 client session + throw POP3Error=(DWORD)EPOP3_STOPPED; + + char query[128]; + + sprintf(query,"DELE %d\r\n",nr); + NetClient->Send(query); + return RecvRest(NetClient->Recv(),POP3_SEARCHACK); +} +//Performs "RETR" pop query and returns server response +//sets AckFlag +char* CPop3Client::Retr(int nr) +{ + if (NetClient->Stopped) //check if we can work with this POP3 client session + throw POP3Error=(DWORD)EPOP3_STOPPED; + + char query[128]; + + sprintf(query,"RETR %d\r\n",nr); + NetClient->Send(query); + RecvRest(NetClient->Recv(),POP3_SEARCHACK); + return NetClient->Recv(); +} \ No newline at end of file diff --git a/protocols/YAMN/proto/pop3/pop3.h b/protocols/YAMN/proto/pop3/pop3.h new file mode 100644 index 0000000000..1f7f2ea737 --- /dev/null +++ b/protocols/YAMN/proto/pop3/pop3.h @@ -0,0 +1,66 @@ +#ifndef __POP3_H +#define __POP3_H + +#include "../../debug.h" +#include "../netlib.h" //NetLib client + +#define DOTLINE(s) ((((s)[-2]=='\r') || ((s)[-2]=='\n')) && ((s)[-1]=='.') && (((s)[0]=='\r') || ((s)[0]=='\n') || ((s)[0]=='\0'))) // be careful, it's different to ESR's pop3.c ;-) +#define ENDLINE(s) (((s)[0]=='\r') || ((s)[0]=='\n')) //endline +#define OKLINE(s) (((s)[0]=='+') && (((s)[1]=='o') || ((s)[1]=='O')) && (((s)[2]=='k') || ((s)[2]=='K'))) // +OK +#define ERRLINE(s) (((s)[0]=='-') && (((s)[1]=='e') || ((s)[1]=='E')) && (((s)[2]=='r') || ((s)[2]=='R')) && (((s)[3]=='r') || ((s)[3]=='R'))) // -ERR +#define ACKLINE(s) (OKLINE(s) || ERRLINE(s)) + +#define POP3_SEARCHDOT 1 +#define POP3_SEARCHACK 2 +#define POP3_SEARCHOK 3 +#define POP3_SEARCHERR 4 +#define POP3_SEARCHNL 5 + +#define POP3_FOK 1 +#define POP3_FERR 2 + +class CPop3Client +{ +public: + CPop3Client(): NetClient(NULL), Stopped(FALSE) {} + ~CPop3Client() {if (NetClient!=NULL) delete NetClient;} + + char* Connect(const char* servername,const int port=110,BOOL UseSSL=FALSE, BOOL NoTLS=FALSE); + char* RecvRest(char* prev,int mode,int size=65536); + char* User(char* name); + char* Pass(char* pw); + char* APOP(char* name, char* pw, char* timestamp); + char* Quit(); + char* Stat(); + char* List(); + char* Top(int nr, int lines=0); + char* Uidl(int nr=0); + char* Dele(int nr); + char* Retr(int nr); + + unsigned char AckFlag; + BOOL SSL; + BOOL Stopped; + + DWORD POP3Error; + class CNetClient *NetClient; //here the network layout is defined (TCP or SSL+TCP etc.) +private: + BOOL SearchFromEnd(char *end,int bs,int mode); + BOOL SearchFromStart(char *end,int bs,int mode); +}; + +enum +{ + EPOP3_QUEUEALLOC=1, //memory allocation + EPOP3_STOPPED, //stop account + EPOP3_CONNECT, //cannot connect to server + EPOP3_RESTALLOC, //cannot allocate memory for received data + EPOP3_BADUSER, //cannot login because USER command failed + EPOP3_BADPASS, //cannot login because PASS command failed + EPOP3_APOP, //server does not send timestamp for APOP auth + EPOP3_STAT, + EPOP3_LIST, + EPOP3_UIDL, +}; + +#endif diff --git a/protocols/YAMN/proto/pop3/pop3comm.cpp b/protocols/YAMN/proto/pop3/pop3comm.cpp new file mode 100644 index 0000000000..dcd38ee2c8 --- /dev/null +++ b/protocols/YAMN/proto/pop3/pop3comm.cpp @@ -0,0 +1,1563 @@ +/* + * This code implements POP3 server checking for new mail and so on. + * There's function SynchroPOP3 in this file- for checking and synchronising POP3 account + * and DeleteMailsPOP3- for deleting mails from POP3 server + * + * Note this file acts as main file for internal plugin. + * + * (c) majvan 2002-2004 + * 18/08 +*/ + + +#pragma warning( disable : 4290 ) +#include "../../yamn.h" +#include "../../main.h" +#include "pop3.h" +#include "pop3comm.h" //all we need for POP3 account (POP3 account= YAMN account + some more POP3 specified members) +#include //socket thorugh proxy functions + +#define ERRORSTR_MAXLEN 1024 //in wide-chars + +//-------------------------------------------------------------------------------------------------- + +HANDLE hNetLib = NULL; +PSCOUNTER CPOP3Account::AccountWriterSO = NULL; + +//Creates new CPOP3Account structure +HACCOUNT WINAPI CreatePOP3Account(HYAMNPROTOPLUGIN Plugin,DWORD CAccountVersion); + +//Deletes CPOP3Account structure +void WINAPI DeletePOP3Account(HACCOUNT Which); + +//Sets stop flag to account +void WINAPI StopPOP3Account(HACCOUNT Which); + +//Function registers standard functions for YAMN +int RegisterPOP3Plugin(WPARAM,LPARAM); + +//Unloads all variables created on heap (delete[]) +DWORD WINAPI UnLoadPOP3(void *); + +//Function writes POP3 accounts using YAMN exported functions +DWORD WINAPI WritePOP3Accounts(); + +//Function stores plugin's data for account to file +DWORD WINAPI WritePOP3Options(HANDLE,HACCOUNT); + +//Function reads plugin's data for account from file +DWORD WINAPI ReadPOP3Options(HACCOUNT,char **,char *); + +//Creates new mail for an account +HYAMNMAIL WINAPI CreatePOP3Mail(HACCOUNT Account,DWORD CMimeMailVersion); + +//Function does all needed work when connection failed or any error occured +//Creates structure containing error code, closes internet session, runs "bad connect" function +static void PostErrorProc(HPOP3ACCOUNT ActualAccount,void *ParamToBadConnect,DWORD POP3PluginParam,BOOL UseSSL); + +//Checks POP3 account and stores all info to account. It deletes old mails=> synchro +// WhichTemp- pointer to strucure containing needed information +DWORD WINAPI SynchroPOP3(struct CheckParam *WhichTemp); + +//Deletes mails from POP3 server +// WhichTemp- structure containing needed information (queued messages to delete) +//Function deletes from memory queue in WhichTemp structure +DWORD WINAPI DeleteMailsPOP3(struct DeleteParam *WhichTemp); + +//Function makes readable message about error. It sends it back to YAMN, so YAMN then +//can show it to the message window +TCHAR* WINAPI GetErrorString(DWORD Code); + +//Function deletes string allocated in GetErrorString +void WINAPI DeleteErrorString(LPVOID String); + +//Extracts info from result of POP3's STAT command +// stream- source string +// len- length of source string +// mboxsize- adreess to integer, that receives size of mailbox +// mails- adreess to integer, that receives number of mails +void ExtractStat(char *stream,int len,int *mboxsize,int *mails); + +//Extracts mail ID on mailbox +// stream- source string +// len- length of source string +// queue- address of first message, where first ID will be stored +void ExtractUIDL(char *stream,int len,HYAMNMAIL queue); + +//Extracts mail size on mailbox +// stream- source string +// len- length of source string +// queue- address of first message, where size of message #1 will be stored +void ExtractList(char *stream,int len,HYAMNMAIL queue); + +void ExtractMail(char *stream,int len,HYAMNMAIL queue); + +YAMNExportedFcns *pYAMNFcn = NULL; +MailExportedFcns *pYAMNMailFcn = NULL; + +YAMN_PROTOIMPORTFCN POP3ProtocolFunctions = +{ + CreatePOP3Account, + DeletePOP3Account, + StopPOP3Account, + WritePOP3Options, + ReadPOP3Options, + SynchroPOP3, + SynchroPOP3, + SynchroPOP3, + DeleteMailsPOP3, + GetErrorString, + NULL, + DeleteErrorString, + WritePOP3Accounts, + NULL, + UnLoadPOP3, +}; + +YAMN_MAILIMPORTFCN POP3MailFunctions = +{ + CreatePOP3Mail, + NULL, + NULL, + NULL, +}; + +PYAMN_VARIABLES pYAMNVar = NULL; +HYAMNPROTOPLUGIN POP3Plugin = NULL; + +YAMN_PROTOREGISTRATION POP3ProtocolRegistration = +{ + "POP3 protocol (internal)", + YAMN_VERSION_C, + " 2002-2004 majvan | 2005-2007 tweety, yb", + "Mail notifier and browser for Miranda IM. Included POP3 protocol.", + "francois.mean@skynet.be", + "http://forums.miranda-im.org/showthread.php?t=3035", +}; + +static TCHAR *FileName = NULL; + +HANDLE RegisterNLClient(const char *name); + +//-------------------------------------------------------------------------------------------------- +//-------------------------------------------------------------------------------------------------- + +CPOP3Account::CPOP3Account() +{ +//NOTE! This constructor constructs CAccount structure. If your plugin is not internal, +//you will need these constructors. All you need is in Account.cpp. Just copy to your source code +//constructor and destructor of CAccount. + UseInternetFree=CreateEvent(NULL,FALSE,TRUE,NULL); + InternetQueries=new SCOUNTER; + AbilityFlags=YAMN_ACC_BROWSE | YAMN_ACC_POPUP; + + SetAccountStatus((HACCOUNT)this,TranslateT("Disconnected")); +} + +CPOP3Account::~CPOP3Account() +{ + CloseHandle(UseInternetFree); + if (InternetQueries!=NULL) + delete InternetQueries; +} + +HACCOUNT WINAPI CreatePOP3Account(HYAMNPROTOPLUGIN Plugin,DWORD CAccountVersion) +{ +//First, we should check whether CAccountVersion matches. +//But this is internal plugin, so YAMN's CAccount structure and our CAccount structure are +//the same, so we do not need to test version. Otherwise, if CAccount version does not match +//in your plugin, you should return NULL, like this: +// if (CAccountVersion!=YAMN_ACCOUNTVERSION) return NULL; + +//Now it is needed to construct our POP3 account and return its handle + return (HACCOUNT)new struct CPOP3Account(); +} + +void WINAPI DeletePOP3Account(HACCOUNT Which) +{ + delete (HPOP3ACCOUNT)Which; +} + +void WINAPI StopPOP3Account(HACCOUNT Which) +{ + ((HPOP3ACCOUNT)Which)->Client.Stopped=TRUE; + if (((HPOP3ACCOUNT)Which)->Client.NetClient!=NULL) //we should inform also network client. Usefull only when network client implements this feature + ((HPOP3ACCOUNT)Which)->Client.NetClient->Stopped=TRUE; +} + +//This function is like main function for POP3 internal protocol +int RegisterPOP3Plugin(WPARAM,LPARAM) +{ + + //Get YAMN variables we can use + if (NULL==(pYAMNVar=(PYAMN_VARIABLES)CallService(MS_YAMN_GETVARIABLES,(WPARAM)YAMN_VARIABLESVERSION,(LPARAM)0))) + return 0; + + //We have to get pointers to YAMN exported functions: allocate structure and fill it + if (NULL==(pYAMNFcn=new struct YAMNExportedFcns)) + {UnLoadPOP3(0); return 0;} + + //Register new pop3 user in netlib + if (NULL==(hNetLib=RegisterNLClient("YAMN-POP3"))) + {UnLoadPOP3(0); return 0;} + + pYAMNFcn->SetProtocolPluginFcnImportFcn=(YAMN_SETPROTOCOLPLUGINFCNIMPORTFCN)CallService(MS_YAMN_GETFCNPTR,(WPARAM)YAMN_SETPROTOCOLPLUGINFCNIMPORTID,(LPARAM)0); + pYAMNFcn->WaitToWriteFcn=(YAMN_WAITTOWRITEFCN)CallService(MS_YAMN_GETFCNPTR,(WPARAM)YAMN_WAITTOWRITEID,(LPARAM)0); + pYAMNFcn->WriteDoneFcn=(YAMN_WRITEDONEFCN)CallService(MS_YAMN_GETFCNPTR,(WPARAM)YAMN_WRITEDONEID,(LPARAM)0); + pYAMNFcn->WaitToReadFcn=(YAMN_WAITTOREADFCN)CallService(MS_YAMN_GETFCNPTR,(WPARAM)YAMN_WAITTOREADID,(LPARAM)0); + pYAMNFcn->ReadDoneFcn=(YAMN_READDONEFCN)CallService(MS_YAMN_GETFCNPTR,(WPARAM)YAMN_READDONEID,(LPARAM)0); + pYAMNFcn->SCGetNumberFcn=(YAMN_SCMANAGEFCN)CallService(MS_YAMN_GETFCNPTR,(WPARAM)YAMN_SCGETNUMBERID,(LPARAM)0); + pYAMNFcn->SCIncFcn=(YAMN_SCMANAGEFCN)CallService(MS_YAMN_GETFCNPTR,(WPARAM)YAMN_SCINCID,(LPARAM)0); + pYAMNFcn->SCDecFcn=(YAMN_SCMANAGEFCN)CallService(MS_YAMN_GETFCNPTR,(WPARAM)YAMN_SCDECID,(LPARAM)0); + pYAMNFcn->SetStatusFcn=(YAMN_SETSTATUSFCN)CallService(MS_YAMN_GETFCNPTR,(WPARAM)YAMN_SETSTATUSID,(LPARAM)0); + pYAMNFcn->GetStatusFcn=(YAMN_GETSTATUSFCN)CallService(MS_YAMN_GETFCNPTR,(WPARAM)YAMN_GETSTATUSID,(LPARAM)0); + + if (NULL==(pYAMNMailFcn=new struct MailExportedFcns)) + {UnLoadPOP3(0); return 0;} + + pYAMNMailFcn->SynchroMessagesFcn=(YAMN_SYNCHROMIMEMSGSFCN)CallService(MS_YAMN_GETFCNPTR,(WPARAM)YAMN_SYNCHROMIMEMSGSID,(LPARAM)0); + pYAMNMailFcn->TranslateHeaderFcn=(YAMN_TRANSLATEHEADERFCN)CallService(MS_YAMN_GETFCNPTR,(WPARAM)YAMN_TRANSLATEHEADERID,(LPARAM)0); + pYAMNMailFcn->AppendQueueFcn=(YAMN_APPENDQUEUEFCN)CallService(MS_YAMN_GETFCNPTR,(WPARAM)YAMN_APPENDQUEUEID,(LPARAM)0); + pYAMNMailFcn->DeleteMessagesToEndFcn=(YAMN_DELETEMIMEQUEUEFCN)CallService(MS_YAMN_GETFCNPTR,(WPARAM)YAMN_DELETEMIMEQUEUEID,(LPARAM)0); + pYAMNMailFcn->DeleteMessageFromQueueFcn=(YAMN_DELETEMIMEMESSAGEFCN)CallService(MS_YAMN_GETFCNPTR,(WPARAM)YAMN_DELETEMIMEMESSAGEID,(LPARAM)0); + pYAMNMailFcn->FindMessageByIDFcn=(YAMN_FINDMIMEMESSAGEFCN)CallService(MS_YAMN_GETFCNPTR,(WPARAM)YAMN_FINDMIMEMESSAGEID,(LPARAM)0); + pYAMNMailFcn->CreateNewDeleteQueueFcn=(YAMN_CREATENEWDELETEQUEUEFCN)CallService(MS_YAMN_GETFCNPTR,(WPARAM)YAMN_CREATENEWDELETEQUEUEID,(LPARAM)0); + + //set static variable + if (CPOP3Account::AccountWriterSO==NULL) { + if (NULL==(CPOP3Account::AccountWriterSO=new SCOUNTER)) + {UnLoadPOP3(0); return 0;} + } + + //First, we register this plugin + //it is quite impossible this function returns zero (failure) as YAMN and internal plugin structre versions are the same + POP3ProtocolRegistration.Name = Translate("POP3 protocol (internal)"); + POP3ProtocolRegistration.Description = Translate("Mail notifier and browser for Miranda IM. Included POP3 protocol."); + if (NULL==(POP3Plugin=(HYAMNPROTOPLUGIN)CallService(MS_YAMN_REGISTERPROTOPLUGIN,(WPARAM)&POP3ProtocolRegistration,(LPARAM)YAMN_PROTOREGISTRATIONVERSION))) + return 0; + + //Next we set our imported functions for YAMN + if (!SetProtocolPluginFcnImport(POP3Plugin,&POP3ProtocolFunctions,YAMN_PROTOIMPORTFCNVERSION,&POP3MailFunctions,YAMN_MAILIMPORTFCNVERSION)) + return 0; + + //Then, we read all mails for accounts. + //You must first register account, before using this function as YAMN must use CreatePOP3Account function to add new accounts + //But if CreatePOP3Account is not implemented (equals to NULL), YAMN creates account as YAMN's standard HACCOUNT + if (FileName) CallService(MS_YAMN_DELETEFILENAME,(WPARAM)FileName, 0); //shoud not happen (only for secure) + FileName = (TCHAR *)CallService(MS_YAMN_GETFILENAME,(WPARAM)_T("pop3"), 0); + + switch(CallService(MS_YAMN_READACCOUNTS,(WPARAM)POP3Plugin,(LPARAM)FileName)) { + case EACC_FILEVERSION: + MessageBox(NULL,TranslateT("Found new version of account book, not compatible with this version of YAMN."),TranslateT("YAMN (internal POP3) read error"),MB_OK); + CallService(MS_YAMN_DELETEFILENAME,(WPARAM)FileName,(LPARAM)0); + FileName = NULL; + return 0; + case EACC_FILECOMPATIBILITY: + MessageBox(NULL,TranslateT("Error reading account file. Account file corrupted."),TranslateT("YAMN (internal POP3) read error"),MB_OK); + CallService(MS_YAMN_DELETEFILENAME,(WPARAM)FileName,(LPARAM)0); + FileName = NULL; + return 0; + case EACC_ALLOC: + MessageBox(NULL,TranslateT("Memory allocation error while data reading"),TranslateT("YAMN (internal POP3) read error"),MB_OK); + CallService(MS_YAMN_DELETEFILENAME,(WPARAM)FileName,(LPARAM)0); + FileName = NULL; + return 0; + case EACC_SYSTEM: + if (ERROR_FILE_NOT_FOUND!=GetLastError()) + { + TCHAR temp[1024] = {0}; + mir_sntprintf(temp, SIZEOF(temp), _T("%s\n%s"),TranslateT("Reading file error. File already in use?"),FileName); + MessageBox(NULL,temp,TranslateT("YAMN (internal POP3) read error"),MB_OK); + CallService(MS_YAMN_DELETEFILENAME,(WPARAM)FileName,(LPARAM)0); + FileName = NULL; + return 0; + } + break; + } + //HookEvent(ME_OPT_INITIALISE,POP3OptInit); + + HACCOUNT Finder; + HANDLE hContact; + DBVARIANT dbv; + char *szProto; + + for (Finder=POP3Plugin->FirstAccount;Finder!=NULL;Finder=Finder->Next) + { + Finder->hContact = NULL; + hContact = (HANDLE)CallService(MS_DB_CONTACT_FINDFIRST, 0, 0); + while(hContact) + { + szProto = (char *)CallService(MS_PROTO_GETCONTACTBASEPROTO, (WPARAM)hContact, 0); + if (szProto != NULL && strcmp(szProto, YAMN_DBMODULE)==0) + { + if (!DBGetContactSettingString(hContact,YAMN_DBMODULE,"Id",&dbv)) { + if ( strcmp( dbv.pszVal, Finder->Name) == 0) { + Finder->hContact = hContact; + DBWriteContactSettingWord(Finder->hContact, YAMN_DBMODULE, "Status", ID_STATUS_ONLINE); + DBWriteContactSettingString(Finder->hContact, "CList", "StatusMsg", Translate("No new mail message")); + if ((Finder->Flags & YAMN_ACC_ENA) && (Finder->NewMailN.Flags & YAMN_ACC_CONT)) + DBDeleteContactSetting(Finder->hContact, "CList", "Hidden"); + + if (!(Finder->Flags & YAMN_ACC_ENA) || !(Finder->NewMailN.Flags & YAMN_ACC_CONT)) + DBWriteContactSettingByte(Finder->hContact, "CList", "Hidden", 1); + } + DBFreeVariant(&dbv); + } + } + hContact = (HANDLE)CallService(MS_DB_CONTACT_FINDNEXT, (WPARAM)hContact, 0); + } + + if (Finder->hContact == NULL && (Finder->Flags & YAMN_ACC_ENA) && (Finder->NewMailN.Flags & YAMN_ACC_CONT)) { + //No account contact found, have to create one + Finder->hContact =(HANDLE) CallService(MS_DB_CONTACT_ADD, 0, 0); + CallService(MS_PROTO_ADDTOCONTACT,(WPARAM)Finder->hContact,(LPARAM)YAMN_DBMODULE); + DBWriteContactSettingString(Finder->hContact,YAMN_DBMODULE,"Id",Finder->Name); + DBWriteContactSettingString(Finder->hContact,YAMN_DBMODULE,"Nick",Finder->Name); + DBWriteContactSettingString(Finder->hContact,"Protocol","p",YAMN_DBMODULE); + DBWriteContactSettingWord(Finder->hContact, YAMN_DBMODULE, "Status", YAMN_STATUS); + } + } + + return 0; +} + +DWORD WINAPI UnLoadPOP3(void *) +{ + //pYAMNVar is only a pointr, no need delete or free + if (hNetLib) { + Netlib_CloseHandle(hNetLib); hNetLib = NULL;} + if (CPOP3Account::AccountWriterSO) { + delete CPOP3Account::AccountWriterSO; CPOP3Account::AccountWriterSO = NULL;} + if (pYAMNMailFcn) { + delete pYAMNMailFcn; pYAMNMailFcn = NULL;} + if (pYAMNFcn) { + delete pYAMNFcn; pYAMNFcn = NULL;} + if (FileName) { + CallService(MS_YAMN_DELETEFILENAME,(WPARAM)FileName,(LPARAM)0); FileName = NULL;} + + #ifdef DEBUG_SYNCHRO + DebugLog(SynchroFile,"UnLoadPOP3:done\n"); + #endif + return 1; +} + +DWORD WINAPI WritePOP3Accounts() +{ + DWORD ReturnValue = CallService(MS_YAMN_WRITEACCOUNTS,(WPARAM)POP3Plugin,(LPARAM)FileName); + if (ReturnValue == EACC_SYSTEM) { + TCHAR temp[1024] = {0}; + mir_sntprintf(temp, SIZEOF(temp), _T("%s\n%s"), TranslateT("Error while copying data to disk occured. File in use?"), FileName ); + MessageBox(NULL, temp, TranslateT("POP3 plugin- write file error"), MB_OK ); + } + + return ReturnValue; +} + +DWORD WINAPI WritePOP3Options(HANDLE File,HACCOUNT Which) +{ + DWORD WrittenBytes; + DWORD Ver=POP3_FILEVERSION; + + if ((!WriteFile(File,(char *)&Ver,sizeof(DWORD),&WrittenBytes,NULL)) || + (!WriteFile(File,(char *)&((HPOP3ACCOUNT)Which)->CP,sizeof(WORD),&WrittenBytes,NULL))) + return EACC_SYSTEM; + return 0; +} + +DWORD WINAPI ReadPOP3Options(HACCOUNT Which,char **Parser,char *End) +{ + DWORD Ver; +#ifdef DEBUG_FILEREAD + TCHAR Debug[256]; +#endif + Ver=*(DWORD *)(*Parser); + (*Parser)+=sizeof(DWORD); + if (*Parser>=End) + return EACC_FILECOMPATIBILITY; + if (Ver!=POP3_FILEVERSION) + return EACC_FILECOMPATIBILITY; + + ((HPOP3ACCOUNT)Which)->CP=*(WORD *)(*Parser); + (*Parser)+=sizeof(WORD); + if (*Parser>=End) + return EACC_FILECOMPATIBILITY; +#ifdef DEBUG_FILEREAD + _stprintf(Debug,_T("CodePage: %d, remaining %d chars"),((HPOP3ACCOUNT)Which)->CP,End-*Parser); + MessageBox(NULL,Debug,_T("debug"),MB_OK); +#endif + return 0; +} + +HYAMNMAIL WINAPI CreatePOP3Mail(HACCOUNT Account,DWORD MailDataVersion) +{ + HYAMNMAIL NewMail; +//First, we should check whether MAILDATA matches. +//But this is internal plugin, so YAMN's MAILDATA structure and our MAILDATA structure are +//the same, so we do not need to test version. Otherwise, if MAILDATA version does not match +//in your plugin, you should return NULL, like this: +// if (MailDataVersion!=YAMN_MAILDATAVERSION) return NULL; + +//Now it is needed to construct our POP3 account and return its handle + if (NULL==(NewMail=new YAMNMAIL)) + return NULL; + + if (NULL==(NewMail->MailData=new MAILDATA)) + { + delete NewMail; + return NULL; + } + NewMail->MailData->CP=((HPOP3ACCOUNT)Account)->CP; + return (HYAMNMAIL)NewMail; +} + +static void SetContactStatus(HACCOUNT account, int status){ + if ((account->hContact) && (account->NewMailN.Flags & YAMN_ACC_CONT)) { + DBWriteContactSettingWord(account->hContact, YAMN_DBMODULE, "Status", status); + } +} + +static void PostErrorProc(HPOP3ACCOUNT ActualAccount,void *ParamToBadConnection,DWORD POP3PluginParam,BOOL UseSSL) +{ + char *DataRX; + +//We create new structure, that we pass to bad connection dialog procedure. This procedure next calls YAMN imported fuction +//from POP3 protocol to determine the description of error. We can describe error from our error code structure, because later, +//when YAMN calls our function, it passes us our error code. This is pointer to structure for POP3 protocol in fact. + PPOP3_ERRORCODE ErrorCode; + +//We store status before we do Quit(), because quit can destroy our errorcode status + if (NULL!=(ErrorCode=new POP3_ERRORCODE)) + { + ErrorCode->SSL=UseSSL; + ErrorCode->AppError=ActualAccount->SystemError; + ErrorCode->POP3Error=ActualAccount->Client.POP3Error; + ErrorCode->NetError=ActualAccount->Client.NetClient->NetworkError; + ErrorCode->SystemError=ActualAccount->Client.NetClient->SystemError; + } + + if (POP3PluginParam==(DWORD)NULL) //if it was normal YAMN call (force check or so on) + { + try + { + DataRX=ActualAccount->Client.Quit(); + if (DataRX!=NULL) + free(DataRX); + } + catch(...) + { + } +//We always close connection if error occured + try + { + ActualAccount->Client.NetClient->Disconnect(); + } + catch(...) + { + } + + SetAccountStatus(ActualAccount,TranslateT("Disconnected")); + +//If we cannot allocate memory, do nothing + if (ErrorCode==NULL) + { + SetEvent(ActualAccount->UseInternetFree); + return; + } + } + else //else it was called from POP3 plugin, probably error when deleting old mail (POP3 synchro calls POP3 delete) + if (ErrorCode==NULL) + return; + + if ((ActualAccount->BadConnectN.Flags & YAMN_ACC_MSG) || (ActualAccount->BadConnectN.Flags & YAMN_ACC_ICO) || (ActualAccount->BadConnectN.Flags & YAMN_ACC_POP)) + { + YAMN_BADCONNECTIONPARAM cp={(HANDLE)0,ActualAccount,(UINT_PTR)ErrorCode,ParamToBadConnection}; + + CallService(MS_YAMN_BADCONNECTION,(WPARAM)&cp,(LPARAM)YAMN_BADCONNECTIONVERSION); + } + if (POP3PluginParam==(DWORD)NULL) //if it was normal YAMN call + SetEvent(ActualAccount->UseInternetFree); +} + +//Checks POP3 account and synchronizes it +DWORD WINAPI SynchroPOP3(struct CheckParam * WhichTemp) +{ + HPOP3ACCOUNT ActualAccount; + CPop3Client *MyClient; + HYAMNMAIL NewMails=NULL,MsgQueuePtr=NULL; + char* DataRX=NULL,*Temp; + int mboxsize,msgs,i; + SYSTEMTIME now; + LPVOID YAMNParam; + DWORD CheckFlags; + BOOL UsingInternet=FALSE; + struct { + char *ServerName; + DWORD ServerPort; + char *ServerLogin; + char *ServerPasswd; + DWORD Flags; + DWORD NFlags; + DWORD NNFlags; + } ActualCopied; + + //First, we should compare our version of CheckParam structure, but here it is not needed, because YAMN and internal plugin + //have the same version. But your plugin should do that in this way: + // if (((struct CheckParam *)WhichTemp)->Ver!=YAMN_CHECKVERSION) + // { + // SetEvent(((struct CheckParam *)WhichTemp)->ThreadRunningEV); //don't forget to unblock YAMN + // return (DWORD)-1; //ok, but we should return value. + // //When our plugin returns e.g. 0xFFFFFFFF (=-1, this is only our plugin value, YAMN does nothing with return value, + // //but only tests if it is nonzero. If yes, it calls GetErrorStringFcn. We know problem occured in YAMN incompatibility + // //and then we can in our GetErrorStringFcn e.g. return string "Uncompatible version of YAMN". + // } + + ActualAccount=(HPOP3ACCOUNT)WhichTemp->AccountParam; //copy address of structure from calling thread to stack of this thread + YAMNParam=WhichTemp->BrowserParam; + CheckFlags=WhichTemp->Flags; + #ifdef DEBUG_SYNCHRO + DebugLog(SynchroFile,"CheckPOP3:Incrementing \"using threads\" %x (account %x)\n",ActualAccount->UsingThreads,ActualAccount); + #endif + SCInc(ActualAccount->UsingThreads); + //Unblock YAMN, signal that we have copied all parameters from YAMN thread stack + if (INVALID_HANDLE_VALUE!=WhichTemp->ThreadRunningEV) + SetEvent(WhichTemp->ThreadRunningEV); + + #ifdef DEBUG_SYNCHRO + DebugLog(SynchroFile,"CheckPOP3:ActualAccountSO-read wait\n"); + #endif + if (WAIT_OBJECT_0!=WaitToRead(ActualAccount)) + { + #ifdef DEBUG_SYNCHRO + DebugLog(SynchroFile,"CheckPOP3:ActualAccountSO-read wait failed\n"); + #endif + #ifdef DEBUG_SYNCHRO + DebugLog(SynchroFile,"CheckPOP3:Decrementing \"using threads\" %x (account %x)\n",ActualAccount->UsingThreads,ActualAccount); + #endif + SCDec(ActualAccount->UsingThreads); + return 0; + } + #ifdef DEBUG_SYNCHRO + DebugLog(SynchroFile,"CheckPOP3:ActualAccountSO-read enter\n"); + #endif + MyClient=&ActualAccount->Client; + //Now, copy all needed information about account to local variables, so ActualAccount is not blocked in read mode during all connection process, which can last for several minutes. + ActualCopied.ServerName = _strdup(ActualAccount->Server->Name); + ActualCopied.ServerPort=ActualAccount->Server->Port; + ActualCopied.Flags=ActualAccount->Flags; + ActualCopied.ServerLogin=_strdup(ActualAccount->Server->Login); + ActualCopied.ServerPasswd=_strdup(ActualAccount->Server->Passwd); + ActualCopied.NFlags=ActualAccount->NewMailN.Flags; + ActualCopied.NNFlags=ActualAccount->NoNewMailN.Flags; + + #ifdef DEBUG_SYNCHRO + DebugLog(SynchroFile,"CheckPOP3:ActualAccountSO-read done\n"); + #endif + ReadDone(ActualAccount); + + SCInc(ActualAccount->InternetQueries); //increment counter, that there is one more thread waiting for connection + #ifdef DEBUG_SYNCHRO + DebugLog(SynchroFile,"CheckPOP3:InternetFreeEV-wait\n"); + #endif + WaitForSingleObject(ActualAccount->UseInternetFree,INFINITE); //wait until we can use connection + #ifdef DEBUG_SYNCHRO + DebugLog(SynchroFile,"CheckPOP3:InternetFreeEV-enter\n"); + #endif + SCDec(ActualAccount->InternetQueries); + + //OK, we enter the "use internet" section. But after we start communication, we can test if we did not enter the "use internet" section only for the reason, + //that previous thread release the internet section because this account has stop signal (we stop account and there are 2 threads: one communicating, + //the second one waiting for network access- the first one ends because we want to stop account, this one is released, but should be stopped as well). + if (!ActualAccount->AbleToWork) + { + #ifdef DEBUG_SYNCHRO + DebugLog(SynchroFile,"CheckPOP3:stop signal-InternetFreeEV-done\n"); + #endif + SetEvent(ActualAccount->UseInternetFree); + #ifdef DEBUG_SYNCHRO + DebugLog(SynchroFile,"CheckPOP3:stop signal-Decrementing \"using threads\" %x (account %x)\n",ActualAccount->UsingThreads,ActualAccount); + #endif + SCDec(ActualAccount->UsingThreads); + return 0; + } + UsingInternet=TRUE; + + GetLocalTime(&now); + ActualAccount->SystemError=0; //now we can use internet for this socket. First, clear errorcode. + try + { + SetContactStatus(ActualAccount,ID_STATUS_OCCUPIED); + #ifdef DEBUG_COMM + DebugLog(CommFile,"<--------Communication-------->\n"); + #endif + // if we are already connected, we have open session (another thread left us open session), so we don't need to login + // note that connected state without logging cannot occur, because if we close session, we always close socket too (we must close socket is the right word :) ) + if ((MyClient->NetClient==NULL) || !MyClient->NetClient->Connected()) + { + SetAccountStatus(ActualAccount,TranslateT("Connecting to server")); + + DataRX=MyClient->Connect(ActualCopied.ServerName,ActualCopied.ServerPort,ActualCopied.Flags & YAMN_ACC_SSL23,ActualCopied.Flags & YAMN_ACC_NOTLS); + char *timestamp=NULL; + + if (DataRX!=NULL) + { + if (ActualCopied.Flags & YAMN_ACC_APOP) + { + char *lpos=strchr(DataRX,'<'); + char *rpos=strchr(DataRX,'>'); + if (lpos && rpos && rpos>lpos) { + int sz=(int)(rpos-lpos+2); + timestamp=new char[sz]; + memcpy(timestamp, lpos, sz-1); + timestamp[sz-1]='\0'; + } + } + free(DataRX); + DataRX=NULL; + } + + SetAccountStatus(ActualAccount,TranslateT("Entering POP3 account")); + + if (ActualCopied.Flags & YAMN_ACC_APOP) + { + DataRX=MyClient->APOP(ActualCopied.ServerLogin,ActualCopied.ServerPasswd,timestamp); + if (DataRX!=NULL) + free(DataRX); + DataRX=NULL; + delete[] timestamp; + } else { + DataRX=MyClient->User(ActualCopied.ServerLogin); + if (DataRX!=NULL) + free(DataRX); + DataRX=NULL; + DataRX=MyClient->Pass(ActualCopied.ServerPasswd); + if (DataRX!=NULL) + free(DataRX); + DataRX=NULL; + } + } + SetAccountStatus(ActualAccount,TranslateT("Searching for new mail message")); + + DataRX=MyClient->Stat(); + + #ifdef DEBUG_DECODE + DebugLog(DecodeFile,"<--------Account checking-------->\n"); + DebugLog(DecodeFile,"\n"); + #endif + ExtractStat(DataRX,MyClient->NetClient->Rcv,&mboxsize,&msgs); + #ifdef DEBUG_DECODE + DebugLog(DecodeFile,"%d\n",mboxsize); + DebugLog(DecodeFile,"%d\n",msgs); + DebugLog(DecodeFile,"\n"); + #endif + if (DataRX!=NULL) + free(DataRX); + DataRX=NULL; + for (i=0;iNext=(HYAMNMAIL)CallService(MS_YAMN_CREATEACCOUNTMAIL,(WPARAM)ActualAccount,(LPARAM)YAMN_MAILVERSION); + MsgQueuePtr=MsgQueuePtr->Next; + } + if (MsgQueuePtr==NULL) + { + ActualAccount->SystemError=EPOP3_QUEUEALLOC; + throw (DWORD)ActualAccount->SystemError; + } + } + + if (msgs) + { + DataRX=MyClient->List(); + #ifdef DEBUG_DECODE + DebugLog(DecodeFile,"\n"); + #endif + ExtractList(DataRX,MyClient->NetClient->Rcv,NewMails); + #ifdef DEBUG_DECODE + DebugLog(DecodeFile,"\n"); + #endif + if (DataRX!=NULL) + free(DataRX); + DataRX=NULL; + + #ifdef DEBUG_DECODE + DebugLog(DecodeFile,"\n"); + #endif + DataRX=MyClient->Uidl(); + ExtractUIDL(DataRX,MyClient->NetClient->Rcv,NewMails); + #ifdef DEBUG_DECODE + DebugLog(DecodeFile,"\n"); + #endif + if (DataRX!=NULL) + free(DataRX); + DataRX=NULL; + } + #ifdef DEBUG_SYNCHRO + DebugLog(SynchroFile,"CheckPOP3:ActualAccountMsgsSO-write wait\n"); + #endif + if (WAIT_OBJECT_0!=MsgsWaitToWrite(ActualAccount)) + { + #ifdef DEBUG_SYNCHRO + DebugLog(SynchroFile,"CheckPOP3:ActualAccountMsgsSO-write wait failed\n"); + #endif + throw (DWORD)(ActualAccount->SystemError=EACC_STOPPED); + } + #ifdef DEBUG_SYNCHRO + DebugLog(SynchroFile,"CheckPOP3:ActualAccountMsgsSO-write enter\n"); + #endif + ActualAccount->LastChecked=now; + for (MsgQueuePtr=(HYAMNMAIL)ActualAccount->Mails;MsgQueuePtr!=NULL;MsgQueuePtr=MsgQueuePtr->Next){ + if (MsgQueuePtr->Flags&YAMN_MSG_BODYREQUESTED){ + HYAMNMAIL NewMsgsPtr=NULL; + for (NewMsgsPtr=(HYAMNMAIL)NewMails;NewMsgsPtr!=NULL;NewMsgsPtr=NewMsgsPtr->Next){ + if (!strcmp(MsgQueuePtr->ID,NewMsgsPtr->ID)) { + TCHAR accstatus[512]; + wsprintf(accstatus,TranslateT("Reading body %s"),NewMsgsPtr->ID); + SetAccountStatus(ActualAccount,accstatus); + DataRX=MyClient->Top(MsgQueuePtr->Number,100); + #ifdef DEBUG_DECODE + DebugLog(DecodeFile,"\n"); + DebugLog(DecodeFile,"
%s
\n",DataRX); + #endif + if (DataRX!=NULL) + { + Temp=DataRX; + while((TempNetClient->Rcv) && (WS(Temp) || ENDLINE(Temp))) Temp++; + + if (OKLINE(DataRX)) + for (Temp=DataRX;(TempNetClient->Rcv) && (!ENDLINE(Temp));Temp++); + while((TempNetClient->Rcv) && ENDLINE(Temp)) Temp++; + } + else + continue; + //delete all the headers of the old mail MsgQueuePtr->MailData->TranslatedHeader + struct CMimeItem *TH = MsgQueuePtr->MailData->TranslatedHeader; + if (TH) for (;MsgQueuePtr->MailData->TranslatedHeader!=NULL;) + { + TH=TH->Next; + if (MsgQueuePtr->MailData->TranslatedHeader->name!=NULL) + delete[] MsgQueuePtr->MailData->TranslatedHeader->name; + if (MsgQueuePtr->MailData->TranslatedHeader->value!=NULL) + delete[] MsgQueuePtr->MailData->TranslatedHeader->value; + delete MsgQueuePtr->MailData->TranslatedHeader; + MsgQueuePtr->MailData->TranslatedHeader=TH; + } + + TranslateHeader(Temp,MyClient->NetClient->Rcv-(Temp-DataRX),&MsgQueuePtr->MailData->TranslatedHeader); + + + #ifdef DEBUG_DECODE + DebugLog(DecodeFile,"
\n"); + #endif + MsgQueuePtr->Flags|=YAMN_MSG_BODYRECEIVED; + + if (DataRX!=NULL) + free(DataRX); + DataRX=NULL; + break; + } + } + } + } + + SynchroMessages(ActualAccount,(HYAMNMAIL *)&ActualAccount->Mails,NULL,(HYAMNMAIL *)&NewMails,NULL); //we get only new mails on server! +// NewMails=NULL; + + #ifdef DEBUG_SYNCHRO + DebugLog(SynchroFile,"CheckPOP3:ActualAccountMsgsSO-write done\n"); + #endif + MsgsWriteDone(ActualAccount); + for (MsgQueuePtr=(HYAMNMAIL)ActualAccount->Mails;MsgQueuePtr!=NULL;MsgQueuePtr=MsgQueuePtr->Next){ + if ((MsgQueuePtr->Flags&YAMN_MSG_BODYREQUESTED) && (MsgQueuePtr->Flags&YAMN_MSG_BODYRECEIVED)) { + MsgQueuePtr->Flags&=~YAMN_MSG_BODYREQUESTED; + if (MsgQueuePtr->MsgWindow){ + SendMessage(MsgQueuePtr->MsgWindow,WM_YAMN_CHANGECONTENT,0,0); + } + } + } + + for (msgs=0,MsgQueuePtr=NewMails;MsgQueuePtr!=NULL;MsgQueuePtr=MsgQueuePtr->Next,msgs++); //get number of new mails + + try + { + TCHAR accstatus[512]; + + for (i=0,MsgQueuePtr=NewMails;MsgQueuePtr!=NULL;i++) + { + BOOL autoretr = (ActualAccount->Flags & YAMN_ACC_BODY)!=0; + DataRX=MyClient->Top(MsgQueuePtr->Number,autoretr?100:0); + wsprintf(accstatus,TranslateT("Reading new mail messages (%d%% done)"),100*i/msgs); + SetAccountStatus(ActualAccount,accstatus); + + #ifdef DEBUG_DECODE + DebugLog(DecodeFile,"\n"); + DebugLog(DecodeFile,"
%s
\n",DataRX); + #endif + if (DataRX!=NULL) + { + Temp=DataRX; + while((TempNetClient->Rcv) && (WS(Temp) || ENDLINE(Temp))) Temp++; + + if (OKLINE(DataRX)) + for (Temp=DataRX;(TempNetClient->Rcv) && (!ENDLINE(Temp));Temp++); + while((TempNetClient->Rcv) && ENDLINE(Temp)) Temp++; + } + else + continue; + + TranslateHeader(Temp,MyClient->NetClient->Rcv-(Temp-DataRX),&MsgQueuePtr->MailData->TranslatedHeader); + + + #ifdef DEBUG_DECODE + DebugLog(DecodeFile,"
\n"); + #endif + MsgQueuePtr->Flags|=YAMN_MSG_NORMALNEW; + if (autoretr) MsgQueuePtr->Flags|=YAMN_MSG_BODYRECEIVED; + + //We are going to filter mail. Warning!- we must not be in read access neither write access to mails when calling this service + //This is done, because the "NewMails" queue is not synchronised. It is because it is new queue. Only this thread uses new queue yet, it is not + //connected to account mail queue. + // CallService(MS_YAMN_FILTERMAIL,(WPARAM)ActualAccount,(LPARAM)MsgQueuePtr); + FilterMailSvc((WPARAM)ActualAccount,(LPARAM)MsgQueuePtr); + + if (DataRX!=NULL) + free(DataRX); + DataRX=NULL; + + //MsgQueuePtr->MailData->Body=MyClient->Retr(MsgQueuePtr->Number); + + MsgQueuePtr=MsgQueuePtr->Next; + + } + #ifdef DEBUG_DECODE + DebugLog(DecodeFile,"\n"); + #endif + + #ifdef DEBUG_SYNCHRO + DebugLog(SynchroFile,"CheckPOP3:ActualAccountMsgsSO-write wait\n"); + #endif + if (WAIT_OBJECT_0!=MsgsWaitToWrite(ActualAccount)) + { + #ifdef DEBUG_SYNCHRO + DebugLog(SynchroFile,"CheckPOP3:ActualAccountMsgsSO-write wait failed\n"); + #endif + throw (DWORD)ActualAccount->SystemError==EACC_STOPPED; + } + #ifdef DEBUG_SYNCHRO + DebugLog(SynchroFile,"CheckPOP3:ActualAccountMsgsSO-write enter\n"); + #endif + if (ActualAccount->Mails==NULL) + ActualAccount->Mails=NewMails; + else + { + ActualAccount->LastMail=ActualAccount->LastChecked; + AppendQueue((HYAMNMAIL)ActualAccount->Mails,NewMails); + } + #ifdef DEBUG_SYNCHRO + DebugLog(SynchroFile,"CheckPOP3:ActualAccountMsgsSO-write done\n"); + #endif + MsgsWriteDone(ActualAccount); + + // we are going to delete mails having SPAM flag level3 and 4 (see m_mails.h) set + { + struct DeleteParam ParamToDeleteMails={YAMN_DELETEVERSION,INVALID_HANDLE_VALUE,ActualAccount,YAMNParam,(void *)POP3_DELETEFROMCHECK}; + + // Delete mails from server. Here we should not be in write access for account's mails + DeleteMailsPOP3(&ParamToDeleteMails); + } + + // if there is no waiting thread for internet connection close it + // else leave connection open + if (0==SCGetNumber(ActualAccount->InternetQueries)) + { + DataRX=MyClient->Quit(); + if (DataRX!=NULL) + free(DataRX); + DataRX=NULL; + MyClient->NetClient->Disconnect(); + + SetAccountStatus(ActualAccount,TranslateT("Disconnected")); + } + + UsingInternet=FALSE; + #ifdef DEBUG_SYNCHRO + DebugLog(SynchroFile,"CheckPOP3:InternetFreeEV-done\n"); + #endif + SetEvent(ActualAccount->UseInternetFree); + + ActualAccount->LastSChecked=ActualAccount->LastChecked; + ActualAccount->LastSynchronised=ActualAccount->LastChecked; + } + catch(...) + { + throw; //go to the main exception handling + } + + { + YAMN_MAILBROWSERPARAM Param={(HANDLE)0,ActualAccount,ActualCopied.NFlags,ActualCopied.NNFlags,YAMNParam}; + + if (CheckFlags & YAMN_FORCECHECK) + Param.nnflags|=YAMN_ACC_POP; //if force check, show popup anyway and if mailbrowser was opened, do not close + Param.nnflags|= YAMN_ACC_MSGP; //do not close browser if already open + CallService(MS_YAMN_MAILBROWSER,(WPARAM)&Param,(LPARAM)YAMN_MAILBROWSERVERSION); + } + SetContactStatus(ActualAccount,ActualAccount->isCounting?ID_STATUS_ONLINE:ID_STATUS_OFFLINE); + } + #ifdef DEBUG_COMM + catch(DWORD ErrorCode) + #else + catch(DWORD) + #endif + { + if (ActualAccount->Client.POP3Error==EPOP3_STOPPED) + ActualAccount->SystemError=EACC_STOPPED; + #ifdef DEBUG_COMM + DebugLog(CommFile,"ERROR: %x\n",ErrorCode); + #endif + #ifdef DEBUG_SYNCHRO + DebugLog(SynchroFile,"CheckPOP3:ActualAccountMsgsSO-write wait\n"); + #endif + if (WAIT_OBJECT_0==MsgsWaitToWrite(ActualAccount)) + { + #ifdef DEBUG_SYNCHRO + DebugLog(SynchroFile,"CheckPOP3:ActualAccountMsgsSO-write enter\n"); + #endif + ActualAccount->LastChecked=now; + #ifdef DEBUG_SYNCHRO + DebugLog(SynchroFile,"CheckPOP3:ActualAccountMsgsSO-write done\n"); + #endif + MsgsWriteDone(ActualAccount); + } + #ifdef DEBUG_SYNCHRO + else + DebugLog(SynchroFile,"CheckPOP3:ActualAccountMsgsSO-write wait failed\n"); + #endif + + DeleteMIMEQueue(ActualAccount,NewMails); + + if (DataRX!=NULL) + free(DataRX); + DataRX=NULL; + switch(ActualAccount->SystemError) + { + case EACC_QUEUEALLOC: + case EACC_STOPPED: + ActualAccount->Client.NetClient->Disconnect(); + break; + default: + PostErrorProc(ActualAccount,YAMNParam,(DWORD)NULL,MyClient->SSL); //it closes internet connection too + } + + if (UsingInternet) //if our thread still uses internet + { + #ifdef DEBUG_SYNCHRO + DebugLog(SynchroFile,"CheckPOP3:InternetFreeEV-done\n"); + #endif + SetEvent(ActualAccount->UseInternetFree); + } + SetContactStatus(ActualAccount,ID_STATUS_NA); + } + free(ActualCopied.ServerName); + free(ActualCopied.ServerLogin); + free(ActualCopied.ServerPasswd); + #ifdef DEBUG_COMM + DebugLog(CommFile,"\n"); + #endif +// WriteAccounts(); + #ifdef DEBUG_SYNCHRO + DebugLog(SynchroFile,"CheckPOP3:Decrementing \"using threads\" %x (account %x)\n",ActualAccount->UsingThreads,ActualAccount); + #endif + SCDec(ActualAccount->UsingThreads); + return 0; +} + +DWORD WINAPI DeleteMailsPOP3(struct DeleteParam *WhichTemp) +{ + HPOP3ACCOUNT ActualAccount; + LPVOID YAMNParam; + UINT_PTR POP3PluginParam; + CPop3Client *MyClient; + HYAMNMAIL DeleteMails,NewMails=NULL,MsgQueuePtr; + char* DataRX=NULL; + int mboxsize,msgs,i; + BOOL UsingInternet=FALSE; + struct { + char *ServerName; + DWORD ServerPort; + char *ServerLogin; + char *ServerPasswd; + DWORD Flags; + DWORD NFlags; + DWORD NNFlags; + } ActualCopied; + + //First, we should compare our version of DeleteParam structure, but here it is not needed, because YAMN and internal plugin + //have the same version. But your plugin should do that in this way: + // if (((struct DeleteParam *)WhichTemp)->Ver!=YAMN_DELETEVERSION) + // { + // SetEvent(((struct DeleteParam *)WhichTemp)->ThreadRunningEV); //don't forget to unblock YAMN + // return (DWORD)-1; //ok, but we should return value. + // //When our plugin returns e.g. 0xFFFFFFFF (this is only our plugin value, YAMN does nothing with return value, + // //but only tests if it is nonzero. If yes, it calls GetErrorStringFcn), we know problem occured in YAMN incompatibility + // //and then we can in our GetErrorStringFcn e.g. return string "Uncompatible version of YAMN". + // } + + ActualAccount=(HPOP3ACCOUNT)((struct DeleteParam *)WhichTemp)->AccountParam; //copy address of structure from calling thread to stack of this thread + YAMNParam=((struct DeleteParam *)WhichTemp)->BrowserParam; + POP3PluginParam=(UINT_PTR)((struct DeleteParam *)WhichTemp)->CustomParam; +#ifdef DEBUG_SYNCHRO + DebugLog(SynchroFile,"DeleteMailsPOP3:Incrementing \"using threads\" %x (account %x)\n",ActualAccount->UsingThreads,ActualAccount); +#endif + SCInc(ActualAccount->UsingThreads); + if (INVALID_HANDLE_VALUE!=WhichTemp->ThreadRunningEV) + SetEvent(WhichTemp->ThreadRunningEV); + +#ifdef DEBUG_SYNCHRO + DebugLog(SynchroFile,"DeleteMailsPOP3:ActualAccountSO-read wait\n"); +#endif + if (WAIT_OBJECT_0!=WaitToRead(ActualAccount)) + { +#ifdef DEBUG_SYNCHRO + DebugLog(SynchroFile,"DeleteMailsPOP3:ActualAccountSO-read wait failed\n"); +#endif +#ifdef DEBUG_SYNCHRO + DebugLog(SynchroFile,"DeleteMailsPOP3:Decrementing \"using threads\" %x (account %x)\n",ActualAccount->UsingThreads,ActualAccount); +#endif + SCDec(ActualAccount->UsingThreads); + return 0; + } +#ifdef DEBUG_SYNCHRO + DebugLog(SynchroFile,"DeleteMailsPOP3:ActualAccountSO-read enter\n"); +#endif + if (NULL==(DeleteMails=(HYAMNMAIL)CreateNewDeleteQueue((HYAMNMAIL)ActualAccount->Mails))) //if there's no mail for deleting, return + { + if (POP3_DELETEFROMCHECK!=POP3PluginParam) //We do not wait for free internet when calling from SynchroPOP3. It is because UseInternetFree is blocked + { + YAMN_MAILBROWSERPARAM Param={(HANDLE)0,ActualAccount,YAMN_ACC_MSGP,YAMN_ACC_MSGP,YAMNParam}; //Just update the window + + CallService(MS_YAMN_MAILBROWSER,(WPARAM)&Param,(LPARAM)YAMN_MAILBROWSERVERSION); + } +#ifdef DEBUG_SYNCHRO + DebugLog(SynchroFile,"DeleteMailsPOP3:ActualAccountSO-read done\n"); +#endif + ReadDone(ActualAccount); +#ifdef DEBUG_SYNCHRO + DebugLog(SynchroFile,"DeleteMailsPOP3:Decrementing \"using threads\" %x (account %x)\n",ActualAccount->UsingThreads,ActualAccount); +#endif + SCDec(ActualAccount->UsingThreads); + + return NO_MAIL_FOR_DELETE; + } + MyClient=&(ActualAccount->Client); + +//Now, copy all needed information about account to local variables, so ActualAccount is not blocked in read mode during all connection process, which can last for several minutes. + ActualCopied.ServerName=_strdup(ActualAccount->Server->Name); + ActualCopied.ServerPort=ActualAccount->Server->Port; + ActualCopied.Flags=ActualAccount->Flags; + ActualCopied.ServerLogin=_strdup(ActualAccount->Server->Login); + ActualCopied.ServerPasswd=_strdup(ActualAccount->Server->Passwd); + ActualCopied.NFlags=ActualAccount->NewMailN.Flags; + ActualCopied.NNFlags=ActualAccount->NoNewMailN.Flags; + +#ifdef DEBUG_SYNCHRO + DebugLog(SynchroFile,"DeleteMailsPOP3:ActualAccountSO-read done\n"); +#endif + ReadDone(ActualAccount); + + SCInc(ActualAccount->InternetQueries); //This is POP3-internal SCOUNTER, we set another thread wait for this account to be connected to inet + if (POP3_DELETEFROMCHECK!=POP3PluginParam) //We do not wait for free internet when calling from SynchroPOP3. It is because UseInternetFree is blocked + { +#ifdef DEBUG_SYNCHRO + DebugLog(SynchroFile,"DeleteMailsPOP3:InternetFreeEV-wait\n"); +#endif + WaitForSingleObject(ActualAccount->UseInternetFree,INFINITE); +#ifdef DEBUG_SYNCHRO + DebugLog(SynchroFile,"DeleteMailsPOP3:InternetFreeEV-enter\n"); +#endif + } + SCDec(ActualAccount->InternetQueries); + UsingInternet=TRUE; + + try + { + SetContactStatus(ActualAccount,ID_STATUS_OCCUPIED); +#ifdef DEBUG_COMM + DebugLog(CommFile,"<--------Communication-------->\n"); +#endif + if ((MyClient->NetClient==NULL) || !MyClient->NetClient->Connected()) + { + SetAccountStatus(ActualAccount,TranslateT("Connecting to server")); + + DataRX=MyClient->Connect(ActualCopied.ServerName,ActualCopied.ServerPort,ActualCopied.Flags & YAMN_ACC_SSL23,ActualCopied.Flags & YAMN_ACC_NOTLS); + + char *timestamp=NULL; + if (DataRX!=NULL) { + if (ActualAccount->Flags & YAMN_ACC_APOP) { + char *lpos=strchr(DataRX,'<'); + char *rpos=strchr(DataRX,'>'); + if (lpos && rpos && rpos>lpos) { + int sz=(int)(rpos-lpos+2); + timestamp=new char[sz]; + memcpy(timestamp, lpos, sz-1); + timestamp[sz-1]='\0'; + } + } + free(DataRX); + DataRX=NULL; + } + SetAccountStatus(ActualAccount,TranslateT("Entering POP3 account")); + + if (ActualAccount->Flags & YAMN_ACC_APOP) + { + DataRX=MyClient->APOP(ActualCopied.ServerLogin,ActualCopied.ServerPasswd,timestamp); + if (DataRX!=NULL) + free(DataRX); + DataRX=NULL; + delete[] timestamp; + } else { + DataRX=MyClient->User(ActualCopied.ServerLogin); + if (DataRX!=NULL) + free(DataRX); + DataRX=NULL; + DataRX=MyClient->Pass(ActualCopied.ServerPasswd); + if (DataRX!=NULL) + free(DataRX); + DataRX=NULL; + } + } + +#ifdef DEBUG_DECODE + DebugLog(DecodeFile,"<--------Deleting requested mails-------->\n"); +#endif + if (POP3_DELETEFROMCHECK!=POP3PluginParam) //We do not need to get mails on server as we have already it from check function + { + SetAccountStatus(ActualAccount,TranslateT("Deleting requested mails")); + + DataRX=MyClient->Stat(); + +#ifdef DEBUG_DECODE + DebugLog(DecodeFile,"\n"); +#endif + ExtractStat(DataRX,MyClient->NetClient->Rcv,&mboxsize,&msgs); +#ifdef DEBUG_DECODE + DebugLog(DecodeFile,"%d\n",mboxsize); + DebugLog(DecodeFile,"%d\n",msgs); + DebugLog(DecodeFile,"\n"); +#endif + if (DataRX!=NULL) + free(DataRX); + DataRX=NULL; + for (i=0;iNext=(HYAMNMAIL)CallService(MS_YAMN_CREATEACCOUNTMAIL,(WPARAM)ActualAccount,(LPARAM)YAMN_MAILVERSION); + MsgQueuePtr=MsgQueuePtr->Next; + } + if (MsgQueuePtr==NULL) + { + ActualAccount->SystemError=EPOP3_QUEUEALLOC; + throw (DWORD)ActualAccount->SystemError; + } + } + + if (msgs) + { +#ifdef DEBUG_DECODE + DebugLog(DecodeFile,"\n"); +#endif + DataRX=MyClient->Uidl(); + ExtractUIDL(DataRX,MyClient->NetClient->Rcv,NewMails); +#ifdef DEBUG_DECODE + DebugLog(DecodeFile,"\n"); +#endif + if (DataRX!=NULL) + free(DataRX); + DataRX=NULL; +// we get "new mails" on server (NewMails will contain all mails on server not found in DeleteMails) +// but also in DeleteMails we get only those, which are still on server with their responsable numbers + SynchroMessages(ActualAccount,(HYAMNMAIL *)&DeleteMails,NULL,(HYAMNMAIL *)&NewMails,NULL); + } + } + else + SetAccountStatus(ActualAccount,TranslateT("Deleting spam")); +#ifdef DEBUG_SYNCHRO + DebugLog(SynchroFile,"DeleteMailsPOP3:ActualAccountMsgsSO-write wait\n"); +#endif + if (WAIT_OBJECT_0!=MsgsWaitToWrite(ActualAccount)) + { +#ifdef DEBUG_SYNCHRO + DebugLog(SynchroFile,"DeleteMailsPOP3:ActualAccountMsgsSO-write wait failed\n"); +#endif + throw (DWORD)EACC_STOPPED; + } +#ifdef DEBUG_SYNCHRO + DebugLog(SynchroFile,"DeleteMailsPOP3:ActualAccountMsgsSO-write enter\n"); +#endif + if (msgs || POP3_DELETEFROMCHECK==POP3PluginParam) + { + try + { + HYAMNMAIL Temp; + + for (i=0,MsgQueuePtr=DeleteMails;MsgQueuePtr!=NULL;i++) + { + if (!(MsgQueuePtr->Flags & YAMN_MSG_VIRTUAL)) //of course we can only delete real mails, not virtual + { + DataRX=MyClient->Dele(MsgQueuePtr->Number); + Temp=MsgQueuePtr->Next; + if (POP3_FOK==MyClient->AckFlag) //if server answers that mail was deleted + { + DeleteMIMEMessage((HYAMNMAIL *)&DeleteMails,MsgQueuePtr); + HYAMNMAIL DeletedMail=FindMIMEMessageByID((HYAMNMAIL)ActualAccount->Mails,MsgQueuePtr->ID); + if ((MsgQueuePtr->Flags & YAMN_MSG_MEMDELETE)) //if mail should be deleted from memory (or disk) + { + DeleteMIMEMessage((HYAMNMAIL *)&ActualAccount->Mails,DeletedMail); //remove from queue + CallService(MS_YAMN_DELETEACCOUNTMAIL,(WPARAM)POP3Plugin,(LPARAM)DeletedMail); + } + else //else mark it only as "deleted mail" + { + DeletedMail->Flags |= (YAMN_MSG_VIRTUAL | YAMN_MSG_DELETED); + DeletedMail->Flags &= ~(YAMN_MSG_NEW | YAMN_MSG_USERDELETE | YAMN_MSG_AUTODELETE); //clear "new mail" + } + delete MsgQueuePtr->MailData; + delete[] MsgQueuePtr->ID; + delete MsgQueuePtr; + } + MsgQueuePtr=Temp; + + if (DataRX!=NULL) + free(DataRX); + DataRX=NULL; + } + else + MsgQueuePtr=MsgQueuePtr->Next; + } + } + catch(...) //if any exception in the code where we have write-access to account occured, don't forget to leave write-access + { +#ifdef DEBUG_SYNCHRO + DebugLog(SynchroFile,"DeleteMailsPOP3:ActualAccountMsgsSO-write done\n"); +#endif + MsgsWriteDone(ActualAccount); + throw; //and go to the main exception handling + } + + if (NewMails!=NULL) +// in ActualAccount->Mails we have all mails stored before calling this function +// in NewMails we have all mails not found in DeleteMails (in other words: we performed new ID checking and we +// stored all mails found on server, then we deleted the ones we wanted to delete in this function +// and NewMails queue now contains actual state of mails on server). But we will not use NewMails as actual state, because NewMails does not contain header data (subject, from...) +// We perform deleting from ActualAccount->Mails: we remove from original queue (ActualAccount->Mails) all deleted mails + SynchroMessages(ActualAccount,(HYAMNMAIL *)&ActualAccount->Mails,NULL,(HYAMNMAIL *)&NewMails,NULL); +// Now ActualAccount->Mails contains all mails when calling this function except the ones, we wanted to delete (these are in DeleteMails) +// And in NewMails we have new mails (if any) + else if (POP3_DELETEFROMCHECK!=POP3PluginParam) + { + DeleteMIMEQueue(ActualAccount,(HYAMNMAIL)ActualAccount->Mails); + ActualAccount->Mails=NULL; + } + } + else + { + DeleteMIMEQueue(ActualAccount,(HYAMNMAIL)ActualAccount->Mails); + ActualAccount->Mails=NULL; + } +#ifdef DEBUG_SYNCHRO + DebugLog(SynchroFile,"DeleteMailsPOP3:ActualAccountMsgsSO-write done\n"); +#endif + MsgsWriteDone(ActualAccount); +#ifdef DEBUG_DECODE + DebugLog(DecodeFile,"\n"); +#endif + +// TODO: now, we have in NewMails new mails. If NewMails is not NULL, we found some new mails, so Checking for new mail should be performed +// now, we do not call CheckPOP3 + +// if there is no waiting thread for internet connection close it +// else leave connection open +// if this functin was called from SynchroPOP3, then do not try to disconnect + if (POP3_DELETEFROMCHECK!=POP3PluginParam) + { + YAMN_MAILBROWSERPARAM Param={(HANDLE)0,ActualAccount,ActualCopied.NFlags,YAMN_ACC_MSGP,YAMNParam}; + + CallService(MS_YAMN_MAILBROWSER,(WPARAM)&Param,(LPARAM)YAMN_MAILBROWSERVERSION); + + if (0==SCGetNumber(ActualAccount->InternetQueries)) + { + DataRX=MyClient->Quit(); + if (DataRX!=NULL) + free(DataRX); + DataRX=NULL; + MyClient->NetClient->Disconnect(); + + SetAccountStatus(ActualAccount,TranslateT("Disconnected")); + } + + UsingInternet=FALSE; +#ifdef DEBUG_SYNCHRO + DebugLog(SynchroFile,"DeleteMailsPOP3:InternetFreeEV-done\n"); +#endif + SetEvent(ActualAccount->UseInternetFree); + } + SetContactStatus(ActualAccount,ActualAccount->isCounting?ID_STATUS_ONLINE:ID_STATUS_OFFLINE); + } +#ifdef DEBUG_COMM + catch(DWORD ErrorCode) +#else + catch(DWORD) +#endif + { + if (ActualAccount->Client.POP3Error==EPOP3_STOPPED) + ActualAccount->SystemError=EACC_STOPPED; +#ifdef DEBUG_COMM + DebugLog(CommFile,"ERROR %x\n",ErrorCode); +#endif + if (DataRX!=NULL) + free(DataRX); + switch(ActualAccount->SystemError) + { + case EACC_QUEUEALLOC: + case EACC_STOPPED: + ActualAccount->Client.NetClient->Disconnect(); + break; + default: + PostErrorProc(ActualAccount,YAMNParam,POP3PluginParam,MyClient->SSL); //it closes internet connection too + } + + if (UsingInternet && (POP3_DELETEFROMCHECK!=POP3PluginParam)) //if our thread still uses internet and it is needed to release internet + { +#ifdef DEBUG_SYNCHRO + DebugLog(SynchroFile,"CheckPOP3:InternetFreeEV-done\n"); +#endif + SetEvent(ActualAccount->UseInternetFree); + } + } + + free(ActualCopied.ServerName); + free(ActualCopied.ServerLogin); + free(ActualCopied.ServerPasswd); + + DeleteMIMEQueue(ActualAccount,NewMails); + DeleteMIMEQueue(ActualAccount,DeleteMails); + +#ifdef DEBUG_COMM + DebugLog(CommFile,"\n"); +#endif +// WriteAccounts(); +#ifdef DEBUG_SYNCHRO + DebugLog(SynchroFile,"DeleteMailsPOP3:Decrementing \"using threads\" %x (account %x)\n",ActualAccount->UsingThreads,ActualAccount); +#endif + SCDec(ActualAccount->UsingThreads); + return 0; +} + +void ExtractStat(char *stream,int len,int *mboxsize,int *mails) +{ + char *finder=stream; + while(WS(finder) || ENDLINE(finder)) finder++; + if (ACKLINE(finder)) + { + while(!WS(finder)) finder++; + while(WS(finder)) finder++; + } + if (1!=sscanf(finder,"%d",mails)) + throw (DWORD)EPOP3_STAT; + while(!WS(finder)) finder++; + while(WS(finder)) finder++; + if (1!=sscanf(finder,"%d",mboxsize)) + throw (DWORD)EPOP3_STAT; +} +void ExtractMail(char *stream,int len,HYAMNMAIL queue) +{ + char *finder=stream; + char *finderend; + int msgnr,i; + HYAMNMAIL queueptr=queue; + + while(WS(finder) || ENDLINE(finder)) finder++; + while(!ACKLINE(finder)) finder++; + while(!ENDLINE(finder)) finder++; //now we at the end of first ack line + while(finder<=(stream+len)) + { + while(ENDLINE(finder)) finder++; //go to the new line + if (DOTLINE(finder+1)) //at the end of stream + break; + #ifdef DEBUG_DECODE + DebugLog(DecodeFile,"\n"); + #endif + while(WS(finder)) finder++; //jump whitespace + if (1!=sscanf(finder,"%d",&msgnr)) + throw (DWORD)EPOP3_UIDL; + #ifdef DEBUG_DECODE + DebugLog(DecodeFile,"%d\n",msgnr); + #endif +// for (i=1,queueptr=queue;(queueptr->Next!=NULL) && (iNext,i++); +// if (i!=msgnr) +// throw (DWORD)EPOP3_UIDL; + while(!WS(finder)) finder++; //jump characters + while(WS(finder)) finder++; //jump whitespace + finderend=finder+1; + while(!WS(finderend) && !ENDLINE(finderend)) finderend++; + queueptr->ID=new char[finderend-finder+1]; + for (i=0;finder!=finderend;finder++,i++) + queueptr->MailData->Body[i]=*finder; + queueptr->MailData->Body[i]=0; //ends string + queueptr->Number=msgnr; + #ifdef DEBUG_DECODE + DebugLog(DecodeFile,"%s\n",queueptr->MailData->Body); + DebugLog(DecodeFile,"\n"); + #endif + queueptr=queueptr->Next; + while(!ENDLINE(finder)) finder++; + } +} + +void ExtractUIDL(char *stream,int len,HYAMNMAIL queue) +{ + char *finder=stream; + char *finderend; + int msgnr,i; + HYAMNMAIL queueptr=queue; + + while(WS(finder) || ENDLINE(finder)) finder++; + while(!ACKLINE(finder)) finder++; + while(!ENDLINE(finder)) finder++; //now we at the end of first ack line + while(finder<=(stream+len)) + { + while(ENDLINE(finder)) finder++; //go to the new line + if (DOTLINE(finder+1)) //at the end of stream + break; + #ifdef DEBUG_DECODE + DebugLog(DecodeFile,"\n"); + #endif + while(WS(finder)) finder++; //jump whitespace + if (1!=sscanf(finder,"%d",&msgnr)) + throw (DWORD)EPOP3_UIDL; + #ifdef DEBUG_DECODE + DebugLog(DecodeFile,"%d\n",msgnr); + #endif +// for (i=1,queueptr=queue;(queueptr->Next!=NULL) && (iNext,i++); +// if (i!=msgnr) +// throw (DWORD)EPOP3_UIDL; + while(!WS(finder)) finder++; //jump characters + while(WS(finder)) finder++; //jump whitespace + finderend=finder+1; + while(!WS(finderend) && !ENDLINE(finderend)) finderend++; + queueptr->ID=new char[finderend-finder+1]; + for (i=0;finder!=finderend;finder++,i++) + queueptr->ID[i]=*finder; + queueptr->ID[i]=0; //ends string + queueptr->Number=msgnr; + #ifdef DEBUG_DECODE + DebugLog(DecodeFile,"%s\n",queueptr->ID); + DebugLog(DecodeFile,"\n"); + #endif + queueptr=queueptr->Next; + while(!ENDLINE(finder)) finder++; + } +} + +void ExtractList(char *stream,int len,HYAMNMAIL queue) +{ + char *finder=stream; + char *finderend; + int msgnr,i; + HYAMNMAIL queueptr; + + while(WS(finder) || ENDLINE(finder)) finder++; + while(!ACKLINE(finder)) finder++; + while(!ENDLINE(finder)) finder++; //now we at the end of first ack line + while(finder<=(stream+len)) + { + while(ENDLINE(finder)) finder++; //go to the new line + if (DOTLINE(finder+1)) //at the end of stream + break; + #ifdef DEBUG_DECODE + DebugLog(DecodeFile,"\n",NULL,0); + #endif + while(WS(finder)) finder++; //jump whitespace + if (1!=sscanf(finder,"%d",&msgnr)) //message nr. + throw (DWORD)EPOP3_LIST; + #ifdef DEBUG_DECODE + DebugLog(DecodeFile,"%d\n",msgnr); + #endif + + for (i=1,queueptr=queue;(queueptr->Next!=NULL) && (iNext,i++); + if (i!=msgnr) + throw (DWORD)EPOP3_LIST; + while(!WS(finder)) finder++; //jump characters + while(WS(finder)) finder++; //jump whitespace + finderend=finder+1; + if (1!=sscanf(finder,"%d",&queueptr->MailData->Size)) + throw (DWORD)EPOP3_LIST; + #ifdef DEBUG_DECODE + DebugLog(DecodeFile,"%d\n",queueptr->MailData->Size); + #endif + while(!ENDLINE(finder)) finder++; + } +} + +TCHAR* WINAPI GetErrorString(DWORD Code) +{ + static TCHAR *POP3Errors[]= + { + LPGENT("Memory allocation error."), //memory allocation + LPGENT("Account is about to be stopped."), //stop account + LPGENT("Cannot connect to POP3 server."), + LPGENT("Cannot allocate memory for received data."), + LPGENT("Cannot login to POP3 server."), + LPGENT("Bad user or password."), + LPGENT("Server does not support APOP authorization."), + LPGENT("Error while executing POP3 command."), + LPGENT("Error while executing POP3 command."), + LPGENT("Error while executing POP3 command."), + }; + + static TCHAR *NetlibErrors[]= + { + LPGENT("Cannot connect to server with NetLib."), + LPGENT("Cannot send data."), + LPGENT("Cannot receive data."), + LPGENT("Cannot allocate memory for received data."), + }; + + static TCHAR *SSLErrors[]= + { + LPGENT("OpenSSL not loaded."), + LPGENT("Windows socket 2.0 init failed."), + LPGENT("DNS lookup error."), + LPGENT("Error while creating base socket."), + LPGENT("Error connecting to server with socket."), + LPGENT("Error while creating SSL structure."), + LPGENT("Error connecting socket with SSL."), + LPGENT("Server rejected connection with SSL."), + LPGENT("Cannot write SSL data."), + LPGENT("Cannot read SSL data."), + LPGENT("Cannot allocate memory for received data."), + }; + + TCHAR *ErrorString = new TCHAR[ERRORSTR_MAXLEN]; + POP3_ERRORCODE *ErrorCode=(POP3_ERRORCODE *)(UINT_PTR)Code; + + mir_sntprintf(ErrorString, ERRORSTR_MAXLEN, TranslateT("Error %d-%d-%d-%d:"),ErrorCode->AppError,ErrorCode->POP3Error,ErrorCode->NetError,ErrorCode->SystemError); + if (ErrorCode->POP3Error) + mir_sntprintf(ErrorString, ERRORSTR_MAXLEN, _T("%s\n%s"),ErrorString,TranslateTS(POP3Errors[ErrorCode->POP3Error-1])); + if (ErrorCode->NetError) { + if (ErrorCode->SSL) + mir_sntprintf(ErrorString, ERRORSTR_MAXLEN, _T("%s\n%s"),ErrorString, TranslateTS(SSLErrors[ErrorCode->NetError-1])); + else + mir_sntprintf(ErrorString, ERRORSTR_MAXLEN, _T("%s\n%s"),ErrorString, TranslateTS(NetlibErrors[ErrorCode->NetError-4])); + } + + return ErrorString; +} + +void WINAPI DeleteErrorString(LPVOID String) +{ + delete (char *)String; +} diff --git a/protocols/YAMN/proto/pop3/pop3comm.h b/protocols/YAMN/proto/pop3/pop3comm.h new file mode 100644 index 0000000000..c7eb01b5a1 --- /dev/null +++ b/protocols/YAMN/proto/pop3/pop3comm.h @@ -0,0 +1,97 @@ +#ifndef __POP3COMM_H +#define __POP3COMM_H + +#include +#include "pop3.h" + +#include "m_protoplugin.h" +//We can use synchro.h because this is internal plugin. If you use external plugin, +//and you want to use SO for your plugin, you can use YAMN's SO. +//All you need is to include synchro.h and use YAMN's exported synchronization functions. +#include "m_synchro.h" + +//For mail exported functions defintions +#include "m_mails.h" + +#include "../../debug.h" + +#define POP3_FILEVERSION 1 //Version of aditional information stored in book file + +typedef struct CPOP3Account: public CAccount +{ +// We can use SCOUNTER structure, because this is internal plugin. +// This SO is used to determine if any POP3 account is in "write access" mode + static PSCOUNTER AccountWriterSO; + +// It is usefull to have client structure in account. With this structure we have access to account's socket. +// This is related to InternetQueries and UseInternetFree +// This member should be synchronized with UseInternetFree + class CPop3Client Client; + +// This member is usefull for MIME headers. It is default codepage, if no other codepage found + WORD CP; //access only through AccountAccessSO + +// In this memeber last error code is stored + DWORD SystemError; //access through UseInternetFree + +// We use only counter from this object and it is # of threads waiting to work on internet. +// We use event UseInternet to access critical sections. +// It is usefull in 2 ways: we have mutual exclusion that only one thread works with account on internet. +// Thread, which has done its work with account on internet can close socket, but it is not needed, when any other +// thread wants to work (e.g. we have deleted mails, but when deleting, another thread wants to check new mail, so +// we delete all needed mails and check if there's thread that wants to work. If yes, we do not need to quit session, +// we leave socket open, and leave internet. Another thread then start checking and does not connect, does not send +// user and password... because socket is open- it continues) + PSCOUNTER InternetQueries; + HANDLE UseInternetFree; + + CPOP3Account(); + ~CPOP3Account(); + +} POP3ACCOUNT,*HPOP3ACCOUNT; + +typedef struct POP3LayeredError +{ + BOOL SSL; + DWORD AppError; + DWORD POP3Error; + DWORD NetError; + DWORD SystemError; +} POP3_ERRORCODE,*PPOP3_ERRORCODE; + +struct YAMNExportedFcns +{ + YAMN_SETPROTOCOLPLUGINFCNIMPORTFCN SetProtocolPluginFcnImportFcn; + YAMN_WAITTOWRITEFCN WaitToWriteFcn; + YAMN_WRITEDONEFCN WriteDoneFcn; + YAMN_WAITTOREADFCN WaitToReadFcn; + YAMN_READDONEFCN ReadDoneFcn; + YAMN_SCMANAGEFCN SCGetNumberFcn; + YAMN_SCMANAGEFCN SCIncFcn; + YAMN_SCMANAGEFCN SCDecFcn; + YAMN_SETSTATUSFCN SetStatusFcn; + YAMN_GETSTATUSFCN GetStatusFcn; +}; + +struct MailExportedFcns +{ + YAMN_SYNCHROMIMEMSGSFCN SynchroMessagesFcn; + YAMN_TRANSLATEHEADERFCN TranslateHeaderFcn; + YAMN_APPENDQUEUEFCN AppendQueueFcn; + YAMN_DELETEMIMEQUEUEFCN DeleteMessagesToEndFcn; + YAMN_DELETEMIMEMESSAGEFCN DeleteMessageFromQueueFcn; + YAMN_FINDMIMEMESSAGEFCN FindMessageByIDFcn; + YAMN_CREATENEWDELETEQUEUEFCN CreateNewDeleteQueueFcn; +}; + +enum +{ + EACC_QUEUEALLOC=1, //memory allocation + EACC_STOPPED, //stop account +}; + +#define NO_MAIL_FOR_DELETE 1 + +#define POP3_DELETEFROMCHECK 1 + +#endif diff --git a/protocols/YAMN/proto/pop3/pop3opt.cpp b/protocols/YAMN/proto/pop3/pop3opt.cpp new file mode 100644 index 0000000000..bcbf78e380 --- /dev/null +++ b/protocols/YAMN/proto/pop3/pop3opt.cpp @@ -0,0 +1,1556 @@ +/* + * This code implements POP3 options window handling + * + * (c) majvan 2002-2003 +*/ + +#include "../../yamn.h" +#include "../../main.h" +#include "pop3comm.h" +#include "pop3opt.h" + +//-------------------------------------------------------------------------------------------------- + +static BOOL Check0,Check1,Check2,Check3,Check4,Check5,Check6,Check7,Check8,Check9; +static char DlgInput[MAX_PATH]; + +void CheckMenuItems(); + +//-------------------------------------------------------------------------------------------------- + +INT_PTR CALLBACK DlgProcYAMNOpt(HWND hDlg,UINT msg,WPARAM wParam,LPARAM lParam) +{ + switch(msg) { + case WM_INITDIALOG: + TranslateDialogDefault(hDlg); + CheckDlgButton(hDlg,IDC_CHECKTTB,DBGetContactSettingByte(NULL,YAMN_DBMODULE,YAMN_TTBFCHECK,1) ? BST_CHECKED : BST_UNCHECKED); + CheckDlgButton(hDlg,IDC_LONGDATE,(optDateTime&SHOWDATELONG) ? BST_CHECKED : BST_UNCHECKED); + CheckDlgButton(hDlg,IDC_SMARTDATE,(optDateTime&SHOWDATENOTODAY) ? BST_CHECKED : BST_UNCHECKED); + CheckDlgButton(hDlg,IDC_NOSECONDS,(optDateTime&SHOWDATENOSECONDS) ? BST_CHECKED : BST_UNCHECKED); + CheckDlgButton(hDlg,IDC_MAINMENU,DBGetContactSettingByte(NULL, YAMN_DBMODULE, YAMN_SHOWMAINMENU, 1)); + CheckDlgButton(hDlg,IDC_YAMNASPROTO,DBGetContactSettingByte(NULL, YAMN_DBMODULE, YAMN_SHOWASPROTO, 1)); + CheckDlgButton(hDlg,IDC_CLOSEONDELETE,DBGetContactSettingByte(NULL, YAMN_DBMODULE, YAMN_CLOSEDELETE, 0)); + break; + + case WM_COMMAND: + switch(LOWORD(wParam)) { + case IDC_YAMNASPROTO: + case IDC_MAINMENU: + case IDC_CHECKTTB: + case IDC_CLOSEONDELETE: + case IDC_LONGDATE: + case IDC_SMARTDATE: + case IDC_NOSECONDS: + SendMessage(GetParent(hDlg),PSM_CHANGED,0,0); + break; + } + break; + + case WM_NOTIFY: + switch(((LPNMHDR)lParam)->idFrom) { + case 0: + switch(((LPNMHDR)lParam)->code) { + case PSN_APPLY: + DBWriteContactSettingByte(NULL, YAMN_DBMODULE, YAMN_SHOWASPROTO, IsDlgButtonChecked(hDlg,IDC_YAMNASPROTO)); + DBWriteContactSettingByte(NULL, YAMN_DBMODULE, YAMN_SHOWMAINMENU, IsDlgButtonChecked(hDlg,IDC_MAINMENU)); + DBWriteContactSettingByte(NULL, YAMN_DBMODULE, YAMN_CLOSEDELETE, IsDlgButtonChecked(hDlg,IDC_CLOSEONDELETE)); + DBWriteContactSettingByte(NULL, YAMN_DBMODULE, YAMN_TTBFCHECK, IsDlgButtonChecked(hDlg,IDC_CHECKTTB)); + + AddTopToolbarIcon(0, 0); + CheckMenuItems(); + + optDateTime = 0; + if (IsDlgButtonChecked(hDlg,IDC_LONGDATE))optDateTime |= SHOWDATELONG; + if (IsDlgButtonChecked(hDlg,IDC_SMARTDATE))optDateTime |= SHOWDATENOTODAY; + if (IsDlgButtonChecked(hDlg,IDC_NOSECONDS))optDateTime |= SHOWDATENOSECONDS; + DBWriteContactSettingByte(NULL,YAMN_DBMODULE,YAMN_DBTIMEOPTIONS,optDateTime); + } + } + break; + } + + return FALSE; +} + +INT_PTR CALLBACK DlgProcPluginOpt(HWND hDlg,UINT msg,WPARAM wParam,LPARAM lParam) +{ + switch(msg) { + case WM_INITDIALOG: + TranslateDialogDefault(hDlg); + break; + + case WM_COMMAND: + { + WORD wNotifyCode = HIWORD(wParam); + switch(LOWORD(wParam)) + { + case IDC_COMBOPLUGINS: + if (wNotifyCode==CBN_SELCHANGE) + { + HWND hCombo=GetDlgItem(hDlg,IDC_COMBOPLUGINS); + PYAMN_PROTOPLUGINQUEUE PParser; + PYAMN_FILTERPLUGINQUEUE FParser; + int index,id; + + if (CB_ERR==(index=SendMessage(hCombo,CB_GETCURSEL,0,0))) + break; + id=SendMessage(hCombo,CB_GETITEMDATA,(WPARAM)index,(LPARAM)0); + EnterCriticalSection(&PluginRegCS); + for (PParser=FirstProtoPlugin;PParser!=NULL;PParser=PParser->Next) + if (id==(INT_PTR)PParser->Plugin) + { + SetDlgItemTextA(hDlg,IDC_STVER,PParser->Plugin->PluginInfo->Ver); + SetDlgItemTextA(hDlg,IDC_STDESC,PParser->Plugin->PluginInfo->Description == NULL ? "" : PParser->Plugin->PluginInfo->Description); + SetDlgItemTextA(hDlg,IDC_STCOPY,PParser->Plugin->PluginInfo->Copyright == NULL ? "" : PParser->Plugin->PluginInfo->Copyright); + SetDlgItemTextA(hDlg,IDC_STMAIL,PParser->Plugin->PluginInfo->Email == NULL ? "" : PParser->Plugin->PluginInfo->Email); + SetDlgItemTextA(hDlg,IDC_STWWW,PParser->Plugin->PluginInfo->WWW == NULL ? "" : PParser->Plugin->PluginInfo->WWW); + break; + } + for (FParser=FirstFilterPlugin;FParser!=NULL;FParser=FParser->Next) + if (id==(INT_PTR)FParser->Plugin) + { + SetDlgItemTextA(hDlg,IDC_STVER,FParser->Plugin->PluginInfo->Ver); + SetDlgItemTextA(hDlg,IDC_STDESC,FParser->Plugin->PluginInfo->Description == NULL ? "" : FParser->Plugin->PluginInfo->Description); + SetDlgItemTextA(hDlg,IDC_STCOPY,FParser->Plugin->PluginInfo->Copyright == NULL ? "" : FParser->Plugin->PluginInfo->Copyright); + SetDlgItemTextA(hDlg,IDC_STMAIL,FParser->Plugin->PluginInfo->Email == NULL ? "" : FParser->Plugin->PluginInfo->Email); + SetDlgItemTextA(hDlg,IDC_STWWW,FParser->Plugin->PluginInfo->WWW == NULL ? "" : FParser->Plugin->PluginInfo->WWW); + break; + } + LeaveCriticalSection(&PluginRegCS); + } + break; + case IDC_STWWW: + { + char str[1024]; + GetDlgItemTextA(hDlg,IDC_STWWW,str,SIZEOF(str)); + CallService(MS_UTILS_OPENURL,1,(LPARAM)str); + break; + } + + } + break; + } + case WM_SHOWWINDOW: + if (TRUE==(BOOL)wParam) { + PYAMN_PROTOPLUGINQUEUE PParser; + PYAMN_FILTERPLUGINQUEUE FParser; + int index; + + EnterCriticalSection(&PluginRegCS); + for (PParser = FirstProtoPlugin; PParser != NULL; PParser = PParser->Next) { + index = SendDlgItemMessageA(hDlg,IDC_COMBOPLUGINS,CB_ADDSTRING,0,(LPARAM)PParser->Plugin->PluginInfo->Name); + index = SendDlgItemMessage(hDlg,IDC_COMBOPLUGINS,CB_SETITEMDATA,(WPARAM)index,(LPARAM)PParser->Plugin); + } + for (FParser = FirstFilterPlugin; FParser != NULL; FParser = FParser->Next) { + index = SendDlgItemMessageA(hDlg,IDC_COMBOPLUGINS,CB_ADDSTRING,0,(LPARAM)FParser->Plugin->PluginInfo->Name); + index = SendDlgItemMessage(hDlg,IDC_COMBOPLUGINS,CB_SETITEMDATA,(WPARAM)index,(LPARAM)FParser->Plugin); + } + + LeaveCriticalSection(&PluginRegCS); + SendDlgItemMessage(hDlg,IDC_COMBOPLUGINS,CB_SETCURSEL,(WPARAM)0,(LPARAM)0); + SendMessage(hDlg,WM_COMMAND,MAKELONG(IDC_COMBOPLUGINS,CBN_SELCHANGE),(LPARAM)NULL); + break; + } + else { //delete all items in combobox + int cbn=SendDlgItemMessage(hDlg,IDC_COMBOPLUGINS,CB_GETCOUNT,(WPARAM)0,(LPARAM)0); + for (int i=0;iStatusFlags & YAMN_ACC_ST0 ? BST_CHECKED : BST_UNCHECKED); + CheckDlgButton(hDlg,IDC_CHECKST1,ActualAccount->StatusFlags & YAMN_ACC_ST1 ? BST_CHECKED : BST_UNCHECKED); + CheckDlgButton(hDlg,IDC_CHECKST2,ActualAccount->StatusFlags & YAMN_ACC_ST2 ? BST_CHECKED : BST_UNCHECKED); + CheckDlgButton(hDlg,IDC_CHECKST3,ActualAccount->StatusFlags & YAMN_ACC_ST3 ? BST_CHECKED : BST_UNCHECKED); + CheckDlgButton(hDlg,IDC_CHECKST4,ActualAccount->StatusFlags & YAMN_ACC_ST4 ? BST_CHECKED : BST_UNCHECKED); + CheckDlgButton(hDlg,IDC_CHECKST5,ActualAccount->StatusFlags & YAMN_ACC_ST5 ? BST_CHECKED : BST_UNCHECKED); + CheckDlgButton(hDlg,IDC_CHECKST6,ActualAccount->StatusFlags & YAMN_ACC_ST6 ? BST_CHECKED : BST_UNCHECKED); + CheckDlgButton(hDlg,IDC_CHECKST7,ActualAccount->StatusFlags & YAMN_ACC_ST7 ? BST_CHECKED : BST_UNCHECKED); + CheckDlgButton(hDlg,IDC_CHECKST8,ActualAccount->StatusFlags & YAMN_ACC_ST8 ? BST_CHECKED : BST_UNCHECKED); + CheckDlgButton(hDlg,IDC_CHECKST9,ActualAccount->StatusFlags & YAMN_ACC_ST9 ? BST_CHECKED : BST_UNCHECKED); + ReadDone(ActualAccount); + } + else + { + CheckDlgButton(hDlg,IDC_CHECKST0,BST_UNCHECKED); + CheckDlgButton(hDlg,IDC_CHECKST1,BST_CHECKED); + CheckDlgButton(hDlg,IDC_CHECKST2,BST_UNCHECKED); + CheckDlgButton(hDlg,IDC_CHECKST3,BST_UNCHECKED); + CheckDlgButton(hDlg,IDC_CHECKST4,BST_UNCHECKED); + CheckDlgButton(hDlg,IDC_CHECKST5,BST_UNCHECKED); + CheckDlgButton(hDlg,IDC_CHECKST6,BST_UNCHECKED); + CheckDlgButton(hDlg,IDC_CHECKST7,BST_CHECKED); + CheckDlgButton(hDlg,IDC_CHECKST8,BST_CHECKED); + CheckDlgButton(hDlg,IDC_CHECKST9,BST_CHECKED); + } + return TRUE; +} +BOOL DlgShowAccountPopup(HWND hDlg,WPARAM wParam,LPARAM lParam) +{ + HPOP3ACCOUNT ActualAccount=(HPOP3ACCOUNT)lParam; + + if ((DWORD)wParam==M_SHOWACTUAL) + { + #ifdef DEBUG_SYNCHRO + DebugLog(SynchroFile,"Options:SHOWACCOUNT:ActualAccountSO-read wait\n"); + #endif + WaitToRead(ActualAccount); //we do not need to check if account is deleted. It is not deleted, because only thread that can delete account is this thread + #ifdef DEBUG_SYNCHRO + DebugLog(SynchroFile,"Options:SHOWACCOUNT:ActualAccountSO-read enter\n"); + #endif + SetDlgItemInt(hDlg,IDC_EDITPOPS,ActualAccount->NewMailN.PopUpTime,FALSE); + SetDlgItemInt(hDlg,IDC_EDITNPOPS,ActualAccount->NoNewMailN.PopUpTime,FALSE); + SetDlgItemInt(hDlg,IDC_EDITFPOPS,ActualAccount->BadConnectN.PopUpTime,FALSE); + + + CheckDlgButton(hDlg,IDC_CHECKPOP,ActualAccount->NewMailN.Flags & YAMN_ACC_POP ? BST_CHECKED : BST_UNCHECKED); + CheckDlgButton(hDlg,IDC_CHECKCOL,ActualAccount->NewMailN.Flags & YAMN_ACC_POPC ? BST_CHECKED : BST_UNCHECKED); + CheckDlgButton(hDlg,IDC_CHECKNPOP,ActualAccount->NoNewMailN.Flags & YAMN_ACC_POP ? BST_CHECKED : BST_UNCHECKED); + CheckDlgButton(hDlg,IDC_CHECKNCOL,ActualAccount->NoNewMailN.Flags & YAMN_ACC_POPC ? BST_CHECKED : BST_UNCHECKED); + CheckDlgButton(hDlg,IDC_CHECKFPOP,ActualAccount->BadConnectN.Flags & YAMN_ACC_POP ? BST_CHECKED : BST_UNCHECKED); + CheckDlgButton(hDlg,IDC_CHECKFCOL,ActualAccount->BadConnectN.Flags & YAMN_ACC_POPC ? BST_CHECKED : BST_UNCHECKED); + CheckDlgButton(hDlg,IDC_RADIOPOPN,ActualAccount->Flags & YAMN_ACC_POPN ? BST_CHECKED : BST_UNCHECKED); + CheckDlgButton(hDlg,IDC_RADIOPOP1,ActualAccount->Flags & YAMN_ACC_POPN ? BST_UNCHECKED : BST_CHECKED); + #ifdef DEBUG_SYNCHRO + DebugLog(SynchroFile,"Options:SHOWACCOUNT:ActualAccountSO-read done\n"); + #endif + ReadDone(ActualAccount); + } + else //default + { + + SetDlgItemInt(hDlg,IDC_EDITPOPS,0,FALSE); + SetDlgItemInt(hDlg,IDC_EDITNPOPS,0,FALSE); + SetDlgItemInt(hDlg,IDC_EDITFPOPS,0,FALSE); + CheckDlgButton(hDlg,IDC_CHECKPOP,BST_CHECKED); + CheckDlgButton(hDlg,IDC_CHECKCOL,BST_CHECKED); + CheckDlgButton(hDlg,IDC_CHECKNPOP,BST_CHECKED); + CheckDlgButton(hDlg,IDC_CHECKNCOL,BST_CHECKED); + CheckDlgButton(hDlg,IDC_CHECKFPOP,BST_CHECKED); + CheckDlgButton(hDlg,IDC_CHECKFCOL,BST_CHECKED); + CheckDlgButton(hDlg,IDC_RADIOPOPN,BST_UNCHECKED); + CheckDlgButton(hDlg,IDC_RADIOPOP1,BST_CHECKED); + } + return TRUE; +} +BOOL DlgShowAccount(HWND hDlg,WPARAM wParam,LPARAM lParam) +{ + HPOP3ACCOUNT ActualAccount=(HPOP3ACCOUNT)lParam; + int i; + + if ((DWORD)wParam==M_SHOWACTUAL) + { + TCHAR accstatus[256]; + #ifdef DEBUG_SYNCHRO + DebugLog(SynchroFile,"Options:SHOWACCOUNT:ActualAccountSO-read wait\n"); + #endif + WaitToRead(ActualAccount); //we do not need to check if account is deleted. It is not deleted, because only thread that can delete account is this thread + #ifdef DEBUG_SYNCHRO + DebugLog(SynchroFile,"Options:SHOWACCOUNT:ActualAccountSO-read enter\n"); + #endif + DlgSetItemText(hDlg, IDC_EDITSERVER, ActualAccount->Server->Name); + DlgSetItemText(hDlg, IDC_EDITNAME, ActualAccount->Name); + DlgSetItemText(hDlg, IDC_EDITLOGIN, ActualAccount->Server->Login); + DlgSetItemText(hDlg, IDC_EDITPASS, ActualAccount->Server->Passwd); + DlgSetItemTextW(hDlg, IDC_EDITAPP, ActualAccount->NewMailN.App); + DlgSetItemTextW(hDlg, IDC_EDITAPPPARAM, ActualAccount->NewMailN.AppParam); + SetDlgItemInt(hDlg,IDC_EDITPORT,ActualAccount->Server->Port,FALSE); + SetDlgItemInt(hDlg,IDC_EDITINTERVAL,ActualAccount->Interval/60,FALSE); + SetDlgItemInt(hDlg,IDC_EDITPOPS,ActualAccount->NewMailN.PopUpTime,FALSE); + SetDlgItemInt(hDlg,IDC_EDITNPOPS,ActualAccount->NoNewMailN.PopUpTime,FALSE); + SetDlgItemInt(hDlg,IDC_EDITFPOPS,ActualAccount->BadConnectN.PopUpTime,FALSE); + for (i=0;i<=CPLENSUPP;i++) + if ((iCP)) + { + SendMessage(GetDlgItem(hDlg,IDC_COMBOCP),CB_SETCURSEL,(WPARAM)i,(LPARAM)0); + break; + } + if (i==CPLENSUPP) + SendMessage(GetDlgItem(hDlg,IDC_COMBOCP),CB_SETCURSEL,(WPARAM)CPDEFINDEX,(LPARAM)0); + + CheckDlgButton(hDlg,IDC_CHECK,ActualAccount->Flags & YAMN_ACC_ENA ? BST_CHECKED : BST_UNCHECKED); + CheckDlgButton(hDlg,IDC_CHECKSND,ActualAccount->NewMailN.Flags & YAMN_ACC_SND ? BST_CHECKED : BST_UNCHECKED); + CheckDlgButton(hDlg,IDC_CHECKMSG,ActualAccount->NewMailN.Flags & YAMN_ACC_MSG ? BST_CHECKED : BST_UNCHECKED); + CheckDlgButton(hDlg,IDC_CHECKICO,ActualAccount->NewMailN.Flags & YAMN_ACC_ICO ? BST_CHECKED : BST_UNCHECKED); + CheckDlgButton(hDlg,IDC_CHECKPOP,ActualAccount->NewMailN.Flags & YAMN_ACC_POP ? BST_CHECKED : BST_UNCHECKED); + CheckDlgButton(hDlg,IDC_CHECKCOL,ActualAccount->NewMailN.Flags & YAMN_ACC_POPC ? BST_CHECKED : BST_UNCHECKED); + CheckDlgButton(hDlg,IDC_CHECKAPP,ActualAccount->NewMailN.Flags & YAMN_ACC_APP ? BST_CHECKED : BST_UNCHECKED); + CheckDlgButton(hDlg,IDC_CHECKKBN,ActualAccount->NewMailN.Flags & YAMN_ACC_KBN ? BST_CHECKED : BST_UNCHECKED); + CheckDlgButton(hDlg,IDC_CHECKNPOP,ActualAccount->NoNewMailN.Flags & YAMN_ACC_POP ? BST_CHECKED : BST_UNCHECKED); + CheckDlgButton(hDlg,IDC_CHECKNCOL,ActualAccount->NoNewMailN.Flags & YAMN_ACC_POPC ? BST_CHECKED : BST_UNCHECKED); + CheckDlgButton(hDlg,IDC_CHECKNMSGP,ActualAccount->NoNewMailN.Flags & YAMN_ACC_MSGP ? BST_CHECKED : BST_UNCHECKED); + CheckDlgButton(hDlg,IDC_CHECKFSND,ActualAccount->BadConnectN.Flags & YAMN_ACC_SND ? BST_CHECKED : BST_UNCHECKED); + CheckDlgButton(hDlg,IDC_CHECKFMSG,ActualAccount->BadConnectN.Flags & YAMN_ACC_MSG ? BST_CHECKED : BST_UNCHECKED); + CheckDlgButton(hDlg,IDC_CHECKFICO,ActualAccount->BadConnectN.Flags & YAMN_ACC_ICO ? BST_CHECKED : BST_UNCHECKED); + CheckDlgButton(hDlg,IDC_CHECKFPOP,ActualAccount->BadConnectN.Flags & YAMN_ACC_POP ? BST_CHECKED : BST_UNCHECKED); + CheckDlgButton(hDlg,IDC_CHECKFCOL,ActualAccount->BadConnectN.Flags & YAMN_ACC_POPC ? BST_CHECKED : BST_UNCHECKED); + CheckDlgButton(hDlg,IDC_RADIOPOPN,ActualAccount->Flags & YAMN_ACC_POPN ? BST_CHECKED : BST_UNCHECKED); + CheckDlgButton(hDlg,IDC_RADIOPOP1,ActualAccount->Flags & YAMN_ACC_POPN ? BST_UNCHECKED : BST_CHECKED); + CheckDlgButton(hDlg,IDC_CHECKSSL,ActualAccount->Flags & YAMN_ACC_SSL23 ? BST_CHECKED : BST_UNCHECKED); + CheckDlgButton(hDlg,IDC_CHECKNOTLS,ActualAccount->Flags & YAMN_ACC_NOTLS ? BST_CHECKED : BST_UNCHECKED); + CheckDlgButton(hDlg,IDC_CHECKAPOP,ActualAccount->Flags & YAMN_ACC_APOP ? BST_CHECKED : BST_UNCHECKED); + CheckDlgButton(hDlg,IDC_AUTOBODY,ActualAccount->Flags & YAMN_ACC_BODY ? BST_CHECKED : BST_UNCHECKED); + /*CheckDlgButton(hDlg,IDC_CHECKST0,ActualAccount->StatusFlags & YAMN_ACC_ST0 ? BST_CHECKED : BST_UNCHECKED); + CheckDlgButton(hDlg,IDC_CHECKST1,ActualAccount->StatusFlags & YAMN_ACC_ST1 ? BST_CHECKED : BST_UNCHECKED); + CheckDlgButton(hDlg,IDC_CHECKST2,ActualAccount->StatusFlags & YAMN_ACC_ST2 ? BST_CHECKED : BST_UNCHECKED); + CheckDlgButton(hDlg,IDC_CHECKST3,ActualAccount->StatusFlags & YAMN_ACC_ST3 ? BST_CHECKED : BST_UNCHECKED); + CheckDlgButton(hDlg,IDC_CHECKST4,ActualAccount->StatusFlags & YAMN_ACC_ST4 ? BST_CHECKED : BST_UNCHECKED); + CheckDlgButton(hDlg,IDC_CHECKST5,ActualAccount->StatusFlags & YAMN_ACC_ST5 ? BST_CHECKED : BST_UNCHECKED); + CheckDlgButton(hDlg,IDC_CHECKST6,ActualAccount->StatusFlags & YAMN_ACC_ST6 ? BST_CHECKED : BST_UNCHECKED); + CheckDlgButton(hDlg,IDC_CHECKST7,ActualAccount->StatusFlags & YAMN_ACC_ST7 ? BST_CHECKED : BST_UNCHECKED); + CheckDlgButton(hDlg,IDC_CHECKST8,ActualAccount->StatusFlags & YAMN_ACC_ST8 ? BST_CHECKED : BST_UNCHECKED); + CheckDlgButton(hDlg,IDC_CHECKST9,ActualAccount->StatusFlags & YAMN_ACC_ST9 ? BST_CHECKED : BST_UNCHECKED);*/ + Check0=ActualAccount->StatusFlags & YAMN_ACC_ST0; + Check1=ActualAccount->StatusFlags & YAMN_ACC_ST1; + Check2=ActualAccount->StatusFlags & YAMN_ACC_ST2; + Check3=ActualAccount->StatusFlags & YAMN_ACC_ST3; + Check4=ActualAccount->StatusFlags & YAMN_ACC_ST4; + Check5=ActualAccount->StatusFlags & YAMN_ACC_ST5; + Check6=ActualAccount->StatusFlags & YAMN_ACC_ST6; + Check7=ActualAccount->StatusFlags & YAMN_ACC_ST7; + Check8=ActualAccount->StatusFlags & YAMN_ACC_ST8; + Check9=ActualAccount->StatusFlags & YAMN_ACC_ST9; + CheckDlgButton(hDlg,IDC_CHECKSTART,ActualAccount->StatusFlags & YAMN_ACC_STARTS ? BST_CHECKED : BST_UNCHECKED); + CheckDlgButton(hDlg,IDC_CHECKFORCE,ActualAccount->StatusFlags & YAMN_ACC_FORCE ? BST_CHECKED : BST_UNCHECKED); + CheckDlgButton(hDlg,IDC_CHECKCONTACT,ActualAccount->NewMailN.Flags & YAMN_ACC_CONT ? BST_CHECKED : BST_UNCHECKED); + CheckDlgButton(hDlg,IDC_CHECKCONTACTNICK,ActualAccount->NewMailN.Flags & YAMN_ACC_CONTNICK ? BST_CHECKED : BST_UNCHECKED); + CheckDlgButton(hDlg,IDC_CHECKCONTACTNOEVENT,ActualAccount->NewMailN.Flags & YAMN_ACC_CONTNOEVENT ? BST_CHECKED : BST_UNCHECKED); +#ifdef DEBUG_SYNCHRO + DebugLog(SynchroFile,"Options:SHOWACCOUNT:ActualAccountSO-read done\n"); +#endif + GetAccountStatus(ActualAccount,accstatus); + SetDlgItemText(hDlg,IDC_STSTATUS,accstatus); + ReadDone(ActualAccount); + } + else //default + { + DlgSetItemText(hDlg,(WPARAM)IDC_EDITSERVER,(LPARAM)NULL); + DlgSetItemText(hDlg,(WPARAM)IDC_EDITNAME,(LPARAM)NULL); + DlgSetItemText(hDlg,(WPARAM)IDC_EDITLOGIN,(LPARAM)NULL); + DlgSetItemText(hDlg,(WPARAM)IDC_EDITPASS,(LPARAM)NULL); + DlgSetItemText(hDlg,(WPARAM)IDC_EDITAPP,(LPARAM)NULL); + DlgSetItemText(hDlg,(WPARAM)IDC_EDITAPPPARAM,(LPARAM)NULL); + DlgSetItemText(hDlg,(WPARAM)IDC_STTIMELEFT,(LPARAM)NULL); + SetDlgItemInt(hDlg,IDC_EDITPORT,110,FALSE); + SetDlgItemInt(hDlg,IDC_EDITINTERVAL,30,FALSE); + SetDlgItemInt(hDlg,IDC_EDITPOPS,0,FALSE); + SetDlgItemInt(hDlg,IDC_EDITNPOPS,0,FALSE); + SetDlgItemInt(hDlg,IDC_EDITFPOPS,0,FALSE); + SendMessage(GetDlgItem(hDlg,IDC_COMBOCP),CB_SETCURSEL,(WPARAM)CPDEFINDEX,(LPARAM)0); + CheckDlgButton(hDlg,IDC_CHECK,BST_CHECKED); + CheckDlgButton(hDlg,IDC_CHECKSND,BST_CHECKED); + CheckDlgButton(hDlg,IDC_CHECKMSG,BST_UNCHECKED); + CheckDlgButton(hDlg,IDC_CHECKICO,BST_UNCHECKED); + CheckDlgButton(hDlg,IDC_CHECKPOP,BST_CHECKED); + CheckDlgButton(hDlg,IDC_CHECKCOL,BST_CHECKED); + CheckDlgButton(hDlg,IDC_CHECKAPP,BST_UNCHECKED); + CheckDlgButton(hDlg,IDC_CHECKPOP,BST_CHECKED); + CheckDlgButton(hDlg,IDC_CHECKCOL,BST_CHECKED); + CheckDlgButton(hDlg,IDC_CHECKFSND,BST_UNCHECKED); + CheckDlgButton(hDlg,IDC_CHECKFMSG,BST_UNCHECKED); + CheckDlgButton(hDlg,IDC_CHECKFICO,BST_UNCHECKED); + CheckDlgButton(hDlg,IDC_CHECKFPOP,BST_CHECKED); + CheckDlgButton(hDlg,IDC_CHECKFCOL,BST_CHECKED); + /*CheckDlgButton(hDlg,IDC_CHECKST0,BST_UNCHECKED); + CheckDlgButton(hDlg,IDC_CHECKST1,BST_CHECKED); + CheckDlgButton(hDlg,IDC_CHECKST2,BST_UNCHECKED); + CheckDlgButton(hDlg,IDC_CHECKST3,BST_UNCHECKED); + CheckDlgButton(hDlg,IDC_CHECKST4,BST_UNCHECKED); + CheckDlgButton(hDlg,IDC_CHECKST5,BST_UNCHECKED); + CheckDlgButton(hDlg,IDC_CHECKST6,BST_UNCHECKED); + CheckDlgButton(hDlg,IDC_CHECKST7,BST_CHECKED); + CheckDlgButton(hDlg,IDC_CHECKST8,BST_CHECKED); + CheckDlgButton(hDlg,IDC_CHECKST9,BST_CHECKED);*/ + CheckDlgButton(hDlg,IDC_CHECKSTART,BST_CHECKED); + CheckDlgButton(hDlg,IDC_CHECKFORCE,BST_CHECKED); + CheckDlgButton(hDlg,IDC_RADIOPOPN,BST_UNCHECKED); + CheckDlgButton(hDlg,IDC_RADIOPOP1,BST_CHECKED); + CheckDlgButton(hDlg,IDC_CHECKSSL,BST_UNCHECKED); + CheckDlgButton(hDlg,IDC_CHECKNOTLS,BST_UNCHECKED); + CheckDlgButton(hDlg,IDC_CHECKAPOP,BST_UNCHECKED); + CheckDlgButton(hDlg,IDC_AUTOBODY,BST_UNCHECKED); + CheckDlgButton(hDlg,IDC_CHECKCONTACT,BST_CHECKED); + + SetDlgItemText(hDlg,IDC_STSTATUS,TranslateT("No account selected")); + } + return TRUE; +} + +BOOL DlgShowAccountColors(HWND hDlg,WPARAM wParam,LPARAM lParam) +{ + HPOP3ACCOUNT ActualAccount=(HPOP3ACCOUNT)lParam; +#ifdef DEBUG_SYNCHRO + DebugLog(SynchroFile,"Options:SHOWACCOUNTCOLORS:ActualAccountSO-read wait\n"); +#endif + WaitToRead(ActualAccount); //we do not need to check if account is deleted. It is not deleted, because only thread that can delete account is this thread +#ifdef DEBUG_SYNCHRO + DebugLog(SynchroFile,"Options:SHOWACCOUNTCOLORS:ActualAccountSO-read enter\n"); +#endif + if (ActualAccount->NewMailN.Flags & YAMN_ACC_POPC) + { + SendDlgItemMessage(hDlg,IDC_CPB,CPM_SETCOLOUR,0,(LPARAM)ActualAccount->NewMailN.PopUpB); + SendDlgItemMessage(hDlg,IDC_CPT,CPM_SETCOLOUR,0,(LPARAM)ActualAccount->NewMailN.PopUpT); + } + else + { + SendDlgItemMessage(hDlg,IDC_CPB,CPM_SETCOLOUR,0,(LPARAM)GetSysColor(COLOR_BTNFACE)); + SendDlgItemMessage(hDlg,IDC_CPT,CPM_SETCOLOUR,0,(LPARAM)GetSysColor(COLOR_WINDOWTEXT)); + } + if (ActualAccount->BadConnectN.Flags & YAMN_ACC_POPC) + { + SendDlgItemMessage(hDlg,IDC_CPFB,CPM_SETCOLOUR,0,(LPARAM)ActualAccount->BadConnectN.PopUpB); + SendDlgItemMessage(hDlg,IDC_CPFT,CPM_SETCOLOUR,0,(LPARAM)ActualAccount->BadConnectN.PopUpT); + } + else + { + SendDlgItemMessage(hDlg,IDC_CPFB,CPM_SETCOLOUR,0,(LPARAM)GetSysColor(COLOR_BTNFACE)); + SendDlgItemMessage(hDlg,IDC_CPFT,CPM_SETCOLOUR,0,(LPARAM)GetSysColor(COLOR_WINDOWTEXT)); + } + if (ActualAccount->NoNewMailN.Flags & YAMN_ACC_POPC) + { + SendDlgItemMessage(hDlg,IDC_CPNB,CPM_SETCOLOUR,0,(LPARAM)ActualAccount->NoNewMailN.PopUpB); + SendDlgItemMessage(hDlg,IDC_CPNT,CPM_SETCOLOUR,0,(LPARAM)ActualAccount->NoNewMailN.PopUpT); + } + else + { + SendDlgItemMessage(hDlg,IDC_CPNB,CPM_SETCOLOUR,0,(LPARAM)GetSysColor(COLOR_BTNFACE)); + SendDlgItemMessage(hDlg,IDC_CPNT,CPM_SETCOLOUR,0,(LPARAM)GetSysColor(COLOR_WINDOWTEXT)); + } +#ifdef DEBUG_SYNCHRO + DebugLog(SynchroFile,"Options:SHOWACCOUNTCOLORS:ActualAccountSO-read done\n"); +#endif + ReadDone(ActualAccount); //we do not need to check if account is deleted. It is not deleted, because only thread that can delete account is this thread + return TRUE; +} + +BOOL DlgSetItemText(HWND hDlg, WPARAM wParam,const char* str) +{ + if (str == NULL) + SetDlgItemTextA(hDlg, wParam, ""); + else + SetDlgItemTextA(hDlg, wParam, str); + return TRUE; +} + +BOOL DlgSetItemTextW(HWND hDlg,WPARAM wParam,const WCHAR* str) +{ + if (str == NULL) + SetDlgItemTextW(hDlg, wParam, L""); + else + SetDlgItemTextW(hDlg, wParam, str); + return TRUE; +} + +BOOL CALLBACK DlgProcPOP3AccStatusOpt(HWND hDlg,UINT msg,WPARAM wParam,LPARAM lParam) +{ + static HPOP3ACCOUNT ActualAccount; + switch(msg) + { + case WM_INITDIALOG: + { + ActualAccount=(HPOP3ACCOUNT)CallService(MS_YAMN_FINDACCOUNTBYNAME,(WPARAM)POP3Plugin,(LPARAM)DlgInput); + if (ActualAccount != NULL) + { + DlgShowAccountStatus(hDlg,(WPARAM)M_SHOWACTUAL,(LPARAM)ActualAccount); + DlgEnableAccountStatus(hDlg,(WPARAM)TRUE,(LPARAM)TRUE); + } + else + { + CheckDlgButton(hDlg,IDC_CHECKST0,BST_CHECKED); + CheckDlgButton(hDlg,IDC_CHECKST1,BST_CHECKED); + CheckDlgButton(hDlg,IDC_CHECKST2,BST_CHECKED); + CheckDlgButton(hDlg,IDC_CHECKST3,BST_CHECKED); + CheckDlgButton(hDlg,IDC_CHECKST4,BST_CHECKED); + CheckDlgButton(hDlg,IDC_CHECKST5,BST_CHECKED); + CheckDlgButton(hDlg,IDC_CHECKST6,BST_CHECKED); + CheckDlgButton(hDlg,IDC_CHECKST7,BST_CHECKED); + CheckDlgButton(hDlg,IDC_CHECKST8,BST_CHECKED); + CheckDlgButton(hDlg,IDC_CHECKST9,BST_CHECKED); + } + TranslateDialogDefault(hDlg); + SendMessage(GetParent(hDlg),PSM_UNCHANGED,(WPARAM)hDlg,0); + return TRUE; + break; + } + case WM_COMMAND: + { + + WORD wNotifyCode = HIWORD(wParam); + switch(LOWORD(wParam)) + { + case IDOK: + Check0 = (IsDlgButtonChecked(hDlg,IDC_CHECKST0)==BST_CHECKED); + Check1 = (IsDlgButtonChecked(hDlg,IDC_CHECKST1)==BST_CHECKED); + Check2 = (IsDlgButtonChecked(hDlg,IDC_CHECKST2)==BST_CHECKED); + Check3 = (IsDlgButtonChecked(hDlg,IDC_CHECKST3)==BST_CHECKED); + Check4 = (IsDlgButtonChecked(hDlg,IDC_CHECKST4)==BST_CHECKED); + Check5 = (IsDlgButtonChecked(hDlg,IDC_CHECKST5)==BST_CHECKED); + Check6 = (IsDlgButtonChecked(hDlg,IDC_CHECKST6)==BST_CHECKED); + Check7 = (IsDlgButtonChecked(hDlg,IDC_CHECKST7)==BST_CHECKED); + Check8 = (IsDlgButtonChecked(hDlg,IDC_CHECKST8)==BST_CHECKED); + Check9 = (IsDlgButtonChecked(hDlg,IDC_CHECKST9)==BST_CHECKED); + WindowList_BroadcastAsync(YAMNVar.MessageWnds,WM_YAMN_CHANGESTATUSOPTION,(WPARAM)0,(LPARAM)0); + EndDialog(hDlg,0); + DestroyWindow(hDlg); + break; + + case IDCANCEL: + EndDialog(hDlg,0); + DestroyWindow(hDlg); + break; + + default: + break; + } + } + default: + break; + } + return FALSE; +} + + +INT_PTR CALLBACK DlgProcPOP3AccOpt(HWND hDlg,UINT msg,WPARAM wParam,LPARAM lParam) +{ + BOOL Changed=FALSE; + INT_PTR Result; + static BOOL InList=FALSE; + static HPOP3ACCOUNT ActualAccount; + static UCHAR ActualStatus; +// static struct CPOP3Options POP3Options; + + switch(msg) + { + case WM_INITDIALOG: + { + int i; + + EnableWindow(GetDlgItem(hDlg,IDC_BTNDEL),FALSE); + + DlgEnableAccount(hDlg,(WPARAM)FALSE,(LPARAM)FALSE); + DlgShowAccount(hDlg,(WPARAM)M_SHOWDEFAULT,0); + + #ifdef DEBUG_SYNCHRO + DebugLog(SynchroFile,"Options:INITDIALOG:AccountBrowserSO-read wait\n"); + #endif + WaitToReadSO(POP3Plugin->AccountBrowserSO); + #ifdef DEBUG_SYNCHRO + DebugLog(SynchroFile,"Options:INITDIALOG:AccountBrowserSO-read enter\n"); + #endif + + for (ActualAccount=(HPOP3ACCOUNT)POP3Plugin->FirstAccount;ActualAccount!=NULL;ActualAccount=(HPOP3ACCOUNT)ActualAccount->Next) + if (ActualAccount->Name != NULL) + SendDlgItemMessageA(hDlg,IDC_COMBOACCOUNT,CB_ADDSTRING,0,(LPARAM)ActualAccount->Name); + + #ifdef DEBUG_SYNCHRO + DebugLog(SynchroFile,"Options:INITDIALOG:AccountBrowserSO-read done\n"); + #endif + ReadDoneSO(POP3Plugin->AccountBrowserSO); + SendDlgItemMessage(hDlg, IDC_COMBOCP, CB_ADDSTRING, 0, (LPARAM)TranslateT("Default")); + for (i=1; i < CPLENSUPP; i++) { + CPINFOEX info; GetCPInfoEx(CodePageNamesSupp[i].CP,0,&info); + size_t len = lstrlen(info.CodePageName+7); + info.CodePageName[len+6]=0; + SendDlgItemMessage(hDlg,IDC_COMBOCP,CB_ADDSTRING,0,(LPARAM)(info.CodePageName+7)); + } + + SendMessage(GetDlgItem(hDlg,IDC_COMBOCP),CB_SETCURSEL,(WPARAM)CPDEFINDEX,(LPARAM)0); + ActualAccount=NULL; + TranslateDialogDefault(hDlg); + SendMessage(GetParent(hDlg),PSM_UNCHANGED,(WPARAM)hDlg,0); + return TRUE; + } + + case WM_SHOWWINDOW: + if ( wParam == FALSE) { + WindowList_Remove(pYAMNVar->MessageWnds,hDlg); + SendMessage(GetParent(hDlg),PSM_UNCHANGED,(WPARAM)hDlg,(LPARAM)0); + } + else WindowList_Add(pYAMNVar->MessageWnds,hDlg,NULL); + return TRUE; + + case WM_YAMN_CHANGESTATUS: + if ((HPOP3ACCOUNT)wParam == ActualAccount) { + TCHAR accstatus[256]; + GetAccountStatus(ActualAccount,accstatus); + SetDlgItemText(hDlg,IDC_STSTATUS,accstatus); + return TRUE; + } + break; + + case WM_YAMN_CHANGESTATUSOPTION: + Changed=TRUE; + SendMessage(GetParent(hDlg),PSM_CHANGED,0,0); + return TRUE; + + case WM_YAMN_CHANGETIME: + if ((HPOP3ACCOUNT)wParam == ActualAccount) { + TCHAR Text[256]; + mir_sntprintf(Text,SIZEOF(Text),TranslateT("Time left to next check [s]: %d"),(DWORD)lParam); + SetDlgItemText(hDlg,IDC_STTIMELEFT,Text); + } + return TRUE; + + case WM_COMMAND: + switch(LOWORD(wParam)) { + case IDC_COMBOACCOUNT: + switch( HIWORD(wParam)) { + case CBN_EDITCHANGE : + ActualAccount=NULL; + DlgSetItemText(hDlg,(WPARAM)IDC_STTIMELEFT,(LPARAM)NULL); + + if (GetDlgItemTextA(hDlg,IDC_COMBOACCOUNT,DlgInput,sizeof(DlgInput))) + DlgEnableAccount(hDlg,(WPARAM)TRUE,(LPARAM)FALSE); + else + DlgEnableAccount(hDlg,(WPARAM)FALSE,(LPARAM)FALSE); + break; + + case CBN_KILLFOCUS: + GetDlgItemTextA(hDlg,IDC_COMBOACCOUNT,DlgInput,sizeof(DlgInput)); + if (NULL==(ActualAccount=(HPOP3ACCOUNT)CallService(MS_YAMN_FINDACCOUNTBYNAME,(WPARAM)POP3Plugin,(LPARAM)DlgInput))) { + DlgSetItemText(hDlg,(WPARAM)IDC_STTIMELEFT,(LPARAM)NULL); + EnableWindow(GetDlgItem(hDlg,IDC_BTNDEL),FALSE); + if (lstrlenA(DlgInput)) + DlgEnableAccount(hDlg,(WPARAM)TRUE,(LPARAM)TRUE); + else + DlgEnableAccount(hDlg,(WPARAM)FALSE,(LPARAM)FALSE); + } + else { + DlgShowAccount(hDlg,(WPARAM)M_SHOWACTUAL,(LPARAM)ActualAccount); + DlgEnableAccount(hDlg,(WPARAM)TRUE,(LPARAM)TRUE); + EnableWindow(GetDlgItem(hDlg,IDC_BTNDEL),TRUE); + } + break; + + case CBN_SELCHANGE: + if (CB_ERR!=(Result=SendDlgItemMessage(hDlg,IDC_COMBOACCOUNT,CB_GETCURSEL,0,0))) + SendDlgItemMessageA(hDlg,IDC_COMBOACCOUNT,CB_GETLBTEXT,(WPARAM)Result,(LPARAM)DlgInput); + + if ((Result==CB_ERR) || (NULL==(ActualAccount=(HPOP3ACCOUNT)CallService(MS_YAMN_FINDACCOUNTBYNAME,(WPARAM)POP3Plugin,(LPARAM)DlgInput)))) { + DlgSetItemText(hDlg,(WPARAM)IDC_STTIMELEFT,(LPARAM)NULL); + EnableWindow(GetDlgItem(hDlg,IDC_BTNDEL),FALSE); + } + else { + DlgShowAccount(hDlg,(WPARAM)M_SHOWACTUAL,(LPARAM)ActualAccount); + DlgEnableAccount(hDlg,(WPARAM)TRUE,(LPARAM)FALSE); + EnableWindow(GetDlgItem(hDlg,IDC_BTNDEL),TRUE); + } + break; + } + break; + + case IDC_COMBOCP: + { + int sel = SendDlgItemMessage(hDlg,IDC_COMBOCP,CB_GETCURSEL,0,0); + CPINFOEX info; GetCPInfoEx(CodePageNamesSupp[sel].CP,0,&info); + DlgSetItemTextT(hDlg, IDC_STSTATUS, info.CodePageName); + } + case IDC_CHECK: + case IDC_CHECKSND: + case IDC_CHECKMSG: + case IDC_CHECKICO: + case IDC_CHECKFSND: + case IDC_CHECKFMSG: + case IDC_CHECKFICO: + case IDC_CHECKST0: + case IDC_CHECKST1: + case IDC_CHECKST2: + case IDC_CHECKST3: + case IDC_CHECKST4: + case IDC_CHECKST5: + case IDC_CHECKST6: + case IDC_CHECKST7: + case IDC_CHECKST8: + case IDC_CHECKST9: + case IDC_CHECKSTART: + case IDC_CHECKFORCE: + case IDC_EDITAPPPARAM: + case IDC_CHECKAPOP: + case IDC_AUTOBODY: + case IDC_CHECKCONTACTNICK: + case IDC_CHECKCONTACTNOEVENT: + case IDC_CHECKNOTLS: + Changed=TRUE; + break; + + case IDC_CHECKCONTACT: + Changed=IsDlgButtonChecked(hDlg,IDC_CHECKCONTACT)==BST_CHECKED; + EnableWindow(GetDlgItem(hDlg,IDC_CHECKCONTACTNICK),Changed); + EnableWindow(GetDlgItem(hDlg,IDC_CHECKCONTACTNOEVENT),Changed); + Changed=TRUE; + break; + + case IDC_CHECKSSL: + { + BOOL SSLC = (IsDlgButtonChecked(hDlg,IDC_CHECKSSL)==BST_CHECKED); + SetDlgItemInt(hDlg,IDC_EDITPORT,SSLC ? 995 : 110,FALSE); + EnableWindow(GetDlgItem(hDlg,IDC_CHECKNOTLS),SSLC?0:1); + } + Changed=TRUE; + break; + + case IDC_CPB: + case IDC_CPT: + case IDC_CPFB: + case IDC_CPFT: + case IDC_CPNB: + case IDC_CPNT: + if (HIWORD(wParam)!=CPN_COLOURCHANGED) + break; + + case IDC_CHECKKBN: + Changed=TRUE; + break; + + case IDC_CHECKAPP: + Changed=TRUE; + EnableWindow(GetDlgItem(hDlg,IDC_BTNAPP),IsDlgButtonChecked(hDlg,IDC_CHECKAPP)==BST_CHECKED); + EnableWindow(GetDlgItem(hDlg,IDC_EDITAPP),IsDlgButtonChecked(hDlg,IDC_CHECKAPP)==BST_CHECKED); + EnableWindow(GetDlgItem(hDlg,IDC_EDITAPPPARAM),IsDlgButtonChecked(hDlg,IDC_CHECKAPP)==BST_CHECKED); + break; + + case IDC_BTNSTATUS: + DialogBoxParamW(pYAMNVar->hInst,MAKEINTRESOURCEW(IDD_CHOOSESTATUSMODES),hDlg,(DLGPROC)DlgProcPOP3AccStatusOpt,(LPARAM)NULL); + break; + + case IDC_BTNADD: + DlgSetItemText(hDlg,(WPARAM)IDC_STTIMELEFT,(LPARAM)NULL); + DlgShowAccount(hDlg,(WPARAM)M_SHOWDEFAULT,0); + DlgEnableAccount(hDlg,(WPARAM)TRUE,(LPARAM)TRUE); + EnableWindow(GetDlgItem(hDlg,IDC_BTNDEL),FALSE); + DlgSetItemTextT(hDlg, IDC_EDITNAME, TranslateT("New Account")); + { + int index = SendDlgItemMessage(hDlg, IDC_COMBOACCOUNT, CB_ADDSTRING, 0, (LPARAM)TranslateT("New Account")); + if ( index != CB_ERR && index != CB_ERRSPACE ) + SendDlgItemMessage(hDlg, IDC_COMBOACCOUNT, CB_SETCURSEL, index, (LPARAM)TranslateT("New Account")); + } + break; + + case IDC_BTNAPP: + { + TCHAR filter[MAX_PATH]; + mir_sntprintf(filter, SIZEOF(filter), _T("%s (*.exe;*.bat;*.cmd;*.com)%c*.exe;*.bat;*.cmd;*.com%c%s (*.*)%c*.*%c"), + TranslateT("Executables"), 0, 0, TranslateT("All Files"), 0, 0); + + OPENFILENAME OFNStruct = { 0 }; + OFNStruct.lStructSize = sizeof(OPENFILENAME); + OFNStruct.hwndOwner = hDlg; + OFNStruct.lpstrFilter= filter; + OFNStruct.nFilterIndex=1; + OFNStruct.nMaxFile=MAX_PATH; + OFNStruct.lpstrFile=new TCHAR[MAX_PATH]; + OFNStruct.lpstrFile[0]=(TCHAR)0; + OFNStruct.lpstrTitle=TranslateT("Select executable used for notification"); + OFNStruct.Flags=OFN_FILEMUSTEXIST | OFN_NONETWORKBUTTON | OFN_PATHMUSTEXIST | OFN_NOCHANGEDIR; + if (!GetOpenFileName(&OFNStruct)) + { + if (CommDlgExtendedError()) + MessageBox(hDlg,_T("Dialog box error"),_T("Failed"),MB_OK); + } + else DlgSetItemTextT(hDlg, IDC_EDITAPP, OFNStruct.lpstrFile); + delete[] OFNStruct.lpstrFile; + } + break; + + case IDC_BTNDEFAULT: + DlgShowAccount(hDlg,(WPARAM)M_SHOWDEFAULT,0); + break; + + case IDC_BTNDEL: + GetDlgItemTextA(hDlg,IDC_COMBOACCOUNT,DlgInput,sizeof(DlgInput)); + EnableWindow(GetDlgItem(hDlg,IDC_BTNDEL),FALSE); + if ((CB_ERR==(Result=SendDlgItemMessage(hDlg,IDC_COMBOACCOUNT,CB_GETCURSEL,0,0))) + || (NULL==(ActualAccount=(HPOP3ACCOUNT)CallService(MS_YAMN_FINDACCOUNTBYNAME,(WPARAM)POP3Plugin,(LPARAM)DlgInput)))) + return TRUE; + + if (IDOK!=MessageBox(hDlg,TranslateT("Do you really want to delete this account?"),TranslateT("Delete account confirmation"),MB_OKCANCEL | MB_ICONWARNING)) + return TRUE; + + DlgSetItemTextT(hDlg, IDC_STTIMELEFT, TranslateT("Please wait while no account is in use.")); + + if (ActualAccount->hContact != NULL) + CallService(MS_DB_CONTACT_DELETE,(WPARAM)(HANDLE) ActualAccount->hContact, 0); + + CallService(MS_YAMN_DELETEACCOUNT,(WPARAM)POP3Plugin,(LPARAM)ActualAccount); + + //We can consider our account as deleted. + + SendDlgItemMessage(hDlg,IDC_COMBOACCOUNT,CB_DELETESTRING,(WPARAM)Result,0); + DlgSetItemText(hDlg,(WPARAM)IDC_COMBOACCOUNT,(LPARAM)NULL); + DlgEnableAccount(hDlg,(WPARAM)FALSE,0); + DlgShowAccount(hDlg,(WPARAM)M_SHOWDEFAULT,0); + break; + + case IDC_BTNRESET: + if (ActualAccount != NULL) + ActualAccount->TimeLeft=ActualAccount->Interval; + return 1; + } + + if (HIWORD(wParam) == EN_CHANGE) + Changed = TRUE; + break; + + case WM_NOTIFY: + if (((LPNMHDR)lParam)->idFrom == 0 && ((LPNMHDR)lParam)->code == PSN_APPLY ) { + char Text[MAX_PATH]; + WCHAR TextW[MAX_PATH]; + BOOL Translated,NewAcc=FALSE,Check,CheckMsg,CheckSnd,CheckIco,CheckApp, CheckAPOP; + BOOL CheckNMsgP,CheckFMsg,CheckFSnd,CheckFIco; + BOOL CheckKBN, CheckContact,CheckContactNick,CheckContactNoEvent; + BOOL CheckSSL, CheckABody, CheckNoTLS; + //BOOL Check0,Check1,Check2,Check3,Check4,Check5,Check6,Check7,Check8,Check9, + BOOL CheckStart,CheckForce; + size_t Length,index; + UINT Port,Interval; + + if ( GetDlgItemTextA(hDlg,IDC_COMBOACCOUNT, Text, sizeof(Text))) { + Check = (IsDlgButtonChecked(hDlg,IDC_CHECK)==BST_CHECKED); + CheckSSL = (IsDlgButtonChecked(hDlg,IDC_CHECKSSL)==BST_CHECKED); + CheckNoTLS = (IsDlgButtonChecked(hDlg,IDC_CHECKNOTLS)==BST_CHECKED); + CheckAPOP = (IsDlgButtonChecked(hDlg,IDC_CHECKAPOP)==BST_CHECKED); + + CheckABody = (IsDlgButtonChecked(hDlg,IDC_AUTOBODY)==BST_CHECKED); + CheckMsg = (IsDlgButtonChecked(hDlg,IDC_CHECKMSG)==BST_CHECKED); + CheckSnd = (IsDlgButtonChecked(hDlg,IDC_CHECKSND)==BST_CHECKED); + CheckIco = (IsDlgButtonChecked(hDlg,IDC_CHECKICO)==BST_CHECKED); + + CheckApp = (IsDlgButtonChecked(hDlg,IDC_CHECKAPP)==BST_CHECKED); + CheckKBN = (IsDlgButtonChecked(hDlg,IDC_CHECKKBN)==BST_CHECKED); + CheckContact = (IsDlgButtonChecked(hDlg,IDC_CHECKCONTACT)==BST_CHECKED); + CheckContactNick = (IsDlgButtonChecked(hDlg,IDC_CHECKCONTACTNICK)==BST_CHECKED); + CheckContactNoEvent = (IsDlgButtonChecked(hDlg,IDC_CHECKCONTACTNOEVENT)==BST_CHECKED); + + CheckFSnd = (IsDlgButtonChecked(hDlg,IDC_CHECKFSND)==BST_CHECKED); + CheckFMsg = (IsDlgButtonChecked(hDlg,IDC_CHECKFMSG)==BST_CHECKED); + CheckFIco = (IsDlgButtonChecked(hDlg,IDC_CHECKFICO)==BST_CHECKED); + + CheckNMsgP = (IsDlgButtonChecked(hDlg,IDC_CHECKNMSGP)==BST_CHECKED); + + Port = GetDlgItemInt(hDlg, IDC_EDITPORT, &Translated, FALSE); + if ( !Translated ) { + MessageBox(hDlg,TranslateT("This is not a valid number value"),TranslateT("Input error"),MB_OK); + SetFocus(GetDlgItem(hDlg,IDC_EDITPORT)); + break; + } + Interval = GetDlgItemInt(hDlg,IDC_EDITINTERVAL,&Translated,FALSE); + if ( !Translated ) { + MessageBox(hDlg,TranslateT("This is not a valid number value"),TranslateT("Input error"),MB_OK); + SetFocus(GetDlgItem(hDlg,IDC_EDITINTERVAL)); + break; + } + + GetDlgItemTextA(hDlg, IDC_EDITAPP, Text, sizeof(Text)); + if (CheckApp && !(Length = strlen(Text))) { + MessageBox(hDlg,TranslateT("Please select application to run"),TranslateT("Input error"),MB_OK); + break; + } + + GetDlgItemTextA(hDlg, IDC_COMBOACCOUNT, Text, sizeof(Text)); + if ( !( Length = strlen(Text))) { + GetDlgItemTextA(hDlg,IDC_EDITNAME, Text, sizeof(Text)); + if ( !(Length = strlen( Text ))) + break; + } + + DlgSetItemTextT(hDlg, IDC_STTIMELEFT, TranslateT("Please wait while no account is in use.")); + + if (NULL==(ActualAccount=(HPOP3ACCOUNT)CallService(MS_YAMN_FINDACCOUNTBYNAME,(WPARAM)POP3Plugin,(LPARAM)Text))) { + NewAcc=TRUE; + #ifdef DEBUG_SYNCHRO + DebugLog(SynchroFile,"Options:APPLY:AccountBrowserSO-write wait\n"); + #endif + WaitToWriteSO(POP3Plugin->AccountBrowserSO); + #ifdef DEBUG_SYNCHRO + DebugLog(SynchroFile,"Options:APPLY:AccountBrowserSO-write enter\n"); + #endif + if (NULL==(ActualAccount=(HPOP3ACCOUNT)CallService(MS_YAMN_GETNEXTFREEACCOUNT,(WPARAM)POP3Plugin,(LPARAM)YAMN_ACCOUNTVERSION))) { + #ifdef DEBUG_SYNCHRO + DebugLog(SynchroFile,"Options:APPLY:AccountBrowserSO-write done\n"); + #endif + WriteDoneSO(POP3Plugin->AccountBrowserSO); + MessageBox(hDlg,TranslateT("Cannot allocate memory space for new account"),TranslateT("Memory error"),MB_OK); + break; + } + } + else { + #ifdef DEBUG_SYNCHRO + DebugLog(SynchroFile,"Options:APPLY:AccountBrowserSO-write wait\n"); + #endif + //We have to get full access to AccountBrowser, so other iterating thrads cannot get new account until new account is right set + WaitToWriteSO(POP3Plugin->AccountBrowserSO); + #ifdef DEBUG_SYNCHRO + DebugLog(SynchroFile,"Options:APPLY:AccountBrowserSO-write enter\n"); + #endif + } + #ifdef DEBUG_SYNCHRO + DebugLog(SynchroFile,"Options:APPLY:ActualAccountSO-write wait\n"); + #endif + if (WAIT_OBJECT_0!=WaitToWrite(ActualAccount)) + { + #ifdef DEBUG_SYNCHRO + DebugLog(SynchroFile,"Options:APPLY:ActualAccountSO-write wait failed\n"); + #endif + #ifdef DEBUG_SYNCHRO + DebugLog(SynchroFile,"Options:APPLY:ActualBrowserSO-write done\n"); + #endif + WriteDoneSO(POP3Plugin->AccountBrowserSO); + + } + #ifdef DEBUG_SYNCHRO + DebugLog(SynchroFile,"Options:APPLY:ActualAccountSO-write enter\n"); + #endif + + GetDlgItemTextA(hDlg, IDC_EDITNAME, Text, sizeof(Text)); + if ( !(Length = strlen( Text ))) + break; + if (NULL != ActualAccount->Name) + delete[] ActualAccount->Name; + ActualAccount->Name = new char[ strlen(Text)+1]; + strcpy(ActualAccount->Name,Text); + + GetDlgItemTextA(hDlg,IDC_EDITSERVER,Text,sizeof(Text)); + if (NULL!=ActualAccount->Server->Name) + delete[] ActualAccount->Server->Name; + ActualAccount->Server->Name=new char[ strlen(Text)+1]; + strcpy(ActualAccount->Server->Name,Text); + + GetDlgItemTextA(hDlg,IDC_EDITLOGIN,Text,sizeof(Text)); + if (NULL!=ActualAccount->Server->Login) + delete[] ActualAccount->Server->Login; + ActualAccount->Server->Login=new char[ strlen(Text)+1]; + strcpy(ActualAccount->Server->Login,Text); + + GetDlgItemTextA(hDlg,IDC_EDITPASS,Text,sizeof(Text)); + if (NULL!=ActualAccount->Server->Passwd) + delete[] ActualAccount->Server->Passwd; + ActualAccount->Server->Passwd=new char[ strlen(Text)+1]; + strcpy(ActualAccount->Server->Passwd,Text); + + GetDlgItemTextW(hDlg,IDC_EDITAPP,TextW,SIZEOF(TextW)); + if (NULL!=ActualAccount->NewMailN.App) + delete[] ActualAccount->NewMailN.App; + ActualAccount->NewMailN.App=new WCHAR[wcslen(TextW)+1]; + wcscpy(ActualAccount->NewMailN.App,TextW); + + GetDlgItemTextW(hDlg,IDC_EDITAPPPARAM,TextW,SIZEOF(TextW)); + if (NULL!=ActualAccount->NewMailN.AppParam) + delete[] ActualAccount->NewMailN.AppParam; + ActualAccount->NewMailN.AppParam=new WCHAR[wcslen(TextW)+1]; + wcscpy(ActualAccount->NewMailN.AppParam,TextW); + + ActualAccount->Server->Port=Port; + ActualAccount->Interval=Interval*60; + + if (CB_ERR==(index=SendDlgItemMessage(hDlg,IDC_COMBOCP,CB_GETCURSEL,0,0))) + index = CPDEFINDEX; + ActualAccount->CP = CodePageNamesSupp[index].CP; + + if (NewAcc) + ActualAccount->TimeLeft=Interval*60; + + CheckStart = (IsDlgButtonChecked(hDlg,IDC_CHECKSTART)==BST_CHECKED); + CheckForce = (IsDlgButtonChecked(hDlg,IDC_CHECKFORCE)==BST_CHECKED); + + ActualAccount->Flags= + (Check ? YAMN_ACC_ENA : 0) | + (CheckSSL ? YAMN_ACC_SSL23 : 0) | + (CheckNoTLS ? YAMN_ACC_NOTLS : 0) | + (CheckAPOP ? YAMN_ACC_APOP : 0) | + (CheckABody ? YAMN_ACC_BODY : 0) | + (ActualAccount->Flags & YAMN_ACC_POPN); + + ActualAccount->StatusFlags= + (Check0 ? YAMN_ACC_ST0 : 0) | + (Check1 ? YAMN_ACC_ST1 : 0) | + (Check2 ? YAMN_ACC_ST2 : 0) | + (Check3 ? YAMN_ACC_ST3 : 0) | + (Check4 ? YAMN_ACC_ST4 : 0) | + (Check5 ? YAMN_ACC_ST5 : 0) | + (Check6 ? YAMN_ACC_ST6 : 0) | + (Check7 ? YAMN_ACC_ST7 : 0) | + (Check8 ? YAMN_ACC_ST8 : 0) | + (Check9 ? YAMN_ACC_ST9 : 0) | + (CheckStart ? YAMN_ACC_STARTS : 0) | + (CheckForce ? YAMN_ACC_FORCE : 0); + + ActualAccount->NewMailN.Flags= + (CheckSnd ? YAMN_ACC_SND : 0) | + (CheckMsg ? YAMN_ACC_MSG : 0) | + (CheckIco ? YAMN_ACC_ICO : 0) | + (ActualAccount->NewMailN.Flags & YAMN_ACC_POP) | + (ActualAccount->NewMailN.Flags & YAMN_ACC_POPC) | + (CheckApp ? YAMN_ACC_APP : 0) | + (CheckKBN ? YAMN_ACC_KBN : 0) | + (CheckContact ? YAMN_ACC_CONT : 0) | + (CheckContactNick ? YAMN_ACC_CONTNICK : 0) | + (CheckContactNoEvent ? YAMN_ACC_CONTNOEVENT : 0) | + YAMN_ACC_MSGP; //this is default: when new mail arrives and window was displayed, leave it displayed. + + ActualAccount->NoNewMailN.Flags= + (ActualAccount->NoNewMailN.Flags & YAMN_ACC_POP) | + (ActualAccount->NoNewMailN.Flags & YAMN_ACC_POPC) | + (CheckNMsgP ? YAMN_ACC_MSGP : 0); + + ActualAccount->BadConnectN.Flags= + (CheckFSnd ? YAMN_ACC_SND : 0) | + (CheckFMsg ? YAMN_ACC_MSG : 0) | + (CheckFIco ? YAMN_ACC_ICO : 0) | + (ActualAccount->BadConnectN.Flags & YAMN_ACC_POP) | + (ActualAccount->BadConnectN.Flags & YAMN_ACC_POPC); + + #ifdef DEBUG_SYNCHRO + DebugLog(SynchroFile,"Options:APPLY:ActualAccountSO-write done\n"); + #endif + WriteDone(ActualAccount); + #ifdef DEBUG_SYNCHRO + DebugLog(SynchroFile,"Options:APPLY:AccountBrowserSO-write done\n"); + #endif + WriteDoneSO(POP3Plugin->AccountBrowserSO); + + EnableWindow(GetDlgItem(hDlg,IDC_BTNDEL),TRUE); + + DlgSetItemText(hDlg,(WPARAM)IDC_STTIMELEFT,(LPARAM)NULL); + + index = SendDlgItemMessage(hDlg,IDC_COMBOACCOUNT,CB_GETCURSEL,(WPARAM)0,(LPARAM)0); + + HPOP3ACCOUNT temp = ActualAccount; + + SendDlgItemMessage(hDlg,IDC_COMBOACCOUNT,CB_RESETCONTENT,0,(LPARAM)0); + if (POP3Plugin->FirstAccount!=NULL) + for (ActualAccount=(HPOP3ACCOUNT)POP3Plugin->FirstAccount;ActualAccount!=NULL;ActualAccount=(HPOP3ACCOUNT)ActualAccount->Next) + if (ActualAccount->Name!=NULL) + SendDlgItemMessageA(hDlg,IDC_COMBOACCOUNT,CB_ADDSTRING,0,(LPARAM)ActualAccount->Name); + + ActualAccount = temp; + SendDlgItemMessage(hDlg,IDC_COMBOACCOUNT,CB_SETCURSEL,(WPARAM)index,(LPARAM)ActualAccount->Name); + + WritePOP3Accounts(); + RefreshContact(); + return TRUE; + } + } + break; + } + if (Changed) + SendMessage(GetParent(hDlg),PSM_CHANGED,0,0); + return FALSE; +} + +INT_PTR CALLBACK DlgProcPOP3AccPopup(HWND hDlg,UINT msg,WPARAM wParam,LPARAM lParam) +{ + BOOL Changed=FALSE; + static BOOL InList=FALSE; + static HPOP3ACCOUNT ActualAccount; + static UCHAR ActualStatus; +// static struct CPOP3Options POP3Options; + + switch(msg) + { + case WM_INITDIALOG: + { + DlgEnableAccountPopup(hDlg,(WPARAM)FALSE,(LPARAM)FALSE); + DlgShowAccountPopup(hDlg,(WPARAM)M_SHOWDEFAULT,0); + //DlgShowAccountColors(hDlg,0,(LPARAM)ActualAccount); + #ifdef DEBUG_SYNCHRO + DebugLog(SynchroFile,"Options:INITDIALOG:AccountBrowserSO-read wait\n"); + #endif + WaitToReadSO(POP3Plugin->AccountBrowserSO); + #ifdef DEBUG_SYNCHRO + DebugLog(SynchroFile,"Options:INITDIALOG:AccountBrowserSO-read enter\n"); + #endif + if (POP3Plugin->FirstAccount!=NULL) + for (ActualAccount=(HPOP3ACCOUNT)POP3Plugin->FirstAccount;ActualAccount!=NULL;ActualAccount=(HPOP3ACCOUNT)ActualAccount->Next) + if (ActualAccount->Name!=NULL) + SendDlgItemMessageA(hDlg,IDC_COMBOACCOUNT,CB_ADDSTRING,0,(LPARAM)ActualAccount->Name); + #ifdef DEBUG_SYNCHRO + DebugLog(SynchroFile,"Options:INITDIALOG:AccountBrowserSO-read done\n"); + #endif + ReadDoneSO(POP3Plugin->AccountBrowserSO); + ActualAccount=NULL; + + + TranslateDialogDefault(hDlg); + SendMessage(GetParent(hDlg),PSM_UNCHANGED,(WPARAM)hDlg,0); + return TRUE; + } + + case WM_SHOWWINDOW: + if ((BOOL)wParam==FALSE) + { + WindowList_Remove(pYAMNVar->MessageWnds,hDlg); + SendMessage(GetParent(hDlg),PSM_UNCHANGED,(WPARAM)hDlg,(LPARAM)0); + } + else + { + WindowList_Add(pYAMNVar->MessageWnds,hDlg,NULL); + + int index = SendDlgItemMessage(hDlg,IDC_COMBOACCOUNT,CB_GETCURSEL,(WPARAM)0,(LPARAM)0); + HPOP3ACCOUNT temp = ActualAccount; + SendDlgItemMessage(hDlg,IDC_COMBOACCOUNT,CB_RESETCONTENT,0,(LPARAM)0); + + if (POP3Plugin->FirstAccount!=NULL) + for (ActualAccount=(HPOP3ACCOUNT)POP3Plugin->FirstAccount;ActualAccount!=NULL;ActualAccount=(HPOP3ACCOUNT)ActualAccount->Next) + if (ActualAccount->Name!=NULL) + SendDlgItemMessageA(hDlg,IDC_COMBOACCOUNT,CB_ADDSTRING,0,(LPARAM)ActualAccount->Name); + + ActualAccount = temp; + + if (ActualAccount != NULL) + { + SendDlgItemMessage(hDlg,IDC_COMBOACCOUNT,CB_SETCURSEL,(WPARAM)index,(LPARAM)ActualAccount->Name); + DlgShowAccount(hDlg,(WPARAM)M_SHOWACTUAL,(LPARAM)ActualAccount); + DlgShowAccountColors(hDlg,0,(LPARAM)ActualAccount); + DlgEnableAccountPopup(hDlg,(WPARAM)TRUE,(LPARAM)FALSE); + } + else + { + DlgShowAccountPopup(hDlg,(WPARAM)M_SHOWDEFAULT,0); + DlgEnableAccountPopup(hDlg,(WPARAM)FALSE,(LPARAM)FALSE); + } + + } + return TRUE; + + case WM_COMMAND: + { + WORD wNotifyCode = HIWORD(wParam); + switch(LOWORD(wParam)) + { + LONG Result; + case IDC_COMBOACCOUNT: + switch(wNotifyCode) + { + + case CBN_KILLFOCUS: + GetDlgItemTextA(hDlg,IDC_COMBOACCOUNT,DlgInput,sizeof(DlgInput)); + if (NULL==(ActualAccount=(HPOP3ACCOUNT)CallService(MS_YAMN_FINDACCOUNTBYNAME,(WPARAM)POP3Plugin,(LPARAM)DlgInput))) + { + DlgSetItemText(hDlg,(WPARAM)IDC_STTIMELEFT,(LPARAM)NULL); + if (lstrlenA(DlgInput)) + DlgEnableAccountPopup(hDlg,(WPARAM)TRUE,(LPARAM)TRUE); + else + DlgEnableAccountPopup(hDlg,(WPARAM)FALSE,(LPARAM)FALSE); + } + else + { + DlgShowAccount(hDlg,(WPARAM)M_SHOWACTUAL,(LPARAM)ActualAccount); + DlgShowAccountColors(hDlg,0,(LPARAM)ActualAccount); + DlgEnableAccountPopup(hDlg,(WPARAM)TRUE,(LPARAM)TRUE); + } + break; + case CBN_SELCHANGE: + if (CB_ERR!=(Result=SendDlgItemMessage(hDlg,IDC_COMBOACCOUNT,CB_GETCURSEL,0,0))) + SendDlgItemMessageA(hDlg,IDC_COMBOACCOUNT,CB_GETLBTEXT,(WPARAM)Result,(LPARAM)DlgInput); + if ((Result==CB_ERR) || (NULL==(ActualAccount=(HPOP3ACCOUNT)CallService(MS_YAMN_FINDACCOUNTBYNAME,(WPARAM)POP3Plugin,(LPARAM)DlgInput)))) + { + DlgSetItemText(hDlg,(WPARAM)IDC_STTIMELEFT,(LPARAM)NULL); + } + else + { + DlgShowAccount(hDlg,(WPARAM)M_SHOWACTUAL,(LPARAM)ActualAccount); + DlgShowAccountColors(hDlg,0,(LPARAM)ActualAccount); + DlgEnableAccountPopup(hDlg,(WPARAM)TRUE,(LPARAM)FALSE); + } + break; + } + break; + case IDC_COMBOCP: + { + int sel = SendDlgItemMessage(hDlg,IDC_COMBOCP,CB_GETCURSEL,0,0); + CPINFOEX info; GetCPInfoEx(CodePageNamesSupp[sel].CP,0,&info); + DlgSetItemTextT(hDlg, IDC_STSTATUS, info.CodePageName); + } + case IDC_RADIOPOPN: + case IDC_RADIOPOP1: + Changed=TRUE; + break; + case IDC_CPB: + case IDC_CPT: + case IDC_CPFB: + case IDC_CPFT: + case IDC_CPNB: + case IDC_CPNT: + if (HIWORD(wParam)!=CPN_COLOURCHANGED) + break; + case IDC_CHECKCOL: + case IDC_CHECKFCOL: + case IDC_CHECKNCOL: + EnableWindow(GetDlgItem(hDlg,IDC_CPB),(IsDlgButtonChecked(hDlg,IDC_CHECKCOL)==BST_CHECKED) && (IsDlgButtonChecked(hDlg,IDC_CHECKPOP)==BST_CHECKED) && wParam); + EnableWindow(GetDlgItem(hDlg,IDC_CPT),(IsDlgButtonChecked(hDlg,IDC_CHECKCOL)==BST_CHECKED) && (IsDlgButtonChecked(hDlg,IDC_CHECKPOP)==BST_CHECKED) && wParam); + EnableWindow(GetDlgItem(hDlg,IDC_CPNB),(IsDlgButtonChecked(hDlg,IDC_CHECKNCOL)==BST_CHECKED) && (IsDlgButtonChecked(hDlg,IDC_CHECKNPOP)==BST_CHECKED) && wParam); + EnableWindow(GetDlgItem(hDlg,IDC_CPNT),(IsDlgButtonChecked(hDlg,IDC_CHECKNCOL)==BST_CHECKED) && (IsDlgButtonChecked(hDlg,IDC_CHECKNPOP)==BST_CHECKED) && wParam); + EnableWindow(GetDlgItem(hDlg,IDC_CPFB),(IsDlgButtonChecked(hDlg,IDC_CHECKFCOL)==BST_CHECKED) && (IsDlgButtonChecked(hDlg,IDC_CHECKFPOP)==BST_CHECKED) && wParam); + EnableWindow(GetDlgItem(hDlg,IDC_CPFT),(IsDlgButtonChecked(hDlg,IDC_CHECKFCOL)==BST_CHECKED) && (IsDlgButtonChecked(hDlg,IDC_CHECKFPOP)==BST_CHECKED) && wParam); + Changed=TRUE; + break; + + case IDC_PREVIEW: + { + POPUPDATAT Tester; + POPUPDATAT TesterF; + POPUPDATAT TesterN; + BOOL TesterC = (IsDlgButtonChecked(hDlg,IDC_CHECKCOL)==BST_CHECKED); + BOOL TesterFC = (IsDlgButtonChecked(hDlg,IDC_CHECKFCOL)==BST_CHECKED); + BOOL TesterNC = (IsDlgButtonChecked(hDlg,IDC_CHECKNCOL)==BST_CHECKED); + + ZeroMemory(&Tester,sizeof(Tester)); + ZeroMemory(&TesterF,sizeof(TesterF)); + ZeroMemory(&TesterF,sizeof(TesterN)); + Tester.lchContact=NULL; + TesterF.lchContact=NULL; + TesterN.lchContact=NULL; + Tester.lchIcon=g_LoadIconEx(2); + TesterF.lchIcon=g_LoadIconEx(3); + TesterN.lchIcon=g_LoadIconEx(1); + + lstrcpy(Tester.lptzContactName,TranslateT("Account Test")); + lstrcpy(TesterF.lptzContactName,TranslateT("Account Test (failed)")); + lstrcpy(TesterN.lptzContactName,TranslateT("Account Test")); + lstrcpy(Tester.lptzText,TranslateT("You have N new mail messages")); + lstrcpy(TesterF.lptzText,TranslateT("Connection failed message")); + lstrcpy(TesterN.lptzText,TranslateT("No new mail message")); + if (TesterC) + { + Tester.colorBack=SendDlgItemMessage(hDlg,IDC_CPB,CPM_GETCOLOUR,0,0); + Tester.colorText=SendDlgItemMessage(hDlg,IDC_CPT,CPM_GETCOLOUR,0,0); + } + else + { + Tester.colorBack=GetSysColor(COLOR_BTNFACE); + Tester.colorText=GetSysColor(COLOR_WINDOWTEXT); + } + if (TesterFC) + { + TesterF.colorBack=SendDlgItemMessage(hDlg,IDC_CPFB,CPM_GETCOLOUR,0,0); + TesterF.colorText=SendDlgItemMessage(hDlg,IDC_CPFT,CPM_GETCOLOUR,0,0); + } + else + { + TesterF.colorBack=GetSysColor(COLOR_BTNFACE); + TesterF.colorText=GetSysColor(COLOR_WINDOWTEXT); + } + if (TesterNC) + { + TesterN.colorBack=SendDlgItemMessage(hDlg,IDC_CPNB,CPM_GETCOLOUR,0,0); + TesterN.colorText=SendDlgItemMessage(hDlg,IDC_CPNT,CPM_GETCOLOUR,0,0); + } + else + { + TesterN.colorBack=GetSysColor(COLOR_BTNFACE); + TesterN.colorText=GetSysColor(COLOR_WINDOWTEXT); + } + Tester.PluginWindowProc=(WNDPROC)NULL; + TesterF.PluginWindowProc=(WNDPROC)NULL; + TesterN.PluginWindowProc=(WNDPROC)NULL; + Tester.PluginData=NULL; + TesterF.PluginData=NULL; + TesterN.PluginData=NULL; + + if (IsDlgButtonChecked(hDlg,IDC_CHECKPOP)==BST_CHECKED) + CallService(MS_POPUP_ADDPOPUP,(WPARAM)&Tester,0); + if (IsDlgButtonChecked(hDlg,IDC_CHECKFPOP)==BST_CHECKED) + CallService(MS_POPUP_ADDPOPUP,(WPARAM)&TesterF,0); + if (IsDlgButtonChecked(hDlg,IDC_CHECKNPOP)==BST_CHECKED) + CallService(MS_POPUP_ADDPOPUP,(WPARAM)&TesterN,0); + Changed=TRUE; + } + break; + case IDC_CHECKKBN: + Changed=TRUE; + break; + case IDC_CHECKPOP: + Changed=TRUE; + EnableWindow(GetDlgItem(hDlg,IDC_CHECKCOL),IsDlgButtonChecked(hDlg,IDC_CHECKPOP)==BST_CHECKED); + EnableWindow(GetDlgItem(hDlg,IDC_CPB),(IsDlgButtonChecked(hDlg,IDC_CHECKCOL)==BST_CHECKED) && IsDlgButtonChecked(hDlg,IDC_CHECKPOP)==BST_CHECKED); + EnableWindow(GetDlgItem(hDlg,IDC_CPT),(IsDlgButtonChecked(hDlg,IDC_CHECKCOL)==BST_CHECKED) && IsDlgButtonChecked(hDlg,IDC_CHECKPOP)==BST_CHECKED); + EnableWindow(GetDlgItem(hDlg,IDC_RADIOPOPN),(IsDlgButtonChecked(hDlg,IDC_CHECKPOP)==BST_CHECKED)); + EnableWindow(GetDlgItem(hDlg,IDC_RADIOPOP1),(IsDlgButtonChecked(hDlg,IDC_CHECKPOP)==BST_CHECKED)); + EnableWindow(GetDlgItem(hDlg,IDC_EDITPOPS),(IsDlgButtonChecked(hDlg,IDC_CHECKPOP)==BST_CHECKED)); + break; + case IDC_CHECKFPOP: + Changed=TRUE; + EnableWindow(GetDlgItem(hDlg,IDC_CHECKFCOL),IsDlgButtonChecked(hDlg,IDC_CHECKFPOP)==BST_CHECKED); + EnableWindow(GetDlgItem(hDlg,IDC_CPFB),(IsDlgButtonChecked(hDlg,IDC_CHECKFCOL)==BST_CHECKED) && IsDlgButtonChecked(hDlg,IDC_CHECKFPOP)==BST_CHECKED); + EnableWindow(GetDlgItem(hDlg,IDC_CPFT),(IsDlgButtonChecked(hDlg,IDC_CHECKFCOL)==BST_CHECKED) && IsDlgButtonChecked(hDlg,IDC_CHECKFPOP)==BST_CHECKED); + EnableWindow(GetDlgItem(hDlg,IDC_EDITFPOPS),(IsDlgButtonChecked(hDlg,IDC_CHECKFPOP)==BST_CHECKED)); + break; + case IDC_CHECKNPOP: + Changed=TRUE; + EnableWindow(GetDlgItem(hDlg,IDC_CHECKNCOL),IsDlgButtonChecked(hDlg,IDC_CHECKNPOP)==BST_CHECKED); + EnableWindow(GetDlgItem(hDlg,IDC_CPNB),(IsDlgButtonChecked(hDlg,IDC_CHECKNCOL)==BST_CHECKED) && IsDlgButtonChecked(hDlg,IDC_CHECKNPOP)==BST_CHECKED); + EnableWindow(GetDlgItem(hDlg,IDC_CPNT),(IsDlgButtonChecked(hDlg,IDC_CHECKNCOL)==BST_CHECKED) && IsDlgButtonChecked(hDlg,IDC_CHECKNPOP)==BST_CHECKED); + EnableWindow(GetDlgItem(hDlg,IDC_EDITNPOPS),(IsDlgButtonChecked(hDlg,IDC_CHECKNPOP)==BST_CHECKED)); + break; + + } + if (HIWORD(wParam)==EN_CHANGE) + Changed=TRUE; + break; + } + case WM_NOTIFY: + switch(((LPNMHDR)lParam)->idFrom) + { + case 0: + switch(((LPNMHDR)lParam)->code) + { + case PSN_APPLY: + { + TCHAR Text[MAX_PATH]; + BOOL Translated,NewAcc=FALSE,CheckPopup,CheckPopupW; + BOOL CheckNPopup,CheckNPopupW,CheckFPopup,CheckFPopupW; + BOOL CheckPopN; + UINT Time,TimeN,TimeF; + + if (GetDlgItemText(hDlg,IDC_COMBOACCOUNT,Text,sizeof(Text)/sizeof(TCHAR))) + { + CheckPopup = (IsDlgButtonChecked(hDlg,IDC_CHECKPOP)==BST_CHECKED); + CheckPopupW = (IsDlgButtonChecked(hDlg,IDC_CHECKCOL)==BST_CHECKED); + + CheckFPopup = (IsDlgButtonChecked(hDlg,IDC_CHECKFPOP)==BST_CHECKED); + CheckFPopupW = (IsDlgButtonChecked(hDlg,IDC_CHECKFCOL)==BST_CHECKED); + + CheckNPopup = (IsDlgButtonChecked(hDlg,IDC_CHECKNPOP)==BST_CHECKED); + CheckNPopupW = (IsDlgButtonChecked(hDlg,IDC_CHECKNCOL)==BST_CHECKED); + + CheckPopN = (IsDlgButtonChecked(hDlg,IDC_RADIOPOPN)==BST_CHECKED); + + + Time=GetDlgItemInt(hDlg,IDC_EDITPOPS,&Translated,FALSE); + if (!Translated) + { + MessageBox(hDlg,TranslateT("This is not a valid number value"),TranslateT("Input error"),MB_OK); + SetFocus(GetDlgItem(hDlg,IDC_EDITPOPS)); + break; + } + TimeN=GetDlgItemInt(hDlg,IDC_EDITNPOPS,&Translated,FALSE); + if (!Translated) + { + MessageBox(hDlg,TranslateT("This is not a valid number value"),TranslateT("Input error"),MB_OK); + SetFocus(GetDlgItem(hDlg,IDC_EDITNPOPS)); + break; + } + TimeF=GetDlgItemInt(hDlg,IDC_EDITFPOPS,&Translated,FALSE); + if (!Translated) + { + MessageBox(hDlg,TranslateT("This is not a valid number value"),TranslateT("Input error"),MB_OK); + SetFocus(GetDlgItem(hDlg,IDC_EDITFPOPS)); + break; + } + + + DlgSetItemTextT(hDlg, IDC_STTIMELEFT, TranslateT("Please wait while no account is in use.")); + + ActualAccount->Flags= + (ActualAccount->Flags & YAMN_ACC_ENA) | + (ActualAccount->Flags & YAMN_ACC_SSL23) | + (ActualAccount->Flags & YAMN_ACC_NOTLS) | + (ActualAccount->Flags & YAMN_ACC_APOP) | + (ActualAccount->Flags & YAMN_ACC_BODY) | + (CheckPopN ? YAMN_ACC_POPN : 0); + + ActualAccount->NewMailN.Flags= + (ActualAccount->NewMailN.Flags & YAMN_ACC_SND) | + (ActualAccount->NewMailN.Flags & YAMN_ACC_MSG) | + (ActualAccount->NewMailN.Flags & YAMN_ACC_ICO) | + (CheckPopup ? YAMN_ACC_POP : 0) | + (CheckPopupW ? YAMN_ACC_POPC : 0) | + (ActualAccount->NewMailN.Flags & YAMN_ACC_APP) | + (ActualAccount->NewMailN.Flags & YAMN_ACC_KBN) | + (ActualAccount->NewMailN.Flags & YAMN_ACC_CONT) | + (ActualAccount->NewMailN.Flags & YAMN_ACC_CONTNICK) | + (ActualAccount->NewMailN.Flags & YAMN_ACC_CONTNOEVENT) | + YAMN_ACC_MSGP; + + ActualAccount->NoNewMailN.Flags= + (CheckNPopup ? YAMN_ACC_POP : 0) | + (CheckNPopupW ? YAMN_ACC_POPC : 0) | + (ActualAccount->NoNewMailN.Flags & YAMN_ACC_MSGP); + + ActualAccount->BadConnectN.Flags= + (ActualAccount->BadConnectN.Flags & YAMN_ACC_SND) | + (ActualAccount->BadConnectN.Flags & YAMN_ACC_MSG) | + (ActualAccount->BadConnectN.Flags & YAMN_ACC_ICO) | + (CheckFPopup ? YAMN_ACC_POP : 0) | + (CheckFPopupW ? YAMN_ACC_POPC : 0); + + ActualAccount->NewMailN.PopUpB=SendDlgItemMessage(hDlg,IDC_CPB,CPM_GETCOLOUR,0,0); + ActualAccount->NewMailN.PopUpT=SendDlgItemMessage(hDlg,IDC_CPT,CPM_GETCOLOUR,0,0); + ActualAccount->NewMailN.PopUpTime=Time; + + ActualAccount->NoNewMailN.PopUpB=SendDlgItemMessage(hDlg,IDC_CPNB,CPM_GETCOLOUR,0,0); + ActualAccount->NoNewMailN.PopUpT=SendDlgItemMessage(hDlg,IDC_CPNT,CPM_GETCOLOUR,0,0); + ActualAccount->NoNewMailN.PopUpTime=TimeN; + + ActualAccount->BadConnectN.PopUpB=SendDlgItemMessage(hDlg,IDC_CPFB,CPM_GETCOLOUR,0,0); + ActualAccount->BadConnectN.PopUpT=SendDlgItemMessage(hDlg,IDC_CPFT,CPM_GETCOLOUR,0,0); + ActualAccount->BadConnectN.PopUpTime=TimeF; + + + + #ifdef DEBUG_SYNCHRO + DebugLog(SynchroFile,"Options:APPLY:ActualAccountSO-write done\n"); + #endif + WriteDone(ActualAccount); + #ifdef DEBUG_SYNCHRO + DebugLog(SynchroFile,"Options:APPLY:AccountBrowserSO-write done\n"); + #endif + WriteDoneSO(POP3Plugin->AccountBrowserSO); + +// if (0==WritePOP3Accounts()) +// Beep(500,100); + WritePOP3Accounts(); + RefreshContact(); + return TRUE; + } + } + break; + } + break; + } + break; + } + if (Changed) + SendMessage(GetParent(hDlg),PSM_CHANGED,0,0); + return FALSE; +} + diff --git a/protocols/YAMN/proto/pop3/pop3opt.h b/protocols/YAMN/proto/pop3/pop3opt.h new file mode 100644 index 0000000000..c828c221e0 --- /dev/null +++ b/protocols/YAMN/proto/pop3/pop3opt.h @@ -0,0 +1,42 @@ +#ifndef __OPTIONS_H +#define __OPTIONS_H + +#define M_SHOWACTUAL 0 +#define M_SHOWDEFAULT 1 + + +//Enables account in options +BOOL DlgEnableAccount(HWND hDlg,WPARAM wParam,LPARAM lParam); + +//Sets dialog controls to match current account +BOOL DlgShowAccount(HWND hDlg,WPARAM wParam,LPARAM lParam); + +//Sets colors to match colors of actual account +BOOL DlgShowAccountColors(HWND hDlg,WPARAM wParam,LPARAM lParam); + +//Options dialog procedure +INT_PTR CALLBACK DlgProcPOP3AccOpt(HWND hDlg, UINT msg, WPARAM wParam, LPARAM lParam); + +//Options dialog procedure +BOOL CALLBACK DlgProcPOP3AccStatusOpt(HWND hDlg, UINT msg, WPARAM wParam, LPARAM lParam); + +//Options dialog procedure +INT_PTR CALLBACK DlgProcYAMNOpt(HWND hDlg, UINT msg, WPARAM wParam, LPARAM lParam); + +//Options dialog procedure +INT_PTR CALLBACK DlgProcPOP3AccPopup(HWND hDlg, UINT msg, WPARAM wParam, LPARAM lParam); + +//Initializes POP3 options for Miranda +int POP3OptInit(WPARAM wParam,LPARAM lParam); + +//Sets dialog item text +BOOL DlgSetItemText(HWND hDlg,WPARAM wParam,const char*); +BOOL DlgSetItemTextW(HWND hDlg,WPARAM wParam,const WCHAR*); + +#if defined( _UNICODE ) + #define DlgSetItemTextT DlgSetItemTextW +#else + #define DlgSetItemTextT DlgSetItemText +#endif + +#endif diff --git a/protocols/YAMN/protoplugin.cpp b/protocols/YAMN/protoplugin.cpp new file mode 100644 index 0000000000..479b54ce67 --- /dev/null +++ b/protocols/YAMN/protoplugin.cpp @@ -0,0 +1,197 @@ +/* + * YAMN plugin export functions for protocols + * + * (c) majvan 2002-2004 + */ + +#include "yamn.h" + +//-------------------------------------------------------------------------------------------------- +//-------------------------------------------------------------------------------------------------- + +PYAMN_PROTOPLUGINQUEUE FirstProtoPlugin=NULL; + +INT_PTR RegisterProtocolPluginSvc(WPARAM,LPARAM); + +//Removes plugin from queue and deletes registration structures +INT_PTR UnregisterProtocolPlugin(HYAMNPROTOPLUGIN Plugin); + +INT_PTR UnregisterProtocolPluginSvc(WPARAM,LPARAM); + +//Removes plugins from queue and deletes registration structures +INT_PTR UnregisterProtoPlugins(); + +//Sets imported functions for an plugin and therefore it starts plugin to be registered and running +// Plugin- plugin, which wants to set its functions +// YAMNFcn- pointer to imported functions with accounts +// YAMNFcnVer- version of YAMN_PROTOIMPORTFCN, use YAMN_PROTOIMPORTFCNVERSION +// YAMNMailFcn- pointer to imported functions with mails +// YAMNMailFcnVer- version of YAMN_MAILIMPORTFCN, use YAMN_MAILIMPORTFCNVERSION +// returns nonzero if success +int WINAPI SetProtocolPluginFcnImportFcn(HYAMNPROTOPLUGIN Plugin,PYAMN_PROTOIMPORTFCN YAMNFcn,DWORD YAMNFcnVer,PYAMN_MAILIMPORTFCN YAMNMailFcn,DWORD YAMNMailFcnVer); + +struct CExportedFunctions ProtoPluginExportedFcn[]= +{ + {YAMN_SETPROTOCOLPLUGINFCNIMPORTID,(void *)SetProtocolPluginFcnImportFcn}, +}; + +struct CExportedServices ProtoPluginExportedSvc[]= +{ + {MS_YAMN_REGISTERPROTOPLUGIN,RegisterProtocolPluginSvc}, + {MS_YAMN_UNREGISTERPROTOPLUGIN,UnregisterProtocolPluginSvc}, + {MS_YAMN_GETFILENAME,GetFileNameSvc}, + {MS_YAMN_DELETEFILENAME,DeleteFileNameSvc}, +}; + +//-------------------------------------------------------------------------------------------------- +//-------------------------------------------------------------------------------------------------- + +INT_PTR RegisterProtocolPluginSvc(WPARAM wParam,LPARAM lParam) +{ + PYAMN_PROTOREGISTRATION Registration=(PYAMN_PROTOREGISTRATION)wParam; + HYAMNPROTOPLUGIN Plugin; + + if (lParam!=YAMN_PROTOREGISTRATIONVERSION) + return 0; + if ((Registration->Name==NULL) || (Registration->Ver==NULL)) + return (INT_PTR)NULL; + if (NULL==(Plugin=new YAMN_PROTOPLUGIN)) + return (INT_PTR)NULL; + + Plugin->PluginInfo=Registration; + + Plugin->FirstAccount=NULL; + + Plugin->AccountBrowserSO=new SWMRG; + SWMRGInitialize(Plugin->AccountBrowserSO,NULL); + + Plugin->Fcn=NULL; + Plugin->MailFcn=NULL; + +#ifdef DEBUG_SYNCHRO + DebugLog(SynchroFile,"::: YAMN- new protocol registered: %0x (%s) :::\n",Plugin,Registration->Name); +#endif + return (INT_PTR)Plugin; +} + +int WINAPI SetProtocolPluginFcnImportFcn(HYAMNPROTOPLUGIN Plugin,PYAMN_PROTOIMPORTFCN YAMNFcn,DWORD YAMNFcnVer,PYAMN_MAILIMPORTFCN YAMNMailFcn,DWORD YAMNMailFcnVer) +{ + PYAMN_PROTOPLUGINQUEUE Parser; + + if (YAMNFcnVer!=YAMN_PROTOIMPORTFCNVERSION) + return 0; + if (YAMNMailFcnVer!=YAMN_MAILIMPORTFCNVERSION) + return 0; + if (YAMNFcn==NULL) + return 0; + if (YAMNMailFcn==NULL) + return 0; + +#ifdef DEBUG_SYNCHRO + DebugLog(SynchroFile,"::: YAMN- protocol %0x import succeed :::\n",Plugin); +#endif + Plugin->Fcn=YAMNFcn; + Plugin->MailFcn=YAMNMailFcn; + + EnterCriticalSection(&PluginRegCS); +//We add protocol to the protocol list + for (Parser=FirstProtoPlugin;Parser!=NULL && Parser->Next!=NULL;Parser=Parser->Next); + if (Parser==NULL) + { + FirstProtoPlugin=new YAMN_PROTOPLUGINQUEUE; + Parser=FirstProtoPlugin; + } + else + { + Parser->Next=new YAMN_PROTOPLUGINQUEUE; + Parser=Parser->Next; + } + + Parser->Plugin=Plugin; + Parser->Next=NULL; + + LeaveCriticalSection(&PluginRegCS); + return 1; +} + +INT_PTR UnregisterProtocolPlugin(HYAMNPROTOPLUGIN Plugin) +{ + PYAMN_PROTOPLUGINQUEUE Parser,Found; + +#ifdef DEBUG_SYNCHRO + DebugLog(SynchroFile,"Entering UnregisterProtocolPlugin\n"); +#endif + if (FirstProtoPlugin->Plugin==Plugin) + { + Found=FirstProtoPlugin; + FirstProtoPlugin=FirstProtoPlugin->Next; + } + else + { + for (Parser=FirstProtoPlugin;(Parser->Next!=NULL) && (Plugin!=Parser->Next->Plugin);Parser=Parser->Next); + if (Parser->Next!=NULL) + { + Found=Parser->Next; + Parser->Next=Parser->Next->Next; + } + else + Found=NULL; + } + if (Found!=NULL) + { + StopAccounts(Plugin); + DeleteAccounts(Plugin); + if (Plugin->Fcn->UnLoadFcn!=NULL) + Plugin->Fcn->UnLoadFcn((void *)0); + + delete Found->Plugin->AccountBrowserSO; + delete Found->Plugin; + delete Found; + +#ifdef DEBUG_SYNCHRO + DebugLog(SynchroFile,"::: YAMN- protocol %0x unregistered :::\n",Plugin); +#endif + } + else + return 0; + return 1; +} + +INT_PTR UnregisterProtocolPluginSvc(WPARAM wParam,LPARAM lParam) +{ + HYAMNPROTOPLUGIN Plugin=(HYAMNPROTOPLUGIN)wParam; + + EnterCriticalSection(&PluginRegCS); + UnregisterProtocolPlugin(Plugin); + LeaveCriticalSection(&PluginRegCS); + return 1; + +} + +INT_PTR UnregisterProtoPlugins() +{ + EnterCriticalSection(&PluginRegCS); +//We remove protocols from the protocol list + while(FirstProtoPlugin!=NULL) + UnregisterProtocolPlugin(FirstProtoPlugin->Plugin); + LeaveCriticalSection(&PluginRegCS); + return 1; +} + +INT_PTR GetFileNameSvc(WPARAM wParam,LPARAM) +{ + TCHAR *FileName = new TCHAR[MAX_PATH]; + if (FileName == NULL) + return NULL; + + mir_sntprintf(FileName, MAX_PATH, _T("%s\\yamn-accounts.%s.%s.book"), UserDirectory, wParam, ProfileName); + return (INT_PTR)FileName; +} + +INT_PTR DeleteFileNameSvc(WPARAM wParam,LPARAM) +{ + if (( TCHAR* )wParam != NULL) + delete[] ( TCHAR* ) wParam; + + return 0; +} diff --git a/protocols/YAMN/resources/YAMN.rc b/protocols/YAMN/resources/YAMN.rc new file mode 100644 index 0000000000..54320549e4 --- /dev/null +++ b/protocols/YAMN/resources/YAMN.rc @@ -0,0 +1,344 @@ +// Microsoft Visual C++ generated resource script. +// +#include "resource.h" + +#define APSTUDIO_READONLY_SYMBOLS +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 2 resource. +// +#include "afxres.h" + +///////////////////////////////////////////////////////////////////////////// +#undef APSTUDIO_READONLY_SYMBOLS + +///////////////////////////////////////////////////////////////////////////// +// Neutral resources + +#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_NEU) +LANGUAGE LANG_NEUTRAL, SUBLANG_NEUTRAL +#pragma code_page(1251) + +#ifdef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// TEXTINCLUDE +// + +1 TEXTINCLUDE +BEGIN + "resource.h\0" +END + +2 TEXTINCLUDE +BEGIN + "#include ""afxres.h""\r\n" + "\0" +END + +3 TEXTINCLUDE +BEGIN + "\r\n" + "\0" +END + +#endif // APSTUDIO_INVOKED + + +///////////////////////////////////////////////////////////////////////////// +// +// DESIGNINFO +// + +#ifdef APSTUDIO_INVOKED +GUIDELINES DESIGNINFO +BEGIN + IDD_DLGVIEWMESSAGES, DIALOG + BEGIN + LEFTMARGIN, 5 + RIGHTMARGIN, 455 + TOPMARGIN, 5 + BOTTOMMARGIN, 105 + END + + IDD_DLGSHOWMESSAGE, DIALOG + BEGIN + END + + IDD_DLGBADCONNECT, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 179 + TOPMARGIN, 7 + BOTTOMMARGIN, 43 + END + + IDD_PLUGINOPT, DIALOG + BEGIN + LEFTMARGIN, 7 + VERTGUIDE, 13 + VERTGUIDE, 85 + VERTGUIDE, 160 + VERTGUIDE, 307 + TOPMARGIN, 4 + HORZGUIDE, 5 + HORZGUIDE, 20 + HORZGUIDE, 147 + HORZGUIDE, 157 + HORZGUIDE, 173 + HORZGUIDE, 184 + HORZGUIDE, 207 + HORZGUIDE, 217 + END + + IDD_POP3ACCOUNTOPT, DIALOG + BEGIN + VERTGUIDE, 155 + VERTGUIDE, 236 + END + + IDD_CHOOSESTATUSMODES, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 219 + TOPMARGIN, 7 + BOTTOMMARGIN, 147 + END + + IDD_YAMNOPT, DIALOG + BEGIN + RIGHTMARGIN, 310 + VERTGUIDE, 8 + END + + IDD_POP3ACCOUNTPOPUP, DIALOG + BEGIN + VERTGUIDE, 155 + VERTGUIDE, 236 + END +END +#endif // APSTUDIO_INVOKED + + +///////////////////////////////////////////////////////////////////////////// +// +// Dialog +// + +IDD_DLGVIEWMESSAGES DIALOG 50, 200, 460, 110 +STYLE DS_SETFONT | DS_3DLOOK | DS_CENTER | WS_MINIMIZEBOX | WS_POPUP | WS_CAPTION | WS_SYSMENU | WS_THICKFRAME +FONT 8, "MS Shell Dlg" +BEGIN + CONTROL "List4",IDC_LISTMAILS,"SysListView32",LVS_REPORT | LVS_EDITLABELS | WS_BORDER | WS_TABSTOP,5,5,450,70 + DEFPUSHBUTTON "",IDC_BTNOK,395,90,60,15 + PUSHBUTTON "",IDC_BTNAPP,263,90,114,15 + PUSHBUTTON "",IDC_BTNDEL,5,90,114,15 + LTEXT "",IDC_STSTATUS,5,75,450,10 + PUSHBUTTON "",IDC_BTNCHECKALL,150,91,92,14 +END + +IDD_DLGSHOWMESSAGE DIALOGEX 50, 200, 460, 132 +STYLE DS_SETFONT | DS_3DLOOK | WS_MINIMIZEBOX | WS_POPUP | WS_CAPTION | WS_SYSMENU | WS_THICKFRAME +FONT 8, "MS Shell Dlg", 0, 0, 0x1 +BEGIN + CONTROL "List5",IDC_LISTHEADERS,"SysListView32",LVS_REPORT | LVS_EDITLABELS | WS_BORDER | WS_TABSTOP,5,5,450,70 + CONTROL "",IDC_SPLITTER,"Static",SS_ENHMETAFILE | WS_TABSTOP,0,80,187,2,WS_EX_STATICEDGE + EDITTEXT IDC_EDITBODY,3,84,454,45,ES_MULTILINE | ES_READONLY | ES_WANTRETURN | WS_VSCROLL | WS_HSCROLL +END + +IDD_DLGBADCONNECT DIALOG 0, 0, 186, 76 +STYLE DS_SETFONT | DS_MODALFRAME | DS_CENTER | WS_POPUP | WS_CAPTION | WS_SYSMENU +FONT 8, "MS Shell Dlg" +BEGIN + DEFPUSHBUTTON "OK",IDC_BTNOK,69,55,50,14 + LTEXT "",IDC_STATICMSG,7,7,172,37 +END + +IDD_PLUGINOPT DIALOGEX 0, 0, 310, 231 +STYLE DS_SETFONT | DS_FIXEDSYS | DS_CONTROL | WS_CHILD | WS_VISIBLE | WS_BORDER +EXSTYLE WS_EX_CONTROLPARENT +FONT 8, "MS Shell Dlg", 0, 0, 0x1 +BEGIN + GROUPBOX "Installed plugins",IDC_STATIC,7,5,300,142 + COMBOBOX IDC_COMBOPLUGINS,13,14,287,58,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP + LTEXT "Version:",IDC_STATIC,13,30,72,11 + EDITTEXT IDC_STVER,85,30,215,12,ES_AUTOHSCROLL | ES_READONLY | NOT WS_BORDER | WS_GROUP + LTEXT "Description:",IDC_STATIC,13,41,72,23 + EDITTEXT IDC_STDESC,85,41,215,23,ES_AUTOHSCROLL | ES_READONLY | NOT WS_BORDER | WS_GROUP + LTEXT "Copyright:",IDC_STATIC,13,64,72,10 + EDITTEXT IDC_STCOPY,85,63,215,12,ES_AUTOHSCROLL | ES_READONLY | NOT WS_BORDER | WS_GROUP + LTEXT "Contact:",IDC_STATIC,13,77,72,11 + EDITTEXT IDC_STMAIL,85,76,214,12,ES_AUTOHSCROLL | ES_READONLY | NOT WS_BORDER | WS_GROUP + LTEXT "WWW:",IDC_STATIC,13,101,72,11 + CONTROL "",IDC_STWWW,"Hyperlink",WS_TABSTOP,85,101,215,11 +END + +IDD_POP3ACCOUNTOPT DIALOGEX 0, 0, 310, 230 +STYLE DS_SETFONT | DS_FIXEDSYS | DS_CONTROL | WS_CHILD | WS_VISIBLE +EXSTYLE WS_EX_CONTROLPARENT +FONT 8, "MS Shell Dlg", 0, 0, 0x1 +BEGIN + COMBOBOX IDC_COMBOACCOUNT,4,6,106,65,CBS_DROPDOWNLIST | CBS_SORT | WS_VSCROLL | WS_TABSTOP + CONTROL "Check this account",IDC_CHECK,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,167,32,118,10,WS_EX_TRANSPARENT + LTEXT "Check interval [min]:",IDC_STINTERVAL,168,56,94,8 + EDITTEXT IDC_EDITINTERVAL,259,53,20,12,ES_AUTOHSCROLL | ES_NUMBER,WS_EX_TRANSPARENT + GROUPBOX "Notifications",IDC_GBNEWMAIL,4,143,304,87 + CONTROL "Sound",IDC_CHECKSND,"Button",BS_AUTOCHECKBOX | BS_NOTIFY | WS_TABSTOP,12,162,60,10 + CONTROL "Message",IDC_CHECKMSG,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,12,174,135,10 + CONTROL "Tray Icon",IDC_CHECKICO,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,85,163,65,10 + CONTROL "Keyboard Flash",IDC_CHECKKBN,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,12,186,132,9 + CONTROL "Execute Application",IDC_CHECKAPP,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,12,198,135,8 + PUSHBUTTON "...",IDC_BTNAPP,19,209,16,12 + EDITTEXT IDC_EDITAPP,41,209,65,12,ES_AUTOHSCROLL + EDITTEXT IDC_EDITAPPPARAM,111,209,40,12,ES_AUTOHSCROLL + CONTROL "Use contact notification for this account",IDC_CHECKCONTACT, + "Button",BS_AUTOCHECKBOX | WS_TABSTOP,166,107,138,10,WS_EX_TRANSPARENT + CONTROL "Replace nick name",IDC_CHECKCONTACTNICK,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,187,117,117,10,WS_EX_TRANSPARENT + CONTROL "Disable Events",IDC_CHECKCONTACTNOEVENT,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,187,128,115,10,WS_EX_TRANSPARENT + LTEXT "",IDC_STSTATUS,218,9,88,8 + LTEXT "Server:",IDC_STSERVER,10,50,44,8 + EDITTEXT IDC_EDITSERVER,56,48,92,12,ES_AUTOHSCROLL | WS_GROUP + LTEXT "User Name:",IDC_STLOGIN,10,82,44,8 + EDITTEXT IDC_EDITLOGIN,57,80,92,12,ES_AUTOHSCROLL | WS_GROUP + LTEXT "Password:",IDC_STPASS,10,96,44,8 + EDITTEXT IDC_EDITPASS,57,94,92,12,ES_PASSWORD | ES_AUTOHSCROLL | WS_GROUP + LTEXT "Codepage:",IDC_STCP,10,111,44,8 + COMBOBOX IDC_COMBOCP,57,108,92,130,CBS_DROPDOWNLIST | CBS_AUTOHSCROLL | WS_VSCROLL | WS_TABSTOP + LTEXT "Port:",IDC_STPORT,10,65,44,8,SS_CENTERIMAGE + EDITTEXT IDC_EDITPORT,57,64,27,12,ES_AUTOHSCROLL | ES_NUMBER | WS_GROUP + CONTROL "SSL",IDC_CHECKSSL,"Button",BS_AUTOCHECKBOX | BS_LEFT | WS_TABSTOP,87,66,27,10 + CONTROL "Disable STLS",IDC_CHECKNOTLS,"Button",BS_AUTOCHECKBOX | BS_LEFT | WS_TABSTOP,83,125,69,10 + CONTROL "Startup check",IDC_CHECKSTART,"Button",BS_AUTOCHECKBOX | BS_NOTIFY | WS_TABSTOP,167,43,78,10 + CONTROL "Auto retrieve body",IDC_AUTOBODY,"Button",BS_AUTOCHECKBOX | BS_NOTIFY | WS_TABSTOP,166,86,137,10 + CONTROL "Check from menu",IDC_CHECKFORCE,"Button",BS_AUTOCHECKBOX | BS_NOTIFY | WS_TABSTOP,166,97,137,8 + PUSHBUTTON "Only check when ...",IDC_BTNSTATUS,195,69,81,13 + CONTROL "Sound notification if failed",IDC_CHECKFSND,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,166,163,135,10 + CONTROL "Message notification if failed",IDC_CHECKFMSG,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,166,174,135,10 + CONTROL "Tray icon notification if failed",IDC_CHECKFICO,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,166,186,135,10 + PUSHBUTTON "Reset counter",IDC_BTNRESET,161,200,75,13 + PUSHBUTTON "-",IDC_BTNDEL,140,6,15,13 + PUSHBUTTON "Default",IDC_BTNDEFAULT,9,124,54,13 + LTEXT "",IDC_STTIMELEFT,163,216,141,8 + LTEXT "Status:",IDC_STATIC,175,9,34,9 + PUSHBUTTON "+",IDC_BTNADD,118,6,15,13 + GROUPBOX "Account",IDC_STATIC,4,22,151,120 + CONTROL "APOP",IDC_CHECKAPOP,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,119,66,34,10 + LTEXT "Name:",IDC_STATIC,10,34,44,10 + EDITTEXT IDC_EDITNAME,56,32,92,12,ES_AUTOHSCROLL + GROUPBOX "Options",IDC_STATIC,161,22,147,120 + GROUPBOX "New Mail",IDC_STATIC,7,153,149,73 + GROUPBOX "Errors",IDC_STATIC,161,153,143,44 +END + +IDD_CHOOSESTATUSMODES DIALOG 0, 0, 226, 154 +STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU +CAPTION "Check while ..." +FONT 8, "MS Shell Dlg" +BEGIN + DEFPUSHBUTTON "OK",IDOK,112,133,50,14 + PUSHBUTTON "Cancel",IDCANCEL,169,133,50,14 + GROUPBOX "Choose modes",IDC_STATUSGROUP,7,7,212,119 + CONTROL "Offline",IDC_CHECKST0,"Button",BS_AUTOCHECKBOX | BS_NOTIFY | WS_TABSTOP,15,19,70,9 + CONTROL "Online",IDC_CHECKST1,"Button",BS_AUTOCHECKBOX | BS_NOTIFY | WS_TABSTOP,15,39,70,9 + CONTROL "Away",IDC_CHECKST2,"Button",BS_AUTOCHECKBOX | BS_NOTIFY | WS_TABSTOP,15,62,70,9 + CONTROL "N/A",IDC_CHECKST3,"Button",BS_AUTOCHECKBOX | BS_NOTIFY | WS_TABSTOP,15,83,70,9 + CONTROL "Occupied",IDC_CHECKST4,"Button",BS_AUTOCHECKBOX | BS_NOTIFY | WS_TABSTOP,15,104,70,9 + CONTROL "DND",IDC_CHECKST5,"Button",BS_AUTOCHECKBOX | BS_NOTIFY | WS_TABSTOP,134,19,70,9 + CONTROL "Free for chat",IDC_CHECKST6,"Button",BS_AUTOCHECKBOX | BS_NOTIFY | WS_TABSTOP,134,39,70,9 + CONTROL "Invisible",IDC_CHECKST7,"Button",BS_AUTOCHECKBOX | BS_NOTIFY | WS_TABSTOP,134,62,70,9 + CONTROL "On the phone",IDC_CHECKST8,"Button",BS_AUTOCHECKBOX | BS_NOTIFY | WS_TABSTOP,134,83,70,9 + CONTROL "Out to lunch",IDC_CHECKST9,"Button",BS_AUTOCHECKBOX | BS_NOTIFY | WS_TABSTOP,134,104,70,9 +END + +IDD_YAMNOPT DIALOGEX 0, 0, 312, 121 +STYLE DS_SETFONT | DS_FIXEDSYS | DS_CONTROL | WS_CHILD | WS_VISIBLE | WS_BORDER +EXSTYLE WS_EX_CONTROLPARENT +FONT 8, "MS Shell Dlg", 0, 0, 0x1 +BEGIN + GROUPBOX "YAMN General Options",IDC_STATIC,3,2,303,65 + CONTROL "TopToolBar button ""Check mail""",IDC_CHECKTTB,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,7,15,294,11 + CONTROL "Enable YAMN Main Menu",IDC_MAINMENU,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,7,33,293,9 + CONTROL "Show YAMN as a Protocol (Require Restart)",IDC_YAMNASPROTO, + "Button",BS_AUTOCHECKBOX | WS_TABSTOP,7,50,293,9 + + GROUPBOX "MailBrowser Options",IDC_STATIC,3,68,151,47 + CONTROL "Enable Close on Delete Button",IDC_CLOSEONDELETE,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,8,80,143,11 + CONTROL "Show long localised date",IDC_LONGDATE,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,170,77,130,10 + CONTROL "Don't show today's date",IDC_SMARTDATE,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,170,89,131,10 + + GROUPBOX "Date/Time Representation",IDC_STATIC,166,68,141,47 + CONTROL "Don't show seconds",IDC_NOSECONDS,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,170,101,129,8 +END + +IDD_POP3ACCOUNTPOPUP DIALOGEX 0, 0, 315, 230 +STYLE DS_SETFONT | DS_FIXEDSYS | DS_CONTROL | WS_CHILD | WS_VISIBLE +EXSTYLE WS_EX_CONTROLPARENT +FONT 8, "MS Shell Dlg", 0, 0, 0x1 +BEGIN + COMBOBOX IDC_COMBOACCOUNT,4,4,140,65,CBS_DROPDOWNLIST | CBS_SORT | WS_VSCROLL | WS_TABSTOP + GROUPBOX "Mail Notifications",IDC_GBNEWMAIL,5,23,300,76 + CONTROL "Popup",IDC_CHECKPOP,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,11,32,108,10 + CONTROL "Single popup",IDC_RADIOPOP1,"Button",BS_AUTORADIOBUTTON | WS_TABSTOP,23,43,95,10 + CONTROL "Multi popup",IDC_RADIOPOPN,"Button",BS_AUTORADIOBUTTON | WS_TABSTOP,23,55,95,10 + CONTROL "Use custom colour",IDC_CHECKCOL,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,23,83,107,10 + CONTROL "",IDC_CPB,"ColourPicker",WS_TABSTOP,145,66,29,12 + CONTROL "",IDC_CPT,"ColourPicker",WS_TABSTOP,145,83,29,12 + EDITTEXT IDC_EDITPOPS,23,65,20,12,ES_AUTOHSCROLL + GROUPBOX "No new mail notifications",IDC_GBNONEWMAIL,5,152,300,62 + CONTROL "Popup if no mail",IDC_CHECKNPOP,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,11,161,94,10 + CONTROL "Persistant message",IDC_CHECKNMSGP,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,23,188,110,10 + CONTROL "Use custom colour",IDC_CHECKNCOL,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,23,201,107,10 + CONTROL "",IDC_CPNB,"ColourPicker",WS_TABSTOP,145,181,29,12 + CONTROL "",IDC_CPNT,"ColourPicker",WS_TABSTOP,145,198,29,12 + EDITTEXT IDC_EDITNPOPS,23,173,20,12,ES_AUTOHSCROLL + GROUPBOX "Connection failure notifications",IDC_GBBADCONNECT,5,101,300,49 + CONTROL "Popup notification if failed",IDC_CHECKFPOP,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,11,110,118,10 + CONTROL "Use custom colour",IDC_CHECKFCOL,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,23,136,95,10 + CONTROL "",IDC_CPFB,"ColourPicker",WS_TABSTOP,145,118,29,12 + CONTROL "",IDC_CPFT,"ColourPicker",WS_TABSTOP,145,134,29,12 + EDITTEXT IDC_EDITFPOPS,23,121,20,12,ES_AUTOHSCROLL + LTEXT "..s Popup duration",IDC_STATIC,45,67,70,8 + LTEXT "..s Popup duration",IDC_STATIC,45,176,70,8 + LTEXT "..s Popup duration",IDC_STATIC,45,122,70,8 + PUSHBUTTON "Preview",IDC_PREVIEW,255,215,49,13 + LTEXT "Background colour",IDC_STATIC,177,184,108,10 + LTEXT "Text colour",IDC_STATIC,177,200,107,10 + LTEXT "Background colour",IDC_STATIC,177,120,108,10 + LTEXT "Text colour",IDC_STATIC,177,136,107,10 + LTEXT "Background colour",IDC_STATIC,177,69,108,10 + LTEXT "Text colour",IDC_STATIC,177,85,107,10 +END + + +///////////////////////////////////////////////////////////////////////////// +// +// Icon +// + +// Icon with lowest ID value placed first to ensure application icon +// remains consistent on all systems. +IDI_ONLINE ICON "iconeutral.ico" +IDI_OFFLINE ICON "icooffline.ico" +IDI_NA ICON "icoyamn3.ico" +IDI_OCCUPIED ICON "iconttbdown.ico" + +///////////////////////////////////////////////////////////////////////////// +// +// Bitmap +// + +IDB_ICONS BITMAP "yamn.bmp" +#endif // Neutral resources +///////////////////////////////////////////////////////////////////////////// + + + +#ifndef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 3 resource. +// + + +///////////////////////////////////////////////////////////////////////////// +#endif // not APSTUDIO_INVOKED diff --git a/protocols/YAMN/resources/iconeutral.ico b/protocols/YAMN/resources/iconeutral.ico new file mode 100644 index 0000000000..9304f4334a Binary files /dev/null and b/protocols/YAMN/resources/iconeutral.ico differ diff --git a/protocols/YAMN/resources/iconttbdown.ico b/protocols/YAMN/resources/iconttbdown.ico new file mode 100644 index 0000000000..206eba2c76 Binary files /dev/null and b/protocols/YAMN/resources/iconttbdown.ico differ diff --git a/protocols/YAMN/resources/icooffline.ico b/protocols/YAMN/resources/icooffline.ico new file mode 100644 index 0000000000..db5b2e18fa Binary files /dev/null and b/protocols/YAMN/resources/icooffline.ico differ diff --git a/protocols/YAMN/resources/icoyamn3.ico b/protocols/YAMN/resources/icoyamn3.ico new file mode 100644 index 0000000000..ca11f0f4f4 Binary files /dev/null and b/protocols/YAMN/resources/icoyamn3.ico differ diff --git a/protocols/YAMN/resources/resource.h b/protocols/YAMN/resources/resource.h new file mode 100644 index 0000000000..8bfd74c9a3 --- /dev/null +++ b/protocols/YAMN/resources/resource.h @@ -0,0 +1,129 @@ +//{{NO_DEPENDENCIES}} +// Microsoft Developer Studio generated include file. +// Used by YAMN.rc +// +#define IDI_ONLINE 104 +#define IDI_OFFLINE 105 +#define IDD_DLGVIEWMESSAGES 107 +#define IDD_DLGSHOWMESSAGE 108 +#define IDI_ICOYAMN2 112 +#define IDI_ICOYAMN1 113 +#define IDD_DLGBADCONNECT 115 +#define IDD_POP3ACCOUNTOPT 121 +#define IDD_YAMNOPT 126 +#define IDB_ICONS 127 +#define IDI_NA 131 +#define IDI_ICOTTBUP 138 +#define IDD_PLUGINOPT 141 +#define IDI_OCCUPIED 159 +#define IDD_CHOOSESTATUSMODES 310 +#define IDD_OPTIONS 311 +#define IDD_POP3ACCOUNTPOPUP 312 +#define IDC_EDITSERVER 1000 +#define IDC_EDITPORT 1001 +#define IDC_EDITLOGIN 1002 +#define IDC_EDITPASS 1003 +#define IDC_COMBOACCOUNT 1005 +#define IDC_BTNDEFAULT 1006 +#define IDC_EDITINTERVAL 1007 +#define IDC_CHECKSND 1008 +#define IDC_CHECKMSG 1009 +#define IDC_CHECKAPP 1010 +#define IDC_BTNAPP 1011 +#define IDC_CHECKICO 1012 +#define IDC_CHECK 1013 +#define IDC_BTNDEL 1014 +#define IDC_STSERVER 1015 +#define IDC_CHECKFSND 1016 +#define IDC_CHECKFMSG 1017 +#define IDC_CHECKFICO 1018 +#define IDC_CHECKST0 1019 +#define IDC_CHECKST1 1020 +#define IDC_CHECKST2 1021 +#define IDC_CHECKST3 1022 +#define IDC_CHECKST4 1023 +#define IDC_CHECKST5 1024 +#define IDC_CHECKST6 1025 +#define IDC_CHECKST7 1026 +#define IDC_EDITAPP 1027 +#define IDC_CHECKST8 1028 +#define IDC_CHECKST9 1029 +#define IDC_CHECKCONTACT 1030 +#define IDC_CHECKCONTACTNICK 1031 +#define IDC_CHECKCONTACTNOEVENT 1032 +#define IDC_STTIMELEFT 1033 +#define IDC_LISTMAILS 1038 +#define IDC_LISTHEADERS 1039 +#define IDC_EDITAPPPARAM 1044 +#define IDC_BTNOK 1047 +#define IDC_COMBOCP 1050 +#define IDC_STCP 1055 +#define IDC_STATICMSG 1055 +#define IDC_STPORT 1056 +#define IDC_STLOGIN 1057 +#define IDC_STPASS 1058 +#define IDC_STINTERVAL 1059 +#define IDC_AUTOBODY 1062 +#define IDC_BTNRESET 1063 +#define IDC_CHECKSTART 1064 +#define IDC_STWCHECK 1065 +#define IDC_CHECKFORCE 1066 +#define IDC_RADIOPOP1 1068 +#define IDC_RADIOPOPN 1069 +#define IDC_CPB 1070 +#define IDC_CPNB 1071 +#define IDC_CHECKCOL 1073 +#define IDC_CPT 1074 +#define IDC_CPFB 1075 +#define IDC_CPFT 1076 +#define IDC_CHECKFCOL 1077 +#define IDC_CHECKNCOL 1078 +#define IDC_CPNT 1079 +#define IDC_CHECKPOP 1087 +#define IDC_CHECKNPOP 1088 +#define IDC_CHECKFPOP 1089 +#define IDC_EDITPOPS 1090 +#define IDC_EDITNPOPS 1091 +#define IDC_EDITFPOPS 1092 +#define IDC_GBNEWMAIL 1094 +#define IDC_GBNONEWMAIL 1095 +#define IDC_GBBADCONNECT 1096 +#define IDC_STSTATUS 1102 +#define IDC_COMBOPLUGINS 1104 +#define IDC_STWWW 1111 +#define IDC_STMAIL 1113 +#define IDC_STCOPY 1114 +#define IDC_STDESC 1115 +#define IDC_STVER 1116 +#define IDC_CHECKTTB 1117 +#define IDC_CHECKSSL 1117 +#define IDC_CHECKNMSGP 1118 +#define IDC_CHECKNOTLS 1120 +#define IDC_CHECKKBN 1121 +#define IDC_BTNSTATUS 1123 +#define IDC_OPTIONSTAB 1124 +#define IDC_BTNCHECKALL 1125 +#define IDC_MAINMENU 1126 +#define IDC_CLOSEONDELETE 1127 +#define IDC_LONGDATE 1128 +#define IDC_SMARTDATE 1129 +#define IDC_NOSECONDS 1130 +#define IDC_YAMNASPROTO 1131 +#define IDC_CHECKAPOP 1200 +#define IDC_STATUSGROUP 1338 +#define IDC_SPLITTER 1400 +#define IDC_EDITBODY 1401 +#define IDC_PREVIEW 1402 +#define IDC_BTNADD 1403 +#define IDC_EDITNAME 1404 + +// Next default values for new objects +// +#ifdef APSTUDIO_INVOKED +#ifndef APSTUDIO_READONLY_SYMBOLS +#define _APS_NEXT_RESOURCE_VALUE 143 +#define _APS_NEXT_COMMAND_VALUE 40001 +#define _APS_NEXT_CONTROL_VALUE 1407 +#define _APS_NEXT_SYMED_VALUE 101 +#endif +#endif diff --git a/protocols/YAMN/resources/yamn.bmp b/protocols/YAMN/resources/yamn.bmp new file mode 100644 index 0000000000..91a9e34ddf Binary files /dev/null and b/protocols/YAMN/resources/yamn.bmp differ diff --git a/protocols/YAMN/resources/yamn_ver.rc b/protocols/YAMN/resources/yamn_ver.rc new file mode 100644 index 0000000000..e9fb345412 --- /dev/null +++ b/protocols/YAMN/resources/yamn_ver.rc @@ -0,0 +1,77 @@ +// Microsoft Visual C++ generated resource script. +// + +#include "resource.h" +#include "../version.h" + +#define APSTUDIO_READONLY_SYMBOLS +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 2 resource. +// +#include "afxres.h" + +///////////////////////////////////////////////////////////////////////////// +#undef APSTUDIO_READONLY_SYMBOLS + +///////////////////////////////////////////////////////////////////////////// +// Neutral resources + +#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_NEU) +#ifdef _WIN32 +LANGUAGE LANG_NEUTRAL, SUBLANG_NEUTRAL +#pragma code_page(1252) +#endif //_WIN32 + +///////////////////////////////////////////////////////////////////////////// +// +// Version +// + +VS_VERSION_INFO VERSIONINFO + FILEVERSION 0,1,2,5 + PRODUCTVERSION 0,1,2,5 + FILEFLAGSMASK 0x3fL +#ifdef _DEBUG + FILEFLAGS 0x1L +#else + FILEFLAGS 0x0L +#endif + FILEOS 0x40004L + FILETYPE 0x2L + FILESUBTYPE 0x0L +BEGIN + BLOCK "StringFileInfo" + BEGIN + BLOCK "000004b0" + BEGIN + VALUE "Comments", "Yet Another Mail Notifier" + VALUE "FileDescription", "Yet Another Mail Notifier" + VALUE "FileVersion", YAMN_VERSION_C + VALUE "InternalName", "YAMN" + VALUE "LegalCopyright", "Copyright 2007" + VALUE "OriginalFilename", "YAMN.dll" + VALUE "ProductName", "YAMN tweety" + VALUE "ProductVersion", YAMN_VERSION_C + END + END + BLOCK "VarFileInfo" + BEGIN + VALUE "Translation", 0x0, 1200 + END +END + +#endif // Neutral resources +///////////////////////////////////////////////////////////////////////////// + + + +#ifndef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 3 resource. +// + + +///////////////////////////////////////////////////////////////////////////// +#endif // not APSTUDIO_INVOKED diff --git a/protocols/YAMN/services.cpp b/protocols/YAMN/services.cpp new file mode 100644 index 0000000000..b0b524eddc --- /dev/null +++ b/protocols/YAMN/services.cpp @@ -0,0 +1,515 @@ + +#include "yamn.h" +#include "main.h" + +extern HANDLE hMenuItemMain, hMenuItemCont, hMenuItemContApp; + +static INT_PTR Service_GetCaps(WPARAM wParam, LPARAM lParam) +{ + if (wParam == PFLAGNUM_4) + return PF4_NOCUSTOMAUTH; + if (wParam == PFLAG_UNIQUEIDTEXT) + return (INT_PTR) Translate("Nick"); + if (wParam == PFLAG_MAXLENOFMESSAGE) + return 400; + if (wParam == PFLAG_UNIQUEIDSETTING) + return (INT_PTR) "Id"; + if (wParam == PFLAGNUM_2) + return PF2_ONLINE | PF2_SHORTAWAY | PF2_LONGAWAY | PF2_LIGHTDND; + if (wParam == PFLAGNUM_5) { + if (DBGetContactSettingByte(NULL, YAMN_DBMODULE, YAMN_SHOWASPROTO, 1)) + return PF2_SHORTAWAY | PF2_LONGAWAY | PF2_LIGHTDND; + return PF2_ONLINE | PF2_SHORTAWAY | PF2_LONGAWAY | PF2_LIGHTDND; + } + return 0; +} + +static INT_PTR Service_GetStatus(WPARAM wParam, LPARAM lParam) +{ + return YAMN_STATUS; +} + +static INT_PTR Service_SetStatus(WPARAM wParam, LPARAM lParam) +{ + int newstatus = (wParam != ID_STATUS_OFFLINE)?ID_STATUS_ONLINE:ID_STATUS_OFFLINE; + if (newstatus != YAMN_STATUS){ + int oldstatus = YAMN_STATUS; + YAMN_STATUS = newstatus; + ProtoBroadcastAck(YAMN_DBMODULE, NULL, ACKTYPE_STATUS, ACKRESULT_SUCCESS, (HANDLE)oldstatus, newstatus); + } + return 0; + +} + +static INT_PTR Service_GetName(WPARAM wParam, LPARAM lParam) +{ + lstrcpynA((char *) lParam, YAMN_DBMODULE, wParam);; + return 0; +} + +static INT_PTR Service_LoadIcon(WPARAM wParam, LPARAM lParam) +{ + if ( LOWORD( wParam ) == PLI_PROTOCOL ) + return (INT_PTR)CopyIcon(g_LoadIconEx(0)); // noone cares about other than PLI_PROTOCOL + + return (INT_PTR)(HICON)NULL; +} + +INT_PTR ClistContactDoubleclicked(WPARAM wParam, LPARAM lParam) +{ + ContactDoubleclicked(((CLISTEVENT*)lParam)->lParam, lParam); + return 0; +} + +static int Service_ContactDoubleclicked(WPARAM wParam, LPARAM lParam) +{ + ContactDoubleclicked(wParam, lParam); + return 0; +} + +static INT_PTR ContactApplication(WPARAM wParam, LPARAM lParam) +{ + char *szProto = (char *)CallService(MS_PROTO_GETCONTACTBASEPROTO, wParam, 0); + if ( lstrcmpA(szProto, YAMN_DBMODULE)) + return 0; + + DBVARIANT dbv; + if ( DBGetContactSetting((HANDLE) wParam, YAMN_DBMODULE, "Id", &dbv)) + return 0; + + HACCOUNT ActualAccount = (HACCOUNT) CallService(MS_YAMN_FINDACCOUNTBYNAME, (WPARAM)POP3Plugin, (LPARAM)dbv.pszVal); + if (ActualAccount != NULL) { + STARTUPINFOW si = { 0 }; + si.cb = sizeof(si); + + #ifdef DEBUG_SYNCHRO + DebugLog(SynchroFile, "ContactApplication:ActualAccountSO-read wait\n"); + #endif + if (WAIT_OBJECT_0 == WaitToReadFcn(ActualAccount->AccountAccessSO)) { + #ifdef DEBUG_SYNCHRO + DebugLog(SynchroFile, "ContactApplication:ualAccountSO-read enter\n"); + #endif + if (ActualAccount->NewMailN.App != NULL) { + WCHAR *Command; + if (ActualAccount->NewMailN.AppParam != NULL) + Command = new WCHAR[wcslen(ActualAccount->NewMailN.App)+wcslen(ActualAccount->NewMailN.AppParam)+6]; + else + Command = new WCHAR[wcslen(ActualAccount->NewMailN.App)+6]; + + if (Command != NULL) { + lstrcpyW(Command, L"\""); + lstrcatW(Command, ActualAccount->NewMailN.App); + lstrcatW(Command, L"\" "); + if (ActualAccount->NewMailN.AppParam != NULL) + lstrcatW(Command, ActualAccount->NewMailN.AppParam); + + PROCESS_INFORMATION pi; + CreateProcessW(NULL, Command, NULL, NULL, FALSE, NORMAL_PRIORITY_CLASS, NULL, NULL, &si, &pi); + delete[] Command; + } + } + + #ifdef DEBUG_SYNCHRO + DebugLog(SynchroFile, "ContactApplication:ActualAccountSO-read done\n"); + #endif + ReadDoneFcn(ActualAccount->AccountAccessSO); + } + #ifdef DEBUG_SYNCHRO + else + DebugLog(SynchroFile, "ContactApplication:ActualAccountSO-read enter failed\n"); + #endif + } + DBFreeVariant(&dbv); + return 0; +} + +DWORD WINAPI SWMRGWaitToRead(PSWMRG pSWMRG, DWORD dwTimeout); +static INT_PTR AccountMailCheck(WPARAM wParam, LPARAM lParam){ + //This service will check/sincronize the account pointed by wParam + HACCOUNT ActualAccount = (HACCOUNT)wParam; + HANDLE ThreadRunningEV; + DWORD tid; + // copy/paste make mistakes + if (ActualAccount != NULL) { + //we use event to signal, that running thread has all needed stack parameters copied + if (NULL == (ThreadRunningEV = CreateEvent(NULL, FALSE, FALSE, NULL))) + return 0; + //if we want to close miranda, we get event and do not run pop3 checking anymore + if (WAIT_OBJECT_0 == WaitForSingleObject(ExitEV, 0)) + return 0; + + EnterCriticalSection(&PluginRegCS); + #ifdef DEBUG_SYNCHRO + DebugLog(SynchroFile, "AccountCheck:ActualAccountSO-read wait\n"); + #endif + if (WAIT_OBJECT_0 != SWMRGWaitToRead(ActualAccount->AccountAccessSO, 0)) { + #ifdef DEBUG_SYNCHRO + DebugLog(SynchroFile, "ForceCheck:ActualAccountSO-read wait failed\n"); + #endif + } + else { + #ifdef DEBUG_SYNCHRO + DebugLog(SynchroFile, "ForceCheck:ActualAccountSO-read enter\n"); + #endif + if ((ActualAccount->Flags & YAMN_ACC_ENA) && ActualAccount->Plugin->Fcn->SynchroFcnPtr) { + struct CheckParam ParamToPlugin = {YAMN_CHECKVERSION, ThreadRunningEV, ActualAccount, lParam?YAMN_FORCECHECK:YAMN_NORMALCHECK, (void *)0, NULL}; + HANDLE NewThread; + + ActualAccount->TimeLeft = ActualAccount->Interval; + if (NewThread = CreateThread(NULL, 0, (YAMN_STANDARDFCN)ActualAccount->Plugin->Fcn->SynchroFcnPtr, &ParamToPlugin, 0, &tid)) { + WaitForSingleObject(ThreadRunningEV, INFINITE); + CloseHandle(NewThread); + } + } + ReadDoneFcn(ActualAccount->AccountAccessSO); + } + LeaveCriticalSection(&PluginRegCS); + CloseHandle(ThreadRunningEV); + } + return 0; +} + +static INT_PTR ContactMailCheck(WPARAM wParam, LPARAM lParam) +{ + char *szProto = (char *)CallService(MS_PROTO_GETCONTACTBASEPROTO, wParam, 0); + if ( lstrcmpA(szProto, YAMN_DBMODULE)) + return 0; + + DBVARIANT dbv; + if ( DBGetContactSetting((HANDLE) wParam, YAMN_DBMODULE, "Id", &dbv)) + return 0; + + HACCOUNT ActualAccount = (HACCOUNT) CallService(MS_YAMN_FINDACCOUNTBYNAME, (WPARAM)POP3Plugin, (LPARAM)dbv.pszVal); + if (ActualAccount != NULL) { + //we use event to signal, that running thread has all needed stack parameters copied + HANDLE ThreadRunningEV; + if (NULL == (ThreadRunningEV = CreateEvent(NULL, FALSE, FALSE, NULL))) + return 0; + //if we want to close miranda, we get event and do not run pop3 checking anymore + if (WAIT_OBJECT_0 == WaitForSingleObject(ExitEV, 0)) + return 0; + EnterCriticalSection(&PluginRegCS); + #ifdef DEBUG_SYNCHRO + DebugLog(SynchroFile, "ForceCheck:ActualAccountSO-read wait\n"); + #endif + if (WAIT_OBJECT_0 != WaitToReadFcn(ActualAccount->AccountAccessSO)) + { + #ifdef DEBUG_SYNCHRO + DebugLog(SynchroFile, "ForceCheck:ActualAccountSO-read wait failed\n"); + #endif + } + else + { + #ifdef DEBUG_SYNCHRO + DebugLog(SynchroFile, "ForceCheck:ActualAccountSO-read enter\n"); + #endif + if ((ActualAccount->Flags & YAMN_ACC_ENA) && (ActualAccount->StatusFlags & YAMN_ACC_FORCE)) //account cannot be forced to check + { + if (ActualAccount->Plugin->Fcn->ForceCheckFcnPtr == NULL) + ReadDoneFcn(ActualAccount->AccountAccessSO); + + DWORD tid; + struct CheckParam ParamToPlugin = {YAMN_CHECKVERSION, ThreadRunningEV, ActualAccount, YAMN_FORCECHECK, (void *)0, NULL}; + if (NULL == CreateThread(NULL, 0, (YAMN_STANDARDFCN)ActualAccount->Plugin->Fcn->ForceCheckFcnPtr, &ParamToPlugin, 0, &tid)) + ReadDoneFcn(ActualAccount->AccountAccessSO); + else + WaitForSingleObject(ThreadRunningEV, INFINITE); + } + ReadDoneFcn(ActualAccount->AccountAccessSO); + } + LeaveCriticalSection(&PluginRegCS); + CloseHandle(ThreadRunningEV); + } + DBFreeVariant(&dbv); + return 0; +} + +void MainMenuAccountClicked(WPARAM wParam, LPARAM lParam) +{ +} + +/*static*/ void ContactDoubleclicked(WPARAM wParam, LPARAM lParam) +{ + char *szProto = (char *)CallService(MS_PROTO_GETCONTACTBASEPROTO, wParam, 0); + if ( lstrcmpA(szProto, YAMN_DBMODULE)) + return; + + DBVARIANT dbv; + if ( DBGetContactSetting(( HANDLE )wParam, YAMN_DBMODULE, "Id", &dbv)) + return; + + HACCOUNT ActualAccount = (HACCOUNT) CallService(MS_YAMN_FINDACCOUNTBYNAME, (WPARAM)POP3Plugin, (LPARAM)dbv.pszVal); + if (ActualAccount != NULL) { + #ifdef DEBUG_SYNCHRO + DebugLog(SynchroFile, "Service_ContactDoubleclicked:ActualAccountSO-read wait\n"); + #endif + if (WAIT_OBJECT_0 == WaitToReadFcn(ActualAccount->AccountAccessSO)) { + #ifdef DEBUG_SYNCHRO + DebugLog(SynchroFile, "Service_ContactDoubleclicked:ActualAccountSO-read enter\n"); + #endif + YAMN_MAILBROWSERPARAM Param = {(HANDLE)0, ActualAccount, ActualAccount->NewMailN.Flags, ActualAccount->NoNewMailN.Flags, 0}; + + Param.nnflags = Param.nnflags | YAMN_ACC_MSG; //show mails in account even no new mail in account + Param.nnflags = Param.nnflags & ~YAMN_ACC_POP; + + Param.nflags = Param.nflags | YAMN_ACC_MSG; //show mails in account even no new mail in account + Param.nflags = Param.nflags & ~YAMN_ACC_POP; + + RunMailBrowserSvc((WPARAM)&Param, (LPARAM)YAMN_MAILBROWSERVERSION); + + #ifdef DEBUG_SYNCHRO + DebugLog(SynchroFile, "Service_ContactDoubleclicked:ActualAccountSO-read done\n"); + #endif + ReadDoneFcn(ActualAccount->AccountAccessSO); + } + #ifdef DEBUG_SYNCHRO + else + DebugLog(SynchroFile, "Service_ContactDoubleclicked:ActualAccountSO-read enter failed\n"); + #endif + + } + DBFreeVariant(&dbv); +} + +///////////////////////////////////////////////////////////////////////////////////////// + +HBITMAP LoadBmpFromIcon(HICON hIcon) +{ + int IconSizeX = 16; + int IconSizeY = 16; + + HBRUSH hBkgBrush = CreateSolidBrush(GetSysColor(COLOR_3DFACE)); + + BITMAPINFOHEADER bih = {0}; + bih.biSize = sizeof(bih); + bih.biBitCount = 24; + bih.biPlanes = 1; + bih.biCompression = BI_RGB; + bih.biHeight = IconSizeY; + bih.biWidth = IconSizeX; + + int widthBytes = ((bih.biWidth*bih.biBitCount + 31) >> 5) * 4; + + RECT rc; + rc.top = rc.left = 0; + rc.right = bih.biWidth; + rc.bottom = bih.biHeight; + + HDC hdc = GetDC(NULL); + HBITMAP hBmp = CreateCompatibleBitmap(hdc, bih.biWidth, bih.biHeight); + HDC hdcMem = CreateCompatibleDC(hdc); + HBITMAP hoBmp = (HBITMAP)SelectObject(hdcMem, hBmp); + FillRect(hdcMem, &rc, hBkgBrush); + DrawIconEx(hdcMem, 0, 0, hIcon, bih.biWidth, bih.biHeight, 0, NULL, DI_NORMAL); + SelectObject(hdcMem, hoBmp); + return hBmp; +} + +int AddTopToolbarIcon(WPARAM,LPARAM) +{ + if ( DBGetContactSettingByte(NULL, YAMN_DBMODULE, YAMN_TTBFCHECK, 1)) { + if ( ServiceExists(MS_TTB_ADDBUTTON) && hTTButton == NULL) { + TTBButton btn = { 0 }; + btn.cbSize = sizeof(TTBButton); + btn.pszServiceUp = MS_YAMN_FORCECHECK; + btn.dwFlags = TTBBF_VISIBLE | TTBBF_SHOWTOOLTIP; + btn.name = Translate("Check mail"); + btn.hbBitmapUp = LoadBmpFromIcon(g_LoadIconEx(5)); + btn.hbBitmapDown = LoadBmpFromIcon(g_LoadIconEx(6)); + hTTButton = (HANDLE)CallService(MS_TTB_ADDBUTTON, (WPARAM)&btn, 0); + CallService(MS_TTB_SETBUTTONOPTIONS, MAKEWPARAM((WORD)TTBO_TIPNAME, (WORD)hTTButton), (LPARAM)Translate("Check mail")); + } + if ( ServiceExists(MS_TB_ADDBUTTON) && hTButton == NULL) { + TBButton btn = { 0 }; + btn.cbSize = sizeof(TBButton); + btn.pszServiceName = MS_YAMN_FORCECHECK; + btn.tbbFlags = TBBF_VISIBLE | TBBF_SHOWTOOLTIP; + btn.defPos = 10114; + btn.pszButtonID = "yamn_btn"; + btn.pszButtonName = "Check mail"; + btn.hPrimaryIconHandle = g_GetIconHandle(5); + btn.hSecondaryIconHandle = g_GetIconHandle(6); + btn.pszTooltipDn = btn.pszTooltipUp = "Check mail"; + hTButton = (HANDLE)CallService(MS_TB_ADDBUTTON, 0, (WPARAM)&btn); + } + } + else { + if (ServiceExists(MS_TTB_ADDBUTTON) && hTTButton != NULL) { + CallService(MS_TTB_REMOVEBUTTON, (WPARAM)hTTButton, 0); + hTTButton = NULL; + } + if (ServiceExists(MS_TB_ADDBUTTON) && hTButton != NULL) { + CallService(MS_TB_REMOVEBUTTON, (WPARAM)hTButton, 0); + hTButton = NULL; + } } + + return 0; +} + +///////////////////////////////////////////////////////////////////////////////////////// + +int Shutdown(WPARAM, LPARAM) +{ + CallService(MS_TTB_REMOVEBUTTON, (WPARAM)hTTButton, 0); + + DBWriteContactSettingDword(NULL, YAMN_DBMODULE, YAMN_DBMSGPOSX, HeadPosX); + DBWriteContactSettingDword(NULL, YAMN_DBMODULE, YAMN_DBMSGPOSY, HeadPosY); + DBWriteContactSettingDword(NULL, YAMN_DBMODULE, YAMN_DBMSGSIZEX, HeadSizeX); + DBWriteContactSettingDword(NULL, YAMN_DBMODULE, YAMN_DBMSGSIZEY, HeadSizeY); + DBWriteContactSettingWord(NULL, YAMN_DBMODULE, YAMN_DBMSGPOSSPLIT, HeadSplitPos); + YAMNVar.Shutdown = TRUE; + KillTimer(NULL, SecTimer); + + UnregisterProtoPlugins(); + UnregisterFilterPlugins(); + return 0; +} + +int SystemModulesLoaded(WPARAM, LPARAM); //in main.cpp +typedef struct { HANDLE hookHandle; const char *hookName; MIRANDAHOOK mirandaFunction;} HookDataType; +static HookDataType hookData[] = { + {0, ME_SYSTEM_MODULESLOADED, SystemModulesLoaded}, //pop3 plugin must be included after all miranda modules are loaded + {0, ME_TB_MODULELOADED, AddTopToolbarIcon}, + {0, ME_TTB_MODULELOADED, AddTopToolbarIcon}, + {0, ME_OPT_INITIALISE, YAMNOptInitSvc}, + {0, ME_SYSTEM_PRESHUTDOWN, Shutdown}, + {0, ME_CLIST_DOUBLECLICKED, Service_ContactDoubleclicked}, + {0, 0, 0}//end marker +}; + +void HookEvents(void) +{ + //We set function which registers needed POP3 accounts. This is a part of internal POP3 plugin. + //Your plugin should do the same task in your Load fcn. Why we call it in MODULESLOADED? Because netlib + //user can be registered after all modules are loaded (see m_netlib.h in Miranda) + for (int i = 0;hookData[i].hookName;i++) { + hookData[i].hookHandle = HookEvent(hookData[i].hookName, hookData[i].mirandaFunction); + } +} +void UnhookEvents(void){ + for (int i = 0;i<(sizeof(hookData)/sizeof(hookData[0]));i++) { + if (hookData[i].hookHandle) UnhookEvent(hookData[i].hookHandle); + } +} + +typedef struct { HANDLE serviceHandle; const char *serviceName; MIRANDASERVICE serviceFunction;} ServiceDataType; +static ServiceDataType serviceData[] = { + {0, YAMN_DBMODULE PS_GETCAPS, Service_GetCaps}, + {0, YAMN_DBMODULE PS_GETSTATUS, Service_GetStatus}, + {0, YAMN_DBMODULE PS_SETSTATUS, Service_SetStatus}, + {0, YAMN_DBMODULE PS_GETNAME, Service_GetName}, + {0, YAMN_DBMODULE PS_LOADICON, Service_LoadIcon}, + + //Function with which protocol plugin can register + {0, MS_YAMN_GETFCNPTR, GetFcnPtrSvc}, + + //Function returns pointer to YAMN variables + {0, MS_YAMN_GETVARIABLES, GetVariablesSvc}, + + //Function with which protocol plugin can register + {0, MS_YAMN_REGISTERPROTOPLUGIN, RegisterProtocolPluginSvc}, + + //Function with which protocol plugin can unregister + {0, MS_YAMN_UNREGISTERPROTOPLUGIN, UnregisterProtocolPluginSvc}, + + //Function creates an account for plugin + {0, MS_YAMN_CREATEPLUGINACCOUNT, CreatePluginAccountSvc}, + + //Function deletes plugin account + {0, MS_YAMN_DELETEPLUGINACCOUNT, DeletePluginAccountSvc}, + + //Finds account for plugin by name + {0, MS_YAMN_FINDACCOUNTBYNAME, FindAccountByNameSvc}, + + //Creates next account for plugin + {0, MS_YAMN_GETNEXTFREEACCOUNT, GetNextFreeAccountSvc}, + + //Function removes account from YAMN queue. Does not delete it from memory + {0, MS_YAMN_DELETEACCOUNT, DeleteAccountSvc}, + + //Function finds accounts for specified plugin + {0, MS_YAMN_READACCOUNTS, AddAccountsFromFileSvc}, + + //Function that stores all plugin mails to one file + {0, MS_YAMN_WRITEACCOUNTS, WriteAccountsToFileSvc}, + + //Function that returns user's filename + {0, MS_YAMN_GETFILENAME, GetFileNameSvc}, + + //Releases unicode string from memory + {0, MS_YAMN_DELETEFILENAME, DeleteFileNameSvc}, + + //Checks mail + {0, MS_YAMN_FORCECHECK, ForceCheckSvc}, + + //Runs YAMN's mail browser + {0, MS_YAMN_MAILBROWSER, RunMailBrowserSvc}, + + //Runs YAMN's bad conenction window + {0, MS_YAMN_BADCONNECTION, RunBadConnectionSvc}, + + //Function creates new mail for plugin + {0, MS_YAMN_CREATEACCOUNTMAIL, CreateAccountMailSvc}, + + //Function deletes plugin account + {0, MS_YAMN_DELETEACCOUNTMAIL, DeleteAccountMailSvc}, + + //Function with which filter plugin can register + {0, MS_YAMN_REGISTERFILTERPLUGIN, RegisterFilterPluginSvc}, + + //Function with which filter plugin can unregister + {0, MS_YAMN_UNREGISTERFILTERPLUGIN, UnregisterFilterPluginSvc}, + + //Function filters mail + {0, MS_YAMN_FILTERMAIL, FilterMailSvc}, + + //Function contact list double click + {0, MS_YAMN_CLISTDBLCLICK, ClistContactDoubleclicked}, + + //Function to check individual account + {0, MS_YAMN_ACCOUNTCHECK, AccountMailCheck}, + + //Function contact list context menu click + {0, MS_YAMN_CLISTCONTEXT, ContactMailCheck}, + + //Function contact list context menu click + {0, MS_YAMN_CLISTCONTEXTAPP, ContactApplication}, + + {0, 0, 0}//end marker +}; + +void CreateServiceFunctions(void) +{ + for (int i = 0;serviceData[i].serviceName;i++) { + serviceData[i].serviceHandle = CreateServiceFunction(serviceData[i].serviceName, serviceData[i].serviceFunction); + } +}; + +void DestroyServiceFunctions(void) +{ + for (int i = 0;serviceData[i].serviceName;i++) { + if (serviceData[i].serviceHandle) DestroyServiceFunction(serviceData[i].serviceHandle); + } +}; + +//Function to put all enabled contact to the Online status +void RefreshContact(void) +{ + HACCOUNT Finder; + for (Finder = POP3Plugin->FirstAccount;Finder != NULL;Finder = Finder->Next) { + if (Finder->hContact != NULL) { + if ((Finder->Flags & YAMN_ACC_ENA) && (Finder->NewMailN.Flags & YAMN_ACC_CONT)) + DBDeleteContactSetting(Finder->hContact, "CList", "Hidden"); + else + DBWriteContactSettingByte(Finder->hContact, "CList", "Hidden", 1); + } + else { + if ((Finder->Flags & YAMN_ACC_ENA) && (Finder->NewMailN.Flags & YAMN_ACC_CONT)) { + Finder->hContact = (HANDLE) CallService(MS_DB_CONTACT_ADD, 0, 0); + CallService(MS_PROTO_ADDTOCONTACT, (WPARAM)Finder->hContact, (LPARAM)YAMN_DBMODULE); + DBWriteContactSettingString(Finder->hContact, YAMN_DBMODULE, "Id", Finder->Name); + DBWriteContactSettingString(Finder->hContact, YAMN_DBMODULE, "Nick", Finder->Name); + DBWriteContactSettingString(Finder->hContact, "Protocol", "p", YAMN_DBMODULE); + DBWriteContactSettingWord(Finder->hContact, YAMN_DBMODULE, "Status", ID_STATUS_ONLINE); + DBWriteContactSettingString(Finder->hContact, "CList", "StatusMsg", Translate("No new mail message")); +} } } } diff --git a/protocols/YAMN/synchro.cpp b/protocols/YAMN/synchro.cpp new file mode 100644 index 0000000000..e510d8bac9 --- /dev/null +++ b/protocols/YAMN/synchro.cpp @@ -0,0 +1,359 @@ +/* + * This code implements synchronization objects code between threads. If you want, you can include it to your + * code. This file is not dependent on any other external code (functions) + * + * (c) majvan 2002-2004 + */ + +#include "yamn.h" + +// Initializes a SWMRG structure. This structure must be +// initialized before any writer or reader threads attempt +// to wait on it. +// The structure must be allocated by the application and +// the structure's address is passed as the first parameter. +// The lpszName parameter is the name of the object. Pass +// NULL if you do not want to share the object. +BOOL WINAPI SWMRGInitialize(PSWMRG pSWMRG,TCHAR *Name); + +// Deletes the system resources associated with a SWMRG +// structure. The structure must be deleted only when +// no writer or reader threads in the calling process +// will wait on it. +void WINAPI SWMRGDelete(PSWMRG pSWMRG); + +// A writer thread calls this function to know when +// it can successfully write to the shared data. +// returns WAIT_FINISH when we are in write-access or WAIT_FAILED +// when event about quick finishing is set (or when system returns fail when waiting for synchro object) +DWORD WINAPI SWMRGWaitToWrite(PSWMRG pSWMRG,DWORD dwTimeout); + +// A writer thread calls this function to let other threads +// know that it no longer needs to write to the shared data. +void WINAPI SWMRGDoneWriting(PSWMRG pSWMRG); + +// A reader thread calls this function to know when +// it can successfully read the shared data. +// returns WAIT_FINISH when we are in read-access or WAIT_FAILED +// when event about quick finishing is set (or when system returns fail when waiting for synchro object) +DWORD WINAPI SWMRGWaitToRead(PSWMRG pSWMRG, DWORD dwTimeout); + +// A reader thread calls this function to let other threads +// know when it no longer needs to read the shared data. +void WINAPI SWMRGDoneReading(PSWMRG pSWMRG); + +// WaitToReadFcn +// is used to wait for read access with SWMRG SO, but it also increments counter if successfull +// returns WAIT_FAILED or WAIT_FINISH +// when WAIT_FAILED, we should not begin to access datas, we are not in read-access mode +DWORD WINAPI WaitToReadFcn(PSWMRG SObject); + +// WriteDoneFcn +// is used to release read access with SWMRG SO, but it also decrements counter if successfull +void WINAPI ReadDoneFcn(PSWMRG SObject); + +// This functions is for export purposes +// Plugin can call this function to manage SCOUNTER synchronization object + +// Gets number value stored in SCOUNTER SO +// Note you must not read the number from memory directly, because +// CPU can stop reading thread when it has read HI-Word, then another thread +// can change the value and then OS starts the previous thread, that reads the +// LO-WORD of DWORD. And the return value HI+LO-WORD is corrupted +DWORD WINAPI SCGetNumberFcn(PSCOUNTER SCounter); + +// Increments SCOUNTER and unsets event +// Returns Number after incrementing +DWORD WINAPI SCIncFcn(PSCOUNTER SCounter); + +// Decrements SCOUNTER and sets event if zero +// Returns Number after decrementing +DWORD WINAPI SCDecFcn(PSCOUNTER SCounter); + +struct CExportedFunctions SynchroExportedFcn[]= +{ + {YAMN_WAITTOWRITEID,(void *)WaitToWriteFcn}, + {YAMN_WRITEDONEID,(void *)WriteDoneFcn}, + {YAMN_WAITTOREADID,(void *)WaitToReadFcn}, + {YAMN_READDONEID,(void *)ReadDoneFcn}, + {YAMN_SCGETNUMBERID,(void *)SCGetNumberFcn}, + {YAMN_SCINCID,(void *)SCIncFcn}, + {YAMN_SCDECID,(void *)SCDecFcn}, +}; + +//-------------------------------------------------------------------------------------------------- +//-------------------------------------------------------------------------------------------------- + +void WINAPI SWMRGDelete(PSWMRG pSWMRG) +{ +// Destroys any synchronization objects that were +// successfully created. + if (NULL!=pSWMRG->hEventNoWriter) + CloseHandle(pSWMRG->hEventNoWriter); + if (NULL!=pSWMRG->hEventNoReaders) + CloseHandle(pSWMRG->hEventNoReaders); + if (NULL!=pSWMRG->hSemNumReaders) + CloseHandle(pSWMRG->hSemNumReaders); + if (NULL!=pSWMRG->hFinishEV) + CloseHandle(pSWMRG->hFinishEV); +} + +BOOL WINAPI SWMRGInitialize(PSWMRG pSWMRG,TCHAR *Name) +{ + pSWMRG->hEventNoWriter=NULL; + pSWMRG->hEventNoReaders=NULL; + pSWMRG->hSemNumReaders=NULL; + pSWMRG->hFinishEV=NULL; + +// Creates the automatic-reset event that is signalled when +// no writer threads are writing. +// Initially no reader threads are reading. + if (Name!=NULL) + Name[0]=(TCHAR)'W'; + pSWMRG->hEventNoWriter=CreateEvent(NULL,FALSE,TRUE,Name); + +// Creates the manual-reset event that is signalled when +// no reader threads are reading. +// Initially no reader threads are reading. + if (Name!=NULL) + Name[0]=(TCHAR)'R'; + pSWMRG->hEventNoReaders=CreateEvent(NULL,TRUE,TRUE,Name); + +// Initializes the variable that indicates the number of +// reader threads that are reading. +// Initially no reader threads are reading. + if (Name!=NULL) + Name[0]=(TCHAR)'C'; + pSWMRG->hSemNumReaders=CreateSemaphore(NULL,0,0x7FFFFFFF,Name); + + if (Name!=NULL) + Name[0]=(TCHAR)'F'; + pSWMRG->hFinishEV=CreateEvent(NULL,TRUE,FALSE,Name); + +// If a synchronization object could not be created, +// destroys any created objects and return failure. + if ((NULL==pSWMRG->hEventNoWriter) || (NULL==pSWMRG->hEventNoReaders) || (NULL==pSWMRG->hSemNumReaders) || (NULL==pSWMRG->hFinishEV)) + { + SWMRGDelete(pSWMRG); + return FALSE; + } + return TRUE; +} + +DWORD WINAPI SWMRGWaitToWrite(PSWMRG pSWMRG,DWORD dwTimeout) +{ + DWORD dw; + HANDLE aHandles[2]; + +// We can write if the following are true: +// 1. No other threads are writing. +// 2. No threads are reading. +// But first we have to know if SWMRG structure is not about to delete + aHandles[0]=pSWMRG->hEventNoWriter; + aHandles[1]=pSWMRG->hEventNoReaders; + if (WAIT_OBJECT_0==(dw=WaitForSingleObject(pSWMRG->hFinishEV,0))) + return WAIT_FINISH; + if (WAIT_FAILED==dw) + return dw; + dw=WaitForMultipleObjects(2,aHandles,TRUE,dwTimeout); +// if a request to delete became later, we should not catch it. Try once more to ask if account is not about to delete + if ((dw!=WAIT_FAILED) && (WAIT_OBJECT_0==(WaitForSingleObject(pSWMRG->hFinishEV,0)))) + { + SetEvent(pSWMRG->hEventNoWriter); + return WAIT_FINISH; + } + +// This thread can write to the shared data. +// Automatic event for NoWriter sets hEventNoWriter to nonsignaled after WaitForMultipleObject + +// Because a writer thread is writing, the Event +// should not be reset. This stops other +// writers and readers. + return dw; +} + +void WINAPI SWMRGDoneWriting(PSWMRG pSWMRG) +// Presumably, a writer thread calling this function has +// successfully called WaitToWrite. This means that we +// do not have to wait on any synchronization objects +// here because the writer already owns the Event. +{ +// Allow other writer/reader threads to use +// the SWMRG synchronization object. + SetEvent(pSWMRG->hEventNoWriter); +} + +DWORD WINAPI SWMRGWaitToRead(PSWMRG pSWMRG, DWORD dwTimeout) +{ + DWORD dw; + LONG lPreviousCount; + +// We can read if no threads are writing. +// And there's not request to delete structure + if (WAIT_OBJECT_0==(dw=WaitForSingleObject(pSWMRG->hFinishEV,0))) + return WAIT_FINISH; + if (WAIT_FAILED==dw) + return dw; + dw=WaitForSingleObject(pSWMRG->hEventNoWriter, dwTimeout); +// if a request to delete became later, we should not catch it. Try once more to ask if account is not about to delete + if ((dw!=WAIT_FAILED) && (WAIT_OBJECT_0==(WaitForSingleObject(pSWMRG->hFinishEV,0)))) + { + SetEvent(pSWMRG->hEventNoWriter); + return WAIT_FINISH; + } + + if (dw==WAIT_OBJECT_0) + { + // This thread can read from the shared data. + // Increment the number of reader threads. + // But there can't be more than one thread incrementing readers, + // so this is why we use semaphore. + ReleaseSemaphore(pSWMRG->hSemNumReaders,1,&lPreviousCount); + if (lPreviousCount==0) + // If this is the first reader thread, + // set event to reflect this. Other reader threads can read, no writer thread can write. + ResetEvent(pSWMRG->hEventNoReaders); + + // Allow other writer/reader threads to use + // the SWMRG synchronization object. hEventNoWrite is still non-signaled + // (it looks like writer is processing thread, but it is not true) + SetEvent(pSWMRG->hEventNoWriter); + } + + return(dw); +} + +void WINAPI SWMRGDoneReading(PSWMRG pSWMRG) +{ + HANDLE aHandles[2]; + LONG lNumReaders; + +// We can stop reading if the events are available, +// but when we stop reading we must also decrement the +// number of reader threads. + aHandles[0]=pSWMRG->hEventNoWriter; + aHandles[1]=pSWMRG->hSemNumReaders; + WaitForMultipleObjects(2,aHandles,TRUE,INFINITE); + +// Get the remaining number of readers by releasing the +// semaphore and then restoring the count by immediately +// performing a wait. + ReleaseSemaphore(pSWMRG->hSemNumReaders,1,&lNumReaders); + WaitForSingleObject(pSWMRG->hSemNumReaders,INFINITE); + +// If there are no remaining readers, +// set the event to relect this. + if (lNumReaders==0) + // If there are no reader threads, + // set our event to reflect this. + SetEvent(pSWMRG->hEventNoReaders); + +// Allow other writer/reader threads to use +// the SWMRG synchronization object. +// (it looks like writer is processing thread, but it is not true) + SetEvent(pSWMRG->hEventNoWriter); +} + +DWORD WINAPI WaitToWriteFcn(PSWMRG SObject,PSCOUNTER SCounter) +{ + DWORD EnterCode; +#ifdef DEBUG_SYNCHRO + DebugLog(SynchroFile,"\tSO WaitToWrite: %x\n",SObject); +#endif + if (WAIT_OBJECT_0==(EnterCode=SWMRGWaitToWrite(SObject,INFINITE))) + if (SCounter!=NULL) + SCIncFcn(SCounter); + return EnterCode; +} + +void WINAPI WriteDoneFcn(PSWMRG SObject,PSCOUNTER SCounter) +{ +#ifdef DEBUG_SYNCHRO + DebugLog(SynchroFile,"\tSO WriteDone: %x\n",SObject); +#endif + SWMRGDoneWriting(SObject); + if (SCounter!=NULL) + SCDecFcn(SCounter); +} + +DWORD WINAPI WaitToReadFcn(PSWMRG SObject) +{ + DWORD EnterCode; +#ifdef DEBUG_SYNCHRO + DebugLog(SynchroFile,"\tSO WaitToRead: %x\n",SObject); +#endif + EnterCode=SWMRGWaitToRead(SObject,INFINITE); + return EnterCode; +} + +void WINAPI ReadDoneFcn(PSWMRG SObject) +{ +#ifdef DEBUG_SYNCHRO + DebugLog(SynchroFile,"\tSO ReadDone: %x\n",SObject); +#endif + SWMRGDoneReading(SObject); +} + +DWORD WINAPI SCGetNumberFcn(PSCOUNTER SCounter) +{ + DWORD Temp; +#ifdef DEBUG_SYNCHRO + DebugLog(SynchroFile,"\tGetNumber-cs wait\n"); +#endif + EnterCriticalSection(&SCounter->CounterCS); +#ifdef DEBUG_SYNCHRO + DebugLog(SynchroFile,"\tGetNumber-cs enter\n"); +#endif + Temp=SCounter->Number; +#ifdef DEBUG_SYNCHRO + DebugLog(SynchroFile,"\tValue: %d\n",Temp); + DebugLog(SynchroFile,"\tGetNumber-cs done\n"); +#endif + LeaveCriticalSection(&SCounter->CounterCS); + return Temp; +} + +DWORD WINAPI SCIncFcn(PSCOUNTER SCounter) +{ + DWORD Temp; +#ifdef DEBUG_SYNCHRO + DebugLog(SynchroFile,"\tIncrementValue-cs wait\n"); +#endif + EnterCriticalSection(&SCounter->CounterCS); +#ifdef DEBUG_SYNCHRO + DebugLog(SynchroFile,"\tIncrementValue-cs enter\n"); +#endif + Temp=++SCounter->Number; + ResetEvent(SCounter->Event); +#ifdef DEBUG_SYNCHRO + DebugLog(SynchroFile,"\tValue: %d\n",Temp); + DebugLog(SynchroFile,"\tIncrementValue-cs done\n"); +#endif + LeaveCriticalSection(&SCounter->CounterCS); + return Temp; +} + +DWORD WINAPI SCDecFcn(PSCOUNTER SCounter) +{ + DWORD Temp; +#ifdef DEBUG_SYNCHRO + DebugLog(SynchroFile,"\tDecrementValue-cs wait\n"); +#endif + EnterCriticalSection(&SCounter->CounterCS); +#ifdef DEBUG_SYNCHRO + DebugLog(SynchroFile,"\tDecrementValue-cs enter\n"); +#endif + if (!(Temp=--SCounter->Number)) + { +#ifdef DEBUG_SYNCHRO + DebugLog(SynchroFile,"\tDecrementValue-zero ev set\n"); +#endif + SetEvent(SCounter->Event); + } +#ifdef DEBUG_SYNCHRO + DebugLog(SynchroFile,"\tValue: %d\n",Temp); + DebugLog(SynchroFile,"\tDecrementValue-cs done\n"); +#endif + LeaveCriticalSection(&SCounter->CounterCS); + return Temp; +} diff --git a/protocols/YAMN/version.h b/protocols/YAMN/version.h new file mode 100644 index 0000000000..e658cfee0c --- /dev/null +++ b/protocols/YAMN/version.h @@ -0,0 +1,3 @@ +#define YAMN_VERSION_H 0,1,2,5 +#define YAMN_VERSION PLUGIN_MAKE_VERSION( 0,1,2,5 ) +#define YAMN_VERSION_C "0.1.2.5" diff --git a/protocols/YAMN/yamn.cpp b/protocols/YAMN/yamn.cpp new file mode 100644 index 0000000000..c1ffda847a --- /dev/null +++ b/protocols/YAMN/yamn.cpp @@ -0,0 +1,334 @@ +/* + * This code implements miscellaneous usefull functions + * + * (c) majvan 2002-2004 + */ + +#include "yamn.h" + +#include "m_yamn.h" +#include "m_protoplugin.h" +#include "m_messages.h" +#include "m_synchro.h" +#include "main.h" + +//-------------------------------------------------------------------------------------------------- +//-------------------------------------------------------------------------------------------------- + +//Plugin registration CS +//Used if we add (register) plugin to YAMN plugins and when we browse through registered plugins +CRITICAL_SECTION PluginRegCS; + +//AccountWriterCS +//We want to store number of writers of Accounts (number of Accounts used for writing) +//If we want to read all accounts (for saving to file) immidiatelly, we have to wait until no account is changing (no thread writing to account) +SCOUNTER *AccountWriterSO; + +//NoExitEV +//Event that is signaled when there's a request to exit, so no new pop3 check should be performed +HANDLE ExitEV; + +//WriteToFileEV +//If this is signaled, write accounts to file is performed. Set this event if you want to actualize your accounts and messages +HANDLE WriteToFileEV; + +//Returns pointer to YAMN exported function +INT_PTR GetFcnPtrSvc(WPARAM wParam, LPARAM lParam); + +//Returns pointer to YAMN variables +INT_PTR GetVariablesSvc(WPARAM wParam, LPARAM); + +// Function every seconds decrements account counter of seconds and checks if they are 0 +// If yes, creates a POP3 thread to check account +void CALLBACK TimerProc(HWND, UINT, UINT, DWORD); + +// Function called to check all accounts immidialtelly +// no params +INT_PTR ForceCheckSvc(WPARAM, LPARAM); + +//thread is running all the time +//waits for WriteToFileEV and then writes all accounts to file +//DWORD WINAPI FileWritingThread(PVOID); + +// Function is called when Miranda notifies plugin that it is about to exit +// Ensures succesfull end of POP3 checking, sets event that no next checking should be performed +// If there's no writer to account (POP3 thread), saves the results to the file +//not used now, perhaps in the future + + +//int ExitProc(WPARAM wParam, LPARAM lParam); + +//-------------------------------------------------------------------------------------------------- +//-------------------------------------------------------------------------------------------------- + +INT_PTR GetFcnPtrSvc(WPARAM wParam, LPARAM lParam) +{ + register int i; + + for (i=0;iNext) + { +#ifdef DEBUG_SYNCHRO + DebugLog(SynchroFile, "TimerProc:AccountBrowserSO-read wait\n"); +#endif + if (WAIT_OBJECT_0!=SWMRGWaitToRead(ActualPlugin->Plugin->AccountBrowserSO, 0)) //we want to access accounts immiadtelly + { +#ifdef DEBUG_SYNCHRO + DebugLog(SynchroFile, "TimerProc:AccountBrowserSO-read enter failed\n"); +#endif + LeaveCriticalSection(&PluginRegCS); + return; + } +#ifdef DEBUG_SYNCHRO + DebugLog(SynchroFile, "TimerProc:AccountBrowserSO-read enter\n"); +#endif + for (ActualAccount=ActualPlugin->Plugin->FirstAccount;ActualAccount!=NULL;ActualAccount=ActualAccount->Next) + { + if (ActualAccount->Plugin==NULL || ActualAccount->Plugin->Fcn==NULL) //account not inited + continue; +#ifdef DEBUG_SYNCHRO + DebugLog(SynchroFile, "TimerProc:ActualAccountSO-read wait\n"); +#endif + if (WAIT_OBJECT_0!=SWMRGWaitToRead(ActualAccount->AccountAccessSO, 0)) + { +#ifdef DEBUG_SYNCHRO + DebugLog(SynchroFile, "TimerProc:ActualAccountSO-read wait failed\n"); +#endif + continue; + } +#ifdef DEBUG_SYNCHRO + + switch(Status) + { + case ID_STATUS_OFFLINE: + DebugLog(SynchroFile, "TimerProc:ActualAccountSO-read enter status offline\n"); + break; + case ID_STATUS_ONLINE: + DebugLog(SynchroFile, "TimerProc:ActualAccountSO-read enter status online\n"); + break; + case ID_STATUS_AWAY: + DebugLog(SynchroFile, "TimerProc:ActualAccountSO-read enter status away\n"); + break; + case ID_STATUS_DND: + DebugLog(SynchroFile, "TimerProc:ActualAccountSO-read enter status dnd\n"); + break; + case ID_STATUS_NA: + DebugLog(SynchroFile, "TimerProc:ActualAccountSO-read enter status na\n"); + break; + case ID_STATUS_OCCUPIED: + DebugLog(SynchroFile, "TimerProc:ActualAccountSO-read enter status occupied\n"); + break; + case ID_STATUS_FREECHAT: + DebugLog(SynchroFile, "TimerProc:ActualAccountSO-read enter status freechat\n"); + break; + case ID_STATUS_INVISIBLE: + DebugLog(SynchroFile, "TimerProc:ActualAccountSO-read enter status invisible\n"); + break; + case ID_STATUS_ONTHEPHONE: + DebugLog(SynchroFile, "TimerProc:ActualAccountSO-read enter status onthephone\n"); + break; + case ID_STATUS_OUTTOLUNCH: + DebugLog(SynchroFile, "TimerProc:ActualAccountSO-read enter status outtolunch\n"); + break; + default: + DebugLog(SynchroFile, "TimerProc:ActualAccountSO-read enter status unknown\n"); + break; + } +#endif + BOOL isAccountCounting = 0; + if ( + (ActualAccount->Flags & YAMN_ACC_ENA) && + (((ActualAccount->StatusFlags & YAMN_ACC_ST0) && (Status<=ID_STATUS_OFFLINE)) || + ((ActualAccount->StatusFlags & YAMN_ACC_ST1) && (Status==ID_STATUS_ONLINE)) || + ((ActualAccount->StatusFlags & YAMN_ACC_ST2) && (Status==ID_STATUS_AWAY)) || + ((ActualAccount->StatusFlags & YAMN_ACC_ST3) && (Status==ID_STATUS_DND)) || + ((ActualAccount->StatusFlags & YAMN_ACC_ST4) && (Status==ID_STATUS_NA)) || + ((ActualAccount->StatusFlags & YAMN_ACC_ST5) && (Status==ID_STATUS_OCCUPIED)) || + ((ActualAccount->StatusFlags & YAMN_ACC_ST6) && (Status==ID_STATUS_FREECHAT)) || + ((ActualAccount->StatusFlags & YAMN_ACC_ST7) && (Status==ID_STATUS_INVISIBLE)) || + ((ActualAccount->StatusFlags & YAMN_ACC_ST8) && (Status==ID_STATUS_ONTHEPHONE)) || + ((ActualAccount->StatusFlags & YAMN_ACC_ST9) && (Status==ID_STATUS_OUTTOLUNCH)))) + { + + if ((!ActualAccount->Interval && !ActualAccount->TimeLeft) || ActualAccount->Plugin->Fcn->TimeoutFcnPtr==NULL) + { + goto ChangeIsCountingStatusLabel; + } + if (ActualAccount->TimeLeft){ + ActualAccount->TimeLeft--; + isAccountCounting = TRUE; + } +#ifdef DEBUG_SYNCHRO + DebugLog(SynchroFile, "TimerProc:time left : %i\n", ActualAccount->TimeLeft); +#endif + WindowList_BroadcastAsync(YAMNVar.MessageWnds, WM_YAMN_CHANGETIME, (WPARAM)ActualAccount, (LPARAM)ActualAccount->TimeLeft); + if (!ActualAccount->TimeLeft) + { + struct CheckParam ParamToPlugin={YAMN_CHECKVERSION, ThreadRunningEV, ActualAccount, YAMN_NORMALCHECK, (void *)0, NULL}; + HANDLE NewThread; + + ActualAccount->TimeLeft=ActualAccount->Interval; + if (NULL==(NewThread=CreateThread(NULL, 0, (YAMN_STANDARDFCN)ActualAccount->Plugin->Fcn->TimeoutFcnPtr, &ParamToPlugin, 0, &tid))) + { +#ifdef DEBUG_SYNCHRO + DebugLog(SynchroFile, "TimerProc:ActualAccountSO-read done\n"); +#endif + ReadDoneFcn(ActualAccount->AccountAccessSO); + continue; + } + else + { + WaitForSingleObject(ThreadRunningEV, INFINITE); + CloseHandle(NewThread); + } + } + + } +ChangeIsCountingStatusLabel: +#ifdef DEBUG_SYNCHRO + DebugLog(SynchroFile, "TimerProc:ActualAccountSO-read done\n"); +#endif + if (((ActualAccount->isCounting)!=0)!=isAccountCounting){ + ActualAccount->isCounting=isAccountCounting; + WORD cStatus = DBGetContactSettingWord(ActualAccount->hContact, YAMN_DBMODULE, "Status", 0); + switch (cStatus){ + case ID_STATUS_ONLINE: + case ID_STATUS_OFFLINE: + DBWriteContactSettingWord(ActualAccount->hContact, YAMN_DBMODULE, "Status", isAccountCounting?ID_STATUS_ONLINE:ID_STATUS_OFFLINE); + default: break; + } + } + ReadDoneFcn(ActualAccount->AccountAccessSO); + } +#ifdef DEBUG_SYNCHRO + DebugLog(SynchroFile, "TimerProc:AccountBrowserSO-read done\n"); +#endif + SWMRGDoneReading(ActualPlugin->Plugin->AccountBrowserSO); + } + LeaveCriticalSection(&PluginRegCS); + CloseHandle(ThreadRunningEV); + return; +} + +INT_PTR ForceCheckSvc(WPARAM, LPARAM) +{ + PYAMN_PROTOPLUGINQUEUE ActualPlugin; + HACCOUNT ActualAccount; + HANDLE ThreadRunningEV; + DWORD tid; + + //we use event to signal, that running thread has all needed stack parameters copied + if (NULL==(ThreadRunningEV=CreateEvent(NULL, FALSE, FALSE, NULL))) + return 0; + //if we want to close miranda, we get event and do not run pop3 checking anymore + if (WAIT_OBJECT_0==WaitForSingleObject(ExitEV, 0)) + return 0; + EnterCriticalSection(&PluginRegCS); + for (ActualPlugin=FirstProtoPlugin;ActualPlugin!=NULL;ActualPlugin=ActualPlugin->Next) + { + #ifdef DEBUG_SYNCHRO + DebugLog(SynchroFile, "ForceCheck:AccountBrowserSO-read wait\n"); + #endif + SWMRGWaitToRead(ActualPlugin->Plugin->AccountBrowserSO, INFINITE); + #ifdef DEBUG_SYNCHRO + DebugLog(SynchroFile, "ForceCheck:AccountBrowserSO-read enter\n"); + #endif + for (ActualAccount=ActualPlugin->Plugin->FirstAccount;ActualAccount!=NULL;ActualAccount=ActualAccount->Next) + { + if (ActualAccount->Plugin->Fcn==NULL) //account not inited + continue; + #ifdef DEBUG_SYNCHRO + DebugLog(SynchroFile, "ForceCheck:ActualAccountSO-read wait\n"); + #endif + if (WAIT_OBJECT_0!=WaitToReadFcn(ActualAccount->AccountAccessSO)) + { + #ifdef DEBUG_SYNCHRO + DebugLog(SynchroFile, "ForceCheck:ActualAccountSO-read wait failed\n"); + #endif + continue; + } + #ifdef DEBUG_SYNCHRO + DebugLog(SynchroFile, "ForceCheck:ActualAccountSO-read enter\n"); + #endif + if ((ActualAccount->Flags & YAMN_ACC_ENA) && (ActualAccount->StatusFlags & YAMN_ACC_FORCE)) //account cannot be forced to check + { + if (ActualAccount->Plugin->Fcn->ForceCheckFcnPtr==NULL) + { + ReadDoneFcn(ActualAccount->AccountAccessSO); + continue; + } + struct CheckParam ParamToPlugin={YAMN_CHECKVERSION, ThreadRunningEV, ActualAccount, YAMN_FORCECHECK, (void *)0, NULL}; + + if (NULL==CreateThread(NULL, 0, (YAMN_STANDARDFCN)ActualAccount->Plugin->Fcn->ForceCheckFcnPtr, &ParamToPlugin, 0, &tid)) + { + ReadDoneFcn(ActualAccount->AccountAccessSO); + continue; + } + else + WaitForSingleObject(ThreadRunningEV, INFINITE); + } + ReadDoneFcn(ActualAccount->AccountAccessSO); + } +#ifdef DEBUG_SYNCHRO + DebugLog(SynchroFile, "ForceCheck:AccountBrowserSO-read done\n"); +#endif + SWMRGDoneReading(ActualPlugin->Plugin->AccountBrowserSO); + } + LeaveCriticalSection(&PluginRegCS); + CloseHandle(ThreadRunningEV); + + if ( hTTButton ) CallService(MS_TTB_SETBUTTONSTATE, (WPARAM)hTTButton, TTBST_RELEASED); + if ( hTButton ) CallService(MS_TB_SETBUTTONSTATE, (WPARAM)hTButton, TBST_RELEASED); + return 1; +} diff --git a/protocols/YAMN/yamn.h b/protocols/YAMN/yamn.h new file mode 100644 index 0000000000..3a7a7f86f0 --- /dev/null +++ b/protocols/YAMN/yamn.h @@ -0,0 +1,286 @@ + +#ifndef __YAMN_H +#define __YAMN_H +#ifndef _WIN32_IE + #define _WIN32_IE 0x0400 +#endif +#ifndef _WIN32_WINNT + #define _WIN32_WINNT 0x0501 +#endif + +#include +#include +#include +#include +#include //For _chdir() + +#define MIRANDA_VER 0x0A00 + +#include //For hotkeys +#include "win2k.h" +#include "newpluginapi.h" //CallService,UnHookEvent +#include "m_utils.h" //window broadcasting +#include "m_system.h" +#include "m_skin.h" +#include "m_langpack.h" +#include "m_clist.h" +#include "m_clui.h" +#include "m_options.h" +#include "m_database.h" //database +#include "m_contacts.h" //contact +#include "m_protocols.h" //protocols +#include "m_protomod.h" //protocols module +#include "m_protosvc.h" +#include "m_toptoolbar.h" +#include "m_toolbar.h" +#include "m_icolib.h" +#include "m_kbdnotify.h" +#include "m_popup.h" +#include "m_updater.h" +#include "m_account.h" //Account structure and all needed structures to cooperate with YAMN +#include "m_messages.h" //Messages sent to YAMN windows +#include "m_mails.h" //use YAMN's mails +#include "mails/m_decode.h" //use decoding macros (needed for header extracting) +#include "browser/m_browser.h" //we want to run YAMN mailbrowser, no new mail notification and bad connect window +#include "resources/resource.h" +#include "m_protoplugin.h" +#include "m_filterplugin.h" +#include "m_yamn.h" //Main YAMN's variables +#include "m_protoplugin.h" //Protocol registration and so on +#include "m_synchro.h" //Synchronization +#include "debug.h" +#include + + +//icons definitions +#define ICONSNUMBER 8 + +//From services.cpp +void CreateServiceFunctions(void); +void DestroyServiceFunctions(void); +void HookEvents(void); +void UnhookEvents(void); +void RefreshContact(void); +void ContactDoubleclicked(WPARAM wParam,LPARAM lParam); +INT_PTR ClistContactDoubleclicked(WPARAM wParam, LPARAM lParam); + +extern CRITICAL_SECTION PluginRegCS; +extern SCOUNTER *AccountWriterSO; +extern HANDLE ExitEV; +extern HANDLE WriteToFileEV; + +//From debug.cpp +#undef YAMN_DEBUG +#ifdef YAMN_DEBUG +void InitDebug(); +void UnInitDebug(); +#endif + +//From synchro.cpp +//struct CExportedFunctions SynchroExported[]; + +//From yamn.cpp +INT_PTR GetFcnPtrSvc(WPARAM wParam,LPARAM lParam); +INT_PTR GetVariablesSvc(WPARAM,LPARAM); +void CALLBACK TimerProc(HWND,UINT,UINT,DWORD); +INT_PTR ForceCheckSvc(WPARAM,LPARAM); + +extern struct YAMNExportedFcns *pYAMNFcn; + +//From account.cpp +extern CRITICAL_SECTION AccountStatusCS; +extern CRITICAL_SECTION FileWritingCS; + +INT_PTR CreatePluginAccountSvc(WPARAM wParam,LPARAM lParam); +INT_PTR DeletePluginAccountSvc(WPARAM wParam,LPARAM); +int InitAccount(HACCOUNT Which); +void DeInitAccount(HACCOUNT Which); +void StopSignalFcn(HACCOUNT Which); +void CodeDecodeString(char *Dest,BOOL Encrypt); +DWORD FileToMemory(TCHAR *FileName,char **MemFile,char **End); + +#if defined(DEBUG_FILEREAD) || defined(DEBUG_FILEREADMESSAGES) +DWORD ReadStringFromMemory(char **Parser,char *End,char **StoreTo,char *DebugString); +#endif +DWORD ReadStringFromMemory(char **Parser,char *End,char **StoreTo); +#ifndef UNICODE + #if defined(DEBUG_FILEREAD) || defined(DEBUG_FILEREADMESSAGES) +DWORD ReadStringFromMemoryW(WCHAR **Parser,WCHAR *End,WCHAR **StoreTo,WCHAR *DebugString); + #endif //if defined(DEBUG...) +DWORD ReadStringFromMemoryW(WCHAR **Parser,WCHAR *End,WCHAR **StoreTo); +#endif //ifdef Unicode + +DWORD ReadMessagesFromMemory(HACCOUNT Which,char **Parser,char *End); +DWORD ReadAccountFromMemory(HACCOUNT Which,char **Parser,TCHAR *End); +INT_PTR AddAccountsFromFileSvc(WPARAM wParam,LPARAM lParam); + +DWORD WriteStringToFile(HANDLE File,char *Source); +#ifndef UNICODE +#define WriteStringToFileW WriteStringToFile +#else +DWORD WriteStringToFileW(HANDLE File,WCHAR *Source); +#endif + +DWORD WriteMessagesToFile(HANDLE File,HACCOUNT Which); +DWORD WINAPI WritePOP3Accounts(); +INT_PTR WriteAccountsToFileSvc(WPARAM wParam,LPARAM lParam); +INT_PTR FindAccountByNameSvc(WPARAM wParam,LPARAM lParam); +INT_PTR GetNextFreeAccountSvc(WPARAM wParam,LPARAM lParam); + +INT_PTR DeleteAccountSvc(WPARAM wParam,LPARAM); +DWORD WINAPI DeleteAccountInBackground(LPVOID Which); +int StopAccounts(HYAMNPROTOPLUGIN Plugin); +int WaitForAllAccounts(HYAMNPROTOPLUGIN Plugin,BOOL GetAccountBrowserAccess=FALSE); +int DeleteAccounts(HYAMNPROTOPLUGIN Plugin); + +void WINAPI GetStatusFcn(HACCOUNT Which,TCHAR *Value); +void WINAPI SetStatusFcn(HACCOUNT Which,TCHAR *Value); + +INT_PTR UnregisterProtoPlugins(); +INT_PTR RegisterProtocolPluginSvc(WPARAM,LPARAM); +INT_PTR UnregisterProtocolPluginSvc(WPARAM,LPARAM); +INT_PTR GetFileNameSvc(WPARAM,LPARAM); +INT_PTR DeleteFileNameSvc(WPARAM,LPARAM); + +//From filterplugin.cpp +//struct CExportedFunctions FilterPluginExported[]; +INT_PTR UnregisterFilterPlugins(); +INT_PTR RegisterFilterPluginSvc(WPARAM,LPARAM); +INT_PTR UnregisterFilterPluginSvc(WPARAM,LPARAM); +INT_PTR FilterMailSvc(WPARAM,LPARAM); + +//From mails.cpp (MIME) +//struct CExportedFunctions MailExported[]; +INT_PTR CreateAccountMailSvc(WPARAM wParam,LPARAM lParam); +INT_PTR DeleteAccountMailSvc(WPARAM wParam,LPARAM lParam); +INT_PTR LoadMailDataSvc(WPARAM wParam,LPARAM lParam); +INT_PTR UnloadMailDataSvc(WPARAM wParam,LPARAM); +INT_PTR SaveMailDataSvc(WPARAM wParam,LPARAM lParam); + +//From mime.cpp +//void WINAPI ExtractHeaderFcn(char *,int,WORD,HYAMNMAIL); //already in MailExported +struct _tcptable +{ + char *NameBase,*NameSub; + BOOLEAN isValid; + unsigned short int CP; +}; +extern struct _tcptable CodePageNamesAll[]; // in mime/decode.cpp +extern int CPLENALL; +extern struct _tcptable *CodePageNamesSupp; // in mime/decode.cpp +extern int CPLENSUPP; + +extern int PosX,PosY,SizeX,SizeY; +extern int HeadPosX,HeadPosY,HeadSizeX,HeadSizeY,HeadSplitPos; + +//#define CPDEFINDEX 63 //ISO-8859-1 +#define CPDEFINDEX 0 //ACP + +//From pop3comm.cpp +int RegisterPOP3Plugin(WPARAM,LPARAM); + +//From mailbrowser.cpp +INT_PTR RunMailBrowserSvc(WPARAM,LPARAM); + +//From badconnect.cpp +INT_PTR RunBadConnectionSvc(WPARAM,LPARAM); + +//From YAMNopts.cpp +int YAMNOptInitSvc(WPARAM,LPARAM); + +//From main.cpp +int PostLoad(WPARAM,LPARAM); //Executed after all plugins loaded YAMN reads mails from file and notify every protocol it should set its functions +int Shutdown(WPARAM,LPARAM); //Executed before Miranda is going to shutdown +int AddTopToolbarIcon(WPARAM,LPARAM); //Executed when TopToolBar plugin loaded Adds bitmap to toolbar + +extern TCHAR UserDirectory[]; //e.g. "F:\WINNT\Profiles\UserXYZ" +extern TCHAR ProfileName[]; //e.g. "majvan" +extern SWMRG *AccountBrowserSO; +extern CRITICAL_SECTION PluginRegCS; +extern YAMN_VARIABLES YAMNVar; +extern HANDLE hNewMailHook; +extern HANDLE WriteToFileEV; +extern HANDLE hTTButton, hTButton; +extern HCURSOR hCurSplitNS, hCurSplitWE; +extern UINT SecTimer; + +HANDLE WINAPI g_GetIconHandle( int idx ); +HICON WINAPI g_LoadIconEx( int idx, bool big = false ); +void WINAPI g_ReleaseIcon( HICON hIcon ); + +//From synchro.cpp +void WINAPI DeleteMessagesToEndFcn(HACCOUNT Account,HYAMNMAIL From); +DWORD WINAPI WaitToWriteFcn(PSWMRG SObject,PSCOUNTER SCounter=NULL); +void WINAPI WriteDoneFcn(PSWMRG SObject,PSCOUNTER SCounter=NULL); +DWORD WINAPI WaitToReadFcn(PSWMRG SObject); +void WINAPI ReadDoneFcn(PSWMRG SObject); +DWORD WINAPI SCIncFcn(PSCOUNTER SCounter); +DWORD WINAPI SCDecFcn(PSCOUNTER SCounter); +BOOL WINAPI SWMRGInitialize(PSWMRG,TCHAR *); +void WINAPI SWMRGDelete(PSWMRG); +DWORD WINAPI SWMRGWaitToWrite(PSWMRG pSWMRG,DWORD dwTimeout); +void WINAPI SWMRGDoneWriting(PSWMRG pSWMRG); +DWORD WINAPI SWMRGWaitToRead(PSWMRG pSWMRG, DWORD dwTimeout); +void WINAPI SWMRGDoneReading(PSWMRG pSWMRG); + +//From mails.cpp +void WINAPI DeleteMessageFromQueueFcn(HYAMNMAIL *From,HYAMNMAIL Which,int mode); +void WINAPI SetRemoveFlagsInQueueFcn(HYAMNMAIL From,DWORD FlagsSet,DWORD FlagsNotSet,DWORD FlagsToSet,int mode); + +//From mime.cpp +void ExtractHeader(struct CMimeItem *items,int &CP,struct CHeader *head); +void ExtractShortHeader(struct CMimeItem *items,struct CShortHeader *head); +void DeleteHeaderContent(struct CHeader *head); +void DeleteShortHeaderContent(struct CShortHeader *head); +char *ExtractFromContentType(char *ContentType,char *value); +WCHAR *ParseMultipartBody(char *src, char *bond); + +//From account.cpp +void WINAPI GetStatusFcn(HACCOUNT Which,TCHAR *Value); +extern int StopAccounts(HYAMNPROTOPLUGIN Plugin); +extern int DeleteAccounts(HYAMNPROTOPLUGIN Plugin); +extern int WaitForAllAccounts(HYAMNPROTOPLUGIN Plugin,BOOL GetAccountBrowserAccess); + +extern HYAMNPROTOPLUGIN POP3Plugin; + +//from decode.cpp +int DecodeQuotedPrintable(char *Src,char *Dst,int DstLen, BOOL isQ); +int DecodeBase64(char *Src,char *Dst,int DstLen); + +//From maild.cpp +extern INT_PTR LoadMailDataSvc(WPARAM wParam,LPARAM lParam); +extern INT_PTR UnloadMailDataSvc(WPARAM wParam,LPARAM); +extern INT_PTR SaveMailDataSvc(WPARAM wParam,LPARAM lParam); + +//From filterplugin.cpp +extern PYAMN_FILTERPLUGINQUEUE FirstFilterPlugin; + +//From protoplugin.cpp +extern PYAMN_PROTOPLUGINQUEUE FirstProtoPlugin; + +extern struct CExportedFunctions ProtoPluginExportedFcn[1]; +extern struct CExportedServices ProtoPluginExportedSvc[5]; +//From filterplugin.cpp +extern struct CExportedFunctions FilterPluginExportedFcn[1]; +extern struct CExportedServices FilterPluginExportedSvc[2]; +//From synchro.cpp +extern struct CExportedFunctions SynchroExportedFcn[7]; +//From account.cpp +extern struct CExportedFunctions AccountExportedFcn[2]; +extern struct CExportedServices AccountExportedSvc[9]; +//From mails.cpp (MIME) +extern struct CExportedFunctions MailExportedFcn[8]; +extern struct CExportedServices MailExportedSvc[5]; + +extern char *iconDescs[]; +extern char *iconNames[]; +extern HIMAGELIST CSImages; + +extern void __stdcall SSL_DebugLog( const char *fmt, ... ); + +extern int YAMN_STATUS; + +extern PYAMN_VARIABLES pYAMNVar; +extern HYAMNPROTOPLUGIN POP3Plugin; + +#endif -- cgit v1.2.3