summaryrefslogtreecommitdiff
path: root/protocols
diff options
context:
space:
mode:
Diffstat (limited to 'protocols')
-rw-r--r--protocols/NewsAggregator/AtomText.txt482
-rw-r--r--protocols/NewsAggregator/NewsAggregator_10.sln26
-rw-r--r--protocols/NewsAggregator/NewsAggregator_10.vcxproj210
-rw-r--r--protocols/NewsAggregator/NewsAggregator_10.vcxproj.filters79
-rw-r--r--protocols/NewsAggregator/Res/AddFeed.icobin0 -> 318 bytes
-rw-r--r--protocols/NewsAggregator/Res/CheckALL.icobin0 -> 318 bytes
-rw-r--r--protocols/NewsAggregator/Res/Export.icobin0 -> 318 bytes
-rw-r--r--protocols/NewsAggregator/Res/Import.icobin0 -> 318 bytes
-rw-r--r--protocols/NewsAggregator/Res/Main.icobin0 -> 6318 bytes
-rw-r--r--protocols/NewsAggregator/Resource.rc148
-rw-r--r--protocols/NewsAggregator/RssText.txt713
-rw-r--r--protocols/NewsAggregator/Src/Common.h162
-rw-r--r--protocols/NewsAggregator/Src/Entities.cpp381
-rw-r--r--protocols/NewsAggregator/Src/Icons.cpp79
-rw-r--r--protocols/NewsAggregator/Src/Menus.cpp78
-rw-r--r--protocols/NewsAggregator/Src/NewsAggregator.cpp136
-rw-r--r--protocols/NewsAggregator/Src/Options.cpp649
-rw-r--r--protocols/NewsAggregator/Src/Services.cpp240
-rw-r--r--protocols/NewsAggregator/Src/Update.cpp147
-rw-r--r--protocols/NewsAggregator/Src/Utils.cpp1404
-rw-r--r--protocols/NewsAggregator/ToDo.txt11
-rw-r--r--protocols/NewsAggregator/Version.h28
-rw-r--r--protocols/NewsAggregator/Version.rc38
-rw-r--r--protocols/NewsAggregator/resource.h39
-rw-r--r--protocols/Quotes/Base64.cpp43
-rw-r--r--protocols/Quotes/Base64.h12
-rw-r--r--protocols/Quotes/Chart.h280
-rw-r--r--protocols/Quotes/ComHelper.cpp39
-rw-r--r--protocols/Quotes/ComHelper.h9
-rw-r--r--protocols/Quotes/CommonOptionDlg.cpp272
-rw-r--r--protocols/Quotes/CommonOptionDlg.h17
-rw-r--r--protocols/Quotes/CreateFilePath.cpp45
-rw-r--r--protocols/Quotes/CreateFilePath.h8
-rw-r--r--protocols/Quotes/CurrencyConverter.cpp309
-rw-r--r--protocols/Quotes/CurrencyConverter.h6
-rw-r--r--protocols/Quotes/DBUtils.cpp70
-rw-r--r--protocols/Quotes/DBUtils.h16
-rw-r--r--protocols/Quotes/EconomicRateInfo.h59
-rw-r--r--protocols/Quotes/ExtraImages.cpp143
-rw-r--r--protocols/Quotes/ExtraImages.h39
-rw-r--r--protocols/Quotes/Forex.cpp517
-rw-r--r--protocols/Quotes/Forex.rc573
-rw-r--r--protocols/Quotes/Forex.sln26
-rw-r--r--protocols/Quotes/Forex.vcxproj289
-rw-r--r--protocols/Quotes/Forex.vcxproj.filters307
-rw-r--r--protocols/Quotes/HTMLParserMS.cpp313
-rw-r--r--protocols/Quotes/HTMLParserMS.h36
-rw-r--r--protocols/Quotes/HTTPSession.cpp262
-rw-r--r--protocols/Quotes/HTTPSession.h27
-rw-r--r--protocols/Quotes/IHTMLEngine.h18
-rw-r--r--protocols/Quotes/IHTMLParser.h41
-rw-r--r--protocols/Quotes/IQuotesProvider.h41
-rw-r--r--protocols/Quotes/IXMLEngine.h43
-rw-r--r--protocols/Quotes/IconLib.cpp106
-rw-r--r--protocols/Quotes/IconLib.h21
-rw-r--r--protocols/Quotes/ImportExport.cpp850
-rw-r--r--protocols/Quotes/ImportExport.h11
-rw-r--r--protocols/Quotes/IsWithinAccuracy.h15
-rw-r--r--protocols/Quotes/LightMutex.cpp22
-rw-r--r--protocols/Quotes/LightMutex.h34
-rw-r--r--protocols/Quotes/Locale.cpp75
-rw-r--r--protocols/Quotes/Locale.h9
-rw-r--r--protocols/Quotes/Log.cpp56
-rw-r--r--protocols/Quotes/Log.h13
-rw-r--r--protocols/Quotes/ModuleInfo.cpp150
-rw-r--r--protocols/Quotes/ModuleInfo.h46
-rw-r--r--protocols/Quotes/OptionDukasCopy.cpp414
-rw-r--r--protocols/Quotes/OptionDukasCopy.h8
-rw-r--r--protocols/Quotes/QuoteChart.cpp408
-rw-r--r--protocols/Quotes/QuoteChart.h12
-rw-r--r--protocols/Quotes/QuoteInfoDlg.cpp353
-rw-r--r--protocols/Quotes/QuoteInfoDlg.h11
-rw-r--r--protocols/Quotes/QuotesProviderBase.cppbin0 -> 59044 bytes
-rw-r--r--protocols/Quotes/QuotesProviderBase.h112
-rw-r--r--protocols/Quotes/QuotesProviderDukasCopy.cppbin0 -> 15324 bytes
-rw-r--r--protocols/Quotes/QuotesProviderDukasCopy.h38
-rw-r--r--protocols/Quotes/QuotesProviderFinance.cpp318
-rw-r--r--protocols/Quotes/QuotesProviderFinance.h21
-rw-r--r--protocols/Quotes/QuotesProviderGoogle.cpp543
-rw-r--r--protocols/Quotes/QuotesProviderGoogle.h42
-rw-r--r--protocols/Quotes/QuotesProviderGoogleFinance.cpp366
-rw-r--r--protocols/Quotes/QuotesProviderGoogleFinance.h25
-rw-r--r--protocols/Quotes/QuotesProviderVisitor.h25
-rw-r--r--protocols/Quotes/QuotesProviderVisitorDbSettings.cpp157
-rw-r--r--protocols/Quotes/QuotesProviderVisitorDbSettings.h49
-rw-r--r--protocols/Quotes/QuotesProviderVisitorFormatSpecificator.cpp63
-rw-r--r--protocols/Quotes/QuotesProviderVisitorFormatSpecificator.h36
-rw-r--r--protocols/Quotes/QuotesProviderVisitorFormater.cpp216
-rw-r--r--protocols/Quotes/QuotesProviderVisitorFormater.h32
-rw-r--r--protocols/Quotes/QuotesProviderVisitorTendency.cpp70
-rw-r--r--protocols/Quotes/QuotesProviderVisitorTendency.h29
-rw-r--r--protocols/Quotes/QuotesProviderYahoo.cpp193
-rw-r--r--protocols/Quotes/QuotesProviderYahoo.h20
-rw-r--r--protocols/Quotes/QuotesProviders.cpp120
-rw-r--r--protocols/Quotes/QuotesProviders.h32
-rw-r--r--protocols/Quotes/SettingsDlg.cpp1148
-rw-r--r--protocols/Quotes/SettingsDlg.h118
-rw-r--r--protocols/Quotes/Utility/DukasCopy.py48
-rw-r--r--protocols/Quotes/Utility/Dukascopy.xml1635
-rw-r--r--protocols/Quotes/Utility/Google.py52
-rw-r--r--protocols/Quotes/Utility/GoogleFinance.xml7
-rw-r--r--protocols/Quotes/Utility/Quotes_Readme.txt112
-rw-r--r--protocols/Quotes/Utility/Yahoo.xml7
-rw-r--r--protocols/Quotes/Utility/google.xml91
-rw-r--r--protocols/Quotes/Version.rc41
-rw-r--r--protocols/Quotes/WinCtrlHelper.cpp49
-rw-r--r--protocols/Quotes/WinCtrlHelper.h37
-rw-r--r--protocols/Quotes/WorkingThread.cpp15
-rw-r--r--protocols/Quotes/WorkingThread.h6
-rw-r--r--protocols/Quotes/XMLEngineMI.cpp230
-rw-r--r--protocols/Quotes/XMLEngineMI.h17
-rw-r--r--protocols/Quotes/dllmain.cpp23
-rw-r--r--protocols/Quotes/proto_Quotes/proto_Quotes.rc122
-rw-r--r--protocols/Quotes/proto_Quotes/proto_Quotes_10.vcxproj129
-rw-r--r--protocols/Quotes/proto_Quotes/proto_Quotes_10.vcxproj.filters28
-rw-r--r--protocols/Quotes/res/CurrencyConverter.icobin0 -> 5430 bytes
-rw-r--r--protocols/Quotes/res/Export quotes.icobin0 -> 1150 bytes
-rw-r--r--protocols/Quotes/res/Import quotes.icobin0 -> 1150 bytes
-rw-r--r--protocols/Quotes/res/Refresh.icobin0 -> 1406 bytes
-rw-r--r--protocols/Quotes/res/Section.icobin0 -> 1406 bytes
-rw-r--r--protocols/Quotes/res/down.icobin0 -> 1406 bytes
-rw-r--r--protocols/Quotes/res/main.icobin0 -> 1150 bytes
-rw-r--r--protocols/Quotes/res/notchanged.icobin0 -> 1406 bytes
-rw-r--r--protocols/Quotes/res/proto_na.icobin0 -> 1406 bytes
-rw-r--r--protocols/Quotes/res/proto_occupied.icobin0 -> 1406 bytes
-rw-r--r--protocols/Quotes/res/proto_offline.icobin0 -> 1406 bytes
-rw-r--r--protocols/Quotes/res/proto_online.icobin0 -> 1406 bytes
-rw-r--r--protocols/Quotes/res/quote.icobin0 -> 1406 bytes
-rw-r--r--protocols/Quotes/res/swap.icobin0 -> 318 bytes
-rw-r--r--protocols/Quotes/res/up.icobin0 -> 1406 bytes
-rw-r--r--protocols/Quotes/resource.h109
-rw-r--r--protocols/Quotes/stdafx.cpp8
-rw-r--r--protocols/Quotes/stdafx.h165
-rw-r--r--protocols/Quotes/targetver.h24
-rw-r--r--protocols/Quotes/version.h25
-rw-r--r--protocols/Twitter/LICENSE.txt674
-rw-r--r--protocols/Twitter/README.txt10
-rw-r--r--protocols/Twitter/chat.cpp206
-rw-r--r--protocols/Twitter/common.h80
-rw-r--r--protocols/Twitter/connection.cpp435
-rw-r--r--protocols/Twitter/contacts.cpp288
-rw-r--r--protocols/Twitter/http.cpp39
-rw-r--r--protocols/Twitter/http.h39
-rw-r--r--protocols/Twitter/icons/twitter.icobin0 -> 1406 bytes
-rw-r--r--protocols/Twitter/main.cpp168
-rw-r--r--protocols/Twitter/proto.cpp528
-rw-r--r--protocols/Twitter/proto.h179
-rw-r--r--protocols/Twitter/resource.h47
-rw-r--r--protocols/Twitter/stubs.cpp140
-rw-r--r--protocols/Twitter/theme.cpp183
-rw-r--r--protocols/Twitter/theme.h25
-rw-r--r--protocols/Twitter/tinyjson.hpp586
-rw-r--r--protocols/Twitter/twitter.cpp380
-rw-r--r--protocols/Twitter/twitter.h96
-rw-r--r--protocols/Twitter/twitter.rc224
-rw-r--r--protocols/Twitter/twitter.sln26
-rw-r--r--protocols/Twitter/twitter.vcxproj127
-rw-r--r--protocols/Twitter/twitter.vcxproj.filters94
-rw-r--r--protocols/Twitter/ui.cpp529
-rw-r--r--protocols/Twitter/ui.h25
-rw-r--r--protocols/Twitter/utility.cpp133
-rw-r--r--protocols/Twitter/utility.h107
-rw-r--r--protocols/Twitter/version.h20
-rw-r--r--protocols/YAMN/ChangeLog.txt243
-rw-r--r--protocols/YAMN/YAMN_10.sln26
-rw-r--r--protocols/YAMN/YAMN_10.vcxproj222
-rw-r--r--protocols/YAMN/YAMN_10.vcxproj.filters131
-rw-r--r--protocols/YAMN/YAMNopts.cpp2
-rw-r--r--protocols/YAMN/account.cpp1309
-rw-r--r--protocols/YAMN/browser/badconnect.cpp345
-rw-r--r--protocols/YAMN/browser/m_browser.h42
-rw-r--r--protocols/YAMN/browser/mailbrowser.cpp2605
-rw-r--r--protocols/YAMN/debug.cpp139
-rw-r--r--protocols/YAMN/debug.h71
-rw-r--r--protocols/YAMN/docs/InstallScript.xml49
-rw-r--r--protocols/YAMN/docs/YAMN-License.txt340
-rw-r--r--protocols/YAMN/docs/YAMN-Readme.developers.txt205
-rw-r--r--protocols/YAMN/docs/YAMN-Readme.txt79
-rw-r--r--protocols/YAMN/docs/language.pop3.txt118
-rw-r--r--protocols/YAMN/docs/language.txt75
-rw-r--r--protocols/YAMN/filter/Base/AggressiveOptimize.h168
-rw-r--r--protocols/YAMN/filter/Base/Base.dsp108
-rw-r--r--protocols/YAMN/filter/Base/Base.mak229
-rw-r--r--protocols/YAMN/filter/Base/debug.cpp73
-rw-r--r--protocols/YAMN/filter/Base/docs/base-readme.txt63
-rw-r--r--protocols/YAMN/filter/Base/maindll.cpp238
-rw-r--r--protocols/YAMN/filter/Simple/AggressiveOptimize.h168
-rw-r--r--protocols/YAMN/filter/Simple/docs/simple-readme.txt51
-rw-r--r--protocols/YAMN/filter/Simple/maindll.cpp132
-rw-r--r--protocols/YAMN/filter/Simple/simple.dsp105
-rw-r--r--protocols/YAMN/filter/Simple/simple.mak207
-rw-r--r--protocols/YAMN/filter/readme.txt1
-rw-r--r--protocols/YAMN/filterplugin.cpp204
-rw-r--r--protocols/YAMN/icons/iconttbup.icobin0 -> 1150 bytes
-rw-r--r--protocols/YAMN/icons/icoyamn1.icobin0 -> 1150 bytes
-rw-r--r--protocols/YAMN/icons/icoyamn2.icobin0 -> 1150 bytes
-rw-r--r--protocols/YAMN/icons/proto_YAMN.rc19
-rw-r--r--protocols/YAMN/icons/proto_YAMN_10.vcxproj145
-rw-r--r--protocols/YAMN/icons/proto_YAMN_10.vcxproj.filters37
-rw-r--r--protocols/YAMN/icons/resource.h2
-rw-r--r--protocols/YAMN/include/IcoLib.h26
-rw-r--r--protocols/YAMN/mails/decode.cpp558
-rw-r--r--protocols/YAMN/mails/m_decode.h25
-rw-r--r--protocols/YAMN/mails/mails.cpp499
-rw-r--r--protocols/YAMN/mails/mime.cpp732
-rw-r--r--protocols/YAMN/mails/test/header.txt28
-rw-r--r--protocols/YAMN/mails/test/header2.txt97
-rw-r--r--protocols/YAMN/mails/test/readme.txt4
-rw-r--r--protocols/YAMN/mails/test/test.cpp42
-rw-r--r--protocols/YAMN/mails/test/test.dsp112
-rw-r--r--protocols/YAMN/mails/test/test.dsw29
-rw-r--r--protocols/YAMN/main.cpp566
-rw-r--r--protocols/YAMN/main.h61
-rw-r--r--protocols/YAMN/mingw/base.dev69
-rw-r--r--protocols/YAMN/mingw/base.win38
-rw-r--r--protocols/YAMN/mingw/simple.dev59
-rw-r--r--protocols/YAMN/mingw/simple.win35
-rw-r--r--protocols/YAMN/mingw/yamn-2in1.dev469
-rw-r--r--protocols/YAMN/mingw/yamn-2in1.win92
-rw-r--r--protocols/YAMN/mingw/yamn-w9x.dev469
-rw-r--r--protocols/YAMN/mingw/yamn-w9x.win92
-rw-r--r--protocols/YAMN/mingw/yamn.dev469
-rw-r--r--protocols/YAMN/mingw/yamn.win92
-rw-r--r--protocols/YAMN/proto/md5.c260
-rw-r--r--protocols/YAMN/proto/md5.h27
-rw-r--r--protocols/YAMN/proto/netclient.h22
-rw-r--r--protocols/YAMN/proto/netlib.cpp271
-rw-r--r--protocols/YAMN/proto/netlib.h55
-rw-r--r--protocols/YAMN/proto/pop3/pop3.cpp370
-rw-r--r--protocols/YAMN/proto/pop3/pop3.h66
-rw-r--r--protocols/YAMN/proto/pop3/pop3comm.cpp1563
-rw-r--r--protocols/YAMN/proto/pop3/pop3comm.h97
-rw-r--r--protocols/YAMN/proto/pop3/pop3opt.cpp1556
-rw-r--r--protocols/YAMN/proto/pop3/pop3opt.h42
-rw-r--r--protocols/YAMN/protoplugin.cpp197
-rw-r--r--protocols/YAMN/resources/YAMN.rc344
-rw-r--r--protocols/YAMN/resources/iconeutral.icobin0 -> 1150 bytes
-rw-r--r--protocols/YAMN/resources/iconttbdown.icobin0 -> 1150 bytes
-rw-r--r--protocols/YAMN/resources/icooffline.icobin0 -> 1150 bytes
-rw-r--r--protocols/YAMN/resources/icoyamn3.icobin0 -> 1150 bytes
-rw-r--r--protocols/YAMN/resources/resource.h129
-rw-r--r--protocols/YAMN/resources/yamn.bmpbin0 -> 502 bytes
-rw-r--r--protocols/YAMN/resources/yamn_ver.rc77
-rw-r--r--protocols/YAMN/services.cpp515
-rw-r--r--protocols/YAMN/synchro.cpp359
-rw-r--r--protocols/YAMN/version.h3
-rw-r--r--protocols/YAMN/yamn.cpp334
-rw-r--r--protocols/YAMN/yamn.h286
248 files changed, 42852 insertions, 0 deletions
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 @@
+<?xml version="1.0"?>
+
+<feed xmlns="http://www.w3.org/2005/Atom">
+ <updated>2012-01-04T06:45:38Z</updated>
+ <id>http://code.google.com/feeds/p/watcher-miranda/updates/basic</id>
+
+ <title>watcher-miranda project updates - Google Code</title>
+
+ <link rel="self" type="application/atom+xml;type=feed" href="http://code.google.com/feeds/p/watcher-miranda/updates/basic"/>
+ <link rel="alternate" type="text/html" href="http://code.google.com/p/watcher-miranda/updates/list"/>
+
+ <entry>
+ <updated>2012-01-04T06:45:38Z</updated>
+ <id>http://code.google.com/feeds/p/watcher-miranda/updates/basic/z12pftbjzm31hlgp204cepjgmoicsl1oq1w</id>
+ <link rel="alternate" type="text/html" href="http://code.google.com/p/watcher-miranda/downloads/detail?name=miranda-0.10.latest-vc2010_x64-static.7z" />
+ <title type="html">&lt;a class=&quot;ot-download-link&quot; href=&quot;http://code.google.com/p/watcher-miranda/downloads/detail?name=miranda-0.10.latest-vc2010_x64-static.7z&quot;&gt;miranda-0.10.latest-vc2010_x64-static.7z&lt;/a&gt; (Miranda IM 0.10.0 Alpha #2 VC2010 x64) file uploaded by &lt;a class=&quot;ot-profile-link-2&quot; href=&quot;http://code.google.com/u/watcherhd/&quot;&gt;watcherhd&lt;/a&gt;</title>
+ <author>
+ <name>watcherhd</name>
+ </author>
+ <category term="ProjectNewDownload" scheme="http://code.google.com/updates/type"/>
+ <content type="html">&lt;div class=&quot;ot-labels-field-wrapper&quot;&gt;
+ &lt;span class=&quot;ot-labels-field-name&quot;&gt;Labels: &lt;/span&gt;
+ &lt;span class=&quot;ot-labels-field-value&quot;&gt;
+
+
+ &lt;span class=&quot;ot-field-label&quot;&gt;Featured&lt;/span&gt;
+
+
+ &lt;/span&gt;
+ &lt;/div&gt;</content>
+</entry>
+
+
+ <entry>
+ <updated>2012-01-03T21:06:03Z</updated>
+ <id>http://code.google.com/feeds/p/watcher-miranda/updates/basic/z12qdzfqdumlchjgm04cepjgmoicsl1oq1w</id>
+ <link rel="alternate" type="text/html" href="http://code.google.com/p/watcher-miranda/downloads/detail?name=miranda-v0100a2w11.7z" />
+ <title type="html">&lt;a class=&quot;ot-download-link&quot; href=&quot;http://code.google.com/p/watcher-miranda/downloads/detail?name=miranda-v0100a2w11.7z&quot;&gt;miranda-v0100a2w11.7z&lt;/a&gt; (T - ) file uploaded by &lt;a class=&quot;ot-profile-link-2&quot; href=&quot;http://code.google.com/u/watcherhd/&quot;&gt;watcherhd&lt;/a&gt;</title>
+ <author>
+ <name>watcherhd</name>
+ </author>
+ <category term="ProjectNewDownload" scheme="http://code.google.com/updates/type"/>
+ <content type="html">&lt;div class=&quot;ot-labels-field-wrapper&quot;&gt;
+ &lt;span class=&quot;ot-labels-field-name&quot;&gt;Labels: &lt;/span&gt;
+ &lt;span class=&quot;ot-labels-field-value&quot;&gt;
+
+
+ &lt;span class=&quot;ot-field-label&quot;&gt;Featured&lt;/span&gt;
+
+
+ &lt;/span&gt;
+ &lt;/div&gt;</content>
+</entry>
+
+
+ <entry>
+ <updated>2012-01-03T20:47:25Z</updated>
+ <id>http://code.google.com/feeds/p/watcher-miranda/updates/basic/z135ypx45kehgtcq304cepjgmoicsl1oq1w</id>
+ <link rel="alternate" type="text/html" href="http://code.google.com/p/watcher-miranda/downloads/detail?name=miranda-v0100a2w11.7z" />
+ <title type="html">&lt;a class=&quot;ot-download-link&quot; href=&quot;http://code.google.com/p/watcher-miranda/downloads/detail?name=miranda-v0100a2w11.7z&quot;&gt;miranda-v0100a2w11.7z&lt;/a&gt; (Miranda IM 0.10.0 Alpha #2 VC6111) file uploaded by &lt;a class=&quot;ot-profile-link-2&quot; href=&quot;http://code.google.com/u/watcherhd/&quot;&gt;watcherhd&lt;/a&gt;</title>
+ <author>
+ <name>watcherhd</name>
+ </author>
+ <category term="ProjectNewDownload" scheme="http://code.google.com/updates/type"/>
+ <content type="html">&lt;div class=&quot;ot-labels-field-wrapper&quot;&gt;
+ &lt;span class=&quot;ot-labels-field-name&quot;&gt;Labels: &lt;/span&gt;
+ &lt;span class=&quot;ot-labels-field-value&quot;&gt;
+
+
+ &lt;span class=&quot;ot-field-label&quot;&gt;Featured&lt;/span&gt;
+
+
+ &lt;/span&gt;
+ &lt;/div&gt;</content>
+</entry>
+
+
+ <entry>
+ <updated>2012-01-03T09:21:55Z</updated>
+ <id>http://code.google.com/feeds/p/watcher-miranda/updates/basic/z12szb1zzybuejnnv22pfv4p3ma4ch5kj</id>
+ <link rel="alternate" type="text/html" href="http://code.google.com/p/watcher-miranda/downloads/detail?name=mirotr1.7z" />
+ <title type="html">&lt;a class=&quot;ot-download-link&quot; href=&quot;http://code.google.com/p/watcher-miranda/downloads/detail?name=mirotr1.7z&quot;&gt;mirotr1.7z&lt;/a&gt; (Miranda IM 0.10.0 Alpha #2 VC6) file uploaded by &lt;a class=&quot;ot-profile-link-2&quot; href=&quot;http://code.google.com/u/watcherhd/&quot;&gt;watcherhd&lt;/a&gt;</title>
+ <author>
+ <name>watcherhd</name>
+ </author>
+ <category term="ProjectNewDownload" scheme="http://code.google.com/updates/type"/>
+ <content type="html">&lt;div class=&quot;ot-labels-field-wrapper&quot;&gt;
+ &lt;span class=&quot;ot-labels-field-name&quot;&gt;Labels: &lt;/span&gt;
+ &lt;span class=&quot;ot-labels-field-value&quot;&gt;
+
+
+ &lt;span class=&quot;ot-field-label&quot;&gt;Featured&lt;/span&gt;
+
+
+ &lt;/span&gt;
+ &lt;/div&gt;</content>
+</entry>
+
+
+ <entry>
+ <updated>2012-01-02T20:12:28Z</updated>
+ <id>http://code.google.com/feeds/p/watcher-miranda/updates/basic/z12ltxpzuvr4xvahk04cepjgmoicsl1oq1w</id>
+ <link rel="alternate" type="text/html" href="http://code.google.com/p/watcher-miranda/downloads/detail?name=miranda32.exe" />
+ <title type="html">&lt;a class=&quot;ot-download-link&quot; href=&quot;http://code.google.com/p/watcher-miranda/downloads/detail?name=miranda32.exe&quot;&gt;miranda32.exe&lt;/a&gt; (Miranda32 v.0.9.40.0) file uploaded by &lt;a class=&quot;ot-profile-link-2&quot; href=&quot;http://code.google.com/u/watcherhd/&quot;&gt;watcherhd&lt;/a&gt;</title>
+ <author>
+ <name>watcherhd</name>
+ </author>
+ <category term="ProjectNewDownload" scheme="http://code.google.com/updates/type"/>
+ <content type="html">&lt;div class=&quot;ot-labels-field-wrapper&quot;&gt;
+ &lt;span class=&quot;ot-labels-field-name&quot;&gt;Labels: &lt;/span&gt;
+ &lt;span class=&quot;ot-labels-field-value&quot;&gt;
+
+
+ &lt;span class=&quot;ot-field-label&quot;&gt;Featured&lt;/span&gt;
+
+
+ &lt;/span&gt;
+ &lt;/div&gt;</content>
+</entry>
+
+
+ <entry>
+ <updated>2012-01-01T18:00:06Z</updated>
+ <id>http://code.google.com/feeds/p/watcher-miranda/updates/basic/z13idtjadwu5y3q2322pfv4p3ma4ch5kj</id>
+ <link rel="alternate" type="text/html" href="http://code.google.com/p/watcher-miranda/downloads/detail?name=Miranda%20IM%20Watcher%20Pack%20v3.1.0.exe" />
+ <title type="html">&lt;a class=&quot;ot-download-link&quot; href=&quot;http://code.google.com/p/watcher-miranda/downloads/detail?name=Miranda%20IM%20Watcher%20Pack%20v3.1.0.exe&quot;&gt;Miranda IM Watcher Pack v3.1.0.exe&lt;/a&gt; (Miranda IM Watcher Pack v3.1.0) file uploaded by &lt;a class=&quot;ot-profile-link-2&quot; href=&quot;http://code.google.com/u/watcherhd/&quot;&gt;watcherhd&lt;/a&gt;</title>
+ <author>
+ <name>watcherhd</name>
+ </author>
+ <category term="ProjectNewDownload" scheme="http://code.google.com/updates/type"/>
+ <content type="html">&lt;div class=&quot;ot-labels-field-wrapper&quot;&gt;
+ &lt;span class=&quot;ot-labels-field-name&quot;&gt;Labels: &lt;/span&gt;
+ &lt;span class=&quot;ot-labels-field-value&quot;&gt;
+
+
+ &lt;span class=&quot;ot-field-label&quot;&gt;Featured&lt;/span&gt;
+
+
+
+ &lt;span class=&quot;ot-field-label&quot;&gt;Type-Installer&lt;/span&gt;
+
+
+
+ &lt;span class=&quot;ot-field-label&quot;&gt;OpSys-Windows&lt;/span&gt;
+
+
+ &lt;/span&gt;
+ &lt;/div&gt;</content>
+</entry>
+
+
+ <entry>
+ <updated>2011-12-30T11:06:47Z</updated>
+ <id>http://code.google.com/feeds/p/watcher-miranda/updates/basic/z12vzfygpwqng3m3b22pfv4p3ma4ch5kj</id>
+ <link rel="alternate" type="text/html" href="http://code.google.com/p/watcher-miranda/downloads/detail?name=Miranda_Empoli_Pack_Mod.exe" />
+ <title type="html">&lt;a class=&quot;ot-download-link&quot; href=&quot;http://code.google.com/p/watcher-miranda/downloads/detail?name=Miranda_Empoli_Pack_Mod.exe&quot;&gt;Miranda_Empoli_Pack_Mod.exe&lt;/a&gt; (Miranda IM Empoli Pack Mod v.2.2 (core 0.9.39)) file uploaded by &lt;a class=&quot;ot-profile-link-2&quot; href=&quot;http://code.google.com/u/watcherhd/&quot;&gt;watcherhd&lt;/a&gt;</title>
+ <author>
+ <name>watcherhd</name>
+ </author>
+ <category term="ProjectNewDownload" scheme="http://code.google.com/updates/type"/>
+ <content type="html">&lt;div class=&quot;ot-labels-field-wrapper&quot;&gt;
+ &lt;span class=&quot;ot-labels-field-name&quot;&gt;Labels: &lt;/span&gt;
+ &lt;span class=&quot;ot-labels-field-value&quot;&gt;
+
+
+ &lt;span class=&quot;ot-field-label&quot;&gt;Featured&lt;/span&gt;
+
+
+ &lt;/span&gt;
+ &lt;/div&gt;</content>
+</entry>
+
+
+ <entry>
+ <updated>2011-12-29T14:08:24Z</updated>
+ <id>http://code.google.com/feeds/p/watcher-miranda/updates/basic/z135in4x1yi1fd2ou04cepjgmoicsl1oq1w</id>
+ <link rel="alternate" type="text/html" href="http://code.google.com/p/watcher-miranda/downloads/detail?name=mirotr.7z" />
+ <title type="html">&lt;a class=&quot;ot-download-link&quot; href=&quot;http://code.google.com/p/watcher-miranda/downloads/detail?name=mirotr.7z&quot;&gt;mirotr.7z&lt;/a&gt; (MirOTR 0.11.0.3) file uploaded by &lt;a class=&quot;ot-profile-link-2&quot; href=&quot;http://code.google.com/u/watcherhd/&quot;&gt;watcherhd&lt;/a&gt;</title>
+ <author>
+ <name>watcherhd</name>
+ </author>
+ <category term="ProjectNewDownload" scheme="http://code.google.com/updates/type"/>
+ <content type="html">&lt;div class=&quot;ot-labels-field-wrapper&quot;&gt;
+ &lt;span class=&quot;ot-labels-field-name&quot;&gt;Labels: &lt;/span&gt;
+ &lt;span class=&quot;ot-labels-field-value&quot;&gt;
+
+
+ &lt;span class=&quot;ot-field-label&quot;&gt;Featured&lt;/span&gt;
+
+
+ &lt;/span&gt;
+ &lt;/div&gt;</content>
+</entry>
+
+
+ <entry>
+ <updated>2011-12-25T10:59:24Z</updated>
+ <id>http://code.google.com/feeds/p/watcher-miranda/updates/basic/z13dgrs5elfkfp0n122pfv4p3ma4ch5kj</id>
+ <link rel="alternate" type="text/html" href="http://code.google.com/p/watcher-miranda/downloads/detail?name=LangpackSuite.exe" />
+ <title type="html">&lt;a class=&quot;ot-download-link&quot; href=&quot;http://code.google.com/p/watcher-miranda/downloads/detail?name=LangpackSuite.exe&quot;&gt;LangpackSuite.exe&lt;/a&gt; (Test upload) file uploaded by &lt;a class=&quot;ot-profile-link-2&quot; href=&quot;http://code.google.com/u/watcherhd/&quot;&gt;watcherhd&lt;/a&gt;</title>
+ <author>
+ <name>watcherhd</name>
+ </author>
+ <category term="ProjectNewDownload" scheme="http://code.google.com/updates/type"/>
+ <content type="html">&lt;div class=&quot;ot-labels-field-wrapper&quot;&gt;
+ &lt;span class=&quot;ot-labels-field-name&quot;&gt;Labels: &lt;/span&gt;
+ &lt;span class=&quot;ot-labels-field-value&quot;&gt;
+
+
+ &lt;span class=&quot;ot-field-label&quot;&gt;Featured&lt;/span&gt;
+
+
+ &lt;/span&gt;
+ &lt;/div&gt;</content>
+</entry>
+
+
+ <entry>
+ <updated>2011-12-25T10:58:18Z</updated>
+ <id>http://code.google.com/feeds/p/watcher-miranda/updates/basic/z13cu14hyzzawjmev22pfv4p3ma4ch5kj</id>
+ <link rel="alternate" type="text/html" href="http://code.google.com/p/watcher-miranda/downloads/detail?name=LangpackSuite.exe" />
+ <title type="html">&lt;a class=&quot;ot-download-link&quot; href=&quot;http://code.google.com/p/watcher-miranda/downloads/detail?name=LangpackSuite.exe&quot;&gt;LangpackSuite.exe&lt;/a&gt; (Test) file uploaded by &lt;a class=&quot;ot-profile-link-2&quot; href=&quot;http://code.google.com/u/watcherhd/&quot;&gt;watcherhd&lt;/a&gt;</title>
+ <author>
+ <name>watcherhd</name>
+ </author>
+ <category term="ProjectNewDownload" scheme="http://code.google.com/updates/type"/>
+ <content type="html">&lt;div class=&quot;ot-labels-field-wrapper&quot;&gt;
+ &lt;span class=&quot;ot-labels-field-name&quot;&gt;Labels: &lt;/span&gt;
+ &lt;span class=&quot;ot-labels-field-value&quot;&gt;
+
+
+ &lt;span class=&quot;ot-field-label&quot;&gt;Featured&lt;/span&gt;
+
+
+ &lt;/span&gt;
+ &lt;/div&gt;</content>
+</entry>
+
+
+ <entry>
+ <updated>2011-12-21T21:55:28Z</updated>
+ <id>http://code.google.com/feeds/p/watcher-miranda/updates/basic/z12sh1jqflzkj3ofd22pfv4p3ma4ch5kj</id>
+ <link rel="alternate" type="text/html" href="http://code.google.com/p/watcher-miranda/downloads/detail?name=Miranda%20IM%20Watcher%20Pack%20v3.0.9.exe" />
+ <title type="html">&lt;a class=&quot;ot-download-link&quot; href=&quot;http://code.google.com/p/watcher-miranda/downloads/detail?name=Miranda%20IM%20Watcher%20Pack%20v3.0.9.exe&quot;&gt;Miranda IM Watcher Pack v3.0.9.exe&lt;/a&gt; (Miranda IM Watcher Pack v3.0.9) file uploaded by &lt;a class=&quot;ot-profile-link-2&quot; href=&quot;http://code.google.com/u/watcherhd/&quot;&gt;watcherhd&lt;/a&gt;</title>
+ <author>
+ <name>watcherhd</name>
+ </author>
+ <category term="ProjectNewDownload" scheme="http://code.google.com/updates/type"/>
+ <content type="html">&lt;div class=&quot;ot-labels-field-wrapper&quot;&gt;
+ &lt;span class=&quot;ot-labels-field-name&quot;&gt;Labels: &lt;/span&gt;
+ &lt;span class=&quot;ot-labels-field-value&quot;&gt;
+
+
+ &lt;span class=&quot;ot-field-label&quot;&gt;Featured&lt;/span&gt;
+
+
+
+ &lt;span class=&quot;ot-field-label&quot;&gt;Type-Installer&lt;/span&gt;
+
+
+
+ &lt;span class=&quot;ot-field-label&quot;&gt;OpSys-Windows&lt;/span&gt;
+
+
+ &lt;/span&gt;
+ &lt;/div&gt;</content>
+</entry>
+
+
+ <entry>
+ <updated>2011-12-13T19:46:02Z</updated>
+ <id>http://code.google.com/feeds/p/watcher-miranda/updates/basic/z13nxvbpft3ezr5ps04cepjgmoicsl1oq1w</id>
+ <link rel="alternate" type="text/html" href="http://code.google.com/p/watcher-miranda/downloads/detail?name=Miranda%20IM%20Watcher%20Pack%20v3.0.8.exe" />
+ <title type="html">&lt;a class=&quot;ot-download-link&quot; href=&quot;http://code.google.com/p/watcher-miranda/downloads/detail?name=Miranda%20IM%20Watcher%20Pack%20v3.0.8.exe&quot;&gt;Miranda IM Watcher Pack v3.0.8.exe&lt;/a&gt; (Miranda IM Watcher Pack v3.0.8) file uploaded by &lt;a class=&quot;ot-profile-link-2&quot; href=&quot;http://code.google.com/u/watcherhd/&quot;&gt;watcherhd&lt;/a&gt;</title>
+ <author>
+ <name>watcherhd</name>
+ </author>
+ <category term="ProjectNewDownload" scheme="http://code.google.com/updates/type"/>
+ <content type="html">&lt;div class=&quot;ot-labels-field-wrapper&quot;&gt;
+ &lt;span class=&quot;ot-labels-field-name&quot;&gt;Labels: &lt;/span&gt;
+ &lt;span class=&quot;ot-labels-field-value&quot;&gt;
+
+
+ &lt;span class=&quot;ot-field-label&quot;&gt;Featured&lt;/span&gt;
+
+
+
+ &lt;span class=&quot;ot-field-label&quot;&gt;Type-Installer&lt;/span&gt;
+
+
+
+ &lt;span class=&quot;ot-field-label&quot;&gt;OpSys-Windows&lt;/span&gt;
+
+
+ &lt;/span&gt;
+ &lt;/div&gt;</content>
+</entry>
+
+
+ <entry>
+ <updated>2011-12-04T10:52:49Z</updated>
+ <id>http://code.google.com/feeds/p/watcher-miranda/updates/basic/z13vubiqswqqe1cf222pfv4p3ma4ch5kj</id>
+ <link rel="alternate" type="text/html" href="http://code.google.com/p/watcher-miranda/downloads/detail?name=Fingerprint.dll" />
+ <title type="html">&lt;a class=&quot;ot-download-link&quot; href=&quot;http://code.google.com/p/watcher-miranda/downloads/detail?name=Fingerprint.dll&quot;&gt;Fingerprint.dll&lt;/a&gt; (Fingerprint.dll WP update) file uploaded by &lt;a class=&quot;ot-profile-link-2&quot; href=&quot;http://code.google.com/u/watcherhd/&quot;&gt;watcherhd&lt;/a&gt;</title>
+ <author>
+ <name>watcherhd</name>
+ </author>
+ <category term="ProjectNewDownload" scheme="http://code.google.com/updates/type"/>
+ <content type="html"></content>
+</entry>
+
+
+ <entry>
+ <updated>2011-12-04T10:52:32Z</updated>
+ <id>http://code.google.com/feeds/p/watcher-miranda/updates/basic/z125fjy5qruixxloh04cepjgmoicsl1oq1w</id>
+ <link rel="alternate" type="text/html" href="http://code.google.com/p/watcher-miranda/downloads/detail?name=PackUpdater.dll" />
+ <title type="html">&lt;a class=&quot;ot-download-link&quot; href=&quot;http://code.google.com/p/watcher-miranda/downloads/detail?name=PackUpdater.dll&quot;&gt;PackUpdater.dll&lt;/a&gt; (PackUpdater.dll WP update) file uploaded by &lt;a class=&quot;ot-profile-link-2&quot; href=&quot;http://code.google.com/u/watcherhd/&quot;&gt;watcherhd&lt;/a&gt;</title>
+ <author>
+ <name>watcherhd</name>
+ </author>
+ <category term="ProjectNewDownload" scheme="http://code.google.com/updates/type"/>
+ <content type="html"></content>
+</entry>
+
+
+ <entry>
+ <updated>2011-12-03T15:01:42Z</updated>
+ <id>http://code.google.com/feeds/p/watcher-miranda/updates/basic/z13etferquvuyzd0z22pfv4p3ma4ch5kj</id>
+ <link rel="alternate" type="text/html" href="http://code.google.com/p/watcher-miranda/downloads/detail?name=packupdater.7z" />
+ <title type="html">&lt;a class=&quot;ot-download-link&quot; href=&quot;http://code.google.com/p/watcher-miranda/downloads/detail?name=packupdater.7z&quot;&gt;packupdater.7z&lt;/a&gt; (Pack Updater 0.0.1.0) file uploaded by &lt;a class=&quot;ot-profile-link-2&quot; href=&quot;http://code.google.com/u/watcherhd/&quot;&gt;watcherhd&lt;/a&gt;</title>
+ <author>
+ <name>watcherhd</name>
+ </author>
+ <category term="ProjectNewDownload" scheme="http://code.google.com/updates/type"/>
+ <content type="html">&lt;div class=&quot;ot-labels-field-wrapper&quot;&gt;
+ &lt;span class=&quot;ot-labels-field-name&quot;&gt;Labels: &lt;/span&gt;
+ &lt;span class=&quot;ot-labels-field-value&quot;&gt;
+
+
+ &lt;span class=&quot;ot-field-label&quot;&gt;Featured&lt;/span&gt;
+
+
+ &lt;/span&gt;
+ &lt;/div&gt;</content>
+</entry>
+
+
+ <entry>
+ <updated>2011-12-02T22:21:54Z</updated>
+ <id>http://code.google.com/feeds/p/watcher-miranda/updates/basic/z12ysnhy4zi2wvudo22pfv4p3ma4ch5kj</id>
+ <link rel="alternate" type="text/html" href="http://code.google.com/p/watcher-miranda/downloads/detail?name=fingerprintmodplus.7z" />
+ <title type="html">&lt;a class=&quot;ot-download-link&quot; href=&quot;http://code.google.com/p/watcher-miranda/downloads/detail?name=fingerprintmodplus.7z&quot;&gt;fingerprintmodplus.7z&lt;/a&gt; (Fingerprint Mod Plus 0.2.2.4 (latest svn revision)) file uploaded by &lt;a class=&quot;ot-profile-link-2&quot; href=&quot;http://code.google.com/u/watcherhd/&quot;&gt;watcherhd&lt;/a&gt;</title>
+ <author>
+ <name>watcherhd</name>
+ </author>
+ <category term="ProjectNewDownload" scheme="http://code.google.com/updates/type"/>
+ <content type="html">&lt;div class=&quot;ot-labels-field-wrapper&quot;&gt;
+ &lt;span class=&quot;ot-labels-field-name&quot;&gt;Labels: &lt;/span&gt;
+ &lt;span class=&quot;ot-labels-field-value&quot;&gt;
+
+
+ &lt;span class=&quot;ot-field-label&quot;&gt;Featured&lt;/span&gt;
+
+
+ &lt;/span&gt;
+ &lt;/div&gt;</content>
+</entry>
+
+
+ <entry>
+ <updated>2011-11-28T06:15:02Z</updated>
+ <id>http://code.google.com/feeds/p/watcher-miranda/updates/basic/z13hy1xpcr2hgbrfv22pfv4p3ma4ch5kj</id>
+ <link rel="alternate" type="text/html" href="http://code.google.com/p/watcher-miranda/downloads/detail?name=Miranda%20IM%20Watcher%20Pack%20v3.0.7.exe" />
+ <title type="html">&lt;a class=&quot;ot-download-link&quot; href=&quot;http://code.google.com/p/watcher-miranda/downloads/detail?name=Miranda%20IM%20Watcher%20Pack%20v3.0.7.exe&quot;&gt;Miranda IM Watcher Pack v3.0.7.exe&lt;/a&gt; (Miranda IM Watcher Pack v3.0.7) file uploaded by &lt;a class=&quot;ot-profile-link-2&quot; href=&quot;http://code.google.com/u/watcherhd/&quot;&gt;watcherhd&lt;/a&gt;</title>
+ <author>
+ <name>watcherhd</name>
+ </author>
+ <category term="ProjectNewDownload" scheme="http://code.google.com/updates/type"/>
+ <content type="html">&lt;div class=&quot;ot-labels-field-wrapper&quot;&gt;
+ &lt;span class=&quot;ot-labels-field-name&quot;&gt;Labels: &lt;/span&gt;
+ &lt;span class=&quot;ot-labels-field-value&quot;&gt;
+
+
+ &lt;span class=&quot;ot-field-label&quot;&gt;Featured&lt;/span&gt;
+
+
+
+ &lt;span class=&quot;ot-field-label&quot;&gt;Type-Installer&lt;/span&gt;
+
+
+
+ &lt;span class=&quot;ot-field-label&quot;&gt;OpSys-Windows&lt;/span&gt;
+
+
+ &lt;/span&gt;
+ &lt;/div&gt;</content>
+</entry>
+
+
+ <entry>
+ <updated>2011-11-24T16:35:48Z</updated>
+ <id>http://code.google.com/feeds/p/watcher-miranda/updates/basic/z13mcvxqurmeybypn04cepjgmoicsl1oq1w</id>
+ <link rel="alternate" type="text/html" href="http://code.google.com/p/watcher-miranda/downloads/detail?name=Miranda%20IM%20Watcher%20Pack%20v3.0.6.exe" />
+ <title type="html">&lt;a class=&quot;ot-download-link&quot; href=&quot;http://code.google.com/p/watcher-miranda/downloads/detail?name=Miranda%20IM%20Watcher%20Pack%20v3.0.6.exe&quot;&gt;Miranda IM Watcher Pack v3.0.6.exe&lt;/a&gt; (Miranda IM Watcher Pack v3.0.6) file uploaded by &lt;a class=&quot;ot-profile-link-2&quot; href=&quot;http://code.google.com/u/watcherhd/&quot;&gt;watcherhd&lt;/a&gt;</title>
+ <author>
+ <name>watcherhd</name>
+ </author>
+ <category term="ProjectNewDownload" scheme="http://code.google.com/updates/type"/>
+ <content type="html">&lt;div class=&quot;ot-labels-field-wrapper&quot;&gt;
+ &lt;span class=&quot;ot-labels-field-name&quot;&gt;Labels: &lt;/span&gt;
+ &lt;span class=&quot;ot-labels-field-value&quot;&gt;
+
+
+ &lt;span class=&quot;ot-field-label&quot;&gt;Featured&lt;/span&gt;
+
+
+
+ &lt;span class=&quot;ot-field-label&quot;&gt;Type-Installer&lt;/span&gt;
+
+
+
+ &lt;span class=&quot;ot-field-label&quot;&gt;OpSys-Windows&lt;/span&gt;
+
+
+ &lt;/span&gt;
+ &lt;/div&gt;</content>
+</entry>
+
+
+ <entry>
+ <updated>2011-11-23T04:58:16Z</updated>
+ <id>http://code.google.com/feeds/p/watcher-miranda/updates/basic/z13rxxbauu3wxtfmz22pfv4p3ma4ch5kj</id>
+ <link rel="alternate" type="text/html" href="http://code.google.com/p/watcher-miranda/downloads/detail?name=simplestatusmsg.7z" />
+ <title type="html">&lt;a class=&quot;ot-download-link&quot; href=&quot;http://code.google.com/p/watcher-miranda/downloads/detail?name=simplestatusmsg.7z&quot;&gt;simplestatusmsg.7z&lt;/a&gt; (Simple Status Message 1.9.0.4) file uploaded by &lt;a class=&quot;ot-profile-link-2&quot; href=&quot;http://code.google.com/u/watcherhd/&quot;&gt;watcherhd&lt;/a&gt;</title>
+ <author>
+ <name>watcherhd</name>
+ </author>
+ <category term="ProjectNewDownload" scheme="http://code.google.com/updates/type"/>
+ <content type="html">&lt;div class=&quot;ot-labels-field-wrapper&quot;&gt;
+ &lt;span class=&quot;ot-labels-field-name&quot;&gt;Labels: &lt;/span&gt;
+ &lt;span class=&quot;ot-labels-field-value&quot;&gt;
+
+
+ &lt;span class=&quot;ot-field-label&quot;&gt;Featured&lt;/span&gt;
+
+
+ &lt;/span&gt;
+ &lt;/div&gt;</content>
+</entry>
+
+
+ <entry>
+ <updated>2011-11-19T06:13:19Z</updated>
+ <id>http://code.google.com/feeds/p/watcher-miranda/updates/basic/z13di1rprvjfhpta004cepjgmoicsl1oq1w</id>
+ <link rel="alternate" type="text/html" href="http://code.google.com/p/watcher-miranda/downloads/detail?name=Miranda%20IM%20Watcher%20Pack%20v3.0.5.exe" />
+ <title type="html">&lt;a class=&quot;ot-download-link&quot; href=&quot;http://code.google.com/p/watcher-miranda/downloads/detail?name=Miranda%20IM%20Watcher%20Pack%20v3.0.5.exe&quot;&gt;Miranda IM Watcher Pack v3.0.5.exe&lt;/a&gt; (Miranda IM Watcher Pack v3.0.5) file uploaded by &lt;a class=&quot;ot-profile-link-2&quot; href=&quot;http://code.google.com/u/watcherhd/&quot;&gt;watcherhd&lt;/a&gt;</title>
+ <author>
+ <name>watcherhd</name>
+ </author>
+ <category term="ProjectNewDownload" scheme="http://code.google.com/updates/type"/>
+ <content type="html">&lt;div class=&quot;ot-labels-field-wrapper&quot;&gt;
+ &lt;span class=&quot;ot-labels-field-name&quot;&gt;Labels: &lt;/span&gt;
+ &lt;span class=&quot;ot-labels-field-value&quot;&gt;
+
+
+ &lt;span class=&quot;ot-field-label&quot;&gt;Featured&lt;/span&gt;
+
+
+
+ &lt;span class=&quot;ot-field-label&quot;&gt;Type-Installer&lt;/span&gt;
+
+
+
+ &lt;span class=&quot;ot-field-label&quot;&gt;OpSys-Windows&lt;/span&gt;
+
+
+ &lt;/span&gt;
+ &lt;/div&gt;</content>
+</entry>
+
+
+</feed>
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 @@
+<?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>NewsAggregator</ProjectName>
+ <ProjectGuid>{6DE11A47-2268-4B08-8DE5-15A1705FCE28}</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)'=='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;NEWSAGGREGATOR_EXPORTS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <RuntimeLibrary>MultiThreadedDebugDLL</RuntimeLibrary>
+ <WarningLevel>Level3</WarningLevel>
+ <DebugInformationFormat>EditAndContinue</DebugInformationFormat>
+ <DisableSpecificWarnings>4996</DisableSpecificWarnings>
+ <PrecompiledHeader>Use</PrecompiledHeader>
+ <PrecompiledHeaderFile>Common.h</PrecompiledHeaderFile>
+ </ClCompile>
+ <Link>
+ <GenerateDebugInformation>true</GenerateDebugInformation>
+ <SubSystem>Windows</SubSystem>
+ <RandomizedBaseAddress>false</RandomizedBaseAddress>
+ <ImportLibrary>$(IntDir)$(TargetName).lib</ImportLibrary>
+ <AdditionalDependencies>comdlg32.lib;%(AdditionalDependencies)</AdditionalDependencies>
+ <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;NEWSAGGREGATOR_EXPORTS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <RuntimeLibrary>MultiThreadedDebugDLL</RuntimeLibrary>
+ <WarningLevel>Level3</WarningLevel>
+ <DisableSpecificWarnings>4996</DisableSpecificWarnings>
+ <PrecompiledHeader>Use</PrecompiledHeader>
+ <PrecompiledHeaderFile>Common.h</PrecompiledHeaderFile>
+ </ClCompile>
+ <Link>
+ <AdditionalDependencies>comdlg32.lib;%(AdditionalDependencies)</AdditionalDependencies>
+ <GenerateDebugInformation>true</GenerateDebugInformation>
+ <SubSystem>Windows</SubSystem>
+ <RandomizedBaseAddress>false</RandomizedBaseAddress>
+ <ImportLibrary>$(IntDir)$(TargetName).lib</ImportLibrary>
+ <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>
+ <FavorSizeOrSpeed>Size</FavorSizeOrSpeed>
+ <AdditionalIncludeDirectories>..\..\include;..\plugins\ExternalAPI;..\..\..\boost_1_49_0;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+ <PreprocessorDefinitions>WIN32;NDEBUG;_WINDOWS;_USRDLL;NEWSAGGREGATOR_EXPORTS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <WarningLevel>Level3</WarningLevel>
+ <DisableSpecificWarnings>4996</DisableSpecificWarnings>
+ <PrecompiledHeader>Use</PrecompiledHeader>
+ <PrecompiledHeaderFile>Common.h</PrecompiledHeaderFile>
+ </ClCompile>
+ <Link>
+ <SubSystem>Windows</SubSystem>
+ <OptimizeReferences>true</OptimizeReferences>
+ <EnableCOMDATFolding>true</EnableCOMDATFolding>
+ <RandomizedBaseAddress>false</RandomizedBaseAddress>
+ <ImportLibrary>$(IntDir)$(TargetName).lib</ImportLibrary>
+ <GenerateDebugInformation>true</GenerateDebugInformation>
+ <AdditionalDependencies>comdlg32.lib;%(AdditionalDependencies)</AdditionalDependencies>
+ <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>
+ <FavorSizeOrSpeed>Size</FavorSizeOrSpeed>
+ <AdditionalIncludeDirectories>..\..\include;..\plugins\ExternalAPI;..\..\..\boost_1_49_0;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+ <PreprocessorDefinitions>WIN64;NDEBUG;_WINDOWS;_USRDLL;NEWSAGGREGATOR_EXPORTS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <WarningLevel>Level3</WarningLevel>
+ <DisableSpecificWarnings>4996</DisableSpecificWarnings>
+ <PrecompiledHeader>Use</PrecompiledHeader>
+ <PrecompiledHeaderFile>Common.h</PrecompiledHeaderFile>
+ </ClCompile>
+ <Link>
+ <AdditionalDependencies>comdlg32.lib;%(AdditionalDependencies)</AdditionalDependencies>
+ <SubSystem>Windows</SubSystem>
+ <OptimizeReferences>true</OptimizeReferences>
+ <EnableCOMDATFolding>true</EnableCOMDATFolding>
+ <RandomizedBaseAddress>false</RandomizedBaseAddress>
+ <ImportLibrary>$(IntDir)$(TargetName).lib</ImportLibrary>
+ <GenerateDebugInformation>true</GenerateDebugInformation>
+ <AdditionalLibraryDirectories>..\..\..\boost_1_49_0\lib64</AdditionalLibraryDirectories>
+ </Link>
+ <ResourceCompile>
+ <AdditionalIncludeDirectories>..\..\include\msapi</AdditionalIncludeDirectories>
+ <PreprocessorDefinitions>NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ </ResourceCompile>
+ </ItemDefinitionGroup>
+ <ItemGroup>
+ <ResourceCompile Include="Resource.rc" />
+ <ResourceCompile Include="Version.rc" />
+ </ItemGroup>
+ <ItemGroup>
+ <ClInclude Include="resource.h" />
+ <ClInclude Include="Src\Common.h" />
+ <ClInclude Include="Version.h" />
+ </ItemGroup>
+ <ItemGroup>
+ <ClCompile Include="Src\entities.cpp" />
+ <ClCompile Include="Src\Icons.cpp" />
+ <ClCompile Include="Src\Menus.cpp" />
+ <ClCompile Include="Src\Options.cpp" />
+ <ClCompile Include="Src\NewsAggregator.cpp">
+ <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">Create</PrecompiledHeader>
+ <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">Create</PrecompiledHeader>
+ <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release|x64'">Create</PrecompiledHeader>
+ <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">Create</PrecompiledHeader>
+ </ClCompile>
+ <ClCompile Include="Src\Services.cpp" />
+ <ClCompile Include="Src\Update.cpp" />
+ <ClCompile Include="Src\Utils.cpp" />
+ </ItemGroup>
+ <ItemGroup>
+ <None Include="res\AddFeed.ico" />
+ <None Include="res\CheckAll.ico" />
+ <None Include="res\Export.ico" />
+ <None Include="res\Import.ico" />
+ <None Include="res\Main.ico" />
+ </ItemGroup>
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
+ <ImportGroup Label="ExtensionTargets">
+ </ImportGroup>
+</Project> \ 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 @@
+<?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>
+ <ResourceCompile Include="Version.rc">
+ <Filter>Resource Files</Filter>
+ </ResourceCompile>
+ <ResourceCompile Include="Resource.rc">
+ <Filter>Resource Files</Filter>
+ </ResourceCompile>
+ </ItemGroup>
+ <ItemGroup>
+ <ClInclude Include="Version.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="Src\Common.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="resource.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ </ItemGroup>
+ <ItemGroup>
+ <ClCompile Include="Src\Options.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="Src\Menus.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="Src\Services.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="Src\Icons.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="Src\Update.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="Src\Utils.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="Src\NewsAggregator.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="Src\entities.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ </ItemGroup>
+ <ItemGroup>
+ <None Include="res\Main.ico">
+ <Filter>Resource Files</Filter>
+ </None>
+ <None Include="res\CheckAll.ico">
+ <Filter>Resource Files</Filter>
+ </None>
+ <None Include="res\AddFeed.ico">
+ <Filter>Resource Files</Filter>
+ </None>
+ <None Include="res\Import.ico">
+ <Filter>Resource Files</Filter>
+ </None>
+ <None Include="res\Export.ico">
+ <Filter>Resource Files</Filter>
+ </None>
+ </ItemGroup>
+</Project> \ 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
--- /dev/null
+++ b/protocols/NewsAggregator/Res/AddFeed.ico
Binary files differ
diff --git a/protocols/NewsAggregator/Res/CheckALL.ico b/protocols/NewsAggregator/Res/CheckALL.ico
new file mode 100644
index 0000000000..98d434b2ba
--- /dev/null
+++ b/protocols/NewsAggregator/Res/CheckALL.ico
Binary files differ
diff --git a/protocols/NewsAggregator/Res/Export.ico b/protocols/NewsAggregator/Res/Export.ico
new file mode 100644
index 0000000000..ef475bb5cd
--- /dev/null
+++ b/protocols/NewsAggregator/Res/Export.ico
Binary files differ
diff --git a/protocols/NewsAggregator/Res/Import.ico b/protocols/NewsAggregator/Res/Import.ico
new file mode 100644
index 0000000000..4becddf394
--- /dev/null
+++ b/protocols/NewsAggregator/Res/Import.ico
Binary files differ
diff --git a/protocols/NewsAggregator/Res/Main.ico b/protocols/NewsAggregator/Res/Main.ico
new file mode 100644
index 0000000000..4e9d1abc51
--- /dev/null
+++ b/protocols/NewsAggregator/Res/Main.ico
Binary files 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: #<author>#",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 @@
+<?xml version="1.0" encoding="windows-1251"?>
+<rss version="2.0"
+ xmlns:atom="http://www.w3.org/2005/Atom"
+ xmlns:dc="http://purl.org/dc/elements/1.1/"
+ xmlns:content="http://purl.org/rss/1.0/modules/content/">
+ <channel>
+ <title>Bash.Org.Ru</title>
+ <link>http://bash.org.ru/</link>
+ <atom:link href="http://bash.org.ru/rss/" rel="self" type="application/rss+xml" />
+ <description>Öèòàòíèê Ðóíåòà</description>
+ <language>ru</language>
+ <item>
+ <guid isPermaLink="false">b3cf2d64d57bdfea405b43426ec354e4b89a98912c71f243c93568020e2f0a70</guid>
+ <link>http://bash.org.ru/quote/414990</link>
+ <title>Öèòàòà #414990</title>
+ <pubDate>Fri, 30 Dec 2011 12:12:01 +0400</pubDate>
+ <description><![CDATA[xxx: Ýòî âñå ðàâíî ÷òî áðûçãàòü íà ïîðíîáàííåð ñâÿòîé âîäîé, à ïîòîì, êîãäà ìîíèòîð çàêîðîòèò, êðè÷àòü, ìîë, äüÿâîëüñêîå óñòðîéñòâî íå âûíåñëî ïðèñóòñòâèÿ ñâÿòîãî äóõà<br>]]></description>
+ </item>
+ <item>
+ <guid isPermaLink="false">9f3028db6c6020de238a5d27b14d85c21e5f4c8a5f96506b757925df8500c940</guid>
+ <link>http://bash.org.ru/quote/414989</link>
+ <title>Öèòàòà #414989</title>
+ <pubDate>Fri, 30 Dec 2011 11:45:18 +0400</pubDate>
+ <description><![CDATA[ ïîëíîé ìåðå îñîçíàë, ÷òî ïåðåøåë íà íî÷íîé îáðàç æèçíè, êîãäà îòåö ðàçáóäèë â ÷àñ íî÷è ñ âîïðîñàìè: &quot;Òû ÷åãî ñïèøü? Íå çàáîëåë ñëó÷àåì?&quot;]]></description>
+ </item>
+ <item>
+ <guid isPermaLink="false">c917324b76e57d2d6103af4b154f41fb335e9a4cc3f973b0b077a8c857c1353a</guid>
+ <link>http://bash.org.ru/quote/414988</link>
+ <title>Öèòàòà #414988</title>
+ <pubDate>Fri, 30 Dec 2011 11:44:38 +0400</pubDate>
+ <description><![CDATA[õõõ: íó êàê òåáå ôèëüì?<br>óóó: êîíåö òðó<br>õõõ: òû ôèëüì íå ïåðåïóòàë?<br>óóó: ÷åðò, â ñìûñëå, ôèíàë ìåíÿ ïðèÿòíî óäèâèë)]]></description>
+ </item>
+ <item>
+ <guid isPermaLink="false">96b70712a7185b7d1167f6f9aee454841a4246b0f270185ea3f29d034b9bd39f</guid>
+ <link>http://bash.org.ru/quote/414987</link>
+ <title>Öèòàòà #414987</title>
+ <pubDate>Fri, 30 Dec 2011 11:44:01 +0400</pubDate>
+ <description><![CDATA[Îòçûâ î òåëåôîíå ñ ñåíñîðíûì ýêðàíîì:<br>Ñâåòà:<br>Êóïèëà åãî â ***. Êëàññíûé òåëåôîí!!! Åù¸ íå ðàçîáðàëàñü, êàê ñíÿòü áëîêèðîâêó ñ ýêðàíà. Îí êðàñèâûé.]]></description>
+ </item>
+ <item>
+ <guid isPermaLink="false">793886d798688d3e6bec7d2ffb51d6397f356e5c0e00ef06d07f22b87643c93a</guid>
+ <link>http://bash.org.ru/quote/414986</link>
+ <title>Öèòàòà #414986</title>
+ <pubDate>Fri, 30 Dec 2011 11:13:16 +0400</pubDate>
+ <description><![CDATA[xxx: ñåãîäíÿ ïðèøëà ïîñûëêà ïîñûëêà ñ ebay â êîòîðîé 50øò íàêëååê îò ipad. Òåïåðü ó ìåíÿ iÄîì, à â íåì iÓíèòàç, iØêàô, iÕîëîäèëüíèê è äàæå iÊîò êóäà òî óáåæàë....]]></description>
+ </item>
+ <item>
+ <guid isPermaLink="false">6eac3f54c4f58d8a41c7e7f72f72ca6e0c6bf5869f0eefc99044ef4427db28d0</guid>
+ <link>http://bash.org.ru/quote/414985</link>
+ <title>Öèòàòà #414985</title>
+ <pubDate>Fri, 30 Dec 2011 11:12:02 +0400</pubDate>
+ <description><![CDATA[xxx: îòäàì 4-õ êîòÿò â ëþáûå ðóêè, èì óæå 3 ìåñÿöà è îíè âñåõ çàäîëáàëè.]]></description>
+ </item>
+ <item>
+ <guid isPermaLink="false">744d1d505dce7f1877c45baee1fdf97009a403d6dedb3ae1cd185480ec3dbbd0</guid>
+ <link>http://bash.org.ru/quote/414984</link>
+ <title>Öèòàòà #414984</title>
+ <pubDate>Fri, 30 Dec 2011 11:11:01 +0400</pubDate>
+ <description><![CDATA[xxx:<br>Ãäå êóïèòü êîðìîâûõ ìûøåé (ëûñûõ)?<br>Íà çîîðûíêå íåòó.<br><br>yyy:<br>Äîâåëè ñòðàíó... Íàðîä óæå ìûøåé æðàòü íà÷àë.]]></description>
+ </item>
+ <item>
+ <guid isPermaLink="false">aadc7f6194e8062c44250a9a878f010c0fe7d9d95af9a8389fbf8a8f748d6c6f</guid>
+ <link>http://bash.org.ru/quote/414983</link>
+ <title>Öèòàòà #414983</title>
+ <pubDate>Fri, 30 Dec 2011 10:45:08 +0400</pubDate>
+ <description><![CDATA[xxx: ó íàñ ¸ëêà íå ïðîñòàÿ, ïîíòîâàÿ<br>xxx: ñ îïòîâîëîêíîì è ñâåòèòñÿ<br>yyy: wifi áåñïëàòíî íå ðàçäàåò?]]></description>
+ </item>
+ <item>
+ <guid isPermaLink="false">01511c230d7cdf4ed42f09106b3075a5021797ae5a11d3063dc9332bb7baf858</guid>
+ <link>http://bash.org.ru/quote/414982</link>
+ <title>Öèòàòà #414982</title>
+ <pubDate>Fri, 30 Dec 2011 10:44:36 +0400</pubDate>
+ <description><![CDATA[Darkforce: À òû ê ýêçàìåíó ñ ìóçûêîé ãîòîâèøüñÿ?<br>Ergo: Äà. È ñ âêëþ÷åííîé àñåé. Íå áåðè ñ ìåíÿ ïðèìåð.]]></description>
+ </item>
+ <item>
+ <guid isPermaLink="false">cc05613e48d3f285e2a2a95a12f542586c5c0fe4499addf3c2a633cf4940e572</guid>
+ <link>http://bash.org.ru/quote/414981</link>
+ <title>Öèòàòà #414981</title>
+ <pubDate>Fri, 30 Dec 2011 10:44:01 +0400</pubDate>
+ <description><![CDATA[&lt;Jakiro&gt; ñåãîäíÿ âåøàë ãèðëÿíäó, çàïóòàëñÿ â íåé, ñåë, ïðèøëà ñåñòðà, âêëþ÷èëà ãèðëÿíäó è ïîøëà ðæàòü :(]]></description>
+ </item>
+ <item>
+ <guid isPermaLink="false">589fe99078c1447d672503cd8ffb9ba7524d9bd9e03cb5444e7c6fcd2be55269</guid>
+ <link>http://bash.org.ru/quote/414980</link>
+ <title>Öèòàòà #414980</title>
+ <pubDate>Fri, 30 Dec 2011 10:12:44 +0400</pubDate>
+ <description><![CDATA[SeeR: Åñëè ñ÷èòàòü êîýôôèöèåíò ëåíè ðàâíûì îòíîøåíèþ òîãî, ÷òî íóæíî áûëî ñäåëàòü, ê òîìó, ÷òî ñäåëàíî, òî ïî âîñêðåñåíüÿì ÿ òðàäèöèîííî äåëþ íà íîëü.]]></description>
+ </item>
+ <item>
+ <guid isPermaLink="false">58b960aeadb0e2700dd3ec5c18a0f9ca1f446d49f66edabf2ad3ea0f4a9f4933</guid>
+ <link>http://bash.org.ru/quote/414979</link>
+ <title>Öèòàòà #414979</title>
+ <pubDate>Fri, 30 Dec 2011 10:12:01 +0400</pubDate>
+ <description><![CDATA[Ñòèíà: Ãëóïî áûëî ïðèíèìàòü âàííó ñ áîìáî÷êîé ñ áëåñòêàìè. Ìû â áëåñòêàõ, ïîëîòåíöà â áëåñòêàõ, ïîñòåëüíîå áåëüå â áëåñòêàõ, äàæå êîøêà óæå â áëåñòêàõ.<br>Íî åùå ãëóïåå áûëî íàóòðî èäòè ê ãèíåêîëîãó! &gt;.&lt;]]></description>
+ </item>
+ <item>
+ <guid isPermaLink="false">dda44cf9be0c8bf4691ce24629fd67dca371952e1dc45aa5dc1cce16ca095d29</guid>
+ <link>http://bash.org.ru/quote/414978</link>
+ <title>Öèòàòà #414978</title>
+ <pubDate>Fri, 30 Dec 2011 09:46:04 +0400</pubDate>
+ <description><![CDATA[BaDMaN: íåíàâèæó óòðî ñóááîòû. Ïðàâäà, îíî íå âñåãäà óòðîì è íå âñåãäà â ñóááîòó.]]></description>
+ </item>
+ <item>
+ <guid isPermaLink="false">33f18d83baf27fbd1e28e525c942b2c7e379b42a7d91f7436e2e199400ceda30</guid>
+ <link>http://bash.org.ru/quote/414977</link>
+ <title>Öèòàòà #414977</title>
+ <pubDate>Fri, 30 Dec 2011 09:45:01 +0400</pubDate>
+ <description><![CDATA[ÕÕÕ: Ñêàéðèìñêèå íîðäû òàêèå áðóòàëüíûå, ÷òî ñóðîâûå ÷åëÿáèíñêèå ìóæèêè ïî ñðàâíåíèþ ñ íèìè äåâî÷êè èç ïåñî÷íèöû. Íî ïðè ýòîì â êàæäîé ïåùåðå ñàìîãî æåñòîêîãî ðàçáîéíèêà, â êàæäîì äîìå ñàìîãî ÿðîñòíîãî íîðäà íà ñòîëå èëè ïîëêå ñòîèò ñëàäêèé ðóëåò.<br>ÓÓÓ: Ðóëåòèêè ôèãíÿ. Âñå òàìðèýëüñêèå ðàçáîéíèêè è ìàðîä¸ðû ïîääåðæèâàþò ñðåäè ñåáÿ âûñîêóþ ãðàìîòíîñòü è äàæå â ñàìîì ðàñïðîïàùåì, çàðîñøåì ìõîì è ïàóòèíîé ëîãîâå âñåãäà åñòü äâå-òðè êíèæå÷êè. Âîò òàê ïðèõîäèò áðóòàëüíûé ñêàéðèìñêèé äîðîæíûé ðàçáîéíèê ïîñëå òÿæ¸ëîãî òðóäîâîãî áóäíÿ, ñàäèòñÿ íà õëèïêèé òàáóðåòèê, áåð¸ò ñëàäêèé ðóëåòèê è ÷èòàåò &quot;êðàòêóþ èñòîðèþ èìïåðèè&quot;. áðóòàëüíåíüêî.]]></description>
+ </item>
+ <item>
+ <guid isPermaLink="false">5599090163fe32efddbf295e457fd9cc4f3426b524eebaaaa4fa8277f34e9be2</guid>
+ <link>http://bash.org.ru/quote/414976</link>
+ <title>Öèòàòà #414976</title>
+ <pubDate>Fri, 30 Dec 2011 09:13:01 +0400</pubDate>
+ <description><![CDATA[xxx: ìîé äðóã êàæäóþ ñóááîòó õîäèò â êèíîòåàòð!<br>yyy: òîððåíòû çàìàëèâàåò?]]></description>
+ </item>
+ <item>
+ <guid isPermaLink="false">1bb26a5bc553b0570cbdf64be1a9ba3af74c3fd64dc60fe0bf9335ecb74600d0</guid>
+ <link>http://bash.org.ru/quote/414975</link>
+ <title>Öèòàòà #414975</title>
+ <pubDate>Fri, 30 Dec 2011 08:45:35 +0400</pubDate>
+ <description><![CDATA[xxx: Ìàëåíüêèé Ïåòÿ î÷åíü ëþáèò ïîäàðêè. Åãî ìàìà ïîäàðèëà åìó íà äåíü ðîæäåíèÿ äâå ñòðîêè ðàâíîé äëèíû, ñîñòîÿùèå èç áîëüøèõ è ìàëåíüêèõ áóêâ ëàòèíñêîãî àëôàâèòà. Òåïåðü Ïåòÿ õî÷åò ñðàâíèòü ýòè ñòðîêè ëåêñèêîãðàôè÷åñêè. Ïîìîãèòå Ïåòå âûïîëíèòü ñðàâíåíèå. (facepalm)<br>yyy: Ïîìîãèòå Ïåòå íå çàêîí÷èòü æèçíü ñóèöèäîì :D]]></description>
+ </item>
+ <item>
+ <guid isPermaLink="false">cf4da48b55d3fdb9e9825e39a664bd4d41dc5c7a64227796ad1afb0900bdec19</guid>
+ <link>http://bash.org.ru/quote/414974</link>
+ <title>Öèòàòà #414974</title>
+ <pubDate>Fri, 30 Dec 2011 08:45:01 +0400</pubDate>
+ <description><![CDATA[Äàâíûì-äàâíî, êîãäà åù¸ íå áûëî áàòàðååê è àêêóìóëÿòîðîâ, ñàäèëîñü ñîëíöå. Åãî òîæå õâàòàëî îò ñèëû íà äåíü, íå áîëüøå.<br>]]></description>
+ </item>
+ <item>
+ <guid isPermaLink="false">1a7a8ba066100acdf40b79f4fbc967932320641e3565b230678920432e80e1e3</guid>
+ <link>http://bash.org.ru/quote/414973</link>
+ <title>Öèòàòà #414973</title>
+ <pubDate>Fri, 30 Dec 2011 08:12:44 +0400</pubDate>
+ <description><![CDATA[xxx: òîëüêî â àðìèè ïîíèìàåøü, ÷òî çóáíàÿ ùåòêà ðåàëüíî äëÿ òðóäíîäîñòóïíûõ ìåñò...]]></description>
+ </item>
+ <item>
+ <guid isPermaLink="false">339e00558b293e087749ba42e0f06916531e712b1edfb25e470e2c0d10494aea</guid>
+ <link>http://bash.org.ru/quote/414972</link>
+ <title>Öèòàòà #414972</title>
+ <pubDate>Fri, 30 Dec 2011 08:11:44 +0400</pubDate>
+ <description><![CDATA[Ñ ôîðóìà<br><br>XXX: Çäðàâñòâóéòå, ñêàæèòå ïîæàëóéñòà, êàêîâ ñðîê ãîäíîñòè ó ñèãàðåò?<br>Êóïèë ïà÷êó ñèãàðåò è ÷óâñòâóþ, ÷òî êàêèå òî îíè õðåíîâûå, ñíà÷àëà ïîäóìàë, ÷òî ýòî ñâÿçàíî ñ òåì, ÷òî ÿ ñåé÷àñ ïûòàþñü áðîñèòü êóðèòü (ðàíüøå êóðèë ïà÷êó â äåíü, à ùàñ ïà÷êó íà íåäåëþ òÿíó) è íà÷àë îòâûêàòü, ïîòîì ãëÿíóë íà ñðîê èçãîòîâëåíèÿ, à òàì íàïèñàíî èþëü 2008ã...<br><br>YYY: Áîèòåñü íàâðåäèòü çäîðîâüþ? )))]]></description>
+ </item>
+ <item>
+ <guid isPermaLink="false">cfa6ff32cedafbf49ef812730e850a6abc9ec61c7682f3518d95fa00db4e1a14</guid>
+ <link>http://bash.org.ru/quote/414971</link>
+ <title>Öèòàòà #414971</title>
+ <pubDate>Fri, 30 Dec 2011 08:11:01 +0400</pubDate>
+ <description><![CDATA[R*: íè÷î òàê ïðîãà. ðàáî÷èå ìåñòà ïîëüçîâàòåëåé íà ñõåìå ìîæíî èçîáðàçèòü î÷åíü ðàçíîîáðàçíî - åñòü êàðòèíêè îëåíÿ, êåíãóðó, îâöû, æèðàôà]]></description>
+ </item>
+ <item>
+ <guid isPermaLink="false">128696d56057a228c43deb8cad49205905868817d0b4e834e37e3fdaccecafb4</guid>
+ <link>http://bash.org.ru/quote/414970</link>
+ <title>Öèòàòà #414970</title>
+ <pubDate>Thu, 29 Dec 2011 12:12:42 +0400</pubDate>
+ <description><![CDATA[xxx: ß òàêàÿ, êàêàÿ ÿ åñòü!!<br>yyy: Äà, è ãëàçà ó òåáÿ öâåòà òâîèõ ãëàç.]]></description>
+ </item>
+ <item>
+ <guid isPermaLink="false">2d15491a51b88af3e66c02b4d326f1e2802656b6361f8f07dd667fbbe9dce728</guid>
+ <link>http://bash.org.ru/quote/414969</link>
+ <title>Öèòàòà #414969</title>
+ <pubDate>Thu, 29 Dec 2011 12:11:34 +0400</pubDate>
+ <description><![CDATA[õõõ: Äà ó ìåíÿ âîîáùå òàêîå îùóùåíèå, ÷òî âñå ïîêóïàåìûå ìíîþ ñðåäñòâà äëÿ óêðåïëåíèÿ è ðîñòà âîëîñ íå çàäåðæèâàÿñü íà ãîëîâå íà÷èíàþò äåéñòâîâàòü â îáëàñòè íèæíèõ êîíå÷íîñòåé è ïðîìåæíîñòè...]]></description>
+ </item>
+ <item>
+ <guid isPermaLink="false">ed64e480321c46a51035c44a445cfd98927e2e303d972ac8874e8e36c11a8371</guid>
+ <link>http://bash.org.ru/quote/414968</link>
+ <title>Öèòàòà #414968</title>
+ <pubDate>Thu, 29 Dec 2011 12:11:01 +0400</pubDate>
+ <description><![CDATA[&quot;Ïî÷åìó ïðîãðàììèñòû ðàáîòàþò ïî íî÷àì&quot; @habr<br><br>troydm: Àáñîëþòíî ñîãëàñåí ñ àâòîðîì, èìåííî ïîýòîìó ÿ ëîæóñü ñïàòü â 5 óòðà è ïðîñûïàþñü â ÷àñ äíÿ! Âñåì ñïîêîéíîé íî÷è!<br>muzhig: Ýòî ìîæíî ñåáå ïîçâîëèòü, åñëè íåò æåíû. À âîò ìîåé î÷åíü íå íðàâèòñÿ êîãäà ÿ ðàáîòàþ ïî íî÷àì. Âñå îáúÿñíåíèÿ ïðî òî ÷òî «íî÷üþ íàìíîãî ëó÷øå ðàáîòàåòñÿ» îíà íå õî÷åò âîñïðèíèìàòü âñåðü¸ç.<br>ozgg: Íó æåíó ìîæíî òîæå íàó÷èòü ïðîãðàììèðîâàòü, è ãðàôèê ñèíõðîíèçèðóåòñÿ ;)<br>Vexilurz: Êîíå÷íî. Äåëîâ-òî íà 5 ìèíóò]]></description>
+ </item>
+ <item>
+ <guid isPermaLink="false">aaa2f3a8dd486d209a697ecd4e3d728d99a2aa37dd482a3a859af5c473143b69</guid>
+ <link>http://bash.org.ru/quote/414967</link>
+ <title>Öèòàòà #414967</title>
+ <pubDate>Thu, 29 Dec 2011 11:46:07 +0400</pubDate>
+ <description><![CDATA[Íàøåë íà ñàéòå îäíîé íàó÷íîé ëàáîðàòîðèè â ñîòðóäíèêàõ ÷åëîâåêà, êîòîðûé ëåò ýäàê 16 íàçàä óãíàë ó ìåíÿ âåëèê. Âîò äóìàþ, ìîæåò ñõîäèòü, ïîïðîñèòü ó íåãî âåëîñèïåä îáðàòíî, îí æå ãîâîðèë &quot;äà ÿ ïðîêà÷óñü âîí äî òóäà è âåðíó!&quot; :)))]]></description>
+ </item>
+ <item>
+ <guid isPermaLink="false">dc470e391715c450eef79e82aaadfb0342ecc256504946f0a32d2f8c1160557e</guid>
+ <link>http://bash.org.ru/quote/414966</link>
+ <title>Öèòàòà #414966</title>
+ <pubDate>Thu, 29 Dec 2011 11:45:06 +0400</pubDate>
+ <description><![CDATA[vova_belkin:<br><br>Âîò ìîé ïðàäåäóøêà, íàïðèìåð, óõèòðèëñÿ ïðîêóòèòü è ïðîèãðàòü â êàðòû äî êîïåéêè âñå èìåíèå, íàñëåäñòâî è æåíèíî ïðèäàíîå àêêóðàò ê 1917 ãîäó.<br><br>È ñ òåõ ïîð ñ÷èòàëñÿ â íàøåì ñåìåéñòâå íåïðåðåêàåìûì àâòîðèòåòîì â âîïðîñàõ ðàñïîðÿæåíèÿ êàïèòàëîì.]]></description>
+ </item>
+ <item>
+ <guid isPermaLink="false">a7147227d4c9f64edae338c2cec9f4456a1214ea3f9d899c2486038abe99a8f5</guid>
+ <link>http://bash.org.ru/quote/414965</link>
+ <title>Öèòàòà #414965</title>
+ <pubDate>Thu, 29 Dec 2011 11:44:01 +0400</pubDate>
+ <description><![CDATA[íó-íó: åñëè àòåèçì - ýòî ðåëèãèÿ, òî íå ñîáèðàòü ìàðêè - ýòî õîááè]]></description>
+ </item>
+ <item>
+ <guid isPermaLink="false">d35adf64ed961a7e7ff88e11a9b57760b1cd3f0a835f008b6e9782a27ee1a31a</guid>
+ <link>http://bash.org.ru/quote/414964</link>
+ <title>Öèòàòà #414964</title>
+ <pubDate>Thu, 29 Dec 2011 11:13:11 +0400</pubDate>
+ <description><![CDATA[xxx: äà íó íàõåð ýòó ñåññèþ. Ïîêà ó÷èë äèñêðåòíóþ ìàòåìàòèêó, çàáûë ïàðîëè îò äâóõ ïî÷òîâûõ ÿùèêîâ.]]></description>
+ </item>
+ <item>
+ <guid isPermaLink="false">8ce06ad45b760d6b51e2432476e5c13dc9158f589c9b662147b760b0a1b967ac</guid>
+ <link>http://bash.org.ru/quote/414963</link>
+ <title>Öèòàòà #414963</title>
+ <pubDate>Thu, 29 Dec 2011 11:12:01 +0400</pubDate>
+ <description><![CDATA[Îáñóæäåíèå íîâîé àíòðåñîëè â êëàäîâêå:<br><br>Íó òàì âñå êàê íàäî ñäåëàëè. Íî áàðàõëà òðàäèöèîííî áîëüøå, ÷åì ìåñòà ïîä íåãî. Ïðè÷åì âîò â ÷åì çàãàäêà áûòèÿ: âûíèìàåøü áàðàõëî èç êëàäîâêè, ïîëîâèíó âûêèäûâàåøü, îñòàâøååñÿ óáèðàåøü â êëàäîâêó, à îíî òóäà íå âëåçàåò!]]></description>
+ </item>
+ <item>
+ <guid isPermaLink="false">c64eb292881cc760ac0d2f7ac0b1010a8047b1271d39a0bc759076633640bbb4</guid>
+ <link>http://bash.org.ru/quote/414962</link>
+ <title>Öèòàòà #414962</title>
+ <pubDate>Thu, 29 Dec 2011 10:45:24 +0400</pubDate>
+ <description><![CDATA[Lilith: ÿ áîþñü ãîòîâèòü êàëüìàðà<br>Lightning: ïî÷åìó???<br>Lilith: ó íåãî êëþâ, è åùå íàäî ÷òî-òî ñäèðàòü êàê ÷óëîê<br>Lightning: ÷å òû áîèøüñÿ, òàì âñå ñõîäèò êëàññíî<br>Lilith: âäðóã ÿ ñäåðó êàëüìàðà, à ñúåì ÷óëîê<br>Lilith: à åùå ó íèõ òàì ÷åðíèëüíèöà âðîäå, è èêðà<br>Lightning: íó áëèí, òû ïîòðîøèëà êîãî-íèáóäü âîîáùå êîãäà-íèáóäü?<br>Lilith: ÿ ÷òî, ïîõîæà íà ñàìöà êàëüìàðà?<br>Lilith: òîëüêî êîï÷åíóþ ìîéâó<br>Lightning: à êóðèöó? íå? åå òàê ñìåøíî åùå ìîæíî íàäåâàòü íà ðóêó è èãðàòü â òåàòð<br>Lightning: øåâåëèòü êðûëûøêàìè, åñëè ÷åðåç æîïó âñòàâèòü<br>Lightning: òàê âîò, êàëüìàðà ëåã÷å ïîòðîøèòü, îí ìÿãîíüêèé òàêîé<br>Lightning: è æîïû íåò]]></description>
+ </item>
+ <item>
+ <guid isPermaLink="false">19ee3858da403abdebc2f2694ade27e224d83cb2d0325964d802f3313c1333de</guid>
+ <link>http://bash.org.ru/quote/414961</link>
+ <title>Öèòàòà #414961</title>
+ <pubDate>Thu, 29 Dec 2011 10:44:36 +0400</pubDate>
+ <description><![CDATA[ìóæ: äà êàê, êàê, õåðîâî :( íå ïåðåæèâó ÿ, íàâåðíîå, èñïûòàòåëüíûé ñðîê<br>ÿ: ïî÷åìó??<br>ìóæ: äà âîò áëèí. ðåøèë ïîêàçàòü ñåáÿ â õîðîøåì ñâåòå ïåðåä øåôîì. ïîæåëàë åìó ïðèÿòíîãî àïïåòèòà. à îí øåë íå â ñòîëîâóþ à â òóàëåò.]]></description>
+ </item>
+ <item>
+ <guid isPermaLink="false">e0270fd309b6e90cb9f26d9012a1db8ed681fd071f5848b395535442033ffe3a</guid>
+ <link>http://bash.org.ru/quote/414960</link>
+ <title>Öèòàòà #414960</title>
+ <pubDate>Thu, 29 Dec 2011 10:44:01 +0400</pubDate>
+ <description><![CDATA[Luba: ×åì çàíèìàåøüñÿ â îòïóñêå?<br>BreakDancer: Ðàçíûìè âàæíûìè äåëàìè<br>Luba: Íàïðèìåð?<br>BreakDancer: Äà âîò âñïîìíèë, ÷òî â äåòñòâå ó ìåíÿ áûë ïèñòîëåò, ñòðåëÿþùèé ïðèñîñêàìè<br>BreakDancer: è ðåøèë, ÷òî ðàç óæ ÿ âûðîñ äî 29 ëåò è ñòàë áîëüøèì<br>BreakDancer: òî è ïðèñîñêè òîæå äîëæíû áûòü áîëüøèìè!<br>BreakDancer: Ñäåëàë àðáàëåò, êîòîðûé ñòðåëÿåò âàíòóñîì]]></description>
+ </item>
+ <item>
+ <guid isPermaLink="false">8187c704ade265c329ccc02384e4206607407657bc6c9b9425a9542f0cb5a6a1</guid>
+ <link>http://bash.org.ru/quote/414959</link>
+ <title>Öèòàòà #414959</title>
+ <pubDate>Thu, 29 Dec 2011 10:13:01 +0400</pubDate>
+ <description><![CDATA[Îáåùàþò, ÷òî äåòè, ðîæäåííûå â ãîä ×åðíîãî Äðàêîíà, áóäóò òâîð÷åñêèìè è àêòèâíûìè. Íî ìû-òî çíàåì, ÷òî ãëàâíîå äëÿ íèõ - èììóíèòåò ê ìàãèè!]]></description>
+ </item>
+ <item>
+ <guid isPermaLink="false">1e5eadf8678f61893bcf84e0dfb41290f63266eab736941b7ca07653b70f17d4</guid>
+ <link>http://bash.org.ru/quote/414958</link>
+ <title>Öèòàòà #414958</title>
+ <pubDate>Thu, 29 Dec 2011 09:45:26 +0400</pubDate>
+ <description><![CDATA[Çâîíèò êóðüåð èç îäíîé êîíòîðû è ñïðàøèâàåò êàê äîáðàòüñÿ.<br>ß: äàëåå ìîñò ÷åðåç ðåêó, èäåòå ïî ìîñòó...<br>Ê: À ðåêà ãäå â ýòî âðåìÿ? Ñëåâà? Ñïðàâà?<br>ß: ÂÍÈÇÓ!<br>Ê: àãà, ïîíÿòíî...<br>ß: Äàëüøå ïåðåõîäèòå íà äðóãîé áåðåã, ñïóñêàåòåñü íà íàáåðåæíóþ...<br>Ê: À ÷¸, ïðÿìî äî êîíöà ìîñòà èäòè? èëè ðàíüøå ïîâåðíóòü?]]></description>
+ </item>
+ <item>
+ <guid isPermaLink="false">b7c708279640f1efe4ec3401970cb89f075864203ed0fbeeb612e9592655a4c3</guid>
+ <link>http://bash.org.ru/quote/414957</link>
+ <title>Öèòàòà #414957</title>
+ <pubDate>Thu, 29 Dec 2011 09:44:52 +0400</pubDate>
+ <description><![CDATA[gutta_honey@lj<br>Ëèçà ôàíàò &quot;Çâåçäíûõ âîéí&quot;. Ó íåå åñòü ôèãóðêà Äàðòà Âåéäåðà. Íî äåâ÷îíêà åñòü äåâ÷îíêà. Îíà, êàê ñ ïóïñèêîì, ñ íèì èãðàåò. Âîò ñåãîäíÿ:<br>- Äàðòó Âåéäåðó íóæíà êâàðòèðà! ß åãî ïîñåëþ â êîðîáêå èç-ïîä àïåëüñèíîâ.<br>Âîò òàê â æåíñêèõ ðóêàõ äàæå çëîäååâ ãàëàêòè÷åñêîãî ìàñøòàáà ïîñòèãàåò ñóäüáà ÷åáóðàøêè.]]></description>
+ </item>
+ <item>
+ <guid isPermaLink="false">e91f03e5e391060d916a7e7e827cb6eaeec132c17a1ac5d78af70d5368461ec5</guid>
+ <link>http://bash.org.ru/quote/414956</link>
+ <title>Öèòàòà #414956</title>
+ <pubDate>Thu, 29 Dec 2011 09:44:01 +0400</pubDate>
+ <description><![CDATA[ÕÕÕ: êòî ðàíî âñòà¸ò, òîãî êîò ðàçáóäèë :(]]></description>
+ </item>
+ <item>
+ <guid isPermaLink="false">c805cfaf28bf072384933e50ea8e1c48f815063c3bfbfe05a0986d6b944bd14e</guid>
+ <link>http://bash.org.ru/quote/414955</link>
+ <title>Öèòàòà #414955</title>
+ <pubDate>Thu, 29 Dec 2011 09:13:01 +0400</pubDate>
+ <description><![CDATA[XXX: Áåæàòü, áåæàòü îòñþäà!<br>YYY: ×òî ó òåáÿ òàì?<br>XXX: Òîëüêî ÷òî êîììåð÷åñêèé ñ èñïîëíèòåëüíûì â êàáèíåòå îðàëè äðóã íà äðóãà: &quot;Äà ÿ òàêèõ êàê òû â Àôãàíå ê ñòåíêå ñòàâèë&quot; vs &quot;À ÿ òàêèõ êàê òû íà çîíå ïåòóøèë&quot;. Ìíå ñòðàøíî.]]></description>
+ </item>
+ <item>
+ <guid isPermaLink="false">0636538a5462fc292f9b4fc6439cd6f7f8ab0fe79ba081c47e36d3d8338806fe</guid>
+ <link>http://bash.org.ru/quote/414954</link>
+ <title>Öèòàòà #414954</title>
+ <pubDate>Thu, 29 Dec 2011 08:46:01 +0400</pubDate>
+ <description><![CDATA[xxx: Äà òû ÷òî, ýòî æå áàÿíú.<br>xxx: Êðóãîâîðîò èíòåðíåòà.  òâèòòåð ïîñòÿò çàïèñè ïÿòèëåòíåé äàâíîñòè èç ÆÆ.<br>yyy: âîò íå âèäåëà, ææ îáîøåë ìåíÿ ñòîðîíîé<br>õõõ: Òàê ÿ è ãîâîðþ, â ÆÆ ïîñòèëè øóòêè ñ ôîðóìîâ, â ôîðóìû - ñ ôèäî...<br>õõõ: è òîëüêî â ôèäî îñíîâîïîëîæíèêè ñåòåâîãî þìîðà ïåðåïå÷àòûâàëè àíåêäîòû èç ãàçåò]]></description>
+ </item>
+ <item>
+ <guid isPermaLink="false">c8591055f839c5dbc882d36e7a4d2db9ce399460048e8e0e6d466dd43a88cae1</guid>
+ <link>http://bash.org.ru/quote/414953</link>
+ <title>Öèòàòà #414953</title>
+ <pubDate>Thu, 29 Dec 2011 08:13:04 +0400</pubDate>
+ <description><![CDATA[Î ñåêñå:<br>xxx: îòëè÷íî! â ëàáîðàòîðíûõ òàêîãî íå áûëî,íî ÿ ÇÀ! )))<br>yyy:  ëàáîðàòîðèÿõ îïàñíî. çàöåïèë íå òó êîëáó - è âñå, ÷åì ãîðäèëñÿ âñþ æèçíü è ñ ÷åì æèë - ñ òèõèì øèïåíèåì êàïàåò íà ïîë... =(<br>xxx: Èëè âûñîêîâîëüòíàÿ óñòàíîâêà ïî êðåñòöîâîìó ñïëåòåíèþ... Ñòðóÿ ýÿêóëÿòà ïðîáèâàåò êèðïè÷íóþ ñòåíó è ðàíèò ëåêòîðà â ñîñåäíåé àóäèòîðèè!<br>xxx: Êàæåòñÿ, ÿ òîëüêî ÷òî ïðèäóìàë êëàññíîå àíèìå, äà?]]></description>
+ </item>
+ <item>
+ <guid isPermaLink="false">714be978a8678d201b16981150150166752145feaefa2f159980d76051602d87</guid>
+ <link>http://bash.org.ru/quote/414952</link>
+ <title>Öèòàòà #414952</title>
+ <pubDate>Thu, 29 Dec 2011 08:11:54 +0400</pubDate>
+ <description><![CDATA[Ðåêëàìà íà ßíäåêñå èçâåñòíîé êîìïàíèè è ñëîãàí &quot;Ïîïðîáóé ñ íàøèì âûáèðàòîðîì ïîäàðêîâ!&quot;<br>Àãà, ÿ òîæå ïåðâûé ðàç íåïðàâèëüíî ïðî÷èòàë =)]]></description>
+ </item>
+ <item>
+ <guid isPermaLink="false">dd7d36ba1543a7ac360b28c72f669816d3551bb09f34156635f80efbc9a4f390</guid>
+ <link>http://bash.org.ru/quote/414951</link>
+ <title>Öèòàòà #414951</title>
+ <pubDate>Thu, 29 Dec 2011 08:11:01 +0400</pubDate>
+ <description><![CDATA[Ñåãîäíÿ âûíîñèë ìóñîð â îôèñå, à ìîÿ êîëëåãà èãðàëà â âèíäó, çàäàâàÿ âîïðîñû:<br>- Âû óâåðåíû, ÷òî õîòèòå î÷èñòèòü êîðçèíó? Ôàéëû áóäóò óäàëåíû áåçâîçâðàòíî.<br>À ïîòîì ó ìåíÿ ïîðâàëñÿ ïàêåò è âåñü ìóñîð ðàçëåòåëñÿ ïî îôèñó, íà ÷òî êîëëåãà ïå÷àëüíî çàìåòèëà:<br>- Ïðîèçîøåë ñáîé ïðè î÷èñòêå êîðçèíû, ïåðåçàãðóçèòåñü è ïîïðîáóéòå ñíîâà...]]></description>
+ </item>
+ <item>
+ <guid isPermaLink="false">174e14053635b5325be15ae0a37b47953115b33e0d082053064572907d2829a0</guid>
+ <link>http://bash.org.ru/quote/414950</link>
+ <title>Öèòàòà #414950</title>
+ <pubDate>Wed, 28 Dec 2011 12:46:01 +0400</pubDate>
+ <description><![CDATA[[QuizMaster7] Ïîâòîðÿþ âîïðîñ: Èìåííî îíè âåøàëè ïîä øåþ êîíÿ âîë÷üþ ãîëîâó, à íà ñåäëî ïðèêðåïðÿëè ìåòëó, ÷òîáû âûíþõèâàòü èçìåíó è âûìåòàòü åå èç ãîñóäàðñòâà<br>[QuizMaster7] Ïåðâàÿ ïîäñêàçêà: Êîëè÷åñòâî áóêâ: 9<br>[EwokDoUrden] ôèãàñå!<br>[EwokDoUrden] ÍÀÐÊÎÌÀÍÛ]]></description>
+ </item>
+ <item>
+ <guid isPermaLink="false">691660b05378e2d242a7a60429e2cd94a44e8d2041b2facb2597cb21ec213fbf</guid>
+ <link>http://bash.org.ru/quote/414949</link>
+ <title>Öèòàòà #414949</title>
+ <pubDate>Wed, 28 Dec 2011 12:13:18 +0400</pubDate>
+ <description><![CDATA[Äîê: Áëÿ, õîäèë ïîêóðèòü íà áàëêîí, âèæó â óãëó ÷òî-òî ìîõíàòîå ñ óãðîæàþùåé òåíüþ.  ñòîðîíó øàðàõíóëñÿ. È óæå äóìàþ, ãëþêè îò áåññîííèöû ïðóò. Íå áëèí, ÿ ïðîñòî çàáûë, ÷òî â÷åðà åëêó êóïèë.]]></description>
+ </item>
+ <item>
+ <guid isPermaLink="false">634c63c05a37bbb5933ccae9bd50bbc4e04d2a27dfd2895ab8f4be5cc77a5707</guid>
+ <link>http://bash.org.ru/quote/414948</link>
+ <title>Öèòàòà #414948</title>
+ <pubDate>Wed, 28 Dec 2011 12:12:02 +0400</pubDate>
+ <description><![CDATA[XXX: âñå, ôèíèø! ÿ êîíå÷íî ðàçíûõ äåáèëîâ âèäåëà. è ê ñêðåïêàì â ïðèíòåðå óæå äàæå ïî÷òè ïðèâûêëà. è ñêîò÷ íà áàðàáàíå, áëèí, ïðèêëååííûé ñ ÷åñòíûìè ãëàçàìè &quot;íó ÿ æå åãî äàæå íå îòêðûâàëà, ÿ íå çíàþ, êàê îí òóäà ïîïàë!&quot;. íî ÷òîáû òàê! ó ìåíÿ ñåé÷àñ ïðèíòåð ÊÀËÜÊÓËßÒÎÐ çàæåâàë!!! êàëüêóëÿòîð, áëèí!]]></description>
+ </item>
+ <item>
+ <guid isPermaLink="false">2309307a0dd79a2f77f63dbbbf3239d5de3cd41409ce23750c0e8ebecd20466f</guid>
+ <link>http://bash.org.ru/quote/414946</link>
+ <title>Öèòàòà #414946</title>
+ <pubDate>Wed, 28 Dec 2011 11:44:57 +0400</pubDate>
+ <description><![CDATA[xxx:<br>îòäàì â äàð ïëååð<br>Explay T-7, ñëåãêà ïîäåðæàíûé (âõëàìèíó)]]></description>
+ </item>
+ <item>
+ <guid isPermaLink="false">c58a33a67db26dab4b121d14ebad5cd80d78040eea517835a90bbdc81887b4dc</guid>
+ <link>http://bash.org.ru/quote/414945</link>
+ <title>Öèòàòà #414945</title>
+ <pubDate>Wed, 28 Dec 2011 11:44:01 +0400</pubDate>
+ <description><![CDATA[Êóïèëè ñ ñîòðóäíèöåé â îôèñ ëèêåðà. Ïîëîâèíó âûïèëè, îñòàòêè îíà çàìàòûâàåò â ïàêåòèê è ñòàâèò â õîëîäèëüíèê.<br>ß: Ìû ÷òî, òóò åãî è îñòàâèì?<br>Ñîòðóäíèöà: Íó äà, à ÷òî íàì òåðÿòü? )<br>ß: Íó, íàïðèìåð ðàáîòó....]]></description>
+ </item>
+ <item>
+ <guid isPermaLink="false">3a8ab041c452b16f9f415d3f6d209f1d58f11ed2ab0ee5f928a5f6b8e22a78b9</guid>
+ <link>http://bash.org.ru/quote/414944</link>
+ <title>Öèòàòà #414944</title>
+ <pubDate>Wed, 28 Dec 2011 11:12:55 +0400</pubDate>
+ <description><![CDATA[&lt;Belka&gt; Âåñüìà ñìóòèëàñü, íàéäÿ â çàïèñíîé òåëåôîííîé êíèæêå ñâîåãî áåçãðàìîòíîãî áðàòà çàïèñü &quot;Ìàêñ -ñîñåò&quot;.]]></description>
+ </item>
+ <item>
+ <guid isPermaLink="false">d72696e62bb007bb3004d7403e5915734f7ca02ef54757e08cb0a689a1b4df4d</guid>
+ <link>http://bash.org.ru/quote/414943</link>
+ <title>Öèòàòà #414943</title>
+ <pubDate>Wed, 28 Dec 2011 11:12:01 +0400</pubDate>
+ <description><![CDATA[korsa: âîêðóã ìåíÿ òðè êîìïà, äâà òåëåôîíà è íàâèãàòîð<br>fintar: íóæíî ïåðåâåçòè èõ ÷åðåç ðåêó?]]></description>
+ </item>
+ <item>
+ <guid isPermaLink="false">9ffbfa3d0268a0dc955b9969e4c2b77cc50443a7d6bd9b60f9cf4102daeb7fb1</guid>
+ <link>http://bash.org.ru/quote/414942</link>
+ <title>Öèòàòà #414942</title>
+ <pubDate>Wed, 28 Dec 2011 10:45:41 +0400</pubDate>
+ <description><![CDATA[Èç îáñóæäåíèÿ:<br>Êàê–òî ðàç ÿ â ñïîðå ñî ñâîåé æåíîé îáíàðóæèë êàêóþ–òî îòêðîâåííóþ äóðü â åå ñëîâàõ è ñêàçàë:<br>— Íî ýòî æå íå ëîãè÷íî!<br>— Íó è ÷òî?<br>Áëÿäü, ÍÓ È ×ÒÎ? â ýòîò ìîìåíò ó ìåíÿ âîîáùå âåñü ìèð ðóõíóë, è ÿ ïîíÿë ÷òî äëÿ íåå âîîáùå íåò ðàçíèöû, ëîãè÷íî èëè íåò òî, ÷òî îíà ãîâîðèò. ÂÎÎÁÙÅ!<br><br>Êîãäà ÿ ïåðåñêàçûâàþ ýòî ñâîèì äðóçüÿì, âñå õîõî÷óò èëè óëûáàþòñÿ. À êîãäà äåâóøêàì — îíè ïðîñòî æäóò, ÷òî ÿ äàëüøå ñêàæó, ñî âíèìàòåëüíûì ëèöîì, ïîòîìó ÷òî èñêðåííå íå çàìå÷àþò ïðîáëåìû â ýòîé ôðàçå]]></description>
+ </item>
+ <item>
+ <guid isPermaLink="false">6017310e922bd529b5ad3be09f4f0c5e8b6b2fb76d0bd05b617a8eac0ae27193</guid>
+ <link>http://bash.org.ru/quote/414941</link>
+ <title>Öèòàòà #414941</title>
+ <pubDate>Wed, 28 Dec 2011 10:44:47 +0400</pubDate>
+ <description><![CDATA[xxx: ó íàñ â ñòîëîâîé äàâíî âìåñòî ñàëôåòîê áóìàãà ïðîìûøëåííàÿ íàðåçàíà, íî ñåé÷àñ îíà åùå è ãëÿíöåâàÿ]]></description>
+ </item>
+ <item>
+ <guid isPermaLink="false">b101af3976aa2e9b7841576433b0c68af93c3ce85ac75383a6f7b20a0106a9c6</guid>
+ <link>http://bash.org.ru/quote/414940</link>
+ <title>Öèòàòà #414940</title>
+ <pubDate>Wed, 28 Dec 2011 10:44:01 +0400</pubDate>
+ <description><![CDATA[Ñåé÷àñ ñ æåíîé ïî òåëåôîíó ðàçãîâàðèâàë.<br>Îíà ãîâîðèò:<br>- Äàâàé òåáå íà Íà ðóáàøêó ïîøüåì êëåâóþ è ýòî áóäåò ìîèì ïîäàðêîì.<br>- Êàê õî÷åøü.<br>Ïðåäëàãàåò ìåðêè ïîåõàòü ñíÿòü, ÿ íà÷èíàþ äèêòîâàòü.<br>- Äëèíà 174 ñì, øèðèíà 80 ñì. Âíóòðè òêàíü áàðõàò, ñíàðóæè äåðåâî, ëó÷øå äóá, êðûøêà òîæå äóáîâàÿ ðåçíàÿ.<br>Îíà ãîâîðèò:<br>- Âñå çàïèñàëà, ñåé÷àñ èì ïîçâîíþ.<br>È òóò îíà ïðî÷èòàëà òî, ÷òî çàïèñàëà...]]></description>
+ </item>
+ <item>
+ <guid isPermaLink="false">1d3da2d78ecf5bac86c480e26d65184e8b69cab96bc8d6c038de7de9ca468ebd</guid>
+ <link>http://bash.org.ru/quote/414939</link>
+ <title>Öèòàòà #414939</title>
+ <pubDate>Wed, 28 Dec 2011 10:13:07 +0400</pubDate>
+ <description><![CDATA[õõõ: Ó íàñ ñåãîäíÿ ýêçàìåí ïî àíàòîìèè âîîáùå çà÷åòíûé âûøåë. Îäèí ïàðåíü ñðåç ãîðòàíè íàçâàë ñðåçîì øåéêè ìàòêè, äðóãîé â ðîìáîâèäíîé ÿìêå ìîçãà ïðèìåòèë, çâèíÿþñü, âóëüâó.<br>õõõ: Îáîèõ îòïðàâèëè íà ïåðåñäà÷ó ñ ôîðìóëèðîâêîé &quot;âûëå÷èòå íåäîòðàõ è ïðèõîäèòå ñíîâà&quot;.]]></description>
+ </item>
+ <item>
+ <guid isPermaLink="false">0365ddac152e7a1f45d4fe35cc5d673ff9e9cbce8d9d125e40b5dca139cd293e</guid>
+ <link>http://bash.org.ru/quote/414938</link>
+ <title>Öèòàòà #414938</title>
+ <pubDate>Wed, 28 Dec 2011 10:12:01 +0400</pubDate>
+ <description><![CDATA[xxx: Æåíà ïîñëå ñóòîê íà ðàáîòå ïîïðîñèëà ðàçáóäèòü åå â 20:00. Çâîíþ, îíà ïîäíèìàåò òðóáêó, íè÷åãî íå ãîâîðèò, ñëûøíî òîëüêî ìèðíîå ñîïåíèå... Âûêëþ÷èëà áóäèëüíèê, áëèí :D]]></description>
+ </item>
+ <item>
+ <guid isPermaLink="false">8774184a10feb87ab76c3eac63fcf6873b572cd376d06b87ec2cafa48464b57b</guid>
+ <link>http://bash.org.ru/quote/414937</link>
+ <title>Öèòàòà #414937</title>
+ <pubDate>Wed, 28 Dec 2011 09:45:31 +0400</pubDate>
+ <description><![CDATA[Ascha: êàê óäîáíî: åñëè ðåâåòü äâà ÷àñà ïîäðÿä - òî òóøü ñìûâàòü óæå íå íóæíî!]]></description>
+ </item>
+ <item>
+ <guid isPermaLink="false">5f9e58d114c8a86764bd26780e94bb3f00f0a4db026821f84d06b4540db7b5ed</guid>
+ <link>http://bash.org.ru/quote/414936</link>
+ <title>Öèòàòà #414936</title>
+ <pubDate>Wed, 28 Dec 2011 09:45:01 +0400</pubDate>
+ <description><![CDATA[xxx: ÿ çàéäó ùàñ?<br>yyy: ß - ãîðÿ÷àÿ øòó÷êà. È ÿ óæå âñÿ òåêó. Íî áóäü ñî ìíîé îñòîðîæåí.<br>xxx: Àíÿ?<br>yyy: Ó ìåíÿ òåìïåðàòóðà. Ñîïëè ðó÷üåì. Ðèñêóåøü çàðàçèòüñÿ.]]></description>
+ </item>
+ <item>
+ <guid isPermaLink="false">8b1acd9ec8457ac318c78b1dc88005edf4fc9f0ace4d47c1080c1b670de19e2e</guid>
+ <link>http://bash.org.ru/quote/414935</link>
+ <title>Öèòàòà #414935</title>
+ <pubDate>Wed, 28 Dec 2011 09:13:01 +0400</pubDate>
+ <description><![CDATA[Duck: Ðåøèë ïîïðàâèòü çäîðîâüå, çàïèñàëñÿ â áàññåéí.<br>Dimes: óðèíîòåðàïèÿ íå ðàáîòàåò]]></description>
+ </item>
+ <item>
+ <guid isPermaLink="false">187c05af1edfcce0de5da82d30a58fb83ae474e6fa897ad684bd3ad7c50e9dd7</guid>
+ <link>http://bash.org.ru/quote/414934</link>
+ <title>Öèòàòà #414934</title>
+ <pubDate>Wed, 28 Dec 2011 08:46:02 +0400</pubDate>
+ <description><![CDATA[xxx: Ìåíÿ ïîïðîñèëè â ìåòðî ïðîéòè ÷åðåç ðàìêó<br>yyy: êàêîãî õ?<br>xxx: Õðåí åãî çíàåò<br>yyy: òû ïîêàçàëñÿ èì ïîäîçðèòåëüíûì? )<br>xxx: Áûë êàê âñåãäà â äæèíñàõ ÷èñòûõ áîòèíêàõ êîæàíîé ñóìêå è íàãëîé ðîæåé<br>xxx: Ìåíÿ êàê ïðàâèëî îíè âîîáùå íå çàìå÷àþò<br>yyy: õû<br>yyy: òû áûë â êîæàíîé ñóìêå, ýòî íàñòîðàæèâàåò]]></description>
+ </item>
+ <item>
+ <guid isPermaLink="false">00822e572762f43d2fb56ef00c2f7be12f703a27a39949f99036f7734a26f566</guid>
+ <link>http://bash.org.ru/quote/414933</link>
+ <title>Öèòàòà #414933</title>
+ <pubDate>Wed, 28 Dec 2011 08:45:02 +0400</pubDate>
+ <description><![CDATA[misterIT: Ñàíü, ïðèâåò. ñðî÷íî íóæíà ïîìîùü, ÷åðåç ñêîëüêî ìîæåøü â îôèñ ïîäãðåñòè?<br>misterIT: Äîìåí ðóõíóë, ðåéä çàãëþ÷èëî. È âèíò ïðèõâàòè.<br>misterIT: Ñàíü!!! òû òóò?<br>xxx@qip: Òóò, ñîáèðàþñü, à ÷òî ñëó÷èëîñü òî? Íàïðÿæåíèå? Êîðîòíóëî?<br>misterIT: Äà õç<br>misterIT: Áîðîäó â÷åðà ñáðèë, ñâèäàíèå áëÿäü âèäèòå ëè!<br>xxx@qip: À ÿ ñâèòåð ïîñòèðàë. Âèäèìî íå âðàëè.]]></description>
+ </item>
+ <item>
+ <guid isPermaLink="false">a6231be02247fcfffbaa07e020f43a4c7a1c7ed628ed86af16443ffe45ed7127</guid>
+ <link>http://bash.org.ru/quote/414932</link>
+ <title>Öèòàòà #414932</title>
+ <pubDate>Wed, 28 Dec 2011 08:12:38 +0400</pubDate>
+ <description><![CDATA[xxx: Æåíùèíû - êàê êîìïüþòåðíûå èãðû ñ ðàçíûìè óðîâíÿìè ñëîæíîñòè. Åñëè èãðàòü íà Very Easy - òî áûñòðî ïðîïàäàåò èíòåðåñ ê èãðå. À åñëè èãðàòü íà Very Hard - òî ìîæíî íàòåðåòü ìîçîëè äæîéñòèêîì.]]></description>
+ </item>
+ <item>
+ <guid isPermaLink="false">039ba4efda1619b3b4374b223e344b3423a8d9788a18bf73ac07bce7bac04bea</guid>
+ <link>http://bash.org.ru/quote/414931</link>
+ <title>Öèòàòà #414931</title>
+ <pubDate>Wed, 28 Dec 2011 08:12:01 +0400</pubDate>
+ <description><![CDATA[ß:<br>Æåíà ìíå òàêàÿ ãîâîðèò:<br>- ìíå íóæíà øóáà íîðêîâàÿ,<br>- ó òåáÿ æå åñòü,<br>- ó ìåíÿ èç êóñî÷êîâ, à ìíå íàäî öåëüíóþ, ó íàñ ó âñåé ãðóïïû óæå öåëüíûå, à z îäíà êàê ëîøàðà!<br>- ó âñåé - ýòî ó îäíîé Ëþäêè?<br>- íó íåò, ó äâîèõ òî÷íî åñòü!<br>- ... à ìíå íóæåí ôîòîàïïàðàò êýíîí 5ä ìàðê 2<br>- ó òåáÿ æå åñòü óæå.<br>- íó òàê ó ìåíÿ 5ä, à ÿ õî÷ó ÷òîáû áûë ìàðê 2, à òî ó âñåõ óæå â ãîðîäå ìàðêè, à ÿ îäèí êàê ëîøàðà<br>- íó òåáå-òî ïðîñòî õî÷åòñÿ, à ìíå... (âîò òóò âíèìàíèå!!!!) ÍÅÎÁÕÎÄÈÌÎ.<br><br>Êåìï:<br>õîðîøî, ÷òî òû íå ñêàçàë, ÷òî òû èì åùå è äåíüãè çàðàáàòûâàåøü, à òî îíà áû òåáå êàêóþ-íèáóäü àëüòåðíàòèâó ñ øóáîé ïðèäóìàëà]]></description>
+ </item>
+ <item>
+ <guid isPermaLink="false">66fab6cb65e11c7de896d7c6840095b9a90bd70ed8d49f8fb7adc0adb9b6a43c</guid>
+ <link>http://bash.org.ru/quote/414930</link>
+ <title>Öèòàòà #414930</title>
+ <pubDate>Tue, 27 Dec 2011 13:46:01 +0400</pubDate>
+ <description><![CDATA[õõõ: Äðóã ìíå â÷åðà ðàññêàçàë. Îí áàðìåíîì ðàáîòàåò â çàâåäåíèè. Ïî÷òè â íî÷è ê íè íà÷àëè çàëàìûâàòüñÿ äâà ïüÿíûõ â çþçþ ÷óâàêà è îõðàíà èõ íå ïóñòèëà, òàê êàê çàâåäåíèå ïðèëè÷íîå. Ýòè äâà òèïà íå íàøëè íè÷åãî óìíåå è âûçâàëè ïîëèöèþ, òå ïðèåõàëè, èõ ñàìèõ æå çàáðàëè è óâåçëè!]]></description>
+ </item>
+ <item>
+ <guid isPermaLink="false">39b40cb066f0a9b64c53dbc67c1a521a1b3948a5b021efd4b1982753059aaee1</guid>
+ <link>http://bash.org.ru/quote/414929</link>
+ <title>Öèòàòà #414929</title>
+ <pubDate>Tue, 27 Dec 2011 13:13:01 +0400</pubDate>
+ <description><![CDATA[xxx: ÿ èì çâîíèë<br>xxx: íåò ó íèõ âðåìåíè íà ïîíåäåëüíèê<br>yyy: ïå÷àëüêà<br>xxx: ýòî óæå íå ïå÷àëüêà<br>xxx: ýòî óæå çëîñòüêà, ÿðîñòüêà è ãíåâèê]]></description>
+ </item>
+ <item>
+ <guid isPermaLink="false">4f3b79bfba6994d73b3eb21530d98188f4830c26c4f8108a6d8120a4c0b5e8fc</guid>
+ <link>http://bash.org.ru/quote/414928</link>
+ <title>Öèòàòà #414928</title>
+ <pubDate>Tue, 27 Dec 2011 12:46:01 +0400</pubDate>
+ <description><![CDATA[Êîììåíòû ê ñòàòüå &quot;Êàê îñâîáîäèòüñÿ èç íàðó÷íèêîâ-ñòÿæåê&quot;:<br>xxx: À âîò èíòåðåñíî, åñëè òû åäåøü â áàãàæíèêå ìàøèíû, ÷òî äåëàòü?<br>yyy: åñëè íî÷üþ è â ëåñ – òî ýòî ïðîñòî ïëîõàÿ ïðèìåòà.<br>zzz: Âî âñ¸ì íàäî èñêàòü ïîçèòèâ! ß óâåðåí, ýòî áóäåò ïîñëåäíÿÿ ïëîõàÿ ïðèìåòà â âàøåé æèçíè! :)]]></description>
+ </item>
+ <item>
+ <guid isPermaLink="false">d3162ccb1c30aa3f654c0c6b368fa9e583c020dc3d04bcc07b6c5f02eeadaaeb</guid>
+ <link>http://bash.org.ru/quote/414927</link>
+ <title>Öèòàòà #414927</title>
+ <pubDate>Tue, 27 Dec 2011 12:13:01 +0400</pubDate>
+ <description><![CDATA[zzz: Íó âîò êàê îáúÿñíèòü èíîñòðàíöó, ïî÷åìó âèëêà — ëåæèò, òàðåëêà — ñòîèò, à ïòèöà — ñèäèò?<br>xxx: Âîò, êñòàòè, íîóòáóê: êîãäà çàêðûòà êðûøêà — ëåæèò, à êîãäà îòêðûòà — ñòîèò…<br>yyy: ß êàæåòñÿ íà÷èíàþ ïîíèìàòü, ëåæèò — áåç òîëêó, à ñòîèò — âî èìÿ Âåëèêîé Ñïðàâåäëèâîñòè!<br>]]></description>
+ </item>
+ <item>
+ <guid isPermaLink="false">69e05b82fc5a5028a65e0435a584a83ffaa44e9784c024fb30eda9b7d87f38ba</guid>
+ <link>http://bash.org.ru/quote/414926</link>
+ <title>Öèòàòà #414926</title>
+ <pubDate>Tue, 27 Dec 2011 11:46:03 +0400</pubDate>
+ <description><![CDATA[Sovershenstvo: ðàñïå÷àòàëà äîêóìåíò íà 115 ñòðàíèö. çàáèðàëà èç ïðèíòåðà. îáîæãëàñü î áóìàãó :(<br>iNote: ïðèíòåð ææîò :D]]></description>
+ </item>
+ <item>
+ <guid isPermaLink="false">caa3a31eca89b56e3669c9910f23564e1ee2bd2c67f0be5472e206496b688609</guid>
+ <link>http://bash.org.ru/quote/414925</link>
+ <title>Öèòàòà #414925</title>
+ <pubDate>Tue, 27 Dec 2011 11:45:01 +0400</pubDate>
+ <description><![CDATA[Èç îáñóæäåíèÿ èñïîëüçîâàíèÿ àêóñòè÷åñêîãî äàò÷èêà äëÿ âêëþ÷åíèÿ êîìïüþòåðà õëîïêîì â ëàäîøè:<br>xxx: Áûë òàêîé ñëó÷àé.<br>xxx: Ïðèÿòåëü ñäåëàë àêóñòè÷åñêèé âûêëþ÷àòåëü íà îñâåùåíèå.<br>xxx: Äîñòàâàë êíèãè ñ ïîëêè, ñòîÿ íà òàáóðåòå.<br>xxx: Óïàëà êíèãà, ñâåò ïîòóõ, îí îñòóïèëñÿ, ñëîìàë ðóêó.<br>xxx: Ñâåò çàãîðåëñÿ.]]></description>
+ </item>
+ <item>
+ <guid isPermaLink="false">d3db54801b673716d6b41137bbf9ca64c62a04a1211bf43ea44876c411f88728</guid>
+ <link>http://bash.org.ru/quote/414924</link>
+ <title>Öèòàòà #414924</title>
+ <pubDate>Tue, 27 Dec 2011 11:13:12 +0400</pubDate>
+ <description><![CDATA[Îáñóæäàåì ñ ìóæåì Ñêàéðèì:<br>- Ìíå îäíîé êàæåòñÿ, ÷òî äðàóãè êóäàõòàþò? &quot;Êóä-êó-äà&quot;, &quot;Êóä-êó-äààààà&quot;<br>- Ýòî åùå ÷òî. Â÷åðà ñêåëåò ïîäõîäèò êî ìíå è ÷åòêî òàê: &quot;ïàñ-ïîðò&quot;.<br>- Ñóðîâûå ñêåëåòû äðåâíåñêàéðèìñêèõ ïîãðàíè÷íèêîâ. Èç âñåãî, ÷òî ëåïå÷óò, ìîæíî ðàçîáðàòü òîëüêî &quot;ïàñïîðò&quot; è &quot;óõîäè&quot; )]]></description>
+ </item>
+ <item>
+ <guid isPermaLink="false">6206e668575ef7364ca52bacdfc3d6b45da5ab80d4c69c0f1467269cec9ee6c4</guid>
+ <link>http://bash.org.ru/quote/414923</link>
+ <title>Öèòàòà #414923</title>
+ <pubDate>Tue, 27 Dec 2011 11:12:01 +0400</pubDate>
+ <description><![CDATA[xxx: Óñòðîèë äèâåðñèþ íà ðàáîòå - ïðèí¸ñ èðèñ &quot;Êèñ-Êèñ&quot; (ñîâåòñêèé, æåëåçîáåòîííûé). <br>xxx: Òåïåðü íèêòî ñî ìíîé íå ðàçãîâàðèâàåò. <br>xxx: ÂÎÎÁÙÅ ÍÈÊÒÎ ÍÈ Ñ ÊÅÌ ÍÅ ÐÀÇÃÎÂÀÐÈÂÀÅÒ! )))]]></description>
+ </item>
+ <item>
+ <guid isPermaLink="false">47c8ec43ac12036ac0528b4b4077f8d9f80a0fe8d4aa029f8a39b7b9d4327b6f</guid>
+ <link>http://bash.org.ru/quote/414922</link>
+ <title>Öèòàòà #414922</title>
+ <pubDate>Tue, 27 Dec 2011 10:45:34 +0400</pubDate>
+ <description><![CDATA[õõõ: ß ãîòîâëþñü ê çà÷åòó, òîëüêî î÷åíü îáäóìàííî. Ñî ñòîðîíû ýòî âûãëÿäèò, áóäòî ÿ ïðèìåðÿþ êèðçà÷è]]></description>
+ </item>
+ <item>
+ <guid isPermaLink="false">7871bd6a1b62f062468316e82234015b27a0c448d21c39120579d4c66c1b3367</guid>
+ <link>http://bash.org.ru/quote/414921</link>
+ <title>Öèòàòà #414921</title>
+ <pubDate>Tue, 27 Dec 2011 10:45:01 +0400</pubDate>
+ <description><![CDATA[xxx: Ïåðååõàëè â íîâûé îôèñ. Ñïóñòÿ òðè ìåñÿöà îáíàðóæèëè ëþê ïîä íîãàìè, à èç ùåëè ñâåò ãîðèò. Äóìàåì òåïåðü - âñêðûâàòü, èëè íå ñòîèò.<br>yyy: Âû àêêóðàòíåé òàì. À òî ïîñóòî÷íî äåæóðèòü çàñòàâÿò è öèôåðêè ââîäèòü.]]></description>
+ </item>
+ <item>
+ <guid isPermaLink="false">c5fcb5c4cf429099d6540943fd5f376998aee7e5ac90409e8afc3e6a61ef177f</guid>
+ <link>http://bash.org.ru/quote/414920</link>
+ <title>Öèòàòà #414920</title>
+ <pubDate>Tue, 27 Dec 2011 10:13:01 +0400</pubDate>
+ <description><![CDATA[MG: Ìàìà ìîåé ìàìû ñêàçàëà ìîåé ìàìå: òâîþ æ ìàòü çà íîãó! È óïàëà.]]></description>
+ </item>
+ <item>
+ <guid isPermaLink="false">72838435dc732ed7410037dd17b0e38588ac91999f5f195421621a8355ded16e</guid>
+ <link>http://bash.org.ru/quote/414919</link>
+ <title>Öèòàòà #414919</title>
+ <pubDate>Tue, 27 Dec 2011 09:45:45 +0400</pubDate>
+ <description><![CDATA[Seryozha:<br>ðîçîâûé óæå íå ìîäíî â ýòîì ñåçîíå<br>ñòîÿë íà îñòàíîâêå<br>ïðîåõàë ìèìî ðîçîâûé ëèìóçèí<br>îäíà ôèôà äðóãîé ñêàçàëà, ÷òî ýòî áåçâêóñèöà<br>è ýòî âîîáùå óåáèùå<br>íó è ïîòîì ùåìèëèñü ñî ìíîé â àâòîáóñ]]></description>
+ </item>
+ <item>
+ <guid isPermaLink="false">7b098f0d541bdc4ac0f90634a82e781d38e174ef380aa56ff6c94e69734fcde8</guid>
+ <link>http://bash.org.ru/quote/414918</link>
+ <title>Öèòàòà #414918</title>
+ <pubDate>Tue, 27 Dec 2011 09:44:43 +0400</pubDate>
+ <description><![CDATA[Worontzoff: Èçáèðàòåëüíûå ó÷àñòêè áóäóò îñíàùåíû êàìåðàìè, êóäà áóäóò ïîìåùàòü íàáëþäàòåëåé âî âðåìÿ ïîäñ÷åòà áþëëåòåíåé.]]></description>
+ </item>
+ <item>
+ <guid isPermaLink="false">5af15998f29f5f063b9ce01b54dc8d3f0b73bb7d3f877edcc5eaa7ff8f71013b</guid>
+ <link>http://bash.org.ru/quote/414917</link>
+ <title>Öèòàòà #414917</title>
+ <pubDate>Tue, 27 Dec 2011 09:44:01 +0400</pubDate>
+ <description><![CDATA[õõõ: Ó íàñ â äâà ÷àñà íî÷è ïðèøåñòâèå Âèííè Ïóõà<br>óóó:  ñìûñëå? Ìàìà ïðèøëà?<br>õõõ: Íå, Êîëÿ ìåä â õîëîäèëüíèêå íàøåë. Õîäèò ïî êâàðòèðå, íåæíî ïðèæèìàÿ ê ñåáå áàíêó. ß ñåãîäíÿ Ïÿòà÷îê]]></description>
+ </item>
+ <item>
+ <guid isPermaLink="false">b5a66cb535552b46159d467911174f1e4aac941c8c1d891a62619a8cdb00a3ea</guid>
+ <link>http://bash.org.ru/quote/414916</link>
+ <title>Öèòàòà #414916</title>
+ <pubDate>Tue, 27 Dec 2011 09:13:02 +0400</pubDate>
+ <description><![CDATA[(ðàçãîâîð î &quot;Ëåáåäèíîì Îçåðå&quot;)<br>xxx: ìîæåò áûòü, òû è ñþæåò ïîìíèøü?<br>yyy: î÷åíü ñìóòíî. ß ñîâñåì ìàëåíüêàÿ áûëà, êîãäà åãî â ïîñëåäíèé ðàç ïîêàçûâàëè...]]></description>
+ </item>
+ <item>
+ <guid isPermaLink="false">9e007ee3d9984de85c727f6885f913891b11676f10b053ba8a51bec6fba0e23c</guid>
+ <link>http://bash.org.ru/quote/414915</link>
+ <title>Öèòàòà #414915</title>
+ <pubDate>Tue, 27 Dec 2011 08:46:11 +0400</pubDate>
+ <description><![CDATA[xxx: ïðèâåò<br>xxx: êàê ñëóæáà?<br>yyy: êàê ó ñëóæåáíîé ñîáàêè<br>yyy: öåëûé äåíü ñïàñàþ ìèð, à âå÷åðîì îáåùàëè ïîêîðìèòü]]></description>
+ </item>
+ <item>
+ <guid isPermaLink="false">3dc9ddc2fad185181993315c5c3a404405ab704423d3c24bd9213dcb23bad2eb</guid>
+ <link>http://bash.org.ru/quote/414914</link>
+ <title>Öèòàòà #414914</title>
+ <pubDate>Tue, 27 Dec 2011 08:45:01 +0400</pubDate>
+ <description><![CDATA[õõõ: íåò, ÿ ñêîðåå ïîéäó óáèâàòü, ÷åì êðàñòü<br>óóó: ñòðàííàÿ ìîðàëü, ÷òî òàê?<br>õõõ: ÿ ÷åëîâåê ÷åñòíûé, à ïîòîìó çëîé]]></description>
+ </item>
+ <item>
+ <guid isPermaLink="false">61e793991c5dea07ea5a5afa2bbc899e49c23d8a0d8a1f48918915129a13a35c</guid>
+ <link>http://bash.org.ru/quote/414913</link>
+ <title>Öèòàòà #414913</title>
+ <pubDate>Tue, 27 Dec 2011 08:12:04 +0400</pubDate>
+ <description><![CDATA[Ðå÷ü îá àóäèîíàðêîòèêàõ:<br><br>õõõ: Äà ôèãíÿ ýòî âñ¸!<br>yyy: Íó ïî÷åìó ôèãíÿ, åñòü æå çâóêè, êîòîðûå êàê-òî âîçäåéñòâóþò íà ïñèõèêó ÷åëîâåêà...<br>õõõ: Äà, íà ìåíÿ çâóê äðåëè òàê âîçäåéñòâóåò! Ñðàçó õî÷åòñÿ ïîéòè è óáèòü êîãî-íèáóäü!]]></description>
+ </item>
+ <item>
+ <guid isPermaLink="false">ed2932ac0768ceb5ec1a155d4b039fb2cba050296935d7852baccb238ada1819</guid>
+ <link>http://bash.org.ru/quote/414912</link>
+ <title>Öèòàòà #414912</title>
+ <pubDate>Tue, 27 Dec 2011 08:11:31 +0400</pubDate>
+ <description><![CDATA[&lt;xxx&gt; ãîòîâèëè îáåä, ïîëåç â õîëîäèëüíèê<br>&lt;xxx&gt; îêàçûâàåòñÿ, â÷åðà ÿ íåâîëüíî êóïèë ïðîäóêòîâûé íàáîð &quot;Çëûå ïòèöû&quot;: íîãè êóðèíûå, ãðóäêà èíäåéêè, ñâèíûå ýñêàëîïû]]></description>
+ </item>
+ <item>
+ <guid isPermaLink="false">1989a43d3a03de416d16788589caaa318ece611245b328df9b1567c13205cf70</guid>
+ <link>http://bash.org.ru/quote/414911</link>
+ <title>Öèòàòà #414911</title>
+ <pubDate>Tue, 27 Dec 2011 08:11:01 +0400</pubDate>
+ <description><![CDATA[xxx: ñêîëüçêî íà óëèöå, äàæå ñîáàêà ãóëÿòü íå õî÷åò<br>yyy: åé-òî ÷òî, ó íå¸ æ ïîëíûé ïðèâîä]]></description>
+ </item>
+ <item>
+ <guid isPermaLink="false">c207fd198261176146047e54ccfff9058582e311ab402e32dfe67837c3e61e64</guid>
+ <link>http://bash.org.ru/quote/414910</link>
+ <title>Öèòàòà #414910</title>
+ <pubDate>Mon, 26 Dec 2011 13:12:49 +0400</pubDate>
+ <description><![CDATA[Ìàìà, êóïèâøàÿ ñâîåìó ðåáåíêó ÷åõîë ê ìîáèëüíîìó òåëåôîíó, ïðèíåñëà åãî â ìàãàçèí, ÷òîáû âåðíóòü ïðîäàâöó.<br><br>Ï: Íà ÷òî æàëóåòåñü?<br>Ì: Ðåáåíîê îòêàçûâàåòñÿ ïîëüçîâàòüñÿ ÷åõëîì.<br>Ï: Ïî÷åìó? ×òî íå óñòðàèâàåò?<br>Ì: Ìû çàêàçûâàëè ÷åõîë ñ ÷åëîâåêîì-ïàóêîì. Íà ÷åõëå íàäïèñü SPIDER-MAN. Òàê âîò, êîãäà çàñòåãèâàåì ìîëíèþ, ñòàíîâèòñÿ íå âèäíî áóêâó S.]]></description>
+ </item>
+ <item>
+ <guid isPermaLink="false">245f34c6c6da77a68ba258f717177e3ecb27865bd7cd72c5966a9bae3d68cdab</guid>
+ <link>http://bash.org.ru/quote/414909</link>
+ <title>Öèòàòà #414909</title>
+ <pubDate>Mon, 26 Dec 2011 13:11:56 +0400</pubDate>
+ <description><![CDATA[xxx: Äàé ôëîìàñòåð, ïàëåö ïîêðàñèòü!<br>yyy: Çà÷åì?<br>xxx: Èäó â ãîñòè, à ó ìåíÿ íîñîê äûðÿâûé!]]></description>
+ </item>
+ <item>
+ <guid isPermaLink="false">b9674cdf642593a5c193c3262031513822c50bcb950170cc07aadfb7fddc2649</guid>
+ <link>http://bash.org.ru/quote/414908</link>
+ <title>Öèòàòà #414908</title>
+ <pubDate>Mon, 26 Dec 2011 13:11:02 +0400</pubDate>
+ <description><![CDATA[*  ÷àò âõîäèò Âàçåëèí.<br>Âàçåëèí: ñòóäåíòû, ÿ ïðèøåë<br>Âàçåëèí: êîìó ñêîëüêî?<br>Âàçåëèí: ïîðà áû óæå çàêàçûâàòü]]></description>
+ </item>
+ <item>
+ <guid isPermaLink="false">f5e384c1050a5d6df2cbe999fbae0e082deda5e89839ad0a913b490b3fada8c0</guid>
+ <link>http://bash.org.ru/quote/414907</link>
+ <title>Öèòàòà #414907</title>
+ <pubDate>Mon, 26 Dec 2011 12:46:14 +0400</pubDate>
+ <description><![CDATA[õõõ: ãóëÿëè ñ ðåáåíêîì â ïàðêå, êîðìèëè óòî÷åê<br>õõõ: ñíà÷àëà èõ áûëî íåñêîëüêî øòóê, ïîòîì ïîäïëûëè åùå, íåêîòîðûå ïèêèðîâàëè ñ âîçäóõà)))<br>õõõ: ïðèëè÷íîå êîëè÷åñòâî ñîáðàëîñü, â îáùåì, íåêîòîðûå âûëåçëè íà áåðåã è ïîäîøëè ê íàì ïî÷òè âïëîòíóþ<br>õõõ: â êàêîé-òî ìîìåíò ìíå ñòàëî ñòðåìíî, ÷òî áóëêà êîí÷àåòñÿ]]></description>
+ </item>
+ <item>
+ <guid isPermaLink="false">71aba0126bc495b6efcd494e8b95c11b4e27fadb96f8fa31475db7aa85c7f1a4</guid>
+ <link>http://bash.org.ru/quote/414906</link>
+ <title>Öèòàòà #414906</title>
+ <pubDate>Mon, 26 Dec 2011 12:45:14 +0400</pubDate>
+ <description><![CDATA[xxx: &quot;Åñëè âû ÷èòàëè ðîìàí Æþëÿ Âåðíà èëè õîòÿ áû ñìîòðåëè ôèëüì ñ îäíîèì¸ííûì íàçâàíèåì, òî áóäåòå íå òî ÷òîáû ðàçî÷àðîâàííû, âû, ìÿãêî ãîâîðÿ, áóäåòå øîêèðîâàíû óâèäåííûì, íà÷èíàÿ ñ ïåðâûõ ñåêóíä ôèëüìà&quot;<br><br>xxx: êòî áû áëÿòü ìîã ïîäóìàòü, ÷òî èìåííî òàê íà÷èíàåòñÿ ðåöåíçèÿ ê ôèëüìó Ìóøêåò¸ðû...]]></description>
+ </item>
+ <item>
+ <guid isPermaLink="false">3d3b28ac59593143fe32ecbb4c5df048f39482f38d336d6dc4ad119ffbeea78b</guid>
+ <link>http://bash.org.ru/quote/414905</link>
+ <title>Öèòàòà #414905</title>
+ <pubDate>Mon, 26 Dec 2011 12:44:01 +0400</pubDate>
+ <description><![CDATA[xxx: à âåäóùèé ïðîãðàììèñò - ýòî òàêîé ïðîãðàììèñò, êîòîðûé ìîæåò ðåøèòü ëþáóþ ïîñòàâëåííóþ çàäà÷ó åãî ïðîôèëÿ ñàìîñòîÿòåëüíî<br>yyy: íî íå õî÷åò )]]></description>
+ </item>
+ <item>
+ <guid isPermaLink="false">2931790e946054e81789e63e91d5dc9237bf492d3f26c6d7bc530b59ef2672fe</guid>
+ <link>http://bash.org.ru/quote/414904</link>
+ <title>Öèòàòà #414904</title>
+ <pubDate>Mon, 26 Dec 2011 12:13:01 +0400</pubDate>
+ <description><![CDATA[xxx: Ïîãîäèòå, íà àíäðîèäå ïðîõîäèò àâòîðèçàöèÿ ïî ðàñïîçíàâàíèþ ëèöà? Òî åñòü, åñëè ìíå íàáüþò ìîðäó, ÿ íå ñìîãó â ñêîðóþ ïîçâîíèòü?<br>yyy: Áîþñü, ÷òî íàáèòèå ìîðäû è îòú¸ì ñìàðòôîíà - ñîáûòèÿ ñèëüíî ñêîððåëèðîâàííûå, òàê ÷òî Âàøà ïðîáëåìà íåñêîëüêî íàäóìàííà. :)]]></description>
+ </item>
+ <item>
+ <guid isPermaLink="false">5ee6027cf4758aa3989a3552db60d21acfc4bce66518265e9137abc3ce1fc3c7</guid>
+ <link>http://bash.org.ru/quote/414903</link>
+ <title>Öèòàòà #414903</title>
+ <pubDate>Mon, 26 Dec 2011 11:46:01 +0400</pubDate>
+ <description><![CDATA[leon:<br>Ñåãîäíÿ îòâîæó ðåáåíêà â øêîëó, à òàì ñòåíä íîâûé ïîâåñèëè ñ ôîòîãðàôèÿìè ó÷èòåëåé. Îçàãëàâëåíî ãîðäî &quot;Ñåðäöå íàøåé øêîëû!&quot;. Ðÿäîì ñ ôîòîãðàôèåé òðóäîâèêà â áåðåòå, ìàðêåðîì ñòðåëî÷êà è íàäïèñü &quot;ýòî ïå÷åíü&quot;.]]></description>
+ </item>
+ <item>
+ <guid isPermaLink="false">a47fdbea7602bfa4df71054ed3d391d00a1c0dd13f8adaa983bb5f93e5ac3d90</guid>
+ <link>http://bash.org.ru/quote/414902</link>
+ <title>Öèòàòà #414902</title>
+ <pubDate>Mon, 26 Dec 2011 11:13:01 +0400</pubDate>
+ <description><![CDATA[xxx: áåçðàáîòíûé ñòóäåíò âñåì ñâîèì âèäîì äîêàçûâàåò íàì, ÷òî ìèíèìàëüíîãî ðàçìåðà îïëàòû òðóäà íå ñóùåñòâóåò.]]></description>
+ </item>
+ <item>
+ <guid isPermaLink="false">bc8b51fdf44d63edc888ad063db2fa66d1ad92c48d999408fff00a8cbec8e4ae</guid>
+ <link>http://bash.org.ru/quote/414901</link>
+ <title>Öèòàòà #414901</title>
+ <pubDate>Mon, 26 Dec 2011 10:46:12 +0400</pubDate>
+ <description><![CDATA[Psihodel: ñåãîäíÿ ñ óòðà ïðèøëà ñìñ &quot;Ìàì êèíü óòðîì íà ìòñ õõõ-õõ-õõ-õõ 950ð. Ìíå íå çâîíè. Ïîçæå îáúÿñíþ.&quot; ×åðåç ÷àñ ìíå æåíà ñîîáùàåò, ÷òî îíà áåðåìåííà. Òåïåðü ÿ ïîíÿë, ïî÷åìó íå íàäî çâîíèòü. Âîò ëåò ÷åðåç 5 óçíàþ, çà÷åì åìó íàäî áûëî 950ð.]]></description>
+ </item>
+ <item>
+ <guid isPermaLink="false">e5174f709f5372c11eaf170b06efe25bf23fd3a65dbc9669e7b55b83ad598340</guid>
+ <link>http://bash.org.ru/quote/414900</link>
+ <title>Öèòàòà #414900</title>
+ <pubDate>Mon, 26 Dec 2011 10:45:01 +0400</pubDate>
+ <description><![CDATA[xxx: Çàâòðà âñòðå÷à îäíîãðóïïíèêîâ. â 16:00 â Ïàáå íà Òàãàíêå. Íó ÷åãî, òû áóäåøü ?<br>yyy: Âîäêó<br>yyy: Äóìàþ ÿ îòâåòèë ñðàçó íà äâà âîïðîñà]]></description>
+ </item>
+ <item>
+ <guid isPermaLink="false">0f5c7eaee411484a37e8071fb60030eb902f42a26969363233116d425faec446</guid>
+ <link>http://bash.org.ru/quote/414899</link>
+ <title>Öèòàòà #414899</title>
+ <pubDate>Mon, 26 Dec 2011 10:12:34 +0400</pubDate>
+ <description><![CDATA[Íàñòîÿùèé ðàäèîëþáèòåëü, îòêðûâ ñïè÷å÷íûé êîðîáîê è îáíàðóæèâ òàì ñïè÷êè, ñìîòðèò íà íèõ Ñ ÓÄÈÂËÅÍÈÅÌ]]></description>
+ </item>
+ <item>
+ <guid isPermaLink="false">1941999057f97da275dbaee167f5314de54a3de0f1ccc0f25c983cfe08845e71</guid>
+ <link>http://bash.org.ru/quote/414898</link>
+ <title>Öèòàòà #414898</title>
+ <pubDate>Mon, 26 Dec 2011 10:12:01 +0400</pubDate>
+ <description><![CDATA[xxx: Åñëè â âàøåé æèçíè ïîñòîÿííî ïðîèñõîäèò êàêàÿ-òî õåðíÿ, òî ñòîèò çàäóìàòüñÿ, à íå âû ëè òà ñàìàÿ õåðíÿ.]]></description>
+ </item>
+ <item>
+ <guid isPermaLink="false">1493df9ec128867419e1c9e0f8adf1e7c73eaecba9ba81e51395778f2c599faf</guid>
+ <link>http://bash.org.ru/quote/414897</link>
+ <title>Öèòàòà #414897</title>
+ <pubDate>Mon, 26 Dec 2011 09:46:15 +0400</pubDate>
+ <description><![CDATA[õõõ: ïëîõàÿ ýòî èäåÿ, ñ äåòñêèìè äîìàøíèìè ïðàçäíèêàìè.<br>óóó: äà ïî÷åìó? ó ìåíÿ çíàêîìûå ýòèì êàæäûå ïðàçäíèêè çàíèìàþòñÿ. âïîëíå íåïëîõî äëÿ ïîäðàáîòêè, âåñåëî + ñðàçó äåíüãè â êàðìàíå.<br>õõõ: ïàðó ëåò íàçàä ìû ñ ïîäðóãîé òîæå ðàçäîáûëè íîâîãîäíèõ êîñòþìîâ, íàïèñàëè âåñåëûé ñöåíàðèé è ðàçâåñëèëè îáúÿâëåíèÿ: &quot;Âîëøåáíîå íîâîãîäíåå ïðèêëþ÷åíèå îò ñåñòðè÷åê-Ñíåãóðî÷åê â âàøåì äîìå&quot;.<br>õõõ: àõ âû ìîè íåèñïîð÷åííûå!<br>óóó: àãà, âñå ïðàâèëüíî ïîíÿë.]]></description>
+ </item>
+ <item>
+ <guid isPermaLink="false">507045f7af9d1dbc586b1ea528ecc9edb09ea5a1f35dab1141afc0dee491c7f2</guid>
+ <link>http://bash.org.ru/quote/414896</link>
+ <title>Öèòàòà #414896</title>
+ <pubDate>Mon, 26 Dec 2011 09:45:01 +0400</pubDate>
+ <description><![CDATA[CKuB: ÇÀß, áëÿ! Ïåðåëîæèòü âñå ãîâíî íà ìîþ ïîëêó - ýòî íå òî, ÷òî ÿ èìåë â âèäó, ïðîñÿ íàâåñòè ïîðÿäîê ó ñåáÿ íà ïîëêå!]]></description>
+ </item>
+ <item>
+ <guid isPermaLink="false">e4f30a21e7ffa737cc164ea71ddf1fe24a2c87b269a1b47db1dbf591ebe3e843</guid>
+ <link>http://bash.org.ru/quote/414895</link>
+ <title>Öèòàòà #414895</title>
+ <pubDate>Mon, 26 Dec 2011 09:12:45 +0400</pubDate>
+ <description><![CDATA[xxx: Àäìèíñêàÿ ïðèìåòà.<br>xxx: Åñëè 12-ëåòíèé ñûí íà÷àëüíèêà èäåò â ñåðâåðíóþ - ê áîëüøîé áåäå.]]></description>
+ </item>
+ <item>
+ <guid isPermaLink="false">0ac1bcd3e77c115764edf2fef78568d7e88f0dcfa2830ebff7a4a67ca246192b</guid>
+ <link>http://bash.org.ru/quote/414894</link>
+ <title>Öèòàòà #414894</title>
+ <pubDate>Mon, 26 Dec 2011 09:11:52 +0400</pubDate>
+ <description><![CDATA[Vegyja: ðîìàíòèêà - ÷åì åå ìåíüøå, òåì ëó÷øå. åñëè ïàðåíü òîëüêî è äåëàåò, ÷òî ñòðàäàåò òàêîé ôèãíåé... âîïðîñ âîçíèêàåò: à ìóæ÷èíà ëè îí?<br>Telecantrelem: À åñëè ïðåäëîæèòü äåâóøêå áóòåðáðîä ñ êîëáàñîé - ýòî ðîìàíòèêà?<br>1143r: Telecantrelem, â îïðåäåëåííûõ îáñòîÿòåëüñòâàõ ýòî î÷åíü äàæå ðîìàíòè÷íî. Íàïðèìåð, Îíà âûïèëà ñòàêàí ñàìîãîíó, à çàêóñèòü íå÷åì. À òóò òû ñ áóòåðîì. Îïà! Íà, åøü!]]></description>
+ </item>
+ <item>
+ <guid isPermaLink="false">0b0d1ae0708037d49d4edd71c8e1d7a488907c379787b7827be44ba7adab6cef</guid>
+ <link>http://bash.org.ru/quote/414893</link>
+ <title>Öèòàòà #414893</title>
+ <pubDate>Mon, 26 Dec 2011 09:11:01 +0400</pubDate>
+ <description><![CDATA[Èç îáúÿñíèòåëüíîé çàïèñêè:<br><br>12.12 íà ñêëàäå ¹4 áûë ðàçãðóæåí ëàìèíàò &quot;...&quot; ñ áîëüøèì êîëè÷åñòâîì áðàêà. Ïà÷êè áûëè îòñîðòèðîâàíû ìíîé è ïîäïèñàíû, õîðîøèå ïà÷êè &quot;Õ&quot;, à ïëîõèå ïà÷êè &quot;Ï&quot;. Ïðè âîçâðàòå òîâàðà ïîñòàâùèêó, íà÷àëüíèê ñêëàäà îøèáî÷íî ïîñ÷èòàë, ÷òî &quot;Õ&quot; îçíà÷àåò &quot;õó¸âûå&quot;, à &quot;Ï&quot; îçíà÷àåò &quot;ïèçäàòûå&quot;, ÷òî â êîðíå ìåíÿëî ñèòóàöèþ. Ãðóç÷èêè åãî ïîääåðæàëè è íà âîçâðàò áûë îòãðóæåí êà÷åñòâåííûé òîâàð. Âèíîâíûì â äàííîì èíöèäåíòå ñåáÿ íå ïðèçíàþ, óñëóãè òðàíñïîðòíîé êîìïàíèè îïëà÷èâàòü îòêàçûâàþñü.]]></description>
+ </item>
+ <item>
+ <guid isPermaLink="false">4caeec3b83a23c4ef7e6822f1b9151c62dd719538f9719fd9dc49079edf12869</guid>
+ <link>http://bash.org.ru/quote/414892</link>
+ <title>Öèòàòà #414892</title>
+ <pubDate>Mon, 26 Dec 2011 08:46:01 +0400</pubDate>
+ <description><![CDATA[Ëåíà: ÷òî äåëàòü, åñëè êîò ñïèò, ÿ îäíà äîìà, à íà êóõíå ãðîõîò?<br>Îëåã: êèíü òóäà êîòà)]]></description>
+ </item>
+ <item>
+ <guid isPermaLink="false">533d63288a28594dd6858f5eb212c9fd62c95da02ef6c532902585a525f78b2e</guid>
+ <link>http://bash.org.ru/quote/414891</link>
+ <title>Öèòàòà #414891</title>
+ <pubDate>Mon, 26 Dec 2011 08:13:01 +0400</pubDate>
+ <description><![CDATA[îí: Ðàññêàæè ìíå ñêàçêó<br>îíà: Æèëà-áûëà íåêàÿ ôóíêöèÿ ýô îò èêñ, è áûëà îíà äèôôåðåíöèðóåìà íà âñåé ýïñèëîí-îêðåñòíîñòè íåêîé òî÷êè èêñ íóëåâîå<br>îíà: Ó ìåíÿ ÷èñëåííûå ìåòîäû )<br>îíà: Èçâèíè )]]></description>
+ </item>
+ <item>
+ <guid isPermaLink="false">92cf655d26cbe5d10b1af532ab4abb491a0d74ae9759cb81cd6dd4bb84a1d2bc</guid>
+ <link>http://bash.org.ru/quote/414890</link>
+ <title>Öèòàòà #414890</title>
+ <pubDate>Sun, 25 Dec 2011 09:13:01 +0400</pubDate>
+ <description><![CDATA[ñìñ èç î÷åðåäè ê âðà÷ó<br><br>õõõ: Ìàìà, çà ÷àñ ïðèíÿëè òîëüêî äâóõ áîëüíûõ è îíè äî ñèõ ïîð òàì. ïåðåäî ìíîé 12 çëûõ è îïàñíûõ áàáóøåê, êîòîðûå óæå óñïåëè çàêàòèòü äâà ñêàíäàëà ñ ïðèìåíåíèåì äâåðè è ãðóáîé ôèçè÷åñêîé ñèëû òåì, êòî ïûòàëñÿ ïðîéòè áåç î÷åðåäè. Ïîä÷¸ðêèâàþ: ÏÛÒÀËÑß! Ìíå åñòü ñìûñë ñèäåòü äàëüøå?]]></description>
+ </item>
+ </channel>
+</rss> \ 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 <windows.h>
+#include <commctrl.h>
+#include <time.h>
+#include <fcntl.h>
+#include <io.h>
+#include <errno.h>
+#include <string.h>
+#include <stdlib.h>
+#include <sys\stat.h>
+
+#include <boost/regex.hpp>
+
+// Miranda header files
+#include <newpluginapi.h>
+#include <m_clist.h>
+#include <m_skin.h>
+#include <m_langpack.h>
+#include <m_options.h>
+#include <m_database.h>
+#include <m_utils.h>
+#include <m_system.h>
+#include <m_popup.h>
+#include <m_hotkeys.h>
+#include <m_netlib.h>
+#include <m_icolib.h>
+#include <win2k.h>
+#include <m_protocols.h>
+#include <m_protomod.h>
+#include <m_protosvc.h>
+#include <m_xml.h>
+#include <m_avatars.h>
+
+#include <m_folders.h>
+#include <m_popup.h>
+
+#include "..\version.h"
+#include "..\resource.h"
+
+#define MODULE "NewsAggr"
+#define TAGSHELP "#<title># - 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(&current[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"), &timestamp.tm_hour, &timestamp.tm_min, &timestamp.tm_sec ) != 3 )
+ return ( time_t ) 0;
+
+ timestamp.tm_isdst = 0; // DST is already present in _timezone below
+ t = mktime( &timestamp );
+
+ _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&QUOTES_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
--- /dev/null
+++ b/protocols/Quotes/QuotesProviderBase.cpp
Binary files 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
--- /dev/null
+++ b/protocols/Quotes/QuotesProviderDukasCopy.cpp
Binary files 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(),
+ [&quote](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/?&amp;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&amp;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
--- /dev/null
+++ b/protocols/Quotes/res/CurrencyConverter.ico
Binary files differ
diff --git a/protocols/Quotes/res/Export quotes.ico b/protocols/Quotes/res/Export quotes.ico
new file mode 100644
index 0000000000..31c7aa2ba1
--- /dev/null
+++ b/protocols/Quotes/res/Export quotes.ico
Binary files differ
diff --git a/protocols/Quotes/res/Import quotes.ico b/protocols/Quotes/res/Import quotes.ico
new file mode 100644
index 0000000000..506aa62af3
--- /dev/null
+++ b/protocols/Quotes/res/Import quotes.ico
Binary files differ
diff --git a/protocols/Quotes/res/Refresh.ico b/protocols/Quotes/res/Refresh.ico
new file mode 100644
index 0000000000..2dbcfd3878
--- /dev/null
+++ b/protocols/Quotes/res/Refresh.ico
Binary files differ
diff --git a/protocols/Quotes/res/Section.ico b/protocols/Quotes/res/Section.ico
new file mode 100644
index 0000000000..f59105b665
--- /dev/null
+++ b/protocols/Quotes/res/Section.ico
Binary files differ
diff --git a/protocols/Quotes/res/down.ico b/protocols/Quotes/res/down.ico
new file mode 100644
index 0000000000..9dfe185cbe
--- /dev/null
+++ b/protocols/Quotes/res/down.ico
Binary files differ
diff --git a/protocols/Quotes/res/main.ico b/protocols/Quotes/res/main.ico
new file mode 100644
index 0000000000..4d32e57495
--- /dev/null
+++ b/protocols/Quotes/res/main.ico
Binary files differ
diff --git a/protocols/Quotes/res/notchanged.ico b/protocols/Quotes/res/notchanged.ico
new file mode 100644
index 0000000000..e1d9ee3a09
--- /dev/null
+++ b/protocols/Quotes/res/notchanged.ico
Binary files differ
diff --git a/protocols/Quotes/res/proto_na.ico b/protocols/Quotes/res/proto_na.ico
new file mode 100644
index 0000000000..c8888adb80
--- /dev/null
+++ b/protocols/Quotes/res/proto_na.ico
Binary files differ
diff --git a/protocols/Quotes/res/proto_occupied.ico b/protocols/Quotes/res/proto_occupied.ico
new file mode 100644
index 0000000000..3f54c740d1
--- /dev/null
+++ b/protocols/Quotes/res/proto_occupied.ico
Binary files differ
diff --git a/protocols/Quotes/res/proto_offline.ico b/protocols/Quotes/res/proto_offline.ico
new file mode 100644
index 0000000000..cd99c072bf
--- /dev/null
+++ b/protocols/Quotes/res/proto_offline.ico
Binary files differ
diff --git a/protocols/Quotes/res/proto_online.ico b/protocols/Quotes/res/proto_online.ico
new file mode 100644
index 0000000000..29e500e2bb
--- /dev/null
+++ b/protocols/Quotes/res/proto_online.ico
Binary files differ
diff --git a/protocols/Quotes/res/quote.ico b/protocols/Quotes/res/quote.ico
new file mode 100644
index 0000000000..832ed12f52
--- /dev/null
+++ b/protocols/Quotes/res/quote.ico
Binary files differ
diff --git a/protocols/Quotes/res/swap.ico b/protocols/Quotes/res/swap.ico
new file mode 100644
index 0000000000..1bff71b764
--- /dev/null
+++ b/protocols/Quotes/res/swap.ico
Binary files differ
diff --git a/protocols/Quotes/res/up.ico b/protocols/Quotes/res/up.ico
new file mode 100644
index 0000000000..a75899cd3d
--- /dev/null
+++ b/protocols/Quotes/res/up.ico
Binary files 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
--- /dev/null
+++ b/protocols/Twitter/icons/twitter.ico
Binary files 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("&lt;")) != std::string::npos)
+ s.replace(off,4,"<");
+ while( (off = s.find("&gt;")) != 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</title>
+ <file>YAMN.dll</file>
+ </packageinfo>
+
+ <packageinfo>
+ <optional/>
+ <title>Documentation</title>
+ <file>YAMN-Readme.txt</file>
+ <file>YAMN-License.txt</file>
+ <document/>
+ </packageinfo>
+
+ <packageinfo>
+ <optional/>
+ <title>Developers Information</title>
+ <file>YAMN-Readme.developers.txt</file>
+ <document/>
+ </packageinfo>
+
+ <packageinfo>
+ <optional/>
+ <title>Simple filter plugin</title>
+ <file>YAMN\simple.dll</file>
+ <file>YAMN\simple-readme.txt</file>
+ </packageinfo>
+
+ <packageinfo>
+ <optional/>
+ <title>Base filter plugin</title>
+ <file>YAMN\base.dll</file>
+ <file>YAMN\base-readme.txt</file>
+ </packageinfo>
+
+ <autorun>
+ <file>YAMN-Readme.txt</file>
+ <document/>
+ </autorun>
+
+</installscript>
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.
+
+ <one line to give the program's name and a brief idea of what it does.>
+ Copyright (C) 19yy <name of author>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+
+Also add information on how to contact you by electronic and paper mail.
+
+If the program is interactive, make it output a short notice like this
+when it starts in an interactive mode:
+
+ Gnomovision version 69, Copyright (C) 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.
+
+ <signature of Ty Coon>, 1 April 1989
+ Ty Coon, President of Vice
+
+This General Public License does not permit incorporating your program into
+proprietary programs. If your program is a subroutine library, you may
+consider it more useful to permit linking proprietary applications with the
+library. If this is what you want to do, use the GNU Library General
+Public License instead of this License.
diff --git a/protocols/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 <Mike@Geary.com> 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 Gëzim Pani <gpani@siu.edu> 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 gültiges Makefile. Zum Erstellen dieses Projekts mit NMAKE
+!MESSAGE verwenden Sie den Befehl "Makefile exportieren" und führen Sie den Befehl
+!MESSAGE
+!MESSAGE NMAKE /f "Base.mak".
+!MESSAGE
+!MESSAGE Sie können beim Ausführen 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 Für 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 <windows.h>
+#include <tchar.h>
+#include <stdio.h>
+
+
+//--------------------------------------------------------------------------------------------------
+//--------------------------------------------------------------------------------------------------
+
+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 <tab>, press the substring of value needed to be found, press <tab>, define spamlevel and then press <Enter>.
+
+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 <windows.h>
+#include <stdio.h>
+#include <string.h>
+#include <time.h>
+#include <newpluginapi.h>
+#include <m_system.h>
+#include <m_langpack.h>
+#include <m_options.h>
+#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,"<New mail>\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,"<Testing header item %s: %s>\n",Browser->name,Browser->value);
+#endif
+ for(int i=0;i<fts;i++)
+ if (!lstrcmpi(Browser->name,ft[i].name))
+ {
+#ifdef DEBUG_FILTER
+ DebugLog(FilterFile,"\t\t<Found appropriate selector %s>\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</Found appropriate selector>\n");
+#endif
+ }
+#ifdef DEBUG_FILTER
+ DebugLog(FilterFile,"</Testing header>\n");
+#endif
+ }
+#ifdef DEBUG_FILTER
+ DebugLog(FilterFile,"</New mail>\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,"<Loading rules from file %s>\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<Rule><selector>%s</selector><value>%s</value><spamlevel>%d</spamlevel>\n",name,value,sl);
+#endif
+ }
+ }
+ }
+ }
+
+ fclose(fp);
+#ifdef DEBUG_FILTER
+ DebugLog(FilterFile,"</Loading rules>\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 <Mike@Geary.com> 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 Gëzim Pani <gpani@siu.edu> 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 <tab> 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 <windows.h>
+#include <stdio.h>
+#include <string.h>
+#include <time.h>
+#include <newpluginapi.h>
+#include <m_system.h>
+#include <m_langpack.h>
+#include <m_options.h>
+#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 gültiges Makefile. Zum Erstellen dieses Projekts mit NMAKE
+!MESSAGE verwenden Sie den Befehl "Makefile exportieren" und führen Sie den Befehl
+!MESSAGE
+!MESSAGE NMAKE /f "simple.mak".
+!MESSAGE
+!MESSAGE Sie können beim Ausführen 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 Für 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
--- /dev/null
+++ b/protocols/YAMN/icons/iconttbup.ico
Binary files differ
diff --git a/protocols/YAMN/icons/icoyamn1.ico b/protocols/YAMN/icons/icoyamn1.ico
new file mode 100644
index 0000000000..d3959b4fd7
--- /dev/null
+++ b/protocols/YAMN/icons/icoyamn1.ico
Binary files differ
diff --git a/protocols/YAMN/icons/icoyamn2.ico b/protocols/YAMN/icons/icoyamn2.ico
new file mode 100644
index 0000000000..dfada56b5f
--- /dev/null
+++ b/protocols/YAMN/icons/icoyamn2.ico
Binary files 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 @@
+<?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_YAMN</ProjectName>
+ <ProjectGuid>{C1CDB82C-6BBF-496E-88F4-CC57E60B0CA9}</ProjectGuid>
+ </PropertyGroup>
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
+ <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>
+ <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>
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
+ <ImportGroup Label="ExtensionSettings">
+ </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" />
+ <Import Project="$(VCTargetsPath)Microsoft.CPP.UpgradeFromVC60.props" />
+ </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" />
+ <Import Project="$(VCTargetsPath)Microsoft.CPP.UpgradeFromVC60.props" />
+ </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" />
+ <Import Project="$(VCTargetsPath)Microsoft.CPP.UpgradeFromVC60.props" />
+ </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" />
+ <Import Project="$(VCTargetsPath)Microsoft.CPP.UpgradeFromVC60.props" />
+ </ImportGroup>
+ <PropertyGroup Label="UserMacros" />
+ <PropertyGroup>
+ <_ProjectFileVersion>10.0.30319.1</_ProjectFileVersion>
+ <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>
+ <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>
+ <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)'=='Release|Win32'">
+ <ResourceCompile>
+ <PreprocessorDefinitions>NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <AdditionalIncludeDirectories>..\..\include\msapi</AdditionalIncludeDirectories>
+ </ResourceCompile>
+ <Link>
+ <SubSystem>Windows</SubSystem>
+ <NoEntryPoint>true</NoEntryPoint>
+ <RandomizedBaseAddress>false</RandomizedBaseAddress>
+ <OptimizeReferences>true</OptimizeReferences>
+ <EnableCOMDATFolding>true</EnableCOMDATFolding>
+ </Link>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
+ <ResourceCompile>
+ <PreprocessorDefinitions>NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <AdditionalIncludeDirectories>..\..\include\msapi</AdditionalIncludeDirectories>
+ </ResourceCompile>
+ <Link>
+ <SubSystem>Windows</SubSystem>
+ <NoEntryPoint>true</NoEntryPoint>
+ <RandomizedBaseAddress>false</RandomizedBaseAddress>
+ <OptimizeReferences>true</OptimizeReferences>
+ <EnableCOMDATFolding>true</EnableCOMDATFolding>
+ </Link>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+ <ResourceCompile>
+ <PreprocessorDefinitions>_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <AdditionalIncludeDirectories>..\..\include\msapi</AdditionalIncludeDirectories>
+ </ResourceCompile>
+ <Link>
+ <SubSystem>Windows</SubSystem>
+ <NoEntryPoint>true</NoEntryPoint>
+ <RandomizedBaseAddress>false</RandomizedBaseAddress>
+ </Link>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
+ <ResourceCompile>
+ <PreprocessorDefinitions>_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <AdditionalIncludeDirectories>..\..\include\msapi</AdditionalIncludeDirectories>
+ </ResourceCompile>
+ <Link>
+ <SubSystem>Windows</SubSystem>
+ <NoEntryPoint>true</NoEntryPoint>
+ <RandomizedBaseAddress>false</RandomizedBaseAddress>
+ </Link>
+ </ItemDefinitionGroup>
+ <ItemGroup>
+ <None Include="..\resources\iconeutral.ico" />
+ <None Include="..\resources\iconttbdown.ico" />
+ <None Include="iconttbup.ico" />
+ <None Include="..\resources\icooffline.ico" />
+ <None Include="icoyamn1.ico" />
+ <None Include="icoyamn2.ico" />
+ <None Include="..\resources\icoyamn3.ico" />
+ </ItemGroup>
+ <ItemGroup>
+ <ResourceCompile Include="proto_YAMN.rc">
+ <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Release|x64'">%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ </ResourceCompile>
+ </ItemGroup>
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
+ <ImportGroup Label="ExtensionTargets">
+ </ImportGroup>
+</Project> \ 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 @@
+<?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>{4726e1d1-39cd-435a-bd59-51fdb6745f46}</UniqueIdentifier>
+ <Extensions>ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe</Extensions>
+ </Filter>
+ </ItemGroup>
+ <ItemGroup>
+ <None Include="..\resources\iconeutral.ico">
+ <Filter>Resource Files</Filter>
+ </None>
+ <None Include="..\resources\iconttbdown.ico">
+ <Filter>Resource Files</Filter>
+ </None>
+ <None Include="iconttbup.ico">
+ <Filter>Resource Files</Filter>
+ </None>
+ <None Include="..\resources\icooffline.ico">
+ <Filter>Resource Files</Filter>
+ </None>
+ <None Include="icoyamn1.ico">
+ <Filter>Resource Files</Filter>
+ </None>
+ <None Include="icoyamn2.ico">
+ <Filter>Resource Files</Filter>
+ </None>
+ <None Include="..\resources\icoyamn3.ico">
+ <Filter>Resource Files</Filter>
+ </None>
+ </ItemGroup>
+ <ItemGroup>
+ <ResourceCompile Include="proto_YAMN.rc">
+ <Filter>Resource Files</Filter>
+ </ResourceCompile>
+ </ItemGroup>
+</Project> \ 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,"<CodePage>%s</CodePage>",pout);
+#endif
+ for (int i=0;i<CPLENALL;i++) {
+ size_t len = strlen(CodePageNamesAll[i].NameBase);
+ if (0==strncmp(pout,CodePageNamesAll[i].NameBase,len)) {
+ if (0==strcmp(pout+len,CodePageNamesAll[i].NameSub)) {
+ delete[] pout;
+ return CodePageNamesAll[i].CP;
+ }
+ }
+ }
+ delete[] pout;
+ return -1; //not found
+}
+
+int FromHexa(char HexValue,char *DecValue)
+{
+ if (HexValue>='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,"<Decode Quoted><Input>%s</Input>",Src);
+#endif
+ for (int Counter=0;((char)*Src!=0) && DstLen && (Counter++<DstLen);Src++,Dst++)
+ if (*Src=='=')
+ {
+ if (!isQ){
+ if (Src[1]==0x0D){
+ Src++; Src++;
+ if (Src[0]==0x0A) Src++;
+ goto CopyCharQuotedPrintable;
+ }
+ if (Src[1]==0x0A){
+ Src++; Src++;
+ goto CopyCharQuotedPrintable;
+ }
+ }
+ char First,Second;
+ if (!FromHexa(*(++Src),&First))
+ {
+ *Dst++='=';Src--;
+ continue;
+ }
+ if (!FromHexa(*(++Src),&Second))
+ {
+ *Dst++='=';Src--;Src--;
+ continue;
+ }
+ *Dst=(char)(First)<<4;
+ *Dst+=Second;
+ }
+ else if (isQ && *Src=='_')
+ *Dst=' ';
+ else
+CopyCharQuotedPrintable: // Yeah. Bad programming stile.
+ *Dst=*Src;
+ *Dst=(char)0;
+#ifdef DEBUG_DECODEQUOTED
+ DebugLog(DecodeFile,"<Output>%s</Output></Decode Quoted>",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,"<Decode Base64><Input>\n%s\n</Input>\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,"<Output>\n%s\n</Output></Decode Base64>",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,"<CodePage #>%d</CodePage #>",cp);
+#endif
+
+ for (Index=0;Index<sizeof(CodePagesZeroFlags)/sizeof(CodePagesZeroFlags[0]);Index++)
+ if (CodePagesZeroFlags[Index]==cp)
+ {
+ Index=-1;
+ break;
+ }
+ if (Index==-1)
+ streamlen=MultiByteToWideChar(cp,0,stream,-1,NULL,0);
+ else
+ streamlen=MultiByteToWideChar(cp,MB_USEGLYPHCHARS,stream,-1,NULL,0);
+
+ if (*out!=NULL)
+ outlen=wcslen(*out);
+ else
+ outlen=0;
+ temp=new WCHAR[streamlen+outlen+1];
+
+ if (*out!=NULL)
+ {
+ for (dest=temp;*src!=(WCHAR)0;src++,dest++) //copy old string from *out to temp
+ *dest=*src;
+// *dest++=L' '; //add space?
+ delete[] *out;
+ }
+ else
+ dest=temp;
+ *out=temp;
+
+ if (Index==-1)
+ {
+ if (!MultiByteToWideChar(cp,0,stream,-1,dest,streamlen))
+ return 0;
+ }
+ else
+ {
+ if (!MultiByteToWideChar(cp,MB_USEGLYPHCHARS,stream,-1,dest,streamlen))
+ return 0;
+ }
+ return 1;
+}
+
+void ConvertCodedStringToUnicode(char *stream,WCHAR **storeto,DWORD cp,int mode)
+{
+ char *start=stream,*finder,*finderend;
+ char Encoding=0;
+ char *DecodedResult=NULL;
+
+ if (stream==NULL)
+ return;
+
+ while(WS(start)) start++;
+ WCHAR *tempstore=0;
+ if (!ConvertStringToUnicode(stream,cp,&tempstore))return;
+
+ size_t tempstoreLength = wcslen(tempstore);
+
+ size_t outind = 0;
+ while(*start!=0){
+ if (CODES(start)) {
+ finder=start+2;finderend=finder;
+ while(!CODED(finderend) && !EOS(finderend)) finderend++;
+ start = finderend;
+ if (CODED(finderend))
+ {
+ Encoding=*(finderend+1);
+ switch(Encoding)
+ {
+ case 'b':
+ case 'B':
+ case 'q':
+ case 'Q':
+ break;
+ default:
+ goto NotEncoded;
+ }
+ if (-1==(cp=(DWORD)GetCharsetFromString(finder,finderend-finder)))
+ cp=CP_ACP;
+ if (Encoding!=0)
+ {
+ int size,codeend;
+ char *pcodeend;
+
+ finder=finderend+2;
+ if (CODED(finder))
+ finder++;
+ while(WS(finder)) finder++;
+ finderend=finder;
+ while(!CODEE(finderend) && !EOS(finderend)) finderend++;
+ if (codeend=CODEE(finderend))
+ pcodeend=finderend;
+ while(WS(finderend-1)) finderend--;
+ if ((mode==MIME_MAIL) && (((*finder=='"') && (*(finderend-1)=='"'))))
+ {
+ finder++;
+ finderend--;
+ }
+ //*finderend=(char)0;
+ char * oneWordEncoded = new char[finderend-finder+1];
+ strncpy(oneWordEncoded,finder,finderend-finder);
+ oneWordEncoded[finderend-finder]=0;
+ switch(Encoding)
+ {
+ case 'b':
+ case 'B':
+ size=(finderend-finder)*3/4+3+1+1;
+ break;
+ case 'q':
+ case 'Q':
+ size=finderend-finder+1+1;
+ break;
+ }
+ if (DecodedResult!=NULL)
+ delete[] DecodedResult;
+ DecodedResult=new char[size+1];
+ switch(Encoding)
+ {
+ case 'q':
+ case 'Q':
+ DecodeQuotedPrintable(oneWordEncoded,DecodedResult,size, TRUE);
+ break;
+ case 'b':
+ case 'B':
+ DecodeBase64(oneWordEncoded,DecodedResult,size);
+ break;
+ }
+ delete[] oneWordEncoded;
+ if (codeend)
+ finderend=pcodeend+2;
+ if (WS(finderend)) //if string continues and there's some whitespace, add space to string that is to be converted
+ {
+ size_t len=strlen(DecodedResult);
+ DecodedResult[len]=' ';
+ DecodedResult[len+1]=0;
+ finderend++;
+ }
+ WCHAR *oneWord=0;
+ if (ConvertStringToUnicode(DecodedResult,cp,&oneWord)) {
+ size_t len = wcslen(oneWord);
+ memcpy(&tempstore[outind],oneWord,len*sizeof(WCHAR));
+ outind += len;
+ }
+ delete oneWord;
+ oneWord = 0;
+ delete[] DecodedResult; DecodedResult = 0;
+ start = finderend;
+ } else if (!EOS(start)) start++;
+ } else if (!EOS(start)) start++;
+ }else{
+NotEncoded:
+ tempstore[outind] = tempstore[start-stream];
+ outind++;
+ if (outind > 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<srcend;dst++,srcstart++)
+ {
+ if (ENDLINE(srcstart))
+ {
+ while(ENDLINE(srcstart) || WS(srcstart)) srcstart++;
+ *dst=' ';
+ srcstart--; //because at the end of "for loop" we increment srcstart
+ }
+ else
+ *dst=*srcstart;
+ }
+ *dst=0;
+}
+
+void ExtractAddressFromLine(char *finder,char **storeto,char **storetonick)
+{
+ if (finder==NULL)
+ {
+ *storeto=*storetonick=NULL;
+ return;
+ }
+ while(WS(finder)) finder++;
+ if ((*finder)!='<')
+ {
+ char *finderend=finder+1;
+ do
+ {
+ if (ENDLINEWS(finderend)) //after endline information continues
+ finderend+=2;
+ while(!ENDLINE(finderend) && !EOS(finderend)) finderend++; //seek to the end of line or to the end of string
+ }while(ENDLINEWS(finderend));
+ finderend--;
+ while(WS(finderend) || ENDLINE(finderend)) finderend--; //find the end of text, no whitespace
+ if (*finderend!='>') //not '>' 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,"<Extracting from>");
+ #endif
+ ExtractAddressFromLine(items->value,&head->From,&head->FromNick);
+ #ifdef DEBUG_DECODE
+ DebugLog(DecodeFile,"</Extracting>\n");
+ #endif
+ }
+ else if (0==_strnicmp(items->name,"Return-Path",11))
+ {
+ if (items->value==NULL)
+ continue;
+ #ifdef DEBUG_DECODE
+ DebugLog(DecodeFile,"<Extracting return-path>");
+ #endif
+ ExtractAddressFromLine(items->value,&head->ReturnPath,&head->ReturnPathNick);
+ #ifdef DEBUG_DECODE
+ DebugLog(DecodeFile,"</Extracting>\n");
+ #endif
+ }
+ else if (0==_strnicmp(items->name,"Subject",7))
+ {
+ if (items->value==NULL)
+ continue;
+ #ifdef DEBUG_DECODE
+ DebugLog(DecodeFile,"<Extracting subject>");
+ #endif
+ ExtractStringFromLine(items->value,&head->Subject);
+ #ifdef DEBUG_DECODE
+ DebugLog(DecodeFile,"</Extracting>\n");
+ #endif
+ }
+ else if (0==_strnicmp(items->name,"Body",4))
+ {
+ if (items->value==NULL)
+ continue;
+ #ifdef DEBUG_DECODE
+ DebugLog(DecodeFile,"<Extracting body>");
+ #endif
+ ExtractStringFromLine(items->value,&head->Body);
+ #ifdef DEBUG_DECODE
+ DebugLog(DecodeFile,"</Extracting>\n");
+ #endif
+ }
+ else if (0==_strnicmp(items->name,"Date",4))
+ {
+ if (items->value==NULL)
+ continue;
+ #ifdef DEBUG_DECODE
+ DebugLog(DecodeFile,"<Extracting date>");
+ #endif
+ ExtractStringFromLine(items->value,&head->Date);
+ #ifdef DEBUG_DECODE
+ DebugLog(DecodeFile,"</Extracting>\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,"<Extracting Content-Type>");
+ #endif
+ ExtractStringFromLine(items->value,&ContentType);
+ #ifdef DEBUG_DECODE
+ DebugLog(DecodeFile,"</Extracting>\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,"<Extracting importance>");
+ #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,"</Extracting>\n");
+ #endif
+ }
+ else if (0==_strnicmp(items->name,"X-Priority",10))
+ {
+ if (items->value==NULL)
+ continue;
+ #ifdef DEBUG_DECODE
+ DebugLog(DecodeFile,"<X-Priority>");
+ #endif
+ if ((*items->value>='1') && (*items->value<='5'))
+ head->Priority=*items->value-'0';
+ #ifdef DEBUG_DECODE
+ DebugLog(DecodeFile,"</Extracting>\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,"<Extracting header>\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,"<Decoded from>%s</Decoded)\n",ShortHeader.From);
+ if (NULL!=ShortHeader.FromNick)
+ DebugLog(DecodeFile,"<Decoded from-nick>%s</Decoded)\n",ShortHeader.FromNick);
+ if (NULL!=ShortHeader.ReturnPath)
+ DebugLog(DecodeFile,"<Decoded return-path>%s</Decoded)\n",ShortHeader.ReturnPath);
+ if (NULL!=ShortHeader.ReturnPathNick)
+ DebugLog(DecodeFile,"<Decoded return-path nick>%s</Decoded)\n",ShortHeader.ReturnPathNick);
+ if (NULL!=ShortHeader.Subject)
+ DebugLog(DecodeFile,"<Decoded subject>%s</Decoded)\n",ShortHeader.Subject);
+ if (NULL!=ShortHeader.Date)
+ DebugLog(DecodeFile,"<Decoded date>%s</Decoded)\n",ShortHeader.Date);
+ DebugLog(DecodeFile,"</Extracting header>\n");
+ DebugLog(DecodeFile,"<Convert>\n");
+ #endif
+
+ ConvertCodedStringToUnicode(ShortHeader.From,&head->From,CP,MIME_PLAIN);
+
+ #ifdef DEBUG_DECODE
+ if (NULL!=head->From)
+ DebugLogW(DecodeFile,L"<Converted from>%s</Converted>\n",head->From);
+ #endif
+ ConvertCodedStringToUnicode(ShortHeader.FromNick,&head->FromNick,CP,MIME_MAIL);
+ #ifdef DEBUG_DECODE
+ if (NULL!=head->FromNick)
+ DebugLogW(DecodeFile,L"<Converted from-nick>%s</Converted>\n",head->FromNick);
+ #endif
+ ConvertCodedStringToUnicode(ShortHeader.ReturnPath,&head->ReturnPath,CP,MIME_PLAIN);
+ #ifdef DEBUG_DECODE
+ if (NULL!=head->ReturnPath)
+ DebugLogW(DecodeFile,L"<Converted return-path>%s</Converted>\n",head->ReturnPath);
+ #endif
+ ConvertCodedStringToUnicode(ShortHeader.ReturnPathNick,&head->ReturnPathNick,CP,MIME_MAIL);
+ #ifdef DEBUG_DECODE
+ if (NULL!=head->ReturnPathNick)
+ DebugLogW(DecodeFile,L"<Converted return-path nick>%s</Converted>\n",head->ReturnPathNick);
+ #endif
+ ConvertCodedStringToUnicode(ShortHeader.Subject,&head->Subject,CP,MIME_PLAIN);
+ #ifdef DEBUG_DECODE
+ if (NULL!=head->Subject)
+ DebugLogW(DecodeFile,L"<Converted subject>%s</Converted>\n",head->Subject);
+ #endif
+ ConvertCodedStringToUnicode(ShortHeader.Date,&head->Date,CP,MIME_PLAIN);
+ #ifdef DEBUG_DECODE
+ if (NULL!=head->Date)
+ DebugLogW(DecodeFile,L"<Converted date>%s</Converted>\n",head->Date);
+ #endif
+
+ ConvertCodedStringToUnicode(ShortHeader.Body,&head->Body,CP,MIME_PLAIN);
+ #ifdef DEBUG_DECODE
+ if (NULL!=head->Body)
+ DebugLogW(DecodeFile,L"<Converted Body>%s</Converted>\n",head->Body);
+ #endif
+
+ #ifdef DEBUG_DECODE
+ DebugLog(DecodeFile,"</Convert>\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<numparts;i++) {
+ ParseAPart(&partData[i]);
+ if (partData[i].body){
+ if (partData[i].TransEnc){
+ if (!_stricmp(partData[i].TransEnc,"base64")) partData[i].TransEncType=TE_BASE64;
+ else if (!_stricmp(partData[i].TransEnc,"quoted-printable"))partData[i].TransEncType=TE_QUOTEDPRINTABLE;
+ }
+ if (partData[i].ContType){
+ char *CharSetStr;
+ if (NULL!=(CharSetStr=ExtractFromContentType(partData[i].ContType,"charset=")))
+ {
+ partData[i].CodePage=GetCharsetFromString(CharSetStr,strlen(CharSetStr));
+ delete[] CharSetStr;
+ }
+ }
+ if (partData[i].ContType && !_strnicmp(partData[i].ContType,"text",4)) {
+ char *localBody=0;
+ switch (partData[i].TransEncType){
+ case TE_BASE64:
+ {
+ int size =partData[i].bodyLen*3/4+5;
+ localBody = new char[size+1];
+ DecodeBase64(partData[i].body,localBody,size);
+ }break;
+ case TE_QUOTEDPRINTABLE:
+ {
+ int size = partData[i].bodyLen+2;
+ localBody = new char[size+1];
+ DecodeQuotedPrintable(partData[i].body,localBody,size,FALSE);
+ }break;
+ }
+ ConvertStringToUnicode(localBody?localBody:partData[i].body,partData[i].CodePage,&partData[i].wBody);
+ if (localBody) delete[] localBody;
+ } else if (partData[i].ContType && !_strnicmp(partData[i].ContType,"multipart/",10)) {
+ //Multipart in mulitipart recursive? should be SPAM. Ah well
+ char *bondary=NULL;
+ if (NULL!=(bondary=ExtractFromContentType(partData[i].ContType,"boundary=")))
+ {
+ partData[i].wBody = ParseMultipartBody(partData[i].body,bondary);
+ delete[] bondary;
+ } else goto FailBackRaw; //multipart with no boundary? badly formatted messages.
+ } else {
+FailBackRaw:
+ ConvertStringToUnicode(partData[i].body,partData[i].CodePage,&partData[i].wBody);
+ }
+ resultSize += wcslen(partData[i].wBody);
+ }// if (partData[i].body)
+ resultSize += 100+4+3; //cr+nl+100+ 3*bullet
+ }
+ dest = new WCHAR[resultSize+1];
+ size_t destpos = 0;
+ for (i=0;i<numparts;i++) {
+ if (i){ // part before first boudary should not have headers
+ char infoline[104]; size_t linesize = 0;
+ _snprintf(infoline,100,"%s %d",Translate("Part"),i);
+ linesize = strlen(infoline);
+ if (partData[i].TransEnc){
+ _snprintf(infoline+linesize,100-linesize,"; %s",partData[i].TransEnc);
+ linesize = strlen(infoline);
+ }
+ if (partData[i].ContType){
+ char *CharSetStr=strchr(partData[i].ContType,';');
+ if (CharSetStr){
+ CharSetStr[0]=0;
+ _snprintf(infoline+linesize,100-linesize,"; %s",partData[i].ContType);
+ linesize = strlen(infoline);
+ partData[i].ContType=CharSetStr+1;
+ if (NULL!=(CharSetStr=ExtractFromContentType(partData[i].ContType,"charset=")))
+ {
+ _snprintf(infoline+linesize,100-linesize,"; %s",CharSetStr);
+ linesize = strlen(infoline);
+ delete[] CharSetStr;
+ }
+ if (NULL!=(CharSetStr=ExtractFromContentType(partData[i].ContType,"name=")))
+ {
+ _snprintf(infoline+linesize,100-linesize,"; \"%s\"",CharSetStr);
+ linesize = strlen(infoline);
+ delete[] CharSetStr;
+ }
+ } else {
+ _snprintf(infoline+linesize,100-linesize,"; %s",partData[i].ContType);
+ linesize = strlen(infoline);
+ }
+ }
+ sprintf(infoline+linesize,".\r\n");
+ {WCHAR *temp=0;
+ dest[destpos] = dest[destpos+1] = dest[destpos+2] = 0x2022; // bullet;
+ destpos+=3;
+ ConvertStringToUnicode(infoline,CP_ACP,&temp);
+ size_t wsize = wcslen(temp);
+ wcscpy(&dest[destpos],temp);
+ destpos += wsize;
+ delete[] temp;
+ }
+ } // if (i)
+ if (partData[i].wBody){
+ size_t wsize = wcslen(partData[i].wBody);
+ wcscpy(&dest[destpos],partData[i].wBody);
+ destpos += wsize;
+ delete[] partData[i].wBody;
+ }
+ }
+
+ free (srcback);
+ delete[] partData;
+ dest[resultSize] = 0;//just in case
+ return dest;
+}
diff --git a/protocols/YAMN/mails/test/header.txt b/protocols/YAMN/mails/test/header.txt
new file mode 100644
index 0000000000..55a4d86d65
--- /dev/null
+++ b/protocols/YAMN/mails/test/header.txt
@@ -0,0 +1,28 @@
+Return-Path: <foromundial-return-1047-decode.com.ar-pablo=decode.com.ar@decode.com.ar>
+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: <mailto:foromundial@decode.com.ar>
+List-Help: <mailto:foromundial-help@decode.com.ar>
+List-Unsubscribe: <mailto:foromundial-unsubscribe@decode.com.ar>
+List-Subscribe: <mailto:foromundial-subscribe@decode.com.ar>
+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" <sandra@labsem.cetuc.puc-rio.br>
+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: <miranda@megami.sprintserve.net>
+Received: [from megami.sprintserve.net (megami.sprintserve.net [207.142.136.160])
+ by mail2.ba.psg.sk with ESMTP id i4FHNUY6018585
+ for <om3tn@psg.sk>; Sat, 15 May 2004 19:23:31 +0200]
+X-Envelope-To: <om3tn@psg.sk>
+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: UpozornØn¡ na odpovØÔ v t‚matu - YAMN problem
+Reply-to: forum@miranda-im.org
+From: forum@miranda-im.org:
+Message-ID: <e003226b4a46a7ca6b490345f21b91af@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: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: UpozornØn¡ na odpovØÔ v t‚matu - YAMN problem
+
+Return-Path: <miranda@megami.sprintserve.net>
+Received: [from megami.sprintserve.net (megami.sprintserve.net [207.142.136.160])
+ by mail2.ba.psg.sk with ESMTP id i4FHX2Y6020695
+ for <om3tn@psg.sk>; Sat, 15 May 2004 19:33:03 +0200]
+X-Envelope-To: <om3tn@psg.sk>
+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: UpozornØn¡ na odpovØÔ v t‚matu - 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: <HMF@hotbox.ru>
+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 <om3tn@psg.sk>; Tue, 20 May 2003 18:11:44 +0200
+X-Envelope-To: <om3tn@psg.sk>
+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 <om3tn@psg.sk>; Tue, 20 May 2003 20:13:19
+Subject: Òàìîæåííàî÷èñòêà. ÔèíëäèÌîñêâà. Îò 0,8 çà êã, âêëþ÷àâñå ! 20:13:19
+From: <HMF@hotbox.ru>
+To: OM3TN <om3tn@psg.sk>
+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: <DED-173-MCL662@mail-relay2.slovanet.net> \ 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 <stdio.h>
+#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 <io.h>
+
+#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;i<CPLENALL;i++) if (CodePageNamesAll[i].CP == cp) {
+ CodePageNamesAll[i].isValid = TRUE;
+ CPLENSUPP++;
+ #ifdef YAMN_DEBUG
+ found = TRUE;
+ #endif
+ break;
+ }
+ #ifdef YAMN_DEBUG
+ if (!found) {
+ strcat(unknownCP, info.CodePageName);
+ strcat(unknownCP, "\n");
+ }
+ #endif
+ }
+ return TRUE;
+}
+
+void CheckMenuItems()
+{
+ CLISTMENUITEM clmi = {0};
+ clmi.cbSize = sizeof( CLISTMENUITEM );
+ clmi.flags = CMIM_FLAGS;
+ if ( !DBGetContactSettingByte(NULL, YAMN_DBMODULE, YAMN_SHOWMAINMENU, 1))
+ clmi.flags |= CMIF_HIDDEN;
+
+ CallService( MS_CLIST_MODIFYMENUITEM, ( WPARAM )hMenuItemMain, ( LPARAM )&clmi );
+}
+
+int SystemModulesLoaded(WPARAM, LPARAM)
+{
+ //Insert "Check mail (YAMN)" item to Miranda's menu
+ CLISTMENUITEM mi = { 0 };
+ mi.cbSize = sizeof(mi);
+ mi.position = 0xb0000000;
+ mi.flags = CMIF_ICONFROMICOLIB;
+ mi.icolibItem = g_GetIconHandle(5);
+ mi.pszName = "Check &mail (All Account)";
+ mi.pszPopupName = NULL;//YAMN_DBMODULE;
+ mi.pszService = MS_YAMN_FORCECHECK;
+ hMenuItemMain = (HANDLE) CallService(MS_CLIST_ADDMAINMENUITEM, 0, (LPARAM)&mi);
+
+ mi.pszName = "Check &mail (This Account)";
+ mi.pszContactOwner = YAMN_DBMODULE;
+ mi.pszService = MS_YAMN_CLISTCONTEXT;
+ hMenuItemCont = (HANDLE) CallService(MS_CLIST_ADDCONTACTMENUITEM, 0, (LPARAM)&mi);
+
+ mi.icolibItem = g_GetIconHandle(4);
+ mi.pszName = "Launch application";
+ mi.pszContactOwner = YAMN_DBMODULE;
+ mi.pszService = MS_YAMN_CLISTCONTEXTAPP;
+ hMenuItemContApp = (HANDLE) CallService(MS_CLIST_ADDCONTACTMENUITEM, 0, (LPARAM)&mi);
+
+ CheckMenuItems();
+
+ //Use for the Updater plugin
+ if (ServiceExists(MS_UPDATE_REGISTER)) {
+ Update update = {0};
+ char szVersion[16], szUrl[250];
+ wsprintfA(szUrl, "http://www.miranda-fr.net/tweety/yamn/%s.zip", YAMN_FILENAME);
+
+ update.szComponentName = pluginInfo.shortName;
+ update.pbVersion = (BYTE *)CreateVersionStringPlugin((PLUGININFO *)&pluginInfo, szVersion);
+ update.cpbVersion = (int)strlen((char *)update.pbVersion);
+ update.szUpdateURL = "http://addons.miranda-im.org/feed.php?dlfile = 3411";
+ update.szVersionURL = "http://addons.miranda-im.org/details.php?action = viewfile&id = 3411";
+ update.pbVersionPrefix = (BYTE *)"<span class = \"fileNameHeader\">YAMN 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 <string.h> /* 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<<s | 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,"<Register PROXY support>");
+#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,"<error></Register PROXY support>\n");
+ else
+ DebugLog(CommFile,"</Register PROXY support>\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,"<connect>\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,"</connect>\n");
+#endif
+ return;
+ }
+ catch(...)
+ {
+#ifdef DEBUG_COMM
+ DebugLog(CommFile,"<error></connect>\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,"<send>%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,"</send>\n");
+#endif
+ }
+ catch(...)
+ {
+#ifdef DEBUG_COMM
+ DebugLog(CommFile,"<error></send>\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,"<reading>");
+#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,"</reading>\n");
+#endif
+ return(buf);
+ }
+ catch(...)
+ {
+#ifdef DEBUG_COMM
+ DebugLog(CommFile,"<error></reading>\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,"<Unregister PROXY support>");
+#endif
+
+ Netlib_CloseHandle(hNetlibUser);
+ hNetlibUser=(HANDLE)NULL;
+#ifdef DEBUG_COMM
+ DebugLog(CommFile,"</Unregister PROXY support>\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 <brouits@free.fr>
+ * 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 <om3tn@psg.sk>
+ * 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 <m_netlib.h> //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,"<Extracting stat>\n");
+ #endif
+ ExtractStat(DataRX,MyClient->NetClient->Rcv,&mboxsize,&msgs);
+ #ifdef DEBUG_DECODE
+ DebugLog(DecodeFile,"<MailBoxSize>%d</MailBoxSize>\n",mboxsize);
+ DebugLog(DecodeFile,"<Msgs>%d</Msgs>\n",msgs);
+ DebugLog(DecodeFile,"</Extracting stat>\n");
+ #endif
+ if (DataRX!=NULL)
+ free(DataRX);
+ DataRX=NULL;
+ for (i=0;i<msgs;i++)
+ {
+ if (!i)
+ MsgQueuePtr=NewMails=(HYAMNMAIL)CallService(MS_YAMN_CREATEACCOUNTMAIL,(WPARAM)ActualAccount,(LPARAM)YAMN_MAILVERSION);
+ else
+ {
+ MsgQueuePtr->Next=(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,"<Extracting list>\n");
+ #endif
+ ExtractList(DataRX,MyClient->NetClient->Rcv,NewMails);
+ #ifdef DEBUG_DECODE
+ DebugLog(DecodeFile,"</Extracting list>\n");
+ #endif
+ if (DataRX!=NULL)
+ free(DataRX);
+ DataRX=NULL;
+
+ #ifdef DEBUG_DECODE
+ DebugLog(DecodeFile,"<Extracting UIDL>\n");
+ #endif
+ DataRX=MyClient->Uidl();
+ ExtractUIDL(DataRX,MyClient->NetClient->Rcv,NewMails);
+ #ifdef DEBUG_DECODE
+ DebugLog(DecodeFile,"</Extracting UIDL>\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,"<Reading body>\n");
+ DebugLog(DecodeFile,"<Header>%s</Header>\n",DataRX);
+ #endif
+ if (DataRX!=NULL)
+ {
+ Temp=DataRX;
+ while((Temp<DataRX+MyClient->NetClient->Rcv) && (WS(Temp) || ENDLINE(Temp))) Temp++;
+
+ if (OKLINE(DataRX))
+ for (Temp=DataRX;(Temp<DataRX+MyClient->NetClient->Rcv) && (!ENDLINE(Temp));Temp++);
+ while((Temp<DataRX+MyClient->NetClient->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,"</Reading body>\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,"<New mail>\n");
+ DebugLog(DecodeFile,"<Header>%s</Header>\n",DataRX);
+ #endif
+ if (DataRX!=NULL)
+ {
+ Temp=DataRX;
+ while((Temp<DataRX+MyClient->NetClient->Rcv) && (WS(Temp) || ENDLINE(Temp))) Temp++;
+
+ if (OKLINE(DataRX))
+ for (Temp=DataRX;(Temp<DataRX+MyClient->NetClient->Rcv) && (!ENDLINE(Temp));Temp++);
+ while((Temp<DataRX+MyClient->NetClient->Rcv) && ENDLINE(Temp)) Temp++;
+ }
+ else
+ continue;
+
+ TranslateHeader(Temp,MyClient->NetClient->Rcv-(Temp-DataRX),&MsgQueuePtr->MailData->TranslatedHeader);
+
+
+ #ifdef DEBUG_DECODE
+ DebugLog(DecodeFile,"</New mail>\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,"</--------Account checking-------->\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,"</--------Communication-------->\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,"<Extracting stat>\n");
+#endif
+ ExtractStat(DataRX,MyClient->NetClient->Rcv,&mboxsize,&msgs);
+#ifdef DEBUG_DECODE
+ DebugLog(DecodeFile,"<MailBoxSize>%d</MailBoxSize>\n",mboxsize);
+ DebugLog(DecodeFile,"<Msgs>%d</Msgs>\n",msgs);
+ DebugLog(DecodeFile,"</Extracting stat>\n");
+#endif
+ if (DataRX!=NULL)
+ free(DataRX);
+ DataRX=NULL;
+ for (i=0;i<msgs;i++)
+ {
+ if (!i)
+ MsgQueuePtr=NewMails=(HYAMNMAIL)CallService(MS_YAMN_CREATEACCOUNTMAIL,(WPARAM)ActualAccount,(LPARAM)YAMN_MAILVERSION);
+ else
+ {
+ MsgQueuePtr->Next=(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,"<Extracting UIDL>\n");
+#endif
+ DataRX=MyClient->Uidl();
+ ExtractUIDL(DataRX,MyClient->NetClient->Rcv,NewMails);
+#ifdef DEBUG_DECODE
+ DebugLog(DecodeFile,"</Extracting UIDL>\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,"</--------Deleting requested mails-------->\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,"</--------Communication-------->\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,"<Message>\n");
+ #endif
+ while(WS(finder)) finder++; //jump whitespace
+ if (1!=sscanf(finder,"%d",&msgnr))
+ throw (DWORD)EPOP3_UIDL;
+ #ifdef DEBUG_DECODE
+ DebugLog(DecodeFile,"<Nr>%d</Nr>\n",msgnr);
+ #endif
+// for (i=1,queueptr=queue;(queueptr->Next!=NULL) && (i<msgnr);queueptr=queueptr->Next,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,"<ID>%s</ID>\n",queueptr->MailData->Body);
+ DebugLog(DecodeFile,"</Message>\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,"<Message>\n");
+ #endif
+ while(WS(finder)) finder++; //jump whitespace
+ if (1!=sscanf(finder,"%d",&msgnr))
+ throw (DWORD)EPOP3_UIDL;
+ #ifdef DEBUG_DECODE
+ DebugLog(DecodeFile,"<Nr>%d</Nr>\n",msgnr);
+ #endif
+// for (i=1,queueptr=queue;(queueptr->Next!=NULL) && (i<msgnr);queueptr=queueptr->Next,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,"<ID>%s</ID>\n",queueptr->ID);
+ DebugLog(DecodeFile,"</Message>\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,"<Message>\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,"<Nr>%d</Nr>\n",msgnr);
+ #endif
+
+ for (i=1,queueptr=queue;(queueptr->Next!=NULL) && (i<msgnr);queueptr=queueptr->Next,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,"<Nr>%d</Nr>\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 <windows.h>
+#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;i<cbn;i++)
+ SendDlgItemMessage(hDlg,IDC_COMBOPLUGINS,CB_DELETESTRING,(WPARAM)0,(LPARAM)0);
+ break;
+ }
+ }
+
+ return FALSE;
+}
+
+
+int YAMNOptInitSvc(WPARAM wParam,LPARAM lParam)
+{
+ OPTIONSDIALOGPAGE odp={0};
+ odp.cbSize = sizeof(odp);
+ odp.hInstance = YAMNVar.hInst;
+ odp.pszGroup = LPGEN("Network");
+ odp.pszTitle = LPGEN("YAMN");
+ odp.flags = ODPF_BOLDGROUPS;
+
+ odp.pszTab = LPGEN("Accounts");
+ odp.pszTemplate = MAKEINTRESOURCEA(IDD_POP3ACCOUNTOPT);
+ odp.pfnDlgProc = DlgProcPOP3AccOpt;
+ CallService(MS_OPT_ADDPAGE, wParam, (LPARAM) &odp);
+
+ odp.pszTab = LPGEN("General");
+ odp.pszTemplate = MAKEINTRESOURCEA(IDD_YAMNOPT);
+ odp.pfnDlgProc = DlgProcYAMNOpt;
+ CallService(MS_OPT_ADDPAGE, wParam, (LPARAM) &odp);
+
+ odp.pszTab = LPGEN("Plugins");
+ odp.pszTemplate = MAKEINTRESOURCEA(IDD_PLUGINOPT);
+ odp.pfnDlgProc = DlgProcPluginOpt;
+ CallService(MS_OPT_ADDPAGE, wParam, (LPARAM) &odp);
+
+ if ( ServiceExists(MS_POPUP_ADDPOPUPEX)) {
+ odp.pszGroup = LPGEN("PopUps");
+ odp.pszTab = LPGEN("YAMN");
+ odp.pszTemplate = MAKEINTRESOURCEA(IDD_POP3ACCOUNTPOPUP);
+ odp.pfnDlgProc = DlgProcPOP3AccPopup;
+ CallService(MS_OPT_ADDPAGE, wParam, (LPARAM) &odp);
+ }
+ return 0;
+}
+
+//--------------------------------------------------------------------------------------------------
+//--------------------------------------------------------------------------------------------------
+BOOL DlgEnableAccountStatus(HWND hDlg,WPARAM wParam,LPARAM lParam)
+{
+ EnableWindow(GetDlgItem(hDlg,IDC_CHECKST0),(BOOL)wParam);
+ EnableWindow(GetDlgItem(hDlg,IDC_CHECKST1),(BOOL)wParam);
+ EnableWindow(GetDlgItem(hDlg,IDC_CHECKST2),(BOOL)wParam);
+ EnableWindow(GetDlgItem(hDlg,IDC_CHECKST3),(BOOL)wParam);
+ EnableWindow(GetDlgItem(hDlg,IDC_CHECKST4),(BOOL)wParam);
+ EnableWindow(GetDlgItem(hDlg,IDC_CHECKST5),(BOOL)wParam);
+ EnableWindow(GetDlgItem(hDlg,IDC_CHECKST6),(BOOL)wParam);
+ EnableWindow(GetDlgItem(hDlg,IDC_CHECKST7),(BOOL)wParam);
+ EnableWindow(GetDlgItem(hDlg,IDC_CHECKST8),(BOOL)wParam);
+ EnableWindow(GetDlgItem(hDlg,IDC_CHECKST9),(BOOL)wParam);
+ EnableWindow(GetDlgItem(hDlg,IDC_CHECKST9),(BOOL)wParam);
+ return TRUE;
+}
+BOOL DlgEnableAccountPopup(HWND hDlg,WPARAM wParam,LPARAM lParam)
+{
+ EnableWindow(GetDlgItem(hDlg,IDC_CHECKPOP),(BOOL)wParam);
+ EnableWindow(GetDlgItem(hDlg,IDC_EDITPOPS),(IsDlgButtonChecked(hDlg,IDC_CHECKPOP)==BST_CHECKED) && wParam);
+ EnableWindow(GetDlgItem(hDlg,IDC_CHECKCOL),(IsDlgButtonChecked(hDlg,IDC_CHECKPOP)==BST_CHECKED) && wParam);
+ 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_RADIOPOPN),(IsDlgButtonChecked(hDlg,IDC_CHECKPOP)==BST_CHECKED) && wParam);
+ EnableWindow(GetDlgItem(hDlg,IDC_RADIOPOP1),(IsDlgButtonChecked(hDlg,IDC_CHECKPOP)==BST_CHECKED) && wParam);
+ EnableWindow(GetDlgItem(hDlg,IDC_CHECKNPOP),(BOOL)wParam);
+ EnableWindow(GetDlgItem(hDlg,IDC_EDITNPOPS),(IsDlgButtonChecked(hDlg,IDC_CHECKNPOP)==BST_CHECKED) && wParam);
+ EnableWindow(GetDlgItem(hDlg,IDC_CHECKNCOL),(IsDlgButtonChecked(hDlg,IDC_CHECKNPOP)==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_CHECKFPOP),(BOOL)wParam);
+ EnableWindow(GetDlgItem(hDlg,IDC_EDITFPOPS),(IsDlgButtonChecked(hDlg,IDC_CHECKFPOP)==BST_CHECKED) && wParam);
+ EnableWindow(GetDlgItem(hDlg,IDC_CHECKFCOL),(IsDlgButtonChecked(hDlg,IDC_CHECKFPOP)==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);
+ EnableWindow(GetDlgItem(hDlg,IDC_CHECKAPOP),(BOOL)wParam);
+ return TRUE;
+}
+
+BOOL DlgEnableAccount(HWND hDlg,WPARAM wParam,LPARAM lParam)
+{
+ EnableWindow(GetDlgItem(hDlg,IDC_CHECK),(BOOL)wParam);
+ EnableWindow(GetDlgItem(hDlg,IDC_EDITSERVER),wParam);
+ EnableWindow(GetDlgItem(hDlg,IDC_EDITNAME),wParam);
+ EnableWindow(GetDlgItem(hDlg,IDC_EDITPORT),(BOOL)wParam);
+ EnableWindow(GetDlgItem(hDlg,IDC_EDITLOGIN),(BOOL)wParam);
+ EnableWindow(GetDlgItem(hDlg,IDC_EDITPASS),(BOOL)wParam);
+ EnableWindow(GetDlgItem(hDlg,IDC_EDITINTERVAL),(BOOL)wParam);
+ EnableWindow(GetDlgItem(hDlg,IDC_CHECKSND),(BOOL)wParam);
+ EnableWindow(GetDlgItem(hDlg,IDC_CHECKMSG),(BOOL)wParam);
+ EnableWindow(GetDlgItem(hDlg,IDC_CHECKICO),(BOOL)wParam);
+ EnableWindow(GetDlgItem(hDlg,IDC_CHECKAPP),(BOOL)wParam);
+ EnableWindow(GetDlgItem(hDlg,IDC_CHECKKBN),(BOOL)wParam);
+ EnableWindow(GetDlgItem(hDlg,IDC_BTNAPP),(IsDlgButtonChecked(hDlg,IDC_CHECKAPP)==BST_CHECKED) && wParam);
+ EnableWindow(GetDlgItem(hDlg,IDC_EDITAPP),(IsDlgButtonChecked(hDlg,IDC_CHECKAPP)==BST_CHECKED) && wParam);
+ EnableWindow(GetDlgItem(hDlg,IDC_EDITAPPPARAM),(IsDlgButtonChecked(hDlg,IDC_CHECKAPP)==BST_CHECKED) && wParam);
+ EnableWindow(GetDlgItem(hDlg,IDC_CHECKNMSGP),(BOOL)wParam);
+ EnableWindow(GetDlgItem(hDlg,IDC_CHECKFSND),(BOOL)wParam);
+ EnableWindow(GetDlgItem(hDlg,IDC_CHECKFMSG),(BOOL)wParam);
+ EnableWindow(GetDlgItem(hDlg,IDC_CHECKFICO),(BOOL)wParam);
+ /*EnableWindow(GetDlgItem(hDlg,IDC_CHECKST0),(BOOL)wParam);
+ EnableWindow(GetDlgItem(hDlg,IDC_CHECKST1),(BOOL)wParam);
+ EnableWindow(GetDlgItem(hDlg,IDC_CHECKST2),(BOOL)wParam);
+ EnableWindow(GetDlgItem(hDlg,IDC_CHECKST3),(BOOL)wParam);
+ EnableWindow(GetDlgItem(hDlg,IDC_CHECKST4),(BOOL)wParam);
+ EnableWindow(GetDlgItem(hDlg,IDC_CHECKST5),(BOOL)wParam);
+ EnableWindow(GetDlgItem(hDlg,IDC_CHECKST6),(BOOL)wParam);
+ EnableWindow(GetDlgItem(hDlg,IDC_CHECKST7),(BOOL)wParam);
+ EnableWindow(GetDlgItem(hDlg,IDC_CHECKST8),(BOOL)wParam);
+ EnableWindow(GetDlgItem(hDlg,IDC_CHECKST9),(BOOL)wParam);
+ EnableWindow(GetDlgItem(hDlg,IDC_CHECKST9),(BOOL)wParam);*/
+ EnableWindow(GetDlgItem(hDlg,IDC_CHECKSTART),(BOOL)wParam);
+ EnableWindow(GetDlgItem(hDlg,IDC_CHECKFORCE),(BOOL)wParam);
+ EnableWindow(GetDlgItem(hDlg,IDC_COMBOCP),(BOOL)wParam);
+ EnableWindow(GetDlgItem(hDlg,IDC_STTIMELEFT),(BOOL)wParam);
+ EnableWindow(GetDlgItem(hDlg,IDC_BTNRESET),(BOOL)wParam);
+ EnableWindow(GetDlgItem(hDlg,IDC_BTNDEFAULT),(BOOL)wParam);
+ EnableWindow(GetDlgItem(hDlg,IDC_BTNSTATUS),(BOOL)wParam);
+ EnableWindow(GetDlgItem(hDlg,IDC_CHECKSSL),(BOOL)wParam);
+ EnableWindow(GetDlgItem(hDlg,IDC_CHECKNOTLS),(IsDlgButtonChecked(hDlg,IDC_CHECKSSL)==BST_UNCHECKED) && wParam);
+ EnableWindow(GetDlgItem(hDlg,IDC_AUTOBODY),(BOOL)wParam);
+ EnableWindow(GetDlgItem(hDlg,IDC_CHECKCONTACT),(BOOL)wParam);
+ EnableWindow(GetDlgItem(hDlg,IDC_CHECKCONTACTNICK),(IsDlgButtonChecked(hDlg,IDC_CHECKCONTACT)==BST_CHECKED) && wParam);
+ EnableWindow(GetDlgItem(hDlg,IDC_CHECKCONTACTNOEVENT),(IsDlgButtonChecked(hDlg,IDC_CHECKCONTACT)==BST_CHECKED) && wParam);
+ return TRUE;
+}
+BOOL DlgShowAccountStatus(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
+ 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);
+ 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 ((i<CPLENSUPP) && (CodePageNamesSupp[i].CP==ActualAccount->CP))
+ {
+ 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
--- /dev/null
+++ b/protocols/YAMN/resources/iconeutral.ico
Binary files differ
diff --git a/protocols/YAMN/resources/iconttbdown.ico b/protocols/YAMN/resources/iconttbdown.ico
new file mode 100644
index 0000000000..206eba2c76
--- /dev/null
+++ b/protocols/YAMN/resources/iconttbdown.ico
Binary files differ
diff --git a/protocols/YAMN/resources/icooffline.ico b/protocols/YAMN/resources/icooffline.ico
new file mode 100644
index 0000000000..db5b2e18fa
--- /dev/null
+++ b/protocols/YAMN/resources/icooffline.ico
Binary files differ
diff --git a/protocols/YAMN/resources/icoyamn3.ico b/protocols/YAMN/resources/icoyamn3.ico
new file mode 100644
index 0000000000..ca11f0f4f4
--- /dev/null
+++ b/protocols/YAMN/resources/icoyamn3.ico
Binary files 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
--- /dev/null
+++ b/protocols/YAMN/resources/yamn.bmp
Binary files 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;i<sizeof(ProtoPluginExportedFcn)/sizeof(ProtoPluginExportedFcn[0]);i++)
+ if (0==lstrcmpA((char *)wParam, ProtoPluginExportedFcn[i].ID))
+ return (INT_PTR)ProtoPluginExportedFcn[i].Ptr;
+ for (i=0;i<sizeof(ProtoPluginExportedSvc)/sizeof(ProtoPluginExportedSvc[0]);i++)
+ if (0==lstrcmpA((char *)wParam, ProtoPluginExportedSvc[i].ID))
+ return (INT_PTR)ProtoPluginExportedSvc[i].Ptr;
+ for (i=0;i<sizeof(SynchroExportedFcn)/sizeof(SynchroExportedFcn[0]);i++)
+ if (0==lstrcmpA((char *)wParam, SynchroExportedFcn[i].ID))
+ return (INT_PTR)SynchroExportedFcn[i].Ptr;
+ for (i=0;i<sizeof(AccountExportedFcn)/sizeof(AccountExportedFcn[0]);i++)
+ if (0==lstrcmpA((char *)wParam, AccountExportedFcn[i].ID))
+ return (INT_PTR)AccountExportedFcn[i].Ptr;
+ for (i=0;i<sizeof(AccountExportedSvc)/sizeof(AccountExportedSvc[0]);i++)
+ if (0==lstrcmpA((char *)wParam, AccountExportedSvc[i].ID))
+ return (INT_PTR)AccountExportedSvc[i].Ptr;
+ for (i=0;i<sizeof(MailExportedFcn)/sizeof(MailExportedFcn[0]);i++)
+ if (0==lstrcmpA((char *)wParam, MailExportedFcn[i].ID))
+ return (INT_PTR)MailExportedFcn[i].Ptr;
+ for (i=0;i<sizeof(MailExportedSvc)/sizeof(MailExportedSvc[0]);i++)
+ if (0==lstrcmpA((char *)wParam, MailExportedSvc[i].ID))
+ return (INT_PTR)MailExportedSvc[i].Ptr;
+ for (i=0;i<sizeof(FilterPluginExportedFcn)/sizeof(FilterPluginExportedFcn[0]);i++)
+ if (0==lstrcmpA((char *)wParam, FilterPluginExportedFcn[i].ID))
+ return (INT_PTR)FilterPluginExportedFcn[i].Ptr;
+ for (i=0;i<sizeof(FilterPluginExportedSvc)/sizeof(FilterPluginExportedSvc[0]);i++)
+ if (0==lstrcmpA((char *)wParam, FilterPluginExportedSvc[i].ID))
+ return (INT_PTR)FilterPluginExportedSvc[i].Ptr;
+ return (INT_PTR)NULL;
+}
+
+INT_PTR GetVariablesSvc(WPARAM wParam, LPARAM)
+{
+ return wParam==YAMN_VARIABLESVERSION ? (INT_PTR)&YAMNVar : (INT_PTR)NULL;
+}
+
+void CALLBACK TimerProc(HWND, UINT, UINT, DWORD)
+{
+ PYAMN_PROTOPLUGINQUEUE ActualPlugin;
+ HACCOUNT ActualAccount;
+ HANDLE ThreadRunningEV;
+ DWORD Status, tid;
+
+// we use event to signal, that running thread has all needed stack parameters copied
+ if (NULL==(ThreadRunningEV=CreateEvent(NULL, FALSE, FALSE, NULL)))
+ return;
+// if we want to close miranda, we get event and do not run checking anymore
+ if (WAIT_OBJECT_0==WaitForSingleObject(ExitEV, 0))
+ return;
+// Get actual status of current user in Miranda
+ Status=CallService(MS_CLIST_GETSTATUSMODE, 0, 0);
+
+ EnterCriticalSection(&PluginRegCS);
+ for (ActualPlugin=FirstProtoPlugin;ActualPlugin!=NULL;ActualPlugin=ActualPlugin->Next)
+ {
+#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 <wchar.h>
+#include <tchar.h>
+#include <windows.h>
+#include <stdio.h>
+#include <direct.h> //For _chdir()
+
+#define MIRANDA_VER 0x0A00
+
+#include <commctrl.h> //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 <m_folders.h>
+
+
+//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