summaryrefslogtreecommitdiff
path: root/protocols
diff options
context:
space:
mode:
Diffstat (limited to 'protocols')
-rw-r--r--protocols/CloudFile/CloudFile.vcxproj40
-rw-r--r--protocols/CloudFile/CloudFile.vcxproj.filters32
-rw-r--r--protocols/CloudFile/res/dropbox.icobin0 -> 5430 bytes
-rw-r--r--protocols/CloudFile/res/gdrive.icobin0 -> 5430 bytes
-rw-r--r--protocols/CloudFile/res/onedrive.icobin0 -> 7886 bytes
-rw-r--r--protocols/CloudFile/res/resource.rc200
-rw-r--r--protocols/CloudFile/res/upload.icobin0 -> 103999 bytes
-rw-r--r--protocols/CloudFile/res/version.rc9
-rw-r--r--protocols/CloudFile/res/yadisk.icobin0 -> 5430 bytes
-rw-r--r--protocols/CloudFile/src/Services/dropbox_api.h221
-rw-r--r--protocols/CloudFile/src/Services/dropbox_service.cpp302
-rw-r--r--protocols/CloudFile/src/Services/dropbox_service.h36
-rw-r--r--protocols/CloudFile/src/Services/google_api.h200
-rw-r--r--protocols/CloudFile/src/Services/google_service.cpp297
-rw-r--r--protocols/CloudFile/src/Services/google_service.h35
-rw-r--r--protocols/CloudFile/src/Services/microsoft_api.h188
-rw-r--r--protocols/CloudFile/src/Services/microsoft_service.cpp269
-rw-r--r--protocols/CloudFile/src/Services/microsoft_service.h34
-rw-r--r--protocols/CloudFile/src/Services/yandex_api.h131
-rw-r--r--protocols/CloudFile/src/Services/yandex_service.cpp290
-rw-r--r--protocols/CloudFile/src/Services/yandex_service.h35
-rw-r--r--protocols/CloudFile/src/cloud_file.cpp197
-rw-r--r--protocols/CloudFile/src/cloud_file.h61
-rw-r--r--protocols/CloudFile/src/events.cpp48
-rw-r--r--protocols/CloudFile/src/file_transfer.h255
-rw-r--r--protocols/CloudFile/src/http_request.h180
-rw-r--r--protocols/CloudFile/src/icons.cpp39
-rw-r--r--protocols/CloudFile/src/main.cpp42
-rw-r--r--protocols/CloudFile/src/menus.cpp52
-rw-r--r--protocols/CloudFile/src/oauth.cpp33
-rw-r--r--protocols/CloudFile/src/oauth.h23
-rw-r--r--protocols/CloudFile/src/options.cpp124
-rw-r--r--protocols/CloudFile/src/options.h43
-rw-r--r--protocols/CloudFile/src/resource.h38
-rw-r--r--protocols/CloudFile/src/services.cpp106
-rw-r--r--protocols/CloudFile/src/srmm.cpp67
-rw-r--r--protocols/CloudFile/src/stdafx.cxx20
-rw-r--r--protocols/CloudFile/src/stdafx.h126
-rw-r--r--protocols/CloudFile/src/transfers.cpp39
-rw-r--r--protocols/CloudFile/src/utils.cpp113
-rw-r--r--protocols/CloudFile/src/version.h13
-rw-r--r--protocols/ConnectionNotify/ConnectionNotify.vcxproj28
-rw-r--r--protocols/ConnectionNotify/ConnectionNotify.vcxproj.filters4
-rw-r--r--protocols/ConnectionNotify/docs/connectionnotify.pngbin0 -> 163403 bytes
-rw-r--r--protocols/ConnectionNotify/res/ConnectionNotify.rc96
-rw-r--r--protocols/ConnectionNotify/res/add.icobin0 -> 4286 bytes
-rw-r--r--protocols/ConnectionNotify/res/arrowdown.icobin0 -> 4286 bytes
-rw-r--r--protocols/ConnectionNotify/res/arrowup.icobin0 -> 4286 bytes
-rw-r--r--protocols/ConnectionNotify/res/delete_item.icobin0 -> 4286 bytes
-rw-r--r--protocols/ConnectionNotify/res/icon1.icobin0 -> 23246 bytes
-rw-r--r--protocols/ConnectionNotify/res/icon2.icobin0 -> 23246 bytes
-rw-r--r--protocols/ConnectionNotify/res/version.rc9
-rw-r--r--protocols/ConnectionNotify/src/ConnectionNotify.cpp880
-rw-r--r--protocols/ConnectionNotify/src/debug.cpp13
-rw-r--r--protocols/ConnectionNotify/src/debug.h9
-rw-r--r--protocols/ConnectionNotify/src/filter.cpp141
-rw-r--r--protocols/ConnectionNotify/src/filter.h9
-rw-r--r--protocols/ConnectionNotify/src/netstat.cpp148
-rw-r--r--protocols/ConnectionNotify/src/netstat.h18
-rw-r--r--protocols/ConnectionNotify/src/pid2name.cpp21
-rw-r--r--protocols/ConnectionNotify/src/pid2name.h8
-rw-r--r--protocols/ConnectionNotify/src/resource.h34
-rw-r--r--protocols/ConnectionNotify/src/stdafx.cxx18
-rw-r--r--protocols/ConnectionNotify/src/stdafx.h51
-rw-r--r--protocols/ConnectionNotify/src/version.h38
-rw-r--r--protocols/CurrencyRates/CurrencyRatesChart/CurrencyRatesChart.csproj124
-rw-r--r--protocols/CurrencyRates/CurrencyRatesChart/Form1.Designer.cs123
-rw-r--r--protocols/CurrencyRates/CurrencyRatesChart/Form1.cs155
-rw-r--r--protocols/CurrencyRates/CurrencyRatesChart/Form1.resx216
-rw-r--r--protocols/CurrencyRates/CurrencyRatesChart/Program.cs21
-rw-r--r--protocols/CurrencyRates/CurrencyRatesChart/Properties/AssemblyInfo.cs36
-rw-r--r--protocols/CurrencyRates/CurrencyRatesChart/Properties/Resources.Designer.cs63
-rw-r--r--protocols/CurrencyRates/CurrencyRatesChart/Properties/Resources.resx117
-rw-r--r--protocols/CurrencyRates/CurrencyRatesChart/Properties/Settings.Designer.cs26
-rw-r--r--protocols/CurrencyRates/CurrencyRatesChart/Properties/Settings.settings7
-rw-r--r--protocols/CurrencyRates/CurrencyRatesChart/app.config3
-rw-r--r--protocols/CurrencyRates/CurrencyRatesChart/bin/x32/CurrencyRatesChart.exebin0 -> 24064 bytes
-rw-r--r--protocols/CurrencyRates/CurrencyRatesChart/bin/x64/CurrencyRatesChart.exebin0 -> 23552 bytes
-rw-r--r--protocols/CurrencyRates/CurrencyRatesChart/main.icobin0 -> 5430 bytes
-rw-r--r--protocols/CurrencyRates/Forex.vcxproj36
-rw-r--r--protocols/CurrencyRates/Forex.vcxproj.filters4
-rw-r--r--protocols/CurrencyRates/docs/Utility/cc.xml518
-rw-r--r--protocols/CurrencyRates/proto_CurrencyRates/proto_CurrencyRates.vcxproj28
-rw-r--r--protocols/CurrencyRates/proto_CurrencyRates/proto_CurrencyRates.vcxproj.filters4
-rw-r--r--protocols/CurrencyRates/proto_CurrencyRates/res/proto_CurrencyRates.rc121
-rw-r--r--protocols/CurrencyRates/proto_CurrencyRates/res/proto_na.icobin0 -> 5430 bytes
-rw-r--r--protocols/CurrencyRates/proto_CurrencyRates/res/proto_offline.icobin0 -> 5430 bytes
-rw-r--r--protocols/CurrencyRates/proto_CurrencyRates/res/proto_online.icobin0 -> 5430 bytes
-rw-r--r--protocols/CurrencyRates/res/AutoUpdateDisabled.icobin0 -> 1150 bytes
-rw-r--r--protocols/CurrencyRates/res/CurrencyConverter.icobin0 -> 5430 bytes
-rw-r--r--protocols/CurrencyRates/res/Export currencyrates.icobin0 -> 1150 bytes
-rw-r--r--protocols/CurrencyRates/res/Forex.rc376
-rw-r--r--protocols/CurrencyRates/res/Import currencyrates.icobin0 -> 1150 bytes
-rw-r--r--protocols/CurrencyRates/res/Refresh.icobin0 -> 1150 bytes
-rw-r--r--protocols/CurrencyRates/res/Section.icobin0 -> 1150 bytes
-rw-r--r--protocols/CurrencyRates/res/Version.rc9
-rw-r--r--protocols/CurrencyRates/res/currencyrate.icobin0 -> 1150 bytes
-rw-r--r--protocols/CurrencyRates/res/down.icobin0 -> 1150 bytes
-rw-r--r--protocols/CurrencyRates/res/main.icobin0 -> 5430 bytes
-rw-r--r--protocols/CurrencyRates/res/notchanged.icobin0 -> 1150 bytes
-rw-r--r--protocols/CurrencyRates/res/swap.icobin0 -> 1150 bytes
-rw-r--r--protocols/CurrencyRates/res/up.icobin0 -> 1150 bytes
-rw-r--r--protocols/CurrencyRates/src/Chart.h280
-rw-r--r--protocols/CurrencyRates/src/ComHelper.cpp28
-rw-r--r--protocols/CurrencyRates/src/ComHelper.h7
-rw-r--r--protocols/CurrencyRates/src/CommonOptionDlg.cpp221
-rw-r--r--protocols/CurrencyRates/src/CommonOptionDlg.h17
-rw-r--r--protocols/CurrencyRates/src/CreateFilePath.cpp17
-rw-r--r--protocols/CurrencyRates/src/CreateFilePath.h6
-rw-r--r--protocols/CurrencyRates/src/CurrencyConverter.cpp260
-rw-r--r--protocols/CurrencyRates/src/CurrencyConverter.h6
-rw-r--r--protocols/CurrencyRates/src/CurrencyRateChart.cpp101
-rw-r--r--protocols/CurrencyRates/src/CurrencyRateChart.h12
-rw-r--r--protocols/CurrencyRates/src/CurrencyRateInfoDlg.cpp257
-rw-r--r--protocols/CurrencyRates/src/CurrencyRateInfoDlg.h11
-rw-r--r--protocols/CurrencyRates/src/CurrencyRatesProviderBase.cpp935
-rw-r--r--protocols/CurrencyRates/src/CurrencyRatesProviderBase.h122
-rw-r--r--protocols/CurrencyRates/src/CurrencyRatesProviderCurrencyConverter.cpp438
-rw-r--r--protocols/CurrencyRates/src/CurrencyRatesProviderCurrencyConverter.h32
-rw-r--r--protocols/CurrencyRates/src/CurrencyRatesProviders.cpp83
-rw-r--r--protocols/CurrencyRates/src/DBUtils.cpp43
-rw-r--r--protocols/CurrencyRates/src/DBUtils.h53
-rw-r--r--protocols/CurrencyRates/src/EconomicRateInfo.h59
-rw-r--r--protocols/CurrencyRates/src/ExtraImages.cpp30
-rw-r--r--protocols/CurrencyRates/src/ExtraImages.h16
-rw-r--r--protocols/CurrencyRates/src/Forex.cpp325
-rw-r--r--protocols/CurrencyRates/src/HTMLParserMS.cpp254
-rw-r--r--protocols/CurrencyRates/src/HTMLParserMS.h32
-rw-r--r--protocols/CurrencyRates/src/HTTPSession.cpp91
-rw-r--r--protocols/CurrencyRates/src/HTTPSession.h20
-rw-r--r--protocols/CurrencyRates/src/ICurrencyRatesProvider.h62
-rw-r--r--protocols/CurrencyRates/src/IHTMLEngine.h18
-rw-r--r--protocols/CurrencyRates/src/IHTMLParser.h41
-rw-r--r--protocols/CurrencyRates/src/IconLib.cpp40
-rw-r--r--protocols/CurrencyRates/src/IconLib.h11
-rw-r--r--protocols/CurrencyRates/src/ImportExport.cpp507
-rw-r--r--protocols/CurrencyRates/src/ImportExport.h10
-rw-r--r--protocols/CurrencyRates/src/IsWithinAccuracy.h15
-rw-r--r--protocols/CurrencyRates/src/Locale.cpp59
-rw-r--r--protocols/CurrencyRates/src/Locale.h9
-rw-r--r--protocols/CurrencyRates/src/Log.cpp41
-rw-r--r--protocols/CurrencyRates/src/Log.h13
-rw-r--r--protocols/CurrencyRates/src/ModuleInfo.cpp64
-rw-r--r--protocols/CurrencyRates/src/ModuleInfo.h23
-rw-r--r--protocols/CurrencyRates/src/SettingsDlg.cpp971
-rw-r--r--protocols/CurrencyRates/src/SettingsDlg.h116
-rw-r--r--protocols/CurrencyRates/src/WinCtrlHelper.cpp31
-rw-r--r--protocols/CurrencyRates/src/WinCtrlHelper.h37
-rw-r--r--protocols/CurrencyRates/src/resource.h102
-rw-r--r--protocols/CurrencyRates/src/stdafx.cxx18
-rw-r--r--protocols/CurrencyRates/src/stdafx.h113
-rw-r--r--protocols/CurrencyRates/src/version.h13
-rw-r--r--protocols/FacebookRM/kdjfg1
-rw-r--r--protocols/GmailNotifier/GmailNotifier.vcxproj28
-rw-r--r--protocols/GmailNotifier/GmailNotifier.vcxproj.filters4
-rw-r--r--protocols/GmailNotifier/res/empty.icobin0 -> 2550 bytes
-rw-r--r--protocols/GmailNotifier/res/error.icobin0 -> 2550 bytes
-rw-r--r--protocols/GmailNotifier/res/iconnew.icobin0 -> 2550 bytes
-rw-r--r--protocols/GmailNotifier/res/options.rc140
-rw-r--r--protocols/GmailNotifier/res/version.rc9
-rw-r--r--protocols/GmailNotifier/src/check.cpp149
-rw-r--r--protocols/GmailNotifier/src/main.cpp162
-rw-r--r--protocols/GmailNotifier/src/notify.cpp206
-rw-r--r--protocols/GmailNotifier/src/options.cpp284
-rw-r--r--protocols/GmailNotifier/src/resource.h47
-rw-r--r--protocols/GmailNotifier/src/stdafx.cxx18
-rw-r--r--protocols/GmailNotifier/src/stdafx.h100
-rw-r--r--protocols/GmailNotifier/src/utility.cpp77
-rw-r--r--protocols/GmailNotifier/src/version.h13
-rw-r--r--protocols/LotusNotify/LotusNotify.vcxproj20
-rw-r--r--protocols/LotusNotify/LotusNotify.vcxproj.filters4
-rw-r--r--protocols/LotusNotify/res/LotusNotify.rc162
-rw-r--r--protocols/LotusNotify/res/Version.rc9
-rw-r--r--protocols/LotusNotify/res/icon1.icobin0 -> 1406 bytes
-rw-r--r--protocols/LotusNotify/res/icon2.icobin0 -> 318 bytes
-rw-r--r--protocols/LotusNotify/src/LotusNotify.cpp1753
-rw-r--r--protocols/LotusNotify/src/LotusNotify.h37
-rw-r--r--protocols/LotusNotify/src/cnotesapi/include/bsafeerr.h931
-rw-r--r--protocols/LotusNotify/src/cnotesapi/include/extmgr.h492
-rw-r--r--protocols/LotusNotify/src/cnotesapi/include/global.h1242
-rw-r--r--protocols/LotusNotify/src/cnotesapi/include/globerr.h443
-rw-r--r--protocols/LotusNotify/src/cnotesapi/include/misc.h413
-rw-r--r--protocols/LotusNotify/src/cnotesapi/include/names.h177
-rw-r--r--protocols/LotusNotify/src/cnotesapi/include/nif.h520
-rw-r--r--protocols/LotusNotify/src/cnotesapi/include/nls.h536
-rw-r--r--protocols/LotusNotify/src/cnotesapi/include/nsfdata.h841
-rw-r--r--protocols/LotusNotify/src/cnotesapi/include/nsfdb.h924
-rw-r--r--protocols/LotusNotify/src/cnotesapi/include/nsferr.h2663
-rw-r--r--protocols/LotusNotify/src/cnotesapi/include/nsfnote.h551
-rw-r--r--protocols/LotusNotify/src/cnotesapi/include/nsfsearc.h181
-rw-r--r--protocols/LotusNotify/src/cnotesapi/include/nsfstr.h257
-rw-r--r--protocols/LotusNotify/src/cnotesapi/include/osenv.h76
-rw-r--r--protocols/LotusNotify/src/cnotesapi/include/osmisc.h109
-rw-r--r--protocols/LotusNotify/src/cnotesapi/include/pool.h88
-rw-r--r--protocols/LotusNotify/src/cnotesapi/include/stdnames.h6175
-rw-r--r--protocols/LotusNotify/src/debug.cpp41
-rw-r--r--protocols/LotusNotify/src/debug.h8
-rw-r--r--protocols/LotusNotify/src/lotusnotes.cpp84
-rw-r--r--protocols/LotusNotify/src/lotusnotes.h176
-rw-r--r--protocols/LotusNotify/src/resource.h52
-rw-r--r--protocols/LotusNotify/src/stdafx.cxx18
-rw-r--r--protocols/LotusNotify/src/stdafx.h38
-rw-r--r--protocols/LotusNotify/src/version.h15
-rw-r--r--protocols/NewsAggregator/NewsAggregator.vcxproj28
-rw-r--r--protocols/NewsAggregator/NewsAggregator.vcxproj.filters4
-rw-r--r--protocols/NewsAggregator/Res/AddFeed.icobin0 -> 1150 bytes
-rw-r--r--protocols/NewsAggregator/Res/CheckALL.icobin0 -> 1150 bytes
-rw-r--r--protocols/NewsAggregator/Res/Disabled.icobin0 -> 1150 bytes
-rw-r--r--protocols/NewsAggregator/Res/Enabled.icobin0 -> 1150 bytes
-rw-r--r--protocols/NewsAggregator/Res/Export.icobin0 -> 1150 bytes
-rw-r--r--protocols/NewsAggregator/Res/Import.icobin0 -> 1150 bytes
-rw-r--r--protocols/NewsAggregator/Res/Main.icobin0 -> 5430 bytes
-rw-r--r--protocols/NewsAggregator/Res/Resource.rc184
-rw-r--r--protocols/NewsAggregator/Res/Version.rc9
-rw-r--r--protocols/NewsAggregator/Src/Authentication.cpp101
-rw-r--r--protocols/NewsAggregator/Src/CheckFeed.cpp473
-rw-r--r--protocols/NewsAggregator/Src/Icons.cpp53
-rw-r--r--protocols/NewsAggregator/Src/Menus.cpp83
-rw-r--r--protocols/NewsAggregator/Src/NewsAggregator.cpp106
-rw-r--r--protocols/NewsAggregator/Src/Options.cpp1016
-rw-r--r--protocols/NewsAggregator/Src/Options.h162
-rw-r--r--protocols/NewsAggregator/Src/Services.cpp261
-rw-r--r--protocols/NewsAggregator/Src/Update.cpp139
-rw-r--r--protocols/NewsAggregator/Src/Utils.cpp445
-rw-r--r--protocols/NewsAggregator/Src/resource.h57
-rw-r--r--protocols/NewsAggregator/Src/stdafx.cxx18
-rw-r--r--protocols/NewsAggregator/Src/stdafx.h167
-rw-r--r--protocols/NewsAggregator/Src/version.h13
-rw-r--r--protocols/NewsAggregator/docs/AtomText.txt482
-rw-r--r--protocols/NewsAggregator/docs/RssText.txt713
-rw-r--r--protocols/NewsAggregator/docs/ToDo.txt11
-rw-r--r--protocols/NewsAggregator/docs/subscriptions_test.xml169
-rw-r--r--protocols/NewsAggregator/proto_newsaggregator/Proto_NewsAggregator.vcxproj28
-rw-r--r--protocols/NewsAggregator/proto_newsaggregator/Proto_NewsAggregator.vcxproj.filters4
-rw-r--r--protocols/NewsAggregator/proto_newsaggregator/res/Offline.icobin0 -> 5430 bytes
-rw-r--r--protocols/NewsAggregator/proto_newsaggregator/res/Online.icobin0 -> 5430 bytes
-rw-r--r--protocols/NewsAggregator/proto_newsaggregator/res/Proto_NewsAggregator.rc70
-rw-r--r--protocols/NewsAggregator/proto_newsaggregator/src/resource.h17
-rw-r--r--protocols/Non-IM Contact/nimcontact.vcxproj28
-rw-r--r--protocols/Non-IM Contact/nimcontact.vcxproj.filters4
-rw-r--r--protocols/Non-IM Contact/res/Version.rc9
-rw-r--r--protocols/Non-IM Contact/res/resource.rc321
-rw-r--r--protocols/Non-IM Contact/res/star8.icobin0 -> 894 bytes
-rw-r--r--protocols/Non-IM Contact/src/contactinfo.cpp675
-rw-r--r--protocols/Non-IM Contact/src/dialog.cpp332
-rw-r--r--protocols/Non-IM Contact/src/files.cpp328
-rw-r--r--protocols/Non-IM Contact/src/http.cpp100
-rw-r--r--protocols/Non-IM Contact/src/main.cpp194
-rw-r--r--protocols/Non-IM Contact/src/namereplacing.cpp633
-rw-r--r--protocols/Non-IM Contact/src/resource.h76
-rw-r--r--protocols/Non-IM Contact/src/services.cpp112
-rw-r--r--protocols/Non-IM Contact/src/stdafx.cxx18
-rw-r--r--protocols/Non-IM Contact/src/stdafx.h130
-rw-r--r--protocols/Non-IM Contact/src/timer.cpp85
-rw-r--r--protocols/Non-IM Contact/src/version.h13
-rw-r--r--protocols/Weather/docs/history.txt930
-rw-r--r--protocols/Weather/docs/license.txt340
-rw-r--r--protocols/Weather/docs/readme.html230
-rw-r--r--protocols/Weather/docs/sample_ini.ini428
-rw-r--r--protocols/Weather/docs/weather/gismeteo.ini906
-rw-r--r--protocols/Weather/docs/weather/msn.ini1063
-rw-r--r--protocols/Weather/docs/weather/weatherxml.ini911
-rw-r--r--protocols/Weather/docs/weather/wundergrnd_intl.ini348
-rw-r--r--protocols/Weather/docs/weather/wundergrnd_xml.ini325
-rw-r--r--protocols/Weather/proto_weather/proto_weather.vcxproj28
-rw-r--r--protocols/Weather/proto_weather/proto_weather.vcxproj.filters4
-rw-r--r--protocols/Weather/proto_weather/res/Cloud.icobin0 -> 5430 bytes
-rw-r--r--protocols/Weather/proto_weather/res/FOG.icobin0 -> 5430 bytes
-rw-r--r--protocols/Weather/proto_weather/res/LIGHT.icobin0 -> 5430 bytes
-rw-r--r--protocols/Weather/proto_weather/res/NA.icobin0 -> 5430 bytes
-rw-r--r--protocols/Weather/proto_weather/res/PCLOUDY.icobin0 -> 5430 bytes
-rw-r--r--protocols/Weather/proto_weather/res/RAIN.icobin0 -> 5430 bytes
-rw-r--r--protocols/Weather/proto_weather/res/RSHOWER.icobin0 -> 5430 bytes
-rw-r--r--protocols/Weather/proto_weather/res/SNOW.icobin0 -> 5430 bytes
-rw-r--r--protocols/Weather/proto_weather/res/SSHOWER.icobin0 -> 5430 bytes
-rw-r--r--protocols/Weather/proto_weather/res/SUN.icobin0 -> 5430 bytes
-rw-r--r--protocols/Weather/proto_weather/res/resource.rc41
-rw-r--r--protocols/Weather/res/Version.rc9
-rw-r--r--protocols/Weather/res/brief.icobin0 -> 1150 bytes
-rw-r--r--protocols/Weather/res/disabled.icobin0 -> 1150 bytes
-rw-r--r--protocols/Weather/res/edit.icobin0 -> 1150 bytes
-rw-r--r--protocols/Weather/res/icon.icobin0 -> 5430 bytes
-rw-r--r--protocols/Weather/res/log.icobin0 -> 1150 bytes
-rw-r--r--protocols/Weather/res/map.icobin0 -> 1150 bytes
-rw-r--r--protocols/Weather/res/more.icobin0 -> 1150 bytes
-rw-r--r--protocols/Weather/res/popup.icobin0 -> 1150 bytes
-rw-r--r--protocols/Weather/res/popup_no.icobin0 -> 1150 bytes
-rw-r--r--protocols/Weather/res/resource.rc427
-rw-r--r--protocols/Weather/res/update.icobin0 -> 1150 bytes
-rw-r--r--protocols/Weather/res/update2.icobin0 -> 1150 bytes
-rw-r--r--protocols/Weather/src/resource.h175
-rw-r--r--protocols/Weather/src/stdafx.cxx18
-rw-r--r--protocols/Weather/src/stdafx.h547
-rw-r--r--protocols/Weather/src/version.h13
-rw-r--r--protocols/Weather/src/weather.cpp231
-rw-r--r--protocols/Weather/src/weather_addstn.cpp432
-rw-r--r--protocols/Weather/src/weather_contacts.cpp480
-rw-r--r--protocols/Weather/src/weather_conv.cpp637
-rw-r--r--protocols/Weather/src/weather_data.cpp439
-rw-r--r--protocols/Weather/src/weather_http.cpp157
-rw-r--r--protocols/Weather/src/weather_icons.cpp64
-rw-r--r--protocols/Weather/src/weather_info.cpp240
-rw-r--r--protocols/Weather/src/weather_ini.cpp592
-rw-r--r--protocols/Weather/src/weather_mwin.cpp364
-rw-r--r--protocols/Weather/src/weather_opt.cpp601
-rw-r--r--protocols/Weather/src/weather_popup.cpp428
-rw-r--r--protocols/Weather/src/weather_svcs.cpp375
-rw-r--r--protocols/Weather/src/weather_update.cpp607
-rw-r--r--protocols/Weather/src/weather_userinfo.cpp358
-rw-r--r--protocols/Weather/weather.vcxproj28
-rw-r--r--protocols/Weather/weather.vcxproj.filters4
-rw-r--r--protocols/WebView/docs/changelog.txt6
-rw-r--r--protocols/WebView/docs/license.txt340
-rw-r--r--protocols/WebView/docs/readme.txt1000
-rw-r--r--protocols/WebView/docs/todo.txt3
-rw-r--r--protocols/WebView/res/Icon_14.icobin0 -> 2550 bytes
-rw-r--r--protocols/WebView/res/alert.icobin0 -> 2550 bytes
-rw-r--r--protocols/WebView/res/find.icobin0 -> 2550 bytes
-rw-r--r--protocols/WebView/res/folder.icobin0 -> 2550 bytes
-rw-r--r--protocols/WebView/res/markallread.icobin0 -> 2550 bytes
-rw-r--r--protocols/WebView/res/options.icobin0 -> 2550 bytes
-rw-r--r--protocols/WebView/res/ping.icobin0 -> 894 bytes
-rw-r--r--protocols/WebView/res/popup.icobin0 -> 2550 bytes
-rw-r--r--protocols/WebView/res/show_hide.icobin0 -> 2550 bytes
-rw-r--r--protocols/WebView/res/stick.icobin0 -> 2550 bytes
-rw-r--r--protocols/WebView/res/stop.icobin0 -> 2550 bytes
-rw-r--r--protocols/WebView/res/unstick.icobin0 -> 2550 bytes
-rw-r--r--protocols/WebView/res/update.icobin0 -> 2550 bytes
-rw-r--r--protocols/WebView/res/updateall.icobin0 -> 2550 bytes
-rw-r--r--protocols/WebView/res/url.icobin0 -> 2550 bytes
-rw-r--r--protocols/WebView/res/version.rc9
-rw-r--r--protocols/WebView/res/web.icobin0 -> 894 bytes
-rw-r--r--protocols/WebView/res/webview.rc364
-rw-r--r--protocols/WebView/src/main.cpp285
-rw-r--r--protocols/WebView/src/resource.h139
-rw-r--r--protocols/WebView/src/stdafx.cxx18
-rw-r--r--protocols/WebView/src/stdafx.h36
-rw-r--r--protocols/WebView/src/version.h13
-rw-r--r--protocols/WebView/src/webview.cpp481
-rw-r--r--protocols/WebView/src/webview.h254
-rw-r--r--protocols/WebView/src/webview_alerts.cpp839
-rw-r--r--protocols/WebView/src/webview_cleanup.cpp797
-rw-r--r--protocols/WebView/src/webview_datawnd.cpp514
-rw-r--r--protocols/WebView/src/webview_getdata.cpp511
-rw-r--r--protocols/WebView/src/webview_opts.cpp1265
-rw-r--r--protocols/WebView/src/webview_services.cpp458
-rw-r--r--protocols/WebView/webview.vcxproj28
-rw-r--r--protocols/WebView/webview.vcxproj.filters4
-rw-r--r--protocols/YAMN/YAMN.vcxproj53
-rw-r--r--protocols/YAMN/YAMN.vcxproj.filters4
-rw-r--r--protocols/YAMN/docs/ChangeLog.txt243
-rw-r--r--protocols/YAMN/docs/InstallScript.xml49
-rw-r--r--protocols/YAMN/docs/license.txt340
-rw-r--r--protocols/YAMN/docs/readme.developers.txt205
-rw-r--r--protocols/YAMN/docs/readme.txt79
-rw-r--r--protocols/YAMN/proto_yamn/proto_YAMN.vcxproj28
-rw-r--r--protocols/YAMN/proto_yamn/proto_YAMN.vcxproj.filters4
-rw-r--r--protocols/YAMN/proto_yamn/res/icoaway.icobin0 -> 1150 bytes
-rw-r--r--protocols/YAMN/proto_yamn/res/icooccupied.icobin0 -> 1150 bytes
-rw-r--r--protocols/YAMN/proto_yamn/res/icooffline.icobin0 -> 1150 bytes
-rw-r--r--protocols/YAMN/proto_yamn/res/icoonline.icobin0 -> 1150 bytes
-rw-r--r--protocols/YAMN/proto_yamn/res/proto_YAMN.rc16
-rw-r--r--protocols/YAMN/proto_yamn/src/resource.h20
-rw-r--r--protocols/YAMN/res/Version.rc9
-rw-r--r--protocols/YAMN/res/YAMN.rc330
-rw-r--r--protocols/YAMN/res/badconnect.icobin0 -> 1150 bytes
-rw-r--r--protocols/YAMN/res/checkmail.icobin0 -> 1150 bytes
-rw-r--r--protocols/YAMN/res/launchapp.icobin0 -> 1150 bytes
-rw-r--r--protocols/YAMN/res/newmail.icobin0 -> 1150 bytes
-rw-r--r--protocols/YAMN/src/account.cpp1246
-rw-r--r--protocols/YAMN/src/browser/badconnect.cpp296
-rw-r--r--protocols/YAMN/src/browser/browser.h39
-rw-r--r--protocols/YAMN/src/browser/mailbrowser.cpp2369
-rw-r--r--protocols/YAMN/src/debug.cpp127
-rw-r--r--protocols/YAMN/src/debug.h51
-rw-r--r--protocols/YAMN/src/filterplugin.cpp200
-rw-r--r--protocols/YAMN/src/mails/decode.cpp555
-rw-r--r--protocols/YAMN/src/mails/decode.h23
-rw-r--r--protocols/YAMN/src/mails/mails.cpp494
-rw-r--r--protocols/YAMN/src/mails/mime.cpp718
-rw-r--r--protocols/YAMN/src/main.cpp353
-rw-r--r--protocols/YAMN/src/main.h39
-rw-r--r--protocols/YAMN/src/proto/netclient.h22
-rw-r--r--protocols/YAMN/src/proto/netlib.cpp242
-rw-r--r--protocols/YAMN/src/proto/netlib.h51
-rw-r--r--protocols/YAMN/src/proto/pop3/pop3.cpp356
-rw-r--r--protocols/YAMN/src/proto/pop3/pop3.h63
-rw-r--r--protocols/YAMN/src/proto/pop3/pop3comm.cpp1558
-rw-r--r--protocols/YAMN/src/proto/pop3/pop3comm.h83
-rw-r--r--protocols/YAMN/src/proto/pop3/pop3opt.cpp1481
-rw-r--r--protocols/YAMN/src/proto/pop3/pop3opt.h40
-rw-r--r--protocols/YAMN/src/protoplugin.cpp192
-rw-r--r--protocols/YAMN/src/resource.h127
-rw-r--r--protocols/YAMN/src/services.cpp450
-rw-r--r--protocols/YAMN/src/stdafx.cxx18
-rw-r--r--protocols/YAMN/src/stdafx.h262
-rw-r--r--protocols/YAMN/src/synchro.cpp359
-rw-r--r--protocols/YAMN/src/version.h13
-rw-r--r--protocols/YAMN/src/yamn.cpp320
399 files changed, 75336 insertions, 0 deletions
diff --git a/protocols/CloudFile/CloudFile.vcxproj b/protocols/CloudFile/CloudFile.vcxproj
new file mode 100644
index 0000000000..88e1946426
--- /dev/null
+++ b/protocols/CloudFile/CloudFile.vcxproj
@@ -0,0 +1,40 @@
+<?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>CloudFile</ProjectName>
+ <ProjectGuid>{E876FE63-0701-4CDA-BED5-7C73A379C1D1}</ProjectGuid>
+ </PropertyGroup>
+ <ImportGroup Label="PropertySheets">
+ <Import Project="$(ProjectDir)..\..\build\vc.common\plugin.props" />
+ </ImportGroup>
+ <ItemGroup>
+ <ClInclude Include="src\Services\*.h" />
+ <ClCompile Include="src\Services\*.cpp">
+ <PrecompiledHeader>NotUsing</PrecompiledHeader>
+ </ClCompile>
+ <None Include="res\*.ico" />
+ </ItemGroup>
+ <ItemDefinitionGroup>
+ <Link>
+ <AdditionalDependencies>comctl32.lib;shlwapi.lib;%(AdditionalDependencies)</AdditionalDependencies>
+ </Link>
+ </ItemDefinitionGroup>
+</Project>
diff --git a/protocols/CloudFile/CloudFile.vcxproj.filters b/protocols/CloudFile/CloudFile.vcxproj.filters
new file mode 100644
index 0000000000..c26cb717b8
--- /dev/null
+++ b/protocols/CloudFile/CloudFile.vcxproj.filters
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <ItemGroup>
+ <Filter Include="Header Files\Services">
+ <UniqueIdentifier>{64D2CE87-E04F-4768-BD94-86282BBD138B}</UniqueIdentifier>
+ </Filter>
+ <Filter Include="Source Files\Services">
+ <UniqueIdentifier>{1D61FE06-83AA-4C8A-A8FC-36EAD0EAAC97}</UniqueIdentifier>
+ </Filter>
+ </ItemGroup>
+ <ItemGroup>
+ <ClInclude Include="src\*.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="src\Services\*.h">
+ <Filter>Header Files\Services</Filter>
+ </ClInclude>
+ <ClCompile Include="src\*.cpp;src\*.cxx">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="src\Services\*.cpp">
+ <Filter>Source Files\Services</Filter>
+ </ClCompile>
+ <ResourceCompile Include="res\*.rc">
+ <Filter>Resource Files</Filter>
+ </ResourceCompile>
+ <None Include="res\*.ico;res\*.bmp;res\*.cur">
+ <Filter>Resource Files</Filter>
+ </None>
+ </ItemGroup>
+ <Import Project="$(ProjectDir)..\..\build\vc.common\common.filters" />
+</Project>
diff --git a/protocols/CloudFile/res/dropbox.ico b/protocols/CloudFile/res/dropbox.ico
new file mode 100644
index 0000000000..8a286d7f32
--- /dev/null
+++ b/protocols/CloudFile/res/dropbox.ico
Binary files differ
diff --git a/protocols/CloudFile/res/gdrive.ico b/protocols/CloudFile/res/gdrive.ico
new file mode 100644
index 0000000000..a34123e95b
--- /dev/null
+++ b/protocols/CloudFile/res/gdrive.ico
Binary files differ
diff --git a/protocols/CloudFile/res/onedrive.ico b/protocols/CloudFile/res/onedrive.ico
new file mode 100644
index 0000000000..502cee9bb7
--- /dev/null
+++ b/protocols/CloudFile/res/onedrive.ico
Binary files differ
diff --git a/protocols/CloudFile/res/resource.rc b/protocols/CloudFile/res/resource.rc
new file mode 100644
index 0000000000..54eb588ffa
--- /dev/null
+++ b/protocols/CloudFile/res/resource.rc
@@ -0,0 +1,200 @@
+// Microsoft Visual C++ generated resource script.
+//
+#include "..\src\resource.h"
+
+#define APSTUDIO_READONLY_SYMBOLS
+/////////////////////////////////////////////////////////////////////////////
+//
+// Generated from the TEXTINCLUDE 2 resource.
+//
+#include "winres.h"
+
+/////////////////////////////////////////////////////////////////////////////
+#undef APSTUDIO_READONLY_SYMBOLS
+
+/////////////////////////////////////////////////////////////////////////////
+// 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
+ "..\\src\\resource.h\0"
+END
+
+2 TEXTINCLUDE
+BEGIN
+ "#include ""winres.h""\r\n"
+ "\0"
+END
+
+3 TEXTINCLUDE
+BEGIN
+ "\r\n"
+ "\0"
+END
+
+#endif // APSTUDIO_INVOKED
+
+#endif // Russian (Russia) resources
+/////////////////////////////////////////////////////////////////////////////
+
+
+/////////////////////////////////////////////////////////////////////////////
+// English resources
+
+#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU)
+LANGUAGE LANG_ENGLISH, SUBLANG_NEUTRAL
+#pragma code_page(1252)
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Icon
+//
+
+// Icon with lowest ID value placed first to ensure application icon
+// remains consistent on all systems.
+IDI_UPLOAD ICON "upload.ico"
+
+IDI_DROPBOX ICON "dropbox.ico"
+
+IDI_GDRIVE ICON "gdrive.ico"
+
+IDI_ONEDRIVE ICON "onedrive.ico"
+
+IDI_YADISK ICON "yadisk.ico"
+
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Dialog
+//
+
+IDD_OPTIONS_MAIN DIALOGEX 0, 0, 307, 234
+STYLE DS_SETFONT | DS_FIXEDSYS | WS_CHILD
+EXSTYLE WS_EX_CONTROLPARENT
+FONT 8, "MS Shell Dlg", 0, 0, 0x1
+BEGIN
+ LTEXT "Default service",IDC_STATIC,11,19,85,8
+ COMBOBOX IDC_DEFAULTSERVICE,102,17,194,12,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP
+ GROUPBOX "General",IDC_STATIC,5,5,297,33
+ CONTROL "Autosend download link to contact",IDC_URL_AUTOSEND,
+ "Button",BS_AUTORADIOBUTTON | WS_GROUP,11,114,282,10
+ CONTROL "Paste download link into message input area",IDC_URL_COPYTOMIA,
+ "Button",BS_AUTORADIOBUTTON,11,127,282,10
+ CONTROL "Copy download link to clipboard",IDC_URL_COPYTOCB,
+ "Button",BS_AUTOCHECKBOX | WS_TABSTOP,11,140,282,10
+ GROUPBOX "Download link",IDC_STATIC,5,100,297,57
+ CONTROL "Do nothing",IDC_DONOTHINGONCONFLICT,"Button",BS_AUTORADIOBUTTON | WS_GROUP,11,54,285,10
+ CONTROL "Try to rename",IDC_RENAMEONCONFLICT,"Button",BS_AUTORADIOBUTTON,11,67,285,10
+ CONTROL "Try to replace",IDC_REPLACEONCONFLICT,"Button",BS_AUTORADIOBUTTON,11,80,285,10
+ GROUPBOX "On conflict when upload",IDC_STATIC,5,41,297,56
+END
+
+IDD_OAUTH DIALOGEX 0, 0, 193, 83
+STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | DS_CENTER | WS_POPUP | WS_CAPTION | WS_SYSMENU
+EXSTYLE WS_EX_TOPMOST
+CAPTION "Authorization"
+FONT 8, "MS Shell Dlg", 400, 0, 0x1
+BEGIN
+ EDITTEXT IDC_OAUTH_CODE,7,43,179,14,ES_AUTOHSCROLL
+ DEFPUSHBUTTON "OK",IDOK,75,62,50,14
+ PUSHBUTTON "Cancel",IDCANCEL,136,62,50,14
+ LTEXT "Enter authorization code:",IDC_STATIC,7,33,179,8
+ LTEXT "To allow Miranda NG access to %s:",IDC_AUTH_TEXT,7,7,179,8
+ CONTROL "Go to this link",IDC_OAUTH_AUTHORIZE,"Hyperlink",WS_GROUP | WS_TABSTOP | 0x1,7,18,179,8
+END
+
+IDD_ACCMGR DIALOGEX 0, 0, 188, 126
+STYLE DS_SETFONT | DS_FIXEDSYS | WS_CHILD | WS_SYSMENU
+EXSTYLE WS_EX_CONTROLPARENT
+FONT 8, "MS Shell Dlg", 400, 0, 0x1
+BEGIN
+ PUSHBUTTON "Request access",IDC_REQUESTACCESS,5,19,83,14
+ PUSHBUTTON "Revoke access",IDC_REVOKEACCESS,97,19,83,14
+END
+
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// AFX_DIALOG_LAYOUT
+//
+
+IDD_OPTIONS_MAIN AFX_DIALOG_LAYOUT
+BEGIN
+ 0
+END
+
+IDD_OAUTH AFX_DIALOG_LAYOUT
+BEGIN
+ 0
+END
+
+IDD_ACCMGR AFX_DIALOG_LAYOUT
+BEGIN
+ 0
+END
+
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// DESIGNINFO
+//
+
+#ifdef APSTUDIO_INVOKED
+GUIDELINES DESIGNINFO
+BEGIN
+ IDD_OPTIONS_MAIN, DIALOG
+ BEGIN
+ LEFTMARGIN, 5
+ RIGHTMARGIN, 302
+ VERTGUIDE, 11
+ VERTGUIDE, 96
+ VERTGUIDE, 102
+ VERTGUIDE, 296
+ TOPMARGIN, 5
+ BOTTOMMARGIN, 229
+ END
+
+ IDD_OAUTH, DIALOG
+ BEGIN
+ LEFTMARGIN, 7
+ RIGHTMARGIN, 186
+ TOPMARGIN, 7
+ BOTTOMMARGIN, 76
+ END
+
+ IDD_ACCMGR, DIALOG
+ BEGIN
+ LEFTMARGIN, 7
+ RIGHTMARGIN, 181
+ TOPMARGIN, 7
+ BOTTOMMARGIN, 119
+ HORZGUIDE, 33
+ END
+END
+#endif // APSTUDIO_INVOKED
+
+#endif // English resources
+/////////////////////////////////////////////////////////////////////////////
+
+
+
+#ifndef APSTUDIO_INVOKED
+/////////////////////////////////////////////////////////////////////////////
+//
+// Generated from the TEXTINCLUDE 3 resource.
+//
+
+
+/////////////////////////////////////////////////////////////////////////////
+#endif // not APSTUDIO_INVOKED
+
diff --git a/protocols/CloudFile/res/upload.ico b/protocols/CloudFile/res/upload.ico
new file mode 100644
index 0000000000..b51e87ed35
--- /dev/null
+++ b/protocols/CloudFile/res/upload.ico
Binary files differ
diff --git a/protocols/CloudFile/res/version.rc b/protocols/CloudFile/res/version.rc
new file mode 100644
index 0000000000..5a5ddd63ed
--- /dev/null
+++ b/protocols/CloudFile/res/version.rc
@@ -0,0 +1,9 @@
+// Microsoft Visual C++ generated resource script.
+//
+#ifdef APSTUDIO_INVOKED
+#error this file is not editable by Microsoft Visual C++
+#endif //APSTUDIO_INVOKED
+
+#include "..\src\version.h"
+
+#include "..\..\build\Version.rc"
diff --git a/protocols/CloudFile/res/yadisk.ico b/protocols/CloudFile/res/yadisk.ico
new file mode 100644
index 0000000000..b3a5ac69b4
--- /dev/null
+++ b/protocols/CloudFile/res/yadisk.ico
Binary files differ
diff --git a/protocols/CloudFile/src/Services/dropbox_api.h b/protocols/CloudFile/src/Services/dropbox_api.h
new file mode 100644
index 0000000000..e7e77600c0
--- /dev/null
+++ b/protocols/CloudFile/src/Services/dropbox_api.h
@@ -0,0 +1,221 @@
+#ifndef _DROPBOXSERVICE_API_H_
+#define _DROPBOXSERVICE_API_H_
+
+// https://www.dropbox.com/developers/documentation/http/documentation
+namespace DropboxAPI
+{
+#define DROPBOX_API_VER "/2"
+#define DROPBOX_API "https://api.dropboxapi.com"
+#define DROPBOX_API_OAUTH DROPBOX_API "/oauth2"
+#define DROPBOX_API_RPC DROPBOX_API DROPBOX_API_VER
+#define DROPBOX_CONTENT "https://content.dropboxapi.com"
+#define DROPBOX_API_CU DROPBOX_CONTENT DROPBOX_API_VER
+
+#define DROPBOX_APP_KEY "fa8du7gkf2q8xzg"
+#include "../../../miranda-private-keys/Dropbox/secret_key.h"
+
+#define DROPBOX_API_AUTH "https://www.dropbox.com/oauth2/authorize?response_type=code&redirect_uri=https%3A%2F%2Foauth.miranda-ng.org%2Fverification&client_id=" DROPBOX_APP_KEY
+
+ class GetAccessTokenRequest : public HttpRequest
+ {
+ public:
+ GetAccessTokenRequest(const char *code) :
+ HttpRequest(REQUEST_POST, DROPBOX_API_OAUTH "/token")
+ {
+ AddHeader("Content-Type", "application/x-www-form-urlencoded");
+
+ CMStringA data = "redirect_uri=https://oauth.miranda-ng.org/verification";
+ data.AppendFormat("&client_id=%s&client_secret=%s", DROPBOX_APP_KEY, DROPBOX_API_SECRET);
+ data.AppendFormat("&grant_type=authorization_code&code=%s", code);
+ SetData(data.GetBuffer(), data.GetLength());
+ }
+ };
+
+ class RevokeAccessTokenRequest : public HttpRequest
+ {
+ public:
+ RevokeAccessTokenRequest(const char *token) :
+ HttpRequest(REQUEST_POST, DROPBOX_API_OAUTH "/token/revoke")
+ {
+ AddBearerAuthHeader(token);
+ }
+ };
+
+ class UploadFileRequest : public HttpRequest
+ {
+ public:
+ UploadFileRequest(const char *token, const char *path, const char *data, size_t size, OnConflict strategy = NONE) :
+ HttpRequest(REQUEST_POST, DROPBOX_API_CU "/files/upload")
+ {
+ AddBearerAuthHeader(token);
+ AddHeader("Content-Type", "application/octet-stream");
+
+ JSONNode params(JSON_NODE);
+ params
+ << JSONNode("path", path);
+ if (strategy == OnConflict::RENAME) {
+ params
+ << JSONNode("mode", "add")
+ << JSONNode("autorename", true);
+ }
+ else if (strategy == OnConflict::REPLACE) {
+ params
+ << JSONNode("mode", "overwrite")
+ << JSONNode("autorename", false);
+ }
+
+ AddHeader("Dropbox-API-Arg", params.write().c_str());
+
+ SetData(data, size);
+ }
+ };
+
+ class CreateUploadSessionRequest : public HttpRequest
+ {
+ public:
+ CreateUploadSessionRequest(const char *token, const char *chunk, size_t chunkSize) :
+ HttpRequest(REQUEST_POST, DROPBOX_API_CU "/files/upload_session/start")
+ {
+ AddBearerAuthHeader(token);
+ AddHeader("Content-Type", "application/octet-stream");
+
+ SetData(chunk, chunkSize);
+ }
+ };
+
+ class UploadFileChunkRequest : public HttpRequest
+ {
+ public:
+ UploadFileChunkRequest(const char *token, const char *sessionId, size_t offset, const char *chunk, size_t chunkSize) :
+ HttpRequest(REQUEST_POST, DROPBOX_API_CU "/files/upload_session/append_v2")
+ {
+ AddBearerAuthHeader(token);
+ AddHeader("Content-Type", "application/octet-stream");
+
+
+ JSONNode cursor;
+ cursor.set_name("cursor");
+ cursor
+ << JSONNode("session_id", sessionId)
+ << JSONNode("offset", (unsigned long)offset);
+
+ JSONNode param;
+ param << cursor;
+
+ AddHeader("Dropbox-API-Arg", param.write().c_str());
+
+ SetData(chunk, chunkSize);
+ }
+ };
+
+ class CommitUploadSessionRequest : public HttpRequest
+ {
+ public:
+ CommitUploadSessionRequest(const char *token, const char *sessionId, size_t offset, const char *path, const char *chunk, size_t chunkSize, OnConflict strategy = NONE) :
+ HttpRequest(REQUEST_POST, DROPBOX_API_CU "/files/upload_session/finish")
+ {
+ AddBearerAuthHeader(token);
+ AddHeader("Content-Type", "application/octet-stream");
+
+ JSONNode cursor(JSON_NODE);
+ cursor.set_name("cursor");
+ cursor
+ << JSONNode("session_id", sessionId)
+ << JSONNode("offset", (unsigned long)offset);
+
+ JSONNode commit(JSON_NODE);
+ commit.set_name("commit");
+ commit
+ << JSONNode("path", path);
+ if (strategy == OnConflict::RENAME) {
+ commit
+ << JSONNode("mode", "add")
+ << JSONNode("autorename", true);
+ }
+ else if (strategy == OnConflict::REPLACE) {
+ commit
+ << JSONNode("mode", "overwrite")
+ << JSONNode("autorename", false);
+ }
+
+ JSONNode params(JSON_NODE);
+ params
+ << cursor
+ << commit;
+
+ AddHeader("Dropbox-API-Arg", params.write().c_str());
+
+ SetData(chunk, chunkSize);
+ }
+ };
+
+ class CreateFolderRequest : public HttpRequest
+ {
+ public:
+ CreateFolderRequest(const char *token, const char *path) :
+ HttpRequest(REQUEST_POST, DROPBOX_API_RPC "/files/create_folder_v2")
+ {
+ AddBearerAuthHeader(token);
+ AddHeader("Content-Type", "application/json");
+
+ JSONNode root(JSON_NODE);
+ root << JSONNode("path", path);
+
+ json_string data = root.write();
+ SetData(data.c_str(), data.length());
+ }
+ };
+
+ class GetTemporaryLinkRequest : public HttpRequest
+ {
+ public:
+ GetTemporaryLinkRequest(const char *token, const char *path) :
+ HttpRequest(REQUEST_POST, DROPBOX_API_RPC "/files/get_temporary_link")
+ {
+ AddBearerAuthHeader(token);
+ AddHeader("Content-Type", "application/json");
+
+ JSONNode root(JSON_NODE);
+ root << JSONNode("path", path);
+
+ json_string data = root.write();
+ SetData(data.c_str(), data.length());
+ }
+ };
+
+ class CreateSharedLinkRequest : public HttpRequest
+ {
+ public:
+ CreateSharedLinkRequest(const char *token, const char *path) :
+ HttpRequest(REQUEST_POST, DROPBOX_API_RPC "/sharing/create_shared_link_with_settings")
+ {
+ AddBearerAuthHeader(token);
+ AddHeader("Content-Type", "application/json");
+
+ JSONNode root(JSON_NODE);
+ root << JSONNode("path", path);
+
+ json_string data = root.write();
+ SetData(data.c_str(), data.length());
+ }
+ };
+
+ class GetSharedLinkRequest : public HttpRequest
+ {
+ public:
+ GetSharedLinkRequest(const char *token, const char *path) :
+ HttpRequest(REQUEST_POST, DROPBOX_API_RPC "/sharing/list_shared_links")
+ {
+ AddBearerAuthHeader(token);
+ AddHeader("Content-Type", "application/json");
+
+ JSONNode root(JSON_NODE);
+ root << JSONNode("path", path);
+
+ json_string data = root.write();
+ SetData(data.c_str(), data.length());
+ }
+ };
+};
+
+#endif //_DROPBOXSERVICE_API_H_
diff --git a/protocols/CloudFile/src/Services/dropbox_service.cpp b/protocols/CloudFile/src/Services/dropbox_service.cpp
new file mode 100644
index 0000000000..a2cfa5a2e5
--- /dev/null
+++ b/protocols/CloudFile/src/Services/dropbox_service.cpp
@@ -0,0 +1,302 @@
+#include "..\stdafx.h"
+#include "dropbox_api.h"
+
+struct CMPluginDropbox : public PLUGIN<CMPluginDropbox>
+{
+ CMPluginDropbox() :
+ PLUGIN<CMPluginDropbox>(MODULENAME "/Dropbox", pluginInfoEx)
+ {
+ m_hInst = g_plugin.getInst();
+
+ RegisterProtocol(PROTOTYPE_PROTOWITHACCS, (pfnInitProto)CDropboxService::Init, (pfnUninitProto)CDropboxService::UnInit);
+ }
+}
+g_pluginDropbox;
+
+/////////////////////////////////////////////////////////////////////////////////////////
+
+CDropboxService::CDropboxService(const char *protoName, const wchar_t *userName) :
+ CCloudService(protoName, userName, &g_pluginDropbox)
+{
+ m_hProtoIcon = GetIconHandle(IDI_DROPBOX);
+}
+
+CDropboxService* CDropboxService::Init(const char *moduleName, const wchar_t *userName)
+{
+ CDropboxService *proto = new CDropboxService(moduleName, userName);
+ Services.insert(proto);
+ return proto;
+}
+
+int CDropboxService::UnInit(CDropboxService *proto)
+{
+ Services.remove(proto);
+ delete proto;
+ return 0;
+}
+
+const char* CDropboxService::GetModuleName() const
+{
+ return "Dropbox";
+}
+
+int CDropboxService::GetIconId() const
+{
+ return IDI_DROPBOX;
+}
+
+bool CDropboxService::IsLoggedIn()
+{
+ ptrA token(getStringA("TokenSecret"));
+ if (!token || token[0] == 0)
+ return false;
+ return true;
+}
+
+void CDropboxService::Login(HWND owner)
+{
+ COAuthDlg dlg(this, DROPBOX_API_AUTH, (MyThreadFunc)&CDropboxService::RequestAccessTokenThread);
+ dlg.SetParent(owner);
+ dlg.DoModal();
+}
+
+void CDropboxService::Logout()
+{
+ ForkThread((MyThreadFunc)&CDropboxService::RevokeAccessTokenThread);
+}
+
+void CDropboxService::RequestAccessTokenThread(void *param)
+{
+ HWND hwndDlg = (HWND)param;
+
+ if (IsLoggedIn())
+ Logout();
+
+ char requestToken[128];
+ GetDlgItemTextA(hwndDlg, IDC_OAUTH_CODE, requestToken, _countof(requestToken));
+
+ DropboxAPI::GetAccessTokenRequest request(requestToken);
+ NLHR_PTR response(request.Send(m_hConnection));
+
+ if (response == nullptr || response->resultCode != HTTP_CODE_OK) {
+ Netlib_Logf(m_hConnection, "%s: %s", GetAccountName(), HttpStatusToError());
+ ShowNotification(TranslateT("Server does not respond"), MB_ICONERROR);
+ EndDialog(hwndDlg, 0);
+ return;
+ }
+
+ JSONNode root = JSONNode::parse(response->pData);
+ if (root.empty()) {
+ Netlib_Logf(m_hConnection, "%s: %s", GetAccountName(), HttpStatusToError(response->resultCode));
+ ShowNotification(TranslateT("Server does not respond"), MB_ICONERROR);
+ EndDialog(hwndDlg, 0);
+ return;
+ }
+
+ JSONNode node = root.at("error_description");
+ if (!node.isnull()) {
+ CMStringW error_description = node.as_mstring();
+ Netlib_Logf(m_hConnection, "%s: %s", GetAccountName(), HttpStatusToError(response->resultCode));
+ ShowNotification(error_description, MB_ICONERROR);
+ EndDialog(hwndDlg, 0);
+ return;
+ }
+
+ node = root.at("access_token");
+ db_set_s(0, GetAccountName(), "TokenSecret", node.as_string().c_str());
+
+ SetDlgItemTextA(hwndDlg, IDC_OAUTH_CODE, "");
+
+ EndDialog(hwndDlg, 1);
+}
+
+void CDropboxService::RevokeAccessTokenThread(void *)
+{
+ ptrA token(getStringA("TokenSecret"));
+ DropboxAPI::RevokeAccessTokenRequest request(token);
+ NLHR_PTR response(request.Send(m_hConnection));
+
+ delSetting("ExpiresIn");
+ delSetting("TokenSecret");
+ delSetting("RefreshToken");
+}
+
+void CDropboxService::HandleJsonError(JSONNode &node)
+{
+ JSONNode error = node.at("error");
+ if (!error.isnull()) {
+ json_string tag = error.at(".tag").as_string();
+ throw Exception(tag.c_str());
+ }
+}
+
+auto CDropboxService::UploadFile(const char *data, size_t size, const std::string &path)
+{
+ ptrA token(getStringA("TokenSecret"));
+ BYTE strategy = g_plugin.getByte("ConflictStrategy", OnConflict::REPLACE);
+ DropboxAPI::UploadFileRequest request(token, path.c_str(), data, size, (OnConflict)strategy);
+ NLHR_PTR response(request.Send(m_hConnection));
+
+ JSONNode root = GetJsonResponse(response);
+ return root["path_lower"].as_string();
+}
+
+auto CDropboxService::CreateUploadSession(const char *chunk, size_t chunkSize)
+{
+ ptrA token(getStringA("TokenSecret"));
+ DropboxAPI::CreateUploadSessionRequest request(token, chunk, chunkSize);
+ NLHR_PTR response(request.Send(m_hConnection));
+
+ JSONNode root = GetJsonResponse(response);
+ return root["session_id"].as_string();
+}
+
+void CDropboxService::UploadFileChunk(const std::string &sessionId, const char *chunk, size_t chunkSize, size_t offset)
+{
+ ptrA token(getStringA("TokenSecret"));
+ DropboxAPI::UploadFileChunkRequest request(token, sessionId.c_str(), offset, chunk, chunkSize);
+ NLHR_PTR response(request.Send(m_hConnection));
+ HandleHttpError(response);
+}
+
+auto CDropboxService::CommitUploadSession(const std::string &sessionId, const char *data, size_t size, size_t offset, const std::string &path)
+{
+ ptrA token(getStringA("TokenSecret"));
+ BYTE strategy = g_plugin.getByte("ConflictStrategy", OnConflict::REPLACE);
+ DropboxAPI::CommitUploadSessionRequest request(token, sessionId.c_str(), offset, path.c_str(), data, size, (OnConflict)strategy);
+ NLHR_PTR response(request.Send(m_hConnection));
+
+ JSONNode root = GetJsonResponse(response);
+ return root["path_lower"].as_string();
+}
+
+void CDropboxService::CreateFolder(const std::string &path)
+{
+ ptrA token(getStringA("TokenSecret"));
+ DropboxAPI::CreateFolderRequest request(token, path.c_str());
+ NLHR_PTR response(request.Send(m_hConnection));
+
+ if (response == nullptr)
+ throw Exception(HttpStatusToError());
+
+ if (HTTP_CODE_SUCCESS(response->resultCode)) {
+ GetJsonResponse(response);
+ return;
+ }
+
+ // forder exists on server
+ if (response->resultCode == HTTP_CODE_CONFLICT) {
+ return;
+ }
+
+ HttpResponseToError(response);
+}
+
+auto CDropboxService::CreateSharedLink(const std::string &path)
+{
+ ptrA token(getStringA("TokenSecret"));
+ DropboxAPI::CreateSharedLinkRequest shareRequest(token, path.c_str());
+ NLHR_PTR response(shareRequest.Send(m_hConnection));
+
+ if (response && HTTP_CODE_SUCCESS(response->resultCode)) {
+ JSONNode root = GetJsonResponse(response);
+ return root["url"].as_string();
+ }
+
+ if (!response || response->resultCode != HTTP_CODE_CONFLICT)
+ HttpResponseToError(response);
+
+ JSONNode root = JSONNode::parse(response->pData);
+ if (root.isnull())
+ throw Exception(HttpStatusToError());
+
+ JSONNode error = root.at("error");
+ if (error.isnull()) {
+ JSONNode link = root.at("url");
+ return link.as_string();
+ }
+
+ json_string tag = error.at(".tag").as_string();
+ if (tag != "shared_link_already_exists")
+ throw Exception(tag.c_str());
+
+ DropboxAPI::GetSharedLinkRequest getRequest(token, path.c_str());
+ response = getRequest.Send(m_hConnection);
+
+ root = GetJsonResponse(response);
+
+ JSONNode links = root.at("links").as_array();
+ JSONNode link = links[(size_t)0].at("url");
+ return link.as_string();
+}
+
+void CDropboxService::Upload(FileTransferParam *ftp)
+{
+ auto serverDictionary = ftp->GetServerDirectory();
+ std::string serverFolder = serverDictionary ? T2Utf(serverDictionary) : "";
+ if (!serverFolder.empty()) {
+ auto path = PreparePath(serverFolder);
+ CreateFolder(path);
+ auto link = CreateSharedLink(path);
+ ftp->AddSharedLink(link.c_str());
+ }
+
+ ftp->FirstFile();
+ do
+ {
+ std::string fileName = T2Utf(ftp->GetCurrentRelativeFilePath());
+ uint64_t fileSize = ftp->GetCurrentFileSize();
+
+ size_t chunkSize = ftp->GetCurrentFileChunkSize();
+ mir_ptr<char> chunk((char*)mir_calloc(chunkSize));
+
+ std::string path;
+ if (!serverFolder.empty())
+ path = "/" + serverFolder + "/" + fileName;
+ else
+ path = PreparePath(fileName);
+
+ if (chunkSize == fileSize) {
+ ftp->CheckCurrentFile();
+ size_t size = ftp->ReadCurrentFile(chunk, chunkSize);
+
+ path = UploadFile(chunk, size, path);
+
+ ftp->Progress(size);
+ }
+ else {
+ ftp->CheckCurrentFile();
+ size_t size = ftp->ReadCurrentFile(chunk, chunkSize);
+
+ auto sessionId = CreateUploadSession(chunk, size);
+
+ ftp->Progress(size);
+
+ size_t offset = size;
+ double chunkCount = ceil(double(fileSize) / chunkSize) - 2;
+ for (size_t i = 0; i < chunkCount; i++) {
+ ftp->CheckCurrentFile();
+
+ size = ftp->ReadCurrentFile(chunk, chunkSize);
+ UploadFileChunk(sessionId, chunk, size, offset);
+
+ offset += size;
+ ftp->Progress(size);
+ }
+
+ ftp->CheckCurrentFile();
+ size = offset < fileSize
+ ? ftp->ReadCurrentFile(chunk, fileSize - offset)
+ : 0;
+
+ path = CommitUploadSession(sessionId, chunk, size, offset, path);
+
+ ftp->Progress(size);
+ }
+
+ if (!ftp->IsCurrentFileInSubDirectory()) {
+ auto link = CreateSharedLink(path);
+ ftp->AddSharedLink(link.c_str());
+ }
+ } while (ftp->NextFile());
+}
diff --git a/protocols/CloudFile/src/Services/dropbox_service.h b/protocols/CloudFile/src/Services/dropbox_service.h
new file mode 100644
index 0000000000..b6c5a7dfcd
--- /dev/null
+++ b/protocols/CloudFile/src/Services/dropbox_service.h
@@ -0,0 +1,36 @@
+#ifndef _CLOUDSERVICE_DROPBOX_H_
+#define _CLOUDSERVICE_DROPBOX_H_
+
+class CDropboxService : public CCloudService
+{
+private:
+ void __cdecl RequestAccessTokenThread(void *);
+ void __cdecl RevokeAccessTokenThread(void *);
+
+ void HandleJsonError(JSONNode &node) override;
+
+ auto UploadFile(const char *data, size_t size, const std::string &path);
+ auto CreateUploadSession(const char *chunk, size_t chunkSize);
+ void UploadFileChunk(const std::string &sessionId, const char *chunk, size_t chunkSize, size_t offset);
+ auto CommitUploadSession(const std::string &sessionId, const char *chunk, size_t chunkSize, size_t offset, const std::string &path);
+ void CreateFolder(const std::string &path);
+ auto CreateSharedLink(const std::string &path);
+
+ void Upload(FileTransferParam *ftp) override;
+
+public:
+ CDropboxService(const char *protoName, const wchar_t *userName);
+
+ static CDropboxService* Init(const char *szModuleName, const wchar_t *szUserName);
+ static int UnInit(CDropboxService*);
+
+ const char* GetModuleName() const override;
+
+ int GetIconId() const override;
+
+ bool IsLoggedIn() override;
+ void Login(HWND owner = nullptr) override;
+ void Logout() override;
+};
+
+#endif //_CLOUDSERVICE_DROPBOX_H_ \ No newline at end of file
diff --git a/protocols/CloudFile/src/Services/google_api.h b/protocols/CloudFile/src/Services/google_api.h
new file mode 100644
index 0000000000..90cfdb4d03
--- /dev/null
+++ b/protocols/CloudFile/src/Services/google_api.h
@@ -0,0 +1,200 @@
+#ifndef _GDRIVESERVICE_API_H_
+#define _GDRIVESERVICE_API_H_
+
+// https://developers.google.com/drive/v3/reference/
+namespace GDriveAPI
+{
+#define GOOGLE_OAUTH "https://accounts.google.com/o/oauth2/v2"
+#define GOOGLE_API "https://www.googleapis.com"
+#define GDRIVE_API_OAUTH GOOGLE_API "/oauth2/v4"
+#define GDRIVE_API_VER "/v3"
+#define GDRIVE_API GOOGLE_API "/drive" GDRIVE_API_VER "/files"
+#define GDRIVE_UPLOAD GOOGLE_API "/upload/drive" GDRIVE_API_VER "/files"
+#define GDRIVE_SHARE "https://drive.google.com/open?id="
+
+#define GOOGLE_APP_ID "528761318515-h1etlccvk5vjsbjuuj8i73cud8do4adi.apps.googleusercontent.com"
+#include "../../../miranda-private-keys/Google/client_secret.h"
+
+#define GOOGLE_AUTH GOOGLE_OAUTH "/auth?response_type=code&scope=https%3A%2F%2Fwww.googleapis.com%2Fauth%2Fdrive.file&access_type=offline&prompt=consent&redirect_uri=https%3A%2F%2Foauth.miranda-ng.org%2Fverification&client_id=" GOOGLE_APP_ID
+
+ class GetAccessTokenRequest : public HttpRequest
+ {
+ public:
+ GetAccessTokenRequest(const char *code) :
+ HttpRequest(REQUEST_POST, GDRIVE_API_OAUTH "/token")
+ {
+ AddHeader("Content-Type", "application/x-www-form-urlencoded");
+
+ CMStringA data = "redirect_uri=https://oauth.miranda-ng.org/verification";
+ data.AppendFormat("&client_id=%s&client_secret=%s", GOOGLE_APP_ID, GOOGLE_CLIENT_SECRET);
+ data.AppendFormat("&grant_type=authorization_code&code=%s", code);
+ SetData(data.GetBuffer(), data.GetLength());
+ }
+ };
+
+ class RefreshTokenRequest : public HttpRequest
+ {
+ public:
+ RefreshTokenRequest(const char *refreshToken) :
+ HttpRequest(REQUEST_POST, GDRIVE_API_OAUTH "/token")
+ {
+ AddHeader("Content-Type", "application/x-www-form-urlencoded");
+
+ CMStringA data(CMStringDataFormat::FORMAT,
+ "client_id=%s&client_secret=%s&grant_type=refresh_token&refresh_token=%s",
+ GOOGLE_APP_ID, GOOGLE_CLIENT_SECRET, refreshToken);
+ SetData(data.GetBuffer(), data.GetLength());
+ }
+ };
+
+ class RevokeAccessTokenRequest : public HttpRequest
+ {
+ public:
+ RevokeAccessTokenRequest(const char *token) :
+ HttpRequest(REQUEST_POST, GOOGLE_OAUTH "/revoke")
+ {
+ AddUrlParameter("token=%s", token);
+ }
+ };
+
+ class UploadFileRequest : public HttpRequest
+ {
+ public:
+ UploadFileRequest(const char *token, const char *parentId, const char *name, const char *data, size_t size) :
+ HttpRequest(REQUEST_POST, GDRIVE_UPLOAD)
+ {
+ AddUrlParameter("fields=id");
+
+ AddBearerAuthHeader(token);
+ AddHeader("Content-Type", "multipart/related; boundary=upload");
+
+ CMStringA body = "--upload";
+ body.AppendChar(0x0A);
+ body.Append("Content-Type: application/json");
+ body.AppendChar(0x0A);
+ body.AppendChar(0x0A);
+ body.Append("{");
+ body.AppendFormat("\"name\": \"%s\"", name);
+ if (mir_strlen(parentId))
+ body.AppendFormat(", \"parents\": [\"%s\"]", parentId);
+ body.Append("}");
+ body.AppendChar(0x0A);
+ body.AppendChar(0x0A);
+ body.Append("--upload");
+ body.AppendChar(0x0A);
+ body.Append("Content-Type: application/octet-stream");
+ body.AppendChar(0x0A);
+ body.Append("Content-Transfer-Encoding: base64");
+ body.AppendChar(0x0A);
+ body.AppendChar(0x0A);
+ body.Append(ptrA(mir_base64_encode(data, size)));
+ body.AppendChar(0x0A);
+ body.Append("--upload--");
+
+ SetData(body.GetBuffer(), body.GetLength());
+ }
+ };
+
+ class CreateUploadSessionRequest : public HttpRequest
+ {
+ public:
+ CreateUploadSessionRequest(const char *token, const char *parentId, const char *name) :
+ HttpRequest(REQUEST_POST, GDRIVE_UPLOAD)
+ {
+ AddUrlParameter("uploadType=resumable");
+
+ AddBearerAuthHeader(token);
+ AddHeader("Content-Type", "application/json");
+
+ JSONNode parents(JSON_ARRAY);
+ parents << JSONNode("", parentId);
+ parents.set_name("parents");
+
+ JSONNode params(JSON_NODE);
+ params << JSONNode("name", name);
+ params << parents;
+
+ json_string data = params.write();
+ SetData(data.c_str(), data.length());
+ }
+ };
+
+ class UploadFileChunkRequest : public HttpRequest
+ {
+ public:
+ UploadFileChunkRequest(const char *uploadUri, const char *chunk, size_t chunkSize, uint64_t offset, uint64_t fileSize):
+ HttpRequest(REQUEST_PUT, uploadUri)
+ {
+ AddUrlParameter("fields=id");
+
+ uint64_t rangeMin = offset;
+ uint64_t rangeMax = offset + chunkSize - 1;
+ CMStringA range(CMStringDataFormat::FORMAT, "bytes %I64u-%I64u/%I64u", rangeMin, rangeMax, fileSize);
+ AddHeader("Content-Range", range);
+
+ SetData(chunk, chunkSize);
+ }
+ };
+
+ class GetFolderRequest : public HttpRequest
+ {
+ public:
+ GetFolderRequest(const char *token, const char *parentId, const char *name) :
+ HttpRequest(REQUEST_GET, GDRIVE_API)
+ {
+ AddUrlParameterWithEncode("q", "mimeType = 'application/vnd.google-apps.folder' and trashed = false and '%s' in parents and name = '%s'", mir_strlen(parentId) ? parentId : "root", name);
+ AddUrlParameterWithEncode("fields", "files(id)");
+
+ AddBearerAuthHeader(token);
+ }
+ };
+
+ class CreateFolderRequest : public HttpRequest
+ {
+ public:
+ CreateFolderRequest(const char *token, const char *parentId, const char *name) :
+ HttpRequest(REQUEST_POST, GDRIVE_API)
+ {
+ AddUrlParameter("fields=id");
+
+ AddBearerAuthHeader(token);
+ AddHeader("Content-Type", "application/json");
+
+ JSONNode parents(JSON_ARRAY);
+ parents.set_name("parents");
+ parents.push_back(JSONNode("", parentId));
+
+ JSONNode params(JSON_NODE);
+ params
+ << JSONNode("name", name)
+ << JSONNode("mimeType", "application/vnd.google-apps.folder")
+ << parents;
+
+ json_string data = params.write();
+ SetData(data.c_str(), data.length());
+ }
+ };
+
+ class GrantPermissionsRequest : public HttpRequest
+ {
+ public:
+ GrantPermissionsRequest(const char *token, const char *fileId) :
+ HttpRequest(REQUEST_POST, FORMAT, GDRIVE_API "/%s/permissions", fileId)
+ {
+ AddUrlParameter("fields=id");
+
+ AddBearerAuthHeader(token);
+ AddHeader("Content-Type", "application/json");
+
+ JSONNode params(JSON_NODE);
+ params
+ << JSONNode("role", "reader")
+ << JSONNode("type", "anyone");
+
+ json_string data = params.write();
+ SetData(data.c_str(), data.length());
+ }
+ };
+};
+
+#endif //_GDRIVESERVICE_API_H_
diff --git a/protocols/CloudFile/src/Services/google_service.cpp b/protocols/CloudFile/src/Services/google_service.cpp
new file mode 100644
index 0000000000..536d2ff65e
--- /dev/null
+++ b/protocols/CloudFile/src/Services/google_service.cpp
@@ -0,0 +1,297 @@
+#include "..\stdafx.h"
+#include "google_api.h"
+
+
+struct CMPluginGoogle : public CMPluginBase
+{
+ CMPluginGoogle() :
+ CMPluginBase(MODULENAME "/GDrive", pluginInfoEx)
+ {
+ m_hInst = g_plugin.getInst();
+
+ RegisterProtocol(PROTOTYPE_PROTOWITHACCS, (pfnInitProto)CGDriveService::Init, (pfnUninitProto)CGDriveService::UnInit);
+ }
+}
+g_pluginGoogle;
+
+/////////////////////////////////////////////////////////////////////////////////////////
+
+CGDriveService::CGDriveService(const char *protoName, const wchar_t *userName) :
+ CCloudService(protoName, userName, &g_pluginGoogle)
+{
+ m_hProtoIcon = GetIconHandle(IDI_GDRIVE);
+}
+
+CGDriveService* CGDriveService::Init(const char *moduleName, const wchar_t *userName)
+{
+ CGDriveService *proto = new CGDriveService(moduleName, userName);
+ Services.insert(proto);
+ return proto;
+}
+
+int CGDriveService::UnInit(CGDriveService *proto)
+{
+ Services.remove(proto);
+ delete proto;
+ return 0;
+}
+
+const char* CGDriveService::GetModuleName() const
+{
+ return "/Google";
+}
+
+int CGDriveService::GetIconId() const
+{
+ return IDI_GDRIVE;
+}
+
+bool CGDriveService::IsLoggedIn()
+{
+ ptrA token(getStringA("TokenSecret"));
+ if (!token || token[0] == 0)
+ return false;
+ time_t now = time(0);
+ time_t expiresIn = getDword("ExpiresIn");
+ return now < expiresIn;
+}
+
+void CGDriveService::Login(HWND owner)
+{
+ ptrA token(getStringA("TokenSecret"));
+ ptrA refreshToken(getStringA("RefreshToken"));
+ if (token && refreshToken && refreshToken[0]) {
+ GDriveAPI::RefreshTokenRequest request(refreshToken);
+ NLHR_PTR response(request.Send(m_hConnection));
+
+ JSONNode root = GetJsonResponse(response);
+
+ JSONNode node = root.at("access_token");
+ setString("TokenSecret", node.as_string().c_str());
+
+ node = root.at("expires_in");
+ time_t expiresIn = time(0) + node.as_int();
+ setDword("ExpiresIn", expiresIn);
+
+ return;
+ }
+
+ COAuthDlg dlg(this, GOOGLE_AUTH, (MyThreadFunc)&CGDriveService::RequestAccessTokenThread);
+ dlg.SetParent(owner);
+ dlg.DoModal();
+}
+
+void CGDriveService::Logout()
+{
+ ForkThread((MyThreadFunc)&CGDriveService::RevokeAccessTokenThread);
+}
+
+void CGDriveService::RequestAccessTokenThread(void *param)
+{
+ HWND hwndDlg = (HWND)param;
+
+ if (IsLoggedIn())
+ Logout();
+
+ char requestToken[128];
+ GetDlgItemTextA(hwndDlg, IDC_OAUTH_CODE, requestToken, _countof(requestToken));
+
+ GDriveAPI::GetAccessTokenRequest request(requestToken);
+ NLHR_PTR response(request.Send(m_hConnection));
+
+ if (response == nullptr || response->resultCode != HTTP_CODE_OK) {
+ const char *error = response && response->dataLength
+ ? response->pData
+ : HttpStatusToError(response ? response->resultCode : 0);
+
+ Netlib_Logf(m_hConnection, "%s: %s", GetAccountName(), error);
+ ShowNotification(TranslateT("Server does not respond"), MB_ICONERROR);
+ EndDialog(hwndDlg, 0);
+ return;
+ }
+
+ JSONNode root = JSONNode::parse(response->pData);
+ if (root.empty()) {
+ Netlib_Logf(m_hConnection, "%s: %s", GetAccountName(), HttpStatusToError(response->resultCode));
+ ShowNotification(TranslateT("Server does not respond"), MB_ICONERROR);
+ EndDialog(hwndDlg, 0);
+ return;
+ }
+
+ JSONNode node = root.at("error_description");
+ if (!node.isnull()) {
+ CMStringW error_description = node.as_mstring();
+ Netlib_Logf(m_hConnection, "%s: %s", GetAccountName(), HttpStatusToError(response->resultCode));
+ ShowNotification(error_description, MB_ICONERROR);
+ EndDialog(hwndDlg, 0);
+ return;
+ }
+
+ node = root.at("access_token");
+ db_set_s(0, GetAccountName(), "TokenSecret", node.as_string().c_str());
+
+ node = root.at("expires_in");
+ time_t expiresIn = time(0) + node.as_int();
+ db_set_dw(0, GetAccountName(), "ExpiresIn", expiresIn);
+
+ node = root.at("refresh_token");
+ db_set_s(0, GetAccountName(), "RefreshToken", node.as_string().c_str());
+
+ SetDlgItemTextA(hwndDlg, IDC_OAUTH_CODE, "");
+
+ EndDialog(hwndDlg, 1);
+}
+
+void CGDriveService::RevokeAccessTokenThread(void*)
+{
+ ptrA token(db_get_sa(0, GetAccountName(), "TokenSecret"));
+ GDriveAPI::RevokeAccessTokenRequest request(token);
+ NLHR_PTR response(request.Send(m_hConnection));
+
+ delSetting("ExpiresIn");
+ delSetting("TokenSecret");
+ delSetting("RefreshToken");
+}
+
+void CGDriveService::HandleJsonError(JSONNode &node)
+{
+ JSONNode error = node.at("error");
+ if (!error.isnull()) {
+ json_string tag = error.at(".tag").as_string();
+ throw Exception(tag.c_str());
+ }
+}
+
+auto CGDriveService::UploadFile(const std::string &parentId, const std::string &fileName, const char *data, size_t size)
+{
+ ptrA token(getStringA("TokenSecret"));
+ GDriveAPI::UploadFileRequest request(token, parentId.c_str(), fileName.c_str(), data, size);
+ NLHR_PTR response(request.Send(m_hConnection));
+ JSONNode root = GetJsonResponse(response);
+ return root["id"].as_string();
+}
+
+auto CGDriveService::CreateUploadSession(const std::string &parentId, const std::string &fileName)
+{
+ ptrA token(getStringA("TokenSecret"));
+ GDriveAPI::CreateUploadSessionRequest request(token, parentId.c_str(), fileName.c_str());
+ NLHR_PTR response(request.Send(m_hConnection));
+
+ HandleHttpError(response);
+
+ if (HTTP_CODE_SUCCESS(response->resultCode)) {
+ for (int i = 0; i < response->headersCount; i++) {
+ if (mir_strcmpi(response->headers[i].szName, "Location"))
+ continue;
+ return std::string(response->headers[i].szValue);
+ }
+ }
+
+ HttpResponseToError(response);
+
+ return std::string();
+}
+
+auto CGDriveService::UploadFileChunk(const std::string &uploadUri, const char *chunk, size_t chunkSize, uint64_t offset, uint64_t fileSize)
+{
+ GDriveAPI::UploadFileChunkRequest request(uploadUri.c_str(), chunk, chunkSize, offset, fileSize);
+ NLHR_PTR response(request.Send(m_hConnection));
+
+ if (response->resultCode == HTTP_CODE_PERMANENT_REDIRECT)
+ return std::string();
+
+ HandleHttpError(response);
+
+ if (HTTP_CODE_SUCCESS(response->resultCode)) {
+ JSONNode root = GetJsonResponse(response);
+ return root["id"].as_string();
+ }
+
+ HttpResponseToError(response);
+
+ return std::string();
+}
+
+auto CGDriveService::CreateFolder(const std::string &parentId, const std::string &name)
+{
+ ptrA token(getStringA("TokenSecret"));
+ GDriveAPI::GetFolderRequest getFolderRequest(token, parentId.c_str(), name.c_str());
+ NLHR_PTR response(getFolderRequest.Send(m_hConnection));
+
+ JSONNode root = GetJsonResponse(response);
+ JSONNode files = root["files"].as_array();
+ if (files.size() > 0)
+ return files[(size_t)0]["id"].as_string();
+
+ GDriveAPI::CreateFolderRequest createFolderRequest(token, parentId.c_str(), name.c_str());
+ response = createFolderRequest.Send(m_hConnection);
+
+ root = GetJsonResponse(response);
+ return root["id"].as_string();
+}
+
+auto CGDriveService::CreateSharedLink(const std::string &itemId)
+{
+ ptrA token(getStringA("TokenSecret"));
+ GDriveAPI::GrantPermissionsRequest request(token, itemId.c_str());
+ NLHR_PTR response(request.Send(m_hConnection));
+
+ HandleHttpError(response);
+
+ if (HTTP_CODE_SUCCESS(response->resultCode)) {
+ std::string url = GDRIVE_SHARE;
+ url += itemId;
+ return url;
+ }
+
+ HttpResponseToError(response);
+
+ return std::string();
+}
+
+void CGDriveService::Upload(FileTransferParam *ftp)
+{
+ std::string folderId = "root";
+ auto serverDictionary = ftp->GetServerDirectory();
+ std::string serverFolder = serverDictionary ? T2Utf(serverDictionary) : "";
+ if (!serverFolder.empty()) {
+ folderId = CreateFolder(folderId, serverFolder);
+ auto link = CreateSharedLink(folderId);
+ ftp->AddSharedLink(link.c_str());
+ }
+
+ ftp->FirstFile();
+ do {
+ std::string fileName = T2Utf(ftp->GetCurrentRelativeFilePath());
+ uint64_t fileSize = ftp->GetCurrentFileSize();
+
+ size_t chunkSize = ftp->GetCurrentFileChunkSize();
+ mir_ptr<char> chunk((char*)mir_calloc(chunkSize));
+
+ std::string fileId;
+ if (chunkSize == fileSize) {
+ ftp->CheckCurrentFile();
+ size_t size = ftp->ReadCurrentFile(chunk, chunkSize);
+ fileId = UploadFile(folderId, fileName, chunk, size);
+ ftp->Progress(size);
+ }
+ else {
+ auto uploadUri = CreateUploadSession(folderId, fileName);
+
+ uint64_t offset = 0;
+ double chunkCount = ceil(double(fileSize) / chunkSize);
+ for (size_t i = 0; i < chunkCount; i++) {
+ ftp->CheckCurrentFile();
+ size_t size = ftp->ReadCurrentFile(chunk, chunkSize);
+ fileId = UploadFileChunk(uploadUri, chunk, size, offset, fileSize);
+ offset += size;
+ ftp->Progress(size);
+ }
+ }
+
+ if (!ftp->IsCurrentFileInSubDirectory()) {
+ auto link = CreateSharedLink(fileId);
+ ftp->AddSharedLink(link.c_str());
+ }
+ } while (ftp->NextFile());
+}
diff --git a/protocols/CloudFile/src/Services/google_service.h b/protocols/CloudFile/src/Services/google_service.h
new file mode 100644
index 0000000000..919babb86f
--- /dev/null
+++ b/protocols/CloudFile/src/Services/google_service.h
@@ -0,0 +1,35 @@
+#ifndef _CLOUDFILE_GDRIVE_H_
+#define _CLOUDFILE_GDRIVE_H_
+
+class CGDriveService : public CCloudService
+{
+private:
+ void __cdecl RequestAccessTokenThread(void *param);
+ void __cdecl RevokeAccessTokenThread(void *param);
+
+ void HandleJsonError(JSONNode &node) override;
+
+ auto UploadFile(const std::string &parentId, const std::string &fileName, const char *data, size_t size);
+ auto CreateUploadSession(const std::string &parentId, const std::string &fileName);
+ auto UploadFileChunk(const std::string &uploadUri, const char *chunk, size_t chunkSize, uint64_t offset, uint64_t fileSize);
+ auto CreateFolder(const std::string &parentId, const std::string &name);
+ auto CreateSharedLink(const std::string &itemId);
+
+ void Upload(FileTransferParam *ftp) override;
+
+public:
+ CGDriveService(const char *protoName, const wchar_t *userName);
+
+ static CGDriveService* Init(const char *szModuleName, const wchar_t *szUserName);
+ static int UnInit(CGDriveService*);
+
+ const char* GetModuleName() const override;
+
+ int GetIconId() const override;
+
+ bool IsLoggedIn() override;
+ void Login(HWND owner = nullptr) override;
+ void Logout() override;
+};
+
+#endif //_CLOUDFILE_GDRIVE_H_ \ No newline at end of file
diff --git a/protocols/CloudFile/src/Services/microsoft_api.h b/protocols/CloudFile/src/Services/microsoft_api.h
new file mode 100644
index 0000000000..6c22ac512f
--- /dev/null
+++ b/protocols/CloudFile/src/Services/microsoft_api.h
@@ -0,0 +1,188 @@
+#ifndef _ONEDRIVESERVICE_API_H_
+#define _ONEDRIVESERVICE_API_H_
+
+// https://docs.microsoft.com/onedrive/developer/rest-api/
+namespace OneDriveAPI
+{
+#define MICROSOFT_OAUTH "https://login.microsoftonline.com/common/oauth2/v2.0"
+#define ONEDRIVE_API "https://graph.microsoft.com/v1.0/drive"
+
+#define MS_APP_ID "72b87ac7-42eb-4a97-a620-91a7f8d8b5ae"
+#include "../../../miranda-private-keys/Microsoft/client_secret.h"
+
+#define MICROSOFT_AUTH MICROSOFT_OAUTH "/authorize?response_type=code&scope=offline_access%20https%3A%2F%2Fgraph.microsoft.com%2Ffiles.readWrite&redirect_uri=https%3A%2F%2Foauth.miranda-ng.org%2Fverification&client_id=" MS_APP_ID
+
+ class GetAccessTokenRequest : public HttpRequest
+ {
+ public:
+ GetAccessTokenRequest(const char *code) :
+ HttpRequest(REQUEST_POST, MICROSOFT_OAUTH "/token")
+ {
+ AddHeader("Content-Type", "application/x-www-form-urlencoded");
+
+ CMStringA data = "redirect_uri=https://oauth.miranda-ng.org/verification";
+ data.Append("&scope=offline_access https://graph.microsoft.com/files.readWrite");
+ data.AppendFormat("&client_id=%s&client_secret=%s", MS_APP_ID, MS_CLIENT_SECRET);
+ data.AppendFormat("&grant_type=authorization_code&code=%s", code);
+ SetData(data.GetBuffer(), data.GetLength());
+ }
+ };
+
+ class RefreshTokenRequest : public HttpRequest
+ {
+ public:
+ RefreshTokenRequest(const char *refreshToken) :
+ HttpRequest(REQUEST_POST, MICROSOFT_OAUTH "/token")
+ {
+ AddHeader("Content-Type", "application/x-www-form-urlencoded");
+
+ CMStringA data = "redirect_uri=https://oauth.miranda-ng.org/verification";
+ data.Append("&scope=offline_access https://graph.microsoft.com/files.readWrite");
+ data.AppendFormat("&client_id=%s&client_secret=%s", MS_APP_ID, MS_CLIENT_SECRET);
+ data.AppendFormat("&grant_type=refresh_token&refresh_token=%s", refreshToken);
+ SetData(data.GetBuffer(), data.GetLength());
+ }
+ };
+
+ class UploadFileRequest : public HttpRequest
+ {
+ public:
+ UploadFileRequest(const char *token, const char *name, const char *data, size_t size, OnConflict strategy = NONE) :
+ HttpRequest(REQUEST_PUT, FORMAT, ONEDRIVE_API "/special/approot:/%s:/content", mir_urlEncode(name).c_str())
+ {
+ AddUrlParameter("select=id");
+
+ if (strategy == OnConflict::RENAME)
+ AddUrlParameter("@microsoft.graph.conflictBehavior=rename");
+ else if (strategy == OnConflict::REPLACE)
+ AddUrlParameter("@microsoft.graph.conflictBehavior=replace");
+
+ AddBearerAuthHeader(token);
+
+ SetData(data, size);
+ }
+
+ UploadFileRequest(const char *token, const char *parentId, const char *name, const char *data, size_t size, OnConflict strategy = NONE) :
+ HttpRequest(REQUEST_PUT, FORMAT, ONEDRIVE_API "/items/%s:/%s:/content", parentId, mir_urlEncode(name).c_str())
+ {
+ AddUrlParameter("select=id");
+
+ if (strategy == OnConflict::RENAME)
+ AddUrlParameter("@microsoft.graph.conflictBehavior=rename");
+ else if (strategy == OnConflict::REPLACE)
+ AddUrlParameter("@microsoft.graph.conflictBehavior=replace");
+
+ AddBearerAuthHeader(token);
+
+ SetData(data, size);
+ }
+ };
+
+ class CreateUploadSessionRequest : public HttpRequest
+ {
+ public:
+ CreateUploadSessionRequest(const char *token, const char *name, OnConflict strategy = NONE) :
+ HttpRequest(REQUEST_POST, FORMAT, ONEDRIVE_API "/special/approot:/%s:/createUploadSession", mir_urlEncode(name).c_str())
+ {
+ AddBearerAuthHeader(token);
+ AddHeader("Content-Type", "application/json");
+
+ JSONNode item(JSON_NODE);
+ item.set_name("item");
+ if (strategy == OnConflict::RENAME)
+ item << JSONNode("@microsoft.graph.conflictBehavior", "rename");
+ if (strategy == OnConflict::REPLACE)
+ item << JSONNode("@microsoft.graph.conflictBehavior", "replace");
+
+ JSONNode params(JSON_NODE);
+ params << item;
+
+ json_string data = params.write();
+ SetData(data.c_str(), data.length());
+ }
+
+ CreateUploadSessionRequest(const char *token, const char *parentId, const char *name, OnConflict strategy = NONE) :
+ HttpRequest(REQUEST_POST, FORMAT, ONEDRIVE_API "/items/%s:/%s:/createUploadSession", parentId, mir_urlEncode(name).c_str())
+ {
+ AddBearerAuthHeader(token);
+ AddHeader("Content-Type", "application/json");
+
+ JSONNode item(JSON_NODE);
+ item.set_name("item");
+ if (strategy == OnConflict::RENAME)
+ item << JSONNode("@microsoft.graph.conflictBehavior", "rename");
+ if (strategy == OnConflict::REPLACE)
+ item << JSONNode("@microsoft.graph.conflictBehavior", "replace");
+
+ JSONNode params(JSON_NODE);
+ params << item;
+
+ json_string data = params.write();
+ SetData(data.c_str(), data.length());
+ }
+ };
+
+ class UploadFileChunkRequest : public HttpRequest
+ {
+ public:
+ UploadFileChunkRequest(const char *uploadUri, const char *chunk, size_t chunkSize, uint64_t offset, uint64_t fileSize) :
+ HttpRequest(REQUEST_PUT, uploadUri)
+ {
+ AddUrlParameter("select=id");
+
+ uint64_t rangeMin = offset;
+ uint64_t rangeMax = offset + chunkSize - 1;
+ CMStringA range(CMStringDataFormat::FORMAT, "bytes %I64u-%I64u/%I64u", rangeMin, rangeMax, fileSize);
+ AddHeader("Content-Range", range);
+
+ SetData(chunk, chunkSize);
+ }
+ };
+
+ class CreateFolderRequest : public HttpRequest
+ {
+ public:
+ CreateFolderRequest(const char *token, const char *path) :
+ HttpRequest(REQUEST_POST, ONEDRIVE_API "/special/approot/children")
+ {
+ AddUrlParameter("select=id");
+
+ AddBearerAuthHeader(token);
+ AddHeader("Content-Type", "application/json");
+
+ JSONNode folder(JSON_NODE);
+ folder.set_name("folder");
+
+ JSONNode params(JSON_NODE);
+ params
+ << JSONNode("name", path)
+ << folder;
+
+ json_string data = params.write();
+ SetData(data.c_str(), data.length());
+ }
+ };
+
+ class CreateSharedLinkRequest : public HttpRequest
+ {
+ public:
+ CreateSharedLinkRequest(const char *token, const char *itemId) :
+ HttpRequest(REQUEST_POST, FORMAT, ONEDRIVE_API "/items/%s/createLink", itemId)
+ {
+ AddUrlParameter("select=link");
+
+ AddBearerAuthHeader(token);
+ AddHeader("Content-Type", "application/json");
+
+ JSONNode params(JSON_NODE);
+ params
+ << JSONNode("type", "view")
+ << JSONNode("scope", "anonymous");
+
+ json_string data = params.write();
+ SetData(data.c_str(), data.length());
+ }
+ };
+};
+
+#endif //_ONEDRIVESERVICE_API_H_
diff --git a/protocols/CloudFile/src/Services/microsoft_service.cpp b/protocols/CloudFile/src/Services/microsoft_service.cpp
new file mode 100644
index 0000000000..992312e2a8
--- /dev/null
+++ b/protocols/CloudFile/src/Services/microsoft_service.cpp
@@ -0,0 +1,269 @@
+#include "..\stdafx.h"
+#include "microsoft_api.h"
+
+struct CMPluginOnedrive : public CMPluginBase
+{
+ CMPluginOnedrive() :
+ CMPluginBase(MODULENAME "/OneDrive", pluginInfoEx)
+ {
+ m_hInst = g_plugin.getInst();
+
+ RegisterProtocol(PROTOTYPE_PROTOWITHACCS, (pfnInitProto)COneDriveService::Init, (pfnUninitProto)COneDriveService::UnInit);
+ }
+}
+g_pluginOnedrive;
+
+/////////////////////////////////////////////////////////////////////////////////////////
+
+COneDriveService::COneDriveService(const char *protoName, const wchar_t *userName) :
+ CCloudService(protoName, userName, &g_pluginOnedrive)
+{
+ m_hProtoIcon = GetIconHandle(IDI_ONEDRIVE);
+}
+
+COneDriveService* COneDriveService::Init(const char *moduleName, const wchar_t *userName)
+{
+ COneDriveService *proto = new COneDriveService(moduleName, userName);
+ Services.insert(proto);
+ return proto;
+}
+
+int COneDriveService::UnInit(COneDriveService *proto)
+{
+ Services.remove(proto);
+ delete proto;
+ return 0;
+}
+
+const char* COneDriveService::GetModuleName() const
+{
+ return "/OneDrive";
+}
+
+int COneDriveService::GetIconId() const
+{
+ return IDI_ONEDRIVE;
+}
+
+bool COneDriveService::IsLoggedIn()
+{
+ ptrA token(getStringA("TokenSecret"));
+ if (!token || token[0] == 0)
+ return false;
+ time_t now = time(0);
+ time_t expiresIn = getDword("ExpiresIn");
+ return now < expiresIn;
+}
+
+void COneDriveService::Login(HWND owner)
+{
+ ptrA refreshToken(getStringA("RefreshToken"));
+ if (refreshToken && refreshToken[0]) {
+ OneDriveAPI::RefreshTokenRequest request(refreshToken);
+ NLHR_PTR response(request.Send(m_hConnection));
+
+ JSONNode root = GetJsonResponse(response);
+
+ JSONNode node = root.at("access_token");
+ db_set_s(0, GetAccountName(), "TokenSecret", node.as_string().c_str());
+
+ node = root.at("expires_in");
+ time_t expiresIn = time(0) + node.as_int();
+ setDword("ExpiresIn", expiresIn);
+
+ return;
+ }
+
+ COAuthDlg dlg(this, MICROSOFT_AUTH, (MyThreadFunc)&COneDriveService::RequestAccessTokenThread);
+ dlg.SetParent(owner);
+ dlg.DoModal();
+}
+
+void COneDriveService::Logout()
+{
+ delSetting("ExpiresIn");
+ delSetting("TokenSecret");
+ delSetting("RefreshToken");
+}
+
+void COneDriveService::RequestAccessTokenThread(void *param)
+{
+ HWND hwndDlg = (HWND)param;
+
+ if (IsLoggedIn())
+ Logout();
+
+ char requestToken[128];
+ GetDlgItemTextA(hwndDlg, IDC_OAUTH_CODE, requestToken, _countof(requestToken));
+
+ OneDriveAPI::GetAccessTokenRequest request(requestToken);
+ NLHR_PTR response(request.Send(m_hConnection));
+
+ if (response == nullptr || response->resultCode != HTTP_CODE_OK) {
+ const char *error = response->dataLength
+ ? response->pData
+ : HttpStatusToError(response->resultCode);
+
+ Netlib_Logf(m_hConnection, "%s: %s", GetAccountName(), error);
+ ShowNotification(TranslateT("Server does not respond"), MB_ICONERROR);
+ EndDialog(hwndDlg, 0);
+ return;
+ }
+
+ JSONNode root = JSONNode::parse(response->pData);
+ if (root.empty()) {
+ Netlib_Logf(m_hConnection, "%s: %s", GetAccountName(), HttpStatusToError(response->resultCode));
+ ShowNotification(TranslateT("Server does not respond"), MB_ICONERROR);
+ EndDialog(hwndDlg, 0);
+ return;
+ }
+
+ JSONNode node = root.at("error_description");
+ if (!node.isnull()) {
+ CMStringW error_description = node.as_mstring();
+ Netlib_Logf(m_hConnection, "%s: %s", GetAccountName(), HttpStatusToError(response->resultCode));
+ ShowNotification(error_description, MB_ICONERROR);
+ EndDialog(hwndDlg, 0);
+ return;
+ }
+
+ node = root.at("access_token");
+ setString("TokenSecret", node.as_string().c_str());
+
+ node = root.at("expires_in");
+ time_t expiresIn = time(0) + node.as_int();
+ setDword("ExpiresIn", expiresIn);
+
+ node = root.at("refresh_token");
+ setString("RefreshToken", node.as_string().c_str());
+
+ SetDlgItemTextA(hwndDlg, IDC_OAUTH_CODE, "");
+
+ EndDialog(hwndDlg, 1);
+}
+
+void COneDriveService::HandleJsonError(JSONNode &node)
+{
+ JSONNode error = node.at("error");
+ if (!error.isnull()) {
+ json_string tag = error.at("message").as_string();
+ throw Exception(tag.c_str());
+ }
+}
+
+auto COneDriveService::UploadFile(const std::string &parentId, const std::string &fileName, const char *data, size_t size)
+{
+ ptrA token(getStringA("TokenSecret"));
+ BYTE strategy = g_plugin.getByte("ConflictStrategy", OnConflict::REPLACE);
+ OneDriveAPI::UploadFileRequest *request = !parentId.empty()
+ ? new OneDriveAPI::UploadFileRequest(token, parentId.c_str(), fileName.c_str(), data, size, (OnConflict)strategy)
+ : new OneDriveAPI::UploadFileRequest(token, fileName.c_str(), data, size, (OnConflict)strategy);
+ NLHR_PTR response(request->Send(m_hConnection));
+ delete request;
+
+ JSONNode root = GetJsonResponse(response);
+ return root["id"].as_string();
+}
+
+auto COneDriveService::CreateUploadSession(const std::string &parentId, const std::string &fileName)
+{
+ ptrA token(getStringA("TokenSecret"));
+ BYTE strategy = g_plugin.getByte("ConflictStrategy", OnConflict::REPLACE);
+ OneDriveAPI::CreateUploadSessionRequest *request = !parentId.empty()
+ ? new OneDriveAPI::CreateUploadSessionRequest(token, parentId.c_str(), fileName.c_str(), (OnConflict)strategy)
+ : new OneDriveAPI::CreateUploadSessionRequest(token, fileName.c_str(), (OnConflict)strategy);
+ NLHR_PTR response(request->Send(m_hConnection));
+ delete request;
+
+ JSONNode root = GetJsonResponse(response);
+ return root["uploadUrl"].as_string();
+}
+
+auto COneDriveService::UploadFileChunk(const std::string &uploadUri, const char *chunk, size_t chunkSize, uint64_t offset, uint64_t fileSize)
+{
+ OneDriveAPI::UploadFileChunkRequest request(uploadUri.c_str(), chunk, chunkSize, offset, fileSize);
+ NLHR_PTR response(request.Send(m_hConnection));
+
+ HandleHttpError(response);
+
+ if (response->resultCode == HTTP_CODE_ACCEPTED)
+ return std::string();
+
+ if (HTTP_CODE_SUCCESS(response->resultCode)) {
+ JSONNode root = GetJsonResponse(response);
+ return root["id"].as_string();
+ }
+
+ HttpResponseToError(response);
+
+ return std::string();
+}
+
+auto COneDriveService::CreateFolder(const std::string &path)
+{
+ ptrA token(getStringA("TokenSecret"));
+ OneDriveAPI::CreateFolderRequest request(token, path.c_str());
+ NLHR_PTR response(request.Send(m_hConnection));
+
+ JSONNode root = GetJsonResponse(response);
+ return root["id"].as_string();
+}
+
+auto COneDriveService::CreateSharedLink(const std::string &itemId)
+{
+ ptrA token(getStringA("TokenSecret"));
+ OneDriveAPI::CreateSharedLinkRequest request(token, itemId.c_str());
+ NLHR_PTR response(request.Send(m_hConnection));
+
+ JSONNode root = GetJsonResponse(response);
+ return root["link"]["webUrl"].as_string();
+}
+
+void COneDriveService::Upload(FileTransferParam *ftp)
+{
+ std::string folderId;
+ auto serverDictionary = ftp->GetServerDirectory();
+ std::string serverFolder = serverDictionary ? T2Utf(serverDictionary) : "";
+ if (!serverFolder.empty()) {
+ folderId = CreateFolder(serverFolder);
+ auto link = CreateSharedLink(folderId);
+ ftp->AddSharedLink(link.c_str());
+ }
+
+ ftp->FirstFile();
+ do {
+ std::string fileName = T2Utf(ftp->GetCurrentRelativeFilePath());
+ uint64_t fileSize = ftp->GetCurrentFileSize();
+
+ size_t chunkSize = ftp->GetCurrentFileChunkSize();
+ mir_ptr<char> chunk((char*)mir_calloc(chunkSize));
+
+ std::string fileId;
+ if (chunkSize == fileSize) {
+ ftp->CheckCurrentFile();
+ size_t size = ftp->ReadCurrentFile(chunk, chunkSize);
+
+ fileId = UploadFile(folderId, fileName, chunk, size);
+
+ ftp->Progress(size);
+ }
+ else {
+ auto uploadUri = CreateUploadSession(folderId, fileName);
+
+ uint64_t offset = 0;
+ double chunkCount = ceil(double(fileSize) / chunkSize);
+ for (size_t i = 0; i < chunkCount; i++) {
+ ftp->CheckCurrentFile();
+ size_t size = ftp->ReadCurrentFile(chunk, chunkSize);
+ fileId = UploadFileChunk(uploadUri, chunk, size, offset, fileSize);
+ offset += size;
+ ftp->Progress(size);
+ }
+ }
+
+ if (!ftp->IsCurrentFileInSubDirectory()) {
+ auto link = CreateSharedLink(fileId);
+ ftp->AddSharedLink(link.c_str());
+ }
+ } while (ftp->NextFile());
+}
diff --git a/protocols/CloudFile/src/Services/microsoft_service.h b/protocols/CloudFile/src/Services/microsoft_service.h
new file mode 100644
index 0000000000..d993410003
--- /dev/null
+++ b/protocols/CloudFile/src/Services/microsoft_service.h
@@ -0,0 +1,34 @@
+#ifndef _CLOUDFILE_ONEDRIVE_H_
+#define _CLOUDFILE_ONEDRIVE_H_
+
+class COneDriveService : public CCloudService
+{
+private:
+ void __cdecl RequestAccessTokenThread(void *param);
+
+ void HandleJsonError(JSONNode &node) override;
+
+ auto UploadFile(const std::string &parentId, const std::string &fileName, const char *data, size_t size);
+ auto CreateUploadSession(const std::string &parentId, const std::string &fileName);
+ auto UploadFileChunk(const std::string &uploadUri, const char *chunk, size_t chunkSize, uint64_t offset, uint64_t fileSize);
+ auto CreateFolder(const std::string &name);
+ auto CreateSharedLink(const std::string &itemId);
+
+ void Upload(FileTransferParam *ftp) override;
+
+public:
+ COneDriveService(const char *protoName, const wchar_t *userName);
+
+ static COneDriveService* Init(const char *szModuleName, const wchar_t *szUserName);
+ static int UnInit(COneDriveService*);
+
+ const char* GetModuleName() const override;
+
+ int GetIconId() const override;
+
+ bool IsLoggedIn() override;
+ void Login(HWND owner = nullptr) override;
+ void Logout() override;
+};
+
+#endif //_CLOUDFILE_ONEDRIVE_H_ \ No newline at end of file
diff --git a/protocols/CloudFile/src/Services/yandex_api.h b/protocols/CloudFile/src/Services/yandex_api.h
new file mode 100644
index 0000000000..c7c3dfe19d
--- /dev/null
+++ b/protocols/CloudFile/src/Services/yandex_api.h
@@ -0,0 +1,131 @@
+#ifndef _YANDEXSERVICE_API_H_
+#define _YANDEXSERVICE_API_H_
+
+// https://tech.yandex.ru/disk/api/concepts/about-docpage/
+namespace YandexAPI
+{
+#define YANDEX_OAUTH "https://oauth.yandex.ru"
+#define YADISK_API_VER "/v1"
+#define YADISK_API "https://cloud-api.yandex.net" YADISK_API_VER "/disk/resources"
+
+#define YANDEX_APP_ID "c311a5967cae4efa88d1af97d01ea0e8"
+#include "../../../miranda-private-keys/Yandex/client_secret.h"
+
+#define YANDEX_AUTH YANDEX_OAUTH "/authorize?response_type=code&client_id=" YANDEX_APP_ID
+
+ class GetAccessTokenRequest : public HttpRequest
+ {
+ public:
+ GetAccessTokenRequest(const char *code) :
+ HttpRequest(REQUEST_POST, YANDEX_OAUTH "/token")
+ {
+ AddHeader("Content-Type", "application/x-www-form-urlencoded");
+
+ CMStringA data(CMStringDataFormat::FORMAT,
+ "client_id=%s&client_secret=%s&grant_type=authorization_code&code=%s",
+ YANDEX_APP_ID, YADISK_CLIENT_SECRET, code);
+ SetData(data.GetBuffer(), data.GetLength());
+ }
+ };
+
+ class RefreshTokenRequest : public HttpRequest
+ {
+ public:
+ RefreshTokenRequest(const char *refreshToken) :
+ HttpRequest(REQUEST_POST, YANDEX_OAUTH "/token")
+ {
+ AddHeader("Content-Type", "application/x-www-form-urlencoded");
+
+ CMStringA data(CMStringDataFormat::FORMAT,
+ "client_id=%s&client_secret=%s&grant_type=refresh_token&refresh_token=%s",
+ YANDEX_APP_ID, YADISK_CLIENT_SECRET, refreshToken);
+ SetData(data.GetBuffer(), data.GetLength());
+ }
+ };
+
+ class RevokeAccessTokenRequest : public HttpRequest
+ {
+ public:
+ RevokeAccessTokenRequest(const char *token) :
+ HttpRequest(REQUEST_POST, YANDEX_OAUTH "/token/revoke")
+ {
+ AddOAuthHeader(token);
+ }
+ };
+
+ class GetUploadUrlRequest : public HttpRequest
+ {
+ public:
+ GetUploadUrlRequest(const char *token, const char *path, OnConflict strategy = NONE) :
+ HttpRequest(REQUEST_GET, YADISK_API "/upload")
+ {
+ AddOAuthHeader(token);
+ AddUrlParameter("path=app:%s", mir_urlEncode(path).c_str());
+ AddUrlParameter("fields=href");
+ if (strategy == OnConflict::REPLACE)
+ AddUrlParameter("overwrite=true");
+ }
+ };
+
+ class UploadFileRequest : public HttpRequest
+ {
+ public:
+ UploadFileRequest(const char *url, const char *data, size_t size) :
+ HttpRequest(REQUEST_PUT, url)
+ {
+ SetData(data, size);
+ }
+ };
+
+ class UploadFileChunkRequest : public HttpRequest
+ {
+ public:
+ UploadFileChunkRequest(const char *url, const char *chunk, size_t chunkSize, uint64_t offset, uint64_t fileSize) :
+ HttpRequest(REQUEST_PUT, url)
+ {
+ uint64_t rangeMin = offset;
+ uint64_t rangeMax = offset + chunkSize - 1;
+ CMStringA range(CMStringDataFormat::FORMAT, "bytes %I64u-%I64u/%I64u", rangeMin, rangeMax, fileSize);
+ AddHeader("Content-Range", range);
+
+ SetData(chunk, chunkSize);
+ }
+ };
+
+ class CreateFolderRequest : public HttpRequest
+ {
+ public:
+ CreateFolderRequest(const char *token, const char *path) :
+ HttpRequest(REQUEST_PUT, YADISK_API)
+ {
+ AddOAuthHeader(token);
+ AddUrlParameterWithEncode("path", "app:%s", path);
+ AddUrlParameter("fields=href");
+ }
+ };
+
+ class PublishRequest : public HttpRequest
+ {
+ public:
+ PublishRequest(const char *token, const char *path) :
+ HttpRequest(REQUEST_PUT, YADISK_API "/publish")
+ {
+ AddOAuthHeader(token);
+ AddUrlParameter("path=app:%s", mir_urlEncode(path).c_str());
+ }
+ };
+
+ class GetResourcesRequest : public HttpRequest
+ {
+ public:
+ GetResourcesRequest(const char *token, const char *path) :
+ HttpRequest(REQUEST_GET, YADISK_API)
+ {
+ AddOAuthHeader(token);
+ AddUrlParameter("path=app:%s", mir_urlEncode(path).c_str());
+ AddUrlParameter("fields=public_url");
+ }
+ };
+};
+
+#endif //_YANDEXSERVICE_API_H_
diff --git a/protocols/CloudFile/src/Services/yandex_service.cpp b/protocols/CloudFile/src/Services/yandex_service.cpp
new file mode 100644
index 0000000000..4bd0210ca1
--- /dev/null
+++ b/protocols/CloudFile/src/Services/yandex_service.cpp
@@ -0,0 +1,290 @@
+#include "..\stdafx.h"
+#include "yandex_api.h"
+
+struct CMPluginYandex : public CMPluginBase
+{
+ CMPluginYandex() :
+ CMPluginBase(MODULENAME "/YandexDisk", pluginInfoEx)
+ {
+ m_hInst = g_plugin.getInst();
+
+ RegisterProtocol(PROTOTYPE_PROTOWITHACCS, (pfnInitProto)CYandexService::Init, (pfnUninitProto)CYandexService::UnInit);
+ }
+}
+g_pluginYandex;
+
+/////////////////////////////////////////////////////////////////////////////////////////
+
+CYandexService::CYandexService(const char *protoName, const wchar_t *userName) :
+ CCloudService(protoName, userName, &g_pluginYandex)
+{
+ m_hProtoIcon = GetIconHandle(IDI_YADISK);
+}
+
+CYandexService* CYandexService::Init(const char *moduleName, const wchar_t *userName)
+{
+ CYandexService *proto = new CYandexService(moduleName, userName);
+ Services.insert(proto);
+ return proto;
+}
+
+int CYandexService::UnInit(CYandexService *proto)
+{
+ Services.remove(proto);
+ delete proto;
+ return 0;
+}
+
+const char* CYandexService::GetModuleName() const
+{
+ return "Yandex.Disk";
+}
+
+int CYandexService::GetIconId() const
+{
+ return IDI_YADISK;
+}
+
+bool CYandexService::IsLoggedIn()
+{
+ ptrA token(getStringA("TokenSecret"));
+ if (!token || token[0] == 0)
+ return false;
+ time_t now = time(0);
+ time_t expiresIn = getDword("ExpiresIn");
+ return now < expiresIn;
+}
+
+void CYandexService::Login(HWND owner)
+{
+ ptrA token(getStringA("TokenSecret"));
+ ptrA refreshToken(getStringA("RefreshToken"));
+ if (token && refreshToken && refreshToken[0]) {
+ YandexAPI::RefreshTokenRequest request(refreshToken);
+ NLHR_PTR response(request.Send(m_hConnection));
+
+ JSONNode root = GetJsonResponse(response);
+
+ JSONNode node = root.at("access_token");
+ setString("TokenSecret", node.as_string().c_str());
+
+ node = root.at("expires_in");
+ time_t expiresIn = time(0) + node.as_int();
+ setDword("ExpiresIn", expiresIn);
+
+ node = root.at("refresh_token");
+ setString("RefreshToken", node.as_string().c_str());
+
+ return;
+ }
+
+ COAuthDlg dlg(this, YANDEX_AUTH, (MyThreadFunc)&CYandexService::RequestAccessTokenThread);
+ dlg.SetParent(owner);
+ dlg.DoModal();
+}
+
+void CYandexService::Logout()
+{
+ ForkThread((MyThreadFunc)&CYandexService::RevokeAccessTokenThread);
+}
+
+void CYandexService::RequestAccessTokenThread(void *param)
+{
+ HWND hwndDlg = (HWND)param;
+
+ if (IsLoggedIn())
+ Logout();
+
+ char requestToken[128];
+ GetDlgItemTextA(hwndDlg, IDC_OAUTH_CODE, requestToken, _countof(requestToken));
+
+ YandexAPI::GetAccessTokenRequest request(requestToken);
+ NLHR_PTR response(request.Send(m_hConnection));
+
+ if (response == nullptr || response->resultCode != HTTP_CODE_OK) {
+ const char *error = response->dataLength
+ ? response->pData
+ : HttpStatusToError(response->resultCode);
+
+ Netlib_Logf(m_hConnection, "%s: %s", GetAccountName(), error);
+ ShowNotification(TranslateT("Server does not respond"), MB_ICONERROR);
+ EndDialog(hwndDlg, 0);
+ return;
+ }
+
+ JSONNode root = JSONNode::parse(response->pData);
+ if (root.empty()) {
+ Netlib_Logf(m_hConnection, "%s: %s", GetAccountName(), HttpStatusToError(response->resultCode));
+ ShowNotification(TranslateT("Server does not respond"), MB_ICONERROR);
+ EndDialog(hwndDlg, 0);
+ return;
+ }
+
+ JSONNode node = root.at("error_description");
+ if (!node.isnull()) {
+ CMStringW error_description = node.as_mstring();
+ Netlib_Logf(m_hConnection, "%s: %s", GetAccountName(), HttpStatusToError(response->resultCode));
+ ShowNotification(error_description, MB_ICONERROR);
+ EndDialog(hwndDlg, 0);
+ return;
+ }
+
+ node = root.at("access_token");
+ setString("TokenSecret", node.as_string().c_str());
+
+ node = root.at("expires_in");
+ time_t expiresIn = time(0) + node.as_int();
+ setDword("ExpiresIn", expiresIn);
+
+ node = root.at("refresh_token");
+ setString("RefreshToken", node.as_string().c_str());
+
+ SetDlgItemTextA(hwndDlg, IDC_OAUTH_CODE, "");
+
+ EndDialog(hwndDlg, 1);
+}
+
+void CYandexService::RevokeAccessTokenThread(void*)
+{
+ ptrA token(db_get_sa(0, GetAccountName(), "TokenSecret"));
+ YandexAPI::RevokeAccessTokenRequest request(token);
+ NLHR_PTR response(request.Send(m_hConnection));
+
+ delSetting("ExpiresIn");
+ delSetting("TokenSecret");
+ delSetting("RefreshToken");
+}
+
+void CYandexService::HandleJsonError(JSONNode &node)
+{
+ JSONNode error = node.at("error");
+ if (!error.isnull()) {
+ json_string tag = error.at(".tag").as_string();
+ throw Exception(tag.c_str());
+ }
+}
+
+auto CYandexService::CreateUploadSession(const std::string &path)
+{
+ ptrA token(getStringA("TokenSecret"));
+ BYTE strategy = g_plugin.getByte("ConflictStrategy", OnConflict::REPLACE);
+ YandexAPI::GetUploadUrlRequest request(token, path.c_str(), (OnConflict)strategy);
+ NLHR_PTR response(request.Send(m_hConnection));
+
+ JSONNode root = GetJsonResponse(response);
+ return root["href"].as_string();
+}
+
+void CYandexService::UploadFile(const std::string &uploadUri, const char *data, size_t size)
+{
+ YandexAPI::UploadFileRequest request(uploadUri.c_str(), data, size);
+ NLHR_PTR response(request.Send(m_hConnection));
+
+ HandleHttpError(response);
+
+ if (response->resultCode == HTTP_CODE_CREATED)
+ return;
+
+ HttpResponseToError(response);
+}
+
+void CYandexService::UploadFileChunk(const std::string &uploadUri, const char *chunk, size_t chunkSize, uint64_t offset, uint64_t fileSize)
+{
+ YandexAPI::UploadFileChunkRequest request(uploadUri.c_str(), chunk, chunkSize, offset, fileSize);
+ NLHR_PTR response(request.Send(m_hConnection));
+
+ HandleHttpError(response);
+
+ if (response->resultCode == HTTP_CODE_ACCEPTED ||
+ response->resultCode == HTTP_CODE_CREATED)
+ return;
+
+ HttpResponseToError(response);
+}
+
+void CYandexService::CreateFolder(const std::string &path)
+{
+ ptrA token(getStringA("TokenSecret"));
+ YandexAPI::CreateFolderRequest request(token, path.c_str());
+ NLHR_PTR response(request.Send(m_hConnection));
+
+ if (HTTP_CODE_SUCCESS(response->resultCode)) {
+ GetJsonResponse(response);
+ return;
+ }
+
+ // forder exists on server
+ if (response->resultCode == HTTP_CODE_CONFLICT) {
+ return;
+ }
+
+ HttpResponseToError(response);
+}
+
+auto CYandexService::CreateSharedLink(const std::string &path)
+{
+ ptrA token(getStringA("TokenSecret"));
+ YandexAPI::PublishRequest publishRequest(token, path.c_str());
+ NLHR_PTR response(publishRequest.Send(m_hConnection));
+
+ GetJsonResponse(response);
+
+ YandexAPI::GetResourcesRequest resourcesRequest(token, path.c_str());
+ response = resourcesRequest.Send(m_hConnection);
+
+ JSONNode root = GetJsonResponse(response);
+ return root["public_url"].as_string();
+}
+
+void CYandexService::Upload(FileTransferParam *ftp)
+{
+ auto serverDictionary = ftp->GetServerDirectory();
+ std::string serverFolder = serverDictionary ? T2Utf(serverDictionary) : "";
+ if (!serverFolder.empty()) {
+ auto path = PreparePath(serverFolder);
+ CreateFolder(path);
+ auto link = CreateSharedLink(path);
+ ftp->AddSharedLink(link.c_str());
+ }
+
+ ftp->FirstFile();
+ do
+ {
+ std::string fileName = T2Utf(ftp->GetCurrentRelativeFilePath());
+ uint64_t fileSize = ftp->GetCurrentFileSize();
+
+ size_t chunkSize = ftp->GetCurrentFileChunkSize();
+ mir_ptr<char> chunk((char*)mir_calloc(chunkSize));
+
+ std::string path;
+ if (!serverFolder.empty())
+ path = "/" + serverFolder + "/" + fileName;
+ else
+ path = PreparePath(fileName);
+
+ auto uploadUri = CreateUploadSession(path);
+
+ if (chunkSize == fileSize) {
+ ftp->CheckCurrentFile();
+ size_t size = ftp->ReadCurrentFile(chunk, chunkSize);
+ UploadFile(uploadUri, chunk, size);
+ ftp->Progress(size);
+ }
+ else {
+ uint64_t offset = 0;
+ double chunkCount = ceil(double(fileSize) / chunkSize);
+ for (size_t i = 0; i < chunkCount; i++) {
+ ftp->CheckCurrentFile();
+ size_t size = ftp->ReadCurrentFile(chunk, chunkSize);
+ UploadFileChunk(uploadUri, chunk, size, offset, fileSize);
+ offset += size;
+ ftp->Progress(size);
+ }
+ }
+
+ if (!ftp->IsCurrentFileInSubDirectory()) {
+ auto link = CreateSharedLink(path);
+ ftp->AddSharedLink(link.c_str());
+ }
+ } while (ftp->NextFile());
+}
diff --git a/protocols/CloudFile/src/Services/yandex_service.h b/protocols/CloudFile/src/Services/yandex_service.h
new file mode 100644
index 0000000000..0fdcdf679a
--- /dev/null
+++ b/protocols/CloudFile/src/Services/yandex_service.h
@@ -0,0 +1,35 @@
+#ifndef _CLOUDFILE_YANDEX_H_
+#define _CLOUDFILE_YANDEX_H_
+
+class CYandexService : public CCloudService
+{
+private:
+ void __cdecl RequestAccessTokenThread(void *param);
+ void __cdecl RevokeAccessTokenThread(void *param);
+
+ void HandleJsonError(JSONNode &node) override;
+
+ auto CreateUploadSession(const std::string &path);
+ void UploadFile(const std::string &uploadUri, const char *data, size_t size);
+ void UploadFileChunk(const std::string &uploadUri, const char *chunk, size_t chunkSize, uint64_t offset, uint64_t fileSize);
+ void CreateFolder(const std::string &path);
+ auto CreateSharedLink(const std::string &path);
+
+ void Upload(FileTransferParam *ftp) override;
+
+public:
+ CYandexService(const char *protoName, const wchar_t *userName);
+
+ static CYandexService* Init(const char *szModuleName, const wchar_t *szUserName);
+ static int UnInit(CYandexService*);
+
+ const char* GetModuleName() const override;
+
+ int GetIconId() const override;
+
+ bool IsLoggedIn() override;
+ void Login(HWND owner = nullptr) override;
+ void Logout() override;
+};
+
+#endif //_CLOUDFILE_YANDEX_H_ \ No newline at end of file
diff --git a/protocols/CloudFile/src/cloud_file.cpp b/protocols/CloudFile/src/cloud_file.cpp
new file mode 100644
index 0000000000..f6019f8196
--- /dev/null
+++ b/protocols/CloudFile/src/cloud_file.cpp
@@ -0,0 +1,197 @@
+#include "stdafx.h"
+
+CCloudService::CCloudService(const char *protoName, const wchar_t *userName, HPLUGIN pPlugin)
+ : PROTO<CCloudService>(protoName, userName),
+ m_pPlugin(pPlugin)
+{
+ NETLIBUSER nlu = {};
+ nlu.flags = NUF_OUTGOING | NUF_HTTPCONNS | NUF_UNICODE;
+ nlu.szSettingsModule = (char*)protoName;
+ nlu.szDescriptiveName.w = (wchar_t*)userName;
+ m_hConnection = Netlib_RegisterUser(&nlu);
+
+ CreateProtoService(PS_CREATEACCMGRUI, &CCloudService::OnAccountManagerInit);
+}
+
+CCloudService::~CCloudService()
+{
+ Netlib_CloseHandle(m_hConnection);
+ m_hConnection = nullptr;
+}
+
+void CCloudService::OnErase()
+{
+ KillModuleMenus(m_pPlugin);
+}
+
+HPLUGIN CCloudService::GetId() const
+{
+ return m_pPlugin;
+}
+
+const char* CCloudService::GetAccountName() const
+{
+ return m_szModuleName;
+}
+
+const wchar_t* CCloudService::GetUserName() const
+{
+ return m_tszUserName;
+}
+
+INT_PTR CCloudService::GetCaps(int type, MCONTACT)
+{
+ switch (type) {
+ case PFLAGNUM_1:
+ return PF1_FILESEND;
+ case PFLAGNUM_2:
+ case PFLAGNUM_5:
+ return PF2_NONE;
+ default:
+ return 0;
+ }
+}
+
+int CCloudService::FileCancel(MCONTACT, HANDLE hTransfer)
+{
+ FileTransferParam *ftp = Transfers.find((FileTransferParam*)&hTransfer);
+ if (ftp)
+ ftp->Terminate();
+
+ return 0;
+}
+
+HANDLE CCloudService::SendFile(MCONTACT hContact, const wchar_t *description, wchar_t **paths)
+{
+ FileTransferParam *ftp = new FileTransferParam(hContact);
+ ftp->SetDescription(description);
+ ftp->SetWorkingDirectory(paths[0]);
+ for (int i = 0; paths[i]; i++) {
+ if (PathIsDirectory(paths[i]))
+ continue;
+ ftp->AddFile(paths[i]);
+ }
+ Transfers.insert(ftp);
+ mir_forkthreadowner(UploadAndReportProgressThread, this, ftp);
+ return (HANDLE)ftp->GetId();
+}
+
+void CCloudService::OpenUploadDialog(MCONTACT hContact)
+{
+ char *proto = GetContactProto(hContact);
+ if (!mir_strcmpi(proto, META_PROTO))
+ hContact = db_mc_getMostOnline(hContact);
+
+ auto it = InterceptedContacts.find(hContact);
+ if (it == InterceptedContacts.end()) {
+ HWND hwnd = (HWND)CallService(MS_FILE_SENDFILE, hContact, 0);
+ InterceptedContacts[hContact] = hwnd;
+ }
+ else
+ SetActiveWindow(it->second);
+}
+
+INT_PTR CCloudService::OnAccountManagerInit(WPARAM, LPARAM lParam)
+{
+ CAccountManagerDlg *page = new CAccountManagerDlg(this);
+ page->SetParent((HWND)lParam);
+ page->Show();
+ return (INT_PTR)page->GetHwnd();
+}
+
+std::string CCloudService::PreparePath(const std::string &path) const
+{
+ std::string newPath = path;
+ if (newPath[0] != '/')
+ newPath.insert(0, "/");
+ std::replace(newPath.begin(), newPath.end(), '\\', '/');
+ size_t pos = newPath.find("//");
+ while (pos != std::string::npos) {
+ newPath.replace(pos, 2, "/");
+ pos = newPath.find("//", pos + 1);
+ }
+ return newPath;
+}
+
+char* CCloudService::HttpStatusToError(int status)
+{
+ switch (status) {
+ case HTTP_CODE_OK:
+ return "OK";
+ case HTTP_CODE_BAD_REQUEST:
+ return "Bad input parameter. Error message should indicate which one and why";
+ case HTTP_CODE_UNAUTHORIZED:
+ return "Bad or expired token. This can happen if the user or Dropbox revoked or expired an access token. To fix, you should re-authenticate the user";
+ case HTTP_CODE_FORBIDDEN:
+ return "Bad OAuth request (wrong consumer key, bad nonce, expired timestamp...). Unfortunately, re-authenticating the user won't help here";
+ case HTTP_CODE_NOT_FOUND:
+ return "File or folder not found at the specified path";
+ case HTTP_CODE_METHOD_NOT_ALLOWED:
+ return "Request method not expected (generally should be GET or POST)";
+ case HTTP_CODE_TOO_MANY_REQUESTS:
+ return "Your app is making too many requests and is being rate limited. 429s can trigger on a per-app or per-user basis";
+ case HTTP_CODE_SERVICE_UNAVAILABLE:
+ return "If the response includes the Retry-After header, this means your OAuth 1.0 app is being rate limited. Otherwise, this indicates a transient server error, and your app should retry its request.";
+ }
+
+ return "Unknown error";
+}
+
+void CCloudService::HttpResponseToError(NETLIBHTTPREQUEST *response)
+{
+ if (response == nullptr)
+ throw Exception(HttpStatusToError());
+ if (response->dataLength)
+ throw Exception(response->pData);
+ throw Exception(HttpStatusToError(response->resultCode));
+}
+
+void CCloudService::HandleHttpError(NETLIBHTTPREQUEST *response)
+{
+ if (response == nullptr)
+ throw Exception(HttpStatusToError());
+
+ if (HTTP_CODE_SUCCESS(response->resultCode))
+ return;
+
+ if (response->resultCode == HTTP_CODE_UNAUTHORIZED)
+ delSetting("TokenSecret");
+
+ HttpResponseToError(response);
+}
+
+JSONNode CCloudService::GetJsonResponse(NETLIBHTTPREQUEST *response)
+{
+ HandleHttpError(response);
+
+ JSONNode root = JSONNode::parse(response->pData);
+ if (root.isnull())
+ throw Exception(HttpStatusToError());
+
+ HandleJsonError(root);
+
+ return root;
+}
+
+UINT CCloudService::Upload(CCloudService *service, FileTransferParam *ftp)
+{
+ try {
+ if (!service->IsLoggedIn())
+ service->Login();
+
+ if (!service->IsLoggedIn()) {
+ ftp->SetStatus(ACKRESULT_FAILED);
+ return ACKRESULT_FAILED;
+ }
+
+ service->Upload(ftp);
+ }
+ catch (Exception &ex) {
+ service->debugLogA("%s: %s", service->GetModuleName(), ex.what());
+ ftp->SetStatus(ACKRESULT_FAILED);
+ return ACKRESULT_FAILED;
+ }
+
+ ftp->SetStatus(ACKRESULT_SUCCESS);
+ return ACKRESULT_SUCCESS;
+} \ No newline at end of file
diff --git a/protocols/CloudFile/src/cloud_file.h b/protocols/CloudFile/src/cloud_file.h
new file mode 100644
index 0000000000..1e70671054
--- /dev/null
+++ b/protocols/CloudFile/src/cloud_file.h
@@ -0,0 +1,61 @@
+#ifndef _CLOUD_SERVICE_H_
+#define _CLOUD_SERVICE_H_
+
+enum OnConflict
+{
+ NONE,
+ RENAME,
+ REPLACE,
+};
+
+class CCloudService : public PROTO<CCloudService>
+{
+protected:
+ HPLUGIN m_pPlugin;
+ HNETLIBUSER m_hConnection;
+
+ INT_PTR __cdecl OnAccountManagerInit(WPARAM, LPARAM);
+
+ // utils
+ std::string PreparePath(const std::string &path) const;
+
+ virtual char* HttpStatusToError(int status = 0);
+ virtual void HttpResponseToError(NETLIBHTTPREQUEST *response);
+ virtual void HandleHttpError(NETLIBHTTPREQUEST *response);
+ virtual void HandleJsonError(JSONNode &node) = 0;
+
+ void OnErase() override;
+ void OnModulesLoaded() override;
+
+ JSONNode GetJsonResponse(NETLIBHTTPREQUEST *response);
+
+ virtual void Upload(FileTransferParam *ftp) = 0;
+
+public:
+ std::map<MCONTACT, HWND> InterceptedContacts;
+
+ CCloudService(const char *protoName, const wchar_t *userName, HPLUGIN);
+ virtual ~CCloudService();
+
+ INT_PTR GetCaps(int type, MCONTACT) override;
+
+ int FileCancel(MCONTACT hContact, HANDLE hTransfer) override;
+ HANDLE SendFile(MCONTACT hContact, const wchar_t *msg, wchar_t **ppszFiles) override;
+
+ HPLUGIN GetId() const;
+ virtual const char* GetModuleName() const = 0;
+ const char* GetAccountName() const;
+ const wchar_t* GetUserName() const;
+
+ virtual int GetIconId() const = 0;
+
+ virtual bool IsLoggedIn() = 0;
+ virtual void Login(HWND owner = nullptr) = 0;
+ virtual void Logout() = 0;
+
+ void OpenUploadDialog(MCONTACT hContact);
+
+ static UINT Upload(CCloudService *service, FileTransferParam *ftp);
+};
+
+#endif //_CLOUD_SERVICE_H_ \ No newline at end of file
diff --git a/protocols/CloudFile/src/events.cpp b/protocols/CloudFile/src/events.cpp
new file mode 100644
index 0000000000..010729dddb
--- /dev/null
+++ b/protocols/CloudFile/src/events.cpp
@@ -0,0 +1,48 @@
+#include "stdafx.h"
+
+static int OnProtoAck(WPARAM, LPARAM lParam)
+{
+ ACKDATA *ack = (ACKDATA*)lParam;
+
+ if (ack->type != ACKTYPE_STATUS)
+ return 0;
+
+ for (auto &hContact : Contacts(ack->szModule)) {
+ MessageWindowData msgw;
+ if (Srmm_GetWindowData(hContact, msgw) || !(msgw.uState & MSG_WINDOW_STATE_EXISTS))
+ continue;
+
+ BBButton bbd = {};
+ bbd.pszModuleName = MODULENAME;
+ bbd.dwButtonID = BBB_ID_FILE_SEND;
+ bbd.bbbFlags = CanSendToContact(hContact)
+ ? BBSF_RELEASED
+ : BBSF_DISABLED;
+ Srmm_SetButtonState(hContact, &bbd);
+ }
+
+ return 0;
+}
+
+static int OnFileDialogCanceled(WPARAM hContact, LPARAM)
+{
+ for (auto &service : Services) {
+ auto it = service->InterceptedContacts.find(hContact);
+ if (it != service->InterceptedContacts.end())
+ service->InterceptedContacts.erase(it);
+ }
+ return 0;
+}
+
+int OnModulesLoaded(WPARAM, LPARAM)
+{
+ InitializeMenus();
+
+ HookEvent(ME_PROTO_ACK, OnProtoAck);
+
+ // srfile
+ HookEvent(ME_FILEDLG_CANCELED, OnFileDialogCanceled);
+
+ HookTemporaryEvent(ME_MSG_TOOLBARLOADED, OnSrmmToolbarLoaded);
+ return 0;
+} \ No newline at end of file
diff --git a/protocols/CloudFile/src/file_transfer.h b/protocols/CloudFile/src/file_transfer.h
new file mode 100644
index 0000000000..692e717f2e
--- /dev/null
+++ b/protocols/CloudFile/src/file_transfer.h
@@ -0,0 +1,255 @@
+#ifndef _FILE_TRANSFER_H_
+#define _FILE_TRANSFER_H_
+
+class FileTransferParam
+{
+private:
+ static ULONG hFileProcess;
+
+ ULONG id;
+ FILE *hFile;
+ PROTOFILETRANSFERSTATUS pfts;
+
+ bool isTerminated;
+
+ CMStringW m_serverDirectory;
+ int m_relativePathStart;
+
+ LIST<char> m_links;
+ CMStringW m_description;
+
+public:
+ FileTransferParam(MCONTACT hContact)
+ : m_links(1)
+ {
+ hFile = NULL;
+ id = InterlockedIncrement(&hFileProcess);
+
+ isTerminated = false;
+
+ m_relativePathStart = 0;
+
+ pfts.flags = PFTS_UNICODE | PFTS_SENDING;
+ pfts.hContact = hContact;
+ pfts.currentFileNumber = -1;
+ pfts.currentFileProgress = 0;
+ pfts.currentFileSize = 0;
+ pfts.currentFileTime = 0;
+ pfts.totalBytes = 0;
+ pfts.totalFiles = 0;
+ pfts.totalProgress = 0;
+ pfts.pszFiles.w = (wchar_t**)mir_alloc(sizeof(wchar_t*) * (pfts.totalFiles + 1));
+ pfts.pszFiles.w[pfts.totalFiles] = NULL;
+ pfts.szWorkingDir.w = NULL;
+ pfts.szCurrentFile.w = NULL;
+
+ ProtoBroadcastAck(MODULENAME, pfts.hContact, ACKTYPE_FILE, ACKRESULT_INITIALISING, (HANDLE)id, 0);
+ }
+
+ ~FileTransferParam()
+ {
+ CloseCurrentFile();
+
+ if (pfts.szWorkingDir.w)
+ mir_free(pfts.szWorkingDir.w);
+
+ if (pfts.pszFiles.a) {
+ for (int i = 0; pfts.pszFiles.a[i]; i++)
+ mir_free(pfts.pszFiles.a[i]);
+ mir_free(pfts.pszFiles.a);
+ }
+
+ for (auto &link : m_links)
+ mir_free(link);
+ m_links.destroy();
+ }
+
+ ULONG GetId() const
+ {
+ return id;
+ }
+
+ MCONTACT GetContact() const
+ {
+ return pfts.hContact;
+ }
+
+ const wchar_t* GetDescription() const
+ {
+ return m_description.GetString();
+ }
+
+ const char** GetSharedLinks(size_t &count) const
+ {
+ count = m_links.getCount();
+ return (const char**)m_links.getArray();
+ }
+
+ void Terminate()
+ {
+ isTerminated = true;
+ }
+
+ void SetDescription(const wchar_t *description)
+ {
+ m_description = description;
+ }
+
+ void SetWorkingDirectory(const wchar_t *path)
+ {
+ m_relativePathStart = wcsrchr(path, '\\') - path + 1;
+ pfts.szWorkingDir.w = (wchar_t*)mir_calloc(sizeof(wchar_t) * m_relativePathStart);
+ mir_wstrncpy(pfts.szWorkingDir.w, path, m_relativePathStart);
+ if (PathIsDirectory(path))
+ m_serverDirectory = wcsrchr(path, '\\') + 1;
+ }
+
+ void SetServerDirectory(const wchar_t *name)
+ {
+ if (name)
+ m_serverDirectory = name;
+ }
+
+ const wchar_t* GetServerDirectory() const
+ {
+ if (m_serverDirectory.IsEmpty())
+ return nullptr;
+ return m_serverDirectory.GetString();
+ }
+
+ void AddFile(const wchar_t *path)
+ {
+ pfts.pszFiles.w = (wchar_t**)mir_realloc(pfts.pszFiles.w, sizeof(wchar_t*) * (pfts.totalFiles + 2));
+ pfts.pszFiles.w[pfts.totalFiles++] = mir_wstrdup(path);
+ pfts.pszFiles.w[pfts.totalFiles] = NULL;
+
+ FILE *file = _wfopen(path, L"rb");
+ if (file != NULL) {
+ _fseeki64(file, 0, SEEK_END);
+ pfts.totalBytes += _ftelli64(file);
+ fclose(file);
+ }
+ }
+
+ void AddSharedLink(const char *url)
+ {
+ m_links.insert(mir_strdup(url));
+ }
+
+ const bool IsCurrentFileInSubDirectory() const
+ {
+ const wchar_t *backslash = wcschr(GetCurrentRelativeFilePath(), L'\\');
+ return backslash != nullptr;
+ }
+
+ const wchar_t* GetCurrentFilePath() const
+ {
+ return pfts.pszFiles.w[pfts.currentFileNumber];
+ }
+
+ const wchar_t* GetCurrentRelativeFilePath() const
+ {
+ return &GetCurrentFilePath()[m_relativePathStart];
+ }
+
+ const wchar_t* GetCurrentFileName() const
+ {
+ return wcsrchr(GetCurrentFilePath(), '\\') + 1;
+ }
+
+ void OpenCurrentFile()
+ {
+ hFile = _wfopen(GetCurrentFilePath(), L"rb");
+ if (!hFile)
+ throw Exception("Unable to open file");
+ _fseeki64(hFile, 0, SEEK_END);
+ pfts.currentFileSize = _ftelli64(hFile);
+ rewind(hFile);
+ }
+
+ size_t ReadCurrentFile(void *buffer, size_t count)
+ {
+ return fread(buffer, sizeof(char), count, hFile);
+ }
+
+ void CheckCurrentFile()
+ {
+ if (ferror(hFile))
+ throw Exception("Error while file sending");
+
+ if (isTerminated)
+ throw Exception("Transfer was terminated");
+ }
+
+ void CloseCurrentFile()
+ {
+ if (hFile != NULL)
+ {
+ fclose(hFile);
+ hFile = NULL;
+ }
+ }
+
+ const uint64_t GetCurrentFileSize() const
+ {
+ return pfts.currentFileSize;
+ }
+
+ const size_t GetCurrentFileChunkSize() const
+ {
+ size_t chunkSize = 1024 * 1024;
+ if (pfts.currentFileSize < chunkSize)
+ chunkSize = min(pfts.currentFileSize, chunkSize / 4);
+ else if (pfts.currentFileSize > 20 * chunkSize)
+ chunkSize = chunkSize * 4;
+ return chunkSize;
+ }
+
+ void Progress(size_t count)
+ {
+ pfts.currentFileProgress += count;
+ pfts.totalProgress += count;
+ if (pfts.hContact)
+ ProtoBroadcastAck(MODULENAME, pfts.hContact, ACKTYPE_FILE, ACKRESULT_DATA, (HANDLE)id, (LPARAM)&pfts);
+ }
+
+ void FirstFile()
+ {
+ CloseCurrentFile();
+
+ pfts.currentFileNumber = 0;
+ pfts.currentFileProgress = 0;
+ pfts.szCurrentFile.w = wcsrchr(pfts.pszFiles.w[pfts.currentFileNumber], '\\') + 1;
+ if (pfts.hContact)
+ ProtoBroadcastAck(MODULENAME, pfts.hContact, ACKTYPE_FILE, ACKRESULT_DATA, (HANDLE)id, (LPARAM)&pfts);
+
+ OpenCurrentFile();
+ CheckCurrentFile();
+ }
+
+ bool NextFile()
+ {
+ CloseCurrentFile();
+
+ if (++pfts.currentFileNumber == pfts.totalFiles)
+ return false;
+
+ pfts.currentFileProgress = 0;
+ pfts.szCurrentFile.w = wcsrchr(pfts.pszFiles.w[pfts.currentFileNumber], '\\') + 1;
+ if (pfts.hContact)
+ ProtoBroadcastAck(MODULENAME, pfts.hContact, ACKTYPE_FILE, ACKRESULT_NEXTFILE, (HANDLE)id, 0);
+
+ OpenCurrentFile();
+ CheckCurrentFile();
+
+ return true;
+ }
+
+ void SetStatus(int status, LPARAM param = 0)
+ {
+ if (pfts.hContact)
+ ProtoBroadcastAck(MODULENAME, pfts.hContact, ACKTYPE_FILE, status, (HANDLE)id, param);
+ }
+};
+
+#endif //_FILE_TRANSFER_H_ \ No newline at end of file
diff --git a/protocols/CloudFile/src/http_request.h b/protocols/CloudFile/src/http_request.h
new file mode 100644
index 0000000000..c74b2ae40c
--- /dev/null
+++ b/protocols/CloudFile/src/http_request.h
@@ -0,0 +1,180 @@
+#ifndef _HTTP_REQUEST_H_
+#define _HTTP_REQUEST_H_
+
+class HttpRequestException
+{
+ CMStringA message;
+
+public:
+ HttpRequestException(const char *message) :
+ message(message)
+ {
+ }
+
+ const char* what() const throw()
+ {
+ return message.c_str();
+ }
+};
+
+class HttpRequest : protected NETLIBHTTPREQUEST
+{
+private:
+ CMStringA m_szUrl;
+
+ void Init(int type)
+ {
+ cbSize = sizeof(NETLIBHTTPREQUEST);
+ requestType = type;
+ flags = NLHRF_HTTP11 | NLHRF_SSL | NLHRF_NODUMP;
+ szUrl = NULL;
+ headers = NULL;
+ headersCount = 0;
+ pData = NULL;
+ dataLength = 0;
+ resultCode = 0;
+ szResultDescr = NULL;
+ nlc = NULL;
+ timeout = 0;
+ }
+
+protected:
+ enum HttpRequestUrlFormat { FORMAT };
+
+ void AddHeader(LPCSTR szName, LPCSTR szValue)
+ {
+ headers = (NETLIBHTTPHEADER*)mir_realloc(headers, sizeof(NETLIBHTTPHEADER) * (headersCount + 1));
+ headers[headersCount].szName = mir_strdup(szName);
+ headers[headersCount].szValue = mir_strdup(szValue);
+ headersCount++;
+ }
+
+ void AddBasicAuthHeader(LPCSTR szLogin, LPCSTR szPassword)
+ {
+ size_t length = mir_strlen(szLogin) + mir_strlen(szPassword) + 1;
+ ptrA cPair((char*)mir_calloc(length + 1));
+ mir_snprintf(
+ cPair,
+ length,
+ "%s:%s",
+ szLogin,
+ szPassword);
+
+ ptrA ePair(mir_base64_encode(cPair, length));
+
+ length = mir_strlen(ePair) + 7;
+ char *value = (char*)mir_calloc(length + 1);
+ mir_snprintf(
+ value,
+ length,
+ "Basic %s",
+ ePair);
+
+ headers = (NETLIBHTTPHEADER*)mir_realloc(headers, sizeof(NETLIBHTTPHEADER)*(headersCount + 1));
+ headers[headersCount].szName = mir_strdup("Authorization");
+ headers[headersCount].szValue = value;
+ headersCount++;
+ }
+
+ void AddBearerAuthHeader(LPCSTR szValue)
+ {
+ size_t length = mir_strlen(szValue) + 8;
+ char *value = (char*)mir_calloc(length + 1);
+ mir_snprintf(
+ value,
+ length,
+ "Bearer %s",
+ szValue);
+
+ headers = (NETLIBHTTPHEADER*)mir_realloc(headers, sizeof(NETLIBHTTPHEADER)*(headersCount + 1));
+ headers[headersCount].szName = mir_strdup("Authorization");
+ headers[headersCount].szValue = value;
+ headersCount++;
+ }
+
+ void AddOAuthHeader(LPCSTR szValue)
+ {
+ size_t length = mir_strlen(szValue) + 7;
+ char *value = (char*)mir_calloc(length + 1);
+ mir_snprintf(
+ value,
+ length,
+ "OAuth %s",
+ szValue);
+
+ headers = (NETLIBHTTPHEADER*)mir_realloc(headers, sizeof(NETLIBHTTPHEADER)*(headersCount + 1));
+ headers[headersCount].szName = mir_strdup("Authorization");
+ headers[headersCount].szValue = value;
+ headersCount++;
+ }
+
+ void AddUrlParameter(const char *urlFormat, ...)
+ {
+ va_list urlArgs;
+ va_start(urlArgs, urlFormat);
+ m_szUrl += m_szUrl.Find('?') == -1 ? '?' : '&';
+ m_szUrl.AppendFormatV(urlFormat, urlArgs);
+ va_end(urlArgs);
+ }
+
+ void AddUrlParameterWithEncode(const char *name, const char *valueFormat, ...)
+ {
+ va_list valueArgs;
+ va_start(valueArgs, valueFormat);
+ m_szUrl += m_szUrl.Find('?') == -1 ? '?' : '&';
+ m_szUrl.AppendFormat("%s=", name);
+ CMStringA value;
+ value.AppendFormatV(valueFormat, valueArgs);
+ m_szUrl += mir_urlEncode(value);
+ va_end(valueArgs);
+ }
+
+ void SetData(const char *data, size_t size)
+ {
+ if (pData != NULL)
+ mir_free(pData);
+
+ dataLength = (int)size;
+ pData = (char*)mir_alloc(size);
+ memcpy(pData, data, size);
+ }
+
+public:
+ HttpRequest(int type, LPCSTR url)
+ {
+ Init(type);
+
+ m_szUrl = url;
+ }
+
+ HttpRequest(int type, HttpRequestUrlFormat, LPCSTR urlFormat, ...)
+ {
+ Init(type);
+
+ va_list formatArgs;
+ va_start(formatArgs, urlFormat);
+ m_szUrl.AppendFormatV(urlFormat, formatArgs);
+ va_end(formatArgs);
+ }
+
+ ~HttpRequest()
+ {
+ for (int i = 0; i < headersCount; i++)
+ {
+ mir_free(headers[i].szName);
+ mir_free(headers[i].szValue);
+ }
+ mir_free(headers);
+ if (pData)
+ mir_free(pData);
+ }
+
+ NETLIBHTTPREQUEST* Send(HNETLIBUSER hConnection)
+ {
+ m_szUrl.Replace('\\', '/');
+ szUrl = m_szUrl.GetBuffer();
+ return Netlib_HttpTransaction(hConnection, this);
+ }
+};
+
+#endif //_HTTP_REQUEST_H_ \ No newline at end of file
diff --git a/protocols/CloudFile/src/icons.cpp b/protocols/CloudFile/src/icons.cpp
new file mode 100644
index 0000000000..001df50240
--- /dev/null
+++ b/protocols/CloudFile/src/icons.cpp
@@ -0,0 +1,39 @@
+#include "stdafx.h"
+
+static IconItem iconList[] =
+{
+ { LPGEN("Upload file(s)"), "upload", IDI_UPLOAD },
+ { LPGEN("Dropbox"), "dropbox", IDI_DROPBOX },
+ { LPGEN("Google Drive"), "gdrive", IDI_GDRIVE },
+ { LPGEN("OneDrive"), "onedrive", IDI_ONEDRIVE },
+ { LPGEN("Yandex.Disk"), "yadisk", IDI_YADISK }
+};
+
+void InitializeIcons()
+{
+ g_plugin.registerIcon("Protocols/" MODULENAME, iconList, MODULENAME);
+}
+
+HANDLE GetIconHandle(int iconId)
+{
+ for (auto &it : iconList)
+ if (it.defIconID == iconId)
+ return it.hIcolib;
+ return nullptr;
+}
+
+HANDLE GetIconHandle(const char *name)
+{
+ for (auto &it : iconList)
+ if (mir_strcmpi(it.szName, name) == 0)
+ return it.hIcolib;
+ return nullptr;
+}
+
+HICON LoadIconEx(int iconId, bool big)
+{
+ for (auto &it : iconList)
+ if (it.defIconID == iconId)
+ return IcoLib_GetIconByHandle(it.hIcolib, big);
+ return nullptr;
+} \ No newline at end of file
diff --git a/protocols/CloudFile/src/main.cpp b/protocols/CloudFile/src/main.cpp
new file mode 100644
index 0000000000..2b9ffd6c2d
--- /dev/null
+++ b/protocols/CloudFile/src/main.cpp
@@ -0,0 +1,42 @@
+#include "stdafx.h"
+
+CMPlugin g_plugin;
+
+PLUGININFOEX pluginInfoEx =
+{
+ sizeof(PLUGININFOEX),
+ __PLUGIN_NAME,
+ PLUGIN_MAKE_VERSION(__MAJOR_VERSION, __MINOR_VERSION, __RELEASE_NUM, __BUILD_NUM),
+ __DESCRIPTION,
+ __AUTHOR,
+ __COPYRIGHT,
+ __AUTHORWEB,
+ UNICODE_AWARE,
+ // {E876FE63-0701-4CDA-BED5-7C73A379C1D1}
+ { 0xe876fe63, 0x701, 0x4cda, { 0xbe, 0xd5, 0x7c, 0x73, 0xa3, 0x79, 0xc1, 0xd1 }}
+};
+
+CMPlugin::CMPlugin() :
+ PLUGIN<CMPlugin>(MODULENAME, pluginInfoEx)
+{}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// Interface information
+
+extern "C" __declspec(dllexport) const MUUID MirandaInterfaces[] = { MIID_PROTOCOL, MIID_LAST };
+
+/////////////////////////////////////////////////////////////////////////////////////////
+
+int CMPlugin::Load()
+{
+ HookEvent(ME_CLIST_PREBUILDCONTACTMENU, OnPrebuildContactMenu);
+ HookEvent(ME_MSG_WINDOWEVENT, OnSrmmWindowOpened);
+ HookEvent(ME_MSG_BUTTONPRESSED, OnSrmmButtonPressed);
+ HookEvent(ME_OPT_INITIALISE, OnOptionsInitialized);
+ HookEvent(ME_SYSTEM_MODULESLOADED, OnModulesLoaded);
+
+ InitializeIcons();
+ InitializeServices();
+
+ return 0;
+}
diff --git a/protocols/CloudFile/src/menus.cpp b/protocols/CloudFile/src/menus.cpp
new file mode 100644
index 0000000000..3ca1b085b9
--- /dev/null
+++ b/protocols/CloudFile/src/menus.cpp
@@ -0,0 +1,52 @@
+#include "stdafx.h"
+
+HGENMENU hContactMenu;
+
+static INT_PTR UploadMenuCommand(void *obj, WPARAM hContact, LPARAM)
+{
+ CCloudService *service = (CCloudService*)obj;
+ service->OpenUploadDialog(hContact);
+ return 0;
+}
+
+void InitializeMenus()
+{
+ CMenuItem mi(&g_plugin);
+ SET_UID(mi, 0x93d4495b, 0x259b, 0x4fba, 0xbc, 0x14, 0xf9, 0x46, 0x2c, 0xda, 0xfc, 0x6d);
+ mi.name.a = LPGEN("Upload to...");
+
+ ptrA defaultService(g_plugin.getStringA("DefaultService"));
+ if (defaultService) {
+ CCloudService *service = FindService(defaultService);
+ if (service) {
+ mi.name.a = LPGEN("Upload");
+ mi.pszService = MODULENAME "/Default/Upload";
+ CreateServiceFunctionObj(mi.pszService, UploadMenuCommand, service);
+ }
+ }
+
+ mi.position = -2000019999;
+ mi.hIcon = LoadIconEx(IDI_UPLOAD);
+ hContactMenu = Menu_AddContactMenuItem(&mi);
+}
+
+void CCloudService::OnModulesLoaded()
+{
+ CMenuItem mi(GetId());
+ mi.root = hContactMenu;
+ CMStringA serviceName(FORMAT, "/%s/Upload", GetAccountName());
+ mi.pszService = serviceName.GetBuffer();
+ mi.flags = CMIF_SYSTEM | CMIF_UNICODE;
+ mi.name.w = (wchar_t*)GetUserName();
+ mi.position = Services.getCount();
+ mi.hIcolibItem = GetIconHandle(GetIconId());
+ Menu_AddContactMenuItem(&mi);
+
+ CreateServiceFunctionObj(mi.pszService, UploadMenuCommand, this);
+}
+
+int OnPrebuildContactMenu(WPARAM hContact, LPARAM)
+{
+ Menu_ShowItem(hContactMenu, CanSendToContact(hContact));
+ return 0;
+}
diff --git a/protocols/CloudFile/src/oauth.cpp b/protocols/CloudFile/src/oauth.cpp
new file mode 100644
index 0000000000..e62629fcd8
--- /dev/null
+++ b/protocols/CloudFile/src/oauth.cpp
@@ -0,0 +1,33 @@
+#include "stdafx.h"
+
+COAuthDlg::COAuthDlg(CCloudService *service, const char *authUrl, CCloudService::MyThreadFunc requestAccessTokenThread)
+ : CDlgBase(g_plugin, IDD_OAUTH), m_service(service),
+ m_requestAccessTokenThread(requestAccessTokenThread),
+ m_authorize(this, IDC_OAUTH_AUTHORIZE, authUrl),
+ m_code(this, IDC_OAUTH_CODE), m_ok(this, IDOK)
+{
+ m_autoClose = CLOSE_ON_CANCEL;
+ m_code.OnChange = Callback(this, &COAuthDlg::Code_OnChange);
+ m_ok.OnClick = Callback(this, &COAuthDlg::Ok_OnClick);
+}
+
+bool COAuthDlg::OnInitDialog()
+{
+ CCtrlLabel &ctrl = *(CCtrlLabel*)FindControl(IDC_AUTH_TEXT);
+ ptrW format(ctrl.GetText());
+ wchar_t text[MAX_PATH];
+ mir_snwprintf(text, (const wchar_t*)format, m_service->GetUserName());
+ ctrl.SetText(text);
+ return true;
+}
+
+void COAuthDlg::Code_OnChange(CCtrlBase*)
+{
+ ptrA requestToken(m_code.GetTextA());
+ m_ok.Enable(mir_strlen(requestToken) != 0);
+}
+
+void COAuthDlg::Ok_OnClick(CCtrlButton*)
+{
+ m_service->ForkThread(m_requestAccessTokenThread, m_hwnd);
+} \ No newline at end of file
diff --git a/protocols/CloudFile/src/oauth.h b/protocols/CloudFile/src/oauth.h
new file mode 100644
index 0000000000..2b32ecbd9b
--- /dev/null
+++ b/protocols/CloudFile/src/oauth.h
@@ -0,0 +1,23 @@
+#ifndef _OAUTH_H_
+#define _OAUTH_H_
+
+class COAuthDlg : public CDlgBase
+{
+ CCloudService *m_service;
+ CCloudService::MyThreadFunc m_requestAccessTokenThread;
+
+ CCtrlHyperlink m_authorize;
+ CCtrlEdit m_code;
+ CCtrlButton m_ok;
+
+protected:
+ bool OnInitDialog() override;
+
+ void Code_OnChange(CCtrlBase*);
+ void Ok_OnClick(CCtrlButton*);
+
+public:
+ COAuthDlg(CCloudService *service, const char *authUrl, CCloudService::MyThreadFunc requestAccessTokenThread);
+};
+
+#endif //_OAUTH_H_ \ No newline at end of file
diff --git a/protocols/CloudFile/src/options.cpp b/protocols/CloudFile/src/options.cpp
new file mode 100644
index 0000000000..0ac7c120a0
--- /dev/null
+++ b/protocols/CloudFile/src/options.cpp
@@ -0,0 +1,124 @@
+#include "stdafx.h"
+
+COptionsMainDlg::COptionsMainDlg()
+ : CDlgBase(g_plugin, IDD_OPTIONS_MAIN),
+ m_defaultService(this, IDC_DEFAULTSERVICE),
+ m_doNothingOnConflict(this, IDC_DONOTHINGONCONFLICT),
+ m_renameOnConflict(this, IDC_RENAMEONCONFLICT),
+ m_repalceOnConflict(this, IDC_REPLACEONCONFLICT),
+ m_urlAutoSend(this, IDC_URL_AUTOSEND),
+ m_urlPasteToMessageInputArea(this, IDC_URL_COPYTOMIA),
+ m_urlCopyToClipboard(this, IDC_URL_COPYTOCB)
+{
+ CreateLink(m_defaultService, "DefaultService", L"");
+
+ CreateLink(m_urlAutoSend, "UrlAutoSend", DBVT_BYTE, 1);
+ CreateLink(m_urlPasteToMessageInputArea, "UrlPasteToMessageInputArea", DBVT_BYTE, 0);
+ CreateLink(m_urlCopyToClipboard, "UrlCopyToClipboard", DBVT_BYTE, 0);
+}
+
+bool COptionsMainDlg::OnInitDialog()
+{
+ CDlgBase::OnInitDialog();
+
+ ptrA defaultService(g_plugin.getStringA("DefaultService"));
+ int iItem = m_defaultService.AddString(TranslateT("None"));
+ m_defaultService.SetCurSel(iItem);
+
+ for (auto &service : Services) {
+ iItem = m_defaultService.AddString(mir_wstrdup(service->GetUserName()), (LPARAM)service);
+ if (!mir_strcmpi(service->GetAccountName(), defaultService))
+ m_defaultService.SetCurSel(iItem);
+ }
+
+ BYTE strategy = g_plugin.getByte("ConflictStrategy", OnConflict::REPLACE);
+ switch (strategy)
+ {
+ case OnConflict::RENAME:
+ m_renameOnConflict.SetState(TRUE);
+ m_repalceOnConflict.SetState(FALSE);
+ m_doNothingOnConflict.SetState(FALSE);
+ break;
+ case OnConflict::REPLACE:
+ m_renameOnConflict.SetState(FALSE);
+ m_repalceOnConflict.SetState(TRUE);
+ m_doNothingOnConflict.SetState(FALSE);
+ break;
+ default:
+ m_renameOnConflict.SetState(FALSE);
+ m_repalceOnConflict.SetState(FALSE);
+ m_doNothingOnConflict.SetState(TRUE);
+ break;
+ }
+ return true;
+}
+
+bool COptionsMainDlg::OnApply()
+{
+ int iItem = m_defaultService.GetCurSel();
+ CCloudService *service = (CCloudService*)m_defaultService.GetItemData(iItem);
+ if (service)
+ g_plugin.setString("DefaultService", service->GetAccountName());
+ else
+ g_plugin.delSetting("DefaultService");
+
+ if (m_renameOnConflict.GetState())
+ g_plugin.setByte("ConflictStrategy", OnConflict::RENAME);
+ else if (m_repalceOnConflict.GetState())
+ g_plugin.setByte("ConflictStrategy", OnConflict::REPLACE);
+ else
+ g_plugin.delSetting("ConflictStrategy");
+ return true;
+}
+
+/////////////////////////////////////////////////////////////////////////////////
+
+int OnOptionsInitialized(WPARAM wParam, LPARAM)
+{
+ OPTIONSDIALOGPAGE odp = {};
+ odp.szTitle.w = _A2W(MODULENAME);
+ odp.flags = ODPF_BOLDGROUPS | ODPF_UNICODE | ODPF_DONTTRANSLATE;
+ odp.szGroup.w = LPGENW("Services");
+
+ //odp.szTab.w = LPGENW("General");
+ odp.pDialog = new COptionsMainDlg();
+ g_plugin.addOptions(wParam, &odp);
+
+ return 0;
+}
+
+/////////////////////////////////////////////////////////////////////////////////
+
+CAccountManagerDlg::CAccountManagerDlg(CCloudService *service)
+ : CProtoDlgBase(service, IDD_ACCMGR),
+ m_requestAccess(this, IDC_REQUESTACCESS),
+ m_revokeAccess(this, IDC_REVOKEACCESS)
+{
+ m_requestAccess.OnClick = Callback(this, &CAccountManagerDlg::RequestAccess_OnClick);
+ m_revokeAccess.OnClick = Callback(this, &CAccountManagerDlg::RevokeAccess_OnClick);
+}
+
+bool CAccountManagerDlg::OnInitDialog()
+{
+ ptrA token(m_proto->getStringA("TokenSecret"));
+ m_requestAccess.Enable(!token);
+ m_revokeAccess.Enable(token);
+ return true;
+}
+
+void CAccountManagerDlg::RequestAccess_OnClick(CCtrlButton*)
+{
+ m_proto->Login(m_hwnd);
+ ptrA token(m_proto->getStringA("TokenSecret"));
+ m_requestAccess.Enable(!token);
+ m_revokeAccess.Enable(token);
+}
+
+void CAccountManagerDlg::RevokeAccess_OnClick(CCtrlButton*)
+{
+ m_proto->Logout();
+ m_requestAccess.Enable();
+ m_revokeAccess.Disable();
+}
+
+/////////////////////////////////////////////////////////////////////////////////
diff --git a/protocols/CloudFile/src/options.h b/protocols/CloudFile/src/options.h
new file mode 100644
index 0000000000..aaf1440def
--- /dev/null
+++ b/protocols/CloudFile/src/options.h
@@ -0,0 +1,43 @@
+#ifndef _OPTIONS_H_
+#define _OPTIONS_H_
+
+class COptionsMainDlg : public CDlgBase
+{
+private:
+ CCtrlCombo m_defaultService;
+
+ CCtrlCheck m_doNothingOnConflict;
+ CCtrlCheck m_renameOnConflict;
+ CCtrlCheck m_repalceOnConflict;
+
+ CCtrlCheck m_urlAutoSend;
+ CCtrlCheck m_urlPasteToMessageInputArea;
+ CCtrlCheck m_urlCopyToClipboard;
+
+protected:
+ bool OnInitDialog() override;
+ bool OnApply() override;
+
+public:
+ COptionsMainDlg();
+};
+
+/////////////////////////////////////////////////////////////////////////////////
+
+class CAccountManagerDlg : public CProtoDlgBase<CCloudService>
+{
+private:
+ CCtrlButton m_requestAccess;
+ CCtrlButton m_revokeAccess;
+
+protected:
+ bool OnInitDialog() override;
+
+ void RequestAccess_OnClick(CCtrlButton*);
+ void RevokeAccess_OnClick(CCtrlButton*);
+
+public:
+ CAccountManagerDlg(CCloudService *service);
+};
+
+#endif //_OPTIONS_H_ \ No newline at end of file
diff --git a/protocols/CloudFile/src/resource.h b/protocols/CloudFile/src/resource.h
new file mode 100644
index 0000000000..d839f15da4
--- /dev/null
+++ b/protocols/CloudFile/src/resource.h
@@ -0,0 +1,38 @@
+//{{NO_DEPENDENCIES}}
+// Microsoft Visual C++ generated include file.
+// Used by D:\Projects\miranda-ng\miranda-ng\plugins\CloudFile\res\resource.rc
+//
+#define IDOK 1
+#define IDCANCEL 2
+#define IDD_ACCMGR 9
+#define IDI_UPLOAD 101
+#define IDI_DROPBOX 102
+#define IDI_GDRIVE 103
+#define IDI_ONEDRIVE 104
+#define IDI_YADISK 105
+#define IDD_OAUTH 120
+#define IDC_OAUTH_CODE 121
+#define IDC_OAUTH_AUTHORIZE 122
+#define IDD_OPTIONS_MAIN 1000
+#define IDC_DEFAULTSERVICE 1001
+#define IDC_DONOTHINGONCONFLICT 1010
+#define IDC_RENAMEONCONFLICT 1011
+#define IDC_REPLACEONCONFLICT 1012
+#define IDC_URL_ISTEMPORARY 1021
+#define IDC_URL_COPYTOCB 1022
+#define IDC_URL_COPYTOMIA 1023
+#define IDC_URL_AUTOSEND 1024
+#define IDC_AUTH_TEXT 1031
+#define IDC_REQUESTACCESS 1033
+#define IDC_REVOKEACCESS 1034
+
+// Next default values for new objects
+//
+#ifdef APSTUDIO_INVOKED
+#ifndef APSTUDIO_READONLY_SYMBOLS
+#define _APS_NEXT_RESOURCE_VALUE 133
+#define _APS_NEXT_COMMAND_VALUE 40001
+#define _APS_NEXT_CONTROL_VALUE 1034
+#define _APS_NEXT_SYMED_VALUE 101
+#endif
+#endif
diff --git a/protocols/CloudFile/src/services.cpp b/protocols/CloudFile/src/services.cpp
new file mode 100644
index 0000000000..e0a01fbfba
--- /dev/null
+++ b/protocols/CloudFile/src/services.cpp
@@ -0,0 +1,106 @@
+#include "stdafx.h"
+
+static int CompareServices(const CCloudService *p1, const CCloudService *p2)
+{
+ return mir_strcmp(p1->GetAccountName(), p2->GetAccountName());
+}
+
+LIST<CCloudService> Services(10, CompareServices);
+
+CCloudService* FindService(const char *szProto)
+{
+ for (auto &it : Services)
+ if (!mir_strcmp(it->GetAccountName(), szProto))
+ return it;
+
+ return nullptr;
+}
+
+static INT_PTR GetService(WPARAM wParam, LPARAM lParam)
+{
+ CFSERVICEINFO *info = (CFSERVICEINFO*)lParam;
+ if (info == nullptr)
+ return 1;
+
+ ptrA accountName(mir_strdup((char*)wParam));
+ if (!accountName || !mir_strlen(accountName))
+ accountName = g_plugin.getStringA("DefaultService");
+ if (accountName == nullptr)
+ return 2;
+
+ CCloudService *service = FindService(accountName);
+ if (service == nullptr)
+ return 3;
+
+ info->accountName = service->GetAccountName();
+ info->userName = service->GetUserName();
+
+ return 0;
+}
+
+static INT_PTR EnumServices(WPARAM wParam, LPARAM lParam)
+{
+ CFSERVICEINFO info = {};
+ enumCFServiceFunc enumFunc = (enumCFServiceFunc)wParam;
+ void *param = (void*)lParam;
+
+ for (auto &service : Services) {
+ info.accountName = service->GetAccountName();
+ info.userName = service->GetUserName();
+ int res = enumFunc(&info, param);
+ if (res != 0)
+ return res;
+ }
+
+ return 0;
+}
+
+INT_PTR Upload(WPARAM wParam, LPARAM lParam)
+{
+ CFUPLOADDATA *uploadData = (CFUPLOADDATA*)wParam;
+ if (uploadData == nullptr)
+ return 1;
+
+ ptrA accountName(mir_strdup(uploadData->accountName));
+ if (!mir_strlen(accountName))
+ accountName = g_plugin.getStringA("DefaultService");
+ if (accountName == nullptr)
+ return 2;
+
+ CCloudService *service = FindService(uploadData->accountName);
+ if (service == nullptr)
+ return 3;
+
+ if (PathIsDirectory(uploadData->localPath)) {
+ // temporary unsupported
+ return 4;
+ }
+
+ FileTransferParam ftp(0);
+ ftp.SetWorkingDirectory(uploadData->localPath);
+ ftp.SetServerDirectory(uploadData->serverFolder);
+ ftp.AddFile(uploadData->localPath);
+
+ int res = CCloudService::Upload(service, &ftp);
+ if (res == ACKRESULT_SUCCESS && lParam) {
+ size_t linkCount = 0;
+ const char **links = ftp.GetSharedLinks(linkCount);
+ if (linkCount > 0) {
+ CFUPLOADRESULT *result = (CFUPLOADRESULT*)lParam;
+ result->link = mir_strdup(links[linkCount - 1]);
+ }
+ }
+
+ return res;
+}
+
+void InitializeServices()
+{
+ Proto_RegisterModule(PROTOTYPE_FILTER, MODULENAME);
+
+ CreateServiceFunction(MODULENAME PSS_FILE, SendFileInterceptor);
+
+ CreateServiceFunction(MS_CLOUDFILE_GETSERVICE, GetService);
+ CreateServiceFunction(MS_CLOUDFILE_ENUMSERVICES, EnumServices);
+ CreateServiceFunction(MS_CLOUDFILE_UPLOAD, Upload);
+}
diff --git a/protocols/CloudFile/src/srmm.cpp b/protocols/CloudFile/src/srmm.cpp
new file mode 100644
index 0000000000..b4d44c9fdd
--- /dev/null
+++ b/protocols/CloudFile/src/srmm.cpp
@@ -0,0 +1,67 @@
+#include "stdafx.h"
+
+int OnSrmmToolbarLoaded(WPARAM, LPARAM)
+{
+ BBButton bbd = {};
+ bbd.pszModuleName = MODULENAME;
+ bbd.bbbFlags = BBBF_ISIMBUTTON | BBBF_ISCHATBUTTON | BBBF_ISRSIDEBUTTON | BBBF_ISARROWBUTTON;
+
+ CMStringW tooltip(FORMAT, TranslateT("Upload files to..."));
+ bbd.pwszTooltip = tooltip;
+ bbd.hIcon = GetIconHandle(IDI_UPLOAD);
+ bbd.dwButtonID = BBB_ID_FILE_SEND;
+ bbd.dwDefPos = 100 + bbd.dwButtonID;
+ Srmm_AddButton(&bbd, &g_plugin);
+ return 0;
+}
+
+int OnSrmmWindowOpened(WPARAM, LPARAM lParam)
+{
+ MessageWindowEventData *ev = (MessageWindowEventData*)lParam;
+ if (ev->uType == MSG_WINDOW_EVT_OPENING && ev->hContact) {
+ BBButton bbd = {};
+ bbd.pszModuleName = MODULENAME;
+ bbd.dwButtonID = BBB_ID_FILE_SEND;
+ bbd.bbbFlags = CanSendToContact(ev->hContact)
+ ? BBSF_RELEASED
+ : BBSF_DISABLED;
+ Srmm_SetButtonState(ev->hContact, &bbd);
+ }
+
+ return 0;
+}
+
+int OnSrmmButtonPressed(WPARAM, LPARAM lParam)
+{
+ CustomButtonClickData *cbc = (CustomButtonClickData*)lParam;
+
+ if (mir_strcmp(cbc->pszModule, MODULENAME))
+ return 0;
+
+ if (cbc->dwButtonId != BBB_ID_FILE_SEND)
+ return 0;
+
+ if (cbc->flags != BBCF_ARROWCLICKED) {
+ ptrA defaultService(g_plugin.getStringA("DefaultService"));
+ if (defaultService) {
+ CCloudService *service = FindService(defaultService);
+ if (service)
+ service->OpenUploadDialog(cbc->hContact);
+ return 0;
+ }
+ }
+
+ HMENU hMenu = CreatePopupMenu();
+ for (auto &it : Services)
+ AppendMenu(hMenu, MF_STRING, Services.indexOf(&it) + 1, TranslateW(it->GetUserName()));
+
+ int pos = TrackPopupMenu(hMenu, TPM_RETURNCMD, cbc->pt.x, cbc->pt.y, 0, cbc->hwndFrom, nullptr);
+ DestroyMenu(hMenu);
+
+ if (pos > 0) {
+ CCloudService *service = Services[pos - 1];
+ service->OpenUploadDialog(cbc->hContact);
+ }
+
+ return 0;
+} \ No newline at end of file
diff --git a/protocols/CloudFile/src/stdafx.cxx b/protocols/CloudFile/src/stdafx.cxx
new file mode 100644
index 0000000000..708e6f1c91
--- /dev/null
+++ b/protocols/CloudFile/src/stdafx.cxx
@@ -0,0 +1,20 @@
+/*
+Copyright (C) 2012-19 Miranda NG team (https://miranda-ng.org)
+
+This program is free software; you can redistribute it and/or
+modify it under the terms of the GNU General Public License
+as published by the Free Software Foundation version 2
+of the License.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "stdafx.h"
+
+ULONG FileTransferParam::hFileProcess = 1; \ No newline at end of file
diff --git a/protocols/CloudFile/src/stdafx.h b/protocols/CloudFile/src/stdafx.h
new file mode 100644
index 0000000000..58801c4a34
--- /dev/null
+++ b/protocols/CloudFile/src/stdafx.h
@@ -0,0 +1,126 @@
+#ifndef _COMMON_H_
+#define _COMMON_H_
+
+#include <windows.h>
+#include <shlwapi.h>
+#include <commctrl.h>
+
+#include <malloc.h>
+#include <time.h>
+
+#include <map>
+#include <algorithm>
+
+#include <newpluginapi.h>
+
+#include <m_options.h>
+#include <m_database.h>
+#include <m_netlib.h>
+#include <m_clist.h>
+#include <m_icolib.h>
+#include <m_popup.h>
+#include <m_file.h>
+#include <m_langpack.h>
+#include <m_message.h>
+#include <m_gui.h>
+#include <m_chat.h>
+#include <m_http.h>
+#include <m_json.h>
+#include <m_metacontacts.h>
+#include <m_protoint.h>
+#include <m_protosvc.h>
+#include <m_contacts.h>
+
+#include <m_cloudfile.h>
+
+#include "version.h"
+#include "resource.h"
+
+class CCloudService;
+
+#include "options.h"
+
+extern HNETLIBUSER hNetlibConnection;
+extern PLUGININFOEX pluginInfoEx;
+
+class Exception
+{
+ CMStringA message;
+
+public:
+ Exception(const char *message) :
+ message(message)
+ {
+ }
+
+ const char* what() const throw()
+ {
+ return message.c_str();
+ }
+};
+
+#define MODULENAME "CloudFile"
+
+#define FILE_CHUNK_SIZE 1024 * 1024 //1 MB
+
+#include "http_request.h"
+#include "file_transfer.h"
+
+// services
+#include "cloud_file.h"
+#include "oauth.h"
+#include "Services\dropbox_service.h"
+#include "Services\google_service.h"
+#include "Services\microsoft_service.h"
+#include "Services\yandex_service.h"
+extern LIST<CCloudService> Services;
+void InitializeServices();
+
+// events
+int OnModulesLoaded(WPARAM, LPARAM);
+
+// icons
+void InitializeIcons();
+HANDLE GetIconHandle(int iconId);
+HANDLE GetIconHandle(const char *name);
+HICON LoadIconEx(int iconId, bool big = false);
+
+// menus
+extern HGENMENU hContactMenu;
+void InitializeMenus();
+int OnPrebuildContactMenu(WPARAM, LPARAM);
+
+// srmm
+#define BBB_ID_FILE_SEND 10001
+int OnSrmmToolbarLoaded(WPARAM, LPARAM);
+int OnSrmmWindowOpened(WPARAM, LPARAM);
+int OnSrmmButtonPressed(WPARAM, LPARAM);
+
+// options
+int OnOptionsInitialized(WPARAM wParam, LPARAM);
+
+// transfers
+extern LIST<FileTransferParam> Transfers;
+
+INT_PTR SendFileInterceptor(WPARAM wParam, LPARAM lParam);
+UINT UploadAndReportProgressThread(void *owner, void *arg);
+
+// utils
+void ShowNotification(const wchar_t *caption, const wchar_t *message, int flags, MCONTACT hContact = NULL);
+void ShowNotification(const wchar_t *message, int flags, MCONTACT hContact = NULL);
+bool CanSendToContact(MCONTACT hContact);
+void SendToContact(MCONTACT hContact, const wchar_t *data);
+void PasteToInputArea(MCONTACT hContact, const wchar_t *data);
+void PasteToClipboard(const wchar_t *data);
+void Report(MCONTACT hContact, const wchar_t *data);
+
+CCloudService* FindService(const char *szProto);
+
+struct CMPlugin : public PLUGIN<CMPlugin>
+{
+ CMPlugin();
+
+ int Load() override;
+};
+
+#endif //_COMMON_H_ \ No newline at end of file
diff --git a/protocols/CloudFile/src/transfers.cpp b/protocols/CloudFile/src/transfers.cpp
new file mode 100644
index 0000000000..5236e0c9f0
--- /dev/null
+++ b/protocols/CloudFile/src/transfers.cpp
@@ -0,0 +1,39 @@
+#include "stdafx.h"
+
+LIST<FileTransferParam> Transfers(1, HandleKeySortT);
+
+INT_PTR SendFileInterceptor(WPARAM, LPARAM lParam)
+{
+ CCSDATA *pccsd = (CCSDATA*)lParam;
+ for (auto &service : Services) {
+ auto it = service->InterceptedContacts.find(pccsd->hContact);
+ if (it == service->InterceptedContacts.end())
+ continue;
+ service->InterceptedContacts.erase(it);
+ return (INT_PTR)service->SendFile(pccsd->hContact, (wchar_t*)pccsd->wParam, (wchar_t**)pccsd->lParam);
+ }
+ return CALLSERVICE_NOTFOUND;
+}
+
+UINT UploadAndReportProgressThread(void *owner, void *arg)
+{
+ CCloudService *service = (CCloudService*)owner;
+ FileTransferParam *ftp = (FileTransferParam*)arg;
+
+ int res = CCloudService::Upload(service, ftp);
+ if (res == ACKRESULT_SUCCESS) {
+ CMStringW data = ftp->GetDescription();
+ size_t linkCount;
+ auto links = ftp->GetSharedLinks(linkCount);
+ for (size_t i = 0; i < linkCount; i++) {
+ data.Append(ptrW(mir_utf8decodeW(links[i])));
+ data.AppendChar(0x0A);
+ }
+ Report(ftp->GetContact(), data);
+ }
+
+ Transfers.remove(ftp);
+ delete ftp;
+
+ return res;
+}
diff --git a/protocols/CloudFile/src/utils.cpp b/protocols/CloudFile/src/utils.cpp
new file mode 100644
index 0000000000..79b743f5c2
--- /dev/null
+++ b/protocols/CloudFile/src/utils.cpp
@@ -0,0 +1,113 @@
+#include "stdafx.h"
+
+void ShowNotification(const wchar_t *caption, const wchar_t *message, int flags, MCONTACT hContact)
+{
+ if (Miranda_IsTerminated())
+ return;
+
+ if (ServiceExists(MS_POPUP_ADDPOPUPW) && db_get_b(0, "Popup", "ModuleIsEnabled", 1)) {
+ POPUPDATAW ppd = { 0 };
+ ppd.lchContact = hContact;
+ wcsncpy(ppd.lpwzContactName, caption, MAX_CONTACTNAME);
+ wcsncpy(ppd.lpwzText, message, MAX_SECONDLINE);
+ ppd.lchIcon = IcoLib_GetIcon("Slack_main");
+
+ if (!PUAddPopupW(&ppd))
+ return;
+ }
+
+ MessageBox(nullptr, message, caption, MB_OK | flags);
+}
+
+void ShowNotification(const wchar_t *message, int flags, MCONTACT hContact)
+{
+ ShowNotification(_A2W(MODULENAME), message, flags, hContact);
+}
+
+MEVENT AddEventToDb(MCONTACT hContact, WORD type, DWORD flags, DWORD cbBlob, PBYTE pBlob)
+{
+ DBEVENTINFO dbei = {};
+ dbei.szModule = MODULENAME;
+ dbei.timestamp = time(0);
+ dbei.eventType = type;
+ dbei.cbBlob = cbBlob;
+ dbei.pBlob = pBlob;
+ dbei.flags = flags;
+ return db_event_add(hContact, &dbei);
+}
+
+bool CanSendToContact(MCONTACT hContact)
+{
+ if (!hContact)
+ return false;
+
+ const char *proto = GetContactProto(hContact);
+ if (!proto)
+ return false;
+
+ bool isCtrlPressed = (GetKeyState(VK_CONTROL) & 0x8000) != 0;
+ if (isCtrlPressed)
+ return true;
+
+ bool canSend = (CallProtoService(proto, PS_GETCAPS, PFLAGNUM_1, 0) & PF1_IMSEND) != 0;
+ if (!canSend)
+ return false;
+
+ bool isProtoOnline = Proto_GetStatus(proto) > ID_STATUS_OFFLINE;
+ if (!isProtoOnline)
+ return false;
+
+ bool isContactOnline = Contact_GetStatus(hContact) > ID_STATUS_OFFLINE;
+ if (isContactOnline)
+ return true;
+
+ return CallProtoService(proto, PS_GETCAPS, PFLAGNUM_4, 0) & PF4_IMSENDOFFLINE;
+}
+
+void SendToContact(MCONTACT hContact, const wchar_t *data)
+{
+ const char *szProto = GetContactProto(hContact);
+ if (db_get_b(hContact, szProto, "ChatRoom", 0) == TRUE) {
+ ptrW tszChatRoom(db_get_wsa(hContact, szProto, "ChatRoomID"));
+ Chat_SendUserMessage(szProto, tszChatRoom, data);
+ return;
+ }
+
+ char *message = mir_utf8encodeW(data);
+ if (ProtoChainSend(hContact, PSS_MESSAGE, 0, (LPARAM)message) != ACKRESULT_FAILED)
+ AddEventToDb(hContact, EVENTTYPE_MESSAGE, DBEF_UTF | DBEF_SENT, (DWORD)mir_strlen(message), (PBYTE)message);
+}
+
+void PasteToInputArea(MCONTACT hContact, const wchar_t *data)
+{
+ CallService(MS_MSG_SENDMESSAGEW, hContact, (LPARAM)data);
+}
+
+void PasteToClipboard(const wchar_t *data)
+{
+ if (OpenClipboard(nullptr)) {
+ EmptyClipboard();
+
+ size_t size = sizeof(wchar_t) * (mir_wstrlen(data) + 1);
+ HGLOBAL hClipboardData = GlobalAlloc(NULL, size);
+ if (hClipboardData) {
+ wchar_t *pchData = (wchar_t*)GlobalLock(hClipboardData);
+ mir_wstrcpy(pchData, data);
+ GlobalUnlock(hClipboardData);
+ SetClipboardData(CF_UNICODETEXT, hClipboardData);
+ }
+ CloseClipboard();
+ }
+}
+
+void Report(MCONTACT hContact, const wchar_t *data)
+{
+ if (g_plugin.getByte("UrlAutoSend", 1))
+ SendToContact(hContact, data);
+
+ if (g_plugin.getByte("UrlPasteToMessageInputArea", 0))
+ PasteToInputArea(hContact, data);
+
+ if (g_plugin.getByte("UrlCopyToClipboard", 0))
+ PasteToClipboard(data);
+}
diff --git a/protocols/CloudFile/src/version.h b/protocols/CloudFile/src/version.h
new file mode 100644
index 0000000000..fbc4ce1219
--- /dev/null
+++ b/protocols/CloudFile/src/version.h
@@ -0,0 +1,13 @@
+#define __MAJOR_VERSION 0
+#define __MINOR_VERSION 11
+#define __RELEASE_NUM 0
+#define __BUILD_NUM 6
+
+#include <stdver.h>
+
+#define __PLUGIN_NAME "CloudFile"
+#define __FILENAME "CloudFile.dll"
+#define __DESCRIPTION "Allows you to transfer files via cloud services."
+#define __AUTHOR "Miranda NG team"
+#define __AUTHORWEB "https://miranda-ng.org/p/CloudFile/"
+#define __COPYRIGHT "© 2017-19 Miranda NG team"
diff --git a/protocols/ConnectionNotify/ConnectionNotify.vcxproj b/protocols/ConnectionNotify/ConnectionNotify.vcxproj
new file mode 100644
index 0000000000..ff0dd01946
--- /dev/null
+++ b/protocols/ConnectionNotify/ConnectionNotify.vcxproj
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <ItemGroup Label="ProjectConfigurations">
+ <ProjectConfiguration Include="Debug|Win32">
+ <Configuration>Debug</Configuration>
+ <Platform>Win32</Platform>
+ </ProjectConfiguration>
+ <ProjectConfiguration Include="Debug|x64">
+ <Configuration>Debug</Configuration>
+ <Platform>x64</Platform>
+ </ProjectConfiguration>
+ <ProjectConfiguration Include="Release|Win32">
+ <Configuration>Release</Configuration>
+ <Platform>Win32</Platform>
+ </ProjectConfiguration>
+ <ProjectConfiguration Include="Release|x64">
+ <Configuration>Release</Configuration>
+ <Platform>x64</Platform>
+ </ProjectConfiguration>
+ </ItemGroup>
+ <PropertyGroup Label="Globals">
+ <ProjectGuid>{3C83B0AB-9739-41C1-A127-ED7DB9551F76}</ProjectGuid>
+ <ProjectName>ConnectionNotify</ProjectName>
+ </PropertyGroup>
+ <ImportGroup Label="PropertySheets">
+ <Import Project="$(ProjectDir)..\..\build\vc.common\plugin.props" />
+ </ImportGroup>
+</Project> \ No newline at end of file
diff --git a/protocols/ConnectionNotify/ConnectionNotify.vcxproj.filters b/protocols/ConnectionNotify/ConnectionNotify.vcxproj.filters
new file mode 100644
index 0000000000..8f90aeb3d5
--- /dev/null
+++ b/protocols/ConnectionNotify/ConnectionNotify.vcxproj.filters
@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <Import Project="$(ProjectDir)..\..\build\vc.common\common.filters" />
+</Project>
diff --git a/protocols/ConnectionNotify/docs/connectionnotify.png b/protocols/ConnectionNotify/docs/connectionnotify.png
new file mode 100644
index 0000000000..95288d0cce
--- /dev/null
+++ b/protocols/ConnectionNotify/docs/connectionnotify.png
Binary files differ
diff --git a/protocols/ConnectionNotify/res/ConnectionNotify.rc b/protocols/ConnectionNotify/res/ConnectionNotify.rc
new file mode 100644
index 0000000000..02c9c74d0a
--- /dev/null
+++ b/protocols/ConnectionNotify/res/ConnectionNotify.rc
@@ -0,0 +1,96 @@
+// Generated by ResEdit 1.5.11
+// Copyright (C) 2006-2012
+// http://www.resedit.net
+
+#include <windows.h>
+#include <commctrl.h>
+#include <richedit.h>
+#include "..\src\resource.h"
+#include "..\src\version.h"
+
+//
+// Dialog resources
+//
+
+LANGUAGE LANG_NEUTRAL, SUBLANG_NEUTRAL
+IDD_OPT_DIALOG DIALOGEX 0, 0, 314, 239
+STYLE DS_SETFONT | DS_FIXEDSYS | WS_CHILD
+EXSTYLE WS_EX_CONTROLPARENT
+FONT 8, "MS Shell Dlg", 0, 0, 0x1
+{
+
+ AUTOCHECKBOX "Set popup colors", IDC_SETCOLOURS, 20, 174, 132, 10, WS_GROUP | BS_PUSHLIKE
+ CONTROL "Custom1", IDC_BGCOLOR, "ColourPicker", 0x50030000, 18, 185, 10, 10
+ CONTROL "Custom1", IDC_FGCOLOR, "ColourPicker", 0x50030000, 78, 185, 10, 9
+ GROUPBOX "Popup options", IDC_STATIC, 10, 164, 187, 52, WS_GROUP
+ LTEXT "Background", IDC_STATIC, 34, 186, 43, 8, SS_LEFT
+ LTEXT "Text", IDC_STATIC, 94, 186, 41, 8, SS_LEFT
+ EDITTEXT IDC_INTERVAL1, 60, 195, 21, 12, WS_GROUP | ES_AUTOHSCROLL
+ RTEXT "Close after:", IDC_STATIC, 12, 197, 47, 9, SS_RIGHT
+ LTEXT "sec (0 default, -1 disabled)", IDC_STATIC, 84, 197, 111, 8, SS_LEFT
+ CONTROL "", IDC_LIST_EXCEPTIONS, WC_LISTVIEW, WS_TABSTOP | WS_BORDER | LVS_ALIGNLEFT | LVS_REPORT, 5, 14, 292, 104
+ CTEXT "", IDC_VERSION, 39, 222, 52, 9, SS_CENTER, WS_EX_STATICEDGE
+ CONTROL "", IDC_STATUS, WC_LISTVIEW, WS_TABSTOP | LVS_ALIGNLEFT | LVS_NOCOLUMNHEADER | LVS_NOLABELWRAP | LVS_NOSORTHEADER | LVS_REPORT, 209, 131, 96, 99, WS_EX_CLIENTEDGE
+ GROUPBOX "Settings", IDC_STATIC, 5, 118, 196, 101
+ AUTOCHECKBOX "try resolve addresses", IDC_RESOLVEIP, 12, 143, 185, 8
+ EDITTEXT IDC_INTERVAL, 10, 154, 21, 12, ES_AUTOHSCROLL
+ RTEXT "Version:", IDC_STATIC, 5, 223, 34, 8, SS_RIGHT
+ AUTOCHECKBOX "Show notification if no filter defined", ID_CHK_DEFAULTACTION, 12, 131, 187, 8
+ LTEXT "Attempt interval (ms)", IDC_STATIC, 35, 155, 163, 8, SS_LEFT
+ PUSHBUTTON "Delete", ID_DELETE, 297, 68, 16, 16, BS_ICON, WS_EX_CLIENTEDGE
+ LTEXT "'Online' means:", IDC_STATIC, 211, 122, 92, 8, SS_LEFT
+ LTEXT "Filters", IDC_STATIC, 6, 5, 289, 8, SS_LEFT
+ PUSHBUTTON "Move down", ID_DOWN, 297, 52, 16, 16, BS_ICON, WS_EX_CLIENTEDGE
+ PUSHBUTTON "Move up", ID_UP, 297, 37, 16, 16, BS_ICON, WS_EX_CLIENTEDGE
+ PUSHBUTTON "Add", ID_ADD, 297, 22, 16, 16, BS_ICON, WS_EX_CLIENTEDGE
+}
+
+
+LANGUAGE LANG_NEUTRAL, SUBLANG_NEUTRAL
+IDD_FILTER_DIALOG DIALOG 0, 0, 266, 108
+STYLE DS_3DLOOK | DS_CENTER | DS_MODALFRAME | DS_SETFOREGROUND | DS_SHELLFONT | WS_CAPTION | WS_VISIBLE | WS_POPUP | WS_SYSMENU
+CAPTION "Rule editor"
+FONT 8, "Ms Shell Dlg"
+{
+ LTEXT "Application name", -1, 4, 6, 65, 8, SS_LEFT
+ EDITTEXT ID_TEXT_NAME, 72, 4, 140, 13, ES_AUTOHSCROLL
+ LTEXT "Local IP:Port", -1, 4, 24, 65, 8, SS_LEFT
+ LTEXT ":", -1, 213, 24, 8, 8, SS_LEFT
+ LTEXT ":", -1, 214, 43, 8, 8, SS_LEFT
+ EDITTEXT ID_TXT_LOCAL_IP, 72, 22, 140, 13, ES_AUTOHSCROLL
+ EDITTEXT ID_TXT_LOCAL_PORT, 217, 22, 45, 13, ES_AUTOHSCROLL
+ EDITTEXT ID_TXT_REMOTE_IP, 72, 40, 140, 13, ES_AUTOHSCROLL
+ EDITTEXT ID_TXT_REMOTE_PORT, 217, 40, 45, 13, ES_AUTOHSCROLL
+ COMBOBOX ID_CBO_ACTION, 72, 57, 140, 48, WS_TABSTOP | WS_VSCROLL | CBS_DROPDOWNLIST
+ LTEXT "Action:", -1, 4, 59, 23, 8, SS_LEFT
+ DEFPUSHBUTTON "OK", ID_OK, 153, 87, 52, 16
+ PUSHBUTTON "Cancel", ID_CANCEL, 209, 87, 52, 16
+ LTEXT "* and ? wildcard characters also available (for port enter number or *)", -1, 4, 76, 253, 8, SS_LEFT
+ LTEXT "Remote IP:Port", -1, 4, 42, 65, 8, SS_LEFT
+}
+
+//
+// Icon resources
+//
+LANGUAGE LANG_NEUTRAL, SUBLANG_SYS_DEFAULT
+IDI_ICON1 ICON "icon1.ico"
+
+
+LANGUAGE LANG_NEUTRAL, SUBLANG_SYS_DEFAULT
+IDI_ICON2 ICON "icon2.ico"
+
+
+LANGUAGE LANG_NEUTRAL, SUBLANG_NEUTRAL
+IDI_ICON3 ICON ".\\delete_item.ico"
+
+
+LANGUAGE LANG_NEUTRAL, SUBLANG_NEUTRAL
+IDI_ICON4 ICON ".\\arrowdown.ico"
+
+
+LANGUAGE LANG_NEUTRAL, SUBLANG_NEUTRAL
+IDI_ICON5 ICON ".\\arrowup.ico"
+
+
+LANGUAGE LANG_NEUTRAL, SUBLANG_NEUTRAL
+IDI_ICON6 ICON ".\\add.ico"
diff --git a/protocols/ConnectionNotify/res/add.ico b/protocols/ConnectionNotify/res/add.ico
new file mode 100644
index 0000000000..38b2eaaa93
--- /dev/null
+++ b/protocols/ConnectionNotify/res/add.ico
Binary files differ
diff --git a/protocols/ConnectionNotify/res/arrowdown.ico b/protocols/ConnectionNotify/res/arrowdown.ico
new file mode 100644
index 0000000000..6d78998710
--- /dev/null
+++ b/protocols/ConnectionNotify/res/arrowdown.ico
Binary files differ
diff --git a/protocols/ConnectionNotify/res/arrowup.ico b/protocols/ConnectionNotify/res/arrowup.ico
new file mode 100644
index 0000000000..42200e793d
--- /dev/null
+++ b/protocols/ConnectionNotify/res/arrowup.ico
Binary files differ
diff --git a/protocols/ConnectionNotify/res/delete_item.ico b/protocols/ConnectionNotify/res/delete_item.ico
new file mode 100644
index 0000000000..235b015610
--- /dev/null
+++ b/protocols/ConnectionNotify/res/delete_item.ico
Binary files differ
diff --git a/protocols/ConnectionNotify/res/icon1.ico b/protocols/ConnectionNotify/res/icon1.ico
new file mode 100644
index 0000000000..a67cf791ee
--- /dev/null
+++ b/protocols/ConnectionNotify/res/icon1.ico
Binary files differ
diff --git a/protocols/ConnectionNotify/res/icon2.ico b/protocols/ConnectionNotify/res/icon2.ico
new file mode 100644
index 0000000000..7166008d03
--- /dev/null
+++ b/protocols/ConnectionNotify/res/icon2.ico
Binary files differ
diff --git a/protocols/ConnectionNotify/res/version.rc b/protocols/ConnectionNotify/res/version.rc
new file mode 100644
index 0000000000..5a5ddd63ed
--- /dev/null
+++ b/protocols/ConnectionNotify/res/version.rc
@@ -0,0 +1,9 @@
+// Microsoft Visual C++ generated resource script.
+//
+#ifdef APSTUDIO_INVOKED
+#error this file is not editable by Microsoft Visual C++
+#endif //APSTUDIO_INVOKED
+
+#include "..\src\version.h"
+
+#include "..\..\build\Version.rc"
diff --git a/protocols/ConnectionNotify/src/ConnectionNotify.cpp b/protocols/ConnectionNotify/src/ConnectionNotify.cpp
new file mode 100644
index 0000000000..01f00983ca
--- /dev/null
+++ b/protocols/ConnectionNotify/src/ConnectionNotify.cpp
@@ -0,0 +1,880 @@
+#include "stdafx.h"
+
+CMPlugin g_plugin;
+
+static HWND hTimerWnd = (HWND)nullptr;
+static UINT TID = (UINT)12021;
+HANDLE hCheckEvent = nullptr;
+HANDLE hCheckHook = nullptr;
+HANDLE hConnectionCheckThread = nullptr;
+HANDLE hFilterOptionsThread = nullptr;
+HANDLE killCheckThreadEvent = nullptr;
+HANDLE hExceptionsMutex = nullptr;
+
+DWORD FilterOptionsThreadId;
+DWORD ConnectionCheckThreadId;
+BYTE settingSetColours = 0;
+COLORREF settingBgColor;
+COLORREF settingFgColor;
+int settingInterval = 0;
+int settingInterval1 = 0;
+BYTE settingResolveIp = 0;
+BOOL settingStatus[STATUS_COUNT];
+int settingFiltersCount = 0;
+BOOL settingDefaultAction = TRUE;
+WORD settingStatusMask = 0;
+
+struct CONNECTION *first = nullptr;
+struct CONNECTION *connExceptions = nullptr;
+struct CONNECTION *connCurrentEdit;
+struct CONNECTION *connExceptionsTmp = nullptr;
+struct CONNECTION *connCurrentEditModal = nullptr;
+int currentStatus = ID_STATUS_OFFLINE, diffstat = 0;
+BOOL bOptionsOpen = FALSE;
+wchar_t *tcpStates[] = { L"CLOSED", L"LISTEN", L"SYN_SENT", L"SYN_RCVD", L"ESTAB", L"FIN_WAIT1", L"FIN_WAIT2", L"CLOSE_WAIT", L"CLOSING", L"LAST_ACK", L"TIME_WAIT", L"DELETE_TCB" };
+
+/////////////////////////////////////////////////////////////////////////////////////////
+
+PLUGININFOEX pluginInfoEx = {
+ sizeof(PLUGININFOEX),
+ PLUGINNAME,
+ __VERSION_DWORD,
+ __DESCRIPTION,
+ __AUTHOR,
+ __COPYRIGHT,
+ __AUTHORWEB,
+ UNICODE_AWARE, //not transient
+ // 4BB5B4AA-C364-4F23-9746-D5B708A286A5
+ { 0x4bb5b4aa, 0xc364, 0x4f23, { 0x97, 0x46, 0xd5, 0xb7, 0x8, 0xa2, 0x86, 0xa5 } }
+};
+
+CMPlugin::CMPlugin() :
+ PLUGIN<CMPlugin>(PLUGINNAME, pluginInfoEx)
+{
+ RegisterProtocol(PROTOTYPE_PROTOCOL);
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+
+extern "C" __declspec(dllexport) const MUUID MirandaInterfaces[] = { MIID_PROTOCOL, MIID_LAST };
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// authentication callback futnction from extension manager
+
+BOOL strrep(wchar_t *src, wchar_t *needle, wchar_t *newstring)
+{
+ wchar_t *found, begining[MAX_SETTING_STR], tail[MAX_SETTING_STR];
+ size_t pos = 0;
+
+ //strset(begining, ' ');
+ //strset(tail, ' ');
+ if (!(found = wcsstr(src, needle)))
+ return FALSE;
+
+ pos = (found - src);
+ wcsncpy_s(begining, src, pos);
+ begining[pos] = 0;
+
+ pos = pos + mir_wstrlen(needle);
+ wcsncpy_s(tail, src + pos, _TRUNCATE);
+ begining[pos] = 0;
+
+ pos = mir_snwprintf(src, mir_wstrlen(src), L"%s%s%s", begining, newstring, tail);
+ return TRUE;
+}
+
+void saveSettingsConnections(struct CONNECTION *connHead)
+{
+ char buff[128];
+ int i = 0;
+ struct CONNECTION *tmp = connHead;
+ while (tmp != nullptr) {
+
+ mir_snprintf(buff, "%dFilterIntIp", i);
+ g_plugin.setWString(buff, tmp->strIntIp);
+ mir_snprintf(buff, "%dFilterExtIp", i);
+ g_plugin.setWString(buff, tmp->strExtIp);
+ mir_snprintf(buff, "%dFilterPName", i);
+ g_plugin.setWString(buff, tmp->PName);
+ mir_snprintf(buff, "%dFilterIntPort", i);
+ g_plugin.setDword(buff, tmp->intIntPort);
+ mir_snprintf(buff, "%dFilterExtPort", i);
+ g_plugin.setDword(buff, tmp->intExtPort);
+ mir_snprintf(buff, "%dFilterAction", i);
+ g_plugin.setDword(buff, tmp->Pid);
+ i++;
+ tmp = tmp->next;
+ }
+ settingFiltersCount = i;
+ g_plugin.setDword("FiltersCount", settingFiltersCount);
+
+}
+
+//load filters from db
+struct CONNECTION* LoadSettingsConnections()
+{
+ struct CONNECTION *connHead = nullptr;
+ DBVARIANT dbv;
+ char buff[128];
+ int i = 0;
+ for (i = settingFiltersCount - 1; i >= 0; i--) {
+ struct CONNECTION *conn = (struct CONNECTION*)mir_alloc(sizeof(struct CONNECTION));
+ mir_snprintf(buff, "%dFilterIntIp", i);
+ if (!g_plugin.getWString(buff, &dbv))
+ wcsncpy(conn->strIntIp, dbv.pwszVal, _countof(conn->strIntIp));
+ db_free(&dbv);
+ mir_snprintf(buff, "%dFilterExtIp", i);
+ if (!g_plugin.getWString(buff, &dbv))
+ wcsncpy(conn->strExtIp, dbv.pwszVal, _countof(conn->strExtIp));
+ db_free(&dbv);
+ mir_snprintf(buff, "%dFilterPName", i);
+ if (!g_plugin.getWString(buff, &dbv))
+ wcsncpy(conn->PName, dbv.pwszVal, _countof(conn->PName));
+ db_free(&dbv);
+
+ mir_snprintf(buff, "%dFilterIntPort", i);
+ conn->intIntPort = g_plugin.getDword(buff, -1);
+
+ mir_snprintf(buff, "%dFilterExtPort", i);
+ conn->intExtPort = g_plugin.getDword(buff, -1);
+
+ mir_snprintf(buff, "%dFilterAction", i);
+ conn->Pid = g_plugin.getDword(buff, 0);
+
+ conn->next = connHead;
+ connHead = conn;
+ }
+ return connHead;
+}
+//called to load settings from database
+void LoadSettings()
+{
+ settingInterval = g_plugin.getDword("Interval", 500);
+ settingInterval1 = g_plugin.getDword("PopupInterval", 0);
+ settingResolveIp = g_plugin.getByte("ResolveIp", TRUE);
+ settingDefaultAction = g_plugin.getByte("FilterDefaultAction", TRUE);
+
+ settingSetColours = g_plugin.getByte("PopupSetColours", 0);
+ settingBgColor = g_plugin.getDword("PopupBgColor", (DWORD)0xFFFFFF);
+ settingFgColor = g_plugin.getDword("PopupFgColor", (DWORD)0x000000);
+ settingFiltersCount = g_plugin.getDword("FiltersCount", 0);
+ settingStatusMask = g_plugin.getWord("StatusMask", 16);
+ for (int i = 0; i < STATUS_COUNT; i++) {
+ char buff[128];
+ mir_snprintf(buff, "Status%d", i);
+ settingStatus[i] = (g_plugin.getByte(buff, 0) == 1);
+ }
+}
+
+void fillExceptionsListView(HWND hwndDlg)
+{
+ LVITEM lvI = { 0 };
+
+ int i = 0;
+ struct CONNECTION *tmp = connExceptionsTmp;
+ HWND hwndList = GetDlgItem(hwndDlg, IDC_LIST_EXCEPTIONS);
+ ListView_DeleteAllItems(hwndList);
+
+ // Some code to create the list-view control.
+ // Initialize LVITEM members that are common to all
+ // items.
+ lvI.mask = LVIF_TEXT;
+ while (tmp) {
+ wchar_t tmpAddress[25];
+ lvI.iItem = i++;
+ lvI.iSubItem = 0;
+ lvI.pszText = tmp->PName;
+ ListView_InsertItem(hwndList, &lvI);
+ lvI.iSubItem = 1;
+ if (tmp->intIntPort == -1)
+ mir_snwprintf(tmpAddress, L"%s:*", tmp->strIntIp);
+ else
+ mir_snwprintf(tmpAddress, L"%s:%d", tmp->strIntIp, tmp->intIntPort);
+ lvI.pszText = tmpAddress;
+ ListView_SetItem(hwndList, &lvI);
+ lvI.iSubItem = 2;
+ if (tmp->intExtPort == -1)
+ mir_snwprintf(tmpAddress, L"%s:*", tmp->strExtIp);
+ else
+ mir_snwprintf(tmpAddress, L"%s:%d", tmp->strExtIp, tmp->intExtPort);
+ lvI.pszText = tmpAddress;
+ ListView_SetItem(hwndList, &lvI);
+ lvI.iSubItem = 3;
+ lvI.pszText = tmp->Pid ? LPGENW("Show") : LPGENW("Hide");
+ ListView_SetItem(hwndList, &lvI);
+
+ tmp = tmp->next;
+ }
+
+}
+//filter editor dialog box procedure opened modally from options dialog
+static INT_PTR CALLBACK FilterEditProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
+{
+ switch (message) {
+ case WM_INITDIALOG:
+ {
+ struct CONNECTION *conn = (struct CONNECTION*)lParam;
+ TranslateDialogDefault(hWnd);
+ connCurrentEditModal = conn;
+ SetDlgItemText(hWnd, ID_TEXT_NAME, conn->PName);
+ SetDlgItemText(hWnd, ID_TXT_LOCAL_IP, conn->strIntIp);
+ SetDlgItemText(hWnd, ID_TXT_REMOTE_IP, conn->strExtIp);
+
+ if (conn->intIntPort == -1)
+ SetDlgItemText(hWnd, ID_TXT_LOCAL_PORT, L"*");
+ else
+ SetDlgItemInt(hWnd, ID_TXT_LOCAL_PORT, conn->intIntPort, FALSE);
+
+ if (conn->intExtPort == -1)
+ SetDlgItemText(hWnd, ID_TXT_REMOTE_PORT, L"*");
+ else
+ SetDlgItemInt(hWnd, ID_TXT_REMOTE_PORT, conn->intExtPort, FALSE);
+
+ SendDlgItemMessage(hWnd, ID_CBO_ACTION, CB_ADDSTRING, 0, (LPARAM)TranslateT("Always show popup"));
+ SendDlgItemMessage(hWnd, ID_CBO_ACTION, CB_ADDSTRING, 0, (LPARAM)TranslateT("Never show popup"));
+ SendDlgItemMessage(hWnd, ID_CBO_ACTION, CB_SETCURSEL, conn->Pid == 0 ? 1 : 0, 0);
+ return TRUE;
+ }
+ case WM_COMMAND:
+ switch (LOWORD(wParam)) {
+ case ID_OK:
+ {
+ wchar_t tmpPort[6];
+ GetDlgItemText(hWnd, ID_TXT_LOCAL_PORT, tmpPort, _countof(tmpPort));
+ if (tmpPort[0] == '*')
+ connCurrentEditModal->intIntPort = -1;
+ else
+ connCurrentEditModal->intIntPort = GetDlgItemInt(hWnd, ID_TXT_LOCAL_PORT, nullptr, FALSE);
+ GetDlgItemText(hWnd, ID_TXT_REMOTE_PORT, tmpPort, _countof(tmpPort));
+ if (tmpPort[0] == '*')
+ connCurrentEditModal->intExtPort = -1;
+ else
+ connCurrentEditModal->intExtPort = GetDlgItemInt(hWnd, ID_TXT_REMOTE_PORT, nullptr, FALSE);
+
+ GetDlgItemText(hWnd, ID_TXT_LOCAL_IP, connCurrentEditModal->strIntIp, _countof(connCurrentEditModal->strIntIp));
+ GetDlgItemText(hWnd, ID_TXT_REMOTE_IP, connCurrentEditModal->strExtIp, _countof(connCurrentEditModal->strExtIp));
+ GetDlgItemText(hWnd, ID_TEXT_NAME, connCurrentEditModal->PName, _countof(connCurrentEditModal->PName));
+
+ connCurrentEditModal->Pid = !(BOOL)SendDlgItemMessage(hWnd, ID_CBO_ACTION, CB_GETCURSEL, 0, 0);
+
+ connCurrentEditModal = nullptr;
+ EndDialog(hWnd, IDOK);
+ return TRUE;
+ }
+ case ID_CANCEL:
+ connCurrentEditModal = nullptr;
+ EndDialog(hWnd, IDCANCEL);
+ return TRUE;
+ }
+ return FALSE;
+ break;
+ case WM_CLOSE:
+ {
+ connCurrentEditModal = nullptr;
+ EndDialog(hWnd, IDCANCEL);
+ break;
+ }
+ }
+ return FALSE;
+}
+
+//options page on miranda called
+INT_PTR CALLBACK DlgProcConnectionNotifyOpts(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam)
+{
+ HWND hwndList;
+ switch (msg) {
+ case WM_INITDIALOG://initialize dialog, so set properties from db.
+ {
+ LVCOLUMN lvc = { 0 };
+ LVITEM lvI = { 0 };
+ wchar_t buff[256];
+ bOptionsOpen = TRUE;
+ TranslateDialogDefault(hwndDlg);//translate miranda function
+ #ifdef _WIN64
+ mir_snwprintf(buff, L"%d.%d.%d.%d/64", HIBYTE(HIWORD(pluginInfoEx.version)), LOBYTE(HIWORD(pluginInfoEx.version)), HIBYTE(LOWORD(pluginInfoEx.version)), LOBYTE(LOWORD(pluginInfoEx.version)));
+ #else
+ mir_snwprintf(buff, L"%d.%d.%d.%d/32", HIBYTE(HIWORD(pluginInfoEx.version)), LOBYTE(HIWORD(pluginInfoEx.version)), HIBYTE(LOWORD(pluginInfoEx.version)), LOBYTE(LOWORD(pluginInfoEx.version)));
+ #endif
+ SetDlgItemText(hwndDlg, IDC_VERSION, buff);
+ LoadSettings();
+ //connExceptionsTmp=LoadSettingsConnections();
+ SetDlgItemInt(hwndDlg, IDC_INTERVAL, settingInterval, FALSE);
+ SetDlgItemInt(hwndDlg, IDC_INTERVAL1, settingInterval1, TRUE);
+ CheckDlgButton(hwndDlg, IDC_SETCOLOURS, settingSetColours ? BST_CHECKED : BST_UNCHECKED);
+ CheckDlgButton(hwndDlg, IDC_RESOLVEIP, settingResolveIp ? BST_CHECKED : BST_UNCHECKED);
+ CheckDlgButton(hwndDlg, ID_CHK_DEFAULTACTION, settingDefaultAction ? BST_CHECKED : BST_UNCHECKED);
+
+ SendDlgItemMessage(hwndDlg, IDC_BGCOLOR, CPM_SETCOLOUR, 0, (LPARAM)settingBgColor);
+ SendDlgItemMessage(hwndDlg, IDC_FGCOLOR, CPM_SETCOLOUR, 0, (LPARAM)settingFgColor);
+ if (!settingSetColours) {
+ HWND hwnd = GetDlgItem(hwndDlg, IDC_BGCOLOR);
+ CheckDlgButton(hwndDlg, IDC_SETCOLOURS, BST_UNCHECKED);
+ EnableWindow(hwnd, FALSE);
+ hwnd = GetDlgItem(hwndDlg, IDC_FGCOLOR);
+ EnableWindow(hwnd, FALSE);
+ }
+ SendDlgItemMessage(hwndDlg, ID_ADD, BM_SETIMAGE, IMAGE_ICON, (LPARAM)LoadImage(g_plugin.getInst(), MAKEINTRESOURCE(IDI_ICON6), IMAGE_ICON, 16, 16, 0));
+ SendDlgItemMessage(hwndDlg, ID_DELETE, BM_SETIMAGE, IMAGE_ICON, (LPARAM)LoadImage(g_plugin.getInst(), MAKEINTRESOURCE(IDI_ICON3), IMAGE_ICON, 16, 16, 0));
+ SendDlgItemMessage(hwndDlg, ID_DOWN, BM_SETIMAGE, IMAGE_ICON, (LPARAM)LoadImage(g_plugin.getInst(), MAKEINTRESOURCE(IDI_ICON4), IMAGE_ICON, 16, 16, 0));
+ SendDlgItemMessage(hwndDlg, ID_UP, BM_SETIMAGE, IMAGE_ICON, (LPARAM)LoadImage(g_plugin.getInst(), MAKEINTRESOURCE(IDI_ICON5), IMAGE_ICON, 16, 16, 0));
+ // initialise and fill listbox
+ hwndList = GetDlgItem(hwndDlg, IDC_STATUS);
+ ListView_DeleteAllItems(hwndList);
+ SendMessage(hwndList, LVM_SETEXTENDEDLISTVIEWSTYLE, 0, LVS_EX_FULLROWSELECT | LVS_EX_CHECKBOXES);
+ // 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("Status");
+ lvc.cx = 120; // width of column in pixels
+ ListView_InsertColumn(hwndList, 0, &lvc);
+ // Some code to create the list-view control.
+ // Initialize LVITEM members that are common to all
+ // items.
+ lvI.mask = LVIF_TEXT;
+ for (int i = 0; i < STATUS_COUNT; i++) {
+ lvI.pszText = Clist_GetStatusModeDescription(ID_STATUS_ONLINE + i, 0);
+ lvI.iItem = i;
+ ListView_InsertItem(hwndList, &lvI);
+ ListView_SetCheckState(hwndList, i, settingStatus[i]);
+ }
+
+ connExceptionsTmp = LoadSettingsConnections();
+ hwndList = GetDlgItem(hwndDlg, IDC_LIST_EXCEPTIONS);
+ SendMessage(hwndList, LVM_SETEXTENDEDLISTVIEWSTYLE, 0, LVS_EX_FULLROWSELECT);
+
+ lvc.mask = LVCF_FMT | LVCF_WIDTH | LVCF_TEXT | LVCF_SUBITEM;
+ lvc.fmt = LVCFMT_LEFT;
+ lvc.iSubItem = 0;
+ lvc.cx = 120; // width of column in pixels
+ lvc.pszText = TranslateT("Application");
+ ListView_InsertColumn(hwndList, 1, &lvc);
+ lvc.pszText = TranslateT("Internal socket");
+ ListView_InsertColumn(hwndList, 2, &lvc);
+ lvc.pszText = TranslateT("External socket");
+ ListView_InsertColumn(hwndList, 3, &lvc);
+ lvc.pszText = TranslateT("Action");
+ lvc.cx = 50;
+ ListView_InsertColumn(hwndList, 4, &lvc);
+
+ //fill exceptions list
+ fillExceptionsListView(hwndDlg);
+ }
+ break;
+
+ case WM_COMMAND://user changed something, so get changes to variables
+ PostMessage(GetParent(hwndDlg), PSM_CHANGED, 0, 0);
+ switch (LOWORD(wParam)) {
+ case IDC_INTERVAL: settingInterval = GetDlgItemInt(hwndDlg, IDC_INTERVAL, nullptr, FALSE); break;
+ case IDC_INTERVAL1: settingInterval1 = GetDlgItemInt(hwndDlg, IDC_INTERVAL1, nullptr, TRUE); break;
+ case IDC_RESOLVEIP: settingResolveIp = (BYTE)IsDlgButtonChecked(hwndDlg, IDC_RESOLVEIP); break;
+ case ID_CHK_DEFAULTACTION: settingDefaultAction = (BYTE)IsDlgButtonChecked(hwndDlg, ID_CHK_DEFAULTACTION); break;
+ case ID_ADD:
+ {
+ struct CONNECTION *cur = (struct CONNECTION *)mir_alloc(sizeof(struct CONNECTION));
+ memset(cur, 0, sizeof(struct CONNECTION));
+ cur->intExtPort = -1;
+ cur->intIntPort = -1;
+ cur->Pid = 0;
+ cur->PName[0] = '*';
+ cur->strExtIp[0] = '*';
+ cur->strIntIp[0] = '*';
+
+ if (DialogBoxParam(g_plugin.getInst(), MAKEINTRESOURCE(IDD_FILTER_DIALOG), hwndDlg, FilterEditProc, (LPARAM)cur) == IDCANCEL) {
+ mir_free(cur);
+ cur = nullptr;
+ }
+ else {
+ cur->next = connExceptionsTmp;
+ connExceptionsTmp = cur;
+ }
+
+ fillExceptionsListView(hwndDlg);
+ ListView_SetItemState(GetDlgItem(hwndDlg, IDC_LIST_EXCEPTIONS), 0, LVNI_FOCUSED | LVIS_SELECTED, LVNI_FOCUSED | LVIS_SELECTED);
+ SetFocus(GetDlgItem(hwndDlg, IDC_LIST_EXCEPTIONS));
+ }
+ break;
+
+ case ID_DELETE:
+ {
+ int pos, pos1;
+ struct CONNECTION *cur = connExceptionsTmp, *pre = nullptr;
+
+ pos = (int)ListView_GetNextItem(GetDlgItem(hwndDlg, IDC_LIST_EXCEPTIONS), -1, LVNI_FOCUSED);
+ if (pos == -1)break;
+ pos1 = pos;
+ while (pos--) {
+ pre = cur;
+ cur = cur->next;
+ }
+ if (pre == nullptr)
+ connExceptionsTmp = connExceptionsTmp->next;
+ else
+ (pre)->next = cur->next;
+ mir_free(cur);
+ fillExceptionsListView(hwndDlg);
+ ListView_SetItemState(GetDlgItem(hwndDlg, IDC_LIST_EXCEPTIONS), pos1, LVNI_FOCUSED | LVIS_SELECTED, LVNI_FOCUSED | LVIS_SELECTED);
+ SetFocus(GetDlgItem(hwndDlg, IDC_LIST_EXCEPTIONS));
+ break;
+ }
+ case ID_UP:
+ {
+ int pos, pos1;
+ struct CONNECTION *cur = nullptr, *pre = nullptr, *prepre = nullptr;
+
+ cur = connExceptionsTmp;
+
+ pos = (int)ListView_GetNextItem(GetDlgItem(hwndDlg, IDC_LIST_EXCEPTIONS), -1, LVNI_FOCUSED);
+ if (pos == -1)break;
+ pos1 = pos;
+ while (pos--) {
+ prepre = pre;
+ pre = cur;
+ cur = cur->next;
+ }
+ if (prepre != nullptr) {
+ pre->next = cur->next;
+ cur->next = pre;
+ prepre->next = cur;
+ }
+ else if (pre != nullptr) {
+ pre->next = cur->next;
+ cur->next = pre;
+ connExceptionsTmp = cur;
+ }
+ fillExceptionsListView(hwndDlg);
+ ListView_SetItemState(GetDlgItem(hwndDlg, IDC_LIST_EXCEPTIONS), pos1 - 1, LVNI_FOCUSED | LVIS_SELECTED, LVNI_FOCUSED | LVIS_SELECTED);
+ SetFocus(GetDlgItem(hwndDlg, IDC_LIST_EXCEPTIONS));
+ break;
+ }
+ case ID_DOWN:
+ {
+ int pos, pos1;
+ struct CONNECTION *cur = nullptr, *pre = nullptr;
+
+ cur = connExceptionsTmp;
+
+ pos = (int)ListView_GetNextItem(GetDlgItem(hwndDlg, IDC_LIST_EXCEPTIONS), -1, LVNI_FOCUSED);
+ if (pos == -1)break;
+ pos1 = pos;
+ while (pos--) {
+ pre = cur;
+ cur = cur->next;
+ }
+ if (cur == connExceptionsTmp&&cur->next != nullptr) {
+ connExceptionsTmp = cur->next;
+ cur->next = cur->next->next;
+ connExceptionsTmp->next = cur;
+ }
+ else if (cur->next != nullptr) {
+ struct CONNECTION *tmp = cur->next->next;
+ pre->next = cur->next;
+ cur->next->next = cur;
+ cur->next = tmp;
+ }
+ fillExceptionsListView(hwndDlg);
+ ListView_SetItemState(GetDlgItem(hwndDlg, IDC_LIST_EXCEPTIONS), pos1 + 1, LVNI_FOCUSED | LVIS_SELECTED, LVNI_FOCUSED | LVIS_SELECTED);
+ SetFocus(GetDlgItem(hwndDlg, IDC_LIST_EXCEPTIONS));
+ break;
+ }
+ case IDC_SETCOLOURS:
+ {
+ HWND hwnd = GetDlgItem(hwndDlg, IDC_BGCOLOR);
+ settingSetColours = IsDlgButtonChecked(hwndDlg, IDC_SETCOLOURS);
+ EnableWindow(hwnd, settingSetColours);
+ hwnd = GetDlgItem(hwndDlg, IDC_FGCOLOR);
+ EnableWindow(hwnd, settingSetColours);
+ break;
+ }
+ case IDC_BGCOLOR: settingBgColor = (COLORREF)SendDlgItemMessage(hwndDlg, IDC_BGCOLOR, CPM_GETCOLOUR, 0, 0); break;
+ case IDC_FGCOLOR: settingFgColor = (COLORREF)SendDlgItemMessage(hwndDlg, IDC_FGCOLOR, CPM_GETCOLOUR, 0, 0); break;
+
+ }
+ break;
+
+ case WM_NOTIFY://apply changes so write it to db
+ switch (((LPNMHDR)lParam)->idFrom) {
+ case 0:
+ switch (((LPNMHDR)lParam)->code) {
+ case PSN_RESET:
+ LoadSettings();
+ deleteConnectionsTable(connExceptionsTmp);
+ connExceptionsTmp = LoadSettingsConnections();
+ return TRUE;
+
+ case PSN_APPLY:
+ g_plugin.setDword("Interval", settingInterval);
+ g_plugin.setDword("PopupInterval", settingInterval1);
+ g_plugin.setByte("PopupSetColours", settingSetColours);
+ g_plugin.setDword("PopupBgColor", settingBgColor);
+ g_plugin.setDword("PopupFgColor", settingFgColor);
+ g_plugin.setByte("ResolveIp", settingResolveIp);
+ g_plugin.setByte("FilterDefaultAction", settingDefaultAction);
+
+ for (int i = 0; i < STATUS_COUNT; i++) {
+ char buff[128];
+ mir_snprintf(buff, "Status%d", i);
+ settingStatus[i] = (ListView_GetCheckState(GetDlgItem(hwndDlg, IDC_STATUS), i) ? TRUE : FALSE);
+ g_plugin.setByte(buff, settingStatus[i] ? 1 : 0);
+ }
+ if (WAIT_OBJECT_0 == WaitForSingleObject(hExceptionsMutex, 100)) {
+ deleteConnectionsTable(connExceptions);
+ saveSettingsConnections(connExceptionsTmp);
+ connExceptions = connExceptionsTmp;
+ connExceptionsTmp = LoadSettingsConnections();
+ ReleaseMutex(hExceptionsMutex);
+ }
+ return TRUE;
+ }
+ break;
+ }
+
+ if (GetDlgItem(hwndDlg, IDC_LIST_EXCEPTIONS) == ((LPNMHDR)lParam)->hwndFrom) {
+ switch (((LPNMHDR)lParam)->code) {
+ case NM_DBLCLK:
+ {
+ int pos, pos1;
+ struct CONNECTION *cur = nullptr;
+
+ cur = connExceptionsTmp;
+
+ pos = (int)ListView_GetNextItem(GetDlgItem(hwndDlg, IDC_LIST_EXCEPTIONS), -1, LVNI_FOCUSED);
+ if (pos == -1)break;
+ pos1 = pos;
+ while (pos--) {
+ cur = cur->next;
+ }
+ DialogBoxParam(g_plugin.getInst(), MAKEINTRESOURCE(IDD_FILTER_DIALOG), hwndDlg, FilterEditProc, (LPARAM)cur);
+ fillExceptionsListView(hwndDlg);
+ ListView_SetItemState(GetDlgItem(hwndDlg, IDC_LIST_EXCEPTIONS), pos1, LVNI_FOCUSED | LVIS_SELECTED, LVNI_FOCUSED | LVIS_SELECTED);
+ SetFocus(GetDlgItem(hwndDlg, IDC_LIST_EXCEPTIONS));
+ break;
+ }
+ }
+ }
+
+ if (GetDlgItem(hwndDlg, IDC_STATUS) == ((LPNMHDR)lParam)->hwndFrom) {
+ switch (((LPNMHDR)lParam)->code) {
+ case LVN_ITEMCHANGED:
+ NMLISTVIEW *nmlv = (NMLISTVIEW *)lParam;
+ if ((nmlv->uNewState ^ nmlv->uOldState) & LVIS_STATEIMAGEMASK)
+ SendMessage(GetParent(hwndDlg), PSM_CHANGED, 0, 0);
+ break;
+ }
+ }
+ break;
+
+ case WM_DESTROY:
+ bOptionsOpen = FALSE;
+ deleteConnectionsTable(connExceptionsTmp);
+ connExceptionsTmp = nullptr;
+ return TRUE;
+ }
+ return 0;
+}
+
+//options page on miranda called
+int ConnectionNotifyOptInit(WPARAM wParam, LPARAM)
+{
+ OPTIONSDIALOGPAGE odp = {};
+ odp.pszTemplate = MAKEINTRESOURCEA(IDD_OPT_DIALOG);
+ odp.szTitle.w = _A2W(PLUGINNAME);
+ odp.szGroup.w = LPGENW("Plugins");
+ odp.flags = ODPF_BOLDGROUPS | ODPF_UNICODE;
+ odp.pfnDlgProc = DlgProcConnectionNotifyOpts;//callback function name
+ g_plugin.addOptions(wParam, &odp);
+ return 0;
+}
+
+//gives protocol avainable statuses
+INT_PTR GetCaps(WPARAM wParam, LPARAM)
+{
+ if (wParam == PFLAGNUM_1)
+ return 0;
+ if (wParam == PFLAGNUM_2)
+ return PF2_ONLINE; // add the possible statuses here.
+ if (wParam == PFLAGNUM_3)
+ return 0;
+ return 0;
+}
+
+//gives name to protocol module
+INT_PTR GetName(WPARAM wParam, LPARAM lParam)
+{
+ mir_strncpy((char*)lParam, PLUGINNAME, wParam);
+ return 0;
+}
+
+//gives icon for proto module
+INT_PTR TMLoadIcon(WPARAM wParam, LPARAM)
+{
+ UINT id;
+
+ switch (wParam & 0xFFFF) {
+ case PLI_PROTOCOL:
+ id = IDI_ICON1;
+ break; // IDI_TM is the main icon for the protocol
+ default:
+ return 0;
+ }
+ return (INT_PTR)LoadImage(g_plugin.getInst(), MAKEINTRESOURCE(id), IMAGE_ICON, GetSystemMetrics(wParam&PLIF_SMALL ? SM_CXSMICON : SM_CXICON), GetSystemMetrics(wParam&PLIF_SMALL ? SM_CYSMICON : SM_CYICON), 0);
+}
+//=======================================================
+//SetStatus
+//=======================================================
+INT_PTR SetStatus(WPARAM wParam, LPARAM lParam)
+{
+ if (wParam == ID_STATUS_OFFLINE) {
+ diffstat = 0;
+ //PostThreadMessage(ConnectionCheckThreadId,WM_QUIT ,0, 0);
+ SetEvent(killCheckThreadEvent);
+
+ }
+ else if (wParam == ID_STATUS_ONLINE) {
+ diffstat = 0;
+ ResetEvent(killCheckThreadEvent);
+ if (!hConnectionCheckThread)
+ hConnectionCheckThread = (HANDLE)mir_forkthreadex(checkthread, nullptr, (unsigned int*)&ConnectionCheckThreadId);
+ }
+ else {
+ int retv = 0;
+
+ if (settingStatus[wParam - ID_STATUS_ONLINE])
+ retv = SetStatus(ID_STATUS_OFFLINE, lParam);
+ else
+ retv = SetStatus(ID_STATUS_ONLINE, lParam);
+ //LNEnableMenuItem(hMenuHandle ,TRUE);
+ diffstat = wParam;
+ return retv;
+
+ // the status has been changed to unknown (maybe run some more code)
+ }
+ //broadcast the message
+
+ //oldStatus = currentStatus;
+ if (currentStatus != (int)wParam)
+ ProtoBroadcastAck(PLUGINNAME, NULL, ACKTYPE_STATUS, ACKRESULT_SUCCESS, (HANDLE)currentStatus, wParam);
+ currentStatus = wParam;
+ return 0;
+
+}
+//=======================================================
+//GetStatus
+//=======================================================
+INT_PTR GetStatus(WPARAM, LPARAM)
+{
+ return currentStatus;
+}
+
+//thread function with connections check loop
+static unsigned __stdcall checkthread(void *)
+{
+
+ #ifdef _DEBUG
+ _OutputDebugString(L"check thread started");
+ #endif
+ while (1) {
+ struct CONNECTION* conn = nullptr, *connOld = first, *cur = nullptr;
+ #ifdef _DEBUG
+ _OutputDebugString(L"checking connections table...");
+ #endif
+ if (WAIT_OBJECT_0 == WaitForSingleObject(killCheckThreadEvent, 100)) {
+ hConnectionCheckThread = nullptr;
+ return 0;
+ }
+
+ conn = GetConnectionsTable();
+ cur = conn;
+ while (cur != nullptr) {
+ if (searchConnection(first, cur->strIntIp, cur->strExtIp, cur->intIntPort, cur->intExtPort, cur->state) == nullptr && (settingStatusMask & (1 << (cur->state - 1)))) {
+
+ #ifdef _DEBUG
+ wchar_t msg[1024];
+ mir_snwprintf(msg, L"%s:%d\n%s:%d", cur->strIntIp, cur->intIntPort, cur->strExtIp, cur->intExtPort);
+ _OutputDebugString(L"New connection: %s", msg);
+ #endif
+ pid2name(cur->Pid, cur->PName, _countof(cur->PName));
+ if (WAIT_OBJECT_0 == WaitForSingleObject(hExceptionsMutex, 100)) {
+ if (checkFilter(connExceptions, cur)) {
+ showMsg(cur->PName, cur->Pid, cur->strIntIp, cur->strExtIp, cur->intIntPort, cur->intExtPort, cur->state);
+ Skin_PlaySound(PLUGINNAME_NEWSOUND);
+ }
+ ReleaseMutex(hExceptionsMutex);
+ }
+ }
+ cur = cur->next;
+ }
+
+ first = conn;
+ deleteConnectionsTable(connOld);
+ Sleep(settingInterval);
+ }
+ hConnectionCheckThread = nullptr;
+ return 1;
+}
+
+//popup reactions
+static LRESULT CALLBACK PopupDlgProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
+{
+ switch (message) {
+ case WM_COMMAND:
+ if (HIWORD(wParam) == STN_CLICKED)//client clicked on popup with left mouse button
+ {
+ struct CONNECTION *conn = (struct CONNECTION*)mir_alloc(sizeof(struct CONNECTION));
+ struct CONNECTION *mpd = (struct CONNECTION*) PUGetPluginData(hWnd);
+
+ memcpy(conn, mpd, sizeof(struct CONNECTION));
+ PUDeletePopup(hWnd);
+ PostThreadMessage(FilterOptionsThreadId, WM_ADD_FILTER, 0, (LPARAM)conn);
+ }
+ break;
+
+ case WM_RBUTTONUP:
+ PUDeletePopup(hWnd);
+ break;
+
+ case UM_INITPOPUP:
+ //struct CONNECTON *conn=NULL;
+ //conn = (struct CONNECTION*)CallService(MS_POPUP_GETPLUGINDATA, (WPARAM)hWnd,(LPARAM)conn);
+ //MessageBox(NULL,conn->extIp);
+ //PUDeletePopUp(hWnd);
+ break;
+
+ case UM_FREEPLUGINDATA:
+ struct CONNECTION *mpd = (struct CONNECTION*)PUGetPluginData(hWnd);
+ if (mpd > 0) mir_free(mpd);
+ return TRUE; //TRUE or FALSE is the same, it gets ignored.
+ }
+ return DefWindowProc(hWnd, message, wParam, lParam);
+}
+
+
+//show popup
+void showMsg(wchar_t *pName, DWORD pid, wchar_t *intIp, wchar_t *extIp, int intPort, int extPort, int state)
+{
+
+ POPUPDATAW ppd;
+ //hContact = A_VALID_HANDLE_YOU_GOT_FROM_SOMEWHERE;
+ //hIcon = A_VALID_HANDLE_YOU_GOT_SOMEWHERE;
+ //char * lpzContactName = (char*)CallService(MS_CLIST_GETCONTACTDISPLAYNAME,(WPARAM)lhContact,0);
+ //99% of the times you'll just copy this line.
+ //1% of the times you may wish to change the contact's name. I don't know why you should, but you can.
+ //char * lpzText;
+ //The text for the second line. You could even make something like: char lpzText[128]; mir_wstrcpy(lpzText, "Hello world!"); It's your choice.
+
+ struct CONNECTION *mpd = (struct CONNECTION*)mir_alloc(sizeof(struct CONNECTION));
+ //MessageBox(NULL,"aaa","aaa",1);
+ memset(&ppd, 0, sizeof(ppd)); //This is always a good thing to do.
+ ppd.lchContact = NULL;//(HANDLE)hContact; //Be sure to use a GOOD handle, since this will not be checked.
+ ppd.lchIcon = LoadIcon(g_plugin.getInst(), MAKEINTRESOURCE(IDI_ICON1));
+ if (settingResolveIp) {
+ wchar_t hostName[128];
+ getDnsName(extIp, hostName, _countof(hostName));
+ mir_snwprintf(ppd.lpwzText, L"%s:%d\n%s:%d", hostName, extPort, intIp, intPort);
+ }
+ else mir_snwprintf(ppd.lpwzText, L"%s:%d\n%s:%d", extIp, extPort, intIp, intPort);
+
+ mir_snwprintf(ppd.lpwzContactName, L"%s (%s)", pName, tcpStates[state - 1]);
+
+ if (settingSetColours) {
+ ppd.colorBack = settingBgColor;
+ ppd.colorText = settingFgColor;
+ }
+ ppd.PluginWindowProc = PopupDlgProc;
+
+ ppd.iSeconds = settingInterval1;
+ //Now the "additional" data.
+ wcsncpy_s(mpd->strIntIp, intIp, _TRUNCATE);
+ wcsncpy_s(mpd->strExtIp, extIp, _TRUNCATE);
+ wcsncpy_s(mpd->PName, pName, _TRUNCATE);
+ mpd->intIntPort = intPort;
+ mpd->intExtPort = extPort;
+ mpd->Pid = pid;
+
+ //Now that the plugin data has been filled, we add it to the PopUpData.
+ ppd.PluginData = mpd;
+
+ //Now that every field has been filled, we want to see the popup.
+ PUAddPopupW(&ppd);
+}
+
+//called after all plugins loaded.
+//all Connection staff will be called, that will not hang miranda on startup
+static int modulesloaded(WPARAM, LPARAM)
+{
+
+ #ifdef _DEBUG
+ _OutputDebugString(L"Modules loaded, lets start TN...");
+ #endif
+ // hConnectionCheckThread = (HANDLE)mir_forkthreadex(checkthread, 0, 0, ConnectionCheckThreadId);
+
+ //#ifdef _DEBUG
+ // _OutputDebugString("started check thread %d",hConnectionCheckThread);
+ //#endif
+ killCheckThreadEvent = CreateEvent(nullptr, FALSE, FALSE, L"killCheckThreadEvent");
+ hFilterOptionsThread = startFilterThread();
+ //updaterRegister();
+
+ return 0;
+}
+//function hooks before unload
+static int preshutdown(WPARAM, LPARAM)
+{
+ deleteConnectionsTable(first);
+ deleteConnectionsTable(connExceptions);
+ deleteConnectionsTable(connExceptionsTmp);
+
+ PostThreadMessage(ConnectionCheckThreadId, WM_QUIT, 0, 0);
+ PostThreadMessage(FilterOptionsThreadId, WM_QUIT, 0, 0);
+
+ return 0;
+}
+
+int CMPlugin::Load()
+{
+ #ifdef _DEBUG
+ _OutputDebugString(L"Entering Load dll");
+ #endif
+
+ hExceptionsMutex = CreateMutex(nullptr, FALSE, L"ExceptionsMutex");
+
+ LoadSettings();
+ connExceptions = LoadSettingsConnections();
+
+ // set all contacts to offline
+ for (auto &hContact : Contacts(PLUGINNAME))
+ g_plugin.setWord(hContact, "status", ID_STATUS_OFFLINE);
+
+ CreateProtoServiceFunction(PLUGINNAME, PS_GETCAPS, GetCaps);
+ CreateProtoServiceFunction(PLUGINNAME, PS_GETNAME, GetName);
+ CreateProtoServiceFunction(PLUGINNAME, PS_LOADICON, TMLoadIcon);
+ CreateProtoServiceFunction(PLUGINNAME, PS_SETSTATUS, SetStatus);
+ CreateProtoServiceFunction(PLUGINNAME, PS_GETSTATUS, GetStatus);
+
+ g_plugin.addSound(PLUGINNAME_NEWSOUND, _A2W(PLUGINNAME), LPGENW("New Connection Notification"));
+
+ HookEvent(ME_OPT_INITIALISE, ConnectionNotifyOptInit); // register service to hook option call
+ HookEvent(ME_SYSTEM_MODULESLOADED, modulesloaded); // hook event that all plugins are loaded
+ HookEvent(ME_SYSTEM_PRESHUTDOWN, preshutdown);
+ return 0;
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+
+int CMPlugin::Unload()
+{
+ WaitForSingleObjectEx(hConnectionCheckThread, INFINITE, FALSE);
+
+ if (hConnectionCheckThread) CloseHandle(hConnectionCheckThread);
+ if (hCheckEvent) DestroyHookableEvent(hCheckEvent);
+ if (hCheckHook) UnhookEvent(hCheckHook);
+ if (killCheckThreadEvent) CloseHandle(killCheckThreadEvent);
+ if (hExceptionsMutex) CloseHandle(hExceptionsMutex);
+
+ #ifdef _DEBUG
+ _OutputDebugString(L"Unloaded");
+ #endif
+ return 0;
+}
diff --git a/protocols/ConnectionNotify/src/debug.cpp b/protocols/ConnectionNotify/src/debug.cpp
new file mode 100644
index 0000000000..8abe549a22
--- /dev/null
+++ b/protocols/ConnectionNotify/src/debug.cpp
@@ -0,0 +1,13 @@
+#include "stdafx.h"
+
+void _OutputDebugString(wchar_t* lpOutputString, ...)
+{
+ CMStringW format;
+ va_list args;
+ va_start(args, lpOutputString);
+ format.FormatV(lpOutputString, args);
+ va_end(args);
+
+ format.AppendChar('\n');
+ OutputDebugString(format);
+}
diff --git a/protocols/ConnectionNotify/src/debug.h b/protocols/ConnectionNotify/src/debug.h
new file mode 100644
index 0000000000..044e81fe9f
--- /dev/null
+++ b/protocols/ConnectionNotify/src/debug.h
@@ -0,0 +1,9 @@
+#pragma once
+#ifndef _INC_DEBUG
+#define _INC_DEBUG
+
+#include <windows.h>
+#include <stdio.h>
+
+void _OutputDebugString(wchar_t* lpOutputString, ...);
+#endif \ No newline at end of file
diff --git a/protocols/ConnectionNotify/src/filter.cpp b/protocols/ConnectionNotify/src/filter.cpp
new file mode 100644
index 0000000000..e5cc01e98e
--- /dev/null
+++ b/protocols/ConnectionNotify/src/filter.cpp
@@ -0,0 +1,141 @@
+#include "stdafx.h"
+
+HWND filterAddDlg = nullptr;
+extern struct CONNECTION *connExceptions;
+extern HANDLE hFilterOptionsThread;
+extern DWORD FilterOptionsThreadId;
+extern struct CONNECTION *connCurrentEdit;
+extern BOOL settingDefaultAction;
+extern HANDLE hExceptionsMutex;
+extern BOOL bOptionsOpen;
+static unsigned __stdcall filterQueue(void *dummy);
+static INT_PTR CALLBACK ConnectionFilterEditProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam);
+
+HANDLE startFilterThread()
+{
+ return (HANDLE)mir_forkthreadex(filterQueue, nullptr, (unsigned int*)&FilterOptionsThreadId);
+}
+
+static unsigned __stdcall filterQueue(void *)
+{
+ BOOL bRet;
+ MSG msg;
+ //while(1)
+ while ((bRet = GetMessage(&msg, nullptr, 0, 0)) != 0)
+ {
+ if (msg.message == WM_ADD_FILTER)
+ {
+ struct CONNECTION *conn = (struct CONNECTION *)msg.lParam;
+ filterAddDlg = CreateDialogParam(g_plugin.getInst(), MAKEINTRESOURCE(IDD_FILTER_DIALOG), nullptr, ConnectionFilterEditProc, (LPARAM)conn);
+ ShowWindow(filterAddDlg, SW_SHOW);
+
+ }
+ if (nullptr == filterAddDlg || !IsDialogMessage(filterAddDlg, &msg)) { /* Wine fix. */
+ TranslateMessage(&msg);
+ DispatchMessage(&msg);
+ }
+ }
+ hFilterOptionsThread = nullptr;
+ return TRUE;
+}
+
+static INT_PTR CALLBACK ConnectionFilterEditProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
+{
+ switch (message)
+ {
+ case WM_INITDIALOG:
+ {
+ struct CONNECTION *conn = (struct CONNECTION*)lParam;
+ TranslateDialogDefault(hWnd);
+
+ SetDlgItemText(hWnd, ID_TEXT_NAME, conn->PName);
+ SetDlgItemText(hWnd, ID_TXT_LOCAL_IP, conn->strIntIp);
+ SetDlgItemText(hWnd, ID_TXT_REMOTE_IP, conn->strExtIp);
+ SetDlgItemInt(hWnd, ID_TXT_LOCAL_PORT, conn->intIntPort, FALSE);
+ SetDlgItemInt(hWnd, ID_TXT_REMOTE_PORT, conn->intExtPort, FALSE);
+ SendDlgItemMessage(hWnd, ID_CBO_ACTION, CB_ADDSTRING, 0, (LPARAM)TranslateT("Always show popup"));
+ SendDlgItemMessage(hWnd, ID_CBO_ACTION, CB_ADDSTRING, 0, (LPARAM)TranslateT("Never show popup"));
+ SendDlgItemMessage(hWnd, ID_CBO_ACTION, CB_SETCURSEL, 0, 0);
+ mir_free(conn);
+ return TRUE;
+ }
+ case WM_ACTIVATE:
+ if (0 == wParam) // becoming inactive
+ filterAddDlg = nullptr;
+ else // becoming active
+ filterAddDlg = hWnd;
+ return FALSE;
+ case WM_COMMAND:
+ switch (LOWORD(wParam))
+ {
+ case ID_OK:
+ {
+ wchar_t tmpPort[6];
+ if (bOptionsOpen)
+ {
+ MessageBox(hWnd, TranslateT("First close options window"), L"ConnectionNotify", MB_OK | MB_ICONSTOP);
+ break;
+ }
+ if (WAIT_OBJECT_0 == WaitForSingleObject(hExceptionsMutex, 100))
+ {
+ if (connCurrentEdit == nullptr)
+ {
+ connCurrentEdit = (struct CONNECTION*)mir_alloc(sizeof(struct CONNECTION));
+ connCurrentEdit->next = connExceptions;
+ connExceptions = connCurrentEdit;
+ }
+ GetDlgItemText(hWnd, ID_TXT_LOCAL_PORT, tmpPort, _countof(tmpPort));
+ if (tmpPort[0] == '*')
+ connCurrentEdit->intIntPort = -1;
+ else
+ connCurrentEdit->intIntPort = GetDlgItemInt(hWnd, ID_TXT_LOCAL_PORT, nullptr, FALSE);
+ GetDlgItemText(hWnd, ID_TXT_REMOTE_PORT, tmpPort, _countof(tmpPort));
+ if (tmpPort[0] == '*')
+ connCurrentEdit->intExtPort = -1;
+ else
+ connCurrentEdit->intExtPort = GetDlgItemInt(hWnd, ID_TXT_REMOTE_PORT, nullptr, FALSE);
+
+ GetDlgItemText(hWnd, ID_TXT_LOCAL_IP, connCurrentEdit->strIntIp, _countof(connCurrentEdit->strIntIp));
+ GetDlgItemText(hWnd, ID_TXT_REMOTE_IP, connCurrentEdit->strExtIp, _countof(connCurrentEdit->strExtIp));
+ GetDlgItemText(hWnd, ID_TEXT_NAME, connCurrentEdit->PName, _countof(connCurrentEdit->PName));
+
+ connCurrentEdit->Pid = !(BOOL)SendDlgItemMessage(hWnd, ID_CBO_ACTION, CB_GETCURSEL, 0, 0);
+ connCurrentEdit = nullptr;
+ saveSettingsConnections(connExceptions);
+ ReleaseMutex(hExceptionsMutex);
+ }
+ //EndDialog(hWnd,IDOK);
+ DestroyWindow(hWnd);
+ return TRUE;
+ }
+ case ID_CANCEL:
+ connCurrentEdit = nullptr;
+ DestroyWindow(hWnd);
+ //EndDialog(hWnd,IDCANCEL);
+ return TRUE;
+ }
+ return FALSE;
+
+ break;
+ case WM_CLOSE:
+ DestroyWindow(hWnd);
+ case WM_DESTROY:
+ filterAddDlg = nullptr;
+ connCurrentEdit = nullptr;
+ //DestroyWindow(hWnd);
+ //PostQuitMessage(0);
+ break;
+ }
+ return FALSE;
+}
+
+BOOL checkFilter(struct CONNECTION *head, struct CONNECTION *conn)
+{
+ for (struct CONNECTION *cur = head; cur != nullptr; cur = cur->next)
+ if (wildcmpw(conn->PName, cur->PName) && wildcmpw(conn->strIntIp, cur->strIntIp) && wildcmpw(conn->strExtIp, cur->strExtIp)
+ && (cur->intIntPort == -1 || cur->intIntPort == conn->intIntPort) && (cur->intExtPort == -1 || cur->intExtPort == conn->intExtPort))
+ return cur->Pid;
+
+ return settingDefaultAction;
+}
+
diff --git a/protocols/ConnectionNotify/src/filter.h b/protocols/ConnectionNotify/src/filter.h
new file mode 100644
index 0000000000..f21ba7c95a
--- /dev/null
+++ b/protocols/ConnectionNotify/src/filter.h
@@ -0,0 +1,9 @@
+#pragma once
+#ifndef _INC_FILTER
+#define _INC_FILTER
+
+HANDLE startFilterThread();
+BOOL checkFilter(struct CONNECTION *head, struct CONNECTION *conn);
+
+#define WM_ADD_FILTER (WM_APP + 1)
+#endif
diff --git a/protocols/ConnectionNotify/src/netstat.cpp b/protocols/ConnectionNotify/src/netstat.cpp
new file mode 100644
index 0000000000..93d906cc4f
--- /dev/null
+++ b/protocols/ConnectionNotify/src/netstat.cpp
@@ -0,0 +1,148 @@
+#include "stdafx.h"
+
+struct CONNECTION *GetConnectionsTable()
+{
+ // Declare and initialize variables
+ MIB_TCPTABLE_OWNER_PID *pTcpTable = (MIB_TCPTABLE_OWNER_PID *)MALLOC(sizeof(MIB_TCPTABLE_OWNER_PID));
+ if (pTcpTable == nullptr) {
+ //printf("Error allocating memory!\n");
+ return nullptr;
+ }
+
+ DWORD dwSize = sizeof(MIB_TCPTABLE_OWNER_PID);
+ // Make an initial call to GetTcpTable to
+ // get the necessary size into the dwSize variable
+ DWORD dwRetVal = GetExtendedTcpTable(pTcpTable, &dwSize, TRUE, AF_INET, TCP_TABLE_OWNER_PID_ALL, 0);
+ if (dwRetVal == ERROR_INSUFFICIENT_BUFFER) {
+ FREE(pTcpTable);
+ pTcpTable = (MIB_TCPTABLE_OWNER_PID *)MALLOC(dwSize);
+ if (pTcpTable == nullptr) {
+ //printf("Error allocating memory\n");
+ return nullptr;
+ }
+ }
+
+ // Make a second call to GetTcpTable to get
+ // the actual data we require
+ if ((dwRetVal = GetExtendedTcpTable(pTcpTable, &dwSize, TRUE, AF_INET, TCP_TABLE_OWNER_PID_ALL, 0)) != NO_ERROR) {
+ //printf("\tGetTcpTable() failed with return value %d\n", dwRetVal);
+ FREE(pTcpTable);
+ return nullptr;
+ }
+ //printf("\tLocal Addr\tLocal Port\tRemote Addr\tRemote Port\n");
+ //printf("Number of entries: %d\n", (int) pTcpTable->dwNumEntries);
+ struct in_addr IpAddr;
+ struct CONNECTION *connHead = nullptr;
+ for (DWORD i = 0; i < pTcpTable->dwNumEntries; i++) {
+ struct CONNECTION *newConn = (struct CONNECTION*)mir_alloc(sizeof(struct CONNECTION));
+ memset(newConn, 0, sizeof(struct CONNECTION));
+ //pid2name(pTcpTable->table[i].dwOwningPid,&newConn->Pname);
+
+ if (pTcpTable->table[i].dwLocalAddr) {
+ IpAddr.S_un.S_addr = (ULONG)pTcpTable->table[i].dwLocalAddr;
+ //_snprintf(newConn->strIntIp,_countof(newConn->strIntIp),"%d.%d.%d.%d",IpAddr.S_un.S_un_b.s_b1,IpAddr.S_un.S_un_b.s_b2,IpAddr.S_un.S_un_b.s_b3,IpAddr.S_un.S_un_b.s_b4);
+ wchar_t *strIntIp = mir_a2u(inet_ntoa(IpAddr));
+ wcsncpy(newConn->strIntIp, strIntIp, _countof(newConn->strIntIp) - 1);
+ mir_free(strIntIp);
+ }
+
+ if (pTcpTable->table[i].dwRemoteAddr) {
+ IpAddr.S_un.S_addr = (u_long)pTcpTable->table[i].dwRemoteAddr;
+ wchar_t *strExtIp = mir_a2u(inet_ntoa(IpAddr));
+ wcsncpy(newConn->strExtIp, strExtIp, _countof(newConn->strExtIp) - 1);
+ mir_free(strExtIp);
+ }
+ newConn->state = pTcpTable->table[i].dwState;
+ newConn->intIntPort = ntohs((u_short)pTcpTable->table[i].dwLocalPort);
+ newConn->intExtPort = ntohs((u_short)pTcpTable->table[i].dwRemotePort);
+ newConn->Pid = pTcpTable->table[i].dwOwningPid;
+ switch (pTcpTable->table[i].dwState) {
+ case MIB_TCP_STATE_CLOSED:
+ //printf("CLOSED\n");
+ break;
+ case MIB_TCP_STATE_LISTEN:
+ //printf("LISTEN\n");
+ break;
+ case MIB_TCP_STATE_SYN_SENT:
+ //printf("SYN-SENT\n");
+ break;
+ case MIB_TCP_STATE_SYN_RCVD:
+ //printf("SYN-RECEIVED\n");
+ break;
+ case MIB_TCP_STATE_ESTAB:
+ //printf("ESTABLISHED\n");
+ break;
+ case MIB_TCP_STATE_FIN_WAIT1:
+ //printf("FIN-WAIT-1\n");
+ break;
+ case MIB_TCP_STATE_FIN_WAIT2:
+ //printf("FIN-WAIT-2 \n");
+ break;
+ case MIB_TCP_STATE_CLOSE_WAIT:
+ //printf("CLOSE-WAIT\n");
+ break;
+ case MIB_TCP_STATE_CLOSING:
+ //printf("CLOSING\n");
+ break;
+ case MIB_TCP_STATE_LAST_ACK:
+ //printf("LAST-ACK\n");
+ break;
+ case MIB_TCP_STATE_TIME_WAIT:
+ //printf("TIME-WAIT\n");
+ break;
+ case MIB_TCP_STATE_DELETE_TCB:
+ //printf("DELETE-TCB\n");
+ break;
+ default:
+ //printf("UNKNOWN dwState value\n");
+ break;
+ }
+ newConn->next = connHead;
+ connHead = newConn;
+ //printf("TCP[%d]:%s%15d%20s%15d\n", i, szLocalAddr,ntohs((u_short)pTcpTable->table[i].dwLocalPort), szRemoteAddr,ntohs((u_short)pTcpTable->table[i].dwRemotePort));
+ //printf("\tTCP[%d] Local Addr: %s\n", i, szLocalAddr);
+ // printf("\tTCP[%d] Local Port: %d \n", i, ntohs((u_short)pTcpTable->table[i].dwLocalPort));
+ //printf("\tTCP[%d] Remote Addr: %s\n", i, szRemoteAddr);
+ //printf("\tTCP[%d] Remote Port: %d\n", i, ntohs((u_short)pTcpTable->table[i].dwRemotePort));
+ }
+ FREE(pTcpTable);
+
+ return connHead;
+}
+
+void deleteConnectionsTable(struct CONNECTION *head)
+{
+ struct CONNECTION *cur = head, *del;
+
+ while (cur != nullptr) {
+ del = cur;
+ cur = cur->next;
+ mir_free(del);
+ head = cur;
+ }
+ head = nullptr;
+}
+
+struct CONNECTION *searchConnection(struct CONNECTION *head, wchar_t *intIp, wchar_t *extIp, int intPort, int extPort, int state)
+{
+ for (struct CONNECTION *cur = head; cur != nullptr; cur = cur->next) {
+ if (mir_wstrcmp(cur->strIntIp, intIp) == 0 &&
+ mir_wstrcmp(cur->strExtIp, extIp) == 0 &&
+ cur->intExtPort == extPort &&
+ cur->intIntPort == intPort &&
+ cur->state == state)
+ return cur;
+ }
+ return nullptr;
+}
+
+void getDnsName(wchar_t *strIp, wchar_t *strHostName, size_t len)
+{
+ in_addr iaHost;
+
+ char *szStrIP = mir_u2a(strIp);
+ iaHost.s_addr = inet_addr(szStrIP);
+ mir_free(szStrIP);
+ hostent *h = gethostbyaddr((char *)&iaHost, sizeof(struct in_addr), AF_INET);
+ wcsncpy_s(strHostName, len, (h == nullptr) ? strIp : _A2T(h->h_name), _TRUNCATE);
+}
diff --git a/protocols/ConnectionNotify/src/netstat.h b/protocols/ConnectionNotify/src/netstat.h
new file mode 100644
index 0000000000..e4d1631775
--- /dev/null
+++ b/protocols/ConnectionNotify/src/netstat.h
@@ -0,0 +1,18 @@
+#pragma once
+
+struct CONNECTION
+{
+ wchar_t strIntIp[16];
+ wchar_t strExtIp[16];
+ int intIntPort;
+ int intExtPort;
+ int state;
+ DWORD Pid;
+ wchar_t PName[260];
+ struct CONNECTION *next;
+};
+
+struct CONNECTION* GetConnectionsTable();
+void deleteConnectionsTable(struct CONNECTION* head);
+struct CONNECTION* searchConnection(struct CONNECTION* head, wchar_t *intIp, wchar_t *extIp, int intPort, int extPort, int state);
+void getDnsName(wchar_t *strIp, wchar_t *strHostName, size_t len);
diff --git a/protocols/ConnectionNotify/src/pid2name.cpp b/protocols/ConnectionNotify/src/pid2name.cpp
new file mode 100644
index 0000000000..f5c10ca9e6
--- /dev/null
+++ b/protocols/ConnectionNotify/src/pid2name.cpp
@@ -0,0 +1,21 @@
+#include "stdafx.h"
+
+void pid2name(DWORD procid, wchar_t *buffer, size_t bufLen)
+{
+ PROCESSENTRY32 ProcessStruct;
+ ProcessStruct.dwSize = sizeof(PROCESSENTRY32);
+ HANDLE hSnap = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
+ if (hSnap == INVALID_HANDLE_VALUE)
+ return;
+ if (Process32First(hSnap, &ProcessStruct) == FALSE)
+ return;
+
+ do {
+ if (ProcessStruct.th32ProcessID == procid) {
+ wcsncpy_s(buffer, bufLen, ProcessStruct.szExeFile, _TRUNCATE);
+ break;
+ }
+ } while (Process32Next(hSnap, &ProcessStruct));
+
+ CloseHandle(hSnap);
+}
diff --git a/protocols/ConnectionNotify/src/pid2name.h b/protocols/ConnectionNotify/src/pid2name.h
new file mode 100644
index 0000000000..96338a14b1
--- /dev/null
+++ b/protocols/ConnectionNotify/src/pid2name.h
@@ -0,0 +1,8 @@
+#pragma once
+
+#ifndef _INC_PID2NAME
+#define _INC_PID2NAME
+
+void pid2name(DWORD, wchar_t*, size_t);
+#endif
+
diff --git a/protocols/ConnectionNotify/src/resource.h b/protocols/ConnectionNotify/src/resource.h
new file mode 100644
index 0000000000..0215e70270
--- /dev/null
+++ b/protocols/ConnectionNotify/src/resource.h
@@ -0,0 +1,34 @@
+#ifndef IDC_STATIC
+#define IDC_STATIC (-1)
+#endif
+
+#define IDI_ICON1 101
+#define IDD_OPT_DIALOG 102
+#define IDI_ICON2 103
+#define IDD_FILTER_DIALOG 105
+#define IDI_ICON3 110
+#define IDI_ICON4 111
+#define IDI_ICON5 114
+#define IDI_ICON6 115
+#define ID_TEXT_NAME 1000
+#define IDC_RESOLVEIP 1001
+#define IDC_LIST_EXCEPTIONS 1002
+#define IDC_INTERVAL 1003
+#define ID_CHK_DEFAULTACTION 1004
+#define ID_DELETE 1005
+#define ID_DOWN 1006
+#define ID_ADD 1007
+#define ID_UP 1008
+#define IDC_SETCOLOURS 1009
+#define IDC_INTERVAL1 1010
+#define IDC_BGCOLOR 1011
+#define IDC_FGCOLOR 1012
+#define IDC_STATUS 1016
+#define IDC_VERSION 1017
+#define ID_TXT_LOCAL_IP 1070
+#define ID_TXT_REMOTE_IP 1071
+#define ID_CBO_ACTION 1074
+#define ID_TXT_REMOTE_PORT 1075
+#define ID_TXT_LOCAL_PORT 1076
+#define ID_CANCEL 1077
+#define ID_OK 1078
diff --git a/protocols/ConnectionNotify/src/stdafx.cxx b/protocols/ConnectionNotify/src/stdafx.cxx
new file mode 100644
index 0000000000..1b563fc866
--- /dev/null
+++ b/protocols/ConnectionNotify/src/stdafx.cxx
@@ -0,0 +1,18 @@
+/*
+Copyright (C) 2012-19 Miranda NG team (https://miranda-ng.org)
+
+This program is free software; you can redistribute it and/or
+modify it under the terms of the GNU General Public License
+as published by the Free Software Foundation version 2
+of the License.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "stdafx.h" \ No newline at end of file
diff --git a/protocols/ConnectionNotify/src/stdafx.h b/protocols/ConnectionNotify/src/stdafx.h
new file mode 100644
index 0000000000..98123939fd
--- /dev/null
+++ b/protocols/ConnectionNotify/src/stdafx.h
@@ -0,0 +1,51 @@
+#pragma once
+
+#include <windows.h>
+#include <Commctrl.h>
+#include <assert.h>
+#include <iphlpapi.h>
+#include <Tlhelp32.h>
+
+#include <newpluginapi.h>
+#include <m_core.h>
+#include <m_clistint.h>
+#include <m_skin.h>
+#include <m_langpack.h>
+#include <m_options.h>
+#include <m_popup.h>
+#include <m_utils.h>
+#include <m_protosvc.h>
+#include <m_system.h>
+
+#ifdef _DEBUG
+#include "debug.h"
+#endif
+#include "resource.h"
+#include "netstat.h"
+#include "filter.h"
+#include "version.h"
+#include "pid2name.h"
+
+#define MAX_SETTING_STR 512
+#define MAX_LENGTH 512
+#define STATUS_COUNT 9
+
+// Note: could also use malloc() and free()
+#define MALLOC(x) HeapAlloc(GetProcessHeap(), 0, (x))
+#define FREE(x) HeapFree(GetProcessHeap(), 0, (x))
+
+#define PLUGINNAME "ConnectionNotify"
+#define PLUGINNAME_NEWSOUND PLUGINNAME "_new_sound"
+
+struct CMPlugin : public PLUGIN<CMPlugin>
+{
+ CMPlugin();
+
+ int Load() override;
+ int Unload() override;
+};
+
+void showMsg(wchar_t *pName,DWORD pid,wchar_t *intIp,wchar_t *extIp,int intPort,int extPort,int state);
+static unsigned __stdcall checkthread(void *dummy);
+struct CONNECTION * LoadSettingsConnections();
+void saveSettingsConnections(struct CONNECTION *connHead);
diff --git a/protocols/ConnectionNotify/src/version.h b/protocols/ConnectionNotify/src/version.h
new file mode 100644
index 0000000000..6ca2e3eb6f
--- /dev/null
+++ b/protocols/ConnectionNotify/src/version.h
@@ -0,0 +1,38 @@
+/*
+Exchange notifier plugin for Miranda IM
+
+Copyright © 2006 Cristian Libotean, Attila Vajda
+
+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.
+*/
+
+#ifndef M_NONNECTIONNOTIFY_VERSION_H
+#define M_NONNECTIONNOTIFY_VERSION_H
+
+#define __MAJOR_VERSION 0
+#define __MINOR_VERSION 1
+#define __RELEASE_NUM 0
+#define __BUILD_NUM 5
+
+#include <stdver.h>
+
+#define __PLUGIN_NAME "Connection Notify"
+#define __FILENAME "ConnectionNotify.dll"
+#define __DESCRIPTION "Notify with popup if some connection established"
+#define __AUTHOR "MaKaR"
+#define __COPYRIGHT "© 2011-13 MaKaRSoFT"
+#define __AUTHORWEB "https://miranda-ng.org/p/ConnectionNotify/"
+
+#endif //M_EXCHANGE_VERSION_H
diff --git a/protocols/CurrencyRates/CurrencyRatesChart/CurrencyRatesChart.csproj b/protocols/CurrencyRates/CurrencyRatesChart/CurrencyRatesChart.csproj
new file mode 100644
index 0000000000..d58b687ce4
--- /dev/null
+++ b/protocols/CurrencyRates/CurrencyRatesChart/CurrencyRatesChart.csproj
@@ -0,0 +1,124 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <PropertyGroup>
+ <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
+ <Platform Condition=" '$(Platform)' == '' ">x86</Platform>
+ <ProductVersion>8.0.30703</ProductVersion>
+ <SchemaVersion>2.0</SchemaVersion>
+ <ProjectGuid>{C255CA56-D05E-4389-A32E-CA3EBE412684}</ProjectGuid>
+ <OutputType>WinExe</OutputType>
+ <AppDesignerFolder>Properties</AppDesignerFolder>
+ <RootNamespace>CurrencyRatesChart</RootNamespace>
+ <AssemblyName>CurrencyRatesChart</AssemblyName>
+ <TargetFrameworkVersion>v4.0</TargetFrameworkVersion>
+ <FileAlignment>512</FileAlignment>
+ <TargetFrameworkProfile />
+ </PropertyGroup>
+ <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|x86' ">
+ <PlatformTarget>x86</PlatformTarget>
+ <DebugSymbols>true</DebugSymbols>
+ <DebugType>full</DebugType>
+ <Optimize>false</Optimize>
+ <OutputPath>bin\x32\Debug\</OutputPath>
+ <DefineConstants>DEBUG;TRACE</DefineConstants>
+ <ErrorReport>prompt</ErrorReport>
+ <WarningLevel>4</WarningLevel>
+ </PropertyGroup>
+ <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|x86' ">
+ <PlatformTarget>x86</PlatformTarget>
+ <DebugType>pdbonly</DebugType>
+ <Optimize>true</Optimize>
+ <OutputPath>bin\x32\Release\</OutputPath>
+ <DefineConstants>TRACE</DefineConstants>
+ <ErrorReport>prompt</ErrorReport>
+ <WarningLevel>4</WarningLevel>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Debug|x64'">
+ <DebugSymbols>true</DebugSymbols>
+ <OutputPath>bin\x64\Debug\</OutputPath>
+ <DefineConstants>DEBUG;TRACE</DefineConstants>
+ <DebugType>full</DebugType>
+ <PlatformTarget>x64</PlatformTarget>
+ <CodeAnalysisLogFile>bin\Debug\CurrencyRatesChart.exe.CodeAnalysisLog.xml</CodeAnalysisLogFile>
+ <CodeAnalysisUseTypeNameInSuppression>true</CodeAnalysisUseTypeNameInSuppression>
+ <CodeAnalysisModuleSuppressionsFile>GlobalSuppressions.cs</CodeAnalysisModuleSuppressionsFile>
+ <ErrorReport>prompt</ErrorReport>
+ <CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>
+ <CodeAnalysisRuleSetDirectories>;C:\Program Files (x86)\Microsoft Visual Studio 10.0\Team Tools\Static Analysis Tools\\Rule Sets</CodeAnalysisRuleSetDirectories>
+ <CodeAnalysisRuleDirectories>;C:\Program Files (x86)\Microsoft Visual Studio 10.0\Team Tools\Static Analysis Tools\FxCop\\Rules</CodeAnalysisRuleDirectories>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Release|x64'">
+ <OutputPath>bin\x64\Release\</OutputPath>
+ <DefineConstants>TRACE</DefineConstants>
+ <Optimize>true</Optimize>
+ <DebugType>pdbonly</DebugType>
+ <PlatformTarget>x64</PlatformTarget>
+ <CodeAnalysisLogFile>bin\Release\CurrencyRatesChart.exe.CodeAnalysisLog.xml</CodeAnalysisLogFile>
+ <CodeAnalysisUseTypeNameInSuppression>true</CodeAnalysisUseTypeNameInSuppression>
+ <CodeAnalysisModuleSuppressionsFile>GlobalSuppressions.cs</CodeAnalysisModuleSuppressionsFile>
+ <ErrorReport>prompt</ErrorReport>
+ <CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>
+ <CodeAnalysisRuleSetDirectories>;C:\Program Files (x86)\Microsoft Visual Studio 10.0\Team Tools\Static Analysis Tools\\Rule Sets</CodeAnalysisRuleSetDirectories>
+ <CodeAnalysisRuleDirectories>;C:\Program Files (x86)\Microsoft Visual Studio 10.0\Team Tools\Static Analysis Tools\FxCop\\Rules</CodeAnalysisRuleDirectories>
+ </PropertyGroup>
+ <PropertyGroup>
+ <ApplicationIcon>main.ico</ApplicationIcon>
+ </PropertyGroup>
+ <ItemGroup>
+ <Reference Include="Microsoft.VisualBasic" />
+ <Reference Include="System" />
+ <Reference Include="System.Core" />
+ <Reference Include="System.Windows.Forms.DataVisualization" />
+ <Reference Include="System.Xml.Linq" />
+ <Reference Include="System.Data.DataSetExtensions" />
+ <Reference Include="System.Data" />
+ <Reference Include="System.Deployment" />
+ <Reference Include="System.Drawing" />
+ <Reference Include="System.Windows.Forms" />
+ <Reference Include="System.Xml" />
+ </ItemGroup>
+ <ItemGroup>
+ <Compile Include="Form1.cs">
+ <SubType>Form</SubType>
+ </Compile>
+ <Compile Include="Form1.Designer.cs">
+ <DependentUpon>Form1.cs</DependentUpon>
+ </Compile>
+ <Compile Include="Program.cs" />
+ <Compile Include="Properties\AssemblyInfo.cs" />
+ <EmbeddedResource Include="Form1.resx">
+ <DependentUpon>Form1.cs</DependentUpon>
+ </EmbeddedResource>
+ <EmbeddedResource Include="Properties\Resources.resx">
+ <Generator>ResXFileCodeGenerator</Generator>
+ <LastGenOutput>Resources.Designer.cs</LastGenOutput>
+ <SubType>Designer</SubType>
+ </EmbeddedResource>
+ <Compile Include="Properties\Resources.Designer.cs">
+ <AutoGen>True</AutoGen>
+ <DependentUpon>Resources.resx</DependentUpon>
+ <DesignTime>True</DesignTime>
+ </Compile>
+ <None Include="app.config" />
+ <None Include="Properties\Settings.settings">
+ <Generator>SettingsSingleFileGenerator</Generator>
+ <LastGenOutput>Settings.Designer.cs</LastGenOutput>
+ </None>
+ <Compile Include="Properties\Settings.Designer.cs">
+ <AutoGen>True</AutoGen>
+ <DependentUpon>Settings.settings</DependentUpon>
+ <DesignTimeSharedInput>True</DesignTimeSharedInput>
+ </Compile>
+ </ItemGroup>
+ <ItemGroup>
+ <Content Include="main.ico" />
+ </ItemGroup>
+ <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
+ <!-- To modify your build process, add your task inside one of the targets below and uncomment it.
+ Other similar extension points exist, see Microsoft.Common.targets.
+ <Target Name="BeforeBuild">
+ </Target>
+ <Target Name="AfterBuild">
+ </Target>
+ -->
+</Project> \ No newline at end of file
diff --git a/protocols/CurrencyRates/CurrencyRatesChart/Form1.Designer.cs b/protocols/CurrencyRates/CurrencyRatesChart/Form1.Designer.cs
new file mode 100644
index 0000000000..f00dc61cf4
--- /dev/null
+++ b/protocols/CurrencyRates/CurrencyRatesChart/Form1.Designer.cs
@@ -0,0 +1,123 @@
+namespace CurrencyRatesChart
+{
+ partial class FormMirandaCurrencyRatesChart
+ {
+ /// <summary>
+ /// Required designer variable.
+ /// </summary>
+ private System.ComponentModel.IContainer components = null;
+
+ /// <summary>
+ /// Clean up any resources being used.
+ /// </summary>
+ /// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
+ protected override void Dispose(bool disposing)
+ {
+ if (disposing && (components != null))
+ {
+ components.Dispose();
+ }
+ base.Dispose(disposing);
+ }
+
+ #region Windows Form Designer generated code
+
+ /// <summary>
+ /// Required method for Designer support - do not modify
+ /// the contents of this method with the code editor.
+ /// </summary>
+ private void InitializeComponent()
+ {
+ System.Windows.Forms.DataVisualization.Charting.ChartArea chartArea1 = new System.Windows.Forms.DataVisualization.Charting.ChartArea();
+ System.Windows.Forms.DataVisualization.Charting.Legend legend1 = new System.Windows.Forms.DataVisualization.Charting.Legend();
+ System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(FormMirandaCurrencyRatesChart));
+ this.chartCurrencyRates = new System.Windows.Forms.DataVisualization.Charting.Chart();
+ this.label1 = new System.Windows.Forms.Label();
+ this.dateFrom = new System.Windows.Forms.DateTimePicker();
+ this.dateTo = new System.Windows.Forms.DateTimePicker();
+ this.label2 = new System.Windows.Forms.Label();
+ ((System.ComponentModel.ISupportInitialize)(this.chartCurrencyRates)).BeginInit();
+ this.SuspendLayout();
+ //
+ // chartCurrencyRates
+ //
+ this.chartCurrencyRates.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom)
+ | System.Windows.Forms.AnchorStyles.Left)
+ | System.Windows.Forms.AnchorStyles.Right)));
+ chartArea1.Name = "ChartArea1";
+ this.chartCurrencyRates.ChartAreas.Add(chartArea1);
+ legend1.Docking = System.Windows.Forms.DataVisualization.Charting.Docking.Bottom;
+ legend1.Name = "Legend1";
+ this.chartCurrencyRates.Legends.Add(legend1);
+ this.chartCurrencyRates.Location = new System.Drawing.Point(2, 45);
+ this.chartCurrencyRates.Name = "chartCurrencyRates";
+ this.chartCurrencyRates.Size = new System.Drawing.Size(423, 433);
+ this.chartCurrencyRates.TabIndex = 0;
+ this.chartCurrencyRates.Text = "chart1";
+ //
+ // label1
+ //
+ this.label1.AutoSize = true;
+ this.label1.Location = new System.Drawing.Point(-1, 16);
+ this.label1.Name = "label1";
+ this.label1.Size = new System.Drawing.Size(30, 13);
+ this.label1.TabIndex = 1;
+ this.label1.Text = "From";
+ //
+ // dateFrom
+ //
+ this.dateFrom.Format = System.Windows.Forms.DateTimePickerFormat.Short;
+ this.dateFrom.Location = new System.Drawing.Point(35, 9);
+ this.dateFrom.Name = "dateFrom";
+ this.dateFrom.Size = new System.Drawing.Size(98, 20);
+ this.dateFrom.TabIndex = 2;
+ this.dateFrom.ValueChanged += new System.EventHandler(this.dateFrom_ValueChanged);
+ //
+ // dateTo
+ //
+ this.dateTo.Format = System.Windows.Forms.DateTimePickerFormat.Short;
+ this.dateTo.Location = new System.Drawing.Point(177, 10);
+ this.dateTo.Name = "dateTo";
+ this.dateTo.Size = new System.Drawing.Size(98, 20);
+ this.dateTo.TabIndex = 4;
+ this.dateTo.ValueChanged += new System.EventHandler(this.dateTo_ValueChanged);
+ //
+ // label2
+ //
+ this.label2.AutoSize = true;
+ this.label2.Location = new System.Drawing.Point(151, 16);
+ this.label2.Name = "label2";
+ this.label2.Size = new System.Drawing.Size(20, 13);
+ this.label2.TabIndex = 3;
+ this.label2.Text = "To";
+ //
+ // FormMirandaCurrencyRatesChart
+ //
+ this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
+ this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
+ this.ClientSize = new System.Drawing.Size(425, 477);
+ this.Controls.Add(this.dateTo);
+ this.Controls.Add(this.label2);
+ this.Controls.Add(this.dateFrom);
+ this.Controls.Add(this.label1);
+ this.Controls.Add(this.chartCurrencyRates);
+ this.Icon = ((System.Drawing.Icon)(resources.GetObject("$this.Icon")));
+ this.Name = "FormMirandaCurrencyRatesChart";
+ this.Text = "Miranda CurrencyRates Chart";
+ this.Load += new System.EventHandler(this.Form1_Load);
+ ((System.ComponentModel.ISupportInitialize)(this.chartCurrencyRates)).EndInit();
+ this.ResumeLayout(false);
+ this.PerformLayout();
+
+ }
+
+ #endregion
+
+ private System.Windows.Forms.DataVisualization.Charting.Chart chartCurrencyRates;
+ private System.Windows.Forms.Label label1;
+ private System.Windows.Forms.DateTimePicker dateFrom;
+ private System.Windows.Forms.DateTimePicker dateTo;
+ private System.Windows.Forms.Label label2;
+ }
+}
+
diff --git a/protocols/CurrencyRates/CurrencyRatesChart/Form1.cs b/protocols/CurrencyRates/CurrencyRatesChart/Form1.cs
new file mode 100644
index 0000000000..d26457e39f
--- /dev/null
+++ b/protocols/CurrencyRates/CurrencyRatesChart/Form1.cs
@@ -0,0 +1,155 @@
+using System;
+using System.Collections.Generic;
+using System.ComponentModel;
+using System.Data;
+using System.Drawing;
+using System.Linq;
+using System.Text;
+using System.Windows.Forms;
+using Microsoft.VisualBasic.FileIO;
+using System.Runtime.InteropServices;
+
+namespace CurrencyRatesChart
+{
+ public partial class FormMirandaCurrencyRatesChart : Form
+ {
+ public FormMirandaCurrencyRatesChart()
+ {
+ InitializeComponent();
+ }
+
+ private void Form1_Load(object sender, EventArgs e)
+ {
+ string[] cmd_line_args = Environment.GetCommandLineArgs();
+
+ for (int i = 1; i < cmd_line_args.Length; ++i)
+ {
+ string data_file = cmd_line_args[i];
+ AddDataFromFile(data_file);
+ }
+ }
+
+ private void dateFrom_ValueChanged(object sender, EventArgs e)
+ {
+ if (dateFrom.Value < dateTo.Value)
+ {
+ chartCurrencyRates.ChartAreas[0].AxisX.Minimum = dateFrom.Value.ToOADate();
+ chartCurrencyRates.Invalidate();
+ }
+ }
+
+ private void dateTo_ValueChanged(object sender, EventArgs e)
+ {
+ if (dateTo.Value > dateFrom.Value)
+ {
+ chartCurrencyRates.ChartAreas[0].AxisX.Maximum = dateTo.Value.ToOADate();
+ chartCurrencyRates.Invalidate();
+ }
+ }
+
+ int WM_COPYDATA = 0x4A;
+
+ public struct COPYDATASTRUCT
+ {
+ public IntPtr dwData;
+ public int cbData;
+ [MarshalAs(UnmanagedType.LPWStr)]
+ public String lpData;
+ }
+
+ protected override void WndProc(ref Message msg)
+ {
+ if (msg.Msg == WM_COPYDATA)
+ {
+ COPYDATASTRUCT cp = (COPYDATASTRUCT)Marshal.PtrToStructure(msg.LParam, typeof(COPYDATASTRUCT));
+
+ if (/**(cp.dwData) == 0x1945 && */cp.lpData != null)
+ {
+ AddDataFromFile(cp.lpData);
+ }
+
+ }
+ base.WndProc(ref msg);
+ }
+
+ private void AddDataFromFile(string data_file)
+ {
+ using (TextFieldParser parser = new Microsoft.VisualBasic.FileIO.TextFieldParser(data_file))
+ {
+ parser.TrimWhiteSpace = true;
+ parser.TextFieldType = FieldType.Delimited;
+ parser.SetDelimiters("\t");
+
+ System.Windows.Forms.DataVisualization.Charting.Series series = null;
+ while (true)
+ {
+ string[] parts = parser.ReadFields();
+ if (parts == null)
+ {
+ break;
+ }
+
+ if (parts.Length >= 3)
+ {
+ string name = parts[0];
+ string date = parts[1];
+ string value = parts[2];
+
+ if (series == null)
+ {
+ if (chartCurrencyRates.Series.FindByName(name) == null)
+ {
+ chartCurrencyRates.Series.Add(name);
+ series = chartCurrencyRates.Series[name];
+ series.ChartType = System.Windows.Forms.DataVisualization.Charting.SeriesChartType.Line;
+ }
+ else
+ {
+ break;
+ }
+ }
+
+ DateTime dt;
+ double d;
+ if (Double.TryParse(value, out d) && DateTime.TryParse(date, out dt))
+ {
+ series.Points.AddXY(dt, d);
+
+ if (!dateMin.HasValue)
+ {
+ dateMin = new DateTime();
+ dateMin = dt;
+ }
+ else if (dt < dateMin)
+ {
+ dateMin = dt;
+ }
+
+ if (!dateMax.HasValue)
+ {
+ dateMax = new DateTime();
+ dateMax = dt;
+ }
+ else if (dt > dateMax)
+ {
+ dateMax = dt;
+ }
+ }
+ }
+ }
+ }
+
+ if (dateMin.HasValue && dateMax.HasValue)
+ {
+ chartCurrencyRates.ChartAreas[0].AxisX.Minimum = dateMin.Value.ToOADate();
+ chartCurrencyRates.ChartAreas[0].AxisX.Maximum = dateMax.Value.ToOADate();
+
+ dateFrom.Value = dateMin.Value;
+ dateTo.Value = dateMax.Value;
+ }
+ }
+
+ private DateTime? dateMin = null;
+ private DateTime? dateMax = null;
+ }
+}
diff --git a/protocols/CurrencyRates/CurrencyRatesChart/Form1.resx b/protocols/CurrencyRates/CurrencyRatesChart/Form1.resx
new file mode 100644
index 0000000000..3d63dcc355
--- /dev/null
+++ b/protocols/CurrencyRates/CurrencyRatesChart/Form1.resx
@@ -0,0 +1,216 @@
+<?xml version="1.0" encoding="utf-8"?>
+<root>
+ <!--
+ Microsoft ResX Schema
+
+ Version 2.0
+
+ The primary goals of this format is to allow a simple XML format
+ that is mostly human readable. The generation and parsing of the
+ various data types are done through the TypeConverter classes
+ associated with the data types.
+
+ Example:
+
+ ... ado.net/XML headers & schema ...
+ <resheader name="resmimetype">text/microsoft-resx</resheader>
+ <resheader name="version">2.0</resheader>
+ <resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
+ <resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
+ <data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
+ <data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
+ <data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
+ <value>[base64 mime encoded serialized .NET Framework object]</value>
+ </data>
+ <data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
+ <value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
+ <comment>This is a comment</comment>
+ </data>
+
+ There are any number of "resheader" rows that contain simple
+ name/value pairs.
+
+ Each data row contains a name, and value. The row also contains a
+ type or mimetype. Type corresponds to a .NET class that support
+ text/value conversion through the TypeConverter architecture.
+ Classes that don't support this are serialized and stored with the
+ mimetype set.
+
+ The mimetype is used for serialized objects, and tells the
+ ResXResourceReader how to depersist the object. This is currently not
+ extensible. For a given mimetype the value must be set accordingly:
+
+ Note - application/x-microsoft.net.object.binary.base64 is the format
+ that the ResXResourceWriter will generate, however the reader can
+ read any of the formats listed below.
+
+ mimetype: application/x-microsoft.net.object.binary.base64
+ value : The object must be serialized with
+ : System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
+ : and then encoded with base64 encoding.
+
+ mimetype: application/x-microsoft.net.object.soap.base64
+ value : The object must be serialized with
+ : System.Runtime.Serialization.Formatters.Soap.SoapFormatter
+ : and then encoded with base64 encoding.
+
+ mimetype: application/x-microsoft.net.object.bytearray.base64
+ value : The object must be serialized into a byte array
+ : using a System.ComponentModel.TypeConverter
+ : and then encoded with base64 encoding.
+ -->
+ <xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
+ <xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
+ <xsd:element name="root" msdata:IsDataSet="true">
+ <xsd:complexType>
+ <xsd:choice maxOccurs="unbounded">
+ <xsd:element name="metadata">
+ <xsd:complexType>
+ <xsd:sequence>
+ <xsd:element name="value" type="xsd:string" minOccurs="0" />
+ </xsd:sequence>
+ <xsd:attribute name="name" use="required" type="xsd:string" />
+ <xsd:attribute name="type" type="xsd:string" />
+ <xsd:attribute name="mimetype" type="xsd:string" />
+ <xsd:attribute ref="xml:space" />
+ </xsd:complexType>
+ </xsd:element>
+ <xsd:element name="assembly">
+ <xsd:complexType>
+ <xsd:attribute name="alias" type="xsd:string" />
+ <xsd:attribute name="name" type="xsd:string" />
+ </xsd:complexType>
+ </xsd:element>
+ <xsd:element name="data">
+ <xsd:complexType>
+ <xsd:sequence>
+ <xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
+ <xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
+ </xsd:sequence>
+ <xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
+ <xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
+ <xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
+ <xsd:attribute ref="xml:space" />
+ </xsd:complexType>
+ </xsd:element>
+ <xsd:element name="resheader">
+ <xsd:complexType>
+ <xsd:sequence>
+ <xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
+ </xsd:sequence>
+ <xsd:attribute name="name" type="xsd:string" use="required" />
+ </xsd:complexType>
+ </xsd:element>
+ </xsd:choice>
+ </xsd:complexType>
+ </xsd:element>
+ </xsd:schema>
+ <resheader name="resmimetype">
+ <value>text/microsoft-resx</value>
+ </resheader>
+ <resheader name="version">
+ <value>2.0</value>
+ </resheader>
+ <resheader name="reader">
+ <value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
+ </resheader>
+ <resheader name="writer">
+ <value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
+ </resheader>
+ <assembly alias="System.Drawing" name="System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" />
+ <data name="$this.Icon" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
+ <value>
+ AAABAAIAICAAAAEAIACoEAAAJgAAABAQAAABACAAaAQAAM4QAAAoAAAAIAAAAEAAAAABACAAAAAAAIAQ
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAgAAAAYAAAAOAAAAFgAAABwAAAAgAAAAIAAAABwAAAAWAAAADgAA
+ AAYAAAACAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQAAAASAAAAJgAAADQAAABAAAAARAAAAEgAAABIAAAARAAA
+ AEAAAAA0AAAAJgAAABIAAAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIAAAAOAx80NAZKcmoUdaazH47D4ymh0vktrNf/L7DZ/yyo
+ 1v8lmMzzHYa72Q1ciJsFNldwAAAAPgAAACoAAAAOAAAAAgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAAAAFAdCb1QSgLO/MKjW71XI6/9l1PT/b9n4/3Xb
+ +v923Pr/cdn5/2nV9v9gz/L/Rbji+yecy+kIW42jAx0yWAAAADAAAAAUAAAAAgAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgQjPBoQcqKPKqPS81jR9P9j2fr/TtX6/zXQ
+ +f8eyvn/Esf4/wzE+P8Vxvj/Jcj4/zjM+P9R0fn/W9P4/z+75/8fkMXnBjVUcAMIDD4AAAAUAAAAAgAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFK0sWD2+mhzO14fdS0fb/RdP6/ybM
+ +f8PyPn/B8f5/wbH+f8Gx/n/Bsb5/wbE+P8Hw/j/CsL3/xXD9/8qx/j/Rcz3/1HN8/9RoLflO01JgQAA
+ ADAAAAAOAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABA14roMosuD3RNH6/ynN
+ +f8Kx/n/Bcj6/wTK+v8Eyvr/BMr7/wTK+v8Fyfr/Bcj6/wbG+f8GxPj/B8L3/wjA9/8ryvb/ecfE/8uj
+ Q/+ogjLxMicYZAAAACoAAAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIKW5g+Gp7R7zTJ
+ 9P8iyvn/Ccf5/wXJ+v8Ey/r/BMz7/wPN+/8Dzfv/A837/wTM+/8Eyvr/Bcj5/wbG+f8Hw/j/F8j4/2LC
+ wP+4mzT/4a40/9anNf9+YizHJBwWUAAAABIAAAACAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACViSEgyG
+ wLElw/H/I8r5/wnG+f8FyPr/BMv7/wPN+/8C0Pz/AtD8/wLR/f8C0Pz/A8/8/wPN+/8Eyvr/Bcj6/x7N
+ +P9hxcL/xZMY/9yiGP/epR//4Kwv/7uPKvtkTSSXAAAAJgAAAAYAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAJcrBEEqDV6yPI+P8Sxvn/Bcf5/wXK+v8Dzfv/A8/8/wLS/f8B0/3/AdP9/wHS/f8C0fz/A8/8/wTM
+ +/8Rzfr/YsjE/7ecMP/doxf/3aMY/92jGf/epyT/1qMq/5ZzLd8AAAA0AAAADgAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAyEv5kYtef/GMf4/wnF+P8FyPr/BMv6/wPO/P8C0fz/AdP9/wHV/v8A1v7/AdT+/wHS
+ /f8C0Pz/GdT7/2PMxf/JnBT/4asU/+CoFf/epRb/3aMX/92kG//eqCj/v5Aj/0U3KWoAAAAWAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAADo3J1xi+8P8Rxfj/BsX5/wXI+v8Ey/v/A8/8/wLR/f8B1P7/ANb+/wDX
+ //8A1v7/AdP9/wzT/f9lz8b/vqgs/+ayEf/lrxL/4qwT/+CoFf/epBf/3aMY/96oJP/RnSD/bFMvnQAA
+ ABwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAOmdD3GMH0/wzD+P8Gxfj/Bcj6/wTL+v8Dzvz/AtH8/wHU
+ /f8B1f7/ANb+/wTV/v8d2v3/ZdLG/9CqDv/svAz/67kN/+m1D//msBH/46wT/+CnFv/epBf/3qYf/9ij
+ I/+IZiS5AAAAIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA2h1f8Ywvb/CcL4/wfE+P8FyPr/BMr6/wPO
+ +/8C0Pz/AtL9/wzW/f844/7/Tub9/17Gyv/Fujz/8sQI//HCCf/uvgv/7LoN/+i0EP/lrxL/4aoU/9+m
+ Fv/dpB3/3KYl/5hxGb0AAAAgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADqbY/xnD9/8Iwff/B8P4/wfG
+ +f8Qzfr/JNf8/zPZ+v9IwOb/SaLU/yFZs/8MGZH/JCqJ/7+rXP/4zRD/9cgH//LDCf/vvwv/6rgO/+ey
+ Ef/jrBP/4KgV/96lHf/eqCX/oXYTuwAAABwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAASoNT9HcP2/w7C
+ 9/8izvn/R9/8/0nW9f81isj/Jlmy/xQ1sf8LGaz/DBu0/w0ct/8NHLD/Q0WF//zaOv/4zQj/9McH//DB
+ Cf/rug3/6LQP/+OtE//gqRX/3qYe/9umJf+Ych25AAAAFgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACql
+ 1PNNze//UbLc/zqOz/8UOKv/CRel/woavf8KG8f/ChvH/wobx/8KG8T/CxvB/wwcvP8MGrH/mItl//nW
+ KP/2yQb/8sMJ/+28DP/ptQ//5K4S/+GqFP/fqCH/1aEj/4ZlLKcAAAAOAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAALWeswTBar/8ZL7D/Cxqz/woaw/8JG8r/CRrN/wgaz/8IG9D/CRvP/wkbzP8KG8n/ChvD/wwc
+ vv8qMZj/y7Zb//bLDv/ywwn/7bwM/+m1D//krhL/4aoW/+CqJv/PnCH/clk3gwAAAAYAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAOGpNcGyiw8x4txv8NHsn/CBrP/wga0/8HGtf/BhnZ/wYa2v8GGtn/BxrW/wga
+ 0v8JGsz/ChvG/wsauv9MTIP/9tU///HDD//rug3/6LQP/+OtE//hqxz/3akq/7CGKPdLPDIqAAAAAgAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAwZlyoVI6vRJTTN/xUl0P8IGtX/Bhna/wYZ3/8FGeH/BRni/wUZ
+ 4f8GGd3/BxnZ/wga0v8JGsz/ChvD/woZsv+ajGb/9Msq/+q4Dv/nshH/460V/+KuJv/Woyv/mHQwxwAA
+ AAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAoXnWgiMcb7JTXZ/wsd3P8FGeL/BBjo/wMY
+ 6/8DGOv/Axjq/wQZ5v8FGeD/BxnZ/wga0v8KG8n/CxvB/ywzmP/IsV7/67oa/+WvEv/iryL/4a8x/7GI
+ Lel6XzNEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACxecFBknuM0wP9r/IDHk/wcb
+ 5/8DGO3/Ahfx/wIY8v8CGPD/Axjr/wQY5v8GGd3/BxnW/wkazP8KG8T/Cxu1/0xNgv/zzkH/5bIf/+S0
+ OP/WpjH/i2w4l2RQPQ4AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACRemLCEw
+ xMs/Tun/L0Dv/w0h8/8CGff/ARf5/wEX9v8CF/D/Axjq/wUZ4f8GGdn/CRvP/wobx/8MHLz/EB+u/6OV
+ dv/vy17/1Kg/+515OLkAAAACAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAALGKYEER6tPik4zuVJWO7/QVL3/yY4+/8HHf3/ARj5/wIX8v8DGOv/BRni/wYa2v8IG9D/DR3I/yAv
+ wv87R8P/ZWmt/868e/+jgT67fGJCKgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAACBauJB8uxKtDUuX1WWf2/1tp+/9EVPn/L0Hz/yg67v8mOOX/Lj7f/z5M
+ 2v9SXtf/XmjR/1Rexf0yPaXVTEt5hwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACBesGBMivmgkMsrPQE/i/Vto8P9qdvL/b3rx/3B7
+ 7f9teOb/Ym3b/1Jczf8zPrHnIy+ipQ0ZjDAPGooIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIF6s8BxWveAUV
+ tZ0FFbalBRWzqQYWq6MJF6KHCxicXg0ZlRQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP///////////+AB///AAP//AAA//gAAH/wA
+ AA/8AAAP+AAAB/AAAAPwAAAD8AAAA/AAAAPwAAAD8AAAA/AAAAPwAAAD8AAAA/AAAAPwAAAD8AAAA/AA
+ AAf4AAAP+AAAD/wAAB/8AAA//wAA//+AAP//8Af/////////////////KAAAABAAAAAgAAAAAQAgAAAA
+ AABABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAYAAAAcAAAALgAA
+ ADQAAAAuAAAAHAAAAAYAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAUuTR4bfqqTQK3W5U/A
+ 5/1Qw+n/RbLd8yaJtL0EME1YAAAAFgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAxaiS40rtndSdL4/ybN
+ +f8PyPn/C8X4/xzG+P87zPj/Prrm+TJkc4UAAAAWAAAAAAAAAAAAAAAAAAAAAAlTihAkq9rbJsz5/wbJ
+ +v8Ey/v/BMz7/wXK+v8Gxvn/C8P4/3C7rP/Lnzj7Tj0faAAAAAYAAAAAAAAAAAAAAAAOjsZ8H8f2/wbI
+ +v8Dzfv/AtH8/wLS/f8Dz/z/CMv6/2a9rP/Xnxj/3qci/6uCKdsAAAAcAAAAAAAAAAAAAAAAFKXb2w7F
+ +P8Fyvr/AtD8/wHU/v8A1v7/BNL9/2jGrP/dqhP/4KgV/92kGP/TnyT/TTwlTgAAAAAAAAAAAAAAABOv
+ 5P0IxPj/Bcn6/wPP/P8E1P3/I93+/2nLsv/ouwv/67oN/+WwEv/fpxb/3KUh/3tcGmwAAAAAAAAAAAAA
+ AAAWs+b/EMX4/yrS+f8spdz/LGzG/xEqrP9NTob/+M8W//HCCf/ptg//4aoU/92mIf+KZhVoAAAAAAAA
+ AAAAAAAANo/J7SxixP8MIbf/CRrI/wkby/8KG8b/Cxu8/6KSYP/0xwn/67kO/+OsFP/ZpCP/dlouTgAA
+ AAAAAAAAAAAAABYjqJMZKcv/BxrU/wYZ3P8GGd7/BxnY/wkazP8bJ63/3bw3/+m2D//irRr/wZMr70I0
+ LAwAAAAAAAAAAAAAAAAKF50eJDTN8Q4g4v8DGOz/Axju/wQY5v8HGdj/ChvG/1NTi//quiP/364v/5p3
+ MnQAAAAAAAAAAAAAAAAAAAAAAAAAABopu044SOb5HjH3/wIZ+f8DGO7/Bhne/woby/8eLLz/saF//7GM
+ PacAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGSi+OjxK38tPXfL/TFvx/0xa5v9RXdb/RlC94zY8
+ k2QAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABxauLgUVtlAGFa9SChefOA0Z
+ lQYAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD//wAA+A8AAPAHAADgAwAAwAEAAMABAADAAQAAwAEAAMAB
+ AADAAQAAwAEAAMADAADgBwAA8A8AAPwfAAD//wAA
+</value>
+ </data>
+</root> \ No newline at end of file
diff --git a/protocols/CurrencyRates/CurrencyRatesChart/Program.cs b/protocols/CurrencyRates/CurrencyRatesChart/Program.cs
new file mode 100644
index 0000000000..732fd0fc01
--- /dev/null
+++ b/protocols/CurrencyRates/CurrencyRatesChart/Program.cs
@@ -0,0 +1,21 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Windows.Forms;
+
+namespace CurrencyRatesChart
+{
+ static class Program
+ {
+ /// <summary>
+ /// The main entry point for the application.
+ /// </summary>
+ [STAThread]
+ static void Main(string[] args)
+ {
+ Application.EnableVisualStyles();
+ Application.SetCompatibleTextRenderingDefault(false);
+ Application.Run(new FormMirandaCurrencyRatesChart());
+ }
+ }
+}
diff --git a/protocols/CurrencyRates/CurrencyRatesChart/Properties/AssemblyInfo.cs b/protocols/CurrencyRates/CurrencyRatesChart/Properties/AssemblyInfo.cs
new file mode 100644
index 0000000000..765def9d57
--- /dev/null
+++ b/protocols/CurrencyRates/CurrencyRatesChart/Properties/AssemblyInfo.cs
@@ -0,0 +1,36 @@
+using System.Reflection;
+using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
+
+// General Information about an assembly is controlled through the following
+// set of attributes. Change these attribute values to modify the information
+// associated with an assembly.
+[assembly: AssemblyTitle("CurrencyRatesChart")]
+[assembly: AssemblyDescription("Chart Application for Miranda CurrencyRates plugin")]
+[assembly: AssemblyConfiguration("")]
+[assembly: AssemblyCompany("Dioksin")]
+[assembly: AssemblyProduct("Miranda")]
+[assembly: AssemblyCopyright("Don't worry!")]
+[assembly: AssemblyTrademark("")]
+[assembly: AssemblyCulture("")]
+
+// Setting ComVisible to false makes the types in this assembly not visible
+// to COM components. If you need to access a type in this assembly from
+// COM, set the ComVisible attribute to true on that type.
+[assembly: ComVisible(false)]
+
+// The following GUID is for the ID of the typelib if this project is exposed to COM
+[assembly: Guid("9b8250c7-ffbe-4f8a-985e-2e562e253dc4")]
+
+// Version information for an assembly consists of the following four values:
+//
+// Major Version
+// Minor Version
+// Build Number
+// Revision
+//
+// You can specify all the values or you can default the Build and Revision Numbers
+// by using the '*' as shown below:
+// [assembly: AssemblyVersion("1.0.*")]
+[assembly: AssemblyVersion("0.0.1.0")]
+[assembly: AssemblyFileVersion("1.0.0.0")]
diff --git a/protocols/CurrencyRates/CurrencyRatesChart/Properties/Resources.Designer.cs b/protocols/CurrencyRates/CurrencyRatesChart/Properties/Resources.Designer.cs
new file mode 100644
index 0000000000..141d83b862
--- /dev/null
+++ b/protocols/CurrencyRates/CurrencyRatesChart/Properties/Resources.Designer.cs
@@ -0,0 +1,63 @@
+//------------------------------------------------------------------------------
+// <auto-generated>
+// This code was generated by a tool.
+// Runtime Version:4.0.30319.42000
+//
+// Changes to this file may cause incorrect behavior and will be lost if
+// the code is regenerated.
+// </auto-generated>
+//------------------------------------------------------------------------------
+
+namespace CurrencyRatesChart.Properties {
+ using System;
+
+
+ /// <summary>
+ /// A strongly-typed resource class, for looking up localized strings, etc.
+ /// </summary>
+ // This class was auto-generated by the StronglyTypedResourceBuilder
+ // class via a tool like ResGen or Visual Studio.
+ // To add or remove a member, edit your .ResX file then rerun ResGen
+ // with the /str option, or rebuild your VS project.
+ [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")]
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
+ [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
+ internal class Resources {
+
+ private static global::System.Resources.ResourceManager resourceMan;
+
+ private static global::System.Globalization.CultureInfo resourceCulture;
+
+ [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
+ internal Resources() {
+ }
+
+ /// <summary>
+ /// Returns the cached ResourceManager instance used by this class.
+ /// </summary>
+ [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
+ internal static global::System.Resources.ResourceManager ResourceManager {
+ get {
+ if (object.ReferenceEquals(resourceMan, null)) {
+ global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("CurrencyRatesChart.Properties.Resources", typeof(Resources).Assembly);
+ resourceMan = temp;
+ }
+ return resourceMan;
+ }
+ }
+
+ /// <summary>
+ /// Overrides the current thread's CurrentUICulture property for all
+ /// resource lookups using this strongly typed resource class.
+ /// </summary>
+ [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
+ internal static global::System.Globalization.CultureInfo Culture {
+ get {
+ return resourceCulture;
+ }
+ set {
+ resourceCulture = value;
+ }
+ }
+ }
+}
diff --git a/protocols/CurrencyRates/CurrencyRatesChart/Properties/Resources.resx b/protocols/CurrencyRates/CurrencyRatesChart/Properties/Resources.resx
new file mode 100644
index 0000000000..af7dbebbac
--- /dev/null
+++ b/protocols/CurrencyRates/CurrencyRatesChart/Properties/Resources.resx
@@ -0,0 +1,117 @@
+<?xml version="1.0" encoding="utf-8"?>
+<root>
+ <!--
+ Microsoft ResX Schema
+
+ Version 2.0
+
+ The primary goals of this format is to allow a simple XML format
+ that is mostly human readable. The generation and parsing of the
+ various data types are done through the TypeConverter classes
+ associated with the data types.
+
+ Example:
+
+ ... ado.net/XML headers & schema ...
+ <resheader name="resmimetype">text/microsoft-resx</resheader>
+ <resheader name="version">2.0</resheader>
+ <resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
+ <resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
+ <data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
+ <data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
+ <data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
+ <value>[base64 mime encoded serialized .NET Framework object]</value>
+ </data>
+ <data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
+ <value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
+ <comment>This is a comment</comment>
+ </data>
+
+ There are any number of "resheader" rows that contain simple
+ name/value pairs.
+
+ Each data row contains a name, and value. The row also contains a
+ type or mimetype. Type corresponds to a .NET class that support
+ text/value conversion through the TypeConverter architecture.
+ Classes that don't support this are serialized and stored with the
+ mimetype set.
+
+ The mimetype is used for serialized objects, and tells the
+ ResXResourceReader how to depersist the object. This is currently not
+ extensible. For a given mimetype the value must be set accordingly:
+
+ Note - application/x-microsoft.net.object.binary.base64 is the format
+ that the ResXResourceWriter will generate, however the reader can
+ read any of the formats listed below.
+
+ mimetype: application/x-microsoft.net.object.binary.base64
+ value : The object must be serialized with
+ : System.Serialization.Formatters.Binary.BinaryFormatter
+ : and then encoded with base64 encoding.
+
+ mimetype: application/x-microsoft.net.object.soap.base64
+ value : The object must be serialized with
+ : System.Runtime.Serialization.Formatters.Soap.SoapFormatter
+ : and then encoded with base64 encoding.
+
+ mimetype: application/x-microsoft.net.object.bytearray.base64
+ value : The object must be serialized into a byte array
+ : using a System.ComponentModel.TypeConverter
+ : and then encoded with base64 encoding.
+ -->
+ <xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
+ <xsd:element name="root" msdata:IsDataSet="true">
+ <xsd:complexType>
+ <xsd:choice maxOccurs="unbounded">
+ <xsd:element name="metadata">
+ <xsd:complexType>
+ <xsd:sequence>
+ <xsd:element name="value" type="xsd:string" minOccurs="0" />
+ </xsd:sequence>
+ <xsd:attribute name="name" type="xsd:string" />
+ <xsd:attribute name="type" type="xsd:string" />
+ <xsd:attribute name="mimetype" type="xsd:string" />
+ </xsd:complexType>
+ </xsd:element>
+ <xsd:element name="assembly">
+ <xsd:complexType>
+ <xsd:attribute name="alias" type="xsd:string" />
+ <xsd:attribute name="name" type="xsd:string" />
+ </xsd:complexType>
+ </xsd:element>
+ <xsd:element name="data">
+ <xsd:complexType>
+ <xsd:sequence>
+ <xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
+ <xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
+ </xsd:sequence>
+ <xsd:attribute name="name" type="xsd:string" msdata:Ordinal="1" />
+ <xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
+ <xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
+ </xsd:complexType>
+ </xsd:element>
+ <xsd:element name="resheader">
+ <xsd:complexType>
+ <xsd:sequence>
+ <xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
+ </xsd:sequence>
+ <xsd:attribute name="name" type="xsd:string" use="required" />
+ </xsd:complexType>
+ </xsd:element>
+ </xsd:choice>
+ </xsd:complexType>
+ </xsd:element>
+ </xsd:schema>
+ <resheader name="resmimetype">
+ <value>text/microsoft-resx</value>
+ </resheader>
+ <resheader name="version">
+ <value>2.0</value>
+ </resheader>
+ <resheader name="reader">
+ <value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
+ </resheader>
+ <resheader name="writer">
+ <value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
+ </resheader>
+</root> \ No newline at end of file
diff --git a/protocols/CurrencyRates/CurrencyRatesChart/Properties/Settings.Designer.cs b/protocols/CurrencyRates/CurrencyRatesChart/Properties/Settings.Designer.cs
new file mode 100644
index 0000000000..b34f77d1b3
--- /dev/null
+++ b/protocols/CurrencyRates/CurrencyRatesChart/Properties/Settings.Designer.cs
@@ -0,0 +1,26 @@
+//------------------------------------------------------------------------------
+// <auto-generated>
+// This code was generated by a tool.
+// Runtime Version:4.0.30319.42000
+//
+// Changes to this file may cause incorrect behavior and will be lost if
+// the code is regenerated.
+// </auto-generated>
+//------------------------------------------------------------------------------
+
+namespace CurrencyRatesChart.Properties {
+
+
+ [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
+ [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "10.0.0.0")]
+ internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase {
+
+ private static Settings defaultInstance = ((Settings)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new Settings())));
+
+ public static Settings Default {
+ get {
+ return defaultInstance;
+ }
+ }
+ }
+}
diff --git a/protocols/CurrencyRates/CurrencyRatesChart/Properties/Settings.settings b/protocols/CurrencyRates/CurrencyRatesChart/Properties/Settings.settings
new file mode 100644
index 0000000000..39645652af
--- /dev/null
+++ b/protocols/CurrencyRates/CurrencyRatesChart/Properties/Settings.settings
@@ -0,0 +1,7 @@
+<?xml version='1.0' encoding='utf-8'?>
+<SettingsFile xmlns="http://schemas.microsoft.com/VisualStudio/2004/01/settings" CurrentProfile="(Default)">
+ <Profiles>
+ <Profile Name="(Default)" />
+ </Profiles>
+ <Settings />
+</SettingsFile>
diff --git a/protocols/CurrencyRates/CurrencyRatesChart/app.config b/protocols/CurrencyRates/CurrencyRatesChart/app.config
new file mode 100644
index 0000000000..e365603337
--- /dev/null
+++ b/protocols/CurrencyRates/CurrencyRatesChart/app.config
@@ -0,0 +1,3 @@
+<?xml version="1.0"?>
+<configuration>
+<startup><supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.0"/></startup></configuration>
diff --git a/protocols/CurrencyRates/CurrencyRatesChart/bin/x32/CurrencyRatesChart.exe b/protocols/CurrencyRates/CurrencyRatesChart/bin/x32/CurrencyRatesChart.exe
new file mode 100644
index 0000000000..9006c9f9c0
--- /dev/null
+++ b/protocols/CurrencyRates/CurrencyRatesChart/bin/x32/CurrencyRatesChart.exe
Binary files differ
diff --git a/protocols/CurrencyRates/CurrencyRatesChart/bin/x64/CurrencyRatesChart.exe b/protocols/CurrencyRates/CurrencyRatesChart/bin/x64/CurrencyRatesChart.exe
new file mode 100644
index 0000000000..221a27d11b
--- /dev/null
+++ b/protocols/CurrencyRates/CurrencyRatesChart/bin/x64/CurrencyRatesChart.exe
Binary files differ
diff --git a/protocols/CurrencyRates/CurrencyRatesChart/main.ico b/protocols/CurrencyRates/CurrencyRatesChart/main.ico
new file mode 100644
index 0000000000..da85d1f7c6
--- /dev/null
+++ b/protocols/CurrencyRates/CurrencyRatesChart/main.ico
Binary files differ
diff --git a/protocols/CurrencyRates/Forex.vcxproj b/protocols/CurrencyRates/Forex.vcxproj
new file mode 100644
index 0000000000..fec30452f6
--- /dev/null
+++ b/protocols/CurrencyRates/Forex.vcxproj
@@ -0,0 +1,36 @@
+<?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>CurrencyRates</ProjectName>
+ </PropertyGroup>
+ <ImportGroup Label="PropertySheets">
+ <Import Project="$(ProjectDir)..\..\build\vc.common\plugin.props" />
+ </ImportGroup>
+ <PropertyGroup>
+ <IncludePath>$(WindowsSdkDir)include;$(VCInstallDir)include;$(IncludePath)</IncludePath>
+ </PropertyGroup>
+ <ItemDefinitionGroup>
+ <ClCompile>
+ <ExceptionHandling>Sync</ExceptionHandling>
+ </ClCompile>
+ </ItemDefinitionGroup>
+</Project> \ No newline at end of file
diff --git a/protocols/CurrencyRates/Forex.vcxproj.filters b/protocols/CurrencyRates/Forex.vcxproj.filters
new file mode 100644
index 0000000000..fcae13a9d8
--- /dev/null
+++ b/protocols/CurrencyRates/Forex.vcxproj.filters
@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <Import Project="$(ProjectDir)..\..\build\vc.common\common.filters" />
+</Project> \ No newline at end of file
diff --git a/protocols/CurrencyRates/docs/Utility/cc.xml b/protocols/CurrencyRates/docs/Utility/cc.xml
new file mode 100644
index 0000000000..232d7d6488
--- /dev/null
+++ b/protocols/CurrencyRates/docs/Utility/cc.xml
@@ -0,0 +1,518 @@
+<?xml version="1.0" encoding="utf-8"?>
+
+<Provider>
+ <name>Currency Converter API</name>
+ <ref>https://www.currencyconverterapi.com/</ref>
+ <url>https://free.currencyconverterapi.com/api/v5/convert</url>
+
+<section>
+ <name>Currencies</name>
+ <currencyrate>
+ <id>AED</id><symbol>AED</symbol><description>United Arab Emirates Dirham (AED)</description>
+ </currencyrate>
+ <currencyrate>
+ <id>AFN</id><symbol>AFN</symbol><description>Afghan Afghani (AFN)</description>
+ </currencyrate>
+ <currencyrate>
+ <id>ALL</id><symbol>ALL</symbol><description>Albanian Lek (ALL)</description>
+ </currencyrate>
+ <currencyrate>
+ <id>AMD</id><symbol>AMD</symbol><description>Armenian Dram (AMD)</description>
+ </currencyrate>
+ <currencyrate>
+ <id>ANG</id><symbol>ANG</symbol><description>Netherlands Antillean Gulden (ANG)</description>
+ </currencyrate>
+ <currencyrate>
+ <id>AOA</id><symbol>AOA</symbol><description>Angolan Kwanza (AOA)</description>
+ </currencyrate>
+ <currencyrate>
+ <id>ARS</id><symbol>ARS</symbol><description>Argentine Peso (ARS)</description>
+ </currencyrate>
+ <currencyrate>
+ <id>AUD</id><symbol>AUD</symbol><description>Australian Dollar (AUD)</description>
+ </currencyrate>
+ <currencyrate>
+ <id>AWG</id><symbol>AWG</symbol><description>Aruban Florin (AWG)</description>
+ </currencyrate>
+ <currencyrate>
+ <id>AZN</id><symbol>AZN</symbol><description>Azerbaijani Manat (AZN)</description>
+ </currencyrate>
+ <currencyrate>
+ <id>BAM</id><symbol>BAM</symbol><description>Bosnia-Herzegovina Convertible Mark (BAM)</description>
+ </currencyrate>
+ <currencyrate>
+ <id>BBD</id><symbol>BBD</symbol><description>Barbadian Dollar (BBD)</description>
+ </currencyrate>
+ <currencyrate>
+ <id>BDT</id><symbol>BDT</symbol><description>Bangladeshi Taka (BDT)</description>
+ </currencyrate>
+ <currencyrate>
+ <id>BGN</id><symbol>BGN</symbol><description>Bulgarian Lev (BGN)</description>
+ </currencyrate>
+ <currencyrate>
+ <id>BHD</id><symbol>BHD</symbol><description>Bahraini Dinar (BHD)</description>
+ </currencyrate>
+ <currencyrate>
+ <id>BIF</id><symbol>BIF</symbol><description>Burundian Franc (BIF)</description>
+ </currencyrate>
+ <currencyrate>
+ <id>BMD</id><symbol>BMD</symbol><description>Bermudan Dollar (BMD)</description>
+ </currencyrate>
+ <currencyrate>
+ <id>BND</id><symbol>BND</symbol><description>Brunei Dollar (BND)</description>
+ </currencyrate>
+ <currencyrate>
+ <id>BOB</id><symbol>BOB</symbol><description>Bolivian Boliviano (BOB)</description>
+ </currencyrate>
+ <currencyrate>
+ <id>BRL</id><symbol>BRL</symbol><description>Brazilian Real (BRL)</description>
+ </currencyrate>
+ <currencyrate>
+ <id>BSD</id><symbol>BSD</symbol><description>Bahamian Dollar (BSD)</description>
+ </currencyrate>
+ <currencyrate>
+ <id>BTC</id><symbol>BTC</symbol><description>Bitcoin (BTC)</description>
+ </currencyrate>
+ <currencyrate>
+ <id>BTN</id><symbol>BTN</symbol><description>Bhutanese Ngultrum (BTN)</description>
+ </currencyrate>
+ <currencyrate>
+ <id>BWP</id><symbol>BWP</symbol><description>Botswana Pula (BWP)</description>
+ </currencyrate>
+ <currencyrate>
+ <id>BYN</id><symbol>BYN</symbol><description>Belarusian Ruble (BYN)</description>
+ </currencyrate>
+ <currencyrate>
+ <id>BYR</id><symbol>BYR</symbol><description>Belarusian Ruble (2000–2016) (BYR)</description>
+ </currencyrate>
+ <currencyrate>
+ <id>BZD</id><symbol>BZD</symbol><description>Belize Dollar (BZD)</description>
+ </currencyrate>
+ <currencyrate>
+ <id>CAD</id><symbol>CAD</symbol><description>Canadian Dollar (CAD)</description>
+ </currencyrate>
+ <currencyrate>
+ <id>CDF</id><symbol>CDF</symbol><description>Congolese Franc (CDF)</description>
+ </currencyrate>
+ <currencyrate>
+ <id>CHF</id><symbol>CHF</symbol><description>Swiss Franc (CHF)</description>
+ </currencyrate>
+ <currencyrate>
+ <id>CLF</id><symbol>CLF</symbol><description>Chilean Unit of Account (UF) (CLF)</description>
+ </currencyrate>
+ <currencyrate>
+ <id>CLP</id><symbol>CLP</symbol><description>Chilean Peso (CLP)</description>
+ </currencyrate>
+ <currencyrate>
+ <id>CNH</id><symbol>CNH</symbol><description>CNH (CNH)</description>
+ </currencyrate>
+ <currencyrate>
+ <id>CNY</id><symbol>CNY</symbol><description>Chinese Yuan (CNY)</description>
+ </currencyrate>
+ <currencyrate>
+ <id>COP</id><symbol>COP</symbol><description>Colombian Peso (COP)</description>
+ </currencyrate>
+ <currencyrate>
+ <id>CRC</id><symbol>CRC</symbol><description>Costa Rican Colón (CRC)</description>
+ </currencyrate>
+ <currencyrate>
+ <id>CUP</id><symbol>CUP</symbol><description>Cuban Peso (CUP)</description>
+ </currencyrate>
+ <currencyrate>
+ <id>CVE</id><symbol>CVE</symbol><description>Cape Verdean Escudo (CVE)</description>
+ </currencyrate>
+ <currencyrate>
+ <id>CZK</id><symbol>CZK</symbol><description>Czech Koruna (CZK)</description>
+ </currencyrate>
+ <currencyrate>
+ <id>DEM</id><symbol>DEM</symbol><description>German Mark (DEM)</description>
+ </currencyrate>
+ <currencyrate>
+ <id>DJF</id><symbol>DJF</symbol><description>Djiboutian Franc (DJF)</description>
+ </currencyrate>
+ <currencyrate>
+ <id>DKK</id><symbol>DKK</symbol><description>Danish Krone (DKK)</description>
+ </currencyrate>
+ <currencyrate>
+ <id>DOP</id><symbol>DOP</symbol><description>Dominican Peso (DOP)</description>
+ </currencyrate>
+ <currencyrate>
+ <id>DZD</id><symbol>DZD</symbol><description>Algerian Dinar (DZD)</description>
+ </currencyrate>
+ <currencyrate>
+ <id>EGP</id><symbol>EGP</symbol><description>Egyptian Pound (EGP)</description>
+ </currencyrate>
+ <currencyrate>
+ <id>ERN</id><symbol>ERN</symbol><description>Eritrean Nakfa (ERN)</description>
+ </currencyrate>
+ <currencyrate>
+ <id>ETB</id><symbol>ETB</symbol><description>Ethiopian Birr (ETB)</description>
+ </currencyrate>
+ <currencyrate>
+ <id>EUR</id><symbol>EUR</symbol><description>Euro (EUR)</description>
+ </currencyrate>
+ <currencyrate>
+ <id>FIM</id><symbol>FIM</symbol><description>Finnish Markka (FIM)</description>
+ </currencyrate>
+ <currencyrate>
+ <id>FJD</id><symbol>FJD</symbol><description>Fijian Dollar (FJD)</description>
+ </currencyrate>
+ <currencyrate>
+ <id>FKP</id><symbol>FKP</symbol><description>Falkland Islands Pound (FKP)</description>
+ </currencyrate>
+ <currencyrate>
+ <id>FRF</id><symbol>FRF</symbol><description>French Franc (FRF)</description>
+ </currencyrate>
+ <currencyrate>
+ <id>GBP</id><symbol>GBP</symbol><description>British Pound (GBP)</description>
+ </currencyrate>
+ <currencyrate>
+ <id>GEL</id><symbol>GEL</symbol><description>Georgian Lari (GEL)</description>
+ </currencyrate>
+ <currencyrate>
+ <id>GHS</id><symbol>GHS</symbol><description>Ghanaian Cedi (GHS)</description>
+ </currencyrate>
+ <currencyrate>
+ <id>GIP</id><symbol>GIP</symbol><description>Gibraltar Pound (GIP)</description>
+ </currencyrate>
+ <currencyrate>
+ <id>GMD</id><symbol>GMD</symbol><description>Gambian Dalasi (GMD)</description>
+ </currencyrate>
+ <currencyrate>
+ <id>GNF</id><symbol>GNF</symbol><description>Guinean Franc (GNF)</description>
+ </currencyrate>
+ <currencyrate>
+ <id>GTQ</id><symbol>GTQ</symbol><description>Guatemalan Quetzal (GTQ)</description>
+ </currencyrate>
+ <currencyrate>
+ <id>GYD</id><symbol>GYD</symbol><description>Guyanaese Dollar (GYD)</description>
+ </currencyrate>
+ <currencyrate>
+ <id>HKD</id><symbol>HKD</symbol><description>Hong Kong Dollar (HKD)</description>
+ </currencyrate>
+ <currencyrate>
+ <id>HNL</id><symbol>HNL</symbol><description>Honduran Lempira (HNL)</description>
+ </currencyrate>
+ <currencyrate>
+ <id>HRK</id><symbol>HRK</symbol><description>Croatian Kuna (HRK)</description>
+ </currencyrate>
+ <currencyrate>
+ <id>HTG</id><symbol>HTG</symbol><description>Haitian Gourde (HTG)</description>
+ </currencyrate>
+ <currencyrate>
+ <id>HUF</id><symbol>HUF</symbol><description>Hungarian Forint (HUF)</description>
+ </currencyrate>
+ <currencyrate>
+ <id>IDR</id><symbol>IDR</symbol><description>Indonesian Rupiah (IDR)</description>
+ </currencyrate>
+ <currencyrate>
+ <id>IEP</id><symbol>IEP</symbol><description>Irish Pound (IEP)</description>
+ </currencyrate>
+ <currencyrate>
+ <id>ILS</id><symbol>ILS</symbol><description>Israeli New Shekel (ILS)</description>
+ </currencyrate>
+ <currencyrate>
+ <id>INR</id><symbol>INR</symbol><description>Indian Rupee (INR)</description>
+ </currencyrate>
+ <currencyrate>
+ <id>IQD</id><symbol>IQD</symbol><description>Iraqi Dinar (IQD)</description>
+ </currencyrate>
+ <currencyrate>
+ <id>IRR</id><symbol>IRR</symbol><description>Iranian Rial (IRR)</description>
+ </currencyrate>
+ <currencyrate>
+ <id>ISK</id><symbol>ISK</symbol><description>Icelandic Króna (ISK)</description>
+ </currencyrate>
+ <currencyrate>
+ <id>ITL</id><symbol>ITL</symbol><description>Italian Lira (ITL)</description>
+ </currencyrate>
+ <currencyrate>
+ <id>JMD</id><symbol>JMD</symbol><description>Jamaican Dollar (JMD)</description>
+ </currencyrate>
+ <currencyrate>
+ <id>JOD</id><symbol>JOD</symbol><description>Jordanian Dinar (JOD)</description>
+ </currencyrate>
+ <currencyrate>
+ <id>JPY</id><symbol>JPY</symbol><description>Japanese Yen (JPY)</description>
+ </currencyrate>
+ <currencyrate>
+ <id>KES</id><symbol>KES</symbol><description>Kenyan Shilling (KES)</description>
+ </currencyrate>
+ <currencyrate>
+ <id>KGS</id><symbol>KGS</symbol><description>Kyrgystani Som (KGS)</description>
+ </currencyrate>
+ <currencyrate>
+ <id>KHR</id><symbol>KHR</symbol><description>Cambodian Riel (KHR)</description>
+ </currencyrate>
+ <currencyrate>
+ <id>KMF</id><symbol>KMF</symbol><description>Comorian Franc (KMF)</description>
+ </currencyrate>
+ <currencyrate>
+ <id>KPW</id><symbol>KPW</symbol><description>North Korean Won (KPW)</description>
+ </currencyrate>
+ <currencyrate>
+ <id>KRW</id><symbol>KRW</symbol><description>South Korean Won (KRW)</description>
+ </currencyrate>
+ <currencyrate>
+ <id>KWD</id><symbol>KWD</symbol><description>Kuwaiti Dinar (KWD)</description>
+ </currencyrate>
+ <currencyrate>
+ <id>KYD</id><symbol>KYD</symbol><description>Cayman Islands Dollar (KYD)</description>
+ </currencyrate>
+ <currencyrate>
+ <id>KZT</id><symbol>KZT</symbol><description>Kazakhstani Tenge (KZT)</description>
+ </currencyrate>
+ <currencyrate>
+ <id>LAK</id><symbol>LAK</symbol><description>Laotian Kip (LAK)</description>
+ </currencyrate>
+ <currencyrate>
+ <id>LBP</id><symbol>LBP</symbol><description>Lebanese Pound (LBP)</description>
+ </currencyrate>
+ <currencyrate>
+ <id>LKR</id><symbol>LKR</symbol><description>Sri Lankan Rupee (LKR)</description>
+ </currencyrate>
+ <currencyrate>
+ <id>LRD</id><symbol>LRD</symbol><description>Liberian Dollar (LRD)</description>
+ </currencyrate>
+ <currencyrate>
+ <id>LSL</id><symbol>LSL</symbol><description>Lesotho Loti (LSL)</description>
+ </currencyrate>
+ <currencyrate>
+ <id>LTL</id><symbol>LTL</symbol><description>Lithuanian Litas (LTL)</description>
+ </currencyrate>
+ <currencyrate>
+ <id>LVL</id><symbol>LVL</symbol><description>Latvian Lats (LVL)</description>
+ </currencyrate>
+ <currencyrate>
+ <id>LYD</id><symbol>LYD</symbol><description>Libyan Dinar (LYD)</description>
+ </currencyrate>
+ <currencyrate>
+ <id>MAD</id><symbol>MAD</symbol><description>Moroccan Dirham (MAD)</description>
+ </currencyrate>
+ <currencyrate>
+ <id>MDL</id><symbol>MDL</symbol><description>Moldovan Leu (MDL)</description>
+ </currencyrate>
+ <currencyrate>
+ <id>MGA</id><symbol>MGA</symbol><description>Malagasy Ariary (MGA)</description>
+ </currencyrate>
+ <currencyrate>
+ <id>MKD</id><symbol>MKD</symbol><description>Macedonian Denar (MKD)</description>
+ </currencyrate>
+ <currencyrate>
+ <id>MNT</id><symbol>MNT</symbol><description>Mongolian Tugrik (MNT)</description>
+ </currencyrate>
+ <currencyrate>
+ <id>MOP</id><symbol>MOP</symbol><description>Macanese Pataca (MOP)</description>
+ </currencyrate>
+ <currencyrate>
+ <id>MRO</id><symbol>MRO</symbol><description>Mauritanian Ouguiya (MRO)</description>
+ </currencyrate>
+ <currencyrate>
+ <id>MUR</id><symbol>MUR</symbol><description>Mauritian Rupee (MUR)</description>
+ </currencyrate>
+ <currencyrate>
+ <id>MVR</id><symbol>MVR</symbol><description>Maldivian Rufiyaa (MVR)</description>
+ </currencyrate>
+ <currencyrate>
+ <id>MWK</id><symbol>MWK</symbol><description>Malawian Kwacha (MWK)</description>
+ </currencyrate>
+ <currencyrate>
+ <id>MXN</id><symbol>MXN</symbol><description>Mexican Peso (MXN)</description>
+ </currencyrate>
+ <currencyrate>
+ <id>MYR</id><symbol>MYR</symbol><description>Malaysian Ringgit (MYR)</description>
+ </currencyrate>
+ <currencyrate>
+ <id>MZN</id><symbol>MZN</symbol><description>Mozambican Metical (MZN)</description>
+ </currencyrate>
+ <currencyrate>
+ <id>NAD</id><symbol>NAD</symbol><description>Namibian Dollar (NAD)</description>
+ </currencyrate>
+ <currencyrate>
+ <id>NGN</id><symbol>NGN</symbol><description>Nigerian Naira (NGN)</description>
+ </currencyrate>
+ <currencyrate>
+ <id>NIO</id><symbol>NIO</symbol><description>Nicaraguan Córdoba (NIO)</description>
+ </currencyrate>
+ <currencyrate>
+ <id>NOK</id><symbol>NOK</symbol><description>Norwegian Krone (NOK)</description>
+ </currencyrate>
+ <currencyrate>
+ <id>NPR</id><symbol>NPR</symbol><description>Nepalese Rupee (NPR)</description>
+ </currencyrate>
+ <currencyrate>
+ <id>NZD</id><symbol>NZD</symbol><description>New Zealand Dollar (NZD)</description>
+ </currencyrate>
+ <currencyrate>
+ <id>OMR</id><symbol>OMR</symbol><description>Omani Rial (OMR)</description>
+ </currencyrate>
+ <currencyrate>
+ <id>PAB</id><symbol>PAB</symbol><description>Panamanian Balboa (PAB)</description>
+ </currencyrate>
+ <currencyrate>
+ <id>PEN</id><symbol>PEN</symbol><description>Peruvian Nuevo Sol (PEN)</description>
+ </currencyrate>
+ <currencyrate>
+ <id>PGK</id><symbol>PGK</symbol><description>Papua New Guinean Kina (PGK)</description>
+ </currencyrate>
+ <currencyrate>
+ <id>PHP</id><symbol>PHP</symbol><description>Philippine Peso (PHP)</description>
+ </currencyrate>
+ <currencyrate>
+ <id>PKG</id><symbol>PKG</symbol><description>PKG (PKG)</description>
+ </currencyrate>
+ <currencyrate>
+ <id>PKR</id><symbol>PKR</symbol><description>Pakistani Rupee (PKR)</description>
+ </currencyrate>
+ <currencyrate>
+ <id>PLN</id><symbol>PLN</symbol><description>Polish Zloty (PLN)</description>
+ </currencyrate>
+ <currencyrate>
+ <id>PYG</id><symbol>PYG</symbol><description>Paraguayan Guarani (PYG)</description>
+ </currencyrate>
+ <currencyrate>
+ <id>QAR</id><symbol>QAR</symbol><description>Qatari Riyal (QAR)</description>
+ </currencyrate>
+ <currencyrate>
+ <id>RON</id><symbol>RON</symbol><description>New Romanian Leu (RON)</description>
+ </currencyrate>
+ <currencyrate>
+ <id>RSD</id><symbol>RSD</symbol><description>Serbian Dinar (RSD)</description>
+ </currencyrate>
+ <currencyrate>
+ <id>RUB</id><symbol>RUB</symbol><description>Russian Ruble (RUB)</description>
+ </currencyrate>
+ <currencyrate>
+ <id>RWF</id><symbol>RWF</symbol><description>Rwandan Franc (RWF)</description>
+ </currencyrate>
+ <currencyrate>
+ <id>SAR</id><symbol>SAR</symbol><description>Saudi Riyal (SAR)</description>
+ </currencyrate>
+ <currencyrate>
+ <id>SBD</id><symbol>SBD</symbol><description>Solomon Islands Dollar (SBD)</description>
+ </currencyrate>
+ <currencyrate>
+ <id>SCR</id><symbol>SCR</symbol><description>Seychellois Rupee (SCR)</description>
+ </currencyrate>
+ <currencyrate>
+ <id>SDG</id><symbol>SDG</symbol><description>Sudanese Pound (SDG)</description>
+ </currencyrate>
+ <currencyrate>
+ <id>SEK</id><symbol>SEK</symbol><description>Swedish Krona (SEK)</description>
+ </currencyrate>
+ <currencyrate>
+ <id>SGD</id><symbol>SGD</symbol><description>Singapore Dollar (SGD)</description>
+ </currencyrate>
+ <currencyrate>
+ <id>SHP</id><symbol>SHP</symbol><description>St. Helena Pound (SHP)</description>
+ </currencyrate>
+ <currencyrate>
+ <id>SKK</id><symbol>SKK</symbol><description>Slovak Koruna (SKK)</description>
+ </currencyrate>
+ <currencyrate>
+ <id>SLL</id><symbol>SLL</symbol><description>Sierra Leonean Leone (SLL)</description>
+ </currencyrate>
+ <currencyrate>
+ <id>SOS</id><symbol>SOS</symbol><description>Somali Shilling (SOS)</description>
+ </currencyrate>
+ <currencyrate>
+ <id>SRD</id><symbol>SRD</symbol><description>Surinamese Dollar (SRD)</description>
+ </currencyrate>
+ <currencyrate>
+ <id>STD</id><symbol>STD</symbol><description>São Tomé and Príncipe Dobra (STD)</description>
+ </currencyrate>
+ <currencyrate>
+ <id>SVC</id><symbol>SVC</symbol><description>Salvadoran Colón (SVC)</description>
+ </currencyrate>
+ <currencyrate>
+ <id>SYP</id><symbol>SYP</symbol><description>Syrian Pound (SYP)</description>
+ </currencyrate>
+ <currencyrate>
+ <id>SZL</id><symbol>SZL</symbol><description>Swazi Lilangeni (SZL)</description>
+ </currencyrate>
+ <currencyrate>
+ <id>THB</id><symbol>THB</symbol><description>Thai Baht (THB)</description>
+ </currencyrate>
+ <currencyrate>
+ <id>TJS</id><symbol>TJS</symbol><description>Tajikistani Somoni (TJS)</description>
+ </currencyrate>
+ <currencyrate>
+ <id>TMT</id><symbol>TMT</symbol><description>Turkmenistani Manat (TMT)</description>
+ </currencyrate>
+ <currencyrate>
+ <id>TND</id><symbol>TND</symbol><description>Tunisian Dinar (TND)</description>
+ </currencyrate>
+ <currencyrate>
+ <id>TOP</id><symbol>TOP</symbol><description>Tongan Paʻanga (TOP)</description>
+ </currencyrate>
+ <currencyrate>
+ <id>TRY</id><symbol>TRY</symbol><description>Turkish Lira (TRY)</description>
+ </currencyrate>
+ <currencyrate>
+ <id>TTD</id><symbol>TTD</symbol><description>Trinidad and Tobago Dollar (TTD)</description>
+ </currencyrate>
+ <currencyrate>
+ <id>TWD</id><symbol>TWD</symbol><description>New Taiwan Dollar (TWD)</description>
+ </currencyrate>
+ <currencyrate>
+ <id>TZS</id><symbol>TZS</symbol><description>Tanzanian Shilling (TZS)</description>
+ </currencyrate>
+ <currencyrate>
+ <id>UAH</id><symbol>UAH</symbol><description>Ukrainian Hryvnia (UAH)</description>
+ </currencyrate>
+ <currencyrate>
+ <id>UGX</id><symbol>UGX</symbol><description>Ugandan Shilling (UGX)</description>
+ </currencyrate>
+ <currencyrate>
+ <id>USD</id><symbol>USD</symbol><description>United States Dollar (USD)</description>
+ </currencyrate>
+ <currencyrate>
+ <id>UYU</id><symbol>UYU</symbol><description>Uruguayan Peso (UYU)</description>
+ </currencyrate>
+ <currencyrate>
+ <id>UZS</id><symbol>UZS</symbol><description>Uzbekistani Som (UZS)</description>
+ </currencyrate>
+ <currencyrate>
+ <id>VEF</id><symbol>VEF</symbol><description>Venezuelan Bolívar (VEF)</description>
+ </currencyrate>
+ <currencyrate>
+ <id>VND</id><symbol>VND</symbol><description>Vietnamese Dong (VND)</description>
+ </currencyrate>
+ <currencyrate>
+ <id>VUV</id><symbol>VUV</symbol><description>Vanuatu Vatu (VUV)</description>
+ </currencyrate>
+ <currencyrate>
+ <id>WST</id><symbol>WST</symbol><description>Samoan Tala (WST)</description>
+ </currencyrate>
+ <currencyrate>
+ <id>XAF</id><symbol>XAF</symbol><description>Central African CFA Franc (FCFA)</description>
+ </currencyrate>
+ <currencyrate>
+ <id>XCD</id><symbol>XCD</symbol><description>East Caribbean Dollar (XCD)</description>
+ </currencyrate>
+ <currencyrate>
+ <id>XDR</id><symbol>XDR</symbol><description>Special Drawing Rights (XDR)</description>
+ </currencyrate>
+ <currencyrate>
+ <id>XOF</id><symbol>XOF</symbol><description>West African CFA Franc (CFA)</description>
+ </currencyrate>
+ <currencyrate>
+ <id>XPF</id><symbol>XPF</symbol><description>CFP Franc (CFPF)</description>
+ </currencyrate>
+ <currencyrate>
+ <id>YER</id><symbol>YER</symbol><description>Yemeni Rial (YER)</description>
+ </currencyrate>
+ <currencyrate>
+ <id>ZAR</id><symbol>ZAR</symbol><description>South African Rand (ZAR)</description>
+ </currencyrate>
+ <currencyrate>
+ <id>ZMK</id><symbol>ZMK</symbol><description>Zambian Kwacha (1968–2012) (ZMK)</description>
+ </currencyrate>
+ <currencyrate>
+ <id>ZMW</id><symbol>ZMW</symbol><description>Zambian Kwacha (ZMW)</description>
+ </currencyrate>
+ <currencyrate>
+ <id>ZWL</id><symbol>ZWL</symbol><description>Zimbabwean Dollar (2009) (ZWL)</description>
+ </currencyrate>
+</section>
+</Provider> \ No newline at end of file
diff --git a/protocols/CurrencyRates/proto_CurrencyRates/proto_CurrencyRates.vcxproj b/protocols/CurrencyRates/proto_CurrencyRates/proto_CurrencyRates.vcxproj
new file mode 100644
index 0000000000..b3b9b70855
--- /dev/null
+++ b/protocols/CurrencyRates/proto_CurrencyRates/proto_CurrencyRates.vcxproj
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <ItemGroup Label="ProjectConfigurations">
+ <ProjectConfiguration Include="Debug|Win32">
+ <Configuration>Debug</Configuration>
+ <Platform>Win32</Platform>
+ </ProjectConfiguration>
+ <ProjectConfiguration Include="Debug|x64">
+ <Configuration>Debug</Configuration>
+ <Platform>x64</Platform>
+ </ProjectConfiguration>
+ <ProjectConfiguration Include="Release|Win32">
+ <Configuration>Release</Configuration>
+ <Platform>Win32</Platform>
+ </ProjectConfiguration>
+ <ProjectConfiguration Include="Release|x64">
+ <Configuration>Release</Configuration>
+ <Platform>x64</Platform>
+ </ProjectConfiguration>
+ </ItemGroup>
+ <PropertyGroup Label="Globals">
+ <ProjectName>Proto_CurrencyRates</ProjectName>
+ <ProjectGuid>{5A0A9761-78E1-4E0F-AD8C-8931A667A5F2}</ProjectGuid>
+ </PropertyGroup>
+ <ImportGroup Label="PropertySheets">
+ <Import Project="$(ProjectDir)..\..\..\build\vc.common\icons.props" />
+ </ImportGroup>
+</Project> \ No newline at end of file
diff --git a/protocols/CurrencyRates/proto_CurrencyRates/proto_CurrencyRates.vcxproj.filters b/protocols/CurrencyRates/proto_CurrencyRates/proto_CurrencyRates.vcxproj.filters
new file mode 100644
index 0000000000..28f81e7f1b
--- /dev/null
+++ b/protocols/CurrencyRates/proto_CurrencyRates/proto_CurrencyRates.vcxproj.filters
@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <Import Project="$(ProjectDir)..\..\..\build\vc.common\common.filters" />
+</Project> \ No newline at end of file
diff --git a/protocols/CurrencyRates/proto_CurrencyRates/res/proto_CurrencyRates.rc b/protocols/CurrencyRates/proto_CurrencyRates/res/proto_CurrencyRates.rc
new file mode 100644
index 0000000000..16b7546399
--- /dev/null
+++ b/protocols/CurrencyRates/proto_CurrencyRates/res/proto_CurrencyRates.rc
@@ -0,0 +1,121 @@
+//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 "proto_online.ico"
+105 ICON "proto_offline.ico"
+131 ICON "proto_na.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
+ "\r\n"
+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", "CurrencyRates protocol icons"
+ VALUE "FileVersion", "0, 0, 0, 1"
+ VALUE "InternalName", "proto_CurrencyRates"
+ VALUE "LegalCopyright", "Do not worry!"
+ VALUE "OriginalFilename", "proto_CurrencyRates.dll"
+ VALUE "ProductName", "Miranda NG"
+ 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/CurrencyRates/proto_CurrencyRates/res/proto_na.ico b/protocols/CurrencyRates/proto_CurrencyRates/res/proto_na.ico
new file mode 100644
index 0000000000..71c90785aa
--- /dev/null
+++ b/protocols/CurrencyRates/proto_CurrencyRates/res/proto_na.ico
Binary files differ
diff --git a/protocols/CurrencyRates/proto_CurrencyRates/res/proto_offline.ico b/protocols/CurrencyRates/proto_CurrencyRates/res/proto_offline.ico
new file mode 100644
index 0000000000..f6fc5e9f20
--- /dev/null
+++ b/protocols/CurrencyRates/proto_CurrencyRates/res/proto_offline.ico
Binary files differ
diff --git a/protocols/CurrencyRates/proto_CurrencyRates/res/proto_online.ico b/protocols/CurrencyRates/proto_CurrencyRates/res/proto_online.ico
new file mode 100644
index 0000000000..da85d1f7c6
--- /dev/null
+++ b/protocols/CurrencyRates/proto_CurrencyRates/res/proto_online.ico
Binary files differ
diff --git a/protocols/CurrencyRates/res/AutoUpdateDisabled.ico b/protocols/CurrencyRates/res/AutoUpdateDisabled.ico
new file mode 100644
index 0000000000..30c9dbf220
--- /dev/null
+++ b/protocols/CurrencyRates/res/AutoUpdateDisabled.ico
Binary files differ
diff --git a/protocols/CurrencyRates/res/CurrencyConverter.ico b/protocols/CurrencyRates/res/CurrencyConverter.ico
new file mode 100644
index 0000000000..67ac2095f5
--- /dev/null
+++ b/protocols/CurrencyRates/res/CurrencyConverter.ico
Binary files differ
diff --git a/protocols/CurrencyRates/res/Export currencyrates.ico b/protocols/CurrencyRates/res/Export currencyrates.ico
new file mode 100644
index 0000000000..31c7aa2ba1
--- /dev/null
+++ b/protocols/CurrencyRates/res/Export currencyrates.ico
Binary files differ
diff --git a/protocols/CurrencyRates/res/Forex.rc b/protocols/CurrencyRates/res/Forex.rc
new file mode 100644
index 0000000000..3d55d1d363
--- /dev/null
+++ b/protocols/CurrencyRates/res/Forex.rc
@@ -0,0 +1,376 @@
+// Microsoft Visual C++ generated resource script.
+//
+#include "..\src\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 "main.ico"
+
+IDI_ICON_SECTION ICON "Section.ico"
+
+IDI_ICON_CURRENCYRATE ICON "currencyrate.ico"
+
+IDI_ICON_UP ICON "up.ico"
+
+IDI_ICON_DOWN ICON "down.ico"
+
+IDI_ICON_CURRENCY_CONVERTER ICON "CurrencyConverter.ico"
+
+IDI_ICON_REFRESH ICON "Refresh.ico"
+
+IDI_ICON_EXPORT ICON "Export currencyrates.ico"
+
+IDI_ICON_SWAP ICON "swap.ico"
+
+IDI_ICON_IMPORT ICON "Import currencyrates.ico"
+
+IDI_ICON_NOTCHANGED ICON "notchanged.ico"
+
+IDI_ICON_DISABLED ICON "AutoUpdateDisabled.ico"
+
+
+#ifdef APSTUDIO_INVOKED
+/////////////////////////////////////////////////////////////////////////////
+//
+// TEXTINCLUDE
+//
+
+1 TEXTINCLUDE
+BEGIN
+ "..\\src\\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
+
+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%,%currencyratename%",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,328,11
+ PUSHBUTTON "Close",IDCANCEL,148,80,50,14
+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%,%currencyratename%",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 "Colors",IDC_STATIC,7,7,149,82,WS_GROUP
+ CONTROL "Use default colors",IDC_RADIO_DEFAULT_COLOURS,"Button",BS_AUTORADIOBUTTON | WS_TABSTOP,15,20,82,10
+ CONTROL "Use user-defined colors",IDC_RADIO_USER_DEFINED_COLOURS,
+ "Button",BS_AUTORADIOBUTTON,15,34,97,10
+ LTEXT "Background color",IDC_STATIC,70,53,66,8
+ CONTROL "",IDC_BGCOLOR,"ColourPicker",WS_TABSTOP,26,49,35,14
+ LTEXT "Text color",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,90,10
+ CONTROL "Custom",IDC_DELAYCUSTOM,"Button",BS_AUTORADIOBUTTON,174,35,70,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
+
+IDD_DIALOG_CURRENCYRATE_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 "",IDC_STATIC_CURRENCYRATE_NAME,7,7,208,8
+ CONTROL "",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, 242
+STYLE DS_SETFONT | DS_FIXEDSYS | WS_CHILD
+EXSTYLE WS_EX_CONTROLPARENT
+FONT 8, "MS Shell Dlg", 0, 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,167,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,107,8
+ EDITTEXT IDC_EDIT_STATUS_MESSAGE_FORMAT,117,179,120,12,ES_AUTOHSCROLL
+ LTEXT "&Tendency:",IDC_STATIC,7,195,107,8
+ EDITTEXT IDC_EDIT_TENDENCY_FORMAT,117,193,120,12,ES_AUTOHSCROLL
+ LTEXT "&Personal key:",IDC_STATIC,7,210,107,8
+ EDITTEXT IDC_EDIT_PERSONAL_KEY,117,208,120,12,ES_AUTOHSCROLL
+ PUSHBUTTON "&Advanced Settings...",IDC_BUTTON_ADVANCED_SETTINGS,105,223,110,14
+END
+
+IDD_DIALOG_CURRENCYRATE_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 "Rate Info"
+FONT 8, "MS Shell Dlg", 400, 0, 0x1
+BEGIN
+ CTEXT "",IDC_STATIC_CURRENCYRATE_NAME,7,7,208,8
+ CONTROL "",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
+
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// DESIGNINFO
+//
+
+#ifdef APSTUDIO_INVOKED
+GUIDELINES DESIGNINFO
+BEGIN
+ IDD_DIALOG_VARIABLE_LIST, DIALOG
+ BEGIN
+ LEFTMARGIN, 7
+ RIGHTMARGIN, 209
+ TOPMARGIN, 7
+ BOTTOMMARGIN, 175
+ END
+
+ 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_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
+
+ IDD_DIALOG_CURRENCYRATE_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, 237
+ END
+
+ IDD_DIALOG_CURRENCYRATE_INFO_1, DIALOG
+ BEGIN
+ LEFTMARGIN, 7
+ RIGHTMARGIN, 215
+ TOPMARGIN, 7
+ BOTTOMMARGIN, 135
+ END
+END
+#endif // APSTUDIO_INVOKED
+
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// AFX_DIALOG_LAYOUT
+//
+
+IDD_CURRENCY_CONVERTER AFX_DIALOG_LAYOUT
+BEGIN
+ 0
+END
+
+IDD_DIALOG_OPT_GOOGLE AFX_DIALOG_LAYOUT
+BEGIN
+ 0
+END
+
+#endif // Neutral resources
+/////////////////////////////////////////////////////////////////////////////
+
+
+
+#ifndef APSTUDIO_INVOKED
+/////////////////////////////////////////////////////////////////////////////
+//
+// Generated from the TEXTINCLUDE 3 resource.
+//
+
+
+/////////////////////////////////////////////////////////////////////////////
+#endif // not APSTUDIO_INVOKED
+
diff --git a/protocols/CurrencyRates/res/Import currencyrates.ico b/protocols/CurrencyRates/res/Import currencyrates.ico
new file mode 100644
index 0000000000..506aa62af3
--- /dev/null
+++ b/protocols/CurrencyRates/res/Import currencyrates.ico
Binary files differ
diff --git a/protocols/CurrencyRates/res/Refresh.ico b/protocols/CurrencyRates/res/Refresh.ico
new file mode 100644
index 0000000000..f09a47cd9e
--- /dev/null
+++ b/protocols/CurrencyRates/res/Refresh.ico
Binary files differ
diff --git a/protocols/CurrencyRates/res/Section.ico b/protocols/CurrencyRates/res/Section.ico
new file mode 100644
index 0000000000..768b3775aa
--- /dev/null
+++ b/protocols/CurrencyRates/res/Section.ico
Binary files differ
diff --git a/protocols/CurrencyRates/res/Version.rc b/protocols/CurrencyRates/res/Version.rc
new file mode 100644
index 0000000000..5a5ddd63ed
--- /dev/null
+++ b/protocols/CurrencyRates/res/Version.rc
@@ -0,0 +1,9 @@
+// Microsoft Visual C++ generated resource script.
+//
+#ifdef APSTUDIO_INVOKED
+#error this file is not editable by Microsoft Visual C++
+#endif //APSTUDIO_INVOKED
+
+#include "..\src\version.h"
+
+#include "..\..\build\Version.rc"
diff --git a/protocols/CurrencyRates/res/currencyrate.ico b/protocols/CurrencyRates/res/currencyrate.ico
new file mode 100644
index 0000000000..1367c475d6
--- /dev/null
+++ b/protocols/CurrencyRates/res/currencyrate.ico
Binary files differ
diff --git a/protocols/CurrencyRates/res/down.ico b/protocols/CurrencyRates/res/down.ico
new file mode 100644
index 0000000000..20722f63ca
--- /dev/null
+++ b/protocols/CurrencyRates/res/down.ico
Binary files differ
diff --git a/protocols/CurrencyRates/res/main.ico b/protocols/CurrencyRates/res/main.ico
new file mode 100644
index 0000000000..da85d1f7c6
--- /dev/null
+++ b/protocols/CurrencyRates/res/main.ico
Binary files differ
diff --git a/protocols/CurrencyRates/res/notchanged.ico b/protocols/CurrencyRates/res/notchanged.ico
new file mode 100644
index 0000000000..39a8f1ea3c
--- /dev/null
+++ b/protocols/CurrencyRates/res/notchanged.ico
Binary files differ
diff --git a/protocols/CurrencyRates/res/swap.ico b/protocols/CurrencyRates/res/swap.ico
new file mode 100644
index 0000000000..f4a410da41
--- /dev/null
+++ b/protocols/CurrencyRates/res/swap.ico
Binary files differ
diff --git a/protocols/CurrencyRates/res/up.ico b/protocols/CurrencyRates/res/up.ico
new file mode 100644
index 0000000000..0379c80d17
--- /dev/null
+++ b/protocols/CurrencyRates/res/up.ico
Binary files differ
diff --git a/protocols/CurrencyRates/src/Chart.h b/protocols/CurrencyRates/src/Chart.h
new file mode 100644
index 0000000000..1247ead065
--- /dev/null
+++ b/protocols/CurrencyRates/src/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()
+ {
+ memset(&m_rect, 0, 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 nothing to show");
+ int nDrawTextResult = ::DrawText(hdc, pszText, -1, &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(), -1, &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/CurrencyRates/src/ComHelper.cpp b/protocols/CurrencyRates/src/ComHelper.cpp
new file mode 100644
index 0000000000..c4715892b5
--- /dev/null
+++ b/protocols/CurrencyRates/src/ComHelper.cpp
@@ -0,0 +1,28 @@
+#include "StdAfx.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() << L" (" << std::hex << hError << L")";
+
+ IErrorInfo* p = e.ErrorInfo();
+ CComPtr<IErrorInfo> pErrorInfo(p);
+ if (nullptr != p)
+ p->Release();
+
+ if (pErrorInfo)
+ o << L"\n" << e.Description();
+
+ return o.str();
+}
+
+void ShowComError(_com_error& e, const tstring& rsAdditionalInfo)
+{
+ tstring sErrorMsg = ComException2Msg(e, rsAdditionalInfo);
+ LogIt(sErrorMsg);
+ CurrencyRates_MessageBox(nullptr, sErrorMsg.c_str(), MB_OK | MB_ICONERROR);
+}
diff --git a/protocols/CurrencyRates/src/ComHelper.h b/protocols/CurrencyRates/src/ComHelper.h
new file mode 100644
index 0000000000..343d436785
--- /dev/null
+++ b/protocols/CurrencyRates/src/ComHelper.h
@@ -0,0 +1,7 @@
+#ifndef __37ae28ab_c414_4aba_bbef_d23dd68643a5_ComHelper_h__
+#define __37ae28ab_c414_4aba_bbef_d23dd68643a5_ComHelper_h__
+
+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/CurrencyRates/src/CommonOptionDlg.cpp b/protocols/CurrencyRates/src/CommonOptionDlg.cpp
new file mode 100644
index 0000000000..335457ed89
--- /dev/null
+++ b/protocols/CurrencyRates/src/CommonOptionDlg.cpp
@@ -0,0 +1,221 @@
+#include "StdAfx.h"
+
+typedef boost::shared_ptr<CAdvProviderSettings> TAdvSettingsPtr;
+typedef std::map<const ICurrencyRatesProvider*, TAdvSettingsPtr> TAdvSettings;
+
+TAdvSettings g_aAdvSettings;
+
+CAdvProviderSettings* get_adv_settings(const ICurrencyRatesProvider *pProvider, bool bCreateIfNonExist)
+{
+ TAdvSettings::iterator i = g_aAdvSettings.find(pProvider);
+ if (i != g_aAdvSettings.end())
+ return i->second.get();
+
+ if (true == bCreateIfNonExist) {
+ TAdvSettingsPtr pAdvSet(new CAdvProviderSettings(pProvider));
+ g_aAdvSettings.insert(std::make_pair(pProvider, pAdvSet));
+ return pAdvSet.get();
+ }
+
+ return nullptr;
+}
+
+void remove_adv_settings(const ICurrencyRatesProvider *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_pCurrencyRatesProvider);
+
+ // set contact list display format
+ tstring sDspNameFrmt = CurrencyRates_DBGetStringW(NULL, CURRENCYRATES_MODULE_NAME, DB_KEY_DisplayNameFormat, DB_DEF_DisplayNameFormat);
+ ::SetDlgItemText(hWnd, IDC_EDIT_CONTACT_LIST_FORMAT, sDspNameFrmt.c_str());
+
+ // set status message display format
+ tstring sStatusMsgFrmt = CurrencyRates_DBGetStringW(NULL, CURRENCYRATES_MODULE_NAME, DB_KEY_StatusMsgFormat, DB_DEF_StatusMsgFormat);
+ ::SetDlgItemText(hWnd, IDC_EDIT_STATUS_MESSAGE_FORMAT, sStatusMsgFrmt.c_str());
+
+ // set tendency format
+ tstring sTendencyFrmt = CurrencyRates_DBGetStringW(NULL, CURRENCYRATES_MODULE_NAME, DB_KEY_TendencyFormat, DB_DEF_TendencyFormat);
+ ::SetDlgItemText(hWnd, IDC_EDIT_TENDENCY_FORMAT, sTendencyFrmt.c_str());
+
+ // set api key
+ tstring sApiKey = CurrencyRates_DBGetStringW(NULL, CURRENCYRATES_MODULE_NAME, DB_KEY_ApiKey, L"");
+ ::SetDlgItemText(hWnd, IDC_EDIT_PERSONAL_KEY, sApiKey.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 < _countof(pszRefreshRateTypes); ++i)
+ ::SendMessage(hwndCombo, CB_ADDSTRING, 0, reinterpret_cast<LPARAM>(pszRefreshRateTypes[i]));
+
+ int nRefreshRateType = db_get_w(0, CURRENCYRATES_MODULE_NAME, DB_KEY_RefreshRateType, RRT_MINUTES);
+ if (nRefreshRateType < RRT_SECONDS || nRefreshRateType > RRT_HOURS)
+ nRefreshRateType = RRT_MINUTES;
+
+ UINT nRate = db_get_w(0, CURRENCYRATES_MODULE_NAME, DB_KEY_RefreshRateValue, 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:
+ case IDC_EDIT_PERSONAL_KEY:
+ 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_pCurrencyRatesProvider);
+ break;
+ case IDC_BUTTON_ADVANCED_SETTINGS:
+ CAdvProviderSettings* pAdvSet = get_adv_settings(rData.m_pCurrencyRatesProvider, 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>(::SendDlgItemMessage(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));
+ CurrencyRates_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));
+ CurrencyRates_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);
+ CurrencyRates_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>(::SendDlgItemMessage(hWnd, IDC_COMBO_REFRESH_RATE, CB_GETCURSEL, 0, 0));
+
+ assert(rData.m_pCurrencyRatesProvider);
+
+ rData.m_bFireSetingsChangedEvent = true;
+ db_set_w(0, CURRENCYRATES_MODULE_NAME, DB_KEY_RefreshRateType, nType);
+ db_set_w(0, CURRENCYRATES_MODULE_NAME, DB_KEY_RefreshRateValue, nRefreshRate);
+
+ tstring s = get_window_text(::GetDlgItem(hWnd, IDC_EDIT_CONTACT_LIST_FORMAT));
+ db_set_ws(0, CURRENCYRATES_MODULE_NAME, DB_KEY_DisplayNameFormat, s.c_str());
+
+ s = get_window_text(::GetDlgItem(hWnd, IDC_EDIT_STATUS_MESSAGE_FORMAT));
+ db_set_ws(0, CURRENCYRATES_MODULE_NAME, DB_KEY_StatusMsgFormat, s.c_str());
+
+ s = get_window_text(::GetDlgItem(hWnd, IDC_EDIT_TENDENCY_FORMAT));
+ db_set_ws(0, CURRENCYRATES_MODULE_NAME, DB_KEY_TendencyFormat, s.c_str());
+
+ s = get_window_text(::GetDlgItem(hWnd, IDC_EDIT_PERSONAL_KEY));
+ db_set_ws(0, CURRENCYRATES_MODULE_NAME, DB_KEY_ApiKey, s.c_str());
+
+ CAdvProviderSettings* pAdvSet = get_adv_settings(rData.m_pCurrencyRatesProvider, false);
+ if (pAdvSet)
+ pAdvSet->SaveToDb();
+ break;
+ }
+ }
+ break;
+
+ case WM_DESTROY:
+ remove_adv_settings(rData.m_pCurrencyRatesProvider);
+ break;
+ }
+}
diff --git a/protocols/CurrencyRates/src/CommonOptionDlg.h b/protocols/CurrencyRates/src/CommonOptionDlg.h
new file mode 100644
index 0000000000..bc4ca8c456
--- /dev/null
+++ b/protocols/CurrencyRates/src/CommonOptionDlg.h
@@ -0,0 +1,17 @@
+#ifndef __c85fe710_f71b_4a58_9d44_3e39f6209c5f_CommonOptionDlg_h__
+#define __c85fe710_f71b_4a58_9d44_3e39f6209c5f_CommonOptionDlg_h__
+
+class CCurrencyRatesProviderBase;
+
+struct CCommonDlgProcData
+{
+ CCommonDlgProcData(const CCurrencyRatesProviderBase* pCurrencyRatesProvider)
+ : m_pCurrencyRatesProvider(pCurrencyRatesProvider), m_bFireSetingsChangedEvent(false){}
+
+ const CCurrencyRatesProviderBase* m_pCurrencyRatesProvider;
+ 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/CurrencyRates/src/CreateFilePath.cpp b/protocols/CurrencyRates/src/CreateFilePath.cpp
new file mode 100644
index 0000000000..71490432a9
--- /dev/null
+++ b/protocols/CurrencyRates/src/CreateFilePath.cpp
@@ -0,0 +1,17 @@
+#include "StdAfx.h"
+
+tstring CreateFilePath(const tstring &rsName)
+{
+ wchar_t szPath[_MAX_PATH];
+ ::GetModuleFileName(g_plugin.getInst(), szPath, _MAX_PATH);
+
+ wchar_t* p = wcsrchr(szPath, '\\');
+ if (p)
+ *p = 0;
+
+ tstring s(rsName);
+ FixInvalidChars(s);
+ tostringstream o;
+ o << szPath << L"\\CurrencyRates\\" << s;
+ return o.str();
+} \ No newline at end of file
diff --git a/protocols/CurrencyRates/src/CreateFilePath.h b/protocols/CurrencyRates/src/CreateFilePath.h
new file mode 100644
index 0000000000..e4a88494fb
--- /dev/null
+++ b/protocols/CurrencyRates/src/CreateFilePath.h
@@ -0,0 +1,6 @@
+#ifndef _aaf3bee6_cee7_4023_8848_5911ad7a9660_CreateFilePath_h__
+#define _aaf3bee6_cee7_4023_8848_5911ad7a9660_CreateFilePath_h__
+
+tstring CreateFilePath(const tstring& rsName);
+
+#endif //_aaf3bee6_cee7_4023_8848_5911ad7a9660_CreateFilePath_h__
diff --git a/protocols/CurrencyRates/src/CurrencyConverter.cpp b/protocols/CurrencyRates/src/CurrencyConverter.cpp
new file mode 100644
index 0000000000..5a7f4d1487
--- /dev/null
+++ b/protocols/CurrencyRates/src/CurrencyConverter.cpp
@@ -0,0 +1,260 @@
+#include "StdAfx.h"
+#include "CurrencyRatesProviderCurrencyConverter.h"
+
+#define WINDOW_PREFIX "CurrenyConverter_"
+
+#define DB_STR_CC_CURRENCYRATE_FROM_ID "CurrencyConverter_FromID"
+#define DB_STR_CC_CURRENCYRATE_TO_ID "CurrencyConverter_ToID"
+#define DB_STR_CC_AMOUNT "CurrencyConverter_Amount"
+
+static CCurrencyRatesProviderCurrencyConverter *get_currency_converter_provider()
+{
+ for (auto &it : g_apProviders)
+ if (auto p = dynamic_cast<CCurrencyRatesProviderCurrencyConverter*>(it))
+ return p;
+
+ assert(!"We should never get here!");
+ return nullptr;
+}
+
+CCurrencyRateSection get_currencyrates(const CCurrencyRatesProviderCurrencyConverter* pProvider = nullptr)
+{
+ if (nullptr == pProvider)
+ pProvider = get_currency_converter_provider();
+
+ if (pProvider) {
+ const auto& rCurrencyRates = pProvider->GetCurrencyRates();
+ if (rCurrencyRates.GetSectionCount() > 0)
+ return rCurrencyRates.GetSection(0);
+ }
+
+ return CCurrencyRateSection();
+}
+
+inline tstring make_currencyrate_name(const CCurrencyRate &rCurrencyRate)
+{
+ const tstring &rsDesc = rCurrencyRate.GetName();
+ return((false == rsDesc.empty()) ? rsDesc : rCurrencyRate.GetSymbol());
+}
+
+inline void update_convert_button(HWND hDlg)
+{
+ int nFrom = static_cast<int>(::SendDlgItemMessage(hDlg, IDC_COMBO_CONVERT_FROM, CB_GETCURSEL, 0, 0));
+ int nTo = static_cast<int>(::SendDlgItemMessage(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>(::SendDlgItemMessage(hDlg, IDC_COMBO_CONVERT_FROM, CB_GETCURSEL, 0, 0));
+ int nTo = static_cast<int>(::SendDlgItemMessage(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:
+ TranslateDialogDefault(hDlg);
+ {
+ MWindowList hWL = CModuleInfo::GetWindowList(WINDOW_PREFIX, false);
+ assert(hWL);
+ WindowList_Add(hWL, hDlg);
+
+ Window_SetIcon_IcoLib(hDlg, CurrencyRates_GetIconHandle(IDI_ICON_CURRENCY_CONVERTER));
+
+ HWND hcbxFrom = ::GetDlgItem(hDlg, IDC_COMBO_CONVERT_FROM);
+ HWND hcbxTo = ::GetDlgItem(hDlg, IDC_COMBO_CONVERT_INTO);
+
+ tstring sFromCurrencyRateID = CurrencyRates_DBGetStringW(NULL, CURRENCYRATES_MODULE_NAME, DB_STR_CC_CURRENCYRATE_FROM_ID);
+ tstring sToCurrencyRateID = CurrencyRates_DBGetStringW(NULL, CURRENCYRATES_MODULE_NAME, DB_STR_CC_CURRENCYRATE_TO_ID);
+
+ const auto pProvider = get_currency_converter_provider();
+ const auto& rSection = get_currencyrates(pProvider);
+ auto cCurrencyRates = rSection.GetCurrencyRateCount();
+ for (auto i = 0u; i < cCurrencyRates; ++i) {
+ const auto& rCurrencyRate = rSection.GetCurrencyRate(i);
+ tstring sName = make_currencyrate_name(rCurrencyRate);
+ 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 == mir_wstrcmpi(rCurrencyRate.GetID().c_str(), sFromCurrencyRateID.c_str())) {
+ ::SendMessage(hcbxFrom, CB_SETCURSEL, nFrom, 0);
+ }
+
+ if (0 == mir_wstrcmpi(rCurrencyRate.GetID().c_str(), sToCurrencyRateID.c_str())) {
+ ::SendMessage(hcbxTo, CB_SETCURSEL, nTo, 0);
+ }
+ }
+
+ double dAmount = 1.0;
+ CurrencyRates_DBReadDouble(NULL, CURRENCYRATES_MODULE_NAME, DB_STR_CC_AMOUNT, dAmount);
+ ::SetDlgItemText(hDlg, IDC_EDIT_VALUE, double2str(dAmount).c_str());
+
+ const ICurrencyRatesProvider::CProviderInfo& pi = pProvider->GetInfo();
+ tostringstream o;
+ o << TranslateT("Info provided by") << L" <a href=\"" << pi.m_sURL << L"\">" << pi.m_sName << L"</a>";
+
+ ::SetDlgItemText(hDlg, IDC_SYSLINK_PROVIDER, o.str().c_str());
+
+ ::SendDlgItemMessage(hDlg, IDC_BUTTON_SWAP, BM_SETIMAGE, IMAGE_ICON, LPARAM(CurrencyRates_LoadIconEx(IDI_ICON_SWAP)));
+
+ update_convert_button(hDlg);
+ update_swap_button(hDlg);
+
+ Utils_RestoreWindowPositionNoSize(hDlg, NULL, CURRENCYRATES_MODULE_NAME, WINDOW_PREFIX);
+ ::ShowWindow(hDlg, SW_SHOW);
+ }
+ return TRUE;
+
+ case WM_CLOSE:
+ {
+ MWindowList hWL = CModuleInfo::GetWindowList(WINDOW_PREFIX, false);
+ assert(hWL);
+ WindowList_Remove(hWL, hDlg);
+ Utils_SaveWindowPosition(hDlg, NULL, CURRENCYRATES_MODULE_NAME, WINDOW_PREFIX);
+ EndDialog(hDlg, 0);
+ }
+ return TRUE;
+
+ case WM_DESTROY:
+ Window_FreeIcon_IcoLib(hDlg);
+ break;
+
+ 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)) {
+ CurrencyRates_DBWriteDouble(NULL, CURRENCYRATES_MODULE_NAME, DB_STR_CC_AMOUNT, dAmount);
+
+ size_t nFrom = static_cast<size_t>(::SendDlgItemMessage(hDlg, IDC_COMBO_CONVERT_FROM, CB_GETCURSEL, 0, 0));
+ size_t nTo = static_cast<size_t>(::SendDlgItemMessage(hDlg, IDC_COMBO_CONVERT_INTO, CB_GETCURSEL, 0, 0));
+ if ((CB_ERR != nFrom) && (CB_ERR != nTo) && (nFrom != nTo)) {
+ const auto& rSection = get_currencyrates();
+ size_t cCurrencyRates = rSection.GetCurrencyRateCount();
+ if ((nFrom < cCurrencyRates) && (nTo < cCurrencyRates)) {
+ auto from = rSection.GetCurrencyRate(nFrom);
+ auto to = rSection.GetCurrencyRate(nTo);
+
+ db_set_ws(0, CURRENCYRATES_MODULE_NAME, DB_STR_CC_CURRENCYRATE_FROM_ID, from.GetID().c_str());
+ db_set_ws(0, CURRENCYRATES_MODULE_NAME, DB_STR_CC_CURRENCYRATE_TO_ID, to.GetID().c_str());
+
+ const auto pProvider = get_currency_converter_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();
+ }
+
+ if (false == sError.empty())
+ sResult = currencyrates_a2t(sError.c_str());//A2T(sError.c_str());
+
+ SetDlgItemText(hDlg, IDC_EDIT_RESULT, sResult.c_str());
+ }
+ }
+ }
+ }
+ else {
+ CurrencyRates_MessageBox(hDlg, TranslateT("Enter positive number."), MB_OK | MB_ICONERROR);
+ prepare_edit_ctrl_for_error(GetDlgItem(hDlg, IDC_EDIT_VALUE));
+ }
+ }
+ return TRUE;
+ }
+ break;
+
+ 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, L"open", pNMLink->item.szUrl, nullptr, nullptr, SW_SHOWNORMAL);
+ }
+ break;
+ }
+ break;
+ }
+ return (FALSE);
+}
+
+INT_PTR CurrencyRatesMenu_CurrencyConverter(WPARAM, LPARAM)
+{
+ MWindowList hWL = CModuleInfo::GetWindowList(WINDOW_PREFIX, true);
+ HWND hWnd = WindowList_Find(hWL, NULL);
+ if (nullptr != hWnd) {
+ SetForegroundWindow(hWnd);
+ SetFocus(hWnd);
+ }
+ else CreateDialogParam(g_plugin.getInst(), MAKEINTRESOURCE(IDD_CURRENCY_CONVERTER), nullptr, CurrencyConverterDlgProc, 0);
+
+ return 0;
+}
diff --git a/protocols/CurrencyRates/src/CurrencyConverter.h b/protocols/CurrencyRates/src/CurrencyConverter.h
new file mode 100644
index 0000000000..eca03ec40e
--- /dev/null
+++ b/protocols/CurrencyRates/src/CurrencyConverter.h
@@ -0,0 +1,6 @@
+#ifndef __4FB6320B_2D02_408b_BAF5_426C185AAA11_CurrencyConverter_h__
+#define __4FB6320B_2D02_408b_BAF5_426C185AAA11_CurrencyConverter_h__
+
+INT_PTR CurrencyRatesMenu_CurrencyConverter(WPARAM wp, LPARAM lp);
+
+#endif //__4FB6320B_2D02_408b_BAF5_426C185AAA11_CurrencyConverter_h__
diff --git a/protocols/CurrencyRates/src/CurrencyRateChart.cpp b/protocols/CurrencyRates/src/CurrencyRateChart.cpp
new file mode 100644
index 0000000000..a3208811a4
--- /dev/null
+++ b/protocols/CurrencyRates/src/CurrencyRateChart.cpp
@@ -0,0 +1,101 @@
+#include "StdAfx.h"
+
+#ifdef CHART_IMPLEMENT
+
+namespace
+{
+ class CMyJob : private boost::noncopyable
+ {
+ private:
+ CMyJob(LPCTSTR pszName = nullptr): m_hJob(::CreateJobObject(nullptr,pszName))
+ {
+ if(m_hJob)
+ {
+ JOBOBJECT_EXTENDED_LIMIT_INFORMATION jeli = { 0 };
+ jeli.BasicLimitInformation.LimitFlags = JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE;
+ if(0 == ::SetInformationJobObject(m_hJob,JobObjectExtendedLimitInformation,&jeli,sizeof(jeli)))
+ {
+#ifdef OUTPUT_TO_DEBUG_VIEWER
+ ::OutputDebugString(_T("Error occurred during the job initialization\n"));
+#endif
+ }
+ }
+
+ }
+ ~CMyJob()
+ {
+ if(m_hJob)
+ {
+ ::CloseHandle(m_hJob);
+ }
+ }
+
+ public:
+ static CMyJob& GetInstance()
+ {
+ static CMyJob g_job(_T("MirandaJob_E12D5E9C_00E7_4FFA_9831_F35E45C6EBDA"));
+ return g_job;
+ }
+
+ bool AssignProcess(HANDLE hProcess)
+ {
+ if(m_hJob && hProcess)
+ {
+ auto b = (TRUE == ::AssignProcessToJobObject(m_hJob,hProcess));
+ return b;
+ }
+
+ return false;
+ }
+
+ private:
+ HANDLE m_hJob;
+ };
+
+}
+
+INT_PTR CurrencyRatesMenu_Chart(WPARAM wp, LPARAM /*lp*/)
+{
+#ifdef _UNICODE
+ MCONTACT hContact = static_cast<MCONTACT>(wp);
+ if (NULL == hContact)
+ return 0;
+
+ auto sLogFileName = GetContactLogFileName(hContact);
+
+ if(auto hWnd = ::FindWindow(nullptr,_T("Miranda CurrencyRates Chart")))
+ {
+ COPYDATASTRUCT copydata_struct;
+ copydata_struct.cbData = static_cast<DWORD>(sLogFileName.size()*sizeof(TCHAR));
+ copydata_struct.lpData = const_cast<void*>(static_cast<const void*>(sLogFileName.c_str()));
+ copydata_struct.dwData = 0x1945;
+
+ SendMessage(hWnd,WM_COPYDATA,0,reinterpret_cast<LPARAM>(&copydata_struct));
+ }
+ else
+ {
+ STARTUPINFO si;
+ PROCESS_INFORMATION pi;
+ ZeroMemory(&si, sizeof(si));
+ si.cb = sizeof(si);
+ si.dwFlags = STARTF_USESHOWWINDOW;
+ si.wShowWindow = SW_SHOWNORMAL;
+ ZeroMemory(&pi, sizeof(pi));
+
+ auto sCmdLine = CreateFilePath(_T("CurrencyRatesChart.exe"));
+ sCmdLine += _T(" \"");
+ sCmdLine += sLogFileName;
+ sCmdLine += _T("\"");
+ if(::CreateProcess(nullptr,const_cast<LPTSTR>(sCmdLine.c_str()),nullptr,nullptr,FALSE,0,nullptr,nullptr,&si,&pi))
+ {
+ CMyJob::GetInstance().AssignProcess(pi.hProcess);
+
+ ::CloseHandle(pi.hThread);
+ ::CloseHandle(pi.hProcess);
+ }
+ }
+#endif
+ return 0;
+}
+
+#endif //CHART_IMPLEMENT
diff --git a/protocols/CurrencyRates/src/CurrencyRateChart.h b/protocols/CurrencyRates/src/CurrencyRateChart.h
new file mode 100644
index 0000000000..0869c1fa1c
--- /dev/null
+++ b/protocols/CurrencyRates/src/CurrencyRateChart.h
@@ -0,0 +1,12 @@
+#ifndef __39BE8775_A837_494f_925C_0ABF7910F238_CurrencyRateChart_h__
+#define __39BE8775_A837_494f_925C_0ABF7910F238_CurrencyRateChart_h__
+
+#pragma once
+
+#ifdef CHART_IMPLEMENT
+
+INT_PTR CurrencyRatesMenu_Chart(WPARAM wp, LPARAM lp);
+
+#endif
+
+#endif //__39BE8775_A837_494f_925C_0ABF7910F238_CurrencyRateChart_h__
diff --git a/protocols/CurrencyRates/src/CurrencyRateInfoDlg.cpp b/protocols/CurrencyRates/src/CurrencyRateInfoDlg.cpp
new file mode 100644
index 0000000000..c05520686e
--- /dev/null
+++ b/protocols/CurrencyRates/src/CurrencyRateInfoDlg.cpp
@@ -0,0 +1,257 @@
+#include "StdAfx.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, g_hMenuRoot;
+
+#define WINDOW_PREFIX_INFO "Currency Rate Info"
+
+MCONTACT g_hContact;
+
+inline bool IsMyContact(MCONTACT hContact)
+{
+ return nullptr != GetContactProviderPtr(hContact);
+}
+
+inline MCONTACT get_contact(HWND hWnd)
+{
+ return MCONTACT(GetWindowLongPtr(hWnd, GWLP_USERDATA));
+}
+
+static bool get_fetch_time(time_t& rTime, MCONTACT hContact)
+{
+ rTime = db_get_dw(hContact, CURRENCYRATES_MODULE_NAME, DB_STR_CURRENCYRATE_FETCH_TIME, -1);
+ return (rTime != -1);
+}
+
+INT_PTR CALLBACK CurrencyRateInfoDlgProcImpl(MCONTACT 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_CURRENCYRATE_NAME, sDescription.c_str());
+
+ double dRate = 0.0;
+ if (true == CurrencyRates_DBReadDouble(hContact, CURRENCYRATES_MODULE_NAME, DB_STR_CURRENCYRATE_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 == CurrencyRates_DBReadDouble(hContact, CURRENCYRATES_MODULE_NAME, DB_STR_CURRENCYRATE_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)) {
+ wchar_t szTime[50] = { 0 };
+ if (0 == _tctime_s(szTime, 50, &nFetchTime)) {
+ ::SetDlgItemText(hdlg, IDC_EDIT_RATE_FETCH_TIME, szTime);
+ }
+ }
+
+ const ICurrencyRatesProvider::CProviderInfo& pi = GetContactProviderPtr(hContact)->GetInfo();
+ tostringstream o;
+ o << TranslateT("Info provided by") << L" <a href=\"" << pi.m_sURL << L"\">" << pi.m_sName << L"</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, L"open", pNMLink->item.szUrl, nullptr, nullptr, SW_SHOWNORMAL);
+ }
+ break;
+ }
+ break;
+ }
+ return FALSE;
+}
+
+INT_PTR CALLBACK CurrencyRateInfoDlgProc(HWND hdlg, UINT msg, WPARAM wParam, LPARAM lParam)
+{
+ return CurrencyRateInfoDlgProcImpl(g_hContact, hdlg, msg, wParam, lParam);
+}
+
+int CurrencyRatesEventFunc_OnUserInfoInit(WPARAM wp, LPARAM hContact)
+{
+ if (NULL == hContact)
+ return 0;
+
+ if (false == IsMyContact(hContact))
+ return 0;
+
+ g_hContact = hContact;
+
+ OPTIONSDIALOGPAGE odp = {};
+ odp.pfnDlgProc = CurrencyRateInfoDlgProc;
+ odp.position = -2000000000;
+ odp.pszTemplate = MAKEINTRESOURCEA(IDD_DIALOG_CURRENCYRATE_INFO);
+ odp.szTitle.a = LPGEN("Currency Rate");
+ g_plugin.addUserInfo(wp, &odp);
+ return 0;
+}
+
+
+INT_PTR CurrencyRatesMenu_EditSettings(WPARAM wp, LPARAM)
+{
+ MCONTACT hContact = MCONTACT(wp);
+ if (NULL != hContact)
+ ShowSettingsDlg(hContact);
+ return 0;
+}
+
+namespace
+{
+ bool get_log_file(MCONTACT hContact, tstring& rsLogfile)
+ {
+ rsLogfile = GetContactLogFileName(hContact);
+ return ((rsLogfile.empty()) ? false : true);
+ }
+}
+
+INT_PTR CurrencyRatesMenu_OpenLogFile(WPARAM wp, LPARAM)
+{
+ MCONTACT hContact = MCONTACT(wp);
+ if (NULL == hContact)
+ return 0;
+
+ tstring sLogFileName;
+ if ((true == get_log_file(hContact, sLogFileName)) && (false == sLogFileName.empty()))
+ ::ShellExecute(nullptr, L"open", sLogFileName.c_str(), nullptr, nullptr, SW_SHOWNORMAL);
+
+ return 0;
+}
+
+INT_PTR CurrencyRatesMenu_RefreshContact(WPARAM wp, LPARAM)
+{
+ MCONTACT hContact = MCONTACT(wp);
+ if (NULL == hContact)
+ return 0;
+
+ ICurrencyRatesProvider *pProvider = GetContactProviderPtr(hContact);
+ if (pProvider)
+ pProvider->RefreshContact(hContact);
+ return 0;
+}
+
+static INT_PTR CALLBACK CurrencyRateInfoDlgProc1(HWND hdlg, UINT msg, WPARAM wParam, LPARAM lParam)
+{
+ MCONTACT hContact = NULL;
+ MWindowList hWL;
+
+ switch (msg) {
+ case WM_INITDIALOG:
+ hContact = MCONTACT(lParam);
+ hWL = CModuleInfo::GetWindowList(WINDOW_PREFIX_INFO, false);
+ assert(hWL);
+ WindowList_Add(hWL, hdlg, hContact);
+
+ ::SetWindowLongPtr(hdlg, GWLP_USERDATA, hContact);
+ Utils_RestoreWindowPositionNoSize(hdlg, hContact, CURRENCYRATES_MODULE_NAME, WINDOW_PREFIX_INFO);
+ ::ShowWindow(hdlg, SW_SHOW);
+ break;
+
+ case WM_CLOSE:
+ DestroyWindow(hdlg);
+ return FALSE;
+
+ case WM_DESTROY:
+ hContact = get_contact(hdlg);
+ if (hContact) {
+ SetWindowLongPtr(hdlg, GWLP_USERDATA, 0);
+
+ hWL = CModuleInfo::GetWindowList(WINDOW_PREFIX_INFO, false);
+ assert(hWL);
+ WindowList_Remove(hWL, hdlg);
+ Utils_SaveWindowPosition(hdlg, hContact, CURRENCYRATES_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 CurrencyRateInfoDlgProcImpl(hContact, hdlg, msg, wParam, lParam);
+}
+
+int CurrencyRates_OnContactDoubleClick(WPARAM wp, LPARAM/* lp*/)
+{
+ MCONTACT hContact = MCONTACT(wp);
+ if (GetContactProviderPtr(hContact)) {
+ MWindowList hWL = CModuleInfo::GetWindowList(WINDOW_PREFIX_INFO, true);
+ assert(hWL);
+ HWND hWnd = WindowList_Find(hWL, hContact);
+ if (nullptr != hWnd) {
+ SetForegroundWindow(hWnd);
+ SetFocus(hWnd);
+ }
+ else if (true == IsMyContact(hContact))
+ CreateDialogParam(g_plugin.getInst(), MAKEINTRESOURCE(IDD_DIALOG_CURRENCYRATE_INFO_1), nullptr, CurrencyRateInfoDlgProc1, LPARAM(hContact));
+
+ return 1;
+ }
+
+ return 0;
+}
+
+int CurrencyRates_PrebuildContactMenu(WPARAM wp, LPARAM)
+{
+ Menu_EnableItem(g_hMenuEditSettings, false);
+ Menu_EnableItem(g_hMenuOpenLogFile, false);
+ #ifdef CHART_IMPLEMENT
+ Menu_EnableItem(g_hMenuChart, false);
+ #endif
+ Menu_EnableItem(g_hMenuRefresh, false);
+
+ MCONTACT hContact = MCONTACT(wp);
+ char *szProto = GetContactProto(hContact);
+ if (mir_strcmp(szProto, CURRENCYRATES_PROTOCOL_NAME)) {
+ Menu_ShowItem(g_hMenuRoot, false);
+ return 0;
+ }
+
+ Menu_ShowItem(g_hMenuRoot, true);
+ Menu_EnableItem(g_hMenuEditSettings, true);
+
+ Menu_EnableItem(g_hMenuRefresh, true);
+
+ tstring sLogFileName;
+ bool bThereIsLogFile = (true == get_log_file(hContact, sLogFileName))
+ && (false == sLogFileName.empty()) && (0 == _waccess(sLogFileName.c_str(), 04));
+ if (true == bThereIsLogFile) {
+ #ifdef CHART_IMPLEMENT
+ Menu_EnableItem(g_hMenuChart, true);
+ #endif
+ Menu_EnableItem(g_hMenuOpenLogFile, true);
+ }
+
+ return 0;
+}
diff --git a/protocols/CurrencyRates/src/CurrencyRateInfoDlg.h b/protocols/CurrencyRates/src/CurrencyRateInfoDlg.h
new file mode 100644
index 0000000000..d0df6e99c5
--- /dev/null
+++ b/protocols/CurrencyRates/src/CurrencyRateInfoDlg.h
@@ -0,0 +1,11 @@
+#ifndef __aa849fa0_ff3f_49e9_b47a_e7dd34783dc2_CurrencyRateInfoDlg_h__
+#define __aa849fa0_ff3f_49e9_b47a_e7dd34783dc2_CurrencyRateInfoDlg_h__
+
+int CurrencyRatesEventFunc_OnUserInfoInit(WPARAM wp, LPARAM lp);
+INT_PTR CurrencyRatesMenu_EditSettings(WPARAM wp, LPARAM lp);
+INT_PTR CurrencyRatesMenu_OpenLogFile(WPARAM wp, LPARAM lp);
+INT_PTR CurrencyRatesMenu_RefreshContact(WPARAM wp, LPARAM lp);
+int CurrencyRates_PrebuildContactMenu(WPARAM wp, LPARAM lp);
+int CurrencyRates_OnContactDoubleClick(WPARAM wp, LPARAM lp);
+
+#endif //__aa849fa0_ff3f_49e9_b47a_e7dd34783dc2_CurrencyRateInfoDlg_h__
diff --git a/protocols/CurrencyRates/src/CurrencyRatesProviderBase.cpp b/protocols/CurrencyRates/src/CurrencyRatesProviderBase.cpp
new file mode 100644
index 0000000000..592fd551ba
--- /dev/null
+++ b/protocols/CurrencyRates/src/CurrencyRatesProviderBase.cpp
@@ -0,0 +1,935 @@
+#include "StdAfx.h"
+
+extern bool g_bAutoUpdate;
+extern HANDLE g_hEventWorkThreadStop;
+
+struct CXMLFileInfo
+{
+ CXMLFileInfo() : m_qs(L"Unknown") {}
+ ICurrencyRatesProvider::CProviderInfo m_pi;
+ CCurrencyRateSection m_qs;
+ tstring m_sURL;
+};
+
+inline tstring get_ini_file_name(LPCTSTR pszFileName)
+{
+ return CreateFilePath(pszFileName);
+}
+
+bool parse_currencyrate(const TiXmlNode *pTop, CCurrencyRate &q)
+{
+ tstring sSymbol, sDescription, sID;
+
+ for (auto *pNode : TiXmlEnum(pTop)) {
+ const char *sName = pNode->Value();
+ if (!mir_strcmpi(sName, "symbol")) {
+ sSymbol = GetNodeText(pNode);
+ if (sSymbol.empty())
+ return false;
+ }
+ else if (!mir_strcmpi(sName, "description")) {
+ sDescription = GetNodeText(pNode);
+ }
+ else if (!mir_strcmpi(sName, "id")) {
+ sID = GetNodeText(pNode);
+ if (sID.empty())
+ return false;
+ }
+ }
+
+ q = CCurrencyRate(sID, TranslateW(sSymbol.c_str()), TranslateW(sDescription.c_str()));
+ return true;
+}
+
+bool parse_section(const TiXmlNode *pTop, CCurrencyRateSection &qs)
+{
+ CCurrencyRateSection::TSections aSections;
+ CCurrencyRateSection::TCurrencyRates aCurrencyRates;
+ tstring sSectionName;
+
+ for (auto *pNode : TiXmlEnum(pTop)) {
+ const char *sName = pNode->Value();
+ if (!mir_strcmpi(sName, "section")) {
+ CCurrencyRateSection qs1;
+ if (true == parse_section(pNode, qs1))
+ aSections.push_back(qs1);
+ }
+ else if (!mir_strcmpi(sName, "currencyrate")) {
+ CCurrencyRate q;
+ if (true == parse_currencyrate(pNode, q))
+ aCurrencyRates.push_back(q);
+ }
+ else if (!mir_strcmpi(sName, "name")) {
+ sSectionName = GetNodeText(pNode);
+ if (sSectionName.empty())
+ return false;
+ }
+ }
+
+ qs = CCurrencyRateSection(TranslateW(sSectionName.c_str()), aSections, aCurrencyRates);
+ return true;
+}
+
+const TiXmlNode* find_provider(const TiXmlNode *pRoot)
+{
+ for (auto *pNode : TiXmlEnum(pRoot)) {
+ const char *sName = pNode->Value();
+ if (!mir_strcmpi(sName, "Provider"))
+ return pNode;
+
+ if (auto *pProvider = find_provider(pNode))
+ return pProvider;
+ }
+
+ return nullptr;
+}
+
+CXMLFileInfo parse_ini_file(const tstring &rsXMLFile, bool &rbSucceded)
+{
+ CXMLFileInfo res;
+ CCurrencyRateSection::TSections aSections;
+
+ TiXmlDocument doc;
+ if (doc.LoadFile(_T2A(rsXMLFile.c_str())) == tinyxml2::XML_SUCCESS) {
+ const TiXmlNode *pProvider = find_provider(&doc);
+ if (pProvider) {
+ rbSucceded = true;
+ for (auto *pNode : TiXmlEnum(pProvider)) {
+ const char *sName = pNode->Value();
+ if (!mir_strcmpi(sName, "section")) {
+ CCurrencyRateSection qs;
+ if (parse_section(pNode, qs))
+ aSections.push_back(qs);
+ }
+ else if (!mir_strcmpi(sName, "Name"))
+ res.m_pi.m_sName = GetNodeText(pNode);
+ else if (!mir_strcmpi(sName, "ref"))
+ res.m_pi.m_sURL = GetNodeText(pNode);
+ else if (!mir_strcmpi(sName, "url"))
+ res.m_sURL = GetNodeText(pNode);
+ }
+ }
+ }
+
+ res.m_qs = CCurrencyRateSection(res.m_pi.m_sName, aSections);
+ return res;
+}
+
+CXMLFileInfo init_xml_info(LPCTSTR pszFileName, bool& rbSucceded)
+{
+ rbSucceded = false;
+ tstring sIniFile = get_ini_file_name(pszFileName);
+ return parse_ini_file(sIniFile, rbSucceded);
+}
+
+CCurrencyRatesProviderBase::CCurrencyRatesProviderBase() :
+ m_hEventSettingsChanged(::CreateEvent(nullptr, FALSE, FALSE, nullptr)),
+ m_hEventRefreshContact(::CreateEvent(nullptr, FALSE, FALSE, nullptr)),
+ m_bRefreshInProgress(false)
+{
+}
+
+CCurrencyRatesProviderBase::~CCurrencyRatesProviderBase()
+{
+ delete m_pXMLInfo;
+
+ ::CloseHandle(m_hEventSettingsChanged);
+ ::CloseHandle(m_hEventRefreshContact);
+}
+
+bool CCurrencyRatesProviderBase::Init()
+{
+ bool bSucceded = (m_pXMLInfo == nullptr);
+ if (!m_pXMLInfo)
+ m_pXMLInfo = new CXMLFileInfo(init_xml_info(DB_DEF_IniFileName, bSucceded));
+
+ return bSucceded;
+}
+
+const CCurrencyRatesProviderBase::CProviderInfo& CCurrencyRatesProviderBase::GetInfo() const
+{
+ return m_pXMLInfo->m_pi;
+}
+
+const CCurrencyRateSection& CCurrencyRatesProviderBase::GetCurrencyRates() const
+{
+ return m_pXMLInfo->m_qs;
+}
+
+const tstring& CCurrencyRatesProviderBase::GetURL() const
+{
+ return m_pXMLInfo->m_sURL;
+}
+
+bool CCurrencyRatesProviderBase::IsOnline()
+{
+ return /*g_bAutoUpdate*/true;
+}
+
+void CCurrencyRatesProviderBase::AddContact(MCONTACT hContact)
+{
+ // CCritSection cs(m_cs);
+ assert(m_aContacts.end() == std::find(m_aContacts.begin(), m_aContacts.end(), hContact));
+
+ m_aContacts.push_back(hContact);
+}
+
+void CCurrencyRatesProviderBase::DeleteContact(MCONTACT hContact)
+{
+ mir_cslock lck(m_cs);
+
+ TContacts::iterator i = std::find(m_aContacts.begin(), m_aContacts.end(), hContact);
+ if (i != m_aContacts.end())
+ m_aContacts.erase(i);
+}
+
+void CCurrencyRatesProviderBase::SetContactStatus(MCONTACT hContact, int nNewStatus)
+{
+ int nStatus = db_get_w(hContact, CURRENCYRATES_MODULE_NAME, DB_STR_STATUS, ID_STATUS_OFFLINE);
+ if (nNewStatus != nStatus) {
+ db_set_w(hContact, CURRENCYRATES_MODULE_NAME, DB_STR_STATUS, nNewStatus);
+
+ if (ID_STATUS_ONLINE != nNewStatus) {
+ db_unset(hContact, LIST_MODULE_NAME, STATUS_MSG_NAME);
+ tstring sSymbol = CurrencyRates_DBGetStringW(hContact, CURRENCYRATES_MODULE_NAME, DB_STR_CURRENCYRATE_SYMBOL);
+ if (false == sSymbol.empty())
+ db_set_ws(hContact, LIST_MODULE_NAME, CONTACT_LIST_NAME, sSymbol.c_str());
+
+ SetContactExtraImage(hContact, eiEmpty);
+ }
+ }
+}
+
+class CTendency
+{
+ enum { NumValues = 2 };
+ enum EComparison
+ {
+ NonValid,
+ Greater,
+ Less,
+ Equal,
+ GreaterOrEqual,
+ LessOrEqual
+ };
+
+public:
+ enum EResult
+ {
+ NotChanged,
+ Up,
+ Down
+ };
+
+public:
+ CTendency() : m_nComparison(NonValid) {}
+
+ bool Parse(CCurrencyRatesProviderBase *pProvider, const tstring& rsFrmt, MCONTACT hContact)
+ {
+ m_abValueFlags[0] = false;
+ m_abValueFlags[1] = false;
+ m_nComparison = NonValid;
+ bool bValid = true;
+ int nCurValue = 0;
+ for (tstring::const_iterator i = rsFrmt.begin(); i != rsFrmt.end() && bValid && nCurValue < NumValues;) {
+ wchar_t chr = *i;
+ switch (chr) {
+ default:
+ if (false == std::isspace(chr))
+ bValid = false;
+ else
+ ++i;
+ break;
+
+ case '%':
+ ++i;
+ if (i != rsFrmt.end()) {
+ wchar_t t = *i;
+ ++i;
+
+ double d;
+ bValid = pProvider->ParseSymbol(hContact, t, d);
+ if (bValid) {
+ m_adValues[nCurValue] = d;
+ m_abValueFlags[nCurValue] = true;
+ ++nCurValue;
+ }
+ }
+ else bValid = false;
+ break;
+ case '>':
+ m_nComparison = Greater;
+ ++i;
+ break;
+ case '<':
+ m_nComparison = Less;
+ ++i;
+ break;
+ case '=':
+ switch (m_nComparison) {
+ default:
+ bValid = false;
+ break;
+ case NonValid:
+ m_nComparison = Equal;
+ break;
+ case Greater:
+ m_nComparison = GreaterOrEqual;
+ break;
+ case Less:
+ m_nComparison = LessOrEqual;
+ break;
+ }
+ ++i;
+ break;
+ }
+ }
+
+ return (bValid && IsValid());
+ }
+
+ bool IsValid() const { return (m_abValueFlags[0] && m_abValueFlags[1] && (m_nComparison != NonValid)); }
+
+ EResult Compare() const
+ {
+ switch (m_nComparison) {
+ case Greater:
+ if (true == IsWithinAccuracy(m_adValues[0], m_adValues[1]))
+ return NotChanged;
+
+ if (m_adValues[0] > m_adValues[1])
+ return Up;
+ return Down;
+
+ case GreaterOrEqual:
+ if ((true == IsWithinAccuracy(m_adValues[0], m_adValues[1])) || (m_adValues[0] > m_adValues[1]))
+ return Up;
+ return Down;
+
+ case Less:
+ if (true == IsWithinAccuracy(m_adValues[0], m_adValues[1]))
+ return NotChanged;
+
+ if (m_adValues[0] < m_adValues[1])
+ return Up;
+ return Down;
+
+ case LessOrEqual:
+ if ((true == IsWithinAccuracy(m_adValues[0], m_adValues[1])) || (m_adValues[0] < m_adValues[1]))
+ return Up;
+ return Down;
+
+ case Equal:
+ if (true == IsWithinAccuracy(m_adValues[0], m_adValues[1]))
+ return Up;
+ return Down;
+ }
+ return NotChanged;
+ }
+
+private:
+ double m_adValues[NumValues];
+ bool m_abValueFlags[NumValues];
+ EComparison m_nComparison;
+};
+
+tstring format_rate(const ICurrencyRatesProvider *pProvider, MCONTACT hContact, const tstring &rsFrmt)
+{
+ tstring sResult;
+
+ for (tstring::const_iterator i = rsFrmt.begin(); i != rsFrmt.end();) {
+ wchar_t chr = *i;
+ switch (chr) {
+ default:
+ sResult += chr;
+ ++i;
+ break;
+
+ case '\\':
+ ++i;
+ if (i != rsFrmt.end()) {
+ wchar_t t = *i;
+ switch (t) {
+ case '%': sResult += L"%"; break;
+ case 't': sResult += L"\t"; break;
+ case 'n': sResult += L"\n"; break;
+ case '\\': sResult += L"\\"; break;
+ default: sResult += chr; sResult += t; break;
+ }
+ ++i;
+ }
+ else sResult += chr;
+ break;
+
+ case '%':
+ ++i;
+ if (i != rsFrmt.end()) {
+ chr = *i;
+
+ byte nWidth = 0;
+ if (::isdigit(chr)) {
+ nWidth = chr - 0x30;
+ ++i;
+ if (i == rsFrmt.end()) {
+ sResult += chr;
+ break;
+ }
+ else chr = *i;
+ }
+
+ sResult += pProvider->FormatSymbol(hContact, chr, nWidth);
+ ++i;
+ }
+ else sResult += chr;
+ break;
+ }
+ }
+
+ return sResult;
+}
+
+void log_to_file(const ICurrencyRatesProvider *pProvider,
+ MCONTACT hContact,
+ const tstring& rsLogFileName,
+ const tstring& rsFormat)
+{
+ CreatePathToFileW(rsLogFileName.c_str());
+
+ tofstream file(rsLogFileName.c_str(), std::ios::app | std::ios::out);
+ file.imbue(GetSystemLocale());
+ if (file.good()) {
+ tstring s = format_rate(pProvider, hContact, rsFormat);
+ file << s;
+ }
+}
+
+void log_to_history(const ICurrencyRatesProvider *pProvider,
+ MCONTACT hContact,
+ time_t nTime,
+ const tstring& rsFormat)
+{
+ tstring s = format_rate(pProvider, hContact, rsFormat);
+ T2Utf psz(s.c_str());
+
+ DBEVENTINFO dbei = {};
+ dbei.szModule = CURRENCYRATES_MODULE_NAME;
+ dbei.timestamp = static_cast<DWORD>(nTime);
+ dbei.flags = DBEF_READ | DBEF_UTF;
+ dbei.eventType = EVENTTYPE_MESSAGE;
+ dbei.cbBlob = (int)::mir_strlen(psz) + 1;
+ dbei.pBlob = (PBYTE)(char*)psz;
+ db_event_add(hContact, &dbei);
+}
+
+bool do_set_contact_extra_icon(MCONTACT hContact, const CTendency& tendency)
+{
+ CTendency::EResult nComparison = tendency.Compare();
+
+ if (CTendency::NotChanged == nComparison)
+ return SetContactExtraImage(hContact, eiNotChanged);
+
+ if (CTendency::Up == nComparison)
+ return SetContactExtraImage(hContact, eiUp);
+
+ if (CTendency::Down == nComparison)
+ return SetContactExtraImage(hContact, eiDown);
+
+ return false;
+}
+
+bool show_popup(const ICurrencyRatesProvider *pProvider,
+ MCONTACT hContact,
+ const CTendency& tendency,
+ const tstring& rsFormat,
+ const CPopupSettings& ps)
+{
+ if (!ServiceExists(MS_POPUP_ADDPOPUPW))
+ return false;
+
+ POPUPDATAW ppd;
+ memset(&ppd, 0, sizeof(ppd));
+ ppd.lchContact = hContact;
+
+ if (tendency.IsValid()) {
+ CTendency::EResult nComparison = tendency.Compare();
+ if (CTendency::NotChanged == nComparison)
+ ppd.lchIcon = CurrencyRates_LoadIconEx(IDI_ICON_NOTCHANGED);
+ else if (CTendency::Up == nComparison)
+ ppd.lchIcon = CurrencyRates_LoadIconEx(IDI_ICON_UP);
+ else if (CTendency::Down == nComparison)
+ ppd.lchIcon = CurrencyRates_LoadIconEx(IDI_ICON_DOWN);
+ }
+
+ mir_wstrncpy(ppd.lpwzContactName, pProvider->FormatSymbol(hContact, 's').c_str(), MAX_CONTACTNAME);
+ {
+ ptrW ss(variables_parsedup((wchar_t*)rsFormat.c_str(), nullptr, hContact));
+ tstring sText = format_rate(pProvider, hContact, tstring(ss));
+ mir_wstrncpy(ppd.lpwzText, sText.c_str(), MAX_SECONDLINE);
+ }
+
+ if (CPopupSettings::colourDefault == ps.GetColourMode()) {
+ ppd.colorText = CPopupSettings::GetDefColourText();
+ ppd.colorBack = CPopupSettings::GetDefColourBk();
+ }
+ else {
+ ppd.colorText = ps.GetColourText();
+ ppd.colorBack = ps.GetColourBk();
+ }
+
+ switch (ps.GetDelayMode()) {
+ default:
+ assert(!"Unknown popup delay mode");
+ case CPopupSettings::delayFromPopup:
+ ppd.iSeconds = 0;
+ break;
+ case CPopupSettings::delayPermanent:
+ ppd.iSeconds = -1;
+ break;
+ case CPopupSettings::delayCustom:
+ ppd.iSeconds = ps.GetDelayTimeout();
+ break;
+ }
+
+ LPARAM lp = 0;
+ if (false == ps.GetHistoryFlag())
+ lp |= 0x08;
+
+ return (0 == CallService(MS_POPUP_ADDPOPUPW, reinterpret_cast<WPARAM>(&ppd), lp));
+}
+
+void CCurrencyRatesProviderBase::WriteContactRate(MCONTACT hContact, double dRate, const tstring& rsSymbol/* = ""*/)
+{
+ time_t nTime = ::time(0);
+
+ if (false == rsSymbol.empty())
+ db_set_ws(hContact, CURRENCYRATES_MODULE_NAME, DB_STR_CURRENCYRATE_SYMBOL, rsSymbol.c_str());
+
+ double dPrev = 0.0;
+ bool bValidPrev = CurrencyRates_DBReadDouble(hContact, CURRENCYRATES_MODULE_NAME, DB_STR_CURRENCYRATE_CURR_VALUE, dPrev);
+ if (true == bValidPrev)
+ CurrencyRates_DBWriteDouble(hContact, CURRENCYRATES_MODULE_NAME, DB_STR_CURRENCYRATE_PREV_VALUE, dPrev);
+
+ CurrencyRates_DBWriteDouble(hContact, CURRENCYRATES_MODULE_NAME, DB_STR_CURRENCYRATE_CURR_VALUE, dRate);
+ db_set_dw(hContact, CURRENCYRATES_MODULE_NAME, DB_STR_CURRENCYRATE_FETCH_TIME, nTime);
+
+ tstring sSymbol = rsSymbol;
+
+ tostringstream oNick;
+ oNick.imbue(GetSystemLocale());
+ if (false == m_sContactListFormat.empty()) {
+ tstring s = format_rate(this, hContact, m_sContactListFormat);
+ oNick << s;
+ }
+ else {
+ if (true == sSymbol.empty())
+ sSymbol = CurrencyRates_DBGetStringW(hContact, CURRENCYRATES_MODULE_NAME, DB_STR_CURRENCYRATE_SYMBOL);
+
+ oNick << std::setfill(L' ') << std::setw(10) << std::left << sSymbol << std::setw(6) << std::right << dRate;
+ }
+ CTendency tendency;
+
+ if (true == tendency.Parse(this, m_sTendencyFormat, hContact))
+ do_set_contact_extra_icon(hContact, tendency);
+
+ db_set_ws(hContact, LIST_MODULE_NAME, CONTACT_LIST_NAME, oNick.str().c_str());
+
+ tstring sStatusMsg = format_rate(this, hContact, m_sStatusMsgFormat);
+ if (false == sStatusMsg.empty())
+ db_set_ws(hContact, LIST_MODULE_NAME, STATUS_MSG_NAME, sStatusMsg.c_str());
+ else
+ db_unset(hContact, LIST_MODULE_NAME, STATUS_MSG_NAME);
+
+ bool bUseContactSpecific = (db_get_b(hContact, CURRENCYRATES_MODULE_NAME, DB_STR_CONTACT_SPEC_SETTINGS, 0) > 0);
+
+ CAdvProviderSettings global_settings(this);
+
+ WORD dwMode = (bUseContactSpecific)
+ ? db_get_w(hContact, CURRENCYRATES_MODULE_NAME, DB_STR_CURRENCYRATE_LOG, static_cast<WORD>(lmDisabled))
+ : global_settings.GetLogMode();
+ if (dwMode&lmExternalFile) {
+ bool bAdd = true;
+ bool bOnlyIfChanged = (bUseContactSpecific)
+ ? (db_get_w(hContact, CURRENCYRATES_MODULE_NAME, DB_STR_CURRENCYRATE_LOG_FILE_CONDITION, 1) > 0)
+ : global_settings.GetLogOnlyChangedFlag();
+ if (true == bOnlyIfChanged) {
+ bAdd = ((false == bValidPrev) || (false == IsWithinAccuracy(dRate, dPrev)));
+ }
+ if (true == bAdd) {
+ tstring sLogFileName = (bUseContactSpecific)
+ ? CurrencyRates_DBGetStringW(hContact, CURRENCYRATES_MODULE_NAME, DB_STR_CURRENCYRATE_LOG_FILE, global_settings.GetLogFileName().c_str())
+ : global_settings.GetLogFileName();
+
+ if (true == sSymbol.empty()) {
+ sSymbol = CurrencyRates_DBGetStringW(hContact, CURRENCYRATES_MODULE_NAME, DB_STR_CURRENCYRATE_SYMBOL);
+ }
+
+ sLogFileName = GenerateLogFileName(sLogFileName, sSymbol);
+
+ tstring sFormat = global_settings.GetLogFormat();
+ if (bUseContactSpecific)
+ sFormat = CurrencyRates_DBGetStringW(hContact, CURRENCYRATES_MODULE_NAME, DB_STR_CURRENCYRATE_FORMAT_LOG_FILE, DB_DEF_LogFormat);
+
+ log_to_file(this, hContact, sLogFileName, sFormat);
+ }
+ }
+ if (dwMode&lmInternalHistory) {
+ bool bAdd = true;
+ bool bOnlyIfChanged = (bUseContactSpecific)
+ ? (db_get_w(hContact, CURRENCYRATES_MODULE_NAME, DB_STR_CURRENCYRATE_HISTORY_CONDITION, 1) > 0)
+ : global_settings.GetHistoryOnlyChangedFlag();
+
+ if (true == bOnlyIfChanged) {
+ bAdd = ((false == bValidPrev) || (false == IsWithinAccuracy(dRate, dPrev)));
+ }
+ if (true == bAdd) {
+ tstring sFormat = (bUseContactSpecific)
+ ? CurrencyRates_DBGetStringW(hContact, CURRENCYRATES_MODULE_NAME, DB_STR_CURRENCYRATE_FORMAT_HISTORY, global_settings.GetHistoryFormat().c_str())
+ : global_settings.GetHistoryFormat();
+
+ log_to_history(this, hContact, nTime, sFormat);
+ }
+ }
+
+ if (dwMode&lmPopup) {
+ bool bOnlyIfChanged = (bUseContactSpecific)
+ ? (1 == db_get_b(hContact, CURRENCYRATES_MODULE_NAME, DB_STR_CURRENCYRATE_POPUP_CONDITION, 1) > 0)
+ : global_settings.GetShowPopupIfValueChangedFlag();
+ if ((false == bOnlyIfChanged)
+ || ((true == bOnlyIfChanged) && (true == bValidPrev) && (false == IsWithinAccuracy(dRate, dPrev)))) {
+ tstring sFormat = (bUseContactSpecific)
+ ? CurrencyRates_DBGetStringW(hContact, CURRENCYRATES_MODULE_NAME, DB_STR_CURRENCYRATE_FORMAT_POPUP, global_settings.GetPopupFormat().c_str())
+ : global_settings.GetPopupFormat();
+
+ CPopupSettings ps = *(global_settings.GetPopupSettingsPtr());
+ ps.InitForContact(hContact);
+ show_popup(this, hContact, tendency, sFormat, ps);
+ }
+ }
+
+ SetContactStatus(hContact, ID_STATUS_ONLINE);
+}
+
+MCONTACT CCurrencyRatesProviderBase::CreateNewContact(const tstring& rsName)
+{
+ MCONTACT hContact = db_add_contact();
+ if (hContact) {
+ if (0 == Proto_AddToContact(hContact, CURRENCYRATES_PROTOCOL_NAME)) {
+ tstring sProvName = GetInfo().m_sName;
+ db_set_ws(hContact, CURRENCYRATES_MODULE_NAME, DB_STR_CURRENCYRATE_PROVIDER, sProvName.c_str());
+ db_set_ws(hContact, CURRENCYRATES_MODULE_NAME, DB_STR_CURRENCYRATE_SYMBOL, rsName.c_str());
+ db_set_ws(hContact, LIST_MODULE_NAME, CONTACT_LIST_NAME, rsName.c_str());
+
+ mir_cslock lck(m_cs);
+ m_aContacts.push_back(hContact);
+ }
+ else {
+ db_delete_contact(hContact);
+ hContact = NULL;
+ }
+ }
+
+ return hContact;
+}
+
+DWORD get_refresh_timeout_miliseconds()
+{
+ if (!g_bAutoUpdate)
+ return INFINITE;
+
+ int nRefreshRateType = db_get_w(0, CURRENCYRATES_MODULE_NAME, DB_KEY_RefreshRateType, RRT_MINUTES);
+ if (nRefreshRateType < RRT_SECONDS || nRefreshRateType > RRT_HOURS)
+ nRefreshRateType = RRT_MINUTES;
+
+ DWORD nTimeout = db_get_w(0, CURRENCYRATES_MODULE_NAME, DB_KEY_RefreshRateValue, 1);
+ switch (nRefreshRateType) {
+ default:
+ case RRT_SECONDS:
+ if (nTimeout < 1 || nTimeout > 60)
+ nTimeout = 1;
+
+ nTimeout *= 1000;
+ break;
+ case RRT_MINUTES:
+ if (nTimeout < 1 || nTimeout > 60)
+ nTimeout = 1;
+
+ nTimeout *= 1000 * 60;
+ break;
+ case RRT_HOURS:
+ if (nTimeout < 1 || nTimeout > 24)
+ nTimeout = 1;
+
+ nTimeout *= 1000 * 60 * 60;
+ break;
+ }
+
+ return nTimeout;
+}
+
+class CBoolGuard
+{
+public:
+ CBoolGuard(bool& rb) : m_b(rb) { m_b = true; }
+ ~CBoolGuard() { m_b = false; }
+
+private:
+ bool m_b;
+};
+
+void CCurrencyRatesProviderBase::Run()
+{
+ DWORD nTimeout = get_refresh_timeout_miliseconds();
+ m_sContactListFormat = CurrencyRates_DBGetStringW(NULL, CURRENCYRATES_MODULE_NAME, DB_KEY_DisplayNameFormat, DB_DEF_DisplayNameFormat);
+ m_sStatusMsgFormat = CurrencyRates_DBGetStringW(NULL, CURRENCYRATES_MODULE_NAME, DB_KEY_StatusMsgFormat, DB_DEF_StatusMsgFormat);
+ m_sTendencyFormat = CurrencyRates_DBGetStringW(NULL, CURRENCYRATES_MODULE_NAME, DB_KEY_TendencyFormat, DB_DEF_TendencyFormat);
+
+ enum
+ {
+ STOP_THREAD = 0,
+ SETTINGS_CHANGED = 1,
+ REFRESH_CONTACT = 2,
+ COUNT_SYNC_OBJECTS = 3
+ };
+
+ HANDLE anEvents[COUNT_SYNC_OBJECTS];
+ anEvents[STOP_THREAD] = g_hEventWorkThreadStop;
+ anEvents[SETTINGS_CHANGED] = m_hEventSettingsChanged;
+ anEvents[REFRESH_CONTACT] = m_hEventRefreshContact;
+
+ TContacts anContacts;
+ {
+ mir_cslock lck(m_cs);
+ anContacts = m_aContacts;
+ }
+
+ bool bGoToBed = false;
+
+ if (g_bAutoUpdate) {
+ CBoolGuard bg(m_bRefreshInProgress);
+ RefreshCurrencyRates(anContacts);
+ }
+
+ while (false == bGoToBed) {
+ anContacts.clear();
+
+ DWORD dwBegin = ::GetTickCount();
+ DWORD dwResult = ::WaitForMultipleObjects(COUNT_SYNC_OBJECTS, anEvents, FALSE, nTimeout);
+ switch (dwResult) {
+ case WAIT_FAILED:
+ assert(!"WaitForMultipleObjects failed");
+ bGoToBed = true;
+ break;
+
+ case WAIT_ABANDONED_0 + STOP_THREAD:
+ case WAIT_ABANDONED_0 + SETTINGS_CHANGED:
+ case WAIT_ABANDONED_0 + REFRESH_CONTACT:
+ assert(!"WaitForMultipleObjects abandoned");
+
+ case WAIT_OBJECT_0 + STOP_THREAD:
+ bGoToBed = true;
+ break;
+
+ case WAIT_OBJECT_0 + SETTINGS_CHANGED:
+ nTimeout = get_refresh_timeout_miliseconds();
+ m_sContactListFormat = CurrencyRates_DBGetStringW(NULL, CURRENCYRATES_MODULE_NAME, DB_KEY_DisplayNameFormat, DB_DEF_DisplayNameFormat);
+ m_sStatusMsgFormat = CurrencyRates_DBGetStringW(NULL, CURRENCYRATES_MODULE_NAME, DB_KEY_StatusMsgFormat, DB_DEF_StatusMsgFormat);
+ m_sTendencyFormat = CurrencyRates_DBGetStringW(NULL, CURRENCYRATES_MODULE_NAME, DB_KEY_TendencyFormat, DB_DEF_TendencyFormat);
+ {
+ mir_cslock lck(m_cs);
+ anContacts = m_aContacts;
+ }
+ break;
+
+ case WAIT_OBJECT_0 + REFRESH_CONTACT:
+ {
+ DWORD dwTimeRest = ::GetTickCount() - dwBegin;
+ if (INFINITE != nTimeout && dwTimeRest < nTimeout)
+ nTimeout -= dwTimeRest;
+
+ {
+ mir_cslock lck(m_cs);
+ anContacts = m_aRefreshingContacts;
+ m_aRefreshingContacts.clear();
+ }
+
+ CBoolGuard bg(m_bRefreshInProgress);
+ RefreshCurrencyRates(anContacts);
+ }
+ break;
+
+ case WAIT_TIMEOUT:
+ nTimeout = get_refresh_timeout_miliseconds();
+ {
+ mir_cslock lck(m_cs);
+ anContacts = m_aContacts;
+ }
+ {
+ CBoolGuard bg(m_bRefreshInProgress);
+ RefreshCurrencyRates(anContacts);
+ }
+ break;
+
+ default:
+ assert(!"What is the hell?");
+ }
+ }
+
+ OnEndRun();
+}
+
+void CCurrencyRatesProviderBase::OnEndRun()
+{
+ TContacts anContacts;
+ {
+ mir_cslock lck(m_cs);
+ anContacts = m_aContacts;
+ m_aRefreshingContacts.clear();
+ }
+
+ CBoolGuard bg(m_bRefreshInProgress);
+ for (auto &it : anContacts)
+ SetContactStatus(it, ID_STATUS_OFFLINE);
+}
+
+void CCurrencyRatesProviderBase::RefreshSettings()
+{
+ ::SetEvent(m_hEventSettingsChanged);
+}
+
+void CCurrencyRatesProviderBase::RefreshAllContacts()
+{
+ { mir_cslock lck(m_cs);
+ m_aRefreshingContacts.clear();
+ for (auto &hContact : m_aContacts)
+ m_aRefreshingContacts.push_back(hContact);
+ }
+
+ ::SetEvent(m_hEventRefreshContact);
+}
+
+void CCurrencyRatesProviderBase::RefreshContact(MCONTACT hContact)
+{
+ { mir_cslock lck(m_cs);
+ m_aRefreshingContacts.push_back(hContact);
+ }
+
+ ::SetEvent(m_hEventRefreshContact);
+}
+
+void CCurrencyRatesProviderBase::FillFormat(TFormatSpecificators &array) const
+{
+ array.push_back(CFormatSpecificator(L"%S", TranslateT("Source of Information")));
+ array.push_back(CFormatSpecificator(L"%r", TranslateT("Rate Value")));
+ array.push_back(CFormatSpecificator(L"%p", TranslateT("Previous Rate Value")));
+ array.push_back(CFormatSpecificator(L"%X", TranslateT("Fetch Time")));
+ array.push_back(CFormatSpecificator(L"%x", TranslateT("Fetch Date")));
+ array.push_back(CFormatSpecificator(L"%t", TranslateT("Fetch Time and Date")));
+ array.push_back(CFormatSpecificator(L"\\%", TranslateT("Percentage Character (%)")));
+ array.push_back(CFormatSpecificator(L"\\t", TranslateT("Tabulation")));
+ array.push_back(CFormatSpecificator(L"\\\\", TranslateT("Left slash (\\)")));
+}
+
+bool CCurrencyRatesProviderBase::ParseSymbol(MCONTACT hContact, wchar_t c, double &d)
+{
+ switch (c) {
+ case 'r':
+ case 'R':
+ return CurrencyRates_DBReadDouble(hContact, CURRENCYRATES_MODULE_NAME, DB_STR_CURRENCYRATE_CURR_VALUE, d);
+
+ case 'p':
+ case 'P':
+ return CurrencyRates_DBReadDouble(hContact, CURRENCYRATES_MODULE_NAME, DB_STR_CURRENCYRATE_PREV_VALUE, d);
+ }
+
+ return false;
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+
+static bool get_fetch_time(MCONTACT hContact, time_t &rTime)
+{
+ DBVARIANT dbv;
+ if (db_get(hContact, CURRENCYRATES_MODULE_NAME, DB_STR_CURRENCYRATE_FETCH_TIME, &dbv) || (DBVT_DWORD != dbv.type))
+ return false;
+
+ rTime = dbv.dVal;
+ return true;
+}
+
+static tstring format_fetch_time(MCONTACT 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();
+}
+
+static 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();
+}
+
+tstring CCurrencyRatesProviderBase::FormatSymbol(MCONTACT hContact, wchar_t c, int nWidth) const
+{
+ tstring ret;
+ double d = 0.0;
+
+ switch (c) {
+ case '%':
+ case '\t':
+ case '\\':
+ ret = c;
+ break;
+ case 'S':
+ ret = CurrencyRates_DBGetStringW(hContact, CURRENCYRATES_MODULE_NAME, DB_STR_CURRENCYRATE_PROVIDER);
+ break;
+ case 's':
+ ret = CurrencyRates_DBGetStringW(hContact, CURRENCYRATES_MODULE_NAME, DB_STR_CURRENCYRATE_SYMBOL);
+ break;
+ case 'X':
+ ret = format_fetch_time(hContact, CurrencyRates_GetTimeFormat(true));
+ break;
+ case 'x':
+ ret = format_fetch_time(hContact, CurrencyRates_GetDateFormat(true));
+ break;
+ case 't':
+ {
+ tstring sFrmt = CurrencyRates_GetDateFormat(true);
+ sFrmt += L" ";
+ sFrmt += CurrencyRates_GetTimeFormat(true);
+ ret = format_fetch_time(hContact, sFrmt);
+ }
+ break;
+ case 'r':
+ case 'R':
+ if (true == CurrencyRates_DBReadDouble(hContact, CURRENCYRATES_MODULE_NAME, DB_STR_CURRENCYRATE_CURR_VALUE, d))
+ ret = format_double(d, nWidth);
+ else
+ ret = L"-";
+ break;
+
+ case 'p':
+ case 'P':
+ if (true == CurrencyRates_DBReadDouble(hContact, CURRENCYRATES_MODULE_NAME, DB_STR_CURRENCYRATE_PREV_VALUE, d))
+ ret = format_double(d, nWidth);
+ else
+ ret = L"-";
+ break;
+ }
+
+ return ret;
+}
diff --git a/protocols/CurrencyRates/src/CurrencyRatesProviderBase.h b/protocols/CurrencyRates/src/CurrencyRatesProviderBase.h
new file mode 100644
index 0000000000..d407a9a709
--- /dev/null
+++ b/protocols/CurrencyRates/src/CurrencyRatesProviderBase.h
@@ -0,0 +1,122 @@
+#ifndef __3e6cb4ec_fc47_468f_a2c8_a77941176bc9_CurrencyRatesProviderBase_h__
+#define __3e6cb4ec_fc47_468f_a2c8_a77941176bc9_CurrencyRatesProviderBase_h__
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// CCurrencyRate - one currency
+
+class CCurrencyRate
+{
+public:
+ CCurrencyRate(const tstring& rsID = L"", const tstring& rsSymbol = L"", const tstring& rsName = L"")
+ : 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;
+};
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// CCurrencyRateSection - block of currency settings
+
+class CCurrencyRateSection
+{
+public:
+ typedef std::vector<CCurrencyRateSection> TSections;
+ typedef std::vector<CCurrencyRate> TCurrencyRates;
+
+public:
+ CCurrencyRateSection(const tstring& rsName = L"", const TSections& raSections = TSections(), const TCurrencyRates& raCurrencyRates = TCurrencyRates())
+ : m_sName(rsName), m_aSections(raSections), m_aCurrencyRates(raCurrencyRates){}
+
+ const tstring& GetName() const
+ {
+ return m_sName;
+ }
+
+ size_t GetSectionCount() const
+ {
+ return m_aSections.size();
+ }
+
+ CCurrencyRateSection GetSection(size_t nIndex) const
+ {
+ return ((nIndex < m_aSections.size()) ? m_aSections[nIndex] : CCurrencyRateSection());
+ }
+
+ size_t GetCurrencyRateCount() const
+ {
+ return m_aCurrencyRates.size();
+ }
+
+ CCurrencyRate GetCurrencyRate(size_t nIndex) const
+ {
+ return ((nIndex < m_aCurrencyRates.size()) ? m_aCurrencyRates[nIndex] : CCurrencyRate());
+ }
+
+private:
+ tstring m_sName;
+ TSections m_aSections;
+ TCurrencyRates m_aCurrencyRates;
+};
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// CCurrencyRatesProviderBase - basic set of methods for retrieving currencies
+
+typedef std::vector<MCONTACT> TContacts;
+
+class CCurrencyRatesProviderBase : public ICurrencyRatesProvider
+{
+ void OnEndRun();
+
+ struct CXMLFileInfo *m_pXMLInfo = nullptr;
+
+ HANDLE m_hEventSettingsChanged;
+ HANDLE m_hEventRefreshContact;
+ tstring m_sContactListFormat;
+ tstring m_sStatusMsgFormat;
+ tstring m_sTendencyFormat;
+ TContacts m_aRefreshingContacts;
+ bool m_bRefreshInProgress;
+
+public:
+ CCurrencyRatesProviderBase();
+ ~CCurrencyRatesProviderBase();
+
+ const CCurrencyRateSection& GetCurrencyRates() const;
+
+ bool Init() override;
+ const CProviderInfo& GetInfo() const override;
+
+ void AddContact(MCONTACT hContact) override;
+ void DeleteContact(MCONTACT hContact) override;
+
+ void Run() override;
+
+ void RefreshAllContacts() override;
+ void RefreshSettings() override;
+ void RefreshContact(MCONTACT hContact) override;
+
+ void FillFormat(TFormatSpecificators&) const override;
+ bool ParseSymbol(MCONTACT hContact, wchar_t c, double &d) override;
+ tstring FormatSymbol(MCONTACT hContact, wchar_t c, int nWidth = 0) const override;
+
+protected:
+ const tstring& GetURL() const;
+ MCONTACT CreateNewContact(const tstring& rsName);
+ static bool IsOnline();
+ static void SetContactStatus(MCONTACT hContact, int nNewStatus);
+ void WriteContactRate(MCONTACT hContact, double dRate, const tstring& rsSymbol = L"");
+
+ virtual void RefreshCurrencyRates(TContacts &anContacts) = 0;
+
+protected:
+ TContacts m_aContacts;
+ mutable mir_cs m_cs;
+};
+
+#endif //__3e6cb4ec_fc47_468f_a2c8_a77941176bc9_CurrencyRatesProviderBase_h__
diff --git a/protocols/CurrencyRates/src/CurrencyRatesProviderCurrencyConverter.cpp b/protocols/CurrencyRates/src/CurrencyRatesProviderCurrencyConverter.cpp
new file mode 100644
index 0000000000..36693d52b1
--- /dev/null
+++ b/protocols/CurrencyRates/src/CurrencyRatesProviderCurrencyConverter.cpp
@@ -0,0 +1,438 @@
+#include "stdafx.h"
+#include "CurrencyRatesProviderCurrencyConverter.h"
+#include <boost\property_tree\ptree.hpp>
+#include <boost\property_tree\json_parser.hpp>
+
+tstring build_url(const tstring &rsURL, const tstring &from, const tstring &to)
+{
+ tostringstream o;
+ o << rsURL << L"?q=" << from << L"_" << to << "&compact=ultra";
+ ptrA szApiKey(g_plugin.getStringA(DB_KEY_ApiKey));
+ if (szApiKey != nullptr)
+ o << "&apiKey=" << szApiKey.get();
+ return o.str();
+}
+
+tstring build_url(MCONTACT hContact, const tstring &rsURL)
+{
+ tstring sFrom = CurrencyRates_DBGetStringW(hContact, CURRENCYRATES_MODULE_NAME, DB_STR_FROM_ID);
+ tstring sTo = CurrencyRates_DBGetStringW(hContact, CURRENCYRATES_MODULE_NAME, DB_STR_TO_ID);
+ return build_url(rsURL, sFrom, sTo);
+}
+
+bool parse_responce(const tstring &rsJSON, double &dRate)
+{
+ try {
+ boost::property_tree::ptree pt;
+ std::istringstream i_stream(currencyrates_t2a(rsJSON.c_str()));
+
+ boost::property_tree::read_json(i_stream, pt);
+ if (!pt.empty()) {
+ auto pt_nested = pt.begin()->second;
+ dRate = pt_nested.get_value<double>();
+ }
+ else {
+ dRate = pt.get_value<double>();
+ }
+
+ return true;
+ }
+ catch (boost::property_tree::ptree_error&) {
+ }
+ return false;
+}
+
+using TWatchedRates = std::vector<CCurrencyRatesProviderCurrencyConverter::TRateInfo>;
+TWatchedRates g_aWatchedRates;
+
+INT_PTR CALLBACK OptDlgProc(HWND hdlg, UINT message, WPARAM wParam, LPARAM lParam)
+{
+ auto get_provider = []()->CCurrencyRatesProviderCurrencyConverter*
+ {
+ for (auto &pProvider : g_apProviders)
+ if (auto p = dynamic_cast<CCurrencyRatesProviderCurrencyConverter*>(pProvider))
+ return p;
+
+ assert(!"We should never get here!");
+ return nullptr;
+ };
+
+ auto make_currencyrate_name = [](const CCurrencyRate &rCurrencyRate)->tstring
+ {
+ const tstring& rsDesc = rCurrencyRate.GetName();
+ return((false == rsDesc.empty()) ? rsDesc : rCurrencyRate.GetSymbol());
+ };
+
+ auto make_contact_name = [](const tstring &rsSymbolFrom, const tstring &rsSymbolTo)->tstring
+ {
+ tostringstream o;
+ o << rsSymbolFrom << L"/" << rsSymbolTo;
+ return o.str();
+ };
+
+
+ auto make_rate_name = [make_contact_name](const CCurrencyRatesProviderCurrencyConverter::TRateInfo &ri)->tstring
+ {
+ if ((false == ri.first.GetName().empty()) && (false == ri.second.GetName().empty()))
+ return make_contact_name(ri.first.GetName(), ri.second.GetName());
+
+ return make_contact_name(ri.first.GetSymbol(), ri.second.GetSymbol());
+ };
+
+
+ auto pProvider = get_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) {
+ CCurrencyRatesProviderCurrencyConverter::TRateInfo ri;
+ if (true == pProvider->GetWatchedRateInfo(i, ri)) {
+ auto it = std::find_if(aTemp.begin(), aTemp.end(), [&ri](const auto& other)->bool
+ {
+ return ((0 == mir_wstrcmpi(ri.first.GetID().c_str(), other.first.GetID().c_str()))
+ && ((0 == mir_wstrcmpi(ri.second.GetID().c_str(), other.second.GetID().c_str()))));
+ });
+ if (it == aTemp.end()) {
+ aRemove.push_back(ri);
+ }
+ else {
+ aTemp.erase(it);
+ }
+ }
+ }
+
+ for (auto &it : aRemove) pProvider->WatchForRate(it, false);
+ for (auto &it : aTemp) pProvider->WatchForRate(it, true);
+ pProvider->RefreshSettings();
+ }
+ }
+ 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);
+
+ CCurrencyRateSection rSection;
+ const auto& rCurrencyRates = pProvider->GetCurrencyRates();
+ if (rCurrencyRates.GetSectionCount() > 0) {
+ rSection = rCurrencyRates.GetSection(0);
+ }
+
+ auto cCurrencyRates = rSection.GetCurrencyRateCount();
+ for (auto i = 0u; i < cCurrencyRates; ++i) {
+ const auto& rCurrencyRate = rSection.GetCurrencyRate(i);
+ tstring sName = make_currencyrate_name(rCurrencyRate);
+ LPCTSTR pszName = sName.c_str();
+ ::SendMessage(hcbxFrom, CB_ADDSTRING, 0, reinterpret_cast<LPARAM>(pszName));
+ ::SendMessage(hcbxTo, CB_ADDSTRING, 0, reinterpret_cast<LPARAM>(pszName));
+ }
+
+ auto cWatchedRates = pProvider->GetWatchedRateCount();
+ for (auto i = 0u; i < cWatchedRates; ++i) {
+ CCurrencyRatesProviderCurrencyConverter::TRateInfo ri;
+ if (true == pProvider->GetWatchedRateInfo(i, ri)) {
+ g_aWatchedRates.push_back(ri);
+ tstring sRate = make_rate_name(ri);
+ LPCTSTR pszRateName = sRate.c_str();
+ ::SendDlgItemMessage(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>(::SendDlgItemMessage(hdlg, IDC_COMBO_CONVERT_FROM, CB_GETCURSEL, 0, 0));
+ int nTo = static_cast<int>(::SendDlgItemMessage(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 = ::SendDlgItemMessage(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>(::SendDlgItemMessage(hdlg, IDC_COMBO_CONVERT_FROM, CB_GETCURSEL, 0, 0));
+ size_t nTo = static_cast<size_t>(::SendDlgItemMessage(hdlg, IDC_COMBO_CONVERT_INTO, CB_GETCURSEL, 0, 0));
+ if ((CB_ERR != nFrom) && (CB_ERR != nTo) && (nFrom != nTo)) {
+ CCurrencyRateSection rSection;
+ const auto& rCurrencyRates = pProvider->GetCurrencyRates();
+ if (rCurrencyRates.GetSectionCount() > 0) {
+ rSection = rCurrencyRates.GetSection(0);
+ }
+
+ auto cCurrencyRates = rSection.GetCurrencyRateCount();
+ if ((nFrom < cCurrencyRates) && (nTo < cCurrencyRates)) {
+ CCurrencyRatesProviderCurrencyConverter::TRateInfo ri;
+ ri.first = rSection.GetCurrencyRate(nFrom);
+ ri.second = rSection.GetCurrencyRate(nTo);
+
+ g_aWatchedRates.push_back(ri);
+
+ tstring sRate = make_rate_name(ri);
+ LPCTSTR pszRateName = sRate.c_str();
+ ::SendDlgItemMessage(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;
+ }
+ break;
+ }
+
+ return FALSE;
+}
+
+CCurrencyRatesProviderCurrencyConverter::CCurrencyRatesProviderCurrencyConverter()
+{
+}
+
+CCurrencyRatesProviderCurrencyConverter::~CCurrencyRatesProviderCurrencyConverter()
+{
+}
+
+void CCurrencyRatesProviderCurrencyConverter::ShowPropertyPage(WPARAM wp, OPTIONSDIALOGPAGE &odp)
+{
+ odp.pszTemplate = MAKEINTRESOURCEA(IDD_DIALOG_OPT_GOOGLE);
+ odp.pfnDlgProc = OptDlgProc;
+ odp.szTab.w = const_cast<LPTSTR>(GetInfo().m_sName.c_str());
+ g_plugin.addOptions(wp, &odp);
+}
+
+void CCurrencyRatesProviderCurrencyConverter::RefreshCurrencyRates(TContacts &anContacts)
+{
+ CHTTPSession http;
+ tstring sURL = GetURL();
+
+ for (TContacts::const_iterator i = anContacts.begin(); i != anContacts.end() && IsOnline(); ++i) {
+ MCONTACT hContact = *i;
+
+ tstring sFullURL = build_url(hContact, sURL);
+ if ((true == http.OpenURL(sFullURL)) && (true == IsOnline())) {
+ tstring sHTML;
+ if ((true == http.ReadResponce(sHTML)) && (true == IsOnline())) {
+ double dRate = 0.0;
+ if ((true == parse_responce(sHTML, dRate)) && (true == IsOnline())) {
+ WriteContactRate(hContact, dRate);
+ continue;
+ }
+ }
+ }
+
+ SetContactStatus(hContact, ID_STATUS_NA);
+ }
+}
+
+double CCurrencyRatesProviderCurrencyConverter::Convert(double dAmount, const CCurrencyRate &from, const CCurrencyRate &to) const
+{
+ tstring sFullURL = build_url(GetURL(), from.GetID(), to.GetID());
+
+ CHTTPSession http;
+ if ((true == http.OpenURL(sFullURL))) {
+ tstring sHTML;
+ if ((true == http.ReadResponce(sHTML))) {
+ double dResult = 0.0;
+ if ((true == parse_responce(sHTML, dResult)))
+ return dResult * dAmount;
+
+ 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;
+}
+
+size_t CCurrencyRatesProviderCurrencyConverter::GetWatchedRateCount() const
+{
+ return m_aContacts.size();
+}
+
+bool CCurrencyRatesProviderCurrencyConverter::GetWatchedRateInfo(size_t nIndex, TRateInfo &rRateInfo)
+{
+ if (nIndex >= m_aContacts.size())
+ return false;
+
+ MCONTACT hContact = m_aContacts[nIndex];
+ tstring sSymbolFrom = CurrencyRates_DBGetStringW(hContact, CURRENCYRATES_MODULE_NAME, DB_STR_FROM_ID);
+ tstring sSymbolTo = CurrencyRates_DBGetStringW(hContact, CURRENCYRATES_MODULE_NAME, DB_STR_TO_ID);
+ tstring sDescFrom = CurrencyRates_DBGetStringW(hContact, CURRENCYRATES_MODULE_NAME, DB_STR_FROM_DESCRIPTION);
+ tstring sDescTo = CurrencyRates_DBGetStringW(hContact, CURRENCYRATES_MODULE_NAME, DB_STR_TO_DESCRIPTION);
+
+ rRateInfo.first = CCurrencyRate(sSymbolFrom, sSymbolFrom, sDescFrom);
+ rRateInfo.second = CCurrencyRate(sSymbolTo, sSymbolTo, sDescTo);
+ return true;
+}
+
+bool CCurrencyRatesProviderCurrencyConverter::WatchForRate(const TRateInfo &ri, bool bWatch)
+{
+ auto i = std::find_if(m_aContacts.begin(), m_aContacts.end(), [&ri](auto hContact)->bool
+ {
+ tstring sFrom = CurrencyRates_DBGetStringW(hContact, CURRENCYRATES_MODULE_NAME, DB_STR_FROM_ID);
+ tstring sTo = CurrencyRates_DBGetStringW(hContact, CURRENCYRATES_MODULE_NAME, DB_STR_TO_ID);
+ return ((0 == mir_wstrcmpi(ri.first.GetID().c_str(), sFrom.c_str()))
+ && (0 == mir_wstrcmpi(ri.second.GetID().c_str(), sTo.c_str())));
+ });
+
+ auto make_contact_name = [](const tstring &rsSymbolFrom, const tstring &rsSymbolTo)->tstring
+ {
+ tostringstream o;
+ o << rsSymbolFrom << L"/" << rsSymbolTo;
+ return o.str();
+ };
+
+
+ if ((true == bWatch) && (i == m_aContacts.end())) {
+ tstring sName = make_contact_name(ri.first.GetSymbol(), ri.second.GetSymbol());
+ MCONTACT hContact = CreateNewContact(sName);
+ if (hContact) {
+ db_set_ws(hContact, CURRENCYRATES_MODULE_NAME, DB_STR_FROM_ID, ri.first.GetID().c_str());
+ db_set_ws(hContact, CURRENCYRATES_MODULE_NAME, DB_STR_TO_ID, ri.second.GetID().c_str());
+ if (false == ri.first.GetName().empty()) {
+ db_set_ws(hContact, CURRENCYRATES_MODULE_NAME, DB_STR_FROM_DESCRIPTION, ri.first.GetName().c_str());
+ }
+ if (false == ri.second.GetName().empty()) {
+ db_set_ws(hContact, CURRENCYRATES_MODULE_NAME, DB_STR_TO_DESCRIPTION, ri.second.GetName().c_str());
+ }
+
+ return true;
+ }
+ }
+ else if ((false == bWatch) && (i != m_aContacts.end())) {
+ MCONTACT hContact = *i;
+ {// for CCritSection
+ mir_cslock lck(m_cs);
+ m_aContacts.erase(i);
+ }
+
+ db_delete_contact(hContact);
+ return true;
+ }
+
+ return false;
+}
+
+MCONTACT CCurrencyRatesProviderCurrencyConverter::GetContactByID(const tstring& rsFromID, const tstring& rsToID) const
+{
+ mir_cslock lck(m_cs);
+
+ auto i = std::find_if(m_aContacts.begin(), m_aContacts.end(), [rsFromID, rsToID](MCONTACT hContact)->bool
+ {
+ tstring sFrom = CurrencyRates_DBGetStringW(hContact, CURRENCYRATES_MODULE_NAME, DB_STR_FROM_ID);
+ tstring sTo = CurrencyRates_DBGetStringW(hContact, CURRENCYRATES_MODULE_NAME, DB_STR_TO_ID);
+ return ((0 == mir_wstrcmpi(rsFromID.c_str(), sFrom.c_str())) && (0 == mir_wstrcmpi(rsToID.c_str(), sTo.c_str())));
+ });
+
+ if (i != m_aContacts.end())
+ return *i;
+
+ return NULL;
+}
+
+void CCurrencyRatesProviderCurrencyConverter::FillFormat(TFormatSpecificators &array) const
+{
+ CSuper::FillFormat(array);
+
+ array.push_back(CFormatSpecificator(L"%F", TranslateT("From Currency Full Name")));
+ array.push_back(CFormatSpecificator(L"%f", TranslateT("From Currency Short Name")));
+ array.push_back(CFormatSpecificator(L"%I", TranslateT("Into Currency Full Name")));
+ array.push_back(CFormatSpecificator(L"%i", TranslateT("Into Currency Short Name")));
+ array.push_back(CFormatSpecificator(L"%s", TranslateT("Short notation for \"%f/%i\"")));
+}
+
+tstring CCurrencyRatesProviderCurrencyConverter::FormatSymbol(MCONTACT hContact, wchar_t c, int nWidth) const
+{
+ switch (c) {
+ case 'F':
+ return CurrencyRates_DBGetStringW(hContact, CURRENCYRATES_MODULE_NAME, DB_STR_FROM_DESCRIPTION);
+
+ case 'f':
+ return CurrencyRates_DBGetStringW(hContact, CURRENCYRATES_MODULE_NAME, DB_STR_FROM_ID);
+
+ case 'I':
+ return CurrencyRates_DBGetStringW(hContact, CURRENCYRATES_MODULE_NAME, DB_STR_TO_DESCRIPTION);
+
+ case 'i':
+ return CurrencyRates_DBGetStringW(hContact, CURRENCYRATES_MODULE_NAME, DB_STR_TO_ID);
+ }
+
+ return CSuper::FormatSymbol(hContact, c, nWidth);
+}
+
+MCONTACT CCurrencyRatesProviderCurrencyConverter::ImportContact(const TiXmlNode *pRoot)
+{
+ const char *sFromID = nullptr, *sToID = nullptr;
+
+ for (auto *pNode : TiXmlFilter(pRoot, "Setting")) {
+ TNameValue Item = parse_setting_node(pNode);
+ if (!mir_strcmpi(Item.first, DB_STR_FROM_ID))
+ sFromID = Item.second;
+ else if (!mir_strcmpi(Item.first, DB_STR_TO_ID))
+ sToID = Item.second;
+ }
+
+ if (sFromID && sToID)
+ return GetContactByID(Utf2T(sFromID).get(), Utf2T(sToID).get());
+
+ return 0;
+}
diff --git a/protocols/CurrencyRates/src/CurrencyRatesProviderCurrencyConverter.h b/protocols/CurrencyRates/src/CurrencyRatesProviderCurrencyConverter.h
new file mode 100644
index 0000000000..bb65f08737
--- /dev/null
+++ b/protocols/CurrencyRates/src/CurrencyRatesProviderCurrencyConverter.h
@@ -0,0 +1,32 @@
+#pragma once
+
+#define DB_STR_FROM_ID "FromID"
+#define DB_STR_TO_ID "ToID"
+#define DB_STR_FROM_DESCRIPTION "FromDesc"
+#define DB_STR_TO_DESCRIPTION "ToDesc"
+
+
+class CCurrencyRatesProviderCurrencyConverter : public CCurrencyRatesProviderBase
+{
+public:
+ typedef CCurrencyRatesProviderBase CSuper;
+ using TRateInfo = std::pair<CCurrencyRate, CCurrencyRate>;
+
+public:
+ CCurrencyRatesProviderCurrencyConverter();
+ ~CCurrencyRatesProviderCurrencyConverter();
+
+ double Convert(double dAmount, const CCurrencyRate &from, const CCurrencyRate &to) const;
+ size_t GetWatchedRateCount() const;
+ bool GetWatchedRateInfo(size_t nIndex, TRateInfo &rRateInfo);
+ bool WatchForRate(const TRateInfo &ri, bool bWatch);
+ MCONTACT GetContactByID(const tstring &rsFromID, const tstring &rsToID) const;
+
+private:
+ void FillFormat(TFormatSpecificators &) const override;
+ void RefreshCurrencyRates(TContacts &anContacts) override;
+ void ShowPropertyPage(WPARAM wp, OPTIONSDIALOGPAGE &odp) override;
+
+ MCONTACT ImportContact(const TiXmlNode*) override;
+ tstring FormatSymbol(MCONTACT hContact, wchar_t c, int nWidth) const override;
+};
diff --git a/protocols/CurrencyRates/src/CurrencyRatesProviders.cpp b/protocols/CurrencyRates/src/CurrencyRatesProviders.cpp
new file mode 100644
index 0000000000..31dd4c771a
--- /dev/null
+++ b/protocols/CurrencyRates/src/CurrencyRatesProviders.cpp
@@ -0,0 +1,83 @@
+#include "StdAfx.h"
+#include "CurrencyRatesProviderCurrencyConverter.h"
+
+#define LAST_RUN_VERSION "LastRunVersion"
+
+TCurrencyRatesProviders g_apProviders;
+
+/////////////////////////////////////////////////////////////////////////////////////////
+
+template<class T>void create_provider(TCurrencyRatesProviders& g_apProviders)
+{
+ ICurrencyRatesProvider *pProvider = new T;
+ if (pProvider->Init())
+ g_apProviders.push_back(pProvider);
+};
+
+void CreateProviders()
+{
+ create_provider<CCurrencyRatesProviderCurrencyConverter>(g_apProviders);
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+
+void ClearProviders()
+{
+ g_apProviders.clear();
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+
+void convert_contact_settings(MCONTACT hContact)
+{
+ WORD dwLogMode = db_get_w(hContact, CURRENCYRATES_MODULE_NAME, DB_STR_CURRENCYRATE_LOG, static_cast<WORD>(lmDisabled));
+ if ((dwLogMode&lmInternalHistory) || (dwLogMode&lmExternalFile))
+ db_set_b(hContact, CURRENCYRATES_MODULE_NAME, DB_STR_CONTACT_SPEC_SETTINGS, 1);
+}
+
+void InitProviders()
+{
+ CreateProviders();
+
+ const WORD nCurrentVersion = 17;
+ WORD nVersion = db_get_w(0, CURRENCYRATES_MODULE_NAME, LAST_RUN_VERSION, 1);
+
+ for (auto &hContact : Contacts(CURRENCYRATES_MODULE_NAME)) {
+ ICurrencyRatesProvider *pProvider = GetContactProviderPtr(hContact);
+ if (pProvider) {
+ pProvider->AddContact(hContact);
+ if (nVersion < nCurrentVersion)
+ convert_contact_settings(hContact);
+ }
+ }
+
+ db_set_w(0, CURRENCYRATES_MODULE_NAME, LAST_RUN_VERSION, nCurrentVersion);
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+
+ICurrencyRatesProvider* GetContactProviderPtr(MCONTACT hContact)
+{
+ char* szProto = GetContactProto(hContact);
+ if (nullptr == szProto || 0 != ::_stricmp(szProto, CURRENCYRATES_PROTOCOL_NAME))
+ return nullptr;
+
+ tstring sProvider = CurrencyRates_DBGetStringW(hContact, CURRENCYRATES_MODULE_NAME, DB_STR_CURRENCYRATE_PROVIDER);
+ if (true == sProvider.empty())
+ return nullptr;
+
+ return FindProvider(sProvider);
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+
+ICurrencyRatesProvider* FindProvider(const tstring& rsName)
+{
+ for (auto &pProvider : g_apProviders) {
+ const ICurrencyRatesProvider::CProviderInfo& rInfo = pProvider->GetInfo();
+ if (0 == ::mir_wstrcmpi(rsName.c_str(), rInfo.m_sName.c_str()))
+ return pProvider;
+ }
+
+ return nullptr;
+}
diff --git a/protocols/CurrencyRates/src/DBUtils.cpp b/protocols/CurrencyRates/src/DBUtils.cpp
new file mode 100644
index 0000000000..20189c0f3f
--- /dev/null
+++ b/protocols/CurrencyRates/src/DBUtils.cpp
@@ -0,0 +1,43 @@
+#include "StdAfx.h"
+
+std::wstring GetNodeText(const TiXmlElement *pNode)
+{
+ auto *pszText = pNode->GetText();
+ if (pszText)
+ return Utf2T(pszText).get();
+
+ return std::wstring();
+}
+
+std::wstring CurrencyRates_DBGetStringW(MCONTACT hContact, const char *szModule, const char *szSetting, const wchar_t *pszDefValue)
+{
+ if (pszDefValue == nullptr)
+ pszDefValue = L"";
+
+ return std::wstring(ptrW(db_get_wsa(hContact, szModule, szSetting, pszDefValue)));
+}
+
+bool CurrencyRates_DBWriteDouble(MCONTACT hContact, const char *szModule, const char *szSetting, double dValue)
+{
+ return 0 == db_set_blob(hContact, szModule, szSetting, &dValue, sizeof(dValue));
+}
+
+bool CurrencyRates_DBReadDouble(MCONTACT hContact, const char *szModule, const char *szSetting, double& rdValue)
+{
+ DBVARIANT dbv = {};
+ dbv.type = DBVT_BLOB;
+
+ bool bResult = ((0 == db_get(hContact, szModule, szSetting, &dbv)) && (DBVT_BLOB == dbv.type));
+ if (bResult)
+ rdValue = *reinterpret_cast<double*>(dbv.pbVal);
+
+ db_free(&dbv);
+ return bResult;
+}
+
+void FixInvalidChars(tstring &s)
+{
+ for (auto &c : s)
+ if (wcschr(L"\\/:*?\"<>|", c))
+ c = '_';
+}
diff --git a/protocols/CurrencyRates/src/DBUtils.h b/protocols/CurrencyRates/src/DBUtils.h
new file mode 100644
index 0000000000..f6c7f83b71
--- /dev/null
+++ b/protocols/CurrencyRates/src/DBUtils.h
@@ -0,0 +1,53 @@
+#ifndef __54294385_3fdd_4f0c_98c3_c583a96e7fb4_DBUtils_h__
+#define __54294385_3fdd_4f0c_98c3_c583a96e7fb4_DBUtils_h__
+
+#define DB_KEY_RefreshRateType "CC_RefreshRateType"
+#define DB_KEY_RefreshRateValue "CC_RefreshRateValue"
+
+#define DB_KEY_StatusMsgFormat "CC_StatusMessageFormat"
+#define DB_DEF_StatusMsgFormat L""
+
+#define DB_DEF_IniFileName L"CC.xml"
+
+#define DB_KEY_ApiKey "CC_ApiKey"
+
+#define DB_KEY_DisplayNameFormat "CC_DspNameFrmt"
+#define DB_DEF_DisplayNameFormat L"1 %f = %r %i"
+
+#define DB_KEY_HistoryFormat "CC_HistoryFormat"
+#define DB_DEF_HistoryFormat L"%s %r"
+
+#define DB_KEY_HistoryCondition "CC_AddToHistoryOnlyIfValueIsChanged"
+
+#define DB_KEY_LogMode "CC_LogMode"
+#define DB_KEY_LogFile "CC_LogFile"
+#define DB_KEY_LogCondition "CC_AddToLogOnlyIfValueIsChanged"
+
+#define DB_KEY_LogFormat "CC_LogFileFormat"
+#define DB_DEF_LogFormat L"%s\\t%t\\t%r\\n"
+
+#define DB_KEY_PopupFormat "CC_PopupFormat"
+#define DB_DEF_PopupFormat L"\\nCurrent = %r\\nPrevious = %p"
+
+#define DB_KEY_PopupCondition "CC_ShowPopupOnlyIfValueChanged"
+
+#define DB_KEY_PopupColourMode "CC_PopupColourMode"
+#define DB_KEY_PopupBkColour "CC_PopupColourBk"
+#define DB_KEY_PopupTextColour "CC_PopupColourText"
+#define DB_KEY_PopupDelayMode "CC_PopupDelayMode"
+#define DB_KEY_PopupDelayTimeout "CC_PopupDelayTimeout"
+#define DB_KEY_PopupHistoryFlag "CC_PopupHistoryFlag"
+
+#define DB_KEY_TendencyFormat "CC_TendencyFormat"
+#define DB_DEF_TendencyFormat L"%r>%p"
+
+void FixInvalidChars(tstring &s);
+
+std::wstring GetNodeText(const TiXmlElement*);
+
+std::wstring CurrencyRates_DBGetStringW(MCONTACT hContact, const char *szModule, const char *szSetting, const wchar_t* pszDefValue = nullptr);
+
+bool CurrencyRates_DBWriteDouble(MCONTACT hContact, const char *szModule, const char *szSetting, double dValue);
+bool CurrencyRates_DBReadDouble(MCONTACT hContact, const char *szModule, const char *szSetting, double& rdValue);
+
+#endif //__54294385_3fdd_4f0c_98c3_c583a96e7fb4_DBUtils_h__
diff --git a/protocols/CurrencyRates/src/EconomicRateInfo.h b/protocols/CurrencyRates/src/EconomicRateInfo.h
new file mode 100644
index 0000000000..664649a47a
--- /dev/null
+++ b/protocols/CurrencyRates/src/EconomicRateInfo.h
@@ -0,0 +1,59 @@
+#ifndef __87d726e0_26c6_485d_8016_1fba819b037d_EconomicRateInfo__
+#define __87d726e0_26c6_485d_8016_1fba819b037d_EconomicRateInfo__
+
+#define CURRENCYRATES_PROTOCOL_NAME "CurrencyRates"// protocol name
+
+#define CURRENCYRATES_MODULE_NAME "CurrencyRates" // db settings module path
+
+enum ERefreshRateType
+{
+ RRT_SECONDS = 0,
+ RRT_MINUTES = 1,
+ RRT_HOURS = 2
+};
+
+#define DB_STR_ENABLE_LOG "EnableLog"
+#define DB_STR_CURRENCYRATE_PROVIDER "CurrencyRateProvider"
+#define DB_STR_CURRENCYRATE_ID "CurrencyRateID"
+#define DB_STR_CURRENCYRATE_SYMBOL "CurrencyRateSymbol"
+#define DB_STR_CURRENCYRATE_DESCRIPTION "CurrencyRateDescription"
+#define DB_STR_CURRENCYRATE_PREV_VALUE "PreviousCurrencyRateValue"
+#define DB_STR_CURRENCYRATE_CURR_VALUE "CurrentCurrencyRateValue"
+#define DB_STR_CURRENCYRATE_FETCH_TIME "FetchTime"
+
+
+enum ELogMode
+{
+ lmDisabled = 0x0000,
+ lmInternalHistory = 0x0001,
+ lmExternalFile = 0x0002,
+ lmPopup = 0x0004,
+};
+
+#define DB_STR_CONTACT_SPEC_SETTINGS "ContactSpecSettings"
+#define DB_STR_CURRENCYRATE_LOG "Log"
+#define DB_STR_CURRENCYRATE_LOG_FILE "LogFile"
+#define DB_STR_CURRENCYRATE_FORMAT_LOG_FILE "LogFileFormat"
+#define DB_STR_CURRENCYRATE_FORMAT_HISTORY "HistoryFormat"
+#define DB_STR_CURRENCYRATE_LOG_FILE_CONDITION "AddToLogOnlyIfValueIsChanged"
+#define DB_STR_CURRENCYRATE_HISTORY_CONDITION "AddToHistoryOnlyIfValueIsChanged"
+#define DB_STR_CURRENCYRATE_EXTRA_IMAGE_SLOT "ExtraImageSlot"
+#define DB_STR_CURRENCYRATE_FORMAT_POPUP "PopupFormat"
+#define DB_STR_CURRENCYRATE_POPUP_CONDITION "ShowPopupOnlyIfValueIsChanged"
+
+#define DB_STR_CURRENCYRATE_POPUP_COLOUR_MODE "PopupColourMode"
+#define DB_STR_CURRENCYRATE_POPUP_COLOUR_BK "PopupColourBk"
+#define DB_STR_CURRENCYRATE_POPUP_COLOUR_TEXT "PopupColourText"
+#define DB_STR_CURRENCYRATE_POPUP_DELAY_MODE "PopupDelayMode"
+#define DB_STR_CURRENCYRATE_POPUP_DELAY_TIMEOUT "PopupDelayTimeout"
+#define DB_STR_CURRENCYRATE_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/CurrencyRates/src/ExtraImages.cpp b/protocols/CurrencyRates/src/ExtraImages.cpp
new file mode 100644
index 0000000000..686f4e34e7
--- /dev/null
+++ b/protocols/CurrencyRates/src/ExtraImages.cpp
@@ -0,0 +1,30 @@
+#include "StdAfx.h"
+
+static HANDLE hExtraIcon;
+
+void CurrencyRates_InitExtraIcons()
+{
+ hExtraIcon = ExtraIcon_RegisterIcolib(ICON_STR_CURRENCYRATE, CURRENCYRATES_PROTOCOL_NAME, CURRENCYRATES_PROTOCOL_NAME "_" ICON_STR_MAIN);
+}
+
+bool SetContactExtraImage(MCONTACT hContact, EImageIndex nIndex)
+{
+ if (!hExtraIcon)
+ return false;
+
+ HANDLE hIcolib;
+ switch (nIndex) {
+ case eiUp:
+ hIcolib = CurrencyRates_GetIconHandle(IDI_ICON_UP);
+ break;
+ case eiDown:
+ hIcolib = CurrencyRates_GetIconHandle(IDI_ICON_DOWN);
+ break;
+ case eiNotChanged:
+ hIcolib = CurrencyRates_GetIconHandle(IDI_ICON_NOTCHANGED);
+ break;
+ default:
+ hIcolib = nullptr;
+ }
+ return ExtraIcon_SetIcon(hExtraIcon, hContact, hIcolib) == 0;
+}
diff --git a/protocols/CurrencyRates/src/ExtraImages.h b/protocols/CurrencyRates/src/ExtraImages.h
new file mode 100644
index 0000000000..b3ef9deaa6
--- /dev/null
+++ b/protocols/CurrencyRates/src/ExtraImages.h
@@ -0,0 +1,16 @@
+#ifndef __9d0dac0c_12e4_46ce_809a_db6dc7d6f269_ExtraImages_h__
+#define __9d0dac0c_12e4_46ce_809a_db6dc7d6f269_ExtraImages_h__
+
+enum EImageIndex
+{
+ eiUp = 0,
+ eiDown = 1,
+ eiNotChanged = 2,
+ eiEmpty = 3
+};
+
+bool SetContactExtraImage(MCONTACT hContact, EImageIndex nIndex);
+
+void CurrencyRates_InitExtraIcons(void);
+
+#endif //__9d0dac0c_12e4_46ce_809a_db6dc7d6f269_ExtraImages_h__
diff --git a/protocols/CurrencyRates/src/Forex.cpp b/protocols/CurrencyRates/src/Forex.cpp
new file mode 100644
index 0000000000..b3b2424d48
--- /dev/null
+++ b/protocols/CurrencyRates/src/Forex.cpp
@@ -0,0 +1,325 @@
+// Forex.cpp : Defines the exported functions for the DLL application.
+//
+
+#include "stdafx.h"
+
+CMPlugin g_plugin;
+
+HANDLE g_hEventWorkThreadStop;
+//int g_nStatus = ID_STATUS_OFFLINE;
+bool g_bAutoUpdate = true;
+HGENMENU g_hMenuEditSettings = nullptr;
+HGENMENU g_hMenuOpenLogFile = nullptr;
+#ifdef CHART_IMPLEMENT
+HGENMENU g_hMenuChart = nullptr;
+#endif
+HGENMENU g_hMenuRefresh = nullptr, g_hMenuRoot = nullptr;
+
+#define DB_STR_AUTO_UPDATE "AutoUpdate"
+
+typedef std::vector<HANDLE> THandles;
+THandles g_ahThreads;
+HGENMENU g_hEnableDisableMenu;
+HANDLE g_hTBButton;
+
+LPSTR g_pszAutoUpdateCmd = "CurrencyRates/Enable-Disable Auto Update";
+LPSTR g_pszCurrencyConverter = "CurrencyRates/CurrencyConverter";
+
+void UpdateMenu(bool bAutoUpdate)
+{
+ if (bAutoUpdate) // to enable auto-update
+ Menu_ModifyItem(g_hEnableDisableMenu, LPGENW("Auto Update Enabled"), CurrencyRates_GetIconHandle(IDI_ICON_MAIN));
+ else // to disable auto-update
+ Menu_ModifyItem(g_hEnableDisableMenu, LPGENW("Auto Update Disabled"), CurrencyRates_GetIconHandle(IDI_ICON_DISABLED));
+
+ CallService(MS_TTB_SETBUTTONSTATE, reinterpret_cast<WPARAM>(g_hTBButton), !bAutoUpdate ? TTBST_PUSHED : 0);
+}
+
+INT_PTR CurrencyRatesMenu_RefreshAll(WPARAM, LPARAM)
+{
+ for (auto &pProvider : g_apProviders)
+ pProvider->RefreshAllContacts();
+ return 0;
+}
+
+INT_PTR CurrencyRatesMenu_EnableDisable(WPARAM, LPARAM)
+{
+ g_bAutoUpdate = (g_bAutoUpdate) ? false : true;
+ db_set_b(0, CURRENCYRATES_MODULE_NAME, DB_STR_AUTO_UPDATE, g_bAutoUpdate);
+
+ for (auto &pProvider : g_apProviders) {
+ pProvider->RefreshSettings();
+ if (g_bAutoUpdate)
+ pProvider->RefreshAllContacts();
+ }
+
+ UpdateMenu(g_bAutoUpdate);
+ return 0;
+}
+
+void InitMenu()
+{
+ CMenuItem mi(&g_plugin);
+ mi.flags = CMIF_UNICODE;
+ mi.root = g_plugin.addRootMenu(MO_MAIN, LPGENW("Currency Rates"), 0, CurrencyRates_GetIconHandle(IDI_ICON_MAIN));
+ Menu_ConfigureItem(mi.root, MCI_OPT_UID, "B474F556-22B6-42A1-A91E-22FE4F671388");
+
+ SET_UID(mi, 0x9de6716, 0x3591, 0x48c4, 0x9f, 0x64, 0x1b, 0xfd, 0xc6, 0xd1, 0x34, 0x97);
+ mi.name.w = LPGENW("Enable/Disable Auto Update");
+ mi.position = 10100001;
+ mi.hIcolibItem = CurrencyRates_GetIconHandle(IDI_ICON_MAIN);
+ mi.pszService = g_pszAutoUpdateCmd;
+ g_hEnableDisableMenu = Menu_AddMainMenuItem(&mi);
+ CreateServiceFunction(mi.pszService, CurrencyRatesMenu_EnableDisable);
+ UpdateMenu(g_bAutoUpdate);
+
+ SET_UID(mi, 0x91cbabf6, 0x5073, 0x4a78, 0x84, 0x8, 0x34, 0x61, 0xc1, 0x8a, 0x34, 0xd9);
+ mi.name.w = LPGENW("Refresh All Rates");
+ mi.position = 20100001;
+ mi.hIcolibItem = CurrencyRates_GetIconHandle(IDI_ICON_MAIN);
+ mi.pszService = "CurrencyRates/RefreshAll";
+ Menu_AddMainMenuItem(&mi);
+ CreateServiceFunction(mi.pszService, CurrencyRatesMenu_RefreshAll);
+
+ SET_UID(mi, 0x3663409c, 0xbd36, 0x473b, 0x9b, 0x4f, 0xff, 0x80, 0xf6, 0x2c, 0xdf, 0x9b);
+ mi.name.w = LPGENW("Currency Converter...");
+ mi.position = 20100002;
+ mi.hIcolibItem = CurrencyRates_GetIconHandle(IDI_ICON_CURRENCY_CONVERTER);
+ mi.pszService = g_pszCurrencyConverter;
+ Menu_AddMainMenuItem(&mi);
+ CreateServiceFunction(mi.pszService, CurrencyRatesMenu_CurrencyConverter);
+
+ SET_UID(mi, 0x7cca4fd9, 0x903f, 0x4b7d, 0x93, 0x7a, 0x18, 0x63, 0x23, 0xd4, 0xa9, 0xa9);
+ mi.name.w = LPGENW("Export All Currency Rates");
+ mi.hIcolibItem = CurrencyRates_GetIconHandle(IDI_ICON_EXPORT);
+ mi.pszService = MS_CURRENCYRATES_EXPORT;
+ mi.position = 20100003;
+ Menu_AddMainMenuItem(&mi);
+
+ SET_UID(mi, 0xa994d3b, 0x77c2, 0x4612, 0x8d, 0x5, 0x6a, 0xae, 0x8c, 0x21, 0xbd, 0xc9);
+ mi.name.w = LPGENW("Import All Currency Rates");
+ mi.hIcolibItem = CurrencyRates_GetIconHandle(IDI_ICON_IMPORT);
+ mi.pszService = MS_CURRENCYRATES_IMPORT;
+ mi.position = 20100004;
+ Menu_AddMainMenuItem(&mi);
+
+ HookEvent(ME_CLIST_PREBUILDCONTACTMENU, CurrencyRates_PrebuildContactMenu);
+
+ g_hMenuRoot = mi.root = g_plugin.addRootMenu(MO_CONTACT, LPGENW("Currency Rates"), 0, CurrencyRates_GetIconHandle(IDI_ICON_MAIN));
+ Menu_ConfigureItem(mi.root, MCI_OPT_UID, "C259BE01-642C-461E-997D-0E756B2A3AD6");
+
+ SET_UID(mi, 0xb9812194, 0x3235, 0x4e76, 0xa3, 0xa4, 0x73, 0x32, 0x96, 0x1c, 0x1c, 0xf4);
+ mi.name.w = LPGENW("Refresh");
+ mi.hIcolibItem = CurrencyRates_GetIconHandle(IDI_ICON_REFRESH);
+ mi.pszService = "CurrencyRates/RefreshContact";
+ g_hMenuRefresh = Menu_AddContactMenuItem(&mi, CURRENCYRATES_PROTOCOL_NAME);
+ Menu_ConfigureItem(g_hMenuRefresh, MCI_OPT_EXECPARAM, INT_PTR(0));
+ CreateServiceFunction(mi.pszService, CurrencyRatesMenu_RefreshContact);
+
+ SET_UID(mi, 0x19a16fa2, 0xf370, 0x4201, 0x92, 0x9, 0x25, 0xde, 0x4e, 0x55, 0xf9, 0x1a);
+ mi.name.w = LPGENW("Open Log File...");
+ mi.hIcolibItem = nullptr;
+ mi.pszService = "CurrencyRates/OpenLogFile";
+ g_hMenuOpenLogFile = Menu_AddContactMenuItem(&mi, CURRENCYRATES_PROTOCOL_NAME);
+ Menu_ConfigureItem(g_hMenuOpenLogFile, MCI_OPT_EXECPARAM, 1);
+ CreateServiceFunction(mi.pszService, CurrencyRatesMenu_OpenLogFile);
+
+ #ifdef CHART_IMPLEMENT
+ SET_UID(mi, 0x65da7256, 0x43a2, 0x4857, 0xac, 0x52, 0x1c, 0xb7, 0xff, 0xd7, 0x96, 0xfa);
+ mi.name.w = LPGENW("Chart...");
+ mi.hIcolibItem = nullptr;
+ mi.pszService = "CurrencyRates/Chart";
+ g_hMenuChart = Menu_AddContactMenuItem(&mi, CURRENCYRATES_PROTOCOL_NAME);
+ CreateServiceFunction(mi.pszService, CurrencyRatesMenu_Chart);
+ #endif
+
+ SET_UID(mi, 0xac5fc17, 0x5640, 0x4f81, 0xa3, 0x44, 0x8c, 0xb6, 0x9a, 0x5c, 0x98, 0xf);
+ mi.name.w = LPGENW("Edit Settings...");
+ mi.hIcolibItem = nullptr;
+ mi.pszService = "CurrencyRates/EditSettings";
+ g_hMenuEditSettings = Menu_AddContactMenuItem(&mi, CURRENCYRATES_PROTOCOL_NAME);
+ #ifdef CHART_IMPLEMENT
+ Menu_ConfigureItem(g_hMenuEditSettings, MCI_OPT_EXECPARAM, 3);
+ #else
+ Menu_ConfigureItem(g_hMenuEditSettings, MCI_OPT_EXECPARAM, 2);
+ #endif
+ CreateServiceFunction(mi.pszService, CurrencyRatesMenu_EditSettings);
+}
+
+int CurrencyRates_OnToolbarLoaded(WPARAM, LPARAM)
+{
+ TTBButton ttb = {};
+ ttb.name = LPGEN("Enable/Disable Currency Rates Auto Update");
+ ttb.pszService = g_pszAutoUpdateCmd;
+ ttb.pszTooltipUp = LPGEN("Currency Rates Auto Update Enabled");
+ ttb.pszTooltipDn = LPGEN("Currency Rates Auto Update Disabled");
+ ttb.hIconHandleUp = CurrencyRates_GetIconHandle(IDI_ICON_MAIN);
+ ttb.hIconHandleDn = CurrencyRates_GetIconHandle(IDI_ICON_DISABLED);
+ ttb.dwFlags = ((g_bAutoUpdate) ? 0 : TTBBF_PUSHED) | TTBBF_ASPUSHBUTTON | TTBBF_VISIBLE;
+ g_hTBButton = g_plugin.addTTB(&ttb);
+
+ ttb.name = LPGEN("Currency Converter");
+ ttb.pszService = g_pszCurrencyConverter;
+ ttb.pszTooltipUp = LPGEN("Currency Converter");
+ ttb.pszTooltipDn = LPGEN("Currency Converter");
+ ttb.hIconHandleUp = CurrencyRates_GetIconHandle(IDI_ICON_CURRENCY_CONVERTER);
+ ttb.hIconHandleDn = CurrencyRates_GetIconHandle(IDI_ICON_CURRENCY_CONVERTER);
+ ttb.dwFlags = TTBBF_VISIBLE;
+ g_plugin.addTTB(&ttb);
+
+ return 0;
+}
+
+static void WorkingThread(void *pParam)
+{
+ ICurrencyRatesProvider *pProvider = reinterpret_cast<ICurrencyRatesProvider*>(pParam);
+ assert(pProvider);
+
+ if (pProvider)
+ pProvider->Run();
+}
+
+int CurrencyRatesEventFunc_OnModulesLoaded(WPARAM, LPARAM)
+{
+ CHTTPSession::Init();
+
+ g_hEventWorkThreadStop = ::CreateEvent(nullptr, TRUE, FALSE, nullptr);
+ HookEvent(ME_USERINFO_INITIALISE, CurrencyRatesEventFunc_OnUserInfoInit);
+
+ HookEvent(ME_CLIST_DOUBLECLICKED, CurrencyRates_OnContactDoubleClick);
+
+ HookEvent(ME_TTB_MODULELOADED, CurrencyRates_OnToolbarLoaded);
+
+ g_bAutoUpdate = 1 == db_get_b(0, CURRENCYRATES_MODULE_NAME, DB_STR_AUTO_UPDATE, 1);
+
+ InitMenu();
+
+ ::ResetEvent(g_hEventWorkThreadStop);
+
+ for (auto &pProvider : g_apProviders)
+ g_ahThreads.push_back(mir_forkthread(WorkingThread, pProvider));
+ return 0;
+}
+
+int CurrencyRatesEventFunc_OnContactDeleted(WPARAM hContact, LPARAM)
+{
+ auto pProvider = GetContactProviderPtr(hContact);
+ if (pProvider)
+ pProvider->DeleteContact(hContact);
+ return 0;
+}
+
+INT_PTR CurrencyRateProtoFunc_GetCaps(WPARAM wParam, LPARAM)
+{
+ switch (wParam) {
+ case PFLAG_UNIQUEIDTEXT:
+ return (INT_PTR)Translate("Currency Symbol");
+ }
+
+ return 0;
+}
+
+INT_PTR CurrencyRateProtoFunc_GetStatus(WPARAM, LPARAM)
+{
+ return g_bAutoUpdate ? ID_STATUS_ONLINE : ID_STATUS_OFFLINE;
+}
+
+void WaitForWorkingThreads()
+{
+ size_t cThreads = g_ahThreads.size();
+ if (cThreads > 0) {
+ HANDLE* paHandles = &*(g_ahThreads.begin());
+ ::WaitForMultipleObjects((DWORD)cThreads, paHandles, TRUE, INFINITE);
+ }
+}
+
+
+int CurrencyRatesEventFunc_PreShutdown(WPARAM, LPARAM)
+{
+ ::SetEvent(g_hEventWorkThreadStop);
+
+ CModuleInfo::OnMirandaShutdown();
+ return 0;
+}
+
+int CurrencyRatesEventFunc_OptInitialise(WPARAM wp, LPARAM/* lp*/)
+{
+ OPTIONSDIALOGPAGE odp = {};
+ odp.position = 910000000;
+ odp.szTitle.w = LPGENW("Currency Rates");
+ odp.szGroup.w = LPGENW("Network");
+ odp.flags = ODPF_USERINFOTAB | ODPF_UNICODE;
+
+ for (auto &it : g_apProviders)
+ it->ShowPropertyPage(wp, odp);
+ return 0;
+}
+
+inline int CurrencyRates_UnhookEvent(HANDLE h)
+{
+ return UnhookEvent(h);
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+
+EXTERN_C __declspec(dllexport) const MUUID MirandaInterfaces[] = { MIID_PROTOCOL, MIID_LAST };
+
+/////////////////////////////////////////////////////////////////////////////////////////
+
+PLUGININFOEX pluginInfoEx =
+{
+ sizeof(PLUGININFOEX),
+ __PLUGIN_NAME,
+ PLUGIN_MAKE_VERSION(__MAJOR_VERSION, __MINOR_VERSION, __RELEASE_NUM, __BUILD_NUM),
+ __DESCRIPTION,
+ __AUTHOR,
+ __COPYRIGHT,
+ __AUTHORWEB,
+ UNICODE_AWARE,
+ // {E882056D-0D1D-4131-9A98-404CBAEA6A9C}
+ { 0xe882056d, 0xd1d, 0x4131, { 0x9a, 0x98, 0x40, 0x4c, 0xba, 0xea, 0x6a, 0x9c } }
+};
+
+CMPlugin::CMPlugin() :
+ PLUGIN<CMPlugin>(CURRENCYRATES_PROTOCOL_NAME, pluginInfoEx)
+{
+ RegisterProtocol(PROTOTYPE_VIRTUAL);
+ SetUniqueId(DB_STR_CURRENCYRATE_SYMBOL);
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+
+int CMPlugin::Load(void)
+{
+ if (!CModuleInfo::Verify())
+ return 1;
+
+ CurrencyRates_IconsInit();
+ CurrencyRates_InitExtraIcons();
+
+ InitProviders();
+
+ CreateProtoServiceFunction(CURRENCYRATES_PROTOCOL_NAME, PS_GETCAPS, CurrencyRateProtoFunc_GetCaps);
+ CreateProtoServiceFunction(CURRENCYRATES_PROTOCOL_NAME, PS_GETSTATUS, CurrencyRateProtoFunc_GetStatus);
+
+ HookEvent(ME_SYSTEM_MODULESLOADED, CurrencyRatesEventFunc_OnModulesLoaded);
+ HookEvent(ME_DB_CONTACT_DELETED, CurrencyRatesEventFunc_OnContactDeleted);
+ HookEvent(ME_SYSTEM_PRESHUTDOWN, CurrencyRatesEventFunc_PreShutdown);
+ HookEvent(ME_OPT_INITIALISE, CurrencyRatesEventFunc_OptInitialise);
+
+ CreateServiceFunction(MS_CURRENCYRATES_EXPORT, CurrencyRates_Export);
+ CreateServiceFunction(MS_CURRENCYRATES_IMPORT, CurrencyRates_Import);
+
+ return 0;
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+
+int CMPlugin::Unload(void)
+{
+ WaitForWorkingThreads();
+
+ ClearProviders();
+ ::CloseHandle(g_hEventWorkThreadStop);
+ return 0;
+}
diff --git a/protocols/CurrencyRates/src/HTMLParserMS.cpp b/protocols/CurrencyRates/src/HTMLParserMS.cpp
new file mode 100644
index 0000000000..a712d7589f
--- /dev/null
+++ b/protocols/CurrencyRates/src/HTMLParserMS.cpp
@@ -0,0 +1,254 @@
+#include "StdAfx.h"
+
+using _com_util::CheckError;
+
+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
+ {
+ tstring sAttr;
+ CComPtr<IHTMLElement> pElement;
+ if (SUCCEEDED(m_pElement->QueryInterface(IID_IHTMLElement, reinterpret_cast<void**>(&pElement))) && pElement) {
+ _variant_t vAttribute;
+ BSTR pbstrAttrName = ::SysAllocString(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&) {
+ }
+ }
+ ::SysFreeString(pbstrAttrName);
+ }
+
+ return sAttr;
+ }
+
+ virtual tstring GetText() const
+ {
+ 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)
+ 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(nullptr));
+
+ m_bCallUninit = true;
+
+ _com_util::CheckError(
+ ::CoCreateInstance(CLSID_HTMLDocument,
+ nullptr,
+ 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 (m_bCallUninit)
+ ::CoUninitialize();
+}
+
+CHTMLParserMS::THTMLNodePtr CHTMLParserMS::ParseString(const tstring& rsHTML)
+{
+ mir_cslock lck(m_cs);
+
+ CComPtr<IMarkupContainer> pMC;
+ HRESULT hr = m_pMS->ParseString((OLECHAR*)rsHTML.c_str(), 0, &pMC, m_pMkStart, m_pMkFinish);
+ if (SUCCEEDED(hr) && pMC) {
+ CComPtr<IHTMLDocument2> pNewDoc;
+ hr = pMC->QueryInterface(IID_IHTMLDocument, (LPVOID*)&pNewDoc);
+ if (SUCCEEDED(hr) && pNewDoc) {
+ CComPtr<IHTMLElementCollection> pColl;
+ pNewDoc->get_all(&pColl);
+
+ CHTMLNode::TDocumentPtr pDoc;
+ pMC->QueryInterface(IID_IHTMLDocument3, (LPVOID*)&pDoc);
+ return THTMLNodePtr(new CHTMLNode(CHTMLNode::TComPtr(pColl), pDoc));
+ }
+ }
+
+ return THTMLNodePtr();
+}
+
+bool CHTMLParserMS::IsInstalled()
+{
+ bool bResult = true;
+ bool bCallUninit = false;
+ try {
+ CheckError(::CoInitialize(nullptr));
+
+ bCallUninit = true;
+
+ CComPtr<IHTMLDocument2> pDoc;
+ _com_util::CheckError(
+ ::CoCreateInstance(CLSID_HTMLDocument,
+ nullptr,
+ 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/CurrencyRates/src/HTMLParserMS.h b/protocols/CurrencyRates/src/HTMLParserMS.h
new file mode 100644
index 0000000000..6b2ceb26d8
--- /dev/null
+++ b/protocols/CurrencyRates/src/HTMLParserMS.h
@@ -0,0 +1,32 @@
+#ifndef __3c99e3f7_ecd9_4d9b_8f86_fe293c5fc8e6_HTMLParserMS_h__
+#define __3c99e3f7_ecd9_4d9b_8f86_fe293c5fc8e6_HTMLParserMS_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 mir_cs 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/CurrencyRates/src/HTTPSession.cpp b/protocols/CurrencyRates/src/HTTPSession.cpp
new file mode 100644
index 0000000000..22c34867c5
--- /dev/null
+++ b/protocols/CurrencyRates/src/HTTPSession.cpp
@@ -0,0 +1,91 @@
+#include "StdAfx.h"
+
+HNETLIBUSER CHTTPSession::g_hNetLib = nullptr;
+
+#define ERROR_MSG LPGENW("This plugin requires a personal key. Press Yes to obtain it at the site and then enter the result in the Options dialog, otherwise this plugin will fail.")
+
+void CALLBACK waitStub()
+{
+ if (IDYES == MessageBox(0, TranslateW(ERROR_MSG), _A2W(CURRENCYRATES_MODULE_NAME), MB_YESNOCANCEL))
+ Utils_OpenUrl("https://free.currencyconverterapi.com/free-api-key");
+}
+
+static 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;
+}
+
+bool CHTTPSession::OpenURL(const tstring &rsURL)
+{
+ std::string s = currencyrates_t2a(rsURL.c_str());
+ m_szUrl = s.c_str();
+ return true;
+}
+
+bool CHTTPSession::ReadResponce(tstring& rsResponce)
+{
+ if (m_szUrl.IsEmpty())
+ return false;
+
+ NETLIBHTTPHEADER headers[] =
+ {
+ { "User-Agent", NETLIB_USER_AGENT },
+ { "Connection", "close" },
+ { "Cache-Control", "no-cache" },
+ { "Pragma", "no-cache" }
+ };
+
+ NETLIBHTTPREQUEST nlhr = {};
+ nlhr.cbSize = sizeof(nlhr);
+ nlhr.requestType = REQUEST_GET;
+ nlhr.flags = NLHRF_DUMPASTEXT | NLHRF_HTTP11 | NLHRF_REDIRECT;
+ nlhr.szUrl = m_szUrl.GetBuffer();
+ nlhr.headersCount = _countof(headers);
+ nlhr.headers = headers;
+
+ bool bResult = false;
+ NETLIBHTTPREQUEST *pReply = nullptr;
+ {
+ mir_cslock lck(m_mx);
+ pReply = Netlib_HttpTransaction(g_hNetLib, &nlhr);
+ }
+
+ if (pReply) {
+ if ((200 == pReply->resultCode) && (pReply->dataLength > 0)) {
+ CMStringA buf(pReply->pData, pReply->dataLength);
+ int nIndex = find_header(pReply, "Content-Type");
+ if ((-1 != nIndex) && (nullptr != strstr(_strlwr(pReply->headers[nIndex].szValue), "utf-8")))
+ rsResponce = ptrW(mir_utf8decodeW(buf));
+ else
+ rsResponce = currencyrates_a2t(buf);
+
+ bResult = true;
+ }
+
+ Netlib_FreeHttpRequest(pReply);
+ }
+ return bResult;
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// module initialization
+
+bool CHTTPSession::Init()
+{
+ assert(nullptr == g_hNetLib);
+
+ ptrA szApiKey(g_plugin.getStringA(DB_KEY_ApiKey));
+ if (szApiKey == nullptr)
+ Miranda_WaitOnHandle(waitStub);
+
+ NETLIBUSER nlu = {};
+ nlu.flags = NUF_OUTGOING | NUF_HTTPCONNS | NUF_NOHTTPSOPTION | NUF_UNICODE;
+ nlu.szSettingsModule = CURRENCYRATES_PROTOCOL_NAME;
+ nlu.szDescriptiveName.w = TranslateT("CurrencyRates HTTP connections");
+ g_hNetLib = Netlib_RegisterUser(&nlu);
+ return (nullptr != g_hNetLib);
+}
diff --git a/protocols/CurrencyRates/src/HTTPSession.h b/protocols/CurrencyRates/src/HTTPSession.h
new file mode 100644
index 0000000000..9928c58304
--- /dev/null
+++ b/protocols/CurrencyRates/src/HTTPSession.h
@@ -0,0 +1,20 @@
+#ifndef __8C9706FF_6B05_4d0d_85B8_5724E5DC0BA4_HTTPSession_h__
+#define __8C9706FF_6B05_4d0d_85B8_5724E5DC0BA4_HTTPSession_h__
+
+class CHTTPSession
+{
+ static HNETLIBUSER g_hNetLib;
+ CMStringA m_szUrl;
+ mir_cs m_mx;
+
+public:
+ CHTTPSession() {}
+ ~CHTTPSession() {}
+
+ static bool Init();
+
+ bool OpenURL(const tstring &rsURL);
+ bool ReadResponce(tstring &rsResponce);
+};
+
+#endif //__8C9706FF_6B05_4d0d_85B8_5724E5DC0BA4_HTTPSession_h__
diff --git a/protocols/CurrencyRates/src/ICurrencyRatesProvider.h b/protocols/CurrencyRates/src/ICurrencyRatesProvider.h
new file mode 100644
index 0000000000..a80cae3088
--- /dev/null
+++ b/protocols/CurrencyRates/src/ICurrencyRatesProvider.h
@@ -0,0 +1,62 @@
+#pragma once
+
+#ifndef __ac71e133_786c_41a7_ab07_625b76ff2a8c_CurrencyRatesProvider_h__
+#define __ac71e133_786c_41a7_ab07_625b76ff2a8c_CurrencyRatesProvider_h__
+
+class CCurrencyRatesProviderVisitor;
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// CFormatSpecificator - array of variables to replace
+
+using CFormatSpecificator = std::pair<tstring, tstring>;
+typedef std::vector<CFormatSpecificator> TFormatSpecificators;
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// ICurrencyRatesProvider - abstract interface
+
+class ICurrencyRatesProvider : private boost::noncopyable
+{
+public:
+ struct CProviderInfo
+ {
+ tstring m_sName;
+ tstring m_sURL;
+ };
+
+public:
+ ICurrencyRatesProvider() {}
+ virtual ~ICurrencyRatesProvider() {}
+
+ virtual bool Init() = 0;
+ virtual const CProviderInfo& GetInfo() const = 0;
+
+ virtual void AddContact(MCONTACT hContact) = 0;
+ virtual void DeleteContact(MCONTACT hContact) = 0;
+ virtual MCONTACT ImportContact(const TiXmlNode*) = 0;
+
+ virtual void ShowPropertyPage(WPARAM wp, OPTIONSDIALOGPAGE& odp) = 0;
+
+ virtual void RefreshAllContacts() = 0;
+ virtual void RefreshSettings() = 0;
+ virtual void RefreshContact(MCONTACT hContact) = 0;
+
+ virtual void FillFormat(TFormatSpecificators&) const = 0;
+ virtual bool ParseSymbol(MCONTACT hContact, wchar_t c, double &d) = 0;
+ virtual tstring FormatSymbol(MCONTACT hContact, wchar_t c, int nWidth = 0) const = 0;
+
+ virtual void Run() = 0;
+};
+
+/////////////////////////////////////////////////////////////////////////////////////////
+
+typedef std::vector<ICurrencyRatesProvider*> TCurrencyRatesProviders;
+extern TCurrencyRatesProviders g_apProviders;
+
+ICurrencyRatesProvider* FindProvider(const tstring& rsName);
+ICurrencyRatesProvider* GetContactProviderPtr(MCONTACT hContact);
+
+void InitProviders();
+void CreateProviders();
+void ClearProviders();
+
+#endif //__ac71e133_786c_41a7_ab07_625b76ff2a8c_CurrencyRatesProvider_h__
diff --git a/protocols/CurrencyRates/src/IHTMLEngine.h b/protocols/CurrencyRates/src/IHTMLEngine.h
new file mode 100644
index 0000000000..6cc9defce7
--- /dev/null
+++ b/protocols/CurrencyRates/src/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/CurrencyRates/src/IHTMLParser.h b/protocols/CurrencyRates/src/IHTMLParser.h
new file mode 100644
index 0000000000..c0b97a7277
--- /dev/null
+++ b/protocols/CurrencyRates/src/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/CurrencyRates/src/IconLib.cpp b/protocols/CurrencyRates/src/IconLib.cpp
new file mode 100644
index 0000000000..da67d1310f
--- /dev/null
+++ b/protocols/CurrencyRates/src/IconLib.cpp
@@ -0,0 +1,40 @@
+#include "StdAfx.h"
+
+static IconItem iconList[] =
+{
+ { LPGEN("Protocol icon"), ICON_STR_MAIN, IDI_ICON_MAIN },
+ { LPGEN("Auto Update Disabled"), "auto_update_disabled", IDI_ICON_DISABLED },
+ { LPGEN("Currency Rate up"), "currencyrate_up", IDI_ICON_UP },
+ { LPGEN("Currency Rate down"), "currencyrate_down", IDI_ICON_DOWN },
+ { LPGEN("Currency Rate not changed"), "currencyrate_not_changed", IDI_ICON_NOTCHANGED },
+ { LPGEN("Currency Rate Section"), "currencyrate_section", IDI_ICON_SECTION },
+ { LPGEN("Currency Rate"), ICON_STR_CURRENCYRATE, IDI_ICON_CURRENCYRATE },
+ { LPGEN("Currency Converter"), "currency_converter", IDI_ICON_CURRENCY_CONVERTER },
+ { LPGEN("Refresh"), "refresh", IDI_ICON_REFRESH },
+ { LPGEN("Export"), "export", IDI_ICON_EXPORT },
+ { LPGEN("Swap button"), "swap", IDI_ICON_SWAP },
+ { LPGEN("Import"), "import", IDI_ICON_IMPORT }
+};
+
+void CurrencyRates_IconsInit()
+{
+ ::g_plugin.registerIcon(CURRENCYRATES_PROTOCOL_NAME, iconList, CURRENCYRATES_PROTOCOL_NAME);
+}
+
+HICON CurrencyRates_LoadIconEx(int iconId, bool bBig /*= false*/)
+{
+ for (int i = 0; i < _countof(iconList); i++)
+ if (iconList[i].defIconID == iconId)
+ return IcoLib_GetIconByHandle(iconList[i].hIcolib, bBig);
+
+ return nullptr;
+}
+
+HANDLE CurrencyRates_GetIconHandle(int iconId)
+{
+ for (int i = 0; i < _countof(iconList); i++)
+ if (iconList[i].defIconID == iconId)
+ return iconList[i].hIcolib;
+
+ return nullptr;
+}
diff --git a/protocols/CurrencyRates/src/IconLib.h b/protocols/CurrencyRates/src/IconLib.h
new file mode 100644
index 0000000000..4e0146fba8
--- /dev/null
+++ b/protocols/CurrencyRates/src/IconLib.h
@@ -0,0 +1,11 @@
+#ifndef __8821d334_afac_439e_9a81_76318e1ac4ef_IconLib_h__
+#define __8821d334_afac_439e_9a81_76318e1ac4ef_IconLib_h__
+
+#define ICON_STR_MAIN "main"
+#define ICON_STR_CURRENCYRATE "currencyrate"
+
+void CurrencyRates_IconsInit();
+HICON CurrencyRates_LoadIconEx(int iconId, bool bBig = false);
+HANDLE CurrencyRates_GetIconHandle(int iconId);
+
+#endif //__8821d334_afac_439e_9a81_76318e1ac4ef_IconLib_h__
diff --git a/protocols/CurrencyRates/src/ImportExport.cpp b/protocols/CurrencyRates/src/ImportExport.cpp
new file mode 100644
index 0000000000..95fb9d95f7
--- /dev/null
+++ b/protocols/CurrencyRates/src/ImportExport.cpp
@@ -0,0 +1,507 @@
+#include "StdAfx.h"
+
+const char g_szXmlValue[] = "Value";
+const char g_szXmlName[] = "Name";
+const char g_szXmlSetting[] = "Setting";
+const char g_szXmlModule[] = "Module";
+const char g_szXmlContact[] = "Contact";
+const char g_szXmlContacts[] = "Contacts";
+const char g_szXmlType[] = "type";
+const char g_szXmlTypeByte[] = "byte";
+const char g_szXmlTypeWord[] = "word";
+const char g_szXmlTypeDword[] = "dword";
+const char g_szXmlTypeAsciiz[] = "asciiz";
+const char g_szXmlTypeWchar[] = "wchar";
+const char g_szXmlTypeUtf8[] = "utf8";
+const char g_szXmlTypeBlob[] = "blob";
+
+struct CEnumContext
+{
+ CEnumContext(TiXmlDocument &doc) :
+ m_xmlDoc(doc)
+ {}
+
+ TiXmlDocument &m_xmlDoc;
+ TiXmlNode *m_pNode;
+ MCONTACT m_hContact;
+ LPCSTR m_pszModule;
+};
+
+struct mir_safety_dbvar
+{
+ mir_safety_dbvar(DBVARIANT* p) : m_p(p) {}
+ ~mir_safety_dbvar() { db_free(m_p); }
+ DBVARIANT* m_p;
+};
+
+static int enum_contact_settings(const char *szSetting, void *lp)
+{
+ CEnumContext *ctx = reinterpret_cast<CEnumContext*>(lp);
+
+ DBVARIANT dbv;
+ if (0 == db_get(ctx->m_hContact, ctx->m_pszModule, szSetting, &dbv)) {
+ mir_safety_dbvar sdbvar(&dbv);
+
+ std::string sType;
+ std::wostringstream sValue;
+ sValue.imbue(GetSystemLocale());
+
+ switch (dbv.type) {
+ case DBVT_BYTE:
+ sValue << dbv.bVal;
+ sType = g_szXmlTypeByte;
+ break;
+ case DBVT_WORD:
+ sValue << dbv.wVal;
+ sType = g_szXmlTypeWord;
+ break;
+ case DBVT_DWORD:
+ sValue << dbv.dVal;
+ sType = g_szXmlTypeDword;
+ break;
+ case DBVT_ASCIIZ:
+ sType = g_szXmlTypeAsciiz;
+ if (dbv.pszVal)
+ sValue << dbv.pszVal;
+ break;
+ case DBVT_WCHAR:
+ sType = g_szXmlTypeWchar;
+ if (dbv.pwszVal)
+ sValue << dbv.pwszVal;
+ break;
+ case DBVT_UTF8:
+ sType = g_szXmlTypeUtf8;
+ if (dbv.pszVal)
+ sValue << dbv.pszVal;
+ break;
+ case DBVT_BLOB:
+ sType = g_szXmlTypeBlob;
+ if (dbv.pbVal) {
+ ptrA buf(mir_base64_encode(dbv.pbVal, dbv.cpbVal));
+ if (buf)
+ sValue << buf;
+ }
+ break;
+ }
+
+ auto *pXmlName = ctx->m_xmlDoc.NewElement(g_szXmlName);
+ pXmlName->SetText(szSetting);
+
+ auto *pXmlValue = ctx->m_xmlDoc.NewElement(g_szXmlValue);
+ pXmlValue->SetText(T2Utf(sValue.str().c_str()).get());
+ pXmlValue->SetAttribute(g_szXmlType, sType.c_str());
+
+ auto *pXmlSet = ctx->m_xmlDoc.NewElement(g_szXmlSetting);
+ pXmlSet->InsertEndChild(pXmlName);
+ pXmlSet->InsertEndChild(pXmlValue);
+ ctx->m_pNode->InsertEndChild(pXmlSet);
+ }
+
+ return 0;
+}
+
+int EnumDbModules(const char *szModuleName, void *lp)
+{
+ CEnumContext *ctx = (CEnumContext*)lp;
+ auto *pXml = ctx->m_pNode;
+ auto *pModule = ctx->m_xmlDoc.NewElement(g_szXmlModule);
+ pModule->SetText(szModuleName);
+
+ ctx->m_pszModule = szModuleName;
+ ctx->m_pNode = pModule;
+ db_enum_settings(ctx->m_hContact, &enum_contact_settings, szModuleName, ctx);
+
+ if (pModule->FirstChildElement(g_szXmlSetting))
+ pXml->InsertEndChild(pModule);
+
+ ctx->m_pNode = pXml;
+ return 0;
+}
+
+TiXmlNode* export_contact(MCONTACT hContact, TiXmlDocument &pDoc)
+{
+ CEnumContext ctx(pDoc);
+ ctx.m_pNode = pDoc.NewElement(g_szXmlContact);
+ ctx.m_hContact = hContact;
+ db_enum_modules(EnumDbModules, &ctx);
+
+ return ctx.m_pNode;
+}
+
+LPCTSTR prepare_filter(LPTSTR pszBuffer, size_t cBuffer)
+{
+ LPTSTR p = pszBuffer;
+ LPCTSTR pszXml = TranslateT("XML File (*.xml)");
+ mir_wstrncpy(p, pszXml, (int)cBuffer);
+ size_t nLen = mir_wstrlen(pszXml) + 1;
+ p += nLen;
+ if (nLen < cBuffer) {
+ mir_wstrncpy(p, L"*.xml", (int)(cBuffer - nLen));
+ p += 6;
+ nLen += 6;
+ }
+
+ if (nLen < cBuffer) {
+ LPCTSTR pszAll = TranslateT("All files (*.*)");
+ mir_wstrncpy(p, pszAll, (int)(cBuffer - nLen));
+ size_t n = mir_wstrlen(pszAll) + 1;
+ nLen += n;
+ p += n;
+ }
+
+ if (nLen < cBuffer) {
+ mir_wstrncpy(p, L"*.*", (int)(cBuffer - nLen));
+ p += 4;
+ nLen += 4;
+ }
+
+ if (nLen < cBuffer)
+ *p = '\0';
+
+ return pszBuffer;
+}
+
+bool show_open_file_dialog(bool bOpen, tstring& rsFile)
+{
+ wchar_t szBuffer[MAX_PATH];
+ wchar_t szFilter[MAX_PATH];
+ OPENFILENAME ofn;
+ memset(&ofn, 0, sizeof(ofn));
+
+ ofn.lStructSize = sizeof(OPENFILENAME);
+
+ ofn.hwndOwner = nullptr;
+ ofn.lpstrFilter = prepare_filter(szFilter, MAX_PATH);
+ ofn.Flags = OFN_PATHMUSTEXIST | OFN_HIDEREADONLY | OFN_EXPLORER;
+ ofn.lpstrDefExt = L"xml";
+ if (bOpen)
+ ofn.Flags |= OFN_FILEMUSTEXIST;
+ else
+ ofn.Flags |= OFN_OVERWRITEPROMPT;
+
+ ofn.nMaxFile = MAX_PATH;
+ ofn.lpstrFile = szBuffer;
+ ofn.lpstrFile[0] = '\0';
+
+ if (bOpen) {
+ if (FALSE == GetOpenFileName(&ofn))
+ return false;
+ }
+ else {
+ if (FALSE == GetSaveFileName(&ofn))
+ return false;
+ }
+
+ rsFile = szBuffer;
+ return true;
+}
+
+INT_PTR CurrencyRates_Export(WPARAM wp, LPARAM lp)
+{
+ tstring sFileName;
+ const char* pszFile = reinterpret_cast<const char*>(lp);
+ if (nullptr == pszFile) {
+ if (false == show_open_file_dialog(false, sFileName))
+ return -1;
+ }
+ else sFileName = currencyrates_a2t(pszFile);
+
+ TiXmlDocument doc;
+ auto *pRoot = doc.NewElement(g_szXmlContacts);
+ doc.InsertFirstChild(pRoot);
+
+ MCONTACT hContact = MCONTACT(wp);
+ if (hContact) {
+ auto pProvider = GetContactProviderPtr(hContact);
+ if (pProvider) {
+ auto *pNode = export_contact(hContact, doc);
+ if (pNode)
+ pRoot->InsertEndChild(pNode);
+ }
+ }
+ else {
+ for (auto &cc : Contacts(CURRENCYRATES_MODULE_NAME)) {
+ auto pProvider = GetContactProviderPtr(cc);
+ if (pProvider) {
+ auto *pNode = export_contact(cc, doc);
+ if (pNode)
+ pRoot->InsertEndChild(pNode);
+ }
+ }
+ }
+
+ return doc.SaveFile(_T2A(sFileName.c_str()), true);
+}
+
+bool set_contact_settings(MCONTACT hContact, DBCONTACTWRITESETTING& dbs)
+{
+ assert(DBVT_DELETED != dbs.value.type);
+ return (0 == db_set(hContact, dbs.szModule, dbs.szSetting, &dbs.value));
+}
+
+bool handle_module(MCONTACT hContact, const TiXmlElement *pXmlModule)
+{
+ const char *szModuleName = pXmlModule->GetText();
+ if (szModuleName == nullptr)
+ return false;
+
+ size_t cCreatedRecords = 0;
+ bool bCListModule = !mir_strcmpi(szModuleName, "CList");
+
+ DBCONTACTWRITESETTING dbs;
+ dbs.szModule = szModuleName;
+ for (auto *pSetting : TiXmlFilter(pXmlModule, g_szXmlSetting)) {
+ auto *pNode = pSetting->FirstChildElement(g_szXmlName);
+ if (pNode == nullptr)
+ continue;
+ const char *sName = pNode->GetText();
+
+ pNode = pSetting->FirstChildElement(g_szXmlValue);
+ if (pNode == nullptr)
+ continue;
+ const char *sValue = pNode->GetText();
+ const char *sType = pNode->Attribute(g_szXmlType);
+
+ if (sName == nullptr || sType == nullptr || sValue == nullptr)
+ continue;
+
+ dbs.szSetting = sName;
+ if (!mir_strcmpi(g_szXmlTypeByte, sType)) {
+ std::istringstream in(sValue);
+ 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 (!mir_strcmpi(g_szXmlTypeWord, sType)) {
+ std::istringstream in(sValue);
+ 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 (!mir_strcmpi(g_szXmlTypeDword, sType)) {
+ std::istringstream in(sValue);
+ 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 (!mir_strcmpi(g_szXmlTypeAsciiz, sType)) {
+ dbs.value.pszVal = (char*)sValue;
+ dbs.value.type = DBVT_ASCIIZ;
+ if (set_contact_settings(hContact, dbs))
+ ++cCreatedRecords;
+ }
+ else if (!mir_strcmpi(g_szXmlTypeUtf8, sType)) {
+ dbs.value.pszVal = (char*)sValue;
+ dbs.value.type = DBVT_UTF8;
+ if (set_contact_settings(hContact, dbs))
+ ++cCreatedRecords;
+ }
+ else if (!mir_strcmpi(g_szXmlTypeWchar, sType)) {
+ Utf2T val(sValue);
+ dbs.value.pwszVal = val;
+ dbs.value.type = DBVT_WCHAR;
+ if (set_contact_settings(hContact, dbs))
+ ++cCreatedRecords;
+ }
+ else if (!mir_strcmpi(g_szXmlTypeBlob, sType)) {
+ size_t bufLen;
+ mir_ptr<BYTE> buf((PBYTE)mir_base64_decode(sValue, &bufLen));
+ if (buf) {
+ dbs.value.pbVal = buf;
+ dbs.value.cpbVal = (WORD)bufLen;
+ dbs.value.type = DBVT_BLOB;
+
+ if (set_contact_settings(hContact, dbs))
+ ++cCreatedRecords;
+ }
+ }
+
+ if (bCListModule && !mir_strcmpi(sName, "Group"))
+ Clist_GroupCreate(NULL, Utf2T(sValue));
+ }
+
+ return true;
+}
+
+size_t count_contacts(const TiXmlNode *pXmlRoot, bool bInContactsGroup)
+{
+ size_t cContacts = 0;
+
+ for (auto *pNode : TiXmlEnum(pXmlRoot)) {
+ const char *sName = pNode->Name();
+ if (false == bInContactsGroup) {
+ if (!mir_strcmpi(g_szXmlContacts, sName))
+ cContacts += count_contacts(pNode, true);
+ else
+ cContacts += count_contacts(pNode, false);
+ }
+ else {
+ if (!mir_strcmpi(g_szXmlContact, sName))
+ ++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) {}
+ MCONTACT m_hContact;
+ ICurrencyRatesProvider *m_pProvider;
+ bool m_bNewContact;
+};
+
+const TiXmlNode* find_currencyrates_module(const TiXmlNode *pXmlContact)
+{
+ for (auto *pNode : TiXmlEnum(pXmlContact))
+ if ((!mir_strcmpi(g_szXmlModule, pNode->Name())) && (!mir_strcmpi(CURRENCYRATES_MODULE_NAME, pNode->GetText())))
+ return pNode;
+
+ return nullptr;
+}
+
+TNameValue parse_setting_node(const TiXmlNode *pXmlSetting)
+{
+ assert(pXmlSetting);
+
+ const char *sName, *sValue;
+ for (auto *pNode : TiXmlEnum(pXmlSetting)) {
+ if (!mir_strcmpi(g_szXmlName, pNode->Name()))
+ sName = pNode->GetText();
+ else if (!mir_strcmpi(g_szXmlValue, pNode->Name()))
+ sValue = pNode->GetText();
+ }
+
+ return std::make_pair(sName, sValue);
+}
+
+ICurrencyRatesProvider* find_provider(const TiXmlNode *pXmlCurrencyRatesModule)
+{
+ for (auto *pNode : TiXmlFilter(pXmlCurrencyRatesModule, g_szXmlSetting)) {
+ TNameValue Item = parse_setting_node(pNode);
+ if ((!mir_strcmpi(DB_STR_CURRENCYRATE_PROVIDER, Item.first)) && Item.second)
+ return FindProvider(Utf2T(Item.second).get());
+ }
+
+ return nullptr;
+}
+
+bool get_contact_state(const TiXmlNode *pXmlContact, CContactState& cst)
+{
+ auto *pXmlCurrencyRates = find_currencyrates_module(pXmlContact);
+ if (!pXmlCurrencyRates)
+ return false;
+
+ cst.m_pProvider = find_provider(pXmlCurrencyRates);
+ if (!cst.m_pProvider)
+ return false;
+
+ cst.m_hContact = cst.m_pProvider->ImportContact(pXmlCurrencyRates);
+ return true;
+}
+
+bool import_contact(const TiXmlNode *pXmlContact, CImportContext &impctx)
+{
+ ++impctx.m_cHandledContacts;
+
+ CContactState cst;
+ if (!get_contact_state(pXmlContact, cst))
+ return false;
+
+ if (NULL == cst.m_hContact) {
+ cst.m_hContact = db_add_contact();
+ cst.m_bNewContact = true;
+ }
+ else if (impctx.m_nFlags & CURRENCYRATES_IMPORT_SKIP_EXISTING_CONTACTS)
+ return true;
+
+ if (!cst.m_hContact)
+ return false;
+
+ for (auto *pNode : TiXmlFilter(pXmlContact, g_szXmlModule))
+ if (!handle_module(cst.m_hContact, pNode))
+ return false;
+
+ if (cst.m_bNewContact) {
+ cst.m_pProvider->AddContact(cst.m_hContact);
+ cst.m_pProvider->RefreshContact(cst.m_hContact);
+ }
+ return true;
+}
+
+size_t import_contacts(const TiXmlNode *pXmlContacts, CImportContext &impctx)
+{
+ size_t cContacts = 0;
+ for (auto *pNode : TiXmlFilter(pXmlContacts, g_szXmlContact))
+ if (import_contact(pNode, impctx))
+ ++cContacts;
+
+ return cContacts;
+}
+
+size_t handle_contacts_node(const TiXmlNode *pXmlRoot, CImportContext& impctx)
+{
+ size_t cContacts = 0;
+ for (auto *pNode : TiXmlEnum(pXmlRoot)) {
+ if (!mir_strcmpi(g_szXmlContacts, pNode->Name()))
+ cContacts += import_contacts(pNode, impctx);
+ else
+ cContacts += handle_contacts_node(pNode, impctx);
+ }
+
+ return cContacts;
+}
+
+bool do_import(const TiXmlNode *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 CurrencyRates_Import(WPARAM wp, LPARAM lp)
+{
+ tstring sFileName;
+ const char* pszFile = reinterpret_cast<const char*>(lp);
+ if (nullptr == pszFile) {
+ if (false == show_open_file_dialog(true, sFileName))
+ return -1;
+ }
+ else sFileName = currencyrates_a2t(pszFile);
+
+ FILE *in = _wfopen(sFileName.c_str(), L"rb");
+ if (in == nullptr)
+ return 1;
+
+ TiXmlDocument doc;
+ int res = doc.LoadFile(in);
+ fclose(in);
+ if (res)
+ return 1;
+
+ return (do_import(&doc, wp) ? 0 : 1);
+}
diff --git a/protocols/CurrencyRates/src/ImportExport.h b/protocols/CurrencyRates/src/ImportExport.h
new file mode 100644
index 0000000000..b07bc4c4c3
--- /dev/null
+++ b/protocols/CurrencyRates/src/ImportExport.h
@@ -0,0 +1,10 @@
+#ifndef __F86374E6_713C_4600_85FB_903A5CDF7251_IMPORT_EXPORT_H__
+#define __F86374E6_713C_4600_85FB_903A5CDF7251_IMPORT_EXPORT_H__
+
+INT_PTR CurrencyRates_Export(WPARAM wp, LPARAM lp);
+INT_PTR CurrencyRates_Import(WPARAM wp, LPARAM lp);
+
+using TNameValue = std::pair<const char*, const char*> ; // first is name,second is value
+TNameValue parse_setting_node(const TiXmlNode *pXmlSetting);
+
+#endif //__F86374E6_713C_4600_85FB_903A5CDF7251_IMPORT_EXPORT_H__
diff --git a/protocols/CurrencyRates/src/IsWithinAccuracy.h b/protocols/CurrencyRates/src/IsWithinAccuracy.h
new file mode 100644
index 0000000000..558dbb87d3
--- /dev/null
+++ b/protocols/CurrencyRates/src/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/CurrencyRates/src/Locale.cpp b/protocols/CurrencyRates/src/Locale.cpp
new file mode 100644
index 0000000000..501015eb21
--- /dev/null
+++ b/protocols/CurrencyRates/src/Locale.cpp
@@ -0,0 +1,59 @@
+#include "StdAfx.h"
+
+const std::locale GetSystemLocale()
+{
+ return std::locale("");
+}
+
+tstring get_int_registry_value(LPCTSTR pszValueName)
+{
+ tstring sResult;
+ HKEY hKey = nullptr;
+ LONG lResult = ::RegOpenKeyEx(HKEY_CURRENT_USER,
+ L"Control Panel\\International", 0, KEY_QUERY_VALUE, &hKey);
+ if ((ERROR_SUCCESS == lResult) && (nullptr != 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<wchar_t> 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 (nullptr != hKey) {
+ lResult = ::RegCloseKey(hKey);
+ assert(ERROR_SUCCESS == lResult);
+ }
+
+ return sResult;
+}
+
+LPCTSTR date_win_2_boost(const tstring& sFrmt)
+{
+ if (sFrmt == L"dd/MM/yy")
+ return L"%d/%m/%y";
+ if (sFrmt == L"yyyy-MM-dd")
+ return L"%y-%m-%d";
+ return L"%d.%m.%y";
+}
+
+LPCTSTR time_win_2_boost(const tstring& sFrmt)
+{
+ if (sFrmt == L"H:mm" || sFrmt == L"HH:mm")
+ return L"%H:%M";
+
+ return L"%H:%M:%S";
+}
+
+LPCTSTR CurrencyRates_GetDateFormat(bool bShort)
+{
+ return date_win_2_boost(get_int_registry_value(bShort ? L"sShortDate" : L"sLongDate"));
+}
+
+LPCTSTR CurrencyRates_GetTimeFormat(bool bShort)
+{
+ return time_win_2_boost(get_int_registry_value(bShort ? L"sShortTime" : L"sTimeFormat"));
+}
diff --git a/protocols/CurrencyRates/src/Locale.h b/protocols/CurrencyRates/src/Locale.h
new file mode 100644
index 0000000000..2ef5e320cb
--- /dev/null
+++ b/protocols/CurrencyRates/src/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();
+LPCTSTR CurrencyRates_GetDateFormat(bool bShort);
+LPCTSTR CurrencyRates_GetTimeFormat(bool bShort);
+
+#endif //__11f7afd0_5a66_4029_8bf3_e3c66346b349_Locale_h_
diff --git a/protocols/CurrencyRates/src/Log.cpp b/protocols/CurrencyRates/src/Log.cpp
new file mode 100644
index 0000000000..c769f1a98d
--- /dev/null
+++ b/protocols/CurrencyRates/src/Log.cpp
@@ -0,0 +1,41 @@
+#include "StdAfx.h"
+
+namespace
+{
+ mir_cs g_Mutex;
+
+ tstring get_log_file_name()
+ {
+ return CreateFilePath(L"CurrencyRates.log");
+ }
+
+ bool is_log_enabled()
+ {
+#ifdef _DEBUG
+ return true;
+#else
+ return (1 == db_get_b(0, CURRENCYRATES_MODULE_NAME, DB_STR_ENABLE_LOG, false));
+#endif
+ }
+
+ void do_log(const tstring& rsFileName, const tstring& rsMsg)
+ {
+ mir_cslock lck(g_Mutex);
+ tofstream file(rsFileName.c_str(), std::ios::ate | std::ios::app);
+ if (file.good())
+ {
+ wchar_t szTime[20];
+ _tstrtime_s(szTime);
+ file << szTime << L" ================================>\n" << rsMsg << L"\n\n";
+ }
+ }
+}
+
+void LogIt(const tstring& rsMsg)
+{
+ if (is_log_enabled())
+ {
+ tstring sFileName = get_log_file_name();
+ do_log(sFileName, rsMsg);
+ }
+}
diff --git a/protocols/CurrencyRates/src/Log.h b/protocols/CurrencyRates/src/Log.h
new file mode 100644
index 0000000000..b62ae9ac52
--- /dev/null
+++ b/protocols/CurrencyRates/src/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(const tstring& rsMsg);
+
+#endif //__653719be_16d6_4058_8555_8aa7d5404214_OutputDlg_h__
diff --git a/protocols/CurrencyRates/src/ModuleInfo.cpp b/protocols/CurrencyRates/src/ModuleInfo.cpp
new file mode 100644
index 0000000000..172f2ba884
--- /dev/null
+++ b/protocols/CurrencyRates/src/ModuleInfo.cpp
@@ -0,0 +1,64 @@
+#include "StdAfx.h"
+
+static CModuleInfo mi;
+static CModuleInfo::THTMLEnginePtr g_pHTMLEngine;
+static mir_cs g_lmParsers;
+
+typedef std::map<std::string, MWindowList> THandles;
+static THandles g_ahWindowLists;
+
+MWindowList CModuleInfo::GetWindowList(const std::string& rsKey, bool bAllocateIfNonExist /*= true*/)
+{
+ MWindowList hResult = nullptr;
+ THandles::const_iterator i = g_ahWindowLists.find(rsKey);
+ if (i != g_ahWindowLists.end()) {
+ hResult = i->second;
+ }
+ else if (bAllocateIfNonExist) {
+ hResult = WindowList_Create();
+ if (hResult)
+ g_ahWindowLists.insert(std::make_pair(rsKey, hResult));
+ }
+
+ return hResult;
+}
+
+void CModuleInfo::OnMirandaShutdown()
+{
+ for (auto &p : g_ahWindowLists)
+ WindowList_Broadcast(p.second, WM_CLOSE, 0, 0);
+}
+
+CModuleInfo::THTMLEnginePtr CModuleInfo::GetHTMLEngine()
+{
+ if (!g_pHTMLEngine) {
+ mir_cslock lck(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 (!g_pHTMLEngine && (false == CHTMLParserMS::IsInstalled())) {
+ CurrencyRates_MessageBox(nullptr,
+ TranslateT("Miranda could not load CurrencyRates plugin. Microsoft HTML parser is missing."),
+ MB_YESNO | MB_ICONQUESTION);
+ return false;
+ }
+
+ return true;
+}
diff --git a/protocols/CurrencyRates/src/ModuleInfo.h b/protocols/CurrencyRates/src/ModuleInfo.h
new file mode 100644
index 0000000000..39399f5c43
--- /dev/null
+++ b/protocols/CurrencyRates/src/ModuleInfo.h
@@ -0,0 +1,23 @@
+#ifndef __d0f22b66_3135_4bbe_bee5_a31ea631ce58_ModuleInfo__
+#define __d0f22b66_3135_4bbe_bee5_a31ea631ce58_ModuleInfo__
+
+class CCurrencyRatesProviders;
+class IHTMLEngine;
+
+class CModuleInfo
+{
+public:
+ typedef boost::shared_ptr<CCurrencyRatesProviders> TCurrencyRatesProvidersPtr;
+ typedef boost::shared_ptr<IHTMLEngine> THTMLEnginePtr;
+
+public:
+ static void OnMirandaShutdown(void);
+ static MWindowList GetWindowList(const std::string& rsKey, bool bAllocateIfNonExist = true);
+
+ static bool Verify();
+
+ static THTMLEnginePtr GetHTMLEngine();
+ static void SetHTMLEngine(THTMLEnginePtr pEngine);
+};
+
+#endif //__d0f22b66_3135_4bbe_bee5_a31ea631ce58_ModuleInfo__
diff --git a/protocols/CurrencyRates/src/SettingsDlg.cpp b/protocols/CurrencyRates/src/SettingsDlg.cpp
new file mode 100644
index 0000000000..0d919d76a0
--- /dev/null
+++ b/protocols/CurrencyRates/src/SettingsDlg.cpp
@@ -0,0 +1,971 @@
+#include "StdAfx.h"
+
+#define WINDOW_PREFIX_SETTINGS "Edit Settings_"
+
+const wchar_t g_pszVariableCurrencyRateName[] = L"%currencyratename%";
+const wchar_t g_pszVariableUserProfile[] = L"%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_ADDPOPUPW);
+ ::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_ADDPOPUPW);
+ 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<wchar_t> get_filter()
+{
+ std::vector<wchar_t> aFilter;
+ LPCTSTR pszFilterParts[] = { LPGENW("Log Files (*.txt,*.log)"), L"*.txt;*.log", LPGENW("All files (*.*)"), L"*.*" };
+ for (int i = 0; i < sizeof(pszFilterParts) / sizeof(pszFilterParts[0]); ++i) {
+ tstring sPart = TranslateW(pszFilterParts[i]);
+ std::copy(sPart.begin(), sPart.end(), std::back_inserter(aFilter));
+ aFilter.push_back('\0');
+
+ }
+ aFilter.push_back('\0');
+ return aFilter;
+}
+void select_log_file(HWND hDlg)
+{
+ std::vector<wchar_t> aFileBuffer(_MAX_PATH * 2, '\0');
+ LPTSTR pszFile = &*aFileBuffer.begin();
+
+ std::vector<wchar_t> 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 = g_plugin.getInst();
+ ofn.lpstrDefExt = L"log";
+ 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(MCONTACT hContact) : m_hContact(hContact), m_pPopupSettings(nullptr) {}
+ ~CSettingWindowParam() { delete m_pPopupSettings; }
+
+ MCONTACT m_hContact;
+ CPopupSettings* m_pPopupSettings;
+};
+
+inline CSettingWindowParam* get_param(HWND hWnd)
+{
+ return reinterpret_cast<CSettingWindowParam*>(GetWindowLongPtr(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_SETCOLOUR, 0, pSettings->GetColourBk());
+ ::SendDlgItemMessage(hWnd, IDC_TEXTCOLOR, CPM_SETCOLOUR, 0, pSettings->GetColourText());
+
+ ::CheckDlgButton(hWnd, IDC_CHECK_DONT_USE_POPUPHISTORY, pSettings->GetHistoryFlag() ? BST_CHECKED : BST_UNCHECKED);
+
+ ::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));
+ CurrencyRates_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:
+ TranslateDialogDefault(hWnd);
+ {
+ MCONTACT hContact = MCONTACT(lp);
+
+ MWindowList hWL = CModuleInfo::GetWindowList(WINDOW_PREFIX_SETTINGS, false);
+ assert(hWL);
+ WindowList_Add(hWL, hWnd, hContact);
+
+ tstring sName = GetContactName(hContact);
+ ::SetDlgItemText(hWnd, IDC_EDIT_NAME, sName.c_str());
+
+ BYTE bUseContactSpecific = db_get_b(hContact, CURRENCYRATES_MODULE_NAME, DB_STR_CONTACT_SPEC_SETTINGS, 0);
+ ::CheckDlgButton(hWnd, IDC_CHECK_CONTACT_SPECIFIC, bUseContactSpecific ? BST_CHECKED : BST_UNCHECKED);
+
+ auto pProvider = GetContactProviderPtr(hContact);
+ CAdvProviderSettings setGlobal(pProvider);
+ // log to history
+ WORD dwLogMode = db_get_w(hContact, CURRENCYRATES_MODULE_NAME, DB_STR_CURRENCYRATE_LOG, setGlobal.GetLogMode());
+ UINT nCheck = (dwLogMode&lmInternalHistory) ? 1 : 0;
+ ::CheckDlgButton(hWnd, IDC_CHECK_INTERNAL_HISTORY, nCheck ? BST_CHECKED : BST_UNCHECKED);
+
+ tstring sHistoryFrmt = CurrencyRates_DBGetStringW(hContact, CURRENCYRATES_MODULE_NAME, DB_STR_CURRENCYRATE_FORMAT_HISTORY, setGlobal.GetHistoryFormat().c_str());
+ ::SetDlgItemText(hWnd, IDC_EDIT_HISTORY_FORMAT, sHistoryFrmt.c_str());
+
+ WORD wOnlyIfChanged = db_get_w(hContact, CURRENCYRATES_MODULE_NAME, DB_STR_CURRENCYRATE_HISTORY_CONDITION, setGlobal.GetHistoryOnlyChangedFlag());
+ ::CheckDlgButton(hWnd, IDC_CHECK_HISTORY_CONDITION, (1 == wOnlyIfChanged) ? BST_CHECKED : BST_UNCHECKED);
+
+ // log to file
+ nCheck = (dwLogMode&lmExternalFile) ? 1 : 0;
+ ::CheckDlgButton(hWnd, IDC_CHECK_EXTERNAL_FILE, nCheck ? BST_CHECKED : BST_UNCHECKED);
+
+ tstring sLogFileName = CurrencyRates_DBGetStringW(hContact, CURRENCYRATES_MODULE_NAME, DB_STR_CURRENCYRATE_LOG_FILE);
+ if (true == sLogFileName.empty()) {
+ sLogFileName = GenerateLogFileName(setGlobal.GetLogFileName(), CurrencyRates_DBGetStringW(hContact, CURRENCYRATES_MODULE_NAME, DB_STR_CURRENCYRATE_SYMBOL), glfnResolveCurrencyRateName);
+ }
+ ::SetDlgItemText(hWnd, IDC_EDIT_FILE_NAME, sLogFileName.c_str());
+
+ tstring sLogFileFrmt = CurrencyRates_DBGetStringW(hContact, CURRENCYRATES_MODULE_NAME, DB_STR_CURRENCYRATE_FORMAT_LOG_FILE, setGlobal.GetLogFormat().c_str());
+ ::SetDlgItemText(hWnd, IDC_EDIT_LOG_FILE_FORMAT, sLogFileFrmt.c_str());
+
+ wOnlyIfChanged = db_get_w(hContact, CURRENCYRATES_MODULE_NAME, DB_STR_CURRENCYRATE_LOG_FILE_CONDITION, setGlobal.GetLogOnlyChangedFlag());
+ ::CheckDlgButton(hWnd, IDC_CHECK_LOG_FILE_CONDITION, (1 == wOnlyIfChanged) ? BST_CHECKED : BST_UNCHECKED);
+
+ // popup
+ nCheck = (dwLogMode&lmPopup) ? 1 : 0;
+ ::CheckDlgButton(hWnd, IDC_CHECK_SHOW_POPUP, nCheck ? BST_CHECKED : BST_UNCHECKED);
+ tstring sPopupFrmt = CurrencyRates_DBGetStringW(hContact, CURRENCYRATES_MODULE_NAME, DB_STR_CURRENCYRATE_FORMAT_POPUP, setGlobal.GetPopupFormat().c_str());
+ ::SetDlgItemText(hWnd, IDC_EDIT_POPUP_FORMAT, sPopupFrmt.c_str());
+ bool bOnlyIfChanged = 1 == db_get_b(hContact, CURRENCYRATES_MODULE_NAME, DB_STR_CURRENCYRATE_POPUP_CONDITION, setGlobal.GetShowPopupIfValueChangedFlag());
+ ::CheckDlgButton(hWnd, IDC_CHECK_SHOW_POPUP_ONLY_VALUE_CHANGED, (bOnlyIfChanged) ? BST_CHECKED : BST_UNCHECKED);
+
+ update_all_controls(hWnd);
+
+ CSettingWindowParam* pParam = new CSettingWindowParam(hContact);
+ ::SetWindowLongPtr(hWnd, GWLP_USERDATA, reinterpret_cast<LONG_PTR>(pParam));
+ Utils_RestoreWindowPositionNoSize(hWnd, hContact, CURRENCYRATES_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))
+ show_variable_list(hWnd, GetContactProviderPtr(get_param(hWnd)->m_hContact));
+ 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) {
+ pParam->m_pPopupSettings = new CPopupSettings();
+ pParam->m_pPopupSettings->InitForContact(pParam->m_hContact);
+ }
+
+ DialogBoxParam(g_plugin.getInst(),
+ MAKEINTRESOURCE(IDD_DIALOG_POPUP),
+ hWnd,
+ EditPopupSettingsDlgProc, reinterpret_cast<LPARAM>(pParam->m_pPopupSettings));
+ }
+ break;
+
+ case IDOK:
+ {
+ CSettingWindowParam* pParam = get_param(hWnd);
+ MCONTACT 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);
+ CurrencyRates_MessageBox(hWnd, TranslateT("Enter log file name."), MB_OK | MB_ICONERROR);
+ bOk = false;
+ }
+ else if (true == sLogFileFormat.empty()) {
+ prepare_edit_ctrl_for_error(hwndLogFileFrmt);
+ CurrencyRates_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);
+ CurrencyRates_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);
+ CurrencyRates_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));
+
+ db_set_b(hContact, CURRENCYRATES_MODULE_NAME, DB_STR_CONTACT_SPEC_SETTINGS, bUseContactSpec);
+ db_set_w(hContact, CURRENCYRATES_MODULE_NAME, DB_STR_CURRENCYRATE_LOG, nLogMode);
+ db_set_w(hContact, CURRENCYRATES_MODULE_NAME, DB_STR_CURRENCYRATE_LOG_FILE_CONDITION, nIfChangedFile);
+ db_set_w(hContact, CURRENCYRATES_MODULE_NAME, DB_STR_CURRENCYRATE_HISTORY_CONDITION, nIfChangedHistory);
+ db_set_b(hContact, CURRENCYRATES_MODULE_NAME, DB_STR_CURRENCYRATE_POPUP_CONDITION, bIfChangedPopup);
+ db_set_ws(hContact, CURRENCYRATES_MODULE_NAME, DB_STR_CURRENCYRATE_LOG_FILE, sLogFile.c_str());
+ db_set_ws(hContact, CURRENCYRATES_MODULE_NAME, DB_STR_CURRENCYRATE_FORMAT_LOG_FILE, sLogFileFormat.c_str());
+ db_set_ws(hContact, CURRENCYRATES_MODULE_NAME, DB_STR_CURRENCYRATE_FORMAT_HISTORY, sHistoryFormat.c_str());
+ db_set_ws(hContact, CURRENCYRATES_MODULE_NAME, DB_STR_CURRENCYRATE_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);
+
+ MWindowList hWL = CModuleInfo::GetWindowList(WINDOW_PREFIX_SETTINGS, false);
+ assert(hWL);
+ WindowList_Remove(hWL, hWnd);
+ Utils_SaveWindowPosition(hWnd, pParam->m_hContact, CURRENCYRATES_MODULE_NAME, WINDOW_PREFIX_SETTINGS);
+ delete pParam;
+ break;
+ }
+
+ return FALSE;
+}
+
+void ShowSettingsDlg(MCONTACT hContact)
+{
+ MWindowList hWL = CModuleInfo::GetWindowList(WINDOW_PREFIX_SETTINGS, true);
+ assert(hWL);
+ HWND hWnd = WindowList_Find(hWL, hContact);
+ if (nullptr != hWnd) {
+ SetForegroundWindow(hWnd);
+ SetFocus(hWnd);
+ }
+ else CreateDialogParam(g_plugin.getInst(), MAKEINTRESOURCE(IDD_CONTACT_SETTINGS), nullptr, EditSettingsPerContactDlgProc, LPARAM(hContact));
+}
+
+//////////////////////////////////////////////////////////////////////////
+
+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 ? BST_CHECKED : BST_UNCHECKED);
+ ::SetDlgItemText(hWnd, IDC_EDIT_HISTORY_FORMAT, pAdvSettings->GetHistoryFormat().c_str());
+ ::CheckDlgButton(hWnd, IDC_CHECK_HISTORY_CONDITION, (pAdvSettings->GetHistoryOnlyChangedFlag()) ? BST_CHECKED : BST_UNCHECKED);
+
+ // log to file
+ nCheck = (dwLogMode&lmExternalFile) ? 1 : 0;
+ ::CheckDlgButton(hWnd, IDC_CHECK_EXTERNAL_FILE, nCheck ? BST_CHECKED : BST_UNCHECKED);
+ ::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, (pAdvSettings->GetLogOnlyChangedFlag()) ? BST_CHECKED : BST_UNCHECKED);
+
+ update_file_controls(hWnd);
+ update_history_controls(hWnd);
+
+ // popup
+ nCheck = (dwLogMode&lmPopup) ? 1 : 0;
+ ::CheckDlgButton(hWnd, IDC_CHECK_SHOW_POPUP, nCheck ? BST_CHECKED : BST_UNCHECKED);
+ ::SetDlgItemText(hWnd, IDC_EDIT_POPUP_FORMAT, pAdvSettings->GetPopupFormat().c_str());
+ ::CheckDlgButton(hWnd, IDC_CHECK_SHOW_POPUP_ONLY_VALUE_CHANGED, (pAdvSettings->GetShowPopupIfValueChangedFlag()) ? BST_CHECKED : BST_UNCHECKED);
+
+ if (true == enable_popup_controls(hWnd))
+ update_popup_controls(hWnd);
+
+ ::SetWindowLongPtr(hWnd, GWLP_USERDATA, reinterpret_cast<LONG_PTR>(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);
+ CurrencyRates_MessageBox(hWnd, TranslateT("Enter log file name."), MB_OK | MB_ICONERROR);
+ bOk = false;
+ }
+ else if (true == sLogFileFormat.empty()) {
+ prepare_edit_ctrl_for_error(hwndLogFileFrmt);
+ CurrencyRates_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);
+ CurrencyRates_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);
+ CurrencyRates_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(g_plugin.getInst(),
+ MAKEINTRESOURCE(IDD_DIALOG_POPUP),
+ hWnd,
+ EditPopupSettingsDlgProc, reinterpret_cast<LPARAM>(pAdvSettings->GetPopupSettingsPtr()));
+ break;
+ }
+ break;
+ }
+ return FALSE;
+}
+
+CAdvProviderSettings::CAdvProviderSettings(const ICurrencyRatesProvider *pCurrencyRatesProvider)
+ : m_pCurrencyRatesProvider(pCurrencyRatesProvider),
+ m_wLogMode(lmDisabled),
+ m_bIsOnlyChangedHistory(false),
+ m_bIsOnlyChangedLogFile(false),
+ m_bShowPopupIfValueChanged(false),
+ m_pPopupSettings(nullptr)
+{
+ assert(m_pCurrencyRatesProvider);
+
+ m_wLogMode = db_get_w(0, CURRENCYRATES_MODULE_NAME, DB_KEY_LogMode, static_cast<WORD>(lmDisabled));
+ m_sFormatHistory = CurrencyRates_DBGetStringW(NULL, CURRENCYRATES_MODULE_NAME, DB_KEY_HistoryFormat, DB_DEF_HistoryFormat);
+ m_bIsOnlyChangedHistory = 1 == db_get_b(0, CURRENCYRATES_MODULE_NAME, DB_KEY_HistoryCondition, 0);
+
+ m_sLogFileName = CurrencyRates_DBGetStringW(NULL, CURRENCYRATES_MODULE_NAME, DB_KEY_LogFile);
+ if (true == m_sLogFileName.empty()) {
+ m_sLogFileName = g_pszVariableUserProfile;
+ m_sLogFileName += L"\\CurrencyRates\\";
+ m_sLogFileName += g_pszVariableCurrencyRateName;
+ m_sLogFileName += L".log";
+ }
+
+ m_sFormatLogFile = CurrencyRates_DBGetStringW(NULL, CURRENCYRATES_MODULE_NAME, DB_KEY_LogFormat, DB_DEF_LogFormat);
+ m_bIsOnlyChangedLogFile = (1 == db_get_b(0, CURRENCYRATES_MODULE_NAME, DB_KEY_LogCondition, 0));
+
+ m_sPopupFormat = CurrencyRates_DBGetStringW(NULL, CURRENCYRATES_MODULE_NAME, DB_KEY_PopupFormat, DB_DEF_PopupFormat);
+ m_bShowPopupIfValueChanged = (1 == db_get_b(0, CURRENCYRATES_MODULE_NAME, DB_KEY_PopupCondition, 0));
+}
+
+CAdvProviderSettings::~CAdvProviderSettings()
+{
+ delete m_pPopupSettings;
+}
+
+const ICurrencyRatesProvider* CAdvProviderSettings::GetProviderPtr() const
+{
+ return m_pCurrencyRatesProvider;
+}
+
+void CAdvProviderSettings::SaveToDb() const
+{
+ db_set_w(0, CURRENCYRATES_MODULE_NAME, DB_KEY_LogMode, m_wLogMode);
+ db_set_ws(0, CURRENCYRATES_MODULE_NAME, DB_KEY_HistoryFormat, m_sFormatHistory.c_str());
+ db_set_b(0, CURRENCYRATES_MODULE_NAME, DB_KEY_HistoryCondition, m_bIsOnlyChangedHistory);
+ db_set_ws(0, CURRENCYRATES_MODULE_NAME, DB_KEY_LogFile, m_sLogFileName.c_str());
+ db_set_ws(0, CURRENCYRATES_MODULE_NAME, DB_KEY_LogFormat, m_sFormatLogFile.c_str());
+ db_set_b(0, CURRENCYRATES_MODULE_NAME, DB_KEY_LogCondition, m_bIsOnlyChangedLogFile);
+ db_set_ws(0, CURRENCYRATES_MODULE_NAME, DB_KEY_PopupFormat, m_sPopupFormat.c_str());
+ db_set_b(0, CURRENCYRATES_MODULE_NAME, DB_KEY_PopupCondition, m_bShowPopupIfValueChanged);
+
+ if (nullptr != m_pPopupSettings) {
+ db_set_b(0, CURRENCYRATES_MODULE_NAME, DB_KEY_PopupColourMode, static_cast<BYTE>(m_pPopupSettings->GetColourMode()));
+ db_set_dw(0, CURRENCYRATES_MODULE_NAME, DB_KEY_PopupBkColour, m_pPopupSettings->GetColourBk());
+ db_set_dw(0, CURRENCYRATES_MODULE_NAME, DB_KEY_PopupTextColour, m_pPopupSettings->GetColourText());
+ db_set_b(0, CURRENCYRATES_MODULE_NAME, DB_KEY_PopupDelayMode, static_cast<BYTE>(m_pPopupSettings->GetDelayMode()));
+ db_set_w(0, CURRENCYRATES_MODULE_NAME, DB_KEY_PopupDelayTimeout, m_pPopupSettings->GetDelayTimeout());
+ db_set_b(0, CURRENCYRATES_MODULE_NAME, DB_KEY_PopupHistoryFlag, 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();
+
+ return m_pPopupSettings;
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// class CPopupSettings
+
+CPopupSettings::CPopupSettings() :
+ m_modeColour(colourDefault),
+ m_modeDelay(delayFromPopup),
+ m_rgbBkg(GetDefColourBk()),
+ m_rgbText(GetDefColourText()),
+ m_wDelay(3),
+ m_bUseHistory(false)
+
+{
+ BYTE m = db_get_b(0, CURRENCYRATES_MODULE_NAME, DB_KEY_PopupColourMode, static_cast<BYTE>(m_modeColour));
+ if (m >= colourDefault && m <= colourUserDefined)
+ m_modeColour = static_cast<EColourMode>(m);
+
+ m_rgbBkg = db_get_dw(0, CURRENCYRATES_MODULE_NAME, DB_KEY_PopupBkColour, m_rgbBkg);
+ m_rgbText = db_get_dw(0, CURRENCYRATES_MODULE_NAME, DB_KEY_PopupTextColour, m_rgbText);
+
+ m = db_get_b(0, CURRENCYRATES_MODULE_NAME, DB_KEY_PopupDelayMode, static_cast<BYTE>(m_modeDelay));
+ if (m >= delayFromPopup && m <= delayPermanent) {
+ m_modeDelay = static_cast<EDelayMode>(m);
+ }
+ m_wDelay = db_get_w(0, CURRENCYRATES_MODULE_NAME, DB_KEY_PopupDelayTimeout, m_wDelay);
+ m_bUseHistory = (1 == db_get_b(0, CURRENCYRATES_MODULE_NAME, DB_KEY_PopupHistoryFlag, m_bUseHistory));
+}
+
+/*static */
+COLORREF CPopupSettings::GetDefColourBk()
+{
+ return ::GetSysColor(COLOR_BTNFACE);
+}
+
+/*static */
+COLORREF CPopupSettings::GetDefColourText()
+{
+ return ::GetSysColor(COLOR_BTNTEXT);
+}
+
+void CPopupSettings::InitForContact(MCONTACT hContact)
+{
+ BYTE m = db_get_b(hContact, CURRENCYRATES_MODULE_NAME, DB_STR_CURRENCYRATE_POPUP_COLOUR_MODE, static_cast<BYTE>(m_modeColour));
+ if (m >= CPopupSettings::colourDefault && m <= CPopupSettings::colourUserDefined) {
+ m_modeColour = static_cast<CPopupSettings::EColourMode>(m);
+ }
+
+ m_rgbBkg = db_get_dw(hContact, CURRENCYRATES_MODULE_NAME, DB_STR_CURRENCYRATE_POPUP_COLOUR_BK, m_rgbBkg);
+ m_rgbText = db_get_dw(hContact, CURRENCYRATES_MODULE_NAME, DB_STR_CURRENCYRATE_POPUP_COLOUR_TEXT, m_rgbText);
+
+ m = db_get_b(hContact, CURRENCYRATES_MODULE_NAME, DB_STR_CURRENCYRATE_POPUP_DELAY_MODE, static_cast<BYTE>(m_modeDelay));
+ if (m >= CPopupSettings::delayFromPopup && m <= CPopupSettings::delayPermanent) {
+ m_modeDelay = static_cast<CPopupSettings::EDelayMode>(m);
+ }
+ m_wDelay = db_get_w(hContact, CURRENCYRATES_MODULE_NAME, DB_STR_CURRENCYRATE_POPUP_DELAY_TIMEOUT, m_wDelay);
+ m_bUseHistory = 1 == db_get_b(hContact, CURRENCYRATES_MODULE_NAME, DB_STR_CURRENCYRATE_POPUP_HISTORY_FLAG, m_bUseHistory);
+}
+
+void CPopupSettings::SaveForContact(MCONTACT hContact) const
+{
+ db_set_b(hContact, CURRENCYRATES_MODULE_NAME, DB_STR_CURRENCYRATE_POPUP_COLOUR_MODE, static_cast<BYTE>(m_modeColour));
+ db_set_dw(hContact, CURRENCYRATES_MODULE_NAME, DB_STR_CURRENCYRATE_POPUP_COLOUR_BK, m_rgbBkg);
+ db_set_dw(hContact, CURRENCYRATES_MODULE_NAME, DB_STR_CURRENCYRATE_POPUP_COLOUR_TEXT, m_rgbText);
+ db_set_b(hContact, CURRENCYRATES_MODULE_NAME, DB_STR_CURRENCYRATE_POPUP_DELAY_MODE, static_cast<BYTE>(m_modeDelay));
+ db_set_w(hContact, CURRENCYRATES_MODULE_NAME, DB_STR_CURRENCYRATE_POPUP_DELAY_TIMEOUT, m_wDelay);
+ db_set_b(hContact, CURRENCYRATES_MODULE_NAME, DB_STR_CURRENCYRATE_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(g_plugin.getInst(),
+ MAKEINTRESOURCE(IDD_PROVIDER_ADV_SETTINGS),
+ hWndParent,
+ EditSettingsPerProviderDlgProc,
+ reinterpret_cast<LPARAM>(pAdvSettings)));
+}
+
+tstring GenerateLogFileName(const tstring &rsLogFilePattern, const tstring &rsCurrencyRateSymbol, int nFlags)
+{
+ tstring sPath = rsLogFilePattern;
+ if (nFlags&glfnResolveCurrencyRateName) {
+ assert(false == rsCurrencyRateSymbol.empty());
+
+ tstring::size_type n = sPath.find(g_pszVariableCurrencyRateName);
+ if (tstring::npos != n) {
+ tstring s = rsCurrencyRateSymbol;
+ FixInvalidChars(s);
+ sPath.replace(n, _countof(g_pszVariableCurrencyRateName)-1, s.c_str());
+ }
+ }
+
+ if (nFlags & glfnResolveUserProfile) {
+ wchar_t *ptszParsedName = Utils_ReplaceVarsW(sPath.c_str());
+ if (ptszParsedName) {
+ sPath = ptszParsedName;
+ mir_free(ptszParsedName);
+ }
+ }
+
+ return sPath;
+}
+
+tstring GetContactLogFileName(MCONTACT hContact)
+{
+ tstring result;
+
+ auto pProvider = GetContactProviderPtr(hContact);
+ if (pProvider) {
+ tstring sPattern;
+ bool bUseContactSpecific = (db_get_b(hContact, CURRENCYRATES_MODULE_NAME, DB_STR_CONTACT_SPEC_SETTINGS, 0) > 0);
+ if (bUseContactSpecific)
+ sPattern = CurrencyRates_DBGetStringW(hContact, CURRENCYRATES_MODULE_NAME, DB_STR_CURRENCYRATE_LOG_FILE);
+ else {
+ CAdvProviderSettings global_settings(pProvider);
+ sPattern = global_settings.GetLogFileName();
+ }
+
+ result = GenerateLogFileName(sPattern, CurrencyRates_DBGetStringW(hContact, CURRENCYRATES_MODULE_NAME, DB_STR_CURRENCYRATE_SYMBOL));
+ }
+
+ return result;
+}
+
+tstring GetContactName(MCONTACT hContact)
+{
+ tstring sDescription = CurrencyRates_DBGetStringW(hContact, CURRENCYRATES_MODULE_NAME, DB_STR_CURRENCYRATE_DESCRIPTION);
+ if (sDescription.empty())
+ sDescription = CurrencyRates_DBGetStringW(hContact, CURRENCYRATES_MODULE_NAME, DB_STR_CURRENCYRATE_SYMBOL);
+
+ return sDescription;
+}
diff --git a/protocols/CurrencyRates/src/SettingsDlg.h b/protocols/CurrencyRates/src/SettingsDlg.h
new file mode 100644
index 0000000000..b6b49b97bd
--- /dev/null
+++ b/protocols/CurrencyRates/src/SettingsDlg.h
@@ -0,0 +1,116 @@
+#ifndef __E211E4D9_383C_43BE_A787_7EF1D585B90D_SettingsDlg_h__
+#define __E211E4D9_383C_43BE_A787_7EF1D585B90D_SettingsDlg_h__
+
+class CPopupSettings
+{
+public:
+ enum EColourMode
+ {
+ colourDefault,
+ colourUserDefined,
+ };
+
+ enum EDelayMode
+ {
+ delayFromPopup,
+ delayCustom,
+ delayPermanent
+ };
+
+public:
+ CPopupSettings();
+
+ static COLORREF GetDefColourBk();
+ static COLORREF GetDefColourText();
+
+ void InitForContact(MCONTACT hContact);
+ void SaveForContact(MCONTACT 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 ICurrencyRatesProvider *pCurrencyRatesProvider);
+ ~CAdvProviderSettings();
+
+ void SaveToDb() const;
+
+ const ICurrencyRatesProvider* 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 ICurrencyRatesProvider *m_pCurrencyRatesProvider;
+ 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(MCONTACT hContact);
+bool ShowSettingsDlg(HWND hWndParent, CAdvProviderSettings* pAdvSettings);
+
+enum
+{
+ glfnResolveCurrencyRateName = 0x0001,
+ glfnResolveUserProfile = 0x0002,
+ glfnResolveAll = glfnResolveCurrencyRateName | glfnResolveUserProfile,
+};
+tstring GenerateLogFileName(const tstring& rsLogFilePattern, const tstring& rsCurrencyRateSymbol, int nFlags = glfnResolveAll);
+tstring GetContactLogFileName(MCONTACT hContact);
+tstring GetContactName(MCONTACT hContact);
+
+#endif //__E211E4D9_383C_43BE_A787_7EF1D585B90D_SettingsDlg_h__
+
diff --git a/protocols/CurrencyRates/src/WinCtrlHelper.cpp b/protocols/CurrencyRates/src/WinCtrlHelper.cpp
new file mode 100644
index 0000000000..f45c4db536
--- /dev/null
+++ b/protocols/CurrencyRates/src/WinCtrlHelper.cpp
@@ -0,0 +1,31 @@
+#include "stdafx.h"
+
+class CVariableListDlg : public CDlgBase
+{
+ const ICurrencyRatesProvider *m_pProvider;
+
+public:
+ CVariableListDlg(HWND hwndParent, const ICurrencyRatesProvider *pProvider) :
+ CDlgBase(g_plugin, IDD_DIALOG_VARIABLE_LIST),
+ m_pProvider(pProvider)
+ {
+ SetParent(hwndParent);
+ }
+
+ bool OnInitDialog() override
+ {
+ TFormatSpecificators aSpecificators;
+ m_pProvider->FillFormat(aSpecificators);
+
+ tostringstream o;
+ for (auto &spec : aSpecificators)
+ o << spec.first << '\t' << spec.second << L"\r\n";
+ ::SetDlgItemText(m_hwnd, IDC_EDIT_VARIABLE, o.str().c_str());
+ return true;
+ }
+};
+
+void show_variable_list(HWND hwndParent, const ICurrencyRatesProvider *pProvider)
+{
+ CVariableListDlg(hwndParent, pProvider).DoModal();
+}
diff --git a/protocols/CurrencyRates/src/WinCtrlHelper.h b/protocols/CurrencyRates/src/WinCtrlHelper.h
new file mode 100644
index 0000000000..a770072bd6
--- /dev/null
+++ b/protocols/CurrencyRates/src/WinCtrlHelper.h
@@ -0,0 +1,37 @@
+#ifndef __a05d6852_4497_4f28_85e1_48a15a170738_WinCtrlHelper_h__
+#define __a05d6852_4497_4f28_85e1_48a15a170738_WinCtrlHelper_h__
+
+class ICurrencyRatesProvider;
+
+inline tstring get_window_text(HWND hWnd)
+{
+ int cBytes = ::GetWindowTextLength(hWnd);
+
+ std::vector<wchar_t> 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 ICurrencyRatesProvider *pProvider);
+
+inline int CurrencyRates_MessageBox(HWND hWnd, LPCTSTR pszText, UINT nType = MB_OK)
+{
+ return ::MessageBox(hWnd, pszText, currencyrates_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/CurrencyRates/src/resource.h b/protocols/CurrencyRates/src/resource.h
new file mode 100644
index 0000000000..e1216a897c
--- /dev/null
+++ b/protocols/CurrencyRates/src/resource.h
@@ -0,0 +1,102 @@
+//{{NO_DEPENDENCIES}}
+// Microsoft Visual C++ generated include file.
+// Used by w:\miranda-ng\plugins\CurrencyRates\res\Forex.rc
+//
+#define IDI_ICON_MAIN 102
+#define IDD_DIALOG_CURRENCYRATE_INFO 102
+#define IDD_DIALOG_OPT_GOOGLE 103
+#define IDI_ICON_SECTION 110
+#define IDI_ICON_CURRENCYRATE 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_DIALOG_CURRENCYRATE_INFO_1 118
+#define IDI_ICON_REFRESH 118
+#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 IDI_ICON_MAIN1 122
+#define IDI_ICON_DISABLED 122
+#define IDD_DIALOG_VARIABLE_LIST 123
+#define IDC_EDIT_REFRESH_RATE 1002
+#define IDC_SPIN_REFRESH_RATE 1003
+#define IDC_COMBO_REFRESH_RATE 1004
+#define IDC_STATIC_CURRENCYRATE_NAME 1008
+#define IDC_SYSLINK_PROVIDER 1009
+#define IDC_STATIC_CHART 1010
+#define IDC_STATIC_CURRENCYRATE_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_EDIT_TENDENCY_FORMAT2 1023
+#define IDC_EDIT_PERSONAL_KEY 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_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_EDIT_FROM2 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 126
+#define _APS_NEXT_COMMAND_VALUE 40001
+#define _APS_NEXT_CONTROL_VALUE 1073
+#define _APS_NEXT_SYMED_VALUE 101
+#endif
+#endif
diff --git a/protocols/CurrencyRates/src/stdafx.cxx b/protocols/CurrencyRates/src/stdafx.cxx
new file mode 100644
index 0000000000..66afad80f1
--- /dev/null
+++ b/protocols/CurrencyRates/src/stdafx.cxx
@@ -0,0 +1,18 @@
+/*
+Copyright (C) 2012-19 Miranda NG team (https://miranda-ng.org)
+
+This program is free software; you can redistribute it and/or
+modify it under the terms of the GNU General Public License
+as published by the Free Software Foundation version 2
+of the License.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "stdafx.h"
diff --git a/protocols/CurrencyRates/src/stdafx.h b/protocols/CurrencyRates/src/stdafx.h
new file mode 100644
index 0000000000..d2bc83fd18
--- /dev/null
+++ b/protocols/CurrencyRates/src/stdafx.h
@@ -0,0 +1,113 @@
+// stdafx.h : include file for standard system include files,
+// or project specific include files that are used frequently, but
+// are changed infrequently
+//
+
+#pragma once
+
+#undef _HAS_EXCEPTIONS
+#define _HAS_EXCEPTIONS 1
+
+#include <windows.h>
+#include <mshtml.h>
+#include <comdef.h>
+#include <commctrl.h>
+#include <ShellAPI.h>
+#include <sys/stat.h>
+#include <CommDlg.h>
+#include <fstream>
+#include <msapi/comptr.h>
+
+#include <newpluginapi.h>
+#include <m_database.h>
+#include <win2k.h>
+#include <m_xml.h>
+#include <m_clist.h>
+#include <m_langpack.h>
+#include <m_options.h>
+#include <m_protosvc.h>
+#include <m_extraicons.h>
+#include <m_icolib.h>
+#include <m_genmenu.h>
+#include <m_netlib.h>
+#include <m_popup.h>
+#include <m_userinfo.h>
+#include <m_gui.h>
+
+#include <m_variables.h>
+#include <m_CurrencyRates.h>
+#include <m_toptoolbar.h>
+
+#include <boost\date_time\posix_time\posix_time.hpp>
+#include <boost\date_time\c_local_time_adjustor.hpp>
+
+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;
+
+inline std::string currencyrates_t2a(const wchar_t* t)
+{
+ std::string s;
+ char* p = mir_u2a(t);
+ if (p) {
+ s = p;
+ mir_free(p);
+ }
+ return s;
+}
+
+inline tstring currencyrates_a2t(const char* s)
+{
+ tstring t;
+ wchar_t* p = mir_a2u(s);
+ if (p) {
+ t = p;
+ mir_free(p);
+ }
+ return t;
+}
+
+#include "resource.h"
+#include "version.h"
+#include "IconLib.h"
+#include "CurrencyRateInfoDlg.h"
+#include "ModuleInfo.h"
+#include "DBUtils.h"
+#include "HTTPSession.h"
+#include "CurrencyConverter.h"
+#include "WinCtrlHelper.h"
+#include "ImportExport.h"
+#include "ComHelper.h"
+#include "Log.h"
+#include "CommonOptionDlg.h"
+#include "EconomicRateInfo.h"
+#include "SettingsDlg.h"
+#include "CreateFilePath.h"
+#include "Locale.h"
+#include "ExtraImages.h"
+#include "IsWithinAccuracy.h"
+#include "ICurrencyRatesProvider.h"
+#include "CurrencyRatesProviderBase.h"
+
+#define CHART_IMPLEMENT
+#ifdef CHART_IMPLEMENT
+#include "CurrencyRateChart.h"
+#include "Chart.h"
+#endif
+#include "IHTMLParser.h"
+#include "IHTMLEngine.h"
+#include "HTMLParserMS.h"
+
+struct CMPlugin : public PLUGIN<CMPlugin>
+{
+ CMPlugin();
+
+ int Load() override;
+ int Unload() override;
+};
diff --git a/protocols/CurrencyRates/src/version.h b/protocols/CurrencyRates/src/version.h
new file mode 100644
index 0000000000..cd73fb3f68
--- /dev/null
+++ b/protocols/CurrencyRates/src/version.h
@@ -0,0 +1,13 @@
+#define __MAJOR_VERSION 0
+#define __MINOR_VERSION 2
+#define __RELEASE_NUM 0
+#define __BUILD_NUM 3
+
+#include <stdver.h>
+
+#define __PLUGIN_NAME "Currency Rates"
+#define __FILENAME "CurrencyRates.dll"
+#define __DESCRIPTION "Shows currency rates."
+#define __AUTHOR "Dioksin"
+#define __AUTHORWEB "https://miranda-ng.org/p/CurrencyRates/"
+#define __COPYRIGHT ""
diff --git a/protocols/FacebookRM/kdjfg b/protocols/FacebookRM/kdjfg
new file mode 100644
index 0000000000..bfb77e43df
--- /dev/null
+++ b/protocols/FacebookRM/kdjfg
@@ -0,0 +1 @@
+https://web.facebook.com/ajax/presence/reconnect.php?reason=6&fb_dtsg=AQF3n013KPtN\u00253AAQHNnNfVkGP2&_rdc=1&__a=1&__req=1&__dyn=7AzkXxaA4ojgDxyLqzGomzEbHGbGey8WhLFwgoqwWhE98nwgUaoepovHyodEbbxW4E4u3ucDBwJx62i2PxOcG4K1Zxa2m4oqyUf8oCK251G6XDwnU567oeo5m4pHxC326U6OfBwHx&__m_async_page__=1&fb_dtsg_ag=AQxlQOmlaBgR-f7MlPV_ZexeE3-zBxR_2bLUJ1ejgT3LXA\u00253AAQx2bODadk1RrKlR8M9URvoaEDMf4iS5sk-hIm95tReiFg&jazoest=27880&_rdr \ No newline at end of file
diff --git a/protocols/GmailNotifier/GmailNotifier.vcxproj b/protocols/GmailNotifier/GmailNotifier.vcxproj
new file mode 100644
index 0000000000..b8ffdd3625
--- /dev/null
+++ b/protocols/GmailNotifier/GmailNotifier.vcxproj
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <ItemGroup Label="ProjectConfigurations">
+ <ProjectConfiguration Include="Debug|Win32">
+ <Configuration>Debug</Configuration>
+ <Platform>Win32</Platform>
+ </ProjectConfiguration>
+ <ProjectConfiguration Include="Debug|x64">
+ <Configuration>Debug</Configuration>
+ <Platform>x64</Platform>
+ </ProjectConfiguration>
+ <ProjectConfiguration Include="Release|Win32">
+ <Configuration>Release</Configuration>
+ <Platform>Win32</Platform>
+ </ProjectConfiguration>
+ <ProjectConfiguration Include="Release|x64">
+ <Configuration>Release</Configuration>
+ <Platform>x64</Platform>
+ </ProjectConfiguration>
+ </ItemGroup>
+ <PropertyGroup Label="Globals">
+ <ProjectName>GmailNotifier</ProjectName>
+ <ProjectGuid>{EDAAD28B-505B-4969-A8BB-97EAE818DEEA}</ProjectGuid>
+ </PropertyGroup>
+ <ImportGroup Label="PropertySheets">
+ <Import Project="$(ProjectDir)..\..\build\vc.common\plugin.props" />
+ </ImportGroup>
+</Project> \ No newline at end of file
diff --git a/protocols/GmailNotifier/GmailNotifier.vcxproj.filters b/protocols/GmailNotifier/GmailNotifier.vcxproj.filters
new file mode 100644
index 0000000000..fcae13a9d8
--- /dev/null
+++ b/protocols/GmailNotifier/GmailNotifier.vcxproj.filters
@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <Import Project="$(ProjectDir)..\..\build\vc.common\common.filters" />
+</Project> \ No newline at end of file
diff --git a/protocols/GmailNotifier/res/empty.ico b/protocols/GmailNotifier/res/empty.ico
new file mode 100644
index 0000000000..e772add255
--- /dev/null
+++ b/protocols/GmailNotifier/res/empty.ico
Binary files differ
diff --git a/protocols/GmailNotifier/res/error.ico b/protocols/GmailNotifier/res/error.ico
new file mode 100644
index 0000000000..18ac70f769
--- /dev/null
+++ b/protocols/GmailNotifier/res/error.ico
Binary files differ
diff --git a/protocols/GmailNotifier/res/iconnew.ico b/protocols/GmailNotifier/res/iconnew.ico
new file mode 100644
index 0000000000..109ece345f
--- /dev/null
+++ b/protocols/GmailNotifier/res/iconnew.ico
Binary files differ
diff --git a/protocols/GmailNotifier/res/options.rc b/protocols/GmailNotifier/res/options.rc
new file mode 100644
index 0000000000..21de3100cb
--- /dev/null
+++ b/protocols/GmailNotifier/res/options.rc
@@ -0,0 +1,140 @@
+// Microsoft Visual C++ generated resource script.
+//
+#include "..\src\resource.h"
+
+#define APSTUDIO_READONLY_SYMBOLS
+/////////////////////////////////////////////////////////////////////////////
+//
+// Generated from the TEXTINCLUDE 2 resource.
+//
+#include <winres.h>
+/////////////////////////////////////////////////////////////////////////////
+#undef APSTUDIO_READONLY_SYMBOLS
+
+/////////////////////////////////////////////////////////////////////////////
+// Neutral (Sys. Default) resources
+
+#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_NEUSD)
+LANGUAGE LANG_NEUTRAL, SUBLANG_SYS_DEFAULT
+#pragma code_page(1252)
+
+#ifdef APSTUDIO_INVOKED
+/////////////////////////////////////////////////////////////////////////////
+//
+// TEXTINCLUDE
+//
+
+1 TEXTINCLUDE
+BEGIN
+ "..\\src\\resource.h\0"
+END
+
+2 TEXTINCLUDE
+BEGIN
+ "#include <winres.h>\0"
+END
+
+3 TEXTINCLUDE
+BEGIN
+ "\r\n"
+ "\0"
+END
+
+#endif // APSTUDIO_INVOKED
+
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Dialog
+//
+
+IDD_OPT DIALOGEX 0, 0, 309, 227
+STYLE DS_SETFONT | DS_FIXEDSYS | WS_CHILD
+EXSTYLE WS_EX_CONTROLPARENT
+FONT 8, "MS Shell Dlg", 0, 0, 0x1
+BEGIN
+ GROUPBOX "Gmail account",IDC_GROUPMAIN,4,2,291,56
+ LTEXT "Name:",IDC_STATIC,8,19,68,9,NOT WS_GROUP,WS_EX_RIGHT
+ COMBOBOX IDC_NAME,82,17,145,50,CBS_DROPDOWN | CBS_AUTOHSCROLL | WS_VSCROLL | WS_TABSTOP | 0x8000
+ LTEXT "Password:",IDC_STATIC,8,35,68,9,NOT WS_GROUP,WS_EX_RIGHT
+ EDITTEXT IDC_PASS,82,33,145,12,ES_PASSWORD | ES_AUTOHSCROLL | NOT WS_BORDER,WS_EX_STATICEDGE
+ PUSHBUTTON "Add",IDC_BTNADD,231,13,57,11,0,WS_EX_STATICEDGE
+ PUSHBUTTON "Save",IDC_BTNSAV,231,26,57,11,0,WS_EX_STATICEDGE
+ PUSHBUTTON "Delete",IDC_BTNDEL,231,39,57,11,0,WS_EX_STATICEDGE
+ GROUPBOX "Configuration",IDC_CONFIG,4,65,291,157
+ LTEXT "Check Gmail inbox every",IDC_STATIC,8,78,149,9,0,WS_EX_RIGHT
+ LTEXT "minutes",IDC_STATIC,183,79,46,9
+ LTEXT "Notify using:",IDC_STATIC,8,93,68,9,0,WS_EX_RIGHT
+ LTEXT "Duration:",IDC_STATIC_DURATION,169,97,58,9,NOT WS_VISIBLE | NOT WS_GROUP,WS_EX_RIGHT
+ EDITTEXT IDC_DURATION,231,96,14,11,NOT WS_VISIBLE | NOT WS_BORDER,WS_EX_STATICEDGE
+ LTEXT "seconds",IDC_STATIC_SEC,249,97,37,9,NOT WS_VISIBLE
+ LTEXT "Text|Background:",IDC_STATIC_COLOR,137,113,90,9,NOT WS_VISIBLE | NOT WS_GROUP,WS_EX_RIGHT
+ CONTROL "",IDC_TEXTCOLOR,"ColourPicker",NOT WS_VISIBLE | WS_TABSTOP,231,114,21,9
+ CONTROL "",IDC_BGCOLOR,"ColourPicker",NOT WS_VISIBLE | WS_TABSTOP,259,114,21,9
+ LTEXT "On double click:",IDC_STATIC,8,123,68,9,0,WS_EX_RIGHT
+ EDITTEXT IDC_CIRCLE,161,77,18,11,NOT WS_BORDER,WS_EX_STATICEDGE
+ CONTROL "System tray",IDC_OPTTRAY,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,82,93,56,10
+ CONTROL "Popup plugin",IDC_OPTPOP,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,82,104,84,10
+ CONTROL "Login using default browser",IDC_SYSDEF,"Button",BS_AUTORADIOBUTTON,82,123,206,10
+ CONTROL "Login using Internet Explorer",IDC_USEIE,"Button",BS_AUTORADIOBUTTON,82,134,206,10
+ CONTROL "Run custom program",IDC_STARTPRG,"Button",BS_AUTORADIOBUTTON,82,145,206,10
+ EDITTEXT IDC_PRG,82,156,189,11,ES_AUTOHSCROLL | NOT WS_VISIBLE | NOT WS_BORDER,WS_EX_STATICEDGE
+ PUSHBUTTON "...",IDC_PRGBROWSE,276,156,12,11,NOT WS_VISIBLE,WS_EX_STATICEDGE
+ CONTROL "Use online contacts when no new mail",IDC_ONLINE,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,8,169,280,10
+ CONTROL "Enable icon selection and icon in status bar (restart)",IDC_SHOWICON,
+ "Button",BS_AUTOCHECKBOX | WS_TABSTOP,8,181,280,10
+ CONTROL "This is a shared computer so disable auto login",IDC_AUTOLOGIN,
+ "Button",BS_AUTOCHECKBOX | WS_TABSTOP,8,194,280,10
+ CONTROL "Log unread threads into database (enable history)",IDC_LOGTHREADS,
+ "Button",BS_AUTOCHECKBOX | WS_TABSTOP,8,207,280,10
+END
+
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Icon
+//
+
+// Icon with lowest ID value placed first to ensure application icon
+// remains consistent on all systems.
+IDI_ICONNEW ICON "iconnew.ico"
+IDI_ICONERR ICON "error.ico"
+IDI_ICONEPT ICON "empty.ico"
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// DESIGNINFO
+//
+
+#ifdef APSTUDIO_INVOKED
+GUIDELINES DESIGNINFO
+BEGIN
+ IDD_OPT, DIALOG
+ BEGIN
+ RIGHTMARGIN, 295
+ VERTGUIDE, 4
+ VERTGUIDE, 8
+ VERTGUIDE, 76
+ VERTGUIDE, 82
+ VERTGUIDE, 227
+ VERTGUIDE, 231
+ VERTGUIDE, 288
+ END
+END
+#endif // APSTUDIO_INVOKED
+
+#endif // Neutral (Sys. Default) resources
+/////////////////////////////////////////////////////////////////////////////
+
+
+
+#ifndef APSTUDIO_INVOKED
+/////////////////////////////////////////////////////////////////////////////
+//
+// Generated from the TEXTINCLUDE 3 resource.
+//
+
+
+/////////////////////////////////////////////////////////////////////////////
+#endif // not APSTUDIO_INVOKED
+
diff --git a/protocols/GmailNotifier/res/version.rc b/protocols/GmailNotifier/res/version.rc
new file mode 100644
index 0000000000..5a5ddd63ed
--- /dev/null
+++ b/protocols/GmailNotifier/res/version.rc
@@ -0,0 +1,9 @@
+// Microsoft Visual C++ generated resource script.
+//
+#ifdef APSTUDIO_INVOKED
+#error this file is not editable by Microsoft Visual C++
+#endif //APSTUDIO_INVOKED
+
+#include "..\src\version.h"
+
+#include "..\..\build\Version.rc"
diff --git a/protocols/GmailNotifier/src/check.cpp b/protocols/GmailNotifier/src/check.cpp
new file mode 100644
index 0000000000..06a1926ef1
--- /dev/null
+++ b/protocols/GmailNotifier/src/check.cpp
@@ -0,0 +1,149 @@
+#include "stdafx.h"
+
+#pragma comment(lib, "Wininet.lib")
+
+static int ParsePage(char *page, resultLink *prst)
+{
+ char *str_head;
+ char *str_tail;
+ char name[64], title[64];
+ int num = 0;
+ wchar_t str[64];
+
+ prst->next = nullptr;
+ if (!(str_head = strstr(page, "<entry>")))
+ return 0;
+
+ while (str_head = strstr(str_head, "<title>")) {
+ prst = prst->next = (resultLink *)malloc(sizeof(resultLink));
+ str_head += 7;
+ str_tail = strstr(str_head, "</title>");
+ *str_tail = '\0';
+ mir_strncpy(title, str_head, 41);
+ if (mir_strlen(title) == 40)
+ mir_strcat(title, "...");
+ *str_tail = ' ';
+
+ str_head = strstr(str_head, "<name>") + 6;
+ str_tail = strstr(str_head, "</name>");
+ *str_tail = '\0';
+ mir_strncpy(name, str_head, 11);
+ mir_strcat(name, ": ");
+ *str_tail = ' ';
+
+ mir_strcpy(prst->content, name);
+ mir_strcat(prst->content, title);
+ MultiByteToWideChar(CP_UTF8, 0, prst->content, -1, str, 64);
+ WideCharToMultiByte(CP_ACP, 0, str, -1, prst->content, 64, nullptr, nullptr);
+ num++;
+ }
+ prst->next = nullptr;
+ return num;
+}
+
+void CheckMailInbox(Account *curAcc)
+{
+ if (curAcc->IsChecking)
+ return;
+
+ curAcc->IsChecking = true;
+
+ ptrA szNick(db_get_sa(curAcc->hContact, "CList", "MyHandle", curAcc->name));
+
+ char *tail = strstr(szNick, " [");
+ if (tail) *tail = 0;
+
+ db_set_s(curAcc->hContact, "CList", "MyHandle", CMStringA(FORMAT, "%s [%s]", szNick.get(), Translate("Checking...")));
+
+ if (curAcc->hosted[0]) {
+ CMStringA szUrl(FORMAT, "https://www.google.com/a/%s/LoginAction", curAcc->hosted);
+ CMStringA szBody("continue=https%3A%2F%2Fmail.google.com%2Fa%2F");
+ szBody.Append(curAcc->hosted);
+ szBody.Append("%2Ffeed%2Fatom&service=mail&userName=");
+ tail = strchr(curAcc->name, '@');
+ if (tail) *tail = 0;
+ szBody.Append(curAcc->name);
+ if (tail) *tail = '@';
+ szBody.Append("&password=");
+ szBody.Append(curAcc->pass);
+
+ NETLIBHTTPHEADER headers[1] = {
+ { "Content-Type", "application/x-www-form-urlencoded" }
+ };
+
+ NETLIBHTTPREQUEST nlr = {};
+ nlr.cbSize = sizeof(nlr);
+ nlr.szUrl = szUrl.GetBuffer();
+ nlr.requestType = REQUEST_POST;
+ nlr.headersCount = _countof(headers);
+ nlr.headers = headers;
+ nlr.dataLength = szBody.GetLength();
+ nlr.pData = szBody.GetBuffer();
+
+ NETLIBHTTPREQUEST *nlu = Netlib_HttpTransaction(hNetlibUser, &nlr);
+ if (nlu == nullptr || nlu->resultCode != 200) {
+ mir_strcpy(curAcc->results.content, Translate("Can't send account data!"));
+
+ Netlib_FreeHttpRequest(nlu);
+ curAcc->results_num = -1;
+ mir_strcat(curAcc->results.content, "]");
+ curAcc->IsChecking = false;
+ return;
+ }
+
+ Netlib_FreeHttpRequest(nlu);
+ }
+
+ // go!
+ CMStringA loginPass(FORMAT, "%s:%s", curAcc->name, curAcc->pass);
+ ptrA loginPassEncoded(mir_base64_encode(loginPass.c_str(), loginPass.GetLength()));
+
+ CMStringA szUrl("https://mail.google.com"), szAuth(FORMAT, "Basic %s", loginPassEncoded.get());
+ if (curAcc->hosted[0])
+ szUrl.AppendFormat("/a/%s/feed/atom", curAcc->hosted);
+ else
+ szUrl.Append("/mail/feed/atom");
+
+ NETLIBHTTPHEADER headers[1] = {
+ { "Authorization", szAuth.GetBuffer() }
+ };
+
+ NETLIBHTTPREQUEST nlr = {};
+ nlr.cbSize = sizeof(nlr);
+ nlr.szUrl = szUrl.GetBuffer();
+ nlr.requestType = REQUEST_GET;
+ nlr.headers = headers;
+ nlr.headersCount = _countof(headers);
+
+ NETLIBHTTPREQUEST *nlu = Netlib_HttpTransaction(hNetlibUser, &nlr);
+ if (nlu == nullptr) {
+ mir_snprintf(curAcc->results.content, "%s [%s]", szNick.get(),
+ (nlr.resultCode == 401) ? Translate("Wrong name or password!") : Translate("Can't get RSS feed!"));
+ Netlib_FreeHttpRequest(nlu);
+
+ curAcc->results_num = -1;
+ curAcc->IsChecking = false;
+ return;
+ }
+
+ curAcc->results_num = ParsePage(nlu->pData, &curAcc->results);
+ mir_snprintf(curAcc->results.content, "%s [%d]", szNick.get(), curAcc->results_num);
+
+ curAcc->IsChecking = false;
+}
+
+void __cdecl Check_ThreadFunc(void *lpParam)
+{
+ if (lpParam) {
+ CheckMailInbox((Account *)lpParam);
+ NotifyUser((Account *)lpParam);
+ }
+ else {
+ for (auto &it : g_accs) {
+ if (GetContactProto(it->hContact)) {
+ CheckMailInbox(it);
+ NotifyUser(it);
+ }
+ }
+ }
+}
diff --git a/protocols/GmailNotifier/src/main.cpp b/protocols/GmailNotifier/src/main.cpp
new file mode 100644
index 0000000000..42158bd826
--- /dev/null
+++ b/protocols/GmailNotifier/src/main.cpp
@@ -0,0 +1,162 @@
+/*
+Miranda plugin template, originally by Richard Hughes
+http://miranda-icq.sourceforge.net/
+
+This file is placed in the public domain. Anybody is free to use or
+modify it as they wish with no restriction.
+There is no warranty.
+*/
+
+#include "stdafx.h"
+#include "version.h"
+
+CMPlugin g_plugin;
+
+UINT hTimer;
+HNETLIBUSER hNetlibUser;
+NOTIFYICONDATA niData;
+optionSettings opt;
+
+OBJLIST<Account> g_accs(1);
+BOOL optionWindowIsOpen = FALSE;
+short ID_STATUS_NONEW;
+
+/////////////////////////////////////////////////////////////////////////////////////////
+
+static PLUGININFOEX pluginInfoEx =
+{
+ sizeof(PLUGININFOEX),
+ __PLUGIN_NAME,
+ PLUGIN_MAKE_VERSION(__MAJOR_VERSION, __MINOR_VERSION, __RELEASE_NUM, __BUILD_NUM),
+ __DESCRIPTION,
+ __AUTHOR,
+ __COPYRIGHT,
+ __AUTHORWEB,
+ UNICODE_AWARE,
+ // {243955E0-75D9-4CC3-9B28-6F9C5AF4532D}
+ { 0x243955e0, 0x75d9, 0x4cc3, { 0x9b, 0x28, 0x6f, 0x9c, 0x5a, 0xf4, 0x53, 0x2d } }
+};
+
+CMPlugin::CMPlugin() :
+ PLUGIN<CMPlugin>(MODULENAME, pluginInfoEx)
+{
+ RegisterProtocol(PROTOTYPE_VIRTUAL);
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+
+INT_PTR GetCaps(WPARAM wParam, LPARAM)
+{
+ if (wParam == PFLAGNUM_2 && opt.ShowCustomIcon)
+ return PF2_ONLINE | PF2_LIGHTDND | PF2_SHORTAWAY;
+
+ return 0;
+}
+
+INT_PTR GetStatus(WPARAM, LPARAM)
+{
+ return ID_STATUS_ONLINE;
+}
+
+INT_PTR GetName(WPARAM wParam, LPARAM lParam)
+{
+ mir_strncpy((char*)lParam, MODULENAME, wParam);
+ return 0;
+}
+
+void CALLBACK TimerProc(HWND, UINT, UINT_PTR, DWORD)
+{
+ PluginMenuCommand(0, 0);
+}
+
+INT_PTR PluginMenuCommand(WPARAM hContact, LPARAM)
+{
+ if (!optionWindowIsOpen)
+ mir_forkthread(Check_ThreadFunc, GetAccountByContact(hContact));
+
+ return 0;
+}
+
+static int OnMirandaStart(WPARAM, LPARAM)
+{
+ PluginMenuCommand(0, 0);
+ return 0;
+}
+
+int CMPlugin::Load()
+{
+ g_plugin.addSound("Gmail", LPGENW("Other"), LPGENW("Gmail: New thread(s)"));
+ HookEvent(ME_CLIST_DOUBLECLICKED, OpenBrowser);
+
+ NETLIBUSER nlu = {};
+ nlu.flags = NUF_OUTGOING | NUF_HTTPCONNS | NUF_NOHTTPSOPTION | NUF_UNICODE;
+ nlu.szSettingsModule = MODULENAME;
+ nlu.szDescriptiveName.w = TranslateT("Gmail Notifier connection");
+ hNetlibUser = Netlib_RegisterUser(&nlu);
+
+ CreateProtoServiceFunction(MODULENAME, PS_GETCAPS, GetCaps);
+ CreateProtoServiceFunction(MODULENAME, PS_GETSTATUS, GetStatus);
+ CreateProtoServiceFunction(MODULENAME, PS_GETNAME, GetName);
+ CreateServiceFunction("GmailMNotifier/Notifying", Notifying);
+
+ opt.circleTime = g_plugin.getDword("circleTime", 30);
+ opt.notifierOnTray = g_plugin.getDword("notifierOnTray", TRUE);
+ opt.notifierOnPop = g_plugin.getDword("notifierOnPop", TRUE);
+ opt.popupDuration = g_plugin.getDword("popupDuration", -1);
+ opt.popupBgColor = g_plugin.getDword("popupBgColor", RGB(173, 206, 247));
+ opt.popupTxtColor = g_plugin.getDword("popupTxtColor", RGB(0, 0, 0));
+ opt.OpenUsePrg = g_plugin.getDword("OpenUsePrg", 0);
+ opt.ShowCustomIcon = g_plugin.getDword("ShowCustomIcon", FALSE);
+ opt.UseOnline = g_plugin.getDword("UseOnline", FALSE);
+ opt.AutoLogin = g_plugin.getDword("AutoLogin", TRUE);
+ opt.LogThreads = g_plugin.getDword("LogThreads", FALSE);
+
+ DBVARIANT dbv;
+ if (db_get_s(0, "SkinIcons", "core_status_" MODULENAME "4", &dbv)) {
+ db_set_s(0, "SkinIcons", "core_status_" MODULENAME "0", "plugins\\GmailNotifier.dll,2");
+ db_set_s(0, "SkinIcons", "core_status_" MODULENAME "1", "plugins\\GmailNotifier.dll,2");
+ db_set_s(0, "SkinIcons", "core_status_" MODULENAME "2", "plugins\\GmailNotifier.dll,0");
+ db_set_s(0, "SkinIcons", "core_status_" MODULENAME "4", "plugins\\GmailNotifier.dll,1");
+ }
+ else db_free(&dbv);
+
+ BuildList();
+ ID_STATUS_NONEW = opt.UseOnline ? ID_STATUS_ONLINE : ID_STATUS_OFFLINE;
+ for (auto &it : g_accs)
+ db_set_dw(it->hContact, MODULENAME, "Status", ID_STATUS_NONEW);
+
+ hTimer = SetTimer(nullptr, 0, opt.circleTime * 60000, TimerProc);
+ HookEvent(ME_SYSTEM_MODULESLOADED, OnMirandaStart);
+ HookEvent(ME_OPT_INITIALISE, OptInit);
+
+ CreateServiceFunction(MODULENAME "/MenuCommand", PluginMenuCommand);
+
+ CMenuItem mi(&g_plugin);
+ SET_UID(mi, 0xbe16f37, 0x17be, 0x4494, 0xaa, 0xb2, 0x3a, 0xa7, 0x38, 0xfa, 0xf9, 0xcc);
+ mi.position = -0x7FFFFFFF;
+ mi.hIcolibItem = Skin_LoadProtoIcon(MODULENAME, ID_STATUS_ONLINE);
+ mi.name.a = LPGEN("&Check all Gmail inboxes");
+ mi.pszService = MODULENAME "/MenuCommand";
+ Menu_AddMainMenuItem(&mi);
+
+ SET_UID(mi, 0x22c6ace1, 0xba0c, 0x44b5, 0xa4, 0xd2, 0x1, 0x7d, 0xb1, 0xe0, 0x51, 0xeb);
+ mi.name.a = LPGEN("&Check Gmail inbox");
+ mi.pszService = "/MenuCommand";
+ Menu_AddContactMenuItem(&mi, MODULENAME);
+ return 0;
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+
+int CMPlugin::Unload()
+{
+ if (hTimer)
+ KillTimer(nullptr, hTimer);
+
+ for (auto &it : g_accs)
+ DeleteResults(it->results.next);
+ g_accs.destroy();
+
+ Netlib_CloseHandle(hNetlibUser);
+ return 0;
+}
diff --git a/protocols/GmailNotifier/src/notify.cpp b/protocols/GmailNotifier/src/notify.cpp
new file mode 100644
index 0000000000..54b47560a6
--- /dev/null
+++ b/protocols/GmailNotifier/src/notify.cpp
@@ -0,0 +1,206 @@
+#include "stdafx.h"
+
+static void __cdecl Login_ThreadFunc(Account *curAcc)
+{
+ if (curAcc == nullptr)
+ return;
+
+ HANDLE hTempFile;
+ DWORD dwBytesWritten, dwBufSize = 1024;
+ char szTempName[MAX_PATH];
+ char buffer[1024];
+ char *str_temp;
+ char lpPathBuffer[1024];
+
+ if (GetBrowser(lpPathBuffer)) {
+ if (opt.AutoLogin == 0) {
+ if (curAcc->hosted[0]) {
+ mir_strcat(lpPathBuffer, "https://mail.google.com/a/");
+ mir_strcat(lpPathBuffer, curAcc->hosted);
+ mir_strcat(lpPathBuffer, "/?logout");
+ }
+ else {
+ mir_strcat(lpPathBuffer, "https://mail.google.com/mail/?logout");
+ }
+ }
+ else {
+ if (curAcc->hosted[0]) {
+ GetTempPathA(dwBufSize, buffer);
+ GetTempFileNameA(buffer, "gmail", 0, szTempName);
+
+ hTempFile = CreateFileA(szTempName, GENERIC_WRITE, 0, nullptr, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, nullptr);
+ mir_strcpy(buffer, FORMDATA1);
+ mir_strcat(buffer, curAcc->hosted);
+ mir_strcat(buffer, FORMDATA2);
+ mir_strcat(buffer, curAcc->hosted);
+ mir_strcat(buffer, FORMDATA3);
+ mir_strcat(buffer, "<input type=hidden name=userName value=");
+ mir_strcat(buffer, curAcc->name);
+ if ((str_temp = strstr(buffer, "@")) != nullptr)
+ *str_temp = '\0';
+ mir_strcat(buffer, "><input type=hidden name=password value=");
+ mir_strcat(buffer, curAcc->pass);
+ mir_strcat(buffer, "></form></body>");
+ WriteFile(hTempFile, buffer, (DWORD)mir_strlen(buffer), &dwBytesWritten, nullptr);
+ CloseHandle(hTempFile);
+ mir_strcat(lpPathBuffer, szTempName);
+ }
+ else {
+ mir_strcat(lpPathBuffer, LINK);
+ mir_strcat(lpPathBuffer, mir_urlEncode(curAcc->name));
+ if (opt.AutoLogin == 1)
+ mir_strcat(lpPathBuffer, "&PersistentCookie=yes");
+ }
+ }
+ }
+
+ STARTUPINFOA suInfo = { 0 };
+ PROCESS_INFORMATION procInfo;
+ suInfo.cb = sizeof(suInfo);
+ suInfo.wShowWindow = SW_MAXIMIZE;
+ if (CreateProcessA(nullptr, lpPathBuffer, nullptr, nullptr, FALSE, 0, nullptr, nullptr, &suInfo, &procInfo))
+ CloseHandle(procInfo.hProcess);
+
+ if (curAcc->hosted[0]) {
+ Sleep(30000);
+ DeleteFileA(szTempName);
+ }
+}
+
+int OpenBrowser(WPARAM hContact, LPARAM)
+{
+ char *proto = GetContactProto(hContact);
+ if (proto && !mir_strcmp(proto, MODULENAME)) {
+ Account *curAcc = GetAccountByContact(hContact);
+ PUDeletePopup(curAcc->popUpHwnd);
+ g_clistApi.pfnRemoveEvent(curAcc->hContact, 1);
+ if (GetKeyState(VK_SHIFT) >> 8 || optionWindowIsOpen)
+ return FALSE;
+
+ if (curAcc->oldResults_num != 0) {
+ g_plugin.setWord(curAcc->hContact, "Status", ID_STATUS_NONEW);
+ curAcc->oldResults_num = 0;
+ DeleteResults(curAcc->results.next);
+ curAcc->results.next = nullptr;
+ }
+ mir_forkThread<Account>(Login_ThreadFunc, curAcc);
+ }
+ return FALSE;
+}
+
+INT_PTR Notifying(WPARAM, LPARAM lParam)
+{
+ OpenBrowser(((CLISTEVENT*)lParam)->hContact, 0);
+ return 0;
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+
+static LRESULT CALLBACK PopupDlgProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
+{
+ MCONTACT hContact = PUGetContact(hWnd);
+ Account *curAcc = GetAccountByContact(hContact);
+
+ switch (message) {
+ case UM_INITPOPUP:
+ curAcc->popUpHwnd = hWnd;
+ break;
+
+ case WM_COMMAND:
+ if (HIWORD(wParam) == STN_CLICKED)
+ OpenBrowser((WPARAM)hContact, 0);
+ break;
+
+ case WM_CONTEXTMENU:
+ PUDeletePopup(hWnd);
+ curAcc->popUpHwnd = nullptr;
+ g_clistApi.pfnRemoveEvent(hContact, 1);
+ }
+ return DefWindowProc(hWnd, message, wParam, lParam);
+}
+
+void NotifyUser(Account *curAcc)
+{
+ if (optionWindowIsOpen)
+ return;
+
+ db_set_s(curAcc->hContact, "CList", "MyHandle", curAcc->results.content);
+ switch (curAcc->results_num) {
+ case 0:
+ PUDeletePopup(curAcc->popUpHwnd);
+ g_clistApi.pfnRemoveEvent(curAcc->hContact, 1);
+ if (curAcc->oldResults_num != 0)
+ g_plugin.setWord(curAcc->hContact, "Status", ID_STATUS_NONEW);
+ break;
+
+ case -1:
+ g_plugin.setWord(curAcc->hContact, "Status", ID_STATUS_AWAY);
+ break;
+
+ default:
+ g_plugin.setWord(curAcc->hContact, "Status", ID_STATUS_OCCUPIED);
+ int newMails = (curAcc->oldResults_num == -1) ? (curAcc->results_num) : (curAcc->results_num - curAcc->oldResults_num);
+ if (opt.LogThreads&&newMails > 0) {
+ DBEVENTINFO dbei = {};
+ dbei.eventType = EVENTTYPE_MESSAGE;
+ dbei.flags = DBEF_READ;
+ dbei.szModule = MODULENAME;
+ dbei.timestamp = time(0);
+
+ resultLink *prst = curAcc->results.next;
+ for (int i = 0; i < newMails; i++) {
+ dbei.cbBlob = (DWORD)mir_strlen(prst->content) + 1;
+ dbei.pBlob = (PBYTE)prst->content;
+ db_event_add(curAcc->hContact, &dbei);
+ prst = prst->next;
+ }
+ }
+ if (opt.notifierOnTray&&newMails > 0) {
+ g_clistApi.pfnRemoveEvent(curAcc->hContact, 1);
+
+ CLISTEVENT cle = {};
+ cle.hContact = curAcc->hContact;
+ cle.hDbEvent = 1;
+ cle.flags = CLEF_URGENT;
+ cle.hIcon = Skin_LoadProtoIcon(MODULENAME, ID_STATUS_OCCUPIED);
+ cle.pszService = "GmailMNotifier/Notifying";
+ cle.szTooltip.a = curAcc->results.next->content;
+ g_clistApi.pfnAddEvent(&cle);
+ }
+
+ if (opt.notifierOnPop&&newMails > 0) {
+ POPUPDATA ppd = { 0 };
+
+ ppd.lchContact = curAcc->hContact;
+ ppd.lchIcon = Skin_LoadProtoIcon(MODULENAME, ID_STATUS_OCCUPIED);
+ mir_strcpy(ppd.lpzContactName, curAcc->results.content);
+ resultLink *prst = curAcc->results.next;
+ for (int i = 0; i < 5 && i < newMails; i++) {
+ mir_strcat(ppd.lpzText, prst->content);
+ mir_strcat(ppd.lpzText, "\n");
+ prst = prst->next;
+ }
+ ppd.colorBack = opt.popupBgColor;
+ ppd.colorText = opt.popupTxtColor;
+ ppd.PluginWindowProc = PopupDlgProc;
+ ppd.PluginData = nullptr;
+ ppd.iSeconds = opt.popupDuration;
+ PUDeletePopup(curAcc->popUpHwnd);
+ PUAddPopup(&ppd);
+ }
+ if (newMails > 0)
+ Skin_PlaySound("Gmail");
+ }
+ curAcc->oldResults_num = curAcc->results_num;
+ DeleteResults(curAcc->results.next);
+ curAcc->results.next = nullptr;
+}
+
+void DeleteResults(resultLink *prst)
+{
+ if (prst != nullptr) {
+ if (prst->next != nullptr)
+ DeleteResults(prst->next);
+ free(prst);
+ }
+}
diff --git a/protocols/GmailNotifier/src/options.cpp b/protocols/GmailNotifier/src/options.cpp
new file mode 100644
index 0000000000..3d83fe4671
--- /dev/null
+++ b/protocols/GmailNotifier/src/options.cpp
@@ -0,0 +1,284 @@
+#include "stdafx.h"
+
+static void SaveButton(HWND hwndDlg, HWND hwndCombo, int curIndex)
+{
+ if (curIndex < 0 || curIndex >= g_accs.getCount())
+ return;
+
+ Account &acc = g_accs[curIndex];
+ if (GetDlgItemTextA(hwndDlg, IDC_NAME, acc.name, _countof(acc.name))) {
+ char *tail = strstr(acc.name, "@");
+ if (tail && mir_strcmp(tail + 1, "gmail.com") != 0)
+ mir_strcpy(acc.hosted, tail + 1);
+ SendMessageA(hwndCombo, CB_DELETESTRING, curIndex, 0);
+ SendMessageA(hwndCombo, CB_INSERTSTRING, curIndex, (LPARAM)acc.name);
+ SendMessageA(hwndCombo, CB_SETCURSEL, curIndex, 0);
+ g_plugin.setString(acc.hContact, "name", acc.name);
+ g_plugin.setString(acc.hContact, "Nick", acc.name);
+
+ GetDlgItemTextA(hwndDlg, IDC_PASS, acc.pass, _countof(acc.pass));
+ g_plugin.setString(acc.hContact, "Password", acc.pass);
+ }
+}
+
+static INT_PTR CALLBACK DlgProcOpts(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam)
+{
+ int ShowControl;
+ char str[MAX_PATH] = { 0 };
+ static int curIndex = 0;
+ static bool bInit = false;
+ HWND hwndCombo = GetDlgItem(hwndDlg, IDC_NAME);
+
+ if (g_accs.getCount()) {
+ EnableWindow(hwndCombo, TRUE);
+ EnableWindow(GetDlgItem(hwndDlg, IDC_PASS), TRUE);
+ EnableWindow(GetDlgItem(hwndDlg, IDC_BTNSAV), TRUE);
+ EnableWindow(GetDlgItem(hwndDlg, IDC_BTNDEL), TRUE);
+ }
+ else {
+ EnableWindow(hwndCombo, FALSE);
+ EnableWindow(GetDlgItem(hwndDlg, IDC_PASS), FALSE);
+ EnableWindow(GetDlgItem(hwndDlg, IDC_BTNSAV), FALSE);
+ EnableWindow(GetDlgItem(hwndDlg, IDC_BTNDEL), FALSE);
+ }
+
+ switch (msg) {
+ case WM_INITDIALOG:
+ bInit = true;
+ TranslateDialogDefault(hwndDlg);
+ optionWindowIsOpen = TRUE;
+ BuildList();
+
+ for (auto &it : g_accs)
+ SendMessageA(hwndCombo, CB_ADDSTRING, 0, (LONG_PTR)it->name);
+ SendMessage(hwndCombo, CB_SETCURSEL, curIndex, 0);
+ if (curIndex < g_accs.getCount())
+ SetDlgItemTextA(hwndDlg, IDC_PASS, g_accs[curIndex].pass);
+
+ SetDlgItemInt(hwndDlg, IDC_CIRCLE, opt.circleTime, FALSE);
+ if (opt.notifierOnTray)
+ CheckDlgButton(hwndDlg, IDC_OPTTRAY, BST_CHECKED);
+ if (opt.notifierOnPop) {
+ CheckDlgButton(hwndDlg, IDC_OPTPOP, BST_CHECKED);
+ ShowWindow(GetDlgItem(hwndDlg, IDC_DURATION), SW_SHOW);
+ ShowWindow(GetDlgItem(hwndDlg, IDC_BGCOLOR), SW_SHOW);
+ ShowWindow(GetDlgItem(hwndDlg, IDC_TEXTCOLOR), SW_SHOW);
+ ShowWindow(GetDlgItem(hwndDlg, IDC_STATIC_DURATION), SW_SHOW);
+ ShowWindow(GetDlgItem(hwndDlg, IDC_STATIC_COLOR), SW_SHOW);
+ ShowWindow(GetDlgItem(hwndDlg, IDC_STATIC_LESS), SW_SHOW);
+ ShowWindow(GetDlgItem(hwndDlg, IDC_STATIC_SEC), SW_SHOW);
+ }
+
+ SetDlgItemInt(hwndDlg, IDC_DURATION, opt.popupDuration, TRUE);
+ SendDlgItemMessage(hwndDlg, IDC_BGCOLOR, CPM_SETCOLOUR, 0, opt.popupBgColor);
+ SendDlgItemMessage(hwndDlg, IDC_TEXTCOLOR, CPM_SETCOLOUR, 0, opt.popupTxtColor);
+
+ if (opt.OpenUsePrg == 0)
+ CheckDlgButton(hwndDlg, IDC_SYSDEF, BST_CHECKED);
+ else if (opt.OpenUsePrg == 1)
+ CheckDlgButton(hwndDlg, IDC_USEIE, BST_CHECKED);
+ else if (opt.OpenUsePrg == 2) {
+ CheckDlgButton(hwndDlg, IDC_STARTPRG, BST_CHECKED);
+ ShowWindow(GetDlgItem(hwndDlg, IDC_PRG), SW_SHOW);
+ ShowWindow(GetDlgItem(hwndDlg, IDC_PRGBROWSE), SW_SHOW);
+ }
+ {
+ DBVARIANT dbv;
+ if (!g_plugin.getString("OpenUsePrgPath", &dbv)) {
+ mir_strcpy(str, dbv.pszVal);
+ db_free(&dbv);
+ }
+ }
+ SetDlgItemTextA(hwndDlg, IDC_PRG, str);
+
+ if (opt.UseOnline)
+ CheckDlgButton(hwndDlg, IDC_ONLINE, BST_CHECKED);
+ if (opt.ShowCustomIcon)
+ CheckDlgButton(hwndDlg, IDC_SHOWICON, BST_CHECKED);
+ if (opt.AutoLogin == 0)
+ CheckDlgButton(hwndDlg, IDC_AUTOLOGIN, BST_CHECKED);
+ else if (opt.AutoLogin == 1)
+ CheckDlgButton(hwndDlg, IDC_AUTOLOGIN, BST_UNCHECKED);
+ else if (opt.AutoLogin == 2)
+ CheckDlgButton(hwndDlg, IDC_AUTOLOGIN, BST_INDETERMINATE);
+ if (opt.LogThreads)
+ CheckDlgButton(hwndDlg, IDC_LOGTHREADS, BST_CHECKED);
+
+ bInit = false;
+ return TRUE;
+
+ case WM_COMMAND:
+ switch (LOWORD(wParam)) {
+ case IDC_SYSDEF:
+ case IDC_USEIE:
+ case IDC_STARTPRG:
+ ShowControl = IsDlgButtonChecked(hwndDlg, IDC_STARTPRG) ? SW_SHOW : SW_HIDE;
+ ShowWindow(GetDlgItem(hwndDlg, IDC_PRG), ShowControl);
+ ShowWindow(GetDlgItem(hwndDlg, IDC_PRGBROWSE), ShowControl);
+ SendMessage(GetParent(hwndDlg), PSM_CHANGED, 0, 0);
+ break;
+
+ case IDC_OPTPOP:
+ ShowControl = IsDlgButtonChecked(hwndDlg, IDC_OPTPOP) ? SW_SHOW : SW_HIDE;
+ ShowWindow(GetDlgItem(hwndDlg, IDC_DURATION), ShowControl);
+ ShowWindow(GetDlgItem(hwndDlg, IDC_BGCOLOR), ShowControl);
+ ShowWindow(GetDlgItem(hwndDlg, IDC_TEXTCOLOR), ShowControl);
+ ShowWindow(GetDlgItem(hwndDlg, IDC_STATIC_DURATION), ShowControl);
+ ShowWindow(GetDlgItem(hwndDlg, IDC_STATIC_COLOR), ShowControl);
+ ShowWindow(GetDlgItem(hwndDlg, IDC_STATIC_LESS), ShowControl);
+ ShowWindow(GetDlgItem(hwndDlg, IDC_STATIC_SEC), ShowControl);
+ SendMessage(GetParent(hwndDlg), PSM_CHANGED, 0, 0);
+ break;
+
+ case IDC_PRGBROWSE:
+ wchar_t szName[_MAX_PATH];
+ GetDlgItemText(hwndDlg, IDC_PRG, szName, _countof(szName));
+ {
+ OPENFILENAME OpenFileName = {};
+ OpenFileName.lStructSize = sizeof(OPENFILENAME);
+ OpenFileName.hwndOwner = hwndDlg;
+ OpenFileName.lpstrFilter = L"Executables (*.exe;*.com;*.bat)\0*.exe;*.com;*.bat\0\0";
+ OpenFileName.lpstrFile = szName;
+ OpenFileName.nMaxFile = _countof(szName);
+ OpenFileName.Flags = OFN_EXPLORER | OFN_PATHMUSTEXIST | OFN_HIDEREADONLY | OFN_FILEMUSTEXIST;
+ if (!GetOpenFileName(&OpenFileName))
+ return 0;
+ SetDlgItemText(hwndDlg, IDC_PRG, szName);
+ }
+ SendMessage(GetParent(hwndDlg), PSM_CHANGED, 0, 0);
+ break;
+
+ case IDC_BTNADD:
+ {
+ Account *p = new Account();
+ p->hContact = db_add_contact();
+ Proto_AddToContact(p->hContact, MODULENAME);
+ g_accs.insert(p);
+
+ curIndex = SendMessageA(hwndCombo, CB_ADDSTRING, 0, (LPARAM)"");
+ SendMessage(hwndCombo, CB_SETCURSEL, curIndex, 0);
+ SetDlgItemTextA(hwndDlg, IDC_PASS, "");
+ SetFocus(hwndCombo);
+ }
+ SendMessage(GetParent(hwndDlg), PSM_CHANGED, 0, 0);
+ break;
+
+ case IDC_BTNSAV:
+ SaveButton(hwndDlg, hwndCombo, curIndex);
+ SendMessage(GetParent(hwndDlg), PSM_CHANGED, 0, 0);
+ break;
+
+ case IDC_BTNDEL:
+ {
+ SendMessage(hwndCombo, CB_DELETESTRING, curIndex, 0);
+
+ Account &acc = g_accs[curIndex];
+ DeleteResults(acc.results.next);
+ db_delete_contact(acc.hContact);
+ g_accs.remove(curIndex);
+
+ curIndex = 0;
+ SendMessage(hwndCombo, CB_SETCURSEL, 0, 0);
+ if (g_accs.getCount())
+ SetDlgItemTextA(hwndDlg, IDC_PASS, g_accs[0].pass);
+ }
+ SendMessage(GetParent(hwndDlg), PSM_CHANGED, 0, 0);
+ break;
+
+ case IDC_NAME:
+ if (HIWORD(wParam) == CBN_SELCHANGE) {
+ curIndex = SendMessage(hwndCombo, CB_GETCURSEL, 0, 0);
+ SetDlgItemTextA(hwndDlg, IDC_PASS, g_accs[curIndex].pass);
+ SendMessage(GetParent(hwndDlg), PSM_CHANGED, 0, 0);
+ }
+ break;
+
+ case IDC_CIRCLE:
+ case IDC_DURATION:
+ if (!bInit && (HIWORD(wParam) == EN_CHANGE))
+ SendMessage(GetParent(hwndDlg), PSM_CHANGED, 0, 0);
+ break;
+
+ case IDC_ONLINE:
+ case IDC_SHOWICON:
+ case IDC_AUTOLOGIN:
+ case IDC_LOGTHREADS:
+ SendMessage(GetParent(hwndDlg), PSM_CHANGED, 0, 0);
+ }
+
+ return TRUE;
+
+ case WM_NOTIFY:
+ switch (((LPNMHDR)lParam)->code) {
+ case PSN_APPLY:
+ SaveButton(hwndDlg, hwndCombo, curIndex);
+ opt.circleTime = GetDlgItemInt(hwndDlg, IDC_CIRCLE, nullptr, FALSE);
+ if (opt.circleTime > 0) {
+ KillTimer(nullptr, hTimer);
+ hTimer = SetTimer(nullptr, 0, opt.circleTime * 60000, TimerProc);
+ g_plugin.setDword("circleTime", opt.circleTime);
+ }
+ opt.notifierOnTray = IsDlgButtonChecked(hwndDlg, IDC_OPTTRAY);
+ opt.notifierOnPop = IsDlgButtonChecked(hwndDlg, IDC_OPTPOP);
+ g_plugin.setDword("notifierOnTray", opt.notifierOnTray);
+ g_plugin.setDword("notifierOnPop", opt.notifierOnPop);
+
+ opt.popupDuration = GetDlgItemInt(hwndDlg, IDC_DURATION, nullptr, TRUE);
+ g_plugin.setDword("popupDuration", opt.popupDuration);
+
+ opt.popupBgColor = SendDlgItemMessage(hwndDlg, IDC_BGCOLOR, CPM_GETCOLOUR, 0, opt.popupBgColor);
+ opt.popupTxtColor = SendDlgItemMessage(hwndDlg, IDC_TEXTCOLOR, CPM_GETCOLOUR, 0, opt.popupBgColor);
+ g_plugin.setDword("popupBgColor", opt.popupBgColor);
+ g_plugin.setDword("popupTxtColor", opt.popupTxtColor);
+
+ if (IsDlgButtonChecked(hwndDlg, IDC_SYSDEF) == BST_CHECKED)
+ opt.OpenUsePrg = 0;
+ else if (IsDlgButtonChecked(hwndDlg, IDC_USEIE) == BST_CHECKED)
+ opt.OpenUsePrg = 1;
+ else if (IsDlgButtonChecked(hwndDlg, IDC_STARTPRG) == BST_CHECKED) {
+ opt.OpenUsePrg = 2;
+ }
+ GetDlgItemTextA(hwndDlg, IDC_PRG, str, _countof(str));
+
+ g_plugin.setDword("OpenUsePrg", opt.OpenUsePrg);
+ g_plugin.setString("OpenUsePrgPath", str);
+
+ opt.ShowCustomIcon = IsDlgButtonChecked(hwndDlg, IDC_SHOWICON);
+ opt.UseOnline = IsDlgButtonChecked(hwndDlg, IDC_ONLINE);
+ if (IsDlgButtonChecked(hwndDlg, IDC_AUTOLOGIN) == BST_CHECKED)
+ opt.AutoLogin = 0;
+ else if (IsDlgButtonChecked(hwndDlg, IDC_AUTOLOGIN) == BST_UNCHECKED)
+ opt.AutoLogin = 1;
+ else if (IsDlgButtonChecked(hwndDlg, IDC_AUTOLOGIN) == BST_INDETERMINATE)
+ opt.AutoLogin = 2;
+ opt.LogThreads = IsDlgButtonChecked(hwndDlg, IDC_LOGTHREADS);
+ g_plugin.setDword("ShowCustomIcon", opt.ShowCustomIcon);
+ g_plugin.setDword("UseOnline", opt.UseOnline);
+ g_plugin.setDword("AutoLogin", opt.AutoLogin);
+ g_plugin.setDword("LogThreads", opt.LogThreads);
+
+ ID_STATUS_NONEW = opt.UseOnline ? ID_STATUS_ONLINE : ID_STATUS_OFFLINE;
+ for (auto &it : g_accs)
+ g_plugin.setWord(it->hContact, "Status", ID_STATUS_NONEW);
+ }
+ return TRUE;
+
+ case WM_CLOSE:
+ optionWindowIsOpen = FALSE;
+ return TRUE;
+ }
+ return FALSE;
+}
+
+int OptInit(WPARAM wParam, LPARAM)
+{
+ OPTIONSDIALOGPAGE odp = {};
+ odp.position = -790000000;
+ odp.pszTemplate = MAKEINTRESOURCEA(IDD_OPT);
+ odp.szTitle.a = LPGEN("GmailNotifier");
+ odp.szGroup.a = LPGEN("Network");
+ odp.flags = ODPF_BOLDGROUPS;
+ odp.pfnDlgProc = DlgProcOpts;
+ g_plugin.addOptions(wParam, &odp);
+ return 0;
+}
diff --git a/protocols/GmailNotifier/src/resource.h b/protocols/GmailNotifier/src/resource.h
new file mode 100644
index 0000000000..7979aabf00
--- /dev/null
+++ b/protocols/GmailNotifier/src/resource.h
@@ -0,0 +1,47 @@
+//{{NO_DEPENDENCIES}}
+// Microsoft Visual C++ generated include file.
+// Used by C:\Users\xx\Documents\Visual Studio 2010\Projects\miranda-ng\plugins\GmailNotifier\res\options.rc
+//
+#define IDD_OPT 101
+#define IDI_ICONNEW 106
+#define IDI_ICONERR 109
+#define IDI_ICONEPT 111
+#define IDC_GROUPMAIN 1000
+#define IDC_CONFIG 1001
+#define IDC_CONFIRM 1002
+#define IDC_OPTTRAY 1002
+#define IDC_OPTPOP 1003
+#define IDC_USEIE 1004
+#define IDC_STATIC_DURATION 1006
+#define IDC_BGCOLOR 1007
+#define IDC_TEXTCOLOR 1008
+#define IDC_PRG 1009
+#define IDC_SYSDEF 1010
+#define IDC_STARTPRG 1011
+#define IDC_PRGBROWSE 1012
+#define IDC_STATIC_COLOR 1014
+#define IDC_STATIC_LESS 1016
+#define IDC_STATIC_SEC 1017
+#define IDC_STATIC_CUSTOM 1018
+#define IDC_BTNADD 1019
+#define IDC_PASS 1020
+#define IDC_BTNSAV 1021
+#define IDC_NAME 1022
+#define IDC_CIRCLE 1023
+#define IDC_DURATION 1024
+#define IDC_SHOWICON 1025
+#define IDC_BTNDEL 1026
+#define IDC_AUTOLOGIN 1028
+#define IDC_LOGTHREADS 1029
+#define IDC_ONLINE 1036
+
+// Next default values for new objects
+//
+#ifdef APSTUDIO_INVOKED
+#ifndef APSTUDIO_READONLY_SYMBOLS
+#define _APS_NEXT_RESOURCE_VALUE 113
+#define _APS_NEXT_COMMAND_VALUE 40001
+#define _APS_NEXT_CONTROL_VALUE 1008
+#define _APS_NEXT_SYMED_VALUE 101
+#endif
+#endif
diff --git a/protocols/GmailNotifier/src/stdafx.cxx b/protocols/GmailNotifier/src/stdafx.cxx
new file mode 100644
index 0000000000..1b563fc866
--- /dev/null
+++ b/protocols/GmailNotifier/src/stdafx.cxx
@@ -0,0 +1,18 @@
+/*
+Copyright (C) 2012-19 Miranda NG team (https://miranda-ng.org)
+
+This program is free software; you can redistribute it and/or
+modify it under the terms of the GNU General Public License
+as published by the Free Software Foundation version 2
+of the License.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "stdafx.h" \ No newline at end of file
diff --git a/protocols/GmailNotifier/src/stdafx.h b/protocols/GmailNotifier/src/stdafx.h
new file mode 100644
index 0000000000..da6bc1039d
--- /dev/null
+++ b/protocols/GmailNotifier/src/stdafx.h
@@ -0,0 +1,100 @@
+#pragma once
+
+#include <windows.h>
+#include <time.h>
+#include <stdio.h>
+#include "resource.h"
+
+#include "newpluginapi.h"
+#include "m_clistint.h"
+#include "m_skin.h"
+#include "m_langpack.h"
+#include "m_database.h"
+#include "m_system.h"
+#include "m_protocols.h"
+#include "m_userinfo.h"
+#include "m_options.h"
+#include "m_protosvc.h"
+#include "m_utils.h"
+#include "m_ignore.h"
+#include "m_clc.h"
+#include "m_popup.h"
+#include "m_netlib.h"
+
+#define WM_SHELLNOTIFY WM_USER+5
+#define IDI_TRAY WM_USER+6
+#define MODULENAME "GmailMNotifier"
+#define _MAX_DOWN_BUFFER 65536
+#define LINK "https://accounts.google.com/ServiceLogin?continue=https%3A%2F%2Fmail.google.com%2Fmail&service=mail&passive=true&Email="
+#define FORMDATA1 "<body onload=document.gmail.submit();><form name=gmail action=https://www.google.com/a/"
+#define FORMDATA2 "/LoginAction method=POST><input type=hidden name=continue value=https://mail.google.com/a/"
+#define FORMDATA3 "><INPUT type=hidden value=mail name=service>"
+// #define STR1 "javascript:document.write('<form name=gmail action=https://www.google.com/a/"
+// #define STR2 "/LoginAction method=post><input type=hidden name=continue value=https://mail.google.com/hosted/"
+// #define STR3 "><input type=hidden value=mail name=service><input type=hidden name=userName value="
+// #define STR4 "><input type=hidden name=password value="
+// #define STR5 ">');document.gmail.submit();"
+//#define LINK2 "https://www.google.com/a/altmanoptik.com/LoginAction?continue=https%3A%2F%2Fmail.google.com%2Fhosted%2Faltmanoptik.com&service=mail&userName=test&password=123456"
+
+struct resultLink
+{
+ char content[64];
+ struct resultLink *next;
+};
+
+struct Account : public MZeroedObject
+{
+ char name[256];
+ char pass[256];
+ char hosted[64];
+ MCONTACT hContact;
+ int oldResults_num;
+ int results_num;
+ resultLink results;
+ HWND popUpHwnd;
+ bool IsChecking;
+};
+
+struct optionSettings
+{
+ int circleTime;
+ BOOL notifierOnTray;
+ BOOL notifierOnPop;
+ int popupDuration;
+ COLORREF popupTxtColor;
+ COLORREF popupBgColor;
+ int OpenUsePrg;
+ BOOL ShowCustomIcon;
+ BOOL UseOnline;
+ int AutoLogin;
+ BOOL LogThreads;
+};
+
+extern OBJLIST<Account> g_accs;
+extern optionSettings opt;
+extern HNETLIBUSER hNetlibUser;
+extern UINT hTimer;
+extern short ID_STATUS_NONEW;
+extern BOOL optionWindowIsOpen;
+
+INT_PTR Notifying(WPARAM, LPARAM);
+INT_PTR PluginMenuCommand(WPARAM, LPARAM);
+void CALLBACK TimerProc(HWND, UINT, UINT_PTR, DWORD);
+BOOL GetBrowser(char *);
+
+void NotifyUser(Account *);
+int OptInit(WPARAM, LPARAM);
+void Check_ThreadFunc(void *);
+int OpenBrowser(WPARAM, LPARAM);
+void DeleteResults(resultLink *);
+void BuildList(void);
+
+Account* GetAccountByContact(MCONTACT hContact);
+
+struct CMPlugin : public PLUGIN<CMPlugin>
+{
+ CMPlugin();
+
+ int Load() override;
+ int Unload() override;
+};
diff --git a/protocols/GmailNotifier/src/utility.cpp b/protocols/GmailNotifier/src/utility.cpp
new file mode 100644
index 0000000000..cda56e956c
--- /dev/null
+++ b/protocols/GmailNotifier/src/utility.cpp
@@ -0,0 +1,77 @@
+#include "stdafx.h"
+
+void BuildList(void)
+{
+ g_accs.destroy();
+
+ for (auto &hContact : Contacts(MODULENAME)) {
+ ptrA szName(g_plugin.getStringA(hContact, "name"));
+ if (szName != nullptr) {
+ Account *p = new Account;
+ p->hContact = hContact;
+ mir_strcpy(p->name, szName);
+ CallService(MS_IGNORE_IGNORE, hContact, IGNOREEVENT_USERONLINE);
+
+ ptrA szPassword(g_plugin.getStringA(hContact, "Password"));
+ if (szPassword != nullptr)
+ mir_strcpy(p->pass, szPassword);
+ g_accs.insert(p);
+ }
+ }
+
+ for (auto &acc : g_accs) {
+ char *tail = strchr(acc->name, '@');
+ if (tail && mir_strcmp(tail + 1, "gmail.com") != 0)
+ mir_strcpy(acc->hosted, tail + 1);
+ acc->IsChecking = false;
+ }
+}
+
+BOOL GetBrowser(char *str)
+{
+ HKEY hKey = nullptr;
+ char *strKey;
+ char strIE[] = "Applications\\iexplore.exe\\shell\\open\\command";
+ char strDefault[] = "https\\shell\\open\\command";
+ DBVARIANT dbv;
+
+ if (opt.OpenUsePrg == 1)
+ strKey = strIE;
+ else if (opt.OpenUsePrg == 0)
+ strKey = strDefault;
+ else {
+ if (!g_plugin.getString("OpenUsePrgPath", &dbv)) {
+ mir_strcpy(str, dbv.pszVal);
+ db_free(&dbv);
+ }
+ else *str = 0;
+ return FALSE;
+ }
+
+ // Open the registry
+ if (RegOpenKeyExA(HKEY_CLASSES_ROOT, strKey, 0, KEY_READ, &hKey) == ERROR_SUCCESS) {
+ // Data size
+ DWORD cbData = 0;
+ // Get the default value
+ if (RegQueryValueExA(hKey, nullptr, nullptr, nullptr, nullptr, &cbData) == ERROR_SUCCESS && cbData > 0) {
+ if (RegQueryValueExA(hKey, nullptr, nullptr, nullptr, (LPBYTE)str, &cbData) == ERROR_SUCCESS) {
+ if ((strKey = strstr(str, "%1")) != nullptr)
+ *(strKey--) = '\0';
+ if ((strKey = strstr(str, "-")) != nullptr)
+ *(strKey--) = '\0';
+ RegCloseKey(hKey);
+ return TRUE;
+ }
+ }
+ }
+ return FALSE;
+}
+
+Account* GetAccountByContact(MCONTACT hContact)
+{
+ for (auto &it : g_accs)
+ if (it->hContact == hContact)
+ return it;
+
+ return nullptr;
+}
diff --git a/protocols/GmailNotifier/src/version.h b/protocols/GmailNotifier/src/version.h
new file mode 100644
index 0000000000..8eeed10480
--- /dev/null
+++ b/protocols/GmailNotifier/src/version.h
@@ -0,0 +1,13 @@
+#define __MAJOR_VERSION 1
+#define __MINOR_VERSION 0
+#define __RELEASE_NUM 1
+#define __BUILD_NUM 2
+
+#include <stdver.h>
+
+#define __PLUGIN_NAME "Gmail Multiple Notifier"
+#define __FILENAME "GmailNotifier.dll"
+#define __DESCRIPTION "Check your Gmail inboxes locally."
+#define __AUTHOR "Mixwind"
+#define __AUTHORWEB "https://miranda-ng.org/p/GmailNotifier/"
+#define __COPYRIGHT "© 2005 Sun Zhuo"
diff --git a/protocols/LotusNotify/LotusNotify.vcxproj b/protocols/LotusNotify/LotusNotify.vcxproj
new file mode 100644
index 0000000000..067cc095bb
--- /dev/null
+++ b/protocols/LotusNotify/LotusNotify.vcxproj
@@ -0,0 +1,20 @@
+<?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">
+ <ProjectName>LotusNotify</ProjectName>
+ <ProjectGuid>{0E046380-14CA-4C23-A807-8C678519A605}</ProjectGuid>
+ </PropertyGroup>
+ <ImportGroup Label="PropertySheets">
+ <Import Project="$(ProjectDir)..\..\build\vc.common\plugin.props" />
+ </ImportGroup>
+</Project> \ No newline at end of file
diff --git a/protocols/LotusNotify/LotusNotify.vcxproj.filters b/protocols/LotusNotify/LotusNotify.vcxproj.filters
new file mode 100644
index 0000000000..fcae13a9d8
--- /dev/null
+++ b/protocols/LotusNotify/LotusNotify.vcxproj.filters
@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <Import Project="$(ProjectDir)..\..\build\vc.common\common.filters" />
+</Project> \ No newline at end of file
diff --git a/protocols/LotusNotify/res/LotusNotify.rc b/protocols/LotusNotify/res/LotusNotify.rc
new file mode 100644
index 0000000000..b4354a60fa
--- /dev/null
+++ b/protocols/LotusNotify/res/LotusNotify.rc
@@ -0,0 +1,162 @@
+// Microsoft Visual C++ generated resource script.
+//
+#include "..\src\resource.h"
+#include "..\src\version.h"
+
+#define APSTUDIO_READONLY_SYMBOLS
+/////////////////////////////////////////////////////////////////////////////
+//
+// Generated from the TEXTINCLUDE 2 resource.
+//
+//#include "afxres.h"
+#include "windows.h"
+#define IDC_STATIC -1
+/////////////////////////////////////////////////////////////////////////////
+#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(1250)
+#endif //_WIN32
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Icon
+//
+
+// Icon with lowest ID value placed first to ensure application icon
+// remains consistent on all systems.
+IDI_ICON1 ICON "icon1.ico"
+IDI_ICON2 ICON "icon2.ico"
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Dialog
+//
+
+IDD_OPT_LOTUS_CONECTION DIALOGEX 0, 0, 255, 185
+STYLE DS_SETFONT | DS_FIXEDSYS | WS_CHILD
+EXSTYLE WS_EX_CONTROLPARENT
+FONT 8, "MS Shell Dlg", 0, 0, 0x1
+BEGIN
+ GROUPBOX "Lotus connection settings",IDC_STATIC,2,39,251,95
+ LTEXT "Primary server:",IDC_STATIC,8,73,105,8
+ COMBOBOX IDC_SERVER,116,71,131,11,CBS_DROPDOWN | CBS_AUTOHSCROLL |
+ CBS_SORT | CBS_DISABLENOSCROLL | WS_VSCROLL | WS_TABSTOP
+ LTEXT "Secondary server:",IDC_STATIC,8,88,105,9
+ EDITTEXT IDC_SERVERSEC,116,87,131,12,ES_AUTOHSCROLL
+ LTEXT "Database:",IDC_STATIC,8,103,105,9
+ EDITTEXT IDC_DATABASE,116,102,131,12,ES_AUTOHSCROLL
+ LTEXT "Password:",IDC_STATIC,8,118,105,9
+ EDITTEXT IDC_PASSWORD,116,117,131,12,ES_PASSWORD | ES_AUTOHSCROLL
+ PUSHBUTTON "try detect",IDC_BUTTON_DETECT,56,51,62,14,BS_MULTILINE
+ CONTROL "autoregister",IDC_BUTTON_CHECK,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,154,54,90,8
+ GROUPBOX "Check interval:",IDC_STATIC,2,140,251,40
+ EDITTEXT IDC_INTERVAL,8,151,21,12,ES_AUTOHSCROLL
+ LTEXT "min.",IDC_STATIC,32,153,19,8
+ LTEXT "(0-disabled)",IDC_STATIC,55,153,121,8
+ CONTROL "Keep connection on error",IDC_KEEP_CONNEXION_ON_ERROR,
+ "Button",BS_AUTOCHECKBOX | BS_MULTILINE | WS_TABSTOP,9,167,168,8
+END
+
+IDD_OPT_LOTUS_POPUP DIALOGEX 0, 0, 235, 204
+STYLE DS_SETFONT | DS_FIXEDSYS | WS_CHILD
+EXSTYLE WS_EX_CONTROLPARENT
+FONT 8, "MS Shell Dlg", 0, 0, 0x1
+BEGIN
+ CONTROL "Set popup colors",IDC_SETCOLOURS,"Button",
+ BS_AUTOCHECKBOX | WS_GROUP | WS_TABSTOP,5,35,218,8
+ CONTROL "Custom1",IDC_BGCOLOR,"ColourPicker",WS_GROUP | WS_TABSTOP,13,48,10,10
+ LTEXT "Background",IDC_STATIC,28,49,85,8
+ CONTROL "Custom1",IDC_FGCOLOR,"ColourPicker",WS_GROUP | WS_TABSTOP,117,48,10,10
+ LTEXT "Text",IDC_STATIC,132,49,85,8
+ LTEXT "Close after:",IDC_STATIC,5,68,65,8
+ EDITTEXT IDC_INTERVAL1,71,67,21,12,ES_AUTOHSCROLL | WS_GROUP
+ LTEXT "sec (0 default, -1 disabled)",IDC_STATIC,97,68,126,9
+ LTEXT "Left button click cmd:",IDC_STATIC,5,152,113,8
+ EDITTEXT IDC_COMMAND,120,150,103,12,ES_AUTOHSCROLL
+ LTEXT "Command parameters:",IDC_STATIC,5,167,113,8
+ EDITTEXT IDC_PARAMETERS,120,165,103,12,ES_AUTOHSCROLL
+ CONTROL "Show again if still unread",IDC_ONCEONLY,"Button",
+ BS_AUTOCHECKBOX | BS_LEFT | WS_TABSTOP,5,86,218,8
+ CONTROL "...but only if popup not clicked",IDC_NONCLICKEDONLY,"Button",
+ BS_AUTOCHECKBOX | BS_LEFT | WS_TABSTOP,5,98,218,8
+ CONTROL "Show error messages",IDC_SHOWERROR,"Button",
+ BS_AUTOCHECKBOX | BS_LEFT | WS_TABSTOP,5,110,218,8
+ CONTROL "Remember newest message ID and don't show older",IDC_NEWEST,"Button",
+ BS_AUTOCHECKBOX | BS_LEFT | BS_MULTILINE | WS_TABSTOP,5,122,230,8
+ CONTROL "...even if popup not clicked",IDC_REMEMBEREVENNONCLICKED,"Button",
+ BS_AUTOCHECKBOX | BS_LEFT | WS_TABSTOP,5,134,218,8
+ PUSHBUTTON "Clear popups history",IDC_BUTTON_CLEAR,43,185,140,14,BS_CENTER | BS_MULTILINE
+END
+
+IDD_OPT_LOTUS_MISC DIALOGEX 0, 0, 245, 216
+STYLE DS_SETFONT | DS_FIXEDSYS | WS_CHILD
+EXSTYLE WS_EX_CONTROLPARENT
+FONT 8, "MS Shell Dlg", 0, 0, 0x1
+BEGIN
+ GROUPBOX "Filter messages containing the following:",IDC_STATIC,5,20,235,62
+ LTEXT "Sender",IDC_STATIC,9,33,71,8
+ COMBOBOX IDC_FILTER_SENDER,82,32,120,11,CBS_DROPDOWN | CBS_SORT |
+ WS_VSCROLL | WS_TABSTOP
+ PUSHBUTTON "+",IDC_BUTTON_ADD_SENDER_FILTER,206,32,13,12,BS_CENTER
+ PUSHBUTTON "-",IDC_BUTTON_REMOVE_SENDER_FILTER,220,32,13,12,BS_CENTER
+ LTEXT "Subject",IDC_STATIC,9,48,71,8
+ COMBOBOX IDC_FILTER_SUBJECT,82,47,120,11,CBS_DROPDOWN | CBS_SORT |
+ WS_VSCROLL | WS_TABSTOP
+ PUSHBUTTON "+",IDC_BUTTON_ADD_SUBJECT_FILTER,206,47,13,12,BS_CENTER
+ PUSHBUTTON "-",IDC_BUTTON_REMOVE_SUBJECT_FILTER,220,47,13,12,BS_CENTER
+ LTEXT "To / CopyTo",IDC_STATIC,9,63,71,8
+ COMBOBOX IDC_FILTER_TO,82,62,120,11,CBS_DROPDOWN | CBS_SORT |
+ WS_VSCROLL | WS_TABSTOP
+ PUSHBUTTON "+",IDC_BUTTON_ADD_TO_FILTER,206,62,13,12,BS_CENTER
+ PUSHBUTTON "-",IDC_BUTTON_REMOVE_TO_FILTER,220,62,13,12,BS_CENTER
+ GROUPBOX "Offline status mean:",IDC_STATIC,66,95,113,112
+ CONTROL "",IDC_STATUS,"SysListView32",LVS_REPORT |
+ LVS_NOLABELWRAP | LVS_ALIGNLEFT | LVS_NOCOLUMNHEADER |
+ LVS_NOSORTHEADER | WS_TABSTOP,71,105,102,97,
+ WS_EX_CLIENTEDGE
+END
+
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// DESIGNINFO
+//
+
+#ifdef APSTUDIO_INVOKED
+GUIDELINES DESIGNINFO
+BEGIN
+ IDD_OPT_LOTUS_CONECTION, DIALOG
+ BEGIN
+ LEFTMARGIN, 5
+ RIGHTMARGIN, 250
+ TOPMARGIN, 5
+ BOTTOMMARGIN, 180
+ END
+
+ IDD_OPT_LOTUS_POPUP, DIALOG
+ BEGIN
+ LEFTMARGIN, 5
+ RIGHTMARGIN, 223
+ TOPMARGIN, 5
+ BOTTOMMARGIN, 199
+ END
+
+ IDD_OPT_LOTUS_MISC, DIALOG
+ BEGIN
+ LEFTMARGIN, 5
+ RIGHTMARGIN, 240
+ TOPMARGIN, 5
+ BOTTOMMARGIN, 211
+ END
+END
+#endif // APSTUDIO_INVOKED
+
+#endif // Neutral resources
+/////////////////////////////////////////////////////////////////////////////
+
diff --git a/protocols/LotusNotify/res/Version.rc b/protocols/LotusNotify/res/Version.rc
new file mode 100644
index 0000000000..5a5ddd63ed
--- /dev/null
+++ b/protocols/LotusNotify/res/Version.rc
@@ -0,0 +1,9 @@
+// Microsoft Visual C++ generated resource script.
+//
+#ifdef APSTUDIO_INVOKED
+#error this file is not editable by Microsoft Visual C++
+#endif //APSTUDIO_INVOKED
+
+#include "..\src\version.h"
+
+#include "..\..\build\Version.rc"
diff --git a/protocols/LotusNotify/res/icon1.ico b/protocols/LotusNotify/res/icon1.ico
new file mode 100644
index 0000000000..2bb90b9eec
--- /dev/null
+++ b/protocols/LotusNotify/res/icon1.ico
Binary files differ
diff --git a/protocols/LotusNotify/res/icon2.ico b/protocols/LotusNotify/res/icon2.ico
new file mode 100644
index 0000000000..dfb94e1042
--- /dev/null
+++ b/protocols/LotusNotify/res/icon2.ico
Binary files differ
diff --git a/protocols/LotusNotify/src/LotusNotify.cpp b/protocols/LotusNotify/src/LotusNotify.cpp
new file mode 100644
index 0000000000..29dc2d91e6
--- /dev/null
+++ b/protocols/LotusNotify/src/LotusNotify.cpp
@@ -0,0 +1,1753 @@
+/*
+Miranda plugin template, originally by Richard Hughes
+http://miranda-icq.sourceforge.net/
+
+This file is placed in the public domain. Anybody is free to use or
+modify it as they wish with no restriction.
+There is no warranty.
+*/
+
+#include "stdafx.h"
+
+#include "debug.h"
+#include "resource.h"
+#include "version.h"
+#include "lotusnotes.h"
+#include "LotusNotify.h"
+
+INT_PTR SetStatus(WPARAM wParam, LPARAM lParam);
+
+#define MAX_FIELD 256
+#define MAX_SETTING_STR 512
+#define STATUS_COUNT 9
+
+char MODULENAME[64] = {0}; //init at init_pluginname();
+CMPlugin g_plugin;
+
+HINSTANCE hLotusDll;
+HEMREGISTRATION hLotusRegister = 0;
+
+boolean volatile Plugin_Terminated = false;
+mir_cs checkthreadCS;
+
+HGENMENU hMenuHandle = nullptr;
+HANDLE hCheckEvent = nullptr;
+
+static HWND hTimerWnd = (HWND)nullptr;
+static UINT TID = (UINT)2006;
+
+char settingServer[MAX_SETTING_STR] = "", settingServerSec[MAX_SETTING_STR] = "", settingDatabase[MAX_SETTING_STR] = "",
+ settingCommand[MAX_SETTING_STR] = "", settingParameters[MAX_SETTING_STR] = "", settingPassword[MAX_SETTING_STR] = "";
+wchar_t settingFilterSubject[MAX_SETTING_STR] = TEXT(""), settingFilterSender[MAX_SETTING_STR] = TEXT(""), settingFilterTo[MAX_SETTING_STR] = TEXT("");
+
+COLORREF settingBgColor, settingFgColor;
+int settingInterval = 0, settingInterval1 = 0;
+DWORD settingNewestID = 0;
+BYTE settingSetColours = 0, settingShowError = 1, settingIniAnswer = -1, settingIniCheck = 0,
+ settingOnceOnly = 0, settingNonClickedOnly = 0, settingNewest = 0, settingEvenNonClicked = 0, settingKeepConnection = 1;
+BOOL settingStatus[STATUS_COUNT];
+BOOL bMirandaCall=FALSE;
+
+struct HISTORIA *first = nullptr;
+BOOL running = FALSE;
+BOOL second = FALSE;
+BOOL isPopupWaiting = FALSE;
+int currentStatus = ID_STATUS_OFFLINE;
+int diffstat = 0;
+int startuperror = 0;
+wchar_t *startuperrors[] = {
+ LPGENW("Unable to load all required Lotus API functions"),
+ LPGENW("Lotus Notes Client not detected. Check plugin configuration description at https://miranda-ng.org/p/LotusNotify"),
+ LPGENW("Unable to initialize Notes."),
+ LPGENW("Lotus Notes Extension Manager was not registered. Authentication function will not work properly"),
+ LPGENW("In notes.ini file there is no required entry EXTMGR_ADDINS=plugindllnamewithout\".dll\"")
+ };
+
+/////////////////////////////////////////////////////////////////////////////////////////
+
+PLUGININFOEX pluginInfoEx = {
+ sizeof(PLUGININFOEX),
+ __PLUGIN_NAME,
+ PLUGIN_MAKE_VERSION(__MAJOR_VERSION, __MINOR_VERSION, __RELEASE_NUM, __BUILD_NUM),
+ __DESCRIPTION,
+ __AUTHOR,
+ __COPYRIGHT,
+ __AUTHORWEB,
+ UNICODE_AWARE,
+ { 0x23eacc0d, 0xbab0, 0x49c0, { 0x8f, 0x37, 0x5e, 0x25, 0x9e, 0xce, 0x52, 0x7f } } // {23EACC0D-BAB0-49c0-8F37-5E259ECE527F}
+};
+
+CMPlugin::CMPlugin() :
+ PLUGIN<CMPlugin>(MODULENAME, pluginInfoEx)
+{
+ RegisterProtocol(PROTOTYPE_PROTOCOL);
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+
+extern "C" __declspec(dllexport) const MUUID MirandaInterfaces[] = { MIID_PROTOCOL, MIID_LAST };
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// authentication callback futnction from extension manager called by nnotes.dll
+
+STATUS LNPUBLIC __stdcall EMCallBack (EMRECORD * pData)
+{
+ VARARG_PTR pArgs;
+ DWORD maxPwdLen;
+ DWORD * retLength;
+ char * retPassword;
+ char * fileName;
+ char * ownerName;
+
+ if (pData->EId != EM_GETPASSWORD) return (ERR_EM_CONTINUE); //asking for password?
+ if (pData->Status != NOERROR) return (ERR_EM_CONTINUE);
+
+ pArgs= pData->Ap;
+ maxPwdLen = VARARG_GET (pArgs, DWORD);
+ retLength = VARARG_GET (pArgs, DWORD *);
+ retPassword = VARARG_GET (pArgs, char *);
+ fileName = VARARG_GET (pArgs, char *);
+ ownerName = VARARG_GET (pArgs, char *);
+ strncpy(retPassword, settingPassword, mir_strlen(settingPassword)); //set our password
+ retPassword[mir_strlen(settingPassword)]='\0';
+ *retLength = (DWORD)mir_strlen(retPassword);//and his length
+ return ERR_BSAFE_EXTERNAL_PASSWORD;
+}
+
+
+//Main entry point for Ext Manager of Lotus API. called by nnotes.dll
+//It don't work (don't know why), and Mirandas Load function is called with value 1 or 0 as parameter...
+__declspec(dllexport)STATUS LNPUBLIC MainEntryPoint (void)
+{
+ STATUS rc = EMRegister1 (EM_GETPASSWORD, EM_REG_BEFORE | EM_REG_AFTER, EMCallBack, 0, &hLotusRegister); //Extension Manager must know that we are here
+ if(rc) {
+ //Extension magager don't know who we are :(
+ startuperror+=8;
+ // Get the info from the .ini file
+ }
+ return rc;
+}
+
+
+//Clear Extension Manager when exiting
+void ExtClear()
+{
+ STATUS status;
+ if (0 != hLotusRegister) {
+ status = EMDeregister1(&hLotusRegister); //we was registered, so let's unregister
+ } else {
+ status = NOERROR;
+ }
+ log_p(L"ExtClear() status=%d", status);
+ return;
+}
+
+
+//check if msg was clicked and exists on msgs list
+struct HISTORIA* getEl(DWORD id)
+{
+ for(struct HISTORIA *cur = first; cur != nullptr; cur = cur->next)
+ {
+ if(cur->noteID == id)
+ return cur;
+ }
+ return nullptr;
+}
+
+
+//creates new entry on list of msgs
+void addNewId(DWORD id)
+{
+ struct HISTORIA* nowy = (struct HISTORIA*)mir_alloc(sizeof(struct HISTORIA)) ;
+ assert(nowy);
+ nowy->noteID = id;
+ nowy->next = first;
+ nowy->pq = nullptr;
+ nowy->again = FALSE;
+ first = nowy;
+}
+
+
+//add popup handle. This queue is used to close popups with same msg
+void addPopup(DWORD id,HWND hWnd)
+{
+ struct POPUPSQUEUE* nowy = (struct POPUPSQUEUE*)mir_alloc(sizeof(struct POPUPSQUEUE)) ;
+ struct HISTORIA *elem = getEl(id);
+ assert(nowy);
+ nowy->hWnd = hWnd;
+ nowy->next = elem->pq;
+ elem->pq = nowy;
+}
+
+
+//clear popups handles list
+void deletePopupsHandles(struct POPUPSQUEUE **firstpq, BOOL closePopup)
+{
+ struct POPUPSQUEUE *curpq = *firstpq, *delpq;
+ while(curpq != nullptr) {
+ delpq = curpq;
+ curpq = curpq->next;
+ if(closePopup)
+ PUDeletePopup(delpq->hWnd);
+ mir_free(delpq);
+ }
+ *firstpq = nullptr;
+}
+
+
+//clear msgs list
+void deleteElements()
+{
+ struct HISTORIA *cur = first, *del;
+ while(cur != nullptr)
+ {
+ del = cur;
+ cur = cur->next;
+ deletePopupsHandles(&(del->pq),FALSE);
+ mir_free(del);
+ first = cur;
+ }
+ first = nullptr;
+}
+
+
+//set plugin name
+void init_pluginname()
+{
+ char text[MAX_PATH], *p, *q;
+ WIN32_FIND_DATAA ffd;
+
+ // Try to find name of the file having original letter sizes
+ GetModuleFileNameA(g_plugin.getInst(), text, sizeof(text));
+
+ HANDLE hFind = FindFirstFileA(text, &ffd);
+ if(hFind != INVALID_HANDLE_VALUE) {
+ strncpy_s(text, _countof(text), ffd.cFileName, mir_strlen(ffd.cFileName));
+ FindClose(hFind);
+ }
+ // Check if we have relative or full path
+ if(p = strrchr(text, '\\')) {
+ p++;
+ } else {
+ p = text;
+ }
+ if(q = strrchr(p, '.')) {
+ *q = '\0';
+ }
+ if((q = strstr(p, "debug")) && mir_strlen(q) == 5) {
+ *q = '\0';
+ }
+
+ // copy to static variable
+ strncpy_s(MODULENAME, _countof(MODULENAME), p, mir_strlen(p));
+ assert(mir_strlen(MODULENAME)>0);
+
+}
+
+
+BOOL strrep(char *src, char *needle, char *newstring)
+{
+ char *found, begining[MAX_SETTING_STR], tail[MAX_SETTING_STR];
+
+ //strset(begining,' ');
+ //strset(tail,' ');
+ if(!(found=strstr(src,needle)))
+ return FALSE;
+
+ size_t pos = (found-src);
+ strncpy_s(begining, _countof(begining), src, pos);
+ begining[pos]='\0';
+
+ pos += mir_strlen(needle);
+ strncpy_s(tail, _countof(tail), src+pos, _countof(tail));
+ begining[pos]='\0';
+
+ pos = sprintf(src, "%s%s%s", begining, newstring, tail); //!!!!!!!!!!!!!!!!
+ return TRUE;
+}
+
+
+//check if given string contain filter string
+//param field= 0-sender
+// 1-subject
+BOOL checkFilters(wchar_t* str, int field)
+{
+ wchar_t buff[512] = L"";
+ wchar_t *strptr = nullptr;
+ switch(field) {
+ case 0:
+ wcsncpy_s(buff, settingFilterSender, _TRUNCATE);
+ break;
+ case 1:
+ wcsncpy_s(buff, settingFilterSubject, _TRUNCATE);
+ break;
+ case 2:
+ wcsncpy_s(buff, settingFilterTo, _TRUNCATE);
+ break;
+ }
+
+
+ while(strptr = wcschr(buff, ';'))
+ {
+ wchar_t tmp[512] = TEXT(""), *ptr;
+ wcsncpy_s(tmp, buff, (strptr-buff));
+ wcsncpy_s(buff, strptr + 1, _TRUNCATE);
+
+ if(wcsstr(wcslwr(ptr=wcsdup(str)),wcslwr(tmp)))
+ {
+ free(ptr);
+ return TRUE;
+ }
+ free(ptr);
+ }
+ return FALSE;
+}
+
+
+//subfunction called from popup plugin callback function
+void Click(HWND hWnd,BOOL execute)
+{
+ POPUPATT *pid = (POPUPATT*)PUGetPluginData(hWnd);
+ if(settingOnceOnly&&settingNonClickedOnly)
+ (getEl(pid->id))->clicked=TRUE;//add to msgs list
+
+ deletePopupsHandles((&(getEl(pid->id))->pq),TRUE);
+
+ if(settingNewest && (pid->id > settingNewestID) ){
+ g_plugin.setDword("LNNewestID", settingNewestID=pid->id);
+ }
+ if(execute && settingCommand[0] ) {
+ char tmpcommand[2*MAX_SETTING_STR];
+ char tmpparameters[2*MAX_SETTING_STR];
+ strncpy_s(tmpcommand, _countof(tmpcommand), settingCommand, _countof(tmpcommand));
+ strncpy_s(tmpparameters, _countof(tmpparameters), settingParameters, _countof(tmpparameters));
+ strrep(tmpcommand, "%OID%", pid->strNote);
+ strrep(tmpparameters, "%OID%", pid->strNote);
+ log_p(L"executing: %S %S", tmpcommand, tmpparameters);
+ ShellExecuteA(nullptr, "Open", tmpcommand, tmpparameters, nullptr, SW_NORMAL);
+ }
+}
+
+
+//popup plugin callback function
+static LRESULT CALLBACK PopupDlgProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
+{
+ switch(message) {
+ case WM_COMMAND:
+ {
+
+ if (HIWORD(wParam) == STN_CLICKED)//client clicked on popup with left mouse button
+ {
+ Click(hWnd,TRUE);
+
+ //system(settingCommand);
+ //if(!settingOnceOnly)
+ //addNewId(noteID);
+ return TRUE;
+ }
+
+ break;
+ }
+
+ case WM_RBUTTONUP:
+ {
+ Click(hWnd,FALSE);
+ break;
+ }
+
+ case UM_INITPOPUP:
+ {
+ POPUPATT *pid = (POPUPATT*)PUGetPluginData(hWnd);
+ addPopup(pid->id,hWnd);
+ //PUDeletePopUp(hWnd);
+ break;
+ }
+
+ case UM_FREEPLUGINDATA:
+ {
+ POPUPATT *mpd = (POPUPATT*)PUGetPluginData(hWnd);
+ if (mpd > 0) free(mpd);
+ return TRUE; //TRUE or FALSE is the same, it gets ignored.
+ }
+
+ default:
+ break;
+ }
+
+ return DefWindowProc(hWnd, message, wParam, lParam);
+}
+
+
+//check notes.ini if it has entry about our plugin
+//return TRUE if notes.ini is set correctly
+//give bInfo=TRUE to show MsgBoxes
+BOOL checkNotesIniFile(BOOL bInfo)
+{
+ char tmp[MAXENVVALUE+1], tmp1[MAXENVVALUE+1];
+ (OSGetEnvironmentString1) ("EXTMGR_ADDINS", tmp, MAXENVVALUE);//get current setting
+ strncpy_s(tmp1,_countof(tmp1),tmp,sizeof(tmp1));//copy temporary
+ assert(mir_strlen(tmp1)>0);
+
+ char* PLUGINNAME_lower = _strlwr(mir_strdup(MODULENAME));
+
+ //is there our plugin as safe?
+ if(strstr(tmp1,PLUGINNAME_lower) == nullptr)
+ {
+ if(!settingIniCheck && !bInfo)
+ return FALSE;
+
+ if(!settingIniAnswer || bInfo){
+ switch(MessageBox(nullptr, TranslateT("This utility check your notes.ini file if it's set to authenticate this plugin as safe. Plugin is not added as Lotus Extension, so plugin built-in authentication will not work properly. Do you want to add plugin as Lotus Extension (modify notes.ini by adding \"EXTMGR_ADDINS=PLUGINNAME\")?"), TranslateT("LotusNotify plugin configuration"), MB_YESNO))
+ {
+ case IDYES:
+ {
+ settingIniAnswer=1;
+ break;
+ }
+ case IDNO:
+ {
+ settingIniAnswer=-1;
+ break;
+ }
+ }
+ }
+
+ if(settingIniAnswer == 1)
+ {
+ if(mir_strlen(tmp) > 0) {
+ strcat_s(tmp, _countof(tmp), ",");
+ strcat_s(tmp, _countof(tmp), PLUGINNAME_lower); //add our plugin to extensions
+ } else {
+ strncpy_s(tmp, _countof(tmp), PLUGINNAME_lower, mir_strlen(PLUGINNAME_lower)); //set our plugin as extension
+ }
+
+ (OSSetEnvironmentVariable1) ("EXTMGR_ADDINS", tmp); //set notes.ini entry
+ if(bInfo) {
+ MessageBox(nullptr, TranslateT("notes.ini modified correctly. Miranda restart required."), TranslateT("LotusNotify plugin configuration"), MB_OK);
+ } else{
+ ErMsgT(TranslateT("notes.ini modified correctly. Miranda restart required."));
+ }
+ return TRUE;
+ } else { if(settingIniAnswer == 0xFF)
+ return FALSE;
+ }
+ } else {
+ //setting set already
+ if(bInfo)
+ MessageBox(nullptr, TranslateT("notes.ini seem to be set correctly."), TranslateT("LotusNotify plugin configuration"), MB_OK);
+ return TRUE;
+ }
+
+ mir_free(PLUGINNAME_lower);
+ return FALSE;
+}
+
+
+//popup plugin to show popup function
+void showMsg(wchar_t* sender,wchar_t* text, DWORD id, char *strUID)
+{
+
+ POPUPDATAW ppd;
+ //hContact = A_VALID_HANDLE_YOU_GOT_FROM_SOMEWHERE;
+ //hIcon = A_VALID_HANDLE_YOU_GOT_SOMEWHERE;
+ //char * lpzContactName = (char*)CallService(MS_CLIST_GETCONTACTDISPLAYNAME,(WPARAM)lhContact,0);
+ //99% of the times you'll just copy this line.
+ //1% of the times you may wish to change the contact's name. I don't know why you should, but you can.
+ //char * lpzText;
+ //The text for the second line. You could even make something like: char lpzText[128]; mir_wstrcpy(lpzText, "Hello world!"); It's your choice.
+
+ POPUPATT * mpd = (POPUPATT*)malloc(sizeof(POPUPATT));
+ memset(&ppd, 0, sizeof(ppd)); //This is always a good thing to do.
+ ppd.lchContact = NULL; //(HANDLE)hContact; //Be sure to use a GOOD handle, since this will not be checked.
+ ppd.lchIcon = LoadIcon(g_plugin.getInst(), MAKEINTRESOURCE(IDI_ICON1));
+ wcscpy_s(ppd.lpwzContactName, _countof(ppd.lpwzContactName), sender);
+ wcscpy_s(ppd.lpwzText, _countof(ppd.lpwzText), text);
+ if(settingSetColours)
+ {
+ ppd.colorBack = settingBgColor;
+ ppd.colorText = settingFgColor;
+ }
+ ppd.PluginWindowProc = PopupDlgProc;
+
+ ppd.iSeconds=settingInterval1;
+ //Now the "additional" data.
+ mpd->id = id;
+ strncpy_s(mpd->strNote, _countof(mpd->strNote), strUID, mir_strlen(strUID));
+ //mpd->newStatus = ID_STATUS_ONLINE;
+
+ //Now that the plugin data has been filled, we add it to the PopUpData.
+ ppd.PluginData = mpd;
+
+ //Now that every field has been filled, we want to see the popup.
+ PUAddPopupW(&ppd);
+}
+
+
+//what to do with error msg
+void ErMsgW(WCHAR* msg)
+{
+ wchar_t* msgT = mir_wstrdup(msg);
+ ErMsgT(msgT);
+ mir_free(msgT);
+}
+///TODO wchar_t->WCHAR and test
+void ErMsgT(wchar_t* msg)
+{
+ log_p(L"Error: %S", msg);
+ if(settingShowError && !isPopupWaiting) {
+ wchar_t buffer[256+14];
+ wcsncpy_s(buffer, L"LotusNotify: ", _TRUNCATE);
+ wcscat_s(buffer, msg);
+ isPopupWaiting = TRUE;
+ PUShowMessageW(buffer, SM_WARNING);
+ isPopupWaiting = FALSE;
+ }
+}
+
+
+//Lotus error occured so translate it
+void ErMsgByLotusCode(STATUS erno)
+{
+ char far error_text_LMBCS[200];
+ char far error_text_UNICODEatCHAR[400];
+ WCHAR far error_text_UNICODE[200];
+ WORD text_len;
+
+ text_len = OSLoadString1(NULLHANDLE, erno, error_text_LMBCS, sizeof(error_text_LMBCS)-1);
+ OSTranslate1(OS_TRANSLATE_LMBCS_TO_UNICODE, error_text_LMBCS, (WORD)mir_strlen(error_text_LMBCS), error_text_UNICODEatCHAR, sizeof(error_text_UNICODEatCHAR)-1);
+ memcpy(error_text_UNICODE, error_text_UNICODEatCHAR, sizeof(error_text_UNICODE));
+
+ ErMsgW(error_text_UNICODE);
+}
+
+int check() {
+
+ log_p(L"check: Entering check function. running=%d", running);
+
+ if(startuperror) {
+ int cnt;
+ for(cnt = 0; cnt <= 4; cnt++)
+ if(startuperror >> cnt & 1)
+ ErMsgT(TranslateW(startuperrors[cnt]));
+ return 1;
+ }
+
+ if (Plugin_Terminated || Miranda_IsTerminated()){
+ log_p(L"check: Plugin_Terminated (=%d) OR Miranda_IsTerminated()", Plugin_Terminated);
+ return 0;
+ }
+
+ if(running) {
+ ErMsgT(TranslateT("Now checking Lotus, try again later"));
+ return 1;
+ }
+
+ running = TRUE;
+ Menu_EnableItem(hMenuHandle, !running);
+
+ log(L"check: starting checkthread");
+ mir_forkthread(checkthread);
+
+ return 0;
+}
+
+
+
+//before pure lotus notes api functions call
+void checkthread(void*)
+{
+ STATUS error = NOERROR;
+ char fullpath[255];
+ DBHANDLE db_handle = NULLHANDLE; /* database handle */
+ char UserName[MAXUSERNAME + 1];
+ HANDLE hTable;
+
+ DWORD noteID = 0L;
+ BOOL fFirst = TRUE;
+
+ NOTEHANDLE note_handle;
+ WORD field_len;
+ char field_date[MAXALPHATIMEDATE + 1];
+
+ char field_lotus_LMBCS[MAX_FIELD];
+ char field_lotus_UNICODEatCHAR[MAX_FIELD * sizeof(wchar_t)];
+ WCHAR field_from_UNICODE[MAX_FIELD], field_subject_UNICODE[MAX_FIELD], field_to_UNICODE[MAX_FIELD],field_copy_UNICODE[MAX_FIELD];
+
+ mir_cslock lck(checkthreadCS);
+ log(L"checkthread: inside new check thread");
+
+ if (error = NotesInitThread1()) {
+ goto errorblock;
+ }
+#ifdef _DEBUG
+ log(L"checkthread: Started NotesInitThread");
+#endif
+
+ if (error = OSPathNetConstruct1(nullptr, settingServer, settingDatabase, fullpath)) {
+ goto errorblock;
+ }
+#ifdef _DEBUG
+ log_p(L"checkthread: OSPathNetConstruct: %S", fullpath);
+#endif
+
+ if (error = NSFDbOpen1(fullpath, &db_handle)) {
+ if (mir_strcmp(settingServerSec, "") != 0) {
+ if (error = OSPathNetConstruct1(nullptr, settingServerSec, settingDatabase, fullpath)) {
+ goto errorblock;
+ }
+ else {
+ if (error = NSFDbOpen1(fullpath, &db_handle)) {
+ goto errorblock;
+ }
+ }
+ }
+ else {
+ goto errorblock;
+ }
+ }
+ assert(db_handle);
+#ifdef _DEBUG
+ log(L"checkthread: DBOpened");
+#endif
+
+ if (error = SECKFMGetUserName1(UserName)) {
+ goto errorblock0;
+ }
+ assert(UserName);
+#ifdef _DEBUG
+ log_p(L"checkthread: Username: %S", UserName);
+#endif
+
+ /* Get the unread list */
+ if (error = NSFDbGetUnreadNoteTable1(db_handle, UserName, (WORD)mir_strlen(UserName), TRUE, &hTable)) {
+ goto errorblock0;
+ }
+#ifdef _DEBUG
+ log(L"checkthread: Unread Table got");
+#endif
+
+ //error = IDTableCopy (hTable, &hOriginalTable);
+ //IDDestroyTable (hTable);
+ if (error = NSFDbUpdateUnread1(db_handle, hTable)) {
+ goto errorblock;
+ }
+#ifdef _DEBUG
+ log(L"checkthread: Unread Table updated");
+#endif
+ assert(hTable);
+
+
+ while (IDScan1(hTable, fFirst, &noteID)) {
+
+ WORD Att;
+ BLOCKID bhAttachment;
+ DWORD cSize = 0;
+ DWORD attSize = 0;
+ OID retNoteOID;
+ TIMEDATE retModified; /* modified timedate */
+ WORD retNoteClass; /* note class */
+ TIMEDATE sendDate;
+ char strLink[4 * 16];
+
+ if (Plugin_Terminated || Miranda_IsTerminated()) {
+ log_p(L"checkthread: Plugin_Terminated (=%d) OR Miranda_IsTerminated()", Plugin_Terminated);
+ break;
+ }
+
+#ifdef _DEBUG
+ log_p(L"checkthread: Getting info about: %d", noteID);
+#endif
+
+ fFirst = FALSE;
+ assert(noteID);
+ if (!getEl(noteID))
+ addNewId(noteID);
+ else
+ (getEl(noteID))->again = TRUE;
+
+ if (!settingOnceOnly && (getEl(noteID))->again == TRUE) {
+ //don't show again and note was not showed (ID not on list)
+ continue;
+ }
+
+#ifdef _DEBUG
+ log(L"checkthread: skiped-don't show again and note was not showed (ID not on list)");
+#endif
+
+ if (settingOnceOnly && settingNonClickedOnly && (getEl(noteID))->clicked == TRUE) {
+ //show again, but only not clicked (id added to list on Left Button click)
+ continue;
+ }
+
+#ifdef _DEBUG
+ log(L"checkthread: skiped-show again, but only not clicked (id added to list on Left Button click)");
+#endif
+
+ if (settingNewest && settingNewestID >= noteID) {
+ //only newest option enabled, so if old id don't show it
+ continue;
+ }
+
+#ifdef _DEBUG
+ log(L"checkthread: skiped-only newest option enabled, so if old id don't show it");
+#endif
+
+ // remember newest id depending on options set
+ if (settingNewest&&settingEvenNonClicked && (noteID > settingNewestID))
+ g_plugin.setDword("LNNewestID", settingNewestID = noteID);
+
+ //if(((!settingOnceOnly||(settingOnceOnly&&settingNonClickedOnly))&&existElem(noteID))||(settingNewest&&settingNewestID>=noteID))
+ //continue;
+
+ if (error = NSFNoteOpen1(db_handle, noteID, 0, &note_handle)) {
+ continue;
+ }
+
+#ifdef _DEBUG
+ log_p(L"checkthread: Opened Note: %d", noteID);
+#endif
+
+ NSFDbGetNoteInfo1(db_handle, /* DBHANDLE */
+ noteID, /* NOTEID */
+ &retNoteOID, /* out: OID */
+ &retModified, /* out: */
+ &retNoteClass);
+ memset(strLink, 0, sizeof(strLink));
+ mir_snprintf(strLink, "%.8lX%.8lX%.8lX%.8lX",
+ retNoteOID.File.Innards[1],
+ retNoteOID.File.Innards[0],
+ retNoteOID.Note.Innards[1],
+ retNoteOID.Note.Innards[0]
+ );
+
+ log_p(L"checkthread: got noteInfo, built link: %S", strLink);
+
+ field_len = NSFItemGetText1(note_handle, MAIL_FROM_ITEM, field_lotus_LMBCS, (WORD)sizeof(field_lotus_LMBCS));
+ OSTranslate1(OS_TRANSLATE_LMBCS_TO_UNICODE, field_lotus_LMBCS, field_len, field_lotus_UNICODEatCHAR, sizeof(field_lotus_UNICODEatCHAR));
+ memcpy(field_from_UNICODE, field_lotus_UNICODEatCHAR, field_len * sizeof(wchar_t));
+ field_from_UNICODE[field_len] = '\0';
+
+ NSFItemGetTime1(note_handle, MAIL_POSTEDDATE_ITEM, &sendDate);
+ error = ConvertTIMEDATEToText1(nullptr, nullptr, &sendDate, field_date, MAXALPHATIMEDATE, &field_len);
+ field_date[field_len] = '\0';
+
+ field_len = NSFItemGetText1(note_handle, MAIL_SUBJECT_ITEM, field_lotus_LMBCS, (WORD)sizeof(field_lotus_LMBCS));
+ OSTranslate1(OS_TRANSLATE_LMBCS_TO_UNICODE, field_lotus_LMBCS, field_len, field_lotus_UNICODEatCHAR, sizeof(field_lotus_UNICODEatCHAR));
+ memcpy(field_subject_UNICODE, field_lotus_UNICODEatCHAR, field_len * sizeof(wchar_t));
+ field_subject_UNICODE[field_len] = '\0';
+
+ field_len = NSFItemGetText1(note_handle, MAIL_SENDTO_ITEM, field_lotus_LMBCS, (WORD)sizeof(field_lotus_LMBCS));
+ OSTranslate1(OS_TRANSLATE_LMBCS_TO_UNICODE, field_lotus_LMBCS, field_len, field_lotus_UNICODEatCHAR, sizeof(field_lotus_UNICODEatCHAR));
+ memcpy(field_to_UNICODE, field_lotus_UNICODEatCHAR, field_len * sizeof(wchar_t));
+ field_to_UNICODE[field_len] = '\0';
+
+ field_len = NSFItemGetText1(note_handle, MAIL_COPYTO_ITEM, field_lotus_LMBCS, (WORD)sizeof(field_lotus_LMBCS));
+ OSTranslate1(OS_TRANSLATE_LMBCS_TO_UNICODE, field_lotus_LMBCS, field_len, field_lotus_UNICODEatCHAR, sizeof(field_lotus_UNICODEatCHAR));
+ memcpy(field_copy_UNICODE, field_lotus_UNICODEatCHAR, field_len * sizeof(wchar_t));
+ field_copy_UNICODE[field_len] = '\0';
+
+
+ WCHAR msgFrom[512], msgSubject[512];
+ memset(msgFrom, 0, sizeof(msgFrom));
+ memset(msgSubject, 0, sizeof(msgSubject));
+
+ if (mir_wstrlen(field_from_UNICODE) < 512 && mir_wstrlen(field_from_UNICODE) > 3 && wcsstr(field_from_UNICODE, L"CN=") == field_from_UNICODE)
+ wcsncpy_s(msgFrom, &(field_from_UNICODE[3]), wcscspn(field_from_UNICODE, L"/") - 3);
+ else
+ wcsncpy_s(msgFrom, field_from_UNICODE, _TRUNCATE);
+
+ for (Att = 0; MailGetMessageAttachmentInfo1(note_handle, Att, &bhAttachment, nullptr, &cSize, nullptr, nullptr, nullptr, nullptr); Att++)
+ attSize += cSize;
+
+#ifdef _DEBUG
+ log_p(L"checkthread: MAIL INFO: date=[%S], from=[%s], to=[%s], cc=[%s], sub=[%s], attSize=[%d]"
+ , field_date
+ , field_from_UNICODE
+ , field_to_UNICODE
+ , field_copy_UNICODE
+ , field_subject_UNICODE
+ , attSize
+ );
+#else
+ //do not put private user data into log
+ log_p(L"checkthread: MAIL INFO (sizes): date=[%S], from=[%d], to=[%d], cc=[%d], sub=[%d], attSize=[%d]"
+ ,field_date
+ ,mir_wstrlen(field_from_UNICODE)
+ ,mir_wstrlen(field_to_UNICODE)
+ ,mir_wstrlen(field_copy_UNICODE)
+ ,mir_wstrlen(field_subject_UNICODE)
+ ,attSize
+ );
+#endif
+
+
+ if (attSize) {
+ WCHAR field_attachments_UNICODE[MAX_FIELD];
+ mir_snwprintf(field_attachments_UNICODE, TranslateT("Attachments: %d bytes"), attSize);
+ mir_snwprintf(msgSubject, L"%S\n%s\n%s", field_date, field_subject_UNICODE, field_attachments_UNICODE);
+ }
+ else {
+ mir_snwprintf(msgSubject, L"%S\n%s", field_date, field_subject_UNICODE);
+ }
+
+ //check if this is not filtered msg
+ if (!checkFilters(field_from_UNICODE, 0)
+ && !checkFilters(field_subject_UNICODE, 1)
+ && !checkFilters(field_to_UNICODE, 2)
+ && !checkFilters(field_copy_UNICODE, 2)) {
+ log(L"checkthread: filters checked - positive");
+ ///TODO eliminate popups with blank fields
+ showMsg(msgFrom, msgSubject, noteID, strLink);
+ Skin_PlaySound("LotusNotify");
+ }
+ else {
+ log(L"checkthread: filters checked - negative");
+ }
+
+ if (error = NSFNoteClose1(note_handle)) {
+ continue;
+ }
+#ifdef _DEBUG
+ log_p(L"checkthread: Close note id: %d", noteID);
+#endif
+
+ }
+
+ if (error = IDDestroyTable1(hTable)) {
+ goto errorblock0;
+ }
+#ifdef _DEBUG
+ log(L"checkthread: Table destroyed");
+#endif
+
+ if (error = NSFDbClose1(db_handle)) {
+ goto errorblock;
+ }
+#ifdef _DEBUG
+ log(L"checkthread: DB closed");
+#endif
+
+ //NotesTerm();
+ NotesTermThread1();
+
+#ifdef _DEBUG
+ log(L"checkthread: Terminating Notes thread");
+#endif
+ running = FALSE;
+ if (currentStatus != ID_STATUS_OFFLINE)
+ Menu_EnableItem(hMenuHandle, !running);
+ return;
+
+errorblock0:
+ log(L"checkthread: errorblock0");
+ NSFDbClose1(db_handle);
+errorblock:
+ log_p(L"checkthread: errorblock. error=%d", error);
+ ErMsgByLotusCode(error);
+ //NotesTerm();
+
+ // go offline if connection error occurs and let KeepStatus or other plugin managing reconnection
+ if (!settingKeepConnection && currentStatus != ID_STATUS_OFFLINE) {
+ Menu_EnableItem(hMenuHandle, !running);
+ SetStatus(ID_STATUS_OFFLINE, 0);
+ }
+
+ running = FALSE;
+ return;
+}
+
+
+//hooked notification from service that listning to check lotus
+static int eventCheck(WPARAM, LPARAM)
+{
+ log(L"check event...");
+ check();
+ return 0;
+}
+
+
+//on click to menu callback function
+static INT_PTR PluginMenuCommand(WPARAM wParam, LPARAM lParam)
+{
+ NotifyEventHooks(hCheckEvent, wParam, lParam); //create event to check lotus
+ return 0;
+}
+
+
+//window timer callback function, called on timer event
+static void CALLBACK atTime(HWND, UINT, UINT_PTR idEvent, DWORD)
+{
+ log(L"atTime: start");
+ KillTimer(hTimerWnd, idEvent);
+ if (currentStatus != ID_STATUS_OFFLINE) {
+ //if status lets to check
+ check();
+ if (settingInterval != 0) {
+ log_p(L"atTime: SetTimer settingInterval=%d", settingInterval * 60000);
+ SetTimer(hTimerWnd, TID, settingInterval * 60000, atTime);
+ }
+ }
+}
+
+
+void decodeServer(char *tmp)
+{
+ if (strstr(tmp, "CN=") && strstr(tmp, "OU=") && strstr(tmp, "O=")) {
+ //if lotus convention
+ while (strrep(tmp, "CN=", ""));
+ while (strrep(tmp, "OU=", ""));
+ while (strrep(tmp, "O=", ""));
+ }
+}
+
+
+//fill combo in options dlgbox with all known servers
+void fillServersList(HWND hwndDlg)
+{
+ HANDLE hServerList = NULLHANDLE;
+ BYTE far *pServerList; /* Pointer to start of Server List */
+ WORD wServerCount; /* Number of servers in list. */
+ WORD far *pwServerLength; /* Index to array of servername lens */
+ BYTE far *pServerName;
+ STATUS error = NOERROR; /* Error return from API routines. */
+ char ServerString[MAXPATH]; /* String to hold server names. */
+ LPSTR szServerString = ServerString;
+
+ if (!hLotusDll) {
+ return;
+ }
+
+ error = NSGetServerList1(nullptr, &hServerList);
+ if (error == NOERROR) {
+
+ pServerList = (BYTE far *) OSLockObject1(hServerList);
+ wServerCount = (WORD)*pServerList;
+
+ pwServerLength = (WORD *)(pServerList + sizeof(WORD));
+
+ pServerName = (BYTE far *) pServerList + sizeof(wServerCount) + ((wServerCount)* sizeof(WORD));
+
+ for (USHORT i = 0; i < wServerCount; pServerName += pwServerLength[i], i++) {
+ memmove(szServerString, pServerName, pwServerLength[i]);
+ szServerString[pwServerLength[i]] = '\0';
+ decodeServer(ServerString);
+ SendDlgItemMessageA(hwndDlg, IDC_SERVER, CB_ADDSTRING, 0, (LPARAM)szServerString);
+ }
+ OSUnlockObject1(hServerList);
+ OSMemFree1(hServerList);
+
+ }
+ else {
+ ErMsgByLotusCode(error);
+ }
+}
+
+
+//gets default settings from notes.ini file
+static void lookupLotusDefaultSettings(HWND hwndDlg)
+{
+ char tmp[MAXENVVALUE + 1];
+ // Get the info from the .ini file
+ if (hLotusDll) {
+ if (OSGetEnvironmentString1("MailFile", tmp, MAXENVVALUE)) //path to mail file
+ SetDlgItemTextA(hwndDlg, IDC_DATABASE, tmp); //and set fields in opt. dialog
+ if (OSGetEnvironmentString1("MailServer", tmp, MAXENVVALUE)) //server name
+ {
+ decodeServer(tmp);
+ SetDlgItemTextA(hwndDlg, IDC_SERVER, tmp);
+ }
+ }
+
+}
+
+// get variables values stored in db.
+static void LoadSettings()
+{
+ settingInterval = (INT)g_plugin.getDword("LNInterval", 15);
+ settingInterval1 = (INT)g_plugin.getDword("LNInterval1", 0);
+ settingKeepConnection = g_plugin.getByte("LNKeepConnection", 1);
+
+ DBVARIANT dbv;
+ if (!g_plugin.getString("LNDatabase", &dbv)) {
+ strncpy_s(settingDatabase, _countof(settingDatabase), dbv.pszVal, _countof(settingDatabase));
+ db_free(&dbv);
+ }
+ if (!g_plugin.getString("LNServer", &dbv)) {
+ strncpy_s(settingServer, _countof(settingServer), dbv.pszVal, _countof(settingServer));
+ db_free(&dbv);
+ }
+ if (!g_plugin.getString("LNServerSec", &dbv)) {
+ strncpy_s(settingServerSec, _countof(settingServerSec), dbv.pszVal, _countof(settingServerSec));
+ db_free(&dbv);
+ }
+ if (!g_plugin.getString("LNPassword", &dbv)) {
+ strncpy_s(settingPassword, _countof(settingPassword), dbv.pszVal, _countof(settingPassword));
+ db_free(&dbv);
+ }
+ if (!g_plugin.getString("LNCommand", &dbv)) {
+ strncpy_s(settingCommand, _countof(settingCommand), dbv.pszVal, _countof(settingCommand));
+ db_free(&dbv);
+ }
+ if (!g_plugin.getString("LNParameters", &dbv)) {
+ strncpy_s(settingParameters, _countof(settingParameters), dbv.pszVal, _countof(settingParameters));
+ db_free(&dbv);
+ }
+
+ if (!g_plugin.getWString("LNFilterSender", &dbv)) {
+ wcsncpy_s(settingFilterSender, dbv.pwszVal, _TRUNCATE);
+ db_free(&dbv);
+ }
+ if (!g_plugin.getWString("LNFilterSubject", &dbv)) {
+ wcsncpy_s(settingFilterSubject, dbv.pwszVal, _TRUNCATE);
+ db_free(&dbv);
+ }
+ if (!g_plugin.getWString("LNFilterTo", &dbv)) {
+ wcsncpy_s(settingFilterTo, dbv.pwszVal, _TRUNCATE);
+ db_free(&dbv);
+ }
+
+ settingOnceOnly = g_plugin.getByte("LNOnceOnly", 0);
+
+ settingNonClickedOnly = g_plugin.getByte("LNNonClickedOnly", 1);
+ settingShowError = g_plugin.getByte("LNShowError", 1);
+ settingSetColours = g_plugin.getByte("LNSetColours", 0);
+ settingBgColor = (COLORREF)g_plugin.getDword("LNBgColor", (DWORD)0xFFFFFF);
+ settingFgColor = (COLORREF)g_plugin.getDword("LNFgColor", (DWORD)0x000000);
+ settingNewest = g_plugin.getByte("LNNewest", 0);
+ settingEvenNonClicked = g_plugin.getByte("LNEvenNonClicked", 0);
+ settingNewestID = (DWORD)g_plugin.getDword("LNNewestID", 0);
+ settingIniAnswer = g_plugin.getByte("LNIniAnswer", 0);
+ settingIniCheck = g_plugin.getByte("LNIniCheck", 0);
+
+ for (int i = 0; i < STATUS_COUNT; i++) {
+ char buff[128];
+ mir_snprintf(buff, "LNStatus%d", i);
+ settingStatus[i] = (g_plugin.getByte(buff, 0) == 1);
+ }
+ //lookupLotusDefaultSettings();
+}
+
+static void SaveSettings(HWND hwndDlg)
+{
+ char buff[128];
+ GetDlgItemTextA(hwndDlg, IDC_SERVER, settingServer, _countof(settingServer));
+ g_plugin.setString("LNServer", settingServer);
+ g_plugin.setString("LNServerSec", settingServerSec);
+ g_plugin.setString("LNPassword", settingPassword);
+ g_plugin.setString("LNDatabase", settingDatabase);
+ g_plugin.setDword("LNInterval", settingInterval);
+ g_plugin.setDword("LNInterval1", settingInterval1);
+ g_plugin.setByte("LNKeepConnection", settingKeepConnection);
+ g_plugin.setString("LNCommand", settingCommand);
+ g_plugin.setString("LNParameters", settingParameters);
+ g_plugin.setByte("LNOnceOnly", settingOnceOnly);
+ g_plugin.setByte("LNNonClickedOnly", settingNonClickedOnly);
+ g_plugin.setByte("LNShowError", settingShowError);
+ g_plugin.setByte("LNSetColours", settingSetColours);
+ g_plugin.setDword("LNBgColor", (DWORD)settingBgColor);
+ g_plugin.setDword("LNFgColor", (DWORD)settingFgColor);
+ g_plugin.setByte("LNNewest", settingNewest);
+ g_plugin.setByte("LNEvenNonClicked", settingEvenNonClicked);
+ g_plugin.setByte("LNIniCheck", settingIniCheck);
+ g_plugin.setByte("LNIniAnswer", settingIniAnswer);
+
+ for (int i = 0; i < STATUS_COUNT; i++) {
+ mir_snprintf(buff, "LNStatus%d", i);
+ settingStatus[i] = (ListView_GetCheckState(GetDlgItem(hwndDlg, IDC_STATUS), i) ? TRUE : FALSE);
+ g_plugin.setByte(buff, settingStatus[i] ? 1 : 0);
+ }
+
+ settingFilterSender[0] = 0;
+ for (int i = 0; i < SendDlgItemMessage(hwndDlg, IDC_FILTER_SENDER, CB_GETCOUNT, 0, 0); i++) {
+ wchar_t text[512] = TEXT("");
+ SendDlgItemMessage(hwndDlg, IDC_FILTER_SENDER, CB_GETLBTEXT, (WPARAM)i, (LPARAM)text);
+ wcscat_s(settingFilterSender, _countof(settingFilterSender), text);
+ wcscat_s(settingFilterSender, _countof(settingFilterSender), TEXT(";"));
+ }
+ g_plugin.setWString("LNFilterSender", settingFilterSender);
+
+ settingFilterSubject[0] = 0;
+ for (int i = 0; i < SendDlgItemMessage(hwndDlg, IDC_FILTER_SUBJECT, CB_GETCOUNT, 0, 0); i++) {
+ wchar_t text[512] = TEXT("");
+ SendDlgItemMessage(hwndDlg, IDC_FILTER_SUBJECT, CB_GETLBTEXT, (WPARAM)i, (LPARAM)text);
+ wcscat_s(settingFilterSubject, _countof(settingFilterSubject), text);
+ wcscat_s(settingFilterSubject, _countof(settingFilterSubject), TEXT(";"));
+ }
+ g_plugin.setWString("LNFilterSubject", settingFilterSubject);
+
+ settingFilterTo[0] = 0;
+ for (int i = 0; i < SendDlgItemMessage(hwndDlg, IDC_FILTER_TO, CB_GETCOUNT, 0, 0); i++) {
+ wchar_t text[512] = TEXT("");
+ SendDlgItemMessage(hwndDlg, IDC_FILTER_TO, CB_GETLBTEXT, (WPARAM)i, (LPARAM)text);
+ wcscat_s(settingFilterTo, _countof(settingFilterTo), text);
+ wcscat_s(settingFilterTo, _countof(settingFilterTo), TEXT(";"));
+ }
+ g_plugin.setWString("LNFilterTo", settingFilterTo);
+}
+
+//callback function to speak with user interactions in options page
+static INT_PTR CALLBACK DlgProcLotusNotifyConnectionOpts(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam)
+{
+ static bool bInit = false;
+
+ switch (msg) {
+ case WM_INITDIALOG://initialize dialog, so set properties from db.
+ bInit = true;
+ TranslateDialogDefault(hwndDlg);//translate miranda function
+ LoadSettings();
+ CheckDlgButton(hwndDlg, IDC_BUTTON_CHECK, settingIniCheck ? BST_CHECKED : BST_UNCHECKED);
+ SetDlgItemTextA(hwndDlg, IDC_SERVER, settingServer);
+ SetDlgItemTextA(hwndDlg, IDC_SERVERSEC, settingServerSec);
+ SetDlgItemTextA(hwndDlg, IDC_DATABASE, settingDatabase);
+ SetDlgItemTextA(hwndDlg, IDC_PASSWORD, settingPassword);
+ SetDlgItemInt(hwndDlg, IDC_INTERVAL, settingInterval, FALSE);
+ CheckDlgButton(hwndDlg, IDC_KEEP_CONNEXION_ON_ERROR, settingKeepConnection ? BST_CHECKED : BST_UNCHECKED);
+ bInit = false;
+ break;
+
+ case WM_COMMAND://user changed something, so get changes to variables
+ if (!bInit) {
+ switch (HIWORD(wParam)) {
+ case EN_CHANGE: // text is modified in an edit ctrl
+ case BN_CLICKED: // a checkbox is modified
+ PostMessage(GetParent(hwndDlg), PSM_CHANGED, 0, 0);
+ break;
+ }
+ }
+ switch (LOWORD(wParam)) {
+ case IDC_BUTTON_DETECT:
+ lookupLotusDefaultSettings(hwndDlg);
+ GetDlgItemTextA(hwndDlg, IDC_SERVER, settingServer, _countof(settingServer));
+ GetDlgItemTextA(hwndDlg, IDC_DATABASE, settingDatabase, _countof(settingDatabase));
+ break;
+ case IDC_BUTTON_CHECK:
+ settingIniCheck = (BYTE)IsDlgButtonChecked(hwndDlg, IDC_BUTTON_CHECK);
+ checkNotesIniFile(TRUE);
+ break;
+ case IDC_DATABASE:
+ GetDlgItemTextA(hwndDlg, IDC_DATABASE, settingDatabase, _countof(settingDatabase));
+ break;
+ case IDC_SERVER:
+ switch (HIWORD(wParam)) {
+ case CBN_SELCHANGE:
+ {
+ int i = SendDlgItemMessage(hwndDlg, IDC_SERVER, CB_GETCURSEL, 0, 0);
+ char text[MAXENVVALUE];
+ SendDlgItemMessageA(hwndDlg, IDC_SERVER, CB_GETLBTEXT, (WPARAM)i, (LPARAM)text);
+ SetDlgItemTextA(hwndDlg, IDC_SERVER, text);
+ if (!bInit) {
+ PostMessage(GetParent(hwndDlg), PSM_CHANGED, 0, 0);
+ }
+ break;
+ }
+
+ case CBN_DROPDOWN:
+ SendDlgItemMessage(hwndDlg, IDC_SERVER, CB_RESETCONTENT, 0, 0);
+ fillServersList(hwndDlg);
+ SendDlgItemMessageA(hwndDlg, IDC_SERVER, CB_ADDSTRING, 0, (LPARAM)settingServer);
+ SendDlgItemMessageA(hwndDlg, IDC_SERVER, CB_SELECTSTRING, -1, (LPARAM)settingServer);
+ break;
+ }
+ break;
+ case IDC_SERVERSEC:
+ GetDlgItemTextA(hwndDlg, IDC_SERVERSEC, settingServerSec, _countof(settingServerSec));
+ break;
+ case IDC_PASSWORD:
+ GetDlgItemTextA(hwndDlg, IDC_PASSWORD, settingPassword, _countof(settingPassword));
+ break;
+ case IDC_INTERVAL:
+ settingInterval = GetDlgItemInt(hwndDlg, IDC_INTERVAL, nullptr, FALSE);
+ break;
+ case IDC_KEEP_CONNEXION_ON_ERROR:
+ settingKeepConnection = (BYTE)IsDlgButtonChecked(hwndDlg, IDC_KEEP_CONNEXION_ON_ERROR);
+ break;
+ }
+ break;
+
+ case WM_NOTIFY://apply changes so write it to db
+ switch (((LPNMHDR)lParam)->idFrom) {
+ case 0:
+ switch (((LPNMHDR)lParam)->code) {
+ case PSN_RESET:
+ LoadSettings();
+ return TRUE;
+
+ case PSN_APPLY:
+ SaveSettings(hwndDlg);
+ return TRUE;
+ }
+ break;
+ } //id from
+
+ break; //switch(msg)
+
+ }
+ return FALSE;
+}
+
+static INT_PTR CALLBACK DlgProcLotusNotifyPopupOpts(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam)
+{
+ static bool bInit = false;
+
+ switch (msg) {
+ case WM_INITDIALOG://initialize dialog, so set properties from db.
+ bInit = true;
+ TranslateDialogDefault(hwndDlg);//translate miranda function
+ LoadSettings();
+
+ CheckDlgButton(hwndDlg, IDC_SETCOLOURS, settingSetColours ? BST_CHECKED : BST_UNCHECKED);
+ SendDlgItemMessage(hwndDlg, IDC_BGCOLOR, CPM_SETCOLOUR, 0, (LPARAM)settingBgColor);
+ EnableWindow(GetDlgItem(hwndDlg, IDC_BGCOLOR), settingSetColours != 0);
+ SendDlgItemMessage(hwndDlg, IDC_FGCOLOR, CPM_SETCOLOUR, 0, (LPARAM)settingFgColor);
+ EnableWindow(GetDlgItem(hwndDlg, IDC_FGCOLOR), settingSetColours != 0);
+
+ SetDlgItemInt(hwndDlg, IDC_INTERVAL1, settingInterval1, TRUE);
+ CheckDlgButton(hwndDlg, IDC_ONCEONLY, settingOnceOnly ? BST_CHECKED : BST_UNCHECKED);
+ CheckDlgButton(hwndDlg, IDC_NONCLICKEDONLY, settingNonClickedOnly ? BST_CHECKED : BST_UNCHECKED);
+ EnableWindow(GetDlgItem(hwndDlg, IDC_NONCLICKEDONLY), settingOnceOnly != 0);
+ CheckDlgButton(hwndDlg, IDC_SHOWERROR, settingShowError ? BST_CHECKED : BST_UNCHECKED);
+ CheckDlgButton(hwndDlg, IDC_NEWEST, settingNewest ? BST_CHECKED : BST_UNCHECKED);
+ CheckDlgButton(hwndDlg, IDC_REMEMBEREVENNONCLICKED, settingEvenNonClicked ? BST_CHECKED : BST_UNCHECKED);
+ EnableWindow(GetDlgItem(hwndDlg, IDC_REMEMBEREVENNONCLICKED), settingNewest != 0);
+ SetDlgItemTextA(hwndDlg, IDC_COMMAND, settingCommand);
+ SetDlgItemTextA(hwndDlg, IDC_PARAMETERS, settingParameters);
+
+ bInit = FALSE;
+ break;
+
+ case WM_COMMAND://user changed something, so get changes to variables
+ if (!bInit) {
+ switch (HIWORD(wParam)) {
+ case EN_CHANGE: // text is modified in an edit ctrl
+ case BN_CLICKED: // a checkbox is modified
+ case CPN_COLOURCHANGED: // a color has changed
+ PostMessage(GetParent(hwndDlg), PSM_CHANGED, 0, 0);
+ break;
+ }
+ }
+ switch (LOWORD(wParam)) {
+ case IDC_SETCOLOURS:
+ settingSetColours = IsDlgButtonChecked(hwndDlg, IDC_SETCOLOURS);
+ EnableWindow(GetDlgItem(hwndDlg, IDC_BGCOLOR), settingSetColours);
+ EnableWindow(GetDlgItem(hwndDlg, IDC_FGCOLOR), settingSetColours);
+ break;
+ case IDC_BGCOLOR:
+ settingBgColor = (COLORREF)SendDlgItemMessage(hwndDlg, IDC_BGCOLOR, CPM_GETCOLOUR, 0, 0);
+ break;
+ case IDC_FGCOLOR:
+ settingFgColor = (COLORREF)SendDlgItemMessage(hwndDlg, IDC_FGCOLOR, CPM_GETCOLOUR, 0, 0);
+ break;
+ case IDC_INTERVAL1:
+ settingInterval1 = GetDlgItemInt(hwndDlg, IDC_INTERVAL1, nullptr, TRUE);
+ break;
+ case IDC_ONCEONLY:
+ settingOnceOnly = (BYTE)IsDlgButtonChecked(hwndDlg, IDC_ONCEONLY);
+ EnableWindow(GetDlgItem(hwndDlg, IDC_NONCLICKEDONLY), settingOnceOnly);
+ break;
+ case IDC_NONCLICKEDONLY:
+ settingNonClickedOnly = (BYTE)IsDlgButtonChecked(hwndDlg, IDC_NONCLICKEDONLY);
+ break;
+ case IDC_SHOWERROR:
+ settingShowError = (BYTE)IsDlgButtonChecked(hwndDlg, IDC_SHOWERROR);
+ break;
+ case IDC_NEWEST:
+ settingNewest = (BYTE)IsDlgButtonChecked(hwndDlg, IDC_NEWEST);
+ EnableWindow(GetDlgItem(hwndDlg, IDC_REMEMBEREVENNONCLICKED), settingNewest);
+ break;
+ case IDC_REMEMBEREVENNONCLICKED:
+ settingEvenNonClicked = (BYTE)IsDlgButtonChecked(hwndDlg, IDC_REMEMBEREVENNONCLICKED);
+ break;
+ case IDC_COMMAND:
+ GetDlgItemTextA(hwndDlg, IDC_COMMAND, settingCommand, _countof(settingCommand));
+ break;
+ case IDC_PARAMETERS:
+ GetDlgItemTextA(hwndDlg, IDC_PARAMETERS, settingParameters, _countof(settingParameters));
+ break;
+ case IDC_BUTTON_CLEAR:
+ deleteElements();
+ break;
+ }
+ break;
+
+ case WM_NOTIFY://apply changes so write it to db
+ switch (((LPNMHDR)lParam)->idFrom) {
+ case 0:
+ {
+ switch (((LPNMHDR)lParam)->code) {
+ case PSN_RESET:
+ LoadSettings();
+ return TRUE;
+ case PSN_APPLY:
+ SaveSettings(hwndDlg);
+
+ return TRUE;
+ break;
+ }
+ //KillTimer(hTimerWnd,TID);
+ //if(settingInterval!=0)
+ // SetTimer(hTimerWnd, TID, settingInterval*60000, (TIMERPROC)atTime);
+
+ break;
+ } //case 0
+ } //id from
+
+ break; //switch(msg)
+
+ }
+ return FALSE;
+}
+
+static INT_PTR CALLBACK DlgProcLotusNotifyMiscOpts(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam)
+{
+ static bool bInit = false;
+
+ wchar_t* strptr;
+ LVITEM lvI = { 0 };
+ LVCOLUMN lvc = { 0 };
+ switch (msg) {
+ case WM_INITDIALOG://initialize dialog, so set properties from db.
+ {
+ wchar_t buff[512];
+ bInit = true;
+ TranslateDialogDefault(hwndDlg);//translate miranda function
+ LoadSettings();
+
+ //fill filter combos
+
+ wcsncpy_s(buff, settingFilterSender, _TRUNCATE);
+ while (strptr = wcschr(buff, TEXT(';'))) {
+ wchar_t tmp[512] = TEXT("");
+ wcsncpy_s(tmp, buff, (strptr - buff));
+ SendDlgItemMessage(hwndDlg, IDC_FILTER_SENDER, CB_ADDSTRING, 0, (LPARAM)tmp);
+ wcsncpy_s(buff, strptr + 1, _TRUNCATE);
+ }
+
+ wcsncpy_s(buff, settingFilterSubject, _TRUNCATE);
+ while (strptr = wcschr(buff, TEXT(';'))) {
+ wchar_t tmp[512] = TEXT("");
+ wcsncpy_s(tmp, buff, (strptr - buff));
+ SendDlgItemMessage(hwndDlg, IDC_FILTER_SUBJECT, CB_ADDSTRING, 0, (LPARAM)tmp);
+ wcsncpy_s(buff, strptr + 1, _TRUNCATE);
+ }
+
+ wcsncpy_s(buff, settingFilterTo, _TRUNCATE);
+ while (strptr = wcschr(buff, TEXT(';'))) {
+ wchar_t tmp[512] = TEXT("");
+ wcsncpy_s(tmp, buff, (strptr - buff));
+ SendDlgItemMessage(hwndDlg, IDC_FILTER_TO, CB_ADDSTRING, 0, (LPARAM)tmp);
+ wcsncpy_s(buff, strptr + 1, _TRUNCATE);
+ }
+
+ // initialise and fill listbox
+ HWND hwndList = GetDlgItem(hwndDlg, IDC_STATUS);
+ ListView_DeleteAllItems(hwndList);
+
+ SendMessage(hwndList, LVM_SETEXTENDEDLISTVIEWSTYLE, 0, LVS_EX_FULLROWSELECT | LVS_EX_CHECKBOXES);
+
+ // 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("Status");
+ lvc.cx = 120; // width of column in pixels
+ ListView_InsertColumn(hwndList, 0, &lvc);
+
+ // Some code to create the list-view control.
+ // Initialize LVITEM members that are common to all items.
+ lvI.mask = LVIF_TEXT;
+ for (int i = 0; i < STATUS_COUNT; i++) {
+ lvI.pszText = Clist_GetStatusModeDescription(ID_STATUS_ONLINE + i, 0);
+ lvI.iItem = i;
+ ListView_InsertItem(hwndList, &lvI);
+ ListView_SetCheckState(hwndList, i, settingStatus[i]);
+ }
+
+ bInit = false;
+ break;
+ }
+ case WM_COMMAND://user changed something, so get changes to variables
+ {
+ if (!bInit && (HIWORD(wParam) == EN_CHANGE)) {
+ PostMessage(GetParent(hwndDlg), PSM_CHANGED, 0, 0);
+ }
+ char tmp[255];
+ int index, size;
+ switch (LOWORD(wParam)) {
+ case IDC_BUTTON_ADD_SENDER_FILTER:
+ GetDlgItemTextA(hwndDlg, IDC_FILTER_SENDER, tmp, _countof(tmp));
+ if (strlen(tmp) > 0) {
+ SendDlgItemMessageA(hwndDlg, IDC_FILTER_SENDER, CB_ADDSTRING, 0, (LPARAM)tmp);
+ PostMessage(GetParent(hwndDlg), PSM_CHANGED, 0, 0);
+ }
+ break;
+ case IDC_BUTTON_REMOVE_SENDER_FILTER:
+ index = SendDlgItemMessage(hwndDlg, IDC_FILTER_SENDER, CB_GETCURSEL, 0, 0);
+ size = SendDlgItemMessage(hwndDlg, IDC_FILTER_SENDER, CB_DELETESTRING, index, 0);
+ SendDlgItemMessage(hwndDlg, IDC_FILTER_SENDER, CB_SETCURSEL, min(index, size - 1), 0);
+ PostMessage(GetParent(hwndDlg), PSM_CHANGED, 0, 0);
+ break;
+ case IDC_BUTTON_ADD_SUBJECT_FILTER:
+ GetDlgItemTextA(hwndDlg, IDC_FILTER_SUBJECT, tmp, _countof(tmp));
+ if (strlen(tmp) > 0) {
+ SendDlgItemMessageA(hwndDlg, IDC_FILTER_SUBJECT, CB_ADDSTRING, 0, (LPARAM)tmp);
+ PostMessage(GetParent(hwndDlg), PSM_CHANGED, 0, 0);
+ }
+ break;
+ case IDC_BUTTON_REMOVE_SUBJECT_FILTER:
+ index = SendDlgItemMessage(hwndDlg, IDC_FILTER_SUBJECT, CB_GETCURSEL, 0, 0);
+ size = SendDlgItemMessage(hwndDlg, IDC_FILTER_SUBJECT, CB_DELETESTRING, index, 0);
+ SendDlgItemMessage(hwndDlg, IDC_FILTER_SUBJECT, CB_SETCURSEL, min(index, size - 1), 0);
+ PostMessage(GetParent(hwndDlg), PSM_CHANGED, 0, 0);
+ break;
+ case IDC_BUTTON_ADD_TO_FILTER:
+ GetDlgItemTextA(hwndDlg, IDC_FILTER_TO, tmp, _countof(tmp));
+ if (strlen(tmp) > 0) {
+ SendDlgItemMessageA(hwndDlg, IDC_FILTER_TO, CB_ADDSTRING, 0, (LPARAM)tmp);
+ PostMessage(GetParent(hwndDlg), PSM_CHANGED, 0, 0);
+ }
+ break;
+ case IDC_BUTTON_REMOVE_TO_FILTER:
+ index = SendDlgItemMessage(hwndDlg, IDC_FILTER_TO, CB_GETCURSEL, 0, 0);
+ size = SendDlgItemMessage(hwndDlg, IDC_FILTER_TO, CB_DELETESTRING, index, 0);
+ SendDlgItemMessage(hwndDlg, IDC_FILTER_TO, CB_SETCURSEL, min(index, size - 1), 0);
+ PostMessage(GetParent(hwndDlg), PSM_CHANGED, 0, 0);
+ break;
+ }
+ break;
+ }
+ case WM_NOTIFY://apply changes so write it to db
+ if (bInit) {
+ break;
+ }
+ switch (((LPNMHDR)lParam)->idFrom) {
+ case 0:
+ switch (((LPNMHDR)lParam)->code) {
+ case PSN_RESET:
+ LoadSettings();
+ return TRUE;
+
+ case PSN_APPLY:
+ SaveSettings(hwndDlg);
+ return TRUE;
+ }
+
+ break;
+ } //id from
+
+ if (GetDlgItem(hwndDlg, IDC_STATUS) == ((LPNMHDR)lParam)->hwndFrom) {
+ switch (((LPNMHDR)lParam)->code) {
+ case LVN_ITEMCHANGED:
+ {
+ NMLISTVIEW *nmlv = (NMLISTVIEW *)lParam;
+ if ((nmlv->uNewState ^ nmlv->uOldState) & LVIS_STATEIMAGEMASK) {
+ SendMessage(GetParent(hwndDlg), PSM_CHANGED, 0, 0);
+ }
+ break;
+
+ }
+ break;
+ }
+ }
+ break; //switch(msg)
+
+ }
+ return FALSE;
+}
+
+
+//options page on miranda called
+int LotusNotifyOptInit(WPARAM wParam, LPARAM)
+{
+ OPTIONSDIALOGPAGE odp = {};
+ odp.szGroup.w = LPGENW("Plugins");
+ odp.szTitle.w = _A2W(__PLUGIN_NAME);
+ odp.flags = ODPF_BOLDGROUPS | ODPF_UNICODE;
+
+ odp.szTab.w = LPGENW("Connection");
+ odp.pszTemplate = MAKEINTRESOURCEA(IDD_OPT_LOTUS_CONECTION);
+ odp.pfnDlgProc = DlgProcLotusNotifyConnectionOpts;
+ g_plugin.addOptions(wParam, &odp);
+
+ odp.szTab.w = LPGENW("Popup");
+ odp.pszTemplate = MAKEINTRESOURCEA(IDD_OPT_LOTUS_POPUP);
+ odp.pfnDlgProc = DlgProcLotusNotifyPopupOpts;
+ g_plugin.addOptions(wParam, &odp);
+
+ odp.szTab.w = LPGENW("Miscellaneous");
+ odp.pszTemplate = MAKEINTRESOURCEA(IDD_OPT_LOTUS_MISC);
+ odp.pfnDlgProc = DlgProcLotusNotifyMiscOpts;
+ g_plugin.addOptions(wParam, &odp);
+ return 0;
+}
+
+
+//gives protocol avainable statuses
+INT_PTR GetCaps(WPARAM wParam, LPARAM)
+{
+ if (wParam == PFLAGNUM_1)
+ return 0;
+ if (wParam == PFLAGNUM_2)
+ return PF2_ONLINE; // add the possible statuses here.
+ if (wParam == PFLAGNUM_3)
+ return 0;
+ return 0;
+}
+
+
+//gives name to protocol module
+INT_PTR GetName(WPARAM wParam, LPARAM lParam)
+{
+ strncpy((char*)lParam, MODULENAME, wParam);
+ return 0;
+}
+
+
+//gives icon for proto module
+INT_PTR TMLoadIcon(WPARAM wParam, LPARAM)
+{
+ UINT id;
+
+ switch (wParam & 0xFFFF) {
+ case PLI_PROTOCOL:
+ id = IDI_ICON1;
+ break; // IDI_TM is the main icon for the protocol
+ default:
+ return 0;
+ }
+ return (INT_PTR)LoadImage(g_plugin.getInst(), MAKEINTRESOURCE(id), IMAGE_ICON, GetSystemMetrics(wParam & PLIF_SMALL ? SM_CXSMICON : SM_CXICON), GetSystemMetrics(wParam & PLIF_SMALL ? SM_CYSMICON : SM_CYICON), 0);
+}
+
+
+INT_PTR SetStatus(WPARAM wParam, LPARAM lParam)
+{
+ if (wParam == ID_STATUS_OFFLINE) {
+ // the status has been changed to online (maybe run some more code)
+ Menu_EnableItem(hMenuHandle, FALSE);
+ diffstat = 0;
+
+ }
+ else if (wParam == ID_STATUS_ONLINE) {
+ diffstat = 0;
+ //Menu_EnableItem(hMenuHandle ,TRUE);
+ //NotifyEventHooks(hCheckEvent,wParam,lParam);
+ // the status has been changed to offline (maybe run some more code)
+ if (currentStatus != ID_STATUS_ONLINE) {
+ if (startuperror) {
+ int cnt;
+ for (cnt = 0; cnt <= 4; cnt++)
+ if (startuperror >> cnt & 1)
+ ErMsgT(TranslateW(startuperrors[cnt]));
+ return 1;
+ }
+
+ if (check() == 0) {
+ if (settingInterval != 0)
+ SetTimer(hTimerWnd, TID, settingInterval * 60000, atTime);
+ Menu_EnableItem(hMenuHandle, TRUE);
+ }
+ else {
+ ProtoBroadcastAck(MODULENAME, NULL, ACKTYPE_STATUS, ACKRESULT_FAILED, (HANDLE)currentStatus, wParam);
+ return -1;
+ }
+ }
+ }
+ else {
+ int retv;
+ if (settingStatus[wParam - ID_STATUS_ONLINE])
+ retv = SetStatus(ID_STATUS_OFFLINE, lParam);
+ else
+ retv = SetStatus(ID_STATUS_ONLINE, lParam);
+ //Menu_EnableItem(hMenuHandle ,TRUE);
+ diffstat = wParam;
+ return retv;
+ // the status has been changed to unknown (maybe run some more code)
+ }
+ //broadcast the message
+ if (currentStatus != (int)wParam)
+ ProtoBroadcastAck(MODULENAME, NULL, ACKTYPE_STATUS, ACKRESULT_SUCCESS, (HANDLE)currentStatus, wParam);
+ currentStatus = wParam;
+
+ return 0;
+}
+
+
+void checkEnvPath(wchar_t *path)
+{
+ log_p(L"checkEnvPath: [%s]", path);
+
+ wcslwr(path);
+ wchar_t *cur = _wgetenv(L"PATH");
+ wcslwr(cur);
+ wchar_t *found = wcsstr(cur, path);
+ size_t len = mir_wstrlen(path);
+ if (found != nullptr && (found[len] == ';' || found[len] == 0 || (found[len] == '\\' && (found[len + 1] == ';' || found[len + 1] == 0))))
+ return;
+
+ _wputenv(CMStringW(FORMAT, L"PATH=%s;%s;", cur, path));
+}
+
+//GetStatus
+static INT_PTR GetStatus(WPARAM, LPARAM)
+{
+ return currentStatus;
+}
+
+
+//called after all plugins loaded.
+//all lotus staff will be called, that will not hang miranda on startup
+static int modulesloaded(WPARAM, LPARAM)
+{
+ int cnt;
+ wchar_t path[255] = { 0 };
+
+ log(L"Modules loaded, lets start LN...");
+
+ GetLotusPath(path, sizeof(path));
+ checkEnvPath(path);
+ wcscat_s(path, _countof(path), L"nnotes.dll");
+ assert(mir_wstrlen(path) > 0);
+
+ log_p(L"Loading dll: %s", path);
+
+ hLotusDll = LoadLibrary(path);
+ assert(hLotusDll);
+ if (hLotusDll != nullptr) {
+
+ log(L"Loading LN Functions");
+
+ if (!HookLotusFunctions()) {
+ FreeLibrary(hLotusDll);
+ startuperror += 1;
+ }
+ else {
+
+ log(L"Initializing Lotus");
+
+ if (NotesInitExtended1(0, nullptr)) {
+
+ //initialize lotus //TODO: Lotus can terminate miranda process here with msgbox "Shared Memory from a previous Notes/Domino run has been detected, this process will exit now"
+ startuperror += 4;
+ running = TRUE;
+ Menu_EnableItem(hMenuHandle, !running);//disable menu cause lotus is not initialized
+
+ }
+ else {
+ log(L"Checking Notes Ini File");
+ if (!checkNotesIniFile(FALSE)) {
+ startuperror += 16;
+ }
+ }
+ }
+
+ }
+ else {
+ startuperror += 2;
+ }
+
+ assert(startuperror == 0);
+ for (cnt = 0; cnt <= 4; cnt++) {
+ if (startuperror >> cnt & 1)
+ ErMsgT(TranslateW(startuperrors[cnt]));
+ }
+
+ return 0;
+}
+
+
+//function hooks before unload
+static int preshutdown(WPARAM, LPARAM)
+{
+ Plugin_Terminated = true;
+ deleteElements();
+ if (hLotusDll) {
+ NotesTerm1();
+ FreeLibrary(hLotusDll);
+ }
+ return 0;
+}
+
+
+int CMPlugin::Load()
+{
+ Plugin_Terminated = false;
+
+ //if(pluginLink)//strange, but this function is called by Lotus API Extension Manager (instead of MainEntryPoint) probably always with parameter poiter =1
+ if (bMirandaCall) {
+ STATUS rc = EMRegister1(EM_GETPASSWORD, EM_REG_BEFORE | EM_REG_AFTER, EMCallBack, 0, &hLotusRegister); //Extension Manager must know that we are here
+ if (rc) {
+ //Extension magager don't know who we are :(
+ startuperror += 8;
+ // Get the info from the .ini file
+ }
+ //log_p(L"Load: Registered Ext. Mngr. res=%d", rc);
+ return rc;
+ }
+ bMirandaCall = TRUE;
+
+ init_pluginname();
+ logRegister();
+ log_p(L"Load: Entering LotusNotify.dll Load() bMirandaCall=%d MODULENAME=[%S]", bMirandaCall, MODULENAME);
+
+ if (!(hCheckEvent = CreateHookableEvent("LotusNotify/Check"))) //check if there is another copy of plugin running
+ second = TRUE;
+
+ HookEvent("LotusNotify/Check", eventCheck); //hook function to menu click event
+
+ if (!second) //if its first plugin instance
+ {
+ //function that will be called on menu click
+ CreateServiceFunction("LotusNotify/MenuCommand", PluginMenuCommand);
+
+ CMenuItem mi(&g_plugin);
+ SET_UID(mi, 0x4519458, 0xb55a, 0x4e22, 0xac, 0x95, 0x5e, 0xa4, 0x4d, 0x92, 0x65, 0x65);
+ mi.position = -0x7FFFFFFF; //on top menu position
+ mi.flags = CMIF_UNICODE;
+ mi.hIcolibItem = LoadIcon(g_plugin.getInst(), MAKEINTRESOURCE(IDI_ICON1));
+ mi.name.w = LPGENW("&Check Lotus");
+ mi.pszService = "LotusNotify/MenuCommand"; //service name thet listning for menu call
+ hMenuHandle = Menu_AddMainMenuItem(&mi); //create menu pos.
+
+ Menu_EnableItem(hMenuHandle, FALSE);
+ }
+
+ // set all contacts to offline
+ for (auto &hContact : Contacts(MODULENAME))
+ g_plugin.setWord(hContact, "status", ID_STATUS_OFFLINE);
+
+ CreateProtoServiceFunction(MODULENAME, PS_GETCAPS, GetCaps);
+ CreateProtoServiceFunction(MODULENAME, PS_GETNAME, GetName);
+ CreateProtoServiceFunction(MODULENAME, PS_LOADICON, TMLoadIcon);
+ CreateProtoServiceFunction(MODULENAME, PS_SETSTATUS, SetStatus);
+ CreateProtoServiceFunction(MODULENAME, PS_GETSTATUS, GetStatus);
+
+ LoadSettings(); //read from db to variables
+
+ g_plugin.addSound("LotusNotify", LPGENW("Lotus Notify"), LPGENW("New Lotus document detected"));
+
+ HookEvent(ME_OPT_INITIALISE, LotusNotifyOptInit); //register service to hook option call
+ HookEvent(ME_SYSTEM_MODULESLOADED, modulesloaded); //hook event that all plugins are loaded
+ HookEvent(ME_SYSTEM_PRESHUTDOWN, preshutdown);
+
+ log(L"Load: ok");
+ return 0;
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+
+int CMPlugin::Unload()
+{
+ log(L"Unload: start");
+ Plugin_Terminated = true;
+ mir_cslock lck(checkthreadCS);
+
+ DestroyHookableEvent(hCheckEvent);
+
+ log(L"Unload: ok");
+ logUnregister();
+
+ ExtClear();
+ return 0;
+}
diff --git a/protocols/LotusNotify/src/LotusNotify.h b/protocols/LotusNotify/src/LotusNotify.h
new file mode 100644
index 0000000000..90f455e34f
--- /dev/null
+++ b/protocols/LotusNotify/src/LotusNotify.h
@@ -0,0 +1,37 @@
+#pragma once
+
+struct HISTORIA
+{
+ DWORD noteID;
+ BOOL clicked;
+ BOOL again;
+ struct HISTORIA *next;
+ struct POPUPSQUEUE *pq;
+};
+
+struct POPUPSQUEUE
+{
+ HWND hWnd;
+ struct POPUPSQUEUE *next;
+};
+
+// structure contines only LN msg id to send to popup
+
+typedef struct {
+ DWORD id;
+ char strNote[4*16];
+} POPUPATT;
+
+__declspec(dllexport) STATUS LNPUBLIC MainEntryPoint (void);
+
+void ErMsgT(wchar_t* msg);
+
+void checkthread(void*);
+
+struct CMPlugin : public PLUGIN<CMPlugin>
+{
+ CMPlugin();
+
+ int Load() override;
+ int Unload() override;
+};
diff --git a/protocols/LotusNotify/src/cnotesapi/include/bsafeerr.h b/protocols/LotusNotify/src/cnotesapi/include/bsafeerr.h
new file mode 100644
index 0000000000..da2175a620
--- /dev/null
+++ b/protocols/LotusNotify/src/cnotesapi/include/bsafeerr.h
@@ -0,0 +1,931 @@
+
+#if defined(OS400) && (__OS400_TGTVRM__ >= 510)
+#pragma datamodel(P128)
+#endif
+
+/*********************************************************************/
+/* */
+/* Licensed Materials - Property of IBM */
+/* */
+/* L-GHUS-5VMPGW, L-GHUS-5S3PEE */
+/* (C) Copyright IBM Corp. 1989, 2005 All Rights Reserved */
+/* */
+/* US Government Users Restricted Rights - Use, duplication or */
+/* disclosure restricted by GSA ADP Schedule Contract with */
+/* IBM Corp. */
+/* */
+/*********************************************************************/
+
+
+
+#ifndef BSAFE_ERR_DEFS
+#define BSAFE_ERR_DEFS
+
+
+/* BSAFE (Security package) Error Code Definitions */
+
+#define ERR_BSAFE_PSW_PROMPT (PKG_BSAFE+0)
+#ifdef OS400
+ errortext(ERR_BSAFE_PSW_PROMPT, "Enter password (press the F3 key to abort): ")
+#else
+ errortext(ERR_BSAFE_PSW_PROMPT, "Enter password (press the Esc key to abort): ")
+#endif
+#define ERR_BSAFE_FALSE (PKG_BSAFE+1)
+ internaltext(ERR_BSAFE_FALSE, "Do not suspend operation")
+#define ERR_BSAFE_ALLOCATE (PKG_BSAFE+2)
+ internaltext(ERR_BSAFE_ALLOCATE, "Error allocating security block")
+#define ERR_BSAFE_FREE (PKG_BSAFE+3)
+ internaltext(ERR_BSAFE_FREE, "Error freeing security block")
+#define ERR_BSAFE_ENTRY (PKG_BSAFE+4)
+ internaltext(ERR_BSAFE_ENTRY, "Error initializing security block")
+#define ERR_BSAFE_EXIT (PKG_BSAFE+5)
+ internaltext(ERR_BSAFE_EXIT, "Error cleaning up security block")
+#define ERR_BSAFE_PAUSE (PKG_BSAFE+6)
+ internaltext(ERR_BSAFE_PAUSE, "Security operation temporarily suspended")
+#define ERR_BSAFE_BADKEY (PKG_BSAFE+7)
+ errortext(ERR_BSAFE_BADKEY, "The encrypted data has been modified or the wrong key was used to decrypt it")
+#define ERR_BSAFE_BADCTX (PKG_BSAFE+8)
+ errortext(ERR_BSAFE_BADCTX, "Bad Security Context information")
+#define ERR_BSAFE_BADOPCODE (PKG_BSAFE+9)
+ errortext(ERR_BSAFE_BADOPCODE, "Illegal Security function code")
+#define ERR_BSAFE_BADCHECKSUM (PKG_BSAFE+10)
+ errortext(ERR_BSAFE_BADCHECKSUM, "The encrypted data has been modified or the wrong key was used to decrypt it")
+#define ERR_BSAFE_BADDATA (PKG_BSAFE+11)
+ errortext(ERR_BSAFE_BADDATA, "The encrypted data has been modified or the wrong key was used to decrypt it")
+
+#define ERR_BSAFE_BUG_1 (PKG_BSAFE+12)
+ errortext(ERR_BSAFE_BUG_1, "BSAFE package software error #1")
+#define ERR_BSAFE_POOLFULL (PKG_BSAFE+13)
+ errortext(ERR_BSAFE_POOLFULL, "Insufficient memory - BSAFE pool is full")
+
+#define ERR_BSAFE_CACHEFULL (PKG_BSAFE+14)
+ errortext(ERR_BSAFE_CACHEFULL, "Insufficient memory - BSAFE Name lookup cache is full")
+
+#define ERR_BSAFE_TOOSMALL (PKG_BSAFE+15)
+ errortext(ERR_BSAFE_TOOSMALL, "Buffer used to receive cryptographic output was too small")
+#define ERR_BSAFE_BAD_ATTRIBUTES (PKG_BSAFE+16)
+ errortext(ERR_BSAFE_BAD_ATTRIBUTES, "Inconsistent name attributes")
+#define ERR_BSAFE_MDLENGTH (PKG_BSAFE+17)
+ errortext(ERR_BSAFE_MDLENGTH, "Bad Message Digest length")
+#define ERR_BSAFE_NOT_ALLOWED (PKG_BSAFE+18)
+ errortext(ERR_BSAFE_NOT_ALLOWED, "Attempted encryption operation is not supported by this version of Notes.")
+#define ERR_BSAFE_ILLEGAL_IDFILE (PKG_BSAFE+19)
+ errortext(ERR_BSAFE_ILLEGAL_IDFILE, "The specified ID file may only be used inside of North America.")
+#define ERR_BSAFE_BAD_PI_VERSION (PKG_BSAFE+20)
+ errortext(ERR_BSAFE_BAD_PI_VERSION, "The public key or certificate version stored in the Address Book is not supported.")
+#define ERR_BSAFE_BAD_PI_CHECKSUM (PKG_BSAFE+21)
+ errortext(ERR_BSAFE_BAD_PI_CHECKSUM, "The public key or certificate stored in the Address Book has been corrupted.")
+#define ERR_BSAFE_MISSING_PI (PKG_BSAFE+22)
+ errortext(ERR_BSAFE_MISSING_PI, "There is no certificate in the Address Book.")
+#define ERR_BSAFE_TABLE_MUST_BE_HI (PKG_BSAFE+23)
+ errortext(ERR_BSAFE_TABLE_MUST_BE_HI, "The supplied certificate table does not contain any hierarchical certificates")
+#define ERR_BSAFE_NO_COMMON_CERT (PKG_BSAFE+24)
+ errortext(ERR_BSAFE_NO_COMMON_CERT, "No certificates in common")
+#define ERR_BSAFE_CERTTABLE_VERSION (PKG_BSAFE+25)
+ errortext(ERR_BSAFE_CERTTABLE_VERSION, "Unrecognized certificate table version")
+#define ERR_BSAFE_ILLUSE_GENID (PKG_BSAFE+26)
+ errortext(ERR_BSAFE_ILLUSE_GENID, "Illegal use of an ID generator file")
+#define ERR_BSAFE_NOT_GENID (PKG_BSAFE+27)
+ errortext(ERR_BSAFE_NOT_GENID, "Specified file is not an ID generator file")
+#define ERR_BSAFE_NOSUCH_PRVKEY (PKG_BSAFE+28)
+ errortext(ERR_BSAFE_NOSUCH_PRVKEY, "Specified private key does not exist")
+#define ERR_BSAFE_NOSUCH_ESCROW (PKG_BSAFE+29)
+ errortext(ERR_BSAFE_NOSUCH_ESCROW, "This version of the software does not know the key of a required escrow authority")
+#define ERR_BSAFE_NETFILE (PKG_BSAFE+30)
+ errortext(ERR_BSAFE_NETFILE, "WARNING: Network-based ID files should be password protected!")
+#define ERR_BSAFE_BAD_IDFILE_VERSION (PKG_BSAFE+31)
+ errortext(ERR_BSAFE_BAD_IDFILE_VERSION, "Unsupported ID file version.")
+#define ERR_BSAFE_NOSUCH_PUBKEY (PKG_BSAFE+32)
+ errortext(ERR_BSAFE_NOSUCH_PUBKEY, "Specified public key does not exist")
+#define ERR_BSAFE_PROC_NOT_INITED (PKG_BSAFE+33)
+ errortext(ERR_BSAFE_PROC_NOT_INITED, "Process has not initialized with the security package")
+#define ERR_BSAFE_SUBPROCESS (PKG_BSAFE+34)
+ errortext(ERR_BSAFE_SUBPROCESS, "A sub-process cannot change to a new ID file or prompt for passwords.")
+#define ERR_BSAFE_NOMEMORY (PKG_BSAFE+35)
+ errortext(ERR_BSAFE_NOMEMORY, "Insufficient memory for attempted security operation.")
+#define ERR_BSAFE_ILLFUNC (PKG_BSAFE+36)
+ debugtext(ERR_BSAFE_ILLFUNC, "Unknown security function code.")
+#define ERR_BSAFE_NULLPARAM (PKG_BSAFE+37)
+ debugtext(ERR_BSAFE_NULLPARAM, "Illegal null parameter passed to security function.")
+#define ERR_BSAFE_INVALID_XCERT (PKG_BSAFE+38)
+ errortext(ERR_BSAFE_INVALID_XCERT, "Invalid Cross Certificate was found for %a. This could be a possible attack, please notify your administrator. Select 'Yes' to keep the current existing Cross Certificate")
+#define ERR_BSAFE_ILLUSE_SAFECOPY (PKG_BSAFE+39)
+ errortext(ERR_BSAFE_ILLUSE_SAFECOPY, "The ID file is a safe copy and cannot be used for that purpose.")
+#define ERR_BSAFE_USER_ABORT (PKG_BSAFE+40)
+ errortext(ERR_BSAFE_USER_ABORT, "The prompt for password was aborted by user")
+#define ERR_BSAFE_ID_PROTECTED (PKG_BSAFE+41)
+ errortext(ERR_BSAFE_ID_PROTECTED, "Cannot access or create the ID file")
+#define ERR_BSAFE_ID_CREATE (PKG_BSAFE+42)
+ errortext(ERR_BSAFE_ID_CREATE, "ID file cannot be created")
+
+#define ERR_BSAFE_ID_TRUNC (PKG_BSAFE+43)
+ errortext(ERR_BSAFE_ID_TRUNC, "The specified ID file has been corrupted, or is not an ID file")
+#define ERR_BSAFE_CORRUPTIDFILE ERR_BSAFE_ID_TRUNC
+
+#define ERR_BSAFE_ID_INVFILENAME (PKG_BSAFE+44)
+ errortext(ERR_BSAFE_ID_INVFILENAME, "Illegal ID file name: too long or uses invalid syntax")
+#define ERR_BSAFE_ID_WRITETRUNC (PKG_BSAFE+45)
+ errortext(ERR_BSAFE_ID_WRITETRUNC, "Cannot write to ID file; either it is READ-ONLY or the disk is out of space")
+#define ERR_BSAFE_ID_INVDRIVE (PKG_BSAFE+46)
+ errortext(ERR_BSAFE_ID_INVDRIVE, "Invalid drive specified for ID file")
+#define ERR_BSAFE_NON_EXISTENT (PKG_BSAFE+47)
+ errortext(ERR_BSAFE_NON_EXISTENT, "The requested item does not exist")
+#define ERR_BSAFE_NEK_NOT_FOUND (PKG_BSAFE+48)
+ errortext(ERR_BSAFE_NEK_NOT_FOUND, "You don't have any of the specified encryption keys")
+#define ERR_BSAFE_KEY_NOT_FOUND (PKG_BSAFE+49)
+ errortext(ERR_BSAFE_KEY_NOT_FOUND, "The cryptographic key was not found")
+#define ERR_BSAFE_KEY_INV_FORMAT (PKG_BSAFE+50)
+ errortext(ERR_BSAFE_KEY_INV_FORMAT, "The cryptographic key's format is invalid")
+#define ERR_BSAFE_NO_KEYS (PKG_BSAFE+51)
+ errortext(ERR_BSAFE_NO_KEYS, "Your ID file does not contain any encryption keys")
+#define ERR_BSAFE_UNKNOWN_CERTIFICATE (PKG_BSAFE+52)
+ errortext(ERR_BSAFE_UNKNOWN_CERTIFICATE,"Unrecognized or unsupported certificate type")
+#define ERR_BSAFE_UNKNOWN_IDFILE (PKG_BSAFE+53)
+ errortext(ERR_BSAFE_UNKNOWN_IDFILE, "Unrecognized or unsupported ID File type")
+#define ERR_BSAFE_UNKNOWN_DOCKEY (PKG_BSAFE+54)
+ errortext(ERR_BSAFE_UNKNOWN_DOCKEY, "Unrecognized or unsupported document encryption key type stored in the ID file")
+#define ERR_BSAFE_UNKNOWN_USERINFO (PKG_BSAFE+55)
+ errortext(ERR_BSAFE_UNKNOWN_USERINFO, "Unrecognized or unsupported user-information structure")
+#define ERR_BSAFE_UNKNOWN_ITEM (PKG_BSAFE+56)
+ debugtext(ERR_BSAFE_UNKNOWN_ITEM, "Internal error: unknown BSAFE-item code or version")
+#define ERR_BSAFE_INV_DNAME (PKG_BSAFE+57)
+ debugtext(ERR_BSAFE_INV_DNAME, "Invalid name syntax")
+
+/* Note: next error message name is misleading; the error was reused for
+* exceeding a 64K buffer length in a variety of cases.
+*/
+
+#define ERR_BSAFE_ODSCERT_TOOBIG (PKG_BSAFE+58)
+ errortext(ERR_BSAFE_ODSCERT_TOOBIG, "Certificate object requires more than 64K bytes")
+#define ERR_BSAFE_UNKNOWN_UDO (PKG_BSAFE+59)
+ errortext(ERR_BSAFE_UNKNOWN_UDO, "Unrecognized or unsupported user-descriptor object found in the ID file")
+#define ERR_BSAFE_FILE_NOT_OPENED (PKG_BSAFE+60)
+ errortext(ERR_BSAFE_FILE_NOT_OPENED, "You must first open the ID file before attempting that operation")
+
+#define ERR_BSAFE_CERTIFICATE_REVOKED (PKG_BSAFE + 61)
+ errortext (ERR_BSAFE_CERTIFICATE_REVOKED, "The certificate was revoked")
+#define ERR_BSAFE_CERT_VALIDITY (PKG_BSAFE + 62)
+ errortext (ERR_BSAFE_CERT_VALIDITY, "Certificate is expired or not yet valid")
+#define ERR_BSAFE_CRL_VALIDITY (PKG_BSAFE + 63)
+ errortext (ERR_BSAFE_CRL_VALIDITY, "The CRL is expired or not yet valid")
+#define ERR_BSAFE_CRL_NOT_FOUND (PKG_BSAFE + 64)
+ errortext (ERR_BSAFE_CRL_NOT_FOUND, "A CRL was required, but not found for the certificate")
+#define ERR_BSAFE_KEY_USAGE (PKG_BSAFE + 65)
+ errortext (ERR_BSAFE_KEY_USAGE, "The certificate or chain is invalid due to a key usage violation")
+#define ERR_BSAFE_BASIC_CONSTRAINTS (PKG_BSAFE + 66)
+ errortext (ERR_BSAFE_BASIC_CONSTRAINTS, "The certificate or chain is invalid due to a basic constraints violation")
+#define STR_BSAFE_IDC_SUBJECT (PKG_BSAFE+67)
+ stringtext(STR_BSAFE_IDC_SUBJECT, "%A has certified the ID belonging to %A. The certificate can be merged into your ID file by using the Actions menu 'Accept Certificate...' option.")
+#define ERR_BSAFE_SENDER_SIGNING_CERT_IS_EXPIRED (PKG_BSAFE+68)
+ errortext(ERR_BSAFE_SENDER_SIGNING_CERT_IS_EXPIRED, "Senders' signing certificate is expired")
+#define ERR_BSAFE_SENDER_SIGNING_CERT_HAS_SINCE_EXPIRED (PKG_BSAFE+69)
+ errortext(ERR_BSAFE_SENDER_SIGNING_CERT_HAS_SINCE_EXPIRED, "Senders' signing certificate has expired after this mail was signed")
+#define ERR_BSAFE_INVALID_XCERT_NO_ARG (PKG_BSAFE+70)
+ errortext(ERR_BSAFE_INVALID_XCERT_NO_ARG, "An invalid Cross Certificate was found. It may be a corrupted Cross Certificate, an attack or a new public key issued. Please notify administrator of the problem")
+#define ERR_BSAFE_CANT_CREATE_XCERT (PKG_BSAFE+71)
+ errortext(ERR_BSAFE_CANT_CREATE_XCERT, "The requested Cross Certificate will not be issued because the subject is already trusted.")
+#define ERR_BSAFE_WRONG_SUBJECT_KEY_IN_SIGNATURE (PKG_BSAFE+72)
+ errortext (ERR_BSAFE_WRONG_SUBJECT_KEY_IN_SIGNATURE, "The signer's public key found in the signature does not match the one stored in the directory")
+#define ERR_BSAFE_NO_VALID_PW (PKG_BSAFE+73)
+ errortext (ERR_BSAFE_NO_VALID_PW, "Password has not yet been validated")
+
+#define ERR_BSAFE_ILL_PW_ALG (PKG_BSAFE+74)
+ errortext (ERR_BSAFE_ILL_PW_ALG, "Unrecognized password object or algorithm")
+
+/* available PKG_BSAFE+75 */
+#define STR_BSAFE_SMIME_UNABLE_TO_DECODE_STREAM (PKG_BSAFE+76)
+ stringtext(STR_BSAFE_SMIME_UNABLE_TO_DECODE_STREAM, "Unable to decode S/MIME stream")
+#define ERR_BSAFE_IDFILE_LOCKED (PKG_BSAFE+77)
+ errortext(ERR_BSAFE_IDFILE_LOCKED, "The ID File is in use elsewhere and cannot be modified")
+#define ERR_BSAFE_NEK_EXISTS (PKG_BSAFE+78)
+ errortext(ERR_BSAFE_NEK_EXISTS, "Cannot add the encryption key to your ID file. A key with that name already exists.")
+#define ERR_BSAFE_KFM_INVREADOPT (PKG_BSAFE+79)
+ debugtext(ERR_BSAFE_KFM_INVREADOPT, "Software error: conflicting read ID File options")
+#define ERR_BSAFE_MERGE_NONCOPY (PKG_BSAFE+80)
+ errortext(ERR_BSAFE_MERGE_NONCOPY, "The certificate(s) have not been issued to you and cannot be merged into your ID file. They have been issued to")
+#define ERR_BSAFE_MERGE_NOPRVKEY (PKG_BSAFE+81)
+ errortext(ERR_BSAFE_MERGE_NOPRVKEY, "The Public Key cannot be accepted since there is no matching Private Key found in the ID file.")
+#define ERR_BSAFE_NONAMECHANGE (PKG_BSAFE+82)
+ errortext(ERR_BSAFE_NONAMECHANGE, "If you change the user name, this ID will lose all of its certificates. When the name change is complete, this ID will need to be certified. Do you want to continue?")
+#define ERR_BSAFE_NOMERGECERT (PKG_BSAFE+83)
+ errortext(ERR_BSAFE_NOMERGECERT, "There are no certificates to be merged into your ID file")
+#define ERR_BSAFE_INVUSERIDFILE (PKG_BSAFE+84)
+ errortext(ERR_BSAFE_INVUSERIDFILE, "Your ID file has been corrupted, or is not an ID file.")
+#define ERR_BSAFE_CORRUPTFILE (PKG_BSAFE+85)
+ errortext(ERR_BSAFE_CORRUPTFILE, "The specified ID file has been corrupted, or is not an ID file.")
+#define ERR_BSAFE_REQUIRES_NONFLATID (PKG_BSAFE+86)
+ errortext(ERR_BSAFE_REQUIRES_NONFLATID, "This request is not supported with the version of your ID file. An ID file containing a hierarchical name is required.")
+#define ERR_BSAFE_NO_CROSS_CERT (PKG_BSAFE+87)
+ errortext(ERR_BSAFE_NO_CROSS_CERT, "The Address Book does not contain a cross certificate capable of validating the public key.")
+#define ERR_BSAFE_INCOMPLETE_CERTTABLE (PKG_BSAFE+88)
+ errortext(ERR_BSAFE_INCOMPLETE_CERTTABLE, "The certificate table does not contain enough valid certificates to verify the public key of its owner.")
+#define ERR_BSAFE_ILLUSE_CERTIFIER (PKG_BSAFE+89)
+ errortext(ERR_BSAFE_ILLUSE_CERTIFIER, "Illegal use of a Certifier ID file")
+#define ERR_BSAFE_MUSTBE_CERTIFIER (PKG_BSAFE+90)
+ errortext(ERR_BSAFE_MUSTBE_CERTIFIER, "The ID file is not a Certifier ID file and cannot be used to issue certificates")
+#define ERR_BSAFE_WRITEPROTECTED (PKG_BSAFE+91)
+ errortext(ERR_BSAFE_WRITEPROTECTED, "The ID file is write protected")
+#define ERR_BSAFE_NOPSW_ON_SAFECOPY (PKG_BSAFE+92)
+ errortext(ERR_BSAFE_NOPSW_ON_SAFECOPY, "This is a safe-copy version of an ID file and cannot be password protected")
+#define ERR_BSAFE_YOU_MUST_BE_HI (PKG_BSAFE+93)
+ errortext(ERR_BSAFE_YOU_MUST_BE_HI, "The local system cannot complete the operation because it is not running with a hierarchical name")
+#define ERR_BSAFE_WRONG_SUBJECT_KEY (PKG_BSAFE+94)
+ errortext(ERR_BSAFE_WRONG_SUBJECT_KEY, "The subject's public key found in the certificate is not the one stored in our ID file for that entity.")
+#define ERR_BSAFE_ILL_CERTTABLE (PKG_BSAFE+95)
+ errortext(ERR_BSAFE_ILL_CERTTABLE, "The supplied certificate table used to validate the signer's public key is improperly formed")
+#define ERR_BSAFE_CERTIFIER_MUST_BE_HI (PKG_BSAFE+96)
+ errortext(ERR_BSAFE_CERTIFIER_MUST_BE_HI, "The certifier has not been assigned a hierarchical name")
+#define ERR_BSAFE_EXTERNAL_PASSWORD (PKG_BSAFE+97)
+ errortext(ERR_BSAFE_EXTERNAL_PASSWORD, "Password Externally Supplied")
+#define ERR_BSAFE_EXTERNAL_PWD_AND_DATA (PKG_BSAFE+98)
+ errortext(ERR_BSAFE_EXTERNAL_PWD_AND_DATA, "Password and Data Externally Supplied")
+#define ERR_BSAFE_FLAT_KEY_TOO_BIG (PKG_BSAFE+99)
+ errortext(ERR_BSAFE_FLAT_KEY_TOO_BIG, "RSA key size limit for a flat ID exceeded")
+#define ERR_BSAFE_CERTREQ_SUBMITTED (PKG_BSAFE+100)
+ errortext(ERR_BSAFE_CERTREQ_SUBMITTED, "A certificate request has been submitted")
+
+#define ERR_BSAFE_ID_EXTRA_UPDATED (PKG_BSAFE+101)
+ errortext(ERR_BSAFE_ID_EXTRA_UPDATED, "%s username and password were updated in the ID file.")
+
+#define ERR_BSAFE_ID_EXTRA_UPDATE_FAIL (PKG_BSAFE+102)
+ errortext(ERR_BSAFE_ID_EXTRA_UPDATE_FAIL, "%s username and password could not be updated in the ID file.")
+
+#define ERR_BSAFE_CANCELED (PKG_BSAFE+103)
+ errortext(ERR_BSAFE_CANCELED, "Operation canceled")
+
+#define ERR_BSAFE_ID_EXTRA_DELETED (PKG_BSAFE+104)
+ errortext(ERR_BSAFE_ID_EXTRA_DELETED, "%s username and password were cleared from the ID file.")
+
+#define ERR_BSAFE_ASSIGNED_TO_DIFF_LANG (PKG_BSAFE+105)
+ errortext(ERR_BSAFE_ASSIGNED_TO_DIFF_LANG, "That name has already been associated with another language specifier.")
+
+#define ERR_BSAFE_ID_EXTRA_DELETE_FAIL (PKG_BSAFE+106)
+ errortext(ERR_BSAFE_ID_EXTRA_DELETE_FAIL, "%s username and password could not be cleared from the ID file.")
+
+
+#define ERR_BSAFE_CERT_HAS_ALTNAME (PKG_BSAFE+108)
+ errortext(ERR_BSAFE_CERT_HAS_ALTNAME, "The operation cannot be completed because the certificate contains an alternate name")
+
+#define ERR_BSAFE_ID_EXTRA_TYPE (PKG_BSAFE+109)
+ errortext(ERR_BSAFE_ID_EXTRA_TYPE, "Domino Controller|DB2")
+/* available PKG_BSAFE + 110 */
+
+#define ERR_BSAFE_USA_KEY_ONLY (PKG_BSAFE+111)
+ errortext(ERR_BSAFE_USA_KEY_ONLY, "This key may only be stored in ID files with North American licenses")
+#define ERR_BSAFE_ID_READ_ONLY (PKG_BSAFE+112)
+ errortext(ERR_BSAFE_ID_READ_ONLY, "The ID file was not opened for write access")
+#define ERR_BSAFE_NO_PUBLIC_INFO (PKG_BSAFE+113)
+ errortext(ERR_BSAFE_NO_PUBLIC_INFO, "Your public key was not found in the Name and Address Book")
+#define ERR_BSAFE_TOOMANY_ORG_UNITS (PKG_BSAFE+114)
+ errortext(ERR_BSAFE_TOOMANY_ORG_UNITS, "You can create only as many as four Organizational Unit levels")
+#define ERR_BSAFE_MUSTBE_HIERARCHICAL (PKG_BSAFE+115)
+ errortext(ERR_BSAFE_MUSTBE_HIERARCHICAL, "This request is not supported for the specified ID file. An ID file containing a hierarchical name is required.")
+#define ERR_BSAFE_ID_DRIVE_NOT_READY (PKG_BSAFE+116)
+ errortext(ERR_BSAFE_ID_DRIVE_NOT_READY, "The disk drive specified for the ID file is not ready")
+#define ERR_BSAFE_ID_DISK (PKG_BSAFE+117)
+ errortext(ERR_BSAFE_ID_DISK, "Cannot update the ID file; insufficient disk space")
+#define ERR_BSAFE_ID_IOERROR (PKG_BSAFE+118)
+ errortext(ERR_BSAFE_ID_IOERROR, "I/O error experienced while accessing the ID file")
+#define ERR_BSAFE_PASSWORD_REQUIRED (PKG_BSAFE+119)
+ errortext(ERR_BSAFE_PASSWORD_REQUIRED, "A password is required for this ID file")
+#define ERR_BSAFE_BAD_AUTH_CODE (PKG_BSAFE+120)
+ errortext(ERR_BSAFE_BAD_AUTH_CODE, "The authentication code has failed the consistency check")
+#define ERR_BSAFE_ILL_AUTH_CODE_VERSION (PKG_BSAFE+121)
+ errortext(ERR_BSAFE_ILL_AUTH_CODE_VERSION, "The authentication code version number is not supported")
+#define ERR_BSAFE_NEWNAME_TOO_LONG (PKG_BSAFE+122)
+ errortext(ERR_BSAFE_NEWNAME_TOO_LONG, "Cannot create certificate, resultant subject name would be too long")
+#define ERR_BSAFE_CERT_NOT_ANCESTOR (PKG_BSAFE+123)
+ errortext(ERR_BSAFE_CERT_NOT_ANCESTOR, "The certifier is not an ancestor of the subject in the certificate.")
+#define ERR_BSAFE_ILL_ATFUNC (PKG_BSAFE+124)
+ errortext(ERR_BSAFE_ILL_ATFUNC, "Unrecognized or unsupported @CERTIFICATE code")
+#define ERR_BSAFE_CERTIFIER_NOT_IN_NAB (PKG_BSAFE+125)
+ errortext(ERR_BSAFE_CERTIFIER_NOT_IN_NAB, "A required certifier entry was not found in the Name and Address Book; consult the Notes Log for details on the specific entry")
+#define ERR_BSAFE_ILL_DISTINFO (PKG_BSAFE+126)
+ errortext(ERR_BSAFE_ILL_DISTINFO, "Unrecognized or unsupported Distinguished Name structure")
+#define ERR_BSAFE_INSUF_INPUT_ARGS (PKG_BSAFE+127)
+ errortext(ERR_BSAFE_INSUF_INPUT_ARGS, "Internal error: too few parameters passed in subroutine call")
+#define ERR_BSAFE_CERT_MISMATCH (PKG_BSAFE+128)
+ errortext(ERR_BSAFE_CERT_MISMATCH, "Either the certificates' issuers or the certificates' subjects don't match")
+#define ERR_BSAFE_ILLUSE_XCERT (PKG_BSAFE+129)
+ errortext(ERR_BSAFE_ILLUSE_XCERT, "A cross-certificate was illegally used as a substitute for an ordinary certificate")
+#define ERR_BSAFE_TOO_MANY_CERTS (PKG_BSAFE+130)
+ errortext(ERR_BSAFE_TOO_MANY_CERTS, "Certificate table could not be constructed because there are too many certificates")
+#define ERR_BSAFE_TOO_FEW_CERTS (PKG_BSAFE+131)
+ errortext(ERR_BSAFE_TOO_FEW_CERTS, "The supplied Certificate Table is missing a required certificate to complete the operation")
+#define ERR_BSAFE_ID_MUST_BE_HI (PKG_BSAFE+132)
+ errortext(ERR_BSAFE_ID_MUST_BE_HI, "This operation is only supported for ID file's containing hierarchical names")
+#define ERR_BSAFE_INV_KFHANDLE (PKG_BSAFE+133)
+ errortext(ERR_BSAFE_INV_KFHANDLE, "Invalid KFHANDLE")
+#define ERR_BSAFE_FILE_LOCKED (PKG_BSAFE+134)
+ errortext(ERR_BSAFE_FILE_LOCKED, "The ID file is locked by another process. Try again later")
+#define ERR_BSAFE_MUST_BE_SERVER (PKG_BSAFE+135)
+ errortext(ERR_BSAFE_MUST_BE_SERVER, "Only the server process is allowed to attempt that operation")
+#define ERR_BSAFE_INAPPROPRIATE_ORGUNIT (PKG_BSAFE+136)
+ errortext(ERR_BSAFE_INAPPROPRIATE_ORGUNIT, "Org Unit may only be supplied when upgrading flat to hierarchical")
+
+/* available PKG_BSAFE+137 */
+
+#define ERR_BSAFE_WRONG_SUBJECT_KEY_X (PKG_BSAFE+138)
+ errortext(ERR_BSAFE_WRONG_SUBJECT_KEY_X, "The subject's public key found in the cross certificate does not match the one found in the certificate table.")
+#define ERR_BSAFE_INVCERT_DATA (PKG_BSAFE+139)
+ errortext(ERR_BSAFE_INVCERT_DATA, "Error processing certificate created by %A for %A")
+#define ERR_BSAFE_INVCROSSCERT_SIG (PKG_BSAFE+140)
+ errortext(ERR_BSAFE_INVCROSSCERT_SIG, "The signature on the cross certificate was found to be invalid. Check the log file for details.")
+#define ERR_BSAFE_WRONG_CERT_SUBJECT (PKG_BSAFE+141)
+ errortext(ERR_BSAFE_WRONG_CERT_SUBJECT, "The certificate contains the wrong subject name")
+#define ERR_BSAFE_WRONG_CERT_ISSUER (PKG_BSAFE+142)
+ errortext(ERR_BSAFE_WRONG_CERT_ISSUER, "The certificate contains the wrong issuer name")
+
+#define STR_BSAFE_SECPANEL_TRUST_CONSTRAINT_PEOPLE (PKG_BSAFE+143)
+ stringtext(STR_BSAFE_SECPANEL_TRUST_CONSTRAINT_PEOPLE, "Mail encryption certificate not found|Usable for signing only (no encryption)|Usable for encryption only (no signing)|May not pass verification checks")
+#define IDX_STR_BSAFE_SECPANEL_CERT_NOTFOUND 1
+#define IDX_STR_BSAFE_SECPANEL_CERT_NOENCRYPTION 2
+#define IDX_STR_BSAFE_SECPANEL_CERT_ENCRYPTION 3
+#define IDX_STR_BSAFE_SECPANEL_CERT_NOTVERIFIED 4
+
+#define STR_BSAFE_SECPANEL_TRUST_CONSTRAINT (PKG_BSAFE+144)
+ stringtext(STR_BSAFE_SECPANEL_TRUST_CONSTRAINT, "<All Names>|<All Internet Names>|*%s|<All Flat Names>")
+#define IDX_STR_BSAFE_SECPANEL_TRUST_CONSTRAINT_ALL 1
+#define IDX_STR_BSAFE_SECPANEL_TRUST_CONSTRAINT_ALLINET 2
+#define IDX_STR_BSAFE_SECPANEL_TRUST_CONSTRAINT_STARSTR 3
+#define IDX_STR_BSAFE_SECPANEL_TRUST_CONSTRAINT_ALLFLAT 4
+
+#define ERR_BSAFE_INVCERT_SIG (PKG_BSAFE+145)
+ errortext(ERR_BSAFE_INVCERT_SIG, "The signature on the certificate was found to be invalid. Check the log file for details.")
+
+#define ERR_BSAFE_SECPANEL_NO_HOME_SERVER (PKG_BSAFE+146)
+ errortext(ERR_BSAFE_SECPANEL_NO_HOME_SERVER, "Your home server could not be contacted or is not configured.")
+
+#define ERR_BSAFE_WRONG_SUBJECT_KEY_SRV (PKG_BSAFE+147)
+ errortext(ERR_BSAFE_WRONG_SUBJECT_KEY_SRV, "The subject's public key found in the certificate is not the one stored in the server's ID file for that entity. Check the server's log file for details.")
+#define ERR_BSAFE_WRONG_SUBJECT_KEY_LOC (PKG_BSAFE+148)
+ errortext(ERR_BSAFE_WRONG_SUBJECT_KEY_LOC, "The subject's public key found in the certificate is not the one stored in our ID file for that entity. Check the local log file for details.")
+#define ERR_BSAFE_CERT_NOT_ANCESTOR_SRV (PKG_BSAFE+149)
+ errortext(ERR_BSAFE_CERT_NOT_ANCESTOR_SRV, "The certifier is not an ancestor of the subject in the certificate. Check the server's log file for details.")
+#define ERR_BSAFE_CERT_NOT_ANCESTOR_LOC (PKG_BSAFE+150)
+ errortext(ERR_BSAFE_CERT_NOT_ANCESTOR_LOC, "The certifier is not an ancestor of the subject in the certificate. Check the local log file for details.")
+#define ERR_BSAFE_ADDBOOK_CERT_ENTRY (PKG_BSAFE+151)
+ errortext(ERR_BSAFE_ADDBOOK_CERT_ENTRY, "Error locating a Domino Directory entry for certifier %s")
+
+
+/* (PKG_BSAFE ends at 151 */
+
+
+#define ERR_BSAFE2_ATTRIBUTE_UNKNOWN (PKG_BSAFE2+0)
+ errortext(ERR_BSAFE2_ATTRIBUTE_UNKNOWN, "Attribute type is unrecognized ")
+
+#define ERR_BSAFE2_UNABLE_TO_PARSE_CERT (PKG_BSAFE2+1)
+ errortext(ERR_BSAFE2_UNABLE_TO_PARSE_CERT, "Unable to parse certificate ")
+
+#define ERR_BSAFE2_BAD_RECOVERY_INFO (PKG_BSAFE2+2)
+ errortext(ERR_BSAFE2_BAD_RECOVERY_INFO, "Nonexistent or invalid recovery information")
+
+#define ERR_BSAFE2_KEY_USAGE_RESTRICTION (PKG_BSAFE2+3)
+ errortext(ERR_BSAFE2_KEY_USAGE_RESTRICTION, "A cross certificate will not be made due to key usage restrictions in the input certificate.")
+
+#define ERR_BSAFE_BIG_CERT_ELEMENT (PKG_BSAFE2+4)
+ errortext (ERR_BSAFE_BIG_CERT_ELEMENT, "Certificate element too large for processing.")
+#define ERR_BSAFE_NAMELIST_VERSION (PKG_BSAFE2+5)
+ errortext (ERR_BSAFE_NAMELIST_VERSION, "Unrecognized name list version.")
+#define ERR_BSAFE_NAMELIST_MALFORMED (PKG_BSAFE2+6)
+ errortext (ERR_BSAFE_NAMELIST_MALFORMED, "The name list is improperly formed and may have been corrupted.")
+#define ERR_BSAFE_NAMELIST_NOSUCH_INDEX (PKG_BSAFE2+7)
+ errortext (ERR_BSAFE_NAMELIST_NOSUCH_INDEX, "The requested name list element does not exist.")
+#define ERR_BSAFE_TOO_MANY_ALTNAMES (PKG_BSAFE2+8)
+ errortext (ERR_BSAFE_TOO_MANY_ALTNAMES, "Too many alternate names in the name list.")
+#define ERR_BSAFE_LANGTAG_EXISTS (PKG_BSAFE2+9)
+ errortext (ERR_BSAFE_LANGTAG_EXISTS, "A name with the specified language already exits.")
+#define ERR_BSAFE_LANGTAG_UNKNOWN (PKG_BSAFE2+10)
+ errortext (ERR_BSAFE_LANGTAG_UNKNOWN, "The specified language is unknown")
+#define ERR_BSAFE_NAME_MALFORMED (PKG_BSAFE2+11)
+ errortext (ERR_BSAFE_NAME_MALFORMED, "An improperly formed name was encountered")
+#define ERR_BSAFE_INV_CERT (PKG_BSAFE2+12)
+ errortext (ERR_BSAFE_INV_CERT, "Invalid certificate contents or format")
+#define ERR_ASN1_ILL_OID (PKG_BSAFE2+13)
+ errortext (ERR_ASN1_ILL_OID, "Illegal ASN.1 Object ID field")
+#define ERR_ASN1_ILL_DATATYPE (PKG_BSAFE2+14)
+ errortext (ERR_ASN1_ILL_DATATYPE, "Illegal or unexpected ASN.1 data type")
+#define ERR_ASN1_ILL_DATALENGTH (PKG_BSAFE2+15)
+ errortext (ERR_ASN1_ILL_DATALENGTH, "Illegal or unsupported ASN.1 data length")
+
+/* (PKG_BSAFE2: limited to 0-15 */
+/* TIPEM errors */
+
+#define ERR_BSAFE3_TE_UNKNOWN (PKG_BSAFE3+0)
+ errortext (ERR_BSAFE3_TE_UNKNOWN, "Unknown S/MIME error")
+#define ERR_BSAFE3_TE_ASN_SIGNATURE (PKG_BSAFE3+1)
+ errortext (ERR_BSAFE3_TE_ASN_SIGNATURE, "Invalid signature on certificate or CRL")
+#define ERR_BSAFE3_TE_ATTRIBUTES_OBJ (PKG_BSAFE3+2)
+ errortext (ERR_BSAFE3_TE_ATTRIBUTES_OBJ, "Invalid cryptographic attributes object")
+#define ERR_BSAFE3_TE_EOS (PKG_BSAFE3+3)
+ errortext (ERR_BSAFE3_TE_EOS, "End of cryptographic data stream")
+
+#define ERR_BSAFE4_TE_MEMORY_OBJ (PKG_BSAFE3+4)
+ errortext (ERR_BSAFE4_TE_MEMORY_OBJ, "Invalid cryptographic memory object")
+#define ERR_BSAFE4_TE_OVER_32K (PKG_BSAFE3+5)
+ errortext (ERR_BSAFE4_TE_OVER_32K, "Cryptographic data block is too big to be processed")
+#define ERR_BSAFE4_TE_PARAMETER (PKG_BSAFE3+6)
+ errortext (ERR_BSAFE4_TE_PARAMETER, "Invalid parameter passed to cryptographic function")
+#define ERR_BSAFE5_TE_VERSION (PKG_BSAFE3+7)
+ errortext (ERR_BSAFE5_TE_VERSION, "S/MIME version not supported")
+
+#define ERR_BSAFE5_ERROR (PKG_BSAFE3+8)
+ errortext (ERR_BSAFE5_ERROR, "Error -- ")
+#define ERR_BSAFE5_WARNING (PKG_BSAFE3+9)
+ errortext (ERR_BSAFE5_WARNING, "Warning -- ")
+#define ERR_BSAFE5_LOG (PKG_BSAFE3+10)
+ errortext(ERR_BSAFE5_LOG, "%s %s")
+#define ERR_BSAFE5_TE_UNTRUSTED_CERTS_CRLS (PKG_BSAFE3+11)
+ errortext (ERR_BSAFE5_TE_UNTRUSTED_CERTS_CRLS, "Cannot establish trust in a certificate or CRL.")
+
+#define ERR_NOCA_KEYMATCH (PKG_BSAFE3+12)
+ errortext (ERR_NOCA_KEYMATCH, "The certifier key in the certificate does not match the key stored in the directory.")
+#define ERR_ILL_RECERT_FCT (PKG_BSAFE3+13)
+ errortext (ERR_ILL_RECERT_FCT, "The requested rename or recertify function is unknown or unsupported.")
+#define ERR_NO_ANCESTOR_LANGTAG (PKG_BSAFE3+14)
+ errortext (ERR_NO_ANCESTOR_LANGTAG, "The certifier has not yet been assigned a name associated with the proposed language.")
+#define ERR_NO_INET_KEY (PKG_BSAFE3+15)
+ errortext (ERR_NO_INET_KEY, "This entry has not been assigned a public key suitable for use on the internet.")
+
+#define ERR_BSAFE_NAME_EXISTS (PKG_BSAFE3+16)
+ errortext (ERR_BSAFE_NAME_EXISTS, "This name already exists.")
+
+#define ERR_BSAFE_INVALID_BB (PKG_BSAFE3+17)
+ errortext (ERR_BSAFE_INVALID_BB, "You are not authorized to recover this ID file.")
+
+
+
+#define ERR_ASN1_INV_SYNTAX (PKG_BSAFE3+18)
+ errortext (ERR_ASN1_INV_SYNTAX, "Invalid ASN.1 syntax")
+#define ERR_BSAFE_INV_CRL (PKG_BSAFE3+19)
+ errortext (ERR_BSAFE_INV_CRL, "Invalid CRL contents or format")
+#define ERR_BSAFE_INV_EXTENSIONS_OBJ (PKG_BSAFE3+20)
+ errortext (ERR_BSAFE_INV_EXTENSIONS_OBJ, "Invalid certificate extensions object")
+#define ERR_BSAFE_INV_MSG_FORMAT (PKG_BSAFE3+21)
+ errortext (ERR_BSAFE_INV_MSG_FORMAT, "Cryptographic error: invalid message format")
+#define ERR_BSAFE_BAD_KEY_LENGTH (PKG_BSAFE3+22)
+ errortext (ERR_BSAFE_BAD_KEY_LENGTH, "Invalid cryptographic key length")
+#define ERR_BSAFE_BAD_SIGNATURE (PKG_BSAFE3+23)
+ errortext (ERR_BSAFE_BAD_SIGNATURE, "Could not verify cryptographic signature")
+#define ERR_BSAFE_BAD_RANDOM_STATE (PKG_BSAFE3+24)
+ errortext (ERR_BSAFE_BAD_RANDOM_STATE, "Bad random number generator state")
+#define ERR_BSAFE_CERTCRL_NOT_FOUND (PKG_BSAFE3+25)
+ errortext (ERR_BSAFE_CERTCRL_NOT_FOUND, "Certificate, private key or CRL was not found")
+#define ERR_BSAFE_MAKING_CERT_CHAIN (PKG_BSAFE3+26)
+ errortext (ERR_BSAFE_MAKING_CERT_CHAIN, "A certificate chain could not be constructed")
+#define ERR_BSAFE_CRYPTO_UPDATE_COUNT (PKG_BSAFE3+27)
+ errortext (ERR_BSAFE_CRYPTO_UPDATE_COUNT, "Cryptographic error: update operation called an inappropriate number of times")
+#define ERR_BSAFE_DATA_STREAM (PKG_BSAFE3+28)
+ errortext (ERR_BSAFE_DATA_STREAM, "Data streaming error encountered during cryptographic operation")
+#define ERR_BSAFE_CERT_EXT_EXISTS (PKG_BSAFE3+29)
+ errortext (ERR_BSAFE_CERT_EXT_EXISTS, "Certificate extension already exists")
+#define ERR_BSAFE_GENERIC_DATA (PKG_BSAFE3+30)
+ errortext (ERR_BSAFE_GENERIC_DATA, "Unknown data error occurred during cryptographic processing")
+#define ERR_BSAFE_HARDWARE (PKG_BSAFE3+31)
+ errortext (ERR_BSAFE_HARDWARE, "Cryptographic hardware error")
+
+/* (PKG_BSAFE3: Limited to 0-31 */
+
+
+#define ERR_BSAFE_UNSUPPORTED_CERTCRLSIG (PKG_BSAFE4+0)
+ errortext (ERR_BSAFE_UNSUPPORTED_CERTCRLSIG,"Unsupported certificate or CRL signature algorithm")
+#define ERR_BSAFE_UNSUPPORTED_CRYPTO_OP (PKG_BSAFE4+1)
+ errortext (ERR_BSAFE_UNSUPPORTED_CRYPTO_OP, "An unsupported cryptographic operation was requested")
+#define ERR_BSAFE_WEAK_KEY (PKG_BSAFE4+2)
+ errortext (ERR_BSAFE_WEAK_KEY, "The data supplied would generate a known weak cryptographic key")
+
+/* +3 thru +6 are available */
+
+#define ERR_BSAFE_INVALID_PASSWORD (PKG_BSAFE4+7)
+ errortext (ERR_BSAFE_INVALID_PASSWORD, "Password does not meet the requirement")
+#define ERR_BSAFE_INSERT_SMARTCARD (PKG_BSAFE4+8)
+ errortext (ERR_BSAFE_INSERT_SMARTCARD, "Please insert the smartcard")
+#define ERR_BSAFE_SC_PIN_INVALID (PKG_BSAFE4+9)
+ errortext (ERR_BSAFE_SC_PIN_INVALID, "Incorrect PIN")
+#define ERR_BSAFE_SC_RESET (PKG_BSAFE4+10)
+ errortext (ERR_BSAFE_SC_RESET, "A smartcard device error has occurred. Please eject and re-insert your smartcard.")
+#define ERR_BSAFE_SC_UNKNOWN (PKG_BSAFE4+11)
+ errortext (ERR_BSAFE_SC_UNKNOWN, "An unknown smartcard error has occurred.")
+#define ERR_BSAFE_SC_INVALID_CONFIG (PKG_BSAFE4+12)
+ errortext (ERR_BSAFE_SC_INVALID_CONFIG, "Incomplete or incorrect smartcard configuration.")
+#define ERR_BSAFE_SC_UNSUPPORTED_FUNC (PKG_BSAFE4+13)
+ errortext (ERR_BSAFE_SC_UNSUPPORTED_FUNC, "This feature is not supported by your smartcard.")
+#define ERR_BSAFE_SC_DEVICE_MEMORY (PKG_BSAFE4+14)
+ errortext (ERR_BSAFE_SC_DEVICE_MEMORY, "Insufficient free space on smartcard. Please contact your administrator.")
+#define ERR_BSAFE_SC_PIN_LOCKED (PKG_BSAFE4+15)
+ errortext (ERR_BSAFE_SC_PIN_LOCKED, "Your smartcard or cryptographic device is locked. Please contact your administrator.")
+#define ERR_BSAFE_RECOVERY_INFO_REMOVED (PKG_BSAFE4+16)
+ errortext (ERR_BSAFE_RECOVERY_INFO_REMOVED, "Recovery information has been removed")
+#define ERR_BSAFE_SC_NOT_RECOGNIZED (PKG_BSAFE4+17)
+ errortext (ERR_BSAFE_SC_NOT_RECOGNIZED, "This smartcard has not been initialized or is incompatible with your smartcard reader.")
+#define ERR_BSAFE_SC_KEY_CREATE (PKG_BSAFE4+18)
+ errortext (ERR_BSAFE_SC_KEY_CREATE, "This key could not be written to your smartcard.")
+#define ERR_SMIME_RECIPIENT_BAD_CERT (PKG_BSAFE4+19)
+ errortext (ERR_SMIME_RECIPIENT_BAD_CERT, " The certificate is not usable.")
+#define ERR_SMIME_RECIPIENT_CERT_CHAIN (PKG_BSAFE4+20)
+ errortext (ERR_SMIME_RECIPIENT_CERT_CHAIN, " The certificate chain is not trusted.")
+#define ERR_SMIME_RECIPIENT_ILLEGAL (PKG_BSAFE4+21)
+ errortext (ERR_SMIME_RECIPIENT_ILLEGAL, " You are not allowed to encrypt for this recipient.")
+#define ERR_SMIME_RECIPIENT_ADD_FAILURE (PKG_BSAFE4+22)
+ errortext (ERR_SMIME_RECIPIENT_ADD_FAILURE, " You cannot encrypt a message to this recipient.")
+#define ERR_SMIME_RECIPIENT_BAD_EMAIL (PKG_BSAFE4+23)
+ errortext (ERR_SMIME_RECIPIENT_BAD_EMAIL, " This recipient's email address was not found in the certificate.")
+#define ERR_SMIME_RECIPIENT_CERT_REVOKED (PKG_BSAFE4+24)
+ errortext (ERR_SMIME_RECIPIENT_CERT_REVOKED,"This recipient's certificate had been revoked.")
+#define ERR_SMIME_RECIPIENT_EMAIL_MISMATCH (PKG_BSAFE4+25)
+ errortext (ERR_SMIME_RECIPIENT_EMAIL_MISMATCH," This recipient's email address in the directory did not match what was found in the certificate.")
+#define ERR_SMIME_RECIPIENT_CERT_EXPIRED (PKG_BSAFE4+26)
+ errortext (ERR_SMIME_RECIPIENT_CERT_EXPIRED," This recipient's certificate is expired.")
+#define ERR_SMIME_SENDER_SIGNING_CERT_EXPIRED (PKG_BSAFE4+27)
+ errortext (ERR_SMIME_SENDER_SIGNING_CERT_EXPIRED," The certificate used to send signed mail is expired.")
+#define ERR_LTPA_TOKEN_SHOULD_RENEW (PKG_BSAFE4+28)
+ errortext (ERR_LTPA_TOKEN_SHOULD_RENEW, "Single Sign-On token should be renewed.")
+#define ERR_BSAFE_CERT_EXPIRES_SERVER (PKG_BSAFE4+29)
+ errortext(ERR_BSAFE_CERT_EXPIRES_SERVER, "WARNING: Server certificate issued to %s by %s will expire on %s. Contact your Domino administrator. %s")
+#define ERR_BSAFE_CERT_EXPIRED_SERVER (PKG_BSAFE4+30)
+ errortext(ERR_BSAFE_CERT_EXPIRED_SERVER, "WARNING: Server certificate issued to %s by %s expired on %s and can no longer be used. Contact your Domino administrator.")
+
+/* PKG_BSAFE4: Limited to 0-31 */
+
+
+#define ERR_BSAFE_RECOVERY_INFO_TOO_OLD (PKG_BSAFE5+0)
+ errortext (ERR_BSAFE_RECOVERY_INFO_TOO_OLD, "The recovery information was not accepted because it is the same or older than your current recovery information")
+#define ERR_BSAFE_NOT_LEAF_CERT (PKG_BSAFE5+1)
+ errortext (ERR_BSAFE_NOT_LEAF_CERT, "Only leaf certificates can be deleted from the ID file")
+#define ERR_BSAFE_NO_REPOSITORY_NAME (PKG_BSAFE5+2)
+ errortext (ERR_BSAFE_NO_REPOSITORY_NAME, "You must specify a name for the backup repository address")
+#define ERR_BSAFE_PKCS12_IMPORT_ADD_KEY (PKG_BSAFE5+3)
+ errortext(ERR_BSAFE_PKCS12_IMPORT_ADD_KEY, "Cannot add key from the import file.")
+#define ERR_BSAFE_PKCS12_IMPORT_ADD_CERT (PKG_BSAFE5+4)
+ errortext(ERR_BSAFE_PKCS12_IMPORT_ADD_CERT, "Cannot add certificate from the import file.")
+#define ERR_BSAFE_SC_NO_PASSWORD (PKG_BSAFE5+5)
+ errortext(ERR_BSAFE_SC_NO_PASSWORD, "The password for this ID file is not stored on a smartcard.")
+#define ERR_BSAFE_SC_NO_DLL_FOUND (PKG_BSAFE5+6)
+ errortext(ERR_BSAFE_SC_NO_DLL_FOUND, "The path or file selected for the smartcard driver is invalid.")
+#define ERR_BSAFE_ILL_CERTTAB_ITEM (PKG_BSAFE5+7)
+ errortext(ERR_BSAFE_ILL_CERTTAB_ITEM, "A certificate table item was unrecognized")
+#define ERR_BSAFE_CANT_MODIFY_ACTIVE_ID (PKG_BSAFE5+8)
+ errortext(ERR_BSAFE_CANT_MODIFY_ACTIVE_ID, "You cannot modify the active ID file")
+#define ERR_BSAFE_TOO_MANY_RO_CERTIFICATES (PKG_BSAFE5+9)
+ errortext(ERR_BSAFE_TOO_MANY_RO_CERTIFICATES, "The certificate table contains too many key rollover certificates")
+#define ERR_BSAFE_KEYGEN_WRONG_STATE (PKG_BSAFE5+10)
+ errortext(ERR_BSAFE_KEYGEN_WRONG_STATE, "Pending public keys are in the wrong state for the requested operation")
+#define ERR_BSAFE_ROLLOVER_TOO_MANY (PKG_BSAFE5+12)
+ errortext(ERR_BSAFE_ROLLOVER_TOO_MANY, "Too many key rollover certificates")
+#define ERR_BSAFE_RECOVERY_CERTIFIER_NOT_ANCESTOR (PKG_BSAFE5+13)
+ errortext (ERR_BSAFE_RECOVERY_CERTIFIER_NOT_ANCESTOR, "Recovery information is from a certifier that is not an ancestor of this user")
+
+#define ERR_BSAFE_ROLLOVER_UNKNOWN_TYPE (PKG_BSAFE5+15)
+ errortext(ERR_BSAFE_ROLLOVER_UNKNOWN_TYPE, "Unknown key rollover object type")
+
+/* PKG_BSAFE5: Available, limited to 0-15 */
+
+#define ERR_BSAFE_TE_UNTRUSTED_SIGNER (PKG_BSAFE6+0)
+ errortext (ERR_BSAFE_TE_UNTRUSTED_SIGNER, "The signer's certificate is not trusted.")
+#define ERR_BSAFE_INCOMPLETE_CERT_CHAIN (PKG_BSAFE6+1)
+ errortext (ERR_BSAFE_INCOMPLETE_CERT_CHAIN, "Cannot accept internet certificate because the certificate authority certificate is unavailable.")
+#define ERR_BSAFE_MISSING_PRIVATE_KEY (PKG_BSAFE6+2)
+ errortext (ERR_BSAFE_MISSING_PRIVATE_KEY, "Cannot accept internet certificate because the current ID file was not used to create the original request.")
+#define ERR_BSAFE_CERT_ALREADY_IN_ID_FILE (PKG_BSAFE6+3)
+ errortext (ERR_BSAFE_CERT_ALREADY_IN_ID_FILE, "Cannot accept internet certificate because the certificate is already in the ID file.")
+
+
+/* Note: Put here, because there was space, but these really belong
+* elsewhere
+*/
+
+/* LATER:
+* In some cases, copies of ERR_DESK codes moved here because they can
+* be returned by the SDK. Corresponding ERR_DESK codes should be eliminated
+*/
+
+#define ERR_BSAFE_ILL_IDCHAR (PKG_BSAFE6+4)
+ errortext(ERR_BSAFE_ILL_IDCHAR, "The only allowed characters for a person, server, or certifier name are letters, numbers, ampersand, apostrophe, hyphen, period, space, and underscore")
+#define ERR_BSAFE_ILL_DOMAIN (PKG_BSAFE6+5)
+ errortext(ERR_BSAFE_ILL_DOMAIN, "The only allowed characters for a domain name are letters, numbers, ampersand, apostrophe, hyphen, space, and underscore")
+#define ERR_BSAFE_NA_ENTRY_NOT_FOUND (PKG_BSAFE6+6)
+ stringtext(ERR_BSAFE_NA_ENTRY_NOT_FOUND, "The ID was certified but there was no corresponding entry in the Address Book to be updated")
+#define ERR_BSAFE_OLDNSF (PKG_BSAFE6+7)
+ errortext(ERR_BSAFE_OLDNSF, "Unable to perform this operation; options were selected that cannot be used with this older format Notes database.")
+#define ERR_BSAFE_INV_RECERT_FORM (PKG_BSAFE6+8)
+ errortext(ERR_BSAFE_INV_RECERT_FORM,"Cannot certify this entry because the form used to create it is not supported for this operation.")
+#define ERR_BSAFE_NOT_IMPLEMENTED (PKG_BSAFE6+9)
+ errortext(ERR_BSAFE_NOT_IMPLEMENTED,"Operation is not yet implemented")
+#define ERR_BSAFE_DUP_NAME (PKG_BSAFE6+10)
+ errortext(ERR_BSAFE_DUP_NAME, "Duplicate name found")
+#define ERR_BSAFE_ILL_CERTIFIER_NAME (PKG_BSAFE6+11)
+ errortext(ERR_BSAFE_ILL_CERTIFIER_NAME, "You specified an illegal certifier name")
+#define ERR_BSAFE_NO_INET_CERTS (PKG_BSAFE6+12)
+ errortext(ERR_BSAFE_NO_INET_CERTS, "Could not locate or process internet certificates for this ID.")
+#define ERR_BSAFE_PKCS12_IMPORT_BAD_FILE_READ (PKG_BSAFE6+13)
+ errortext(ERR_BSAFE_PKCS12_IMPORT_BAD_FILE_READ, "Import file could not be read. Check file permissions.")
+#define ERR_BSAFE_PKCS12_IMPORT_BAD_INFO (PKG_BSAFE6+14)
+ errortext(ERR_BSAFE_PKCS12_IMPORT_BAD_INFO, "Unsupported PKCS12 version or content. Check the import file.")
+#define ERR_BSAFE_PKCS12_IMPORT_BAD_UNKNOWN (PKG_BSAFE6+15)
+ errortext(ERR_BSAFE_PKCS12_IMPORT_BAD_UNKNOWN, "Cannot handle the import file. Check file name and file password.")
+
+/* PKG_BSAFE6: Available, limited to 0-15 */
+
+
+/*PKG_BSAFE_STR bsafe strings 0 - 127 */
+#define ERR_BSAFE_DISPLAY_IDFILE (PKG_BSAFE_STR)
+ stringtext(ERR_BSAFE_DISPLAY_IDFILE, "The ID file being used is: ")
+#define STR_BSAFE_RSA_PRIMARY (PKG_BSAFE_STR + 2)
+ stringtext(STR_BSAFE_RSA_PRIMARY, "Primary RSA")
+#define STR_BSAFE_RSA_SECONDARY (PKG_BSAFE_STR + 3)
+ stringtext(STR_BSAFE_RSA_SECONDARY, "Secondary RSA")
+#define STR_BSAFE_RC2 (PKG_BSAFE_STR + 4)
+ stringtext(STR_BSAFE_RC2, "RC2")
+#define STR_BSAFE_RC4 (PKG_BSAFE_STR + 5)
+ stringtext(STR_BSAFE_RC4, "RC4")
+#define STR_BSAFE_USA (PKG_BSAFE_STR + 6)
+ stringtext(STR_BSAFE_USA, "North American")
+#define STR_BSAFE_NONUSA (PKG_BSAFE_STR + 7)
+ stringtext(STR_BSAFE_NONUSA, "International")
+#define STR_BSAFE_SIGNED_MAIL (PKG_BSAFE_STR + 8)
+ stringtext(STR_BSAFE_SIGNED_MAIL, "Signed mail using %d bit %e key")
+#define STR_BSAFE_SEALED_DOC (PKG_BSAFE_STR + 9)
+ stringtext(STR_BSAFE_SEALED_DOC, "Encrypted document using %d/%d bit %e/%e keys")
+#define STR_BSAFE_CERTIFY (PKG_BSAFE_STR + 10)
+ stringtext(STR_BSAFE_CERTIFY, "Created certificate using %d bit %e key")
+#define STR_BSAFE_IDFILE_ENCRYPTED (PKG_BSAFE_STR + 11)
+ stringtext(STR_BSAFE_IDFILE_ENCRYPTED, "ID file is encrypted with %d bit %e key")
+#define STR_BSAFE_FORCED_AUTH (PKG_BSAFE_STR + 12)
+ stringtext(STR_BSAFE_FORCED_AUTH, "Authentication is being forced due to secure channel setting.")
+#define STR_BSAFE_CERT_EXPIRES (PKG_BSAFE_STR + 13)
+ stringtext(STR_BSAFE_CERT_EXPIRES, "WARNING: Your certificate issued to %s by %s will expire on %s. To request a new certificate, you should start User Security (see File - Security - User Security) and click Renew. %s")
+#define STR_BSAFE_CERT_EXPIRED (PKG_BSAFE_STR + 14)
+ stringtext(STR_BSAFE_CERT_EXPIRED, "WARNING: Your certificate issued to %s by %s expired on %s and can no longer be used. Contact your Domino administrator.")
+#define STR_BSAFE_INVALID (PKG_BSAFE_STR + 15)
+ stringtext(STR_BSAFE_INVALID, "Invalid")
+#define STR_BSAFE_UNKNOWN (PKG_BSAFE_STR + 16)
+ stringtext(STR_BSAFE_UNKNOWN, "Unknown")
+#define STR_BSAFE_CERTIFYING (PKG_BSAFE_STR + 17)
+ stringtext(STR_BSAFE_CERTIFYING, "Certifying %A")
+#define STR_BSAFE_CERTIFIED (PKG_BSAFE_STR + 18)
+ stringtext(STR_BSAFE_CERTIFIED, "%A successfully certified")
+#define STR_BSAFE_REPLACE_ANCESTRY (PKG_BSAFE_STR + 19)
+ stringtext(STR_BSAFE_REPLACE_ANCESTRY, "A certificate hierarchy has already been assigned to this ID. Do you wish to continue and replace it?")
+#define STR_BSAFE_UPGRADETOHI (PKG_BSAFE_STR + 20)
+ stringtext(STR_BSAFE_UPGRADETOHI, "The ID file will be upgraded to hierarchical format. Do you wish to continue?")
+#define STR_BSAFE_AUTHENTICATED (PKG_BSAFE_STR + 21)
+ stringtext(STR_BSAFE_AUTHENTICATED, "Authenticated: %d bit Ticket, %d bit %e session key, %e on RC4 escrow.")
+#define STR_BSAFE_HICERTIFIERID (PKG_BSAFE_STR + 22)
+ stringtext(STR_BSAFE_HICERTIFIERID, "Hierarchical Certifier")
+#define STR_BSAFE_UNKNOWNID (PKG_BSAFE_STR + 23)
+ stringtext(STR_BSAFE_UNKNOWNID, "Unknown ID type")
+#define STR_BSAFE_ID_FULL (PKG_BSAFE_STR + 24)
+ stringtext(STR_BSAFE_ID_FULL, "Notes")
+#define STR_BSAFE_ID_DESKTOP (PKG_BSAFE_STR + 25)
+ stringtext(STR_BSAFE_ID_DESKTOP, "Notes Desktop")
+
+/* Use OSLoadSubString to load substrings - english total length<80!
+*/
+#define STR_BSAFE_LIST_IDFILE (PKG_BSAFE_STR + 26)
+ stringtext(STR_BSAFE_LIST_IDFILE, "Non-Hierarchical ID|Hierarchical User or Server|Hierarchical Certifier")
+
+#define IDX_BSAFE_IDFILE_FLAT 1
+#define IDX_BSAFE_IDFILE_HIUSER 2
+#define IDX_BSAFE_IDFILE_HICA 3
+
+#define STR_BSAFE_LIST_MISCID (PKG_BSAFE_STR + 27)
+ stringtext(STR_BSAFE_LIST_MISCID, "Safe Copy|Unknown ID type|Internet Certifier| ")
+
+#define IDX_BSAFE_MISCID_SAFE 1
+#define IDX_BSAFE_MISCID_UNKNOWN 2
+#define IDX_BSAFE_MISCID_INETCA 3
+#define IDX_BSAFE_MISCID_BLANK 4
+
+#define STR_BSAFE_CROSS_CERTIFYING (PKG_BSAFE_STR + 28)
+ stringtext(STR_BSAFE_CROSS_CERTIFYING, "Cross certifying %A")
+#define STR_BSAFE_CROSS_CERTIFIED (PKG_BSAFE_STR + 29)
+ stringtext(STR_BSAFE_CROSS_CERTIFIED, "%A successfully cross certified")
+#define STR_BSAFE_MAX_IBULKDATAKEY (PKG_BSAFE_STR + 30)
+#ifdef FRANCE_ENGLISH
+ stringtext(STR_BSAFE_MAX_IBULKDATAKEY, "40")
+#else
+ stringtext(STR_BSAFE_MAX_IBULKDATAKEY, "64")
+#endif
+#define STR_BSAFE_DUP_NAMES_IN_DIRECTORY (PKG_BSAFE_STR + 31)
+ stringtext (STR_BSAFE_DUP_NAMES_IN_DIRECTORY, "%A and %A both already exist in the directory but in different entries")
+#define STR_BSAFE_SC_PIN_PROMPT (PKG_BSAFE_STR + 32)
+#ifdef OS400
+ stringtext(STR_BSAFE_SC_PIN_PROMPT, "Enter PIN (press the F3 key to abort): ")
+#else
+ stringtext(STR_BSAFE_SC_PIN_PROMPT, "Enter PIN (press the Esc key to abort): ")
+#endif
+#define STR_BSAFE_DISPLAY_SMARTCARD (PKG_BSAFE_STR + 33)
+ stringtext(STR_BSAFE_DISPLAY_SMARTCARD, "The smartcard being used is: ")
+
+/* available PKG_BSAFE_STR + 34 */
+
+#define STR_BSAFE_PRESS_ENTER (PKG_BSAFE_STR + 35)
+ stringtext(STR_BSAFE_PRESS_ENTER, "Press ENTER to continue")
+
+/* available PKG_BSAFE_STR + 36, 37 */
+
+/* Following are reserved for Password Policy */
+#define STR_BSAFE_PW_LEN_FAIL (PKG_BSAFE_STR + 38)
+ stringtext(STR_BSAFE_PW_LEN_FAIL, "Password does not meet length requirement.")
+#define STR_BSAFE_PW_QTY_FAIL (PKG_BSAFE_STR + 39)
+ stringtext(STR_BSAFE_PW_QTY_FAIL, "Password does not meet quality requirement.")
+#define STR_BSAFE_PW_ALPHA_FAIL (PKG_BSAFE_STR + 40)
+ stringtext(STR_BSAFE_PW_ALPHA_FAIL, "Password does not contain minimum required number of alpha characters.")
+#define STR_BSAFE_PW_NUM_FAIL (PKG_BSAFE_STR + 41)
+ stringtext(STR_BSAFE_PW_NUM_FAIL, "Password does not contain minimum required number of numeric characters.")
+#define STR_BSAFE_PW_PUNC_FAIL (PKG_BSAFE_STR + 42)
+ stringtext(STR_BSAFE_PW_PUNC_FAIL, "Password does not contain minimum required number of punctuation characters.")
+#define STR_BSAFE_PW_UPP_FAIL (PKG_BSAFE_STR + 43)
+ stringtext(STR_BSAFE_PW_UPP_FAIL, "Password does not contain minimum required number of upper case characters.")
+#define STR_BSAFE_PW_LOW_FAIL (PKG_BSAFE_STR + 44)
+ stringtext(STR_BSAFE_PW_LOW_FAIL, "Password does not contain minimum required number of lower case characters.")
+#define STR_BSAFE_PW_UNIQUE_FAIL (PKG_BSAFE_STR + 45)
+ stringtext(STR_BSAFE_PW_UNIQUE_FAIL, "Password does not contain enough number of unique characters.")
+#define STR_BSAFE_PW_REPEAT_FAIL (PKG_BSAFE_STR + 46)
+ stringtext(STR_BSAFE_PW_REPEAT_FAIL, "Password fails repeat characters check. There are too many of the same character.")
+#define STR_BSAFE_PW_START_FAIL (PKG_BSAFE_STR + 47)
+ stringtext(STR_BSAFE_PW_START_FAIL, "Password fails the check 'must not start with'.")
+#define STR_BSAFE_PW_END_FAIL (PKG_BSAFE_STR + 48)
+ stringtext(STR_BSAFE_PW_END_FAIL, "Password fails the check 'must not end with'.")
+#define STR_BSAFE_PW_CNNAME_FAIL (PKG_BSAFE_STR + 49)
+ stringtext(STR_BSAFE_PW_CNNAME_FAIL, "Password contains some aspect of the user name.")
+#define STR_BSAFE_PW_FIRST_CNG (PKG_BSAFE_STR + 50)
+ stringtext(STR_BSAFE_PW_FIRST_CNG, "User must change password on first use.")
+
+
+/* The following are currently used to log to DDM with better context during authentication
+*/
+
+#define STR_BSAFE_REMOTE_HOST (PKG_BSAFE_STR + 51)
+ stringtext(STR_BSAFE_REMOTE_HOST, "from host")
+
+#define STR_BSAFE_AUTH_FAILED_WITHNET (PKG_BSAFE_STR + 52)
+ stringtext(STR_BSAFE_AUTH_FAILED_WITHNET, "%a %e [%s] failed to authenticate")
+#define STR_BSAFE_AUTH_FAILED_NONET (PKG_BSAFE_STR + 53)
+ stringtext(STR_BSAFE_AUTH_FAILED_NONET, "%a failed to authenticate")
+
+#define STR_BSAFE_AUTH_PROBLEM_WITHNET (PKG_BSAFE_STR + 54)
+ stringtext(STR_BSAFE_AUTH_PROBLEM_WITHNET, "%a %e [%s] encountered non-fatal problem during authentication")
+#define STR_BSAFE_AUTH_PROBLEM_NONET (PKG_BSAFE_STR + 55)
+ stringtext(STR_BSAFE_AUTH_PROBLEM_NONET, "%a encountered non-fatal problem during authentication")
+
+ /* Id recovery string for better logging*/
+
+#define STR_BSAFE_BACKUP_ID_NAME_CHANGE (PKG_BSAFE_STR + 56)
+ stringtext (STR_BSAFE_BACKUP_ID_NAME_CHANGE, "ID containing name change for %A marked for backup")
+#define STR_BSAFE_BACKUP_ID_NEW_NEK (PKG_BSAFE_STR + 57)
+ stringtext (STR_BSAFE_BACKUP_ID_NEW_NEK, "ID containing new NEK for %A marked for backup")
+#define STR_BSAFE_BACKUP_ID_NEWKEY_CERTS (PKG_BSAFE_STR + 58)
+ stringtext (STR_BSAFE_BACKUP_ID_NEWKEY_CERTS, "ID containing certificates for new keys for %A marked for backup")
+#define STR_BSAFE_BACKUP_ID_NEW_RECOVERY_INFO (PKG_BSAFE_STR + 59)
+ stringtext (STR_BSAFE_BACKUP_ID_NEW_RECOVERY_INFO, "ID containing new recovery information for %A marked for backup")
+#define STR_BSAFE_RECOVERY_INFO_CREATION_DATE (PKG_BSAFE_STR + 60)
+ stringtext (STR_BSAFE_RECOVERY_INFO_CREATION_DATE, "Creation date of recovery info to be imported is %s")
+#define STR_BSAFE_RECOVERY_INFO_SIGNATURE_FAILURE (PKG_BSAFE_STR + 61)
+ stringtext (STR_BSAFE_RECOVERY_INFO_SIGNATURE_FAILURE, "Signature on recovery information failed to verify")
+#define STR_BSAFE_RECOVERY_OF_ID_FILE (PKG_BSAFE_STR + 62)
+ stringtext (STR_BSAFE_RECOVERY_OF_ID_FILE, "ID file for %A recovered successfully")
+#define STR_BSAFE_RECOVERY_OF_ID_FILE_FAIL (PKG_BSAFE_STR + 63)
+ stringtext (STR_BSAFE_RECOVERY_OF_ID_FILE_FAIL, "ID file for %A recovery failure")
+#define STR_BSAFE_XCERT_LOOKUP_ERROR (PKG_BSAFE_STR + 64)
+ stringtext (STR_BSAFE_XCERT_LOOKUP_ERROR, "Error during Directory lookup for cross certificates issued to %A or one of its ancestors")
+#define STR_BSAFE_RECOVERY_ID_INFO_CREATION_DATE (PKG_BSAFE_STR + 65)
+ stringtext (STR_BSAFE_RECOVERY_ID_INFO_CREATION_DATE, "Creation date of recovery info in ID file is %s")
+#define STR_BSAFE_RECOVERY_ID_INFO_UPDATED (PKG_BSAFE_STR + 66)
+ stringtext (STR_BSAFE_RECOVERY_ID_INFO_UPDATED, "New recovery info successfully updated in ID file for %A")
+#define STR_BSAFE_BACKUP_ON_DEMAND (PKG_BSAFE_STR+67)
+ stringtext (STR_BSAFE_BACKUP_ON_DEMAND, "Requested backup of ID file for %A")
+#define STR_BSAFE_RECOVERY_COOKIES_CREATION_FAILURE (PKG_BSAFE_STR+68)
+ stringtext (STR_BSAFE_RECOVERY_COOKIES_CREATION_FAILURE, "Recovery passwords generation failure")
+#define STR_BSAFE_RECOVERY_MULTI_PASSWORD_FAILURE (PKG_BSAFE_STR+69)
+ stringtext (STR_BSAFE_RECOVERY_MULTI_PASSWORD_FAILURE, "Unable to set multi recovery passwords on ID file")
+#define STR_BSAFE_RECOVERY_PASSWORD_EXTRA_FAILURE (PKG_BSAFE_STR+70)
+ stringtext (STR_BSAFE_RECOVERY_PASSWORD_EXTRA_FAILURE, "Unable to generate password recovery extra in ID file")
+#define STR_BSAFE_RECOVERY_KEYS_CREATION_FAILURE (PKG_BSAFE_STR+71)
+ stringtext (STR_BSAFE_RECOVERY_KEYS_CREATION_FAILURE, "Unable to create keys recovery extra in ID file")
+#define STR_BSAFE_RECOVERY_MAIL_BACKUP_FAIL (PKG_BSAFE_STR+72)
+ stringtext (STR_BSAFE_RECOVERY_MAIL_BACKUP_FAIL, "Failure to mail backup recovery ID file: ")
+#define STR_BSAFE_RECOVERY_MAIL_BACKUP_FAIL_NAMED (PKG_BSAFE_STR+73)
+ stringtext (STR_BSAFE_RECOVERY_MAIL_BACKUP_FAIL_NAMED, "Failure to mail backup recovery ID file for %s to %s")
+#define STR_BSAFE_BACKUP_ID_KEY_CHANGE (PKG_BSAFE_STR + 74)
+ stringtext (STR_BSAFE_BACKUP_ID_KEY_CHANGE, "ID containing new public keys for %A marked for backup")
+
+
+#define STR_BSAFE_AUTH_LOCPROB_ON_CLIENT (PKG_BSAFE_STR + 75)
+ stringtext(STR_BSAFE_AUTH_LOCPROB_ON_CLIENT, "Non-fatal problem encountered during authentication with server %A")
+#define STR_BSAFE_AUTH_LOCFAIL_ON_CLIENT (PKG_BSAFE_STR + 76)
+ stringtext(STR_BSAFE_AUTH_LOCFAIL_ON_CLIENT, "Failed to authenticate with server %A")
+#define STR_BSAFE_AUTH_REMPROB_ON_CLIENT (PKG_BSAFE_STR + 77)
+ stringtext(STR_BSAFE_AUTH_REMPROB_ON_CLIENT, "Server %A reported the following non-fatal problem during authentication")
+#define STR_BSAFE_AUTH_REMFAIL_ON_CLIENT (PKG_BSAFE_STR + 78)
+ stringtext(STR_BSAFE_AUTH_REMFAIL_ON_CLIENT, "Server %A reported the following problem causing authentication to fail")
+#define STR_BSAFE_EXTRA_DATA_FUNCTIONS (PKG_BSAFE_STR+79)
+ stringtext (STR_BSAFE_EXTRA_DATA_FUNCTIONS, "retrieval|deletion|update")
+#define IDX_EXTRA_FUNC_OFFSET 1
+
+#define STR_BSAFE_EXTRA_DATA_TYPES (PKG_BSAFE_STR+80)
+ stringtext (STR_BSAFE_EXTRA_DATA_TYPES, "DB2 user name|DB2 password|Server Controller user name|Server Controller password")
+#define IDX_EXTRA_TYPE_OFFSET 29
+
+#define STR_BSAFE_EXTRA_DATA_LOGSTRING (PKG_BSAFE_STR+81)
+ stringtext (STR_BSAFE_EXTRA_DATA_LOGSTRING, "%s %s by %a completed.|%s %s by %a failed.")
+#define IDX_EXTRA_LOG_PASSED 1
+#define IDX_EXTRA_LOG_FAILED 2
+
+#define STR_BSAFE_BACKUP_ON_REG_SBJ (PKG_BSAFE_STR+82)
+ stringtext (STR_BSAFE_BACKUP_ON_REG_SBJ, "Backup of newly registered ID file for %A")
+#define STR_BSAFE_BACKUP_ON_ACCEPT_SBJ (PKG_BSAFE_STR+83)
+ stringtext (STR_BSAFE_BACKUP_ON_ACCEPT_SBJ, "Backup of newly changed recovery information for %A")
+#define STR_BSAFE_BACKUP_ON_MODIFY_SBJ (PKG_BSAFE_STR+84)
+ stringtext (STR_BSAFE_BACKUP_ON_MODIFY_SBJ, "Backup of recent changes to ID file for %A")
+#define STR_BSAFE_NEW_REC_INFO_SBJ (PKG_BSAFE_STR+85)
+ stringtext (STR_BSAFE_NEW_REC_INFO_SBJ, "New ID file recovery information is attached. Please add it to your ID file by using the Actions menu %s option.")
+
+
+/*PKG_BSAFE_STR bsafe strings up to 127 */
+
+#define ERR_BSAFE3_TE_ALLOC ERR_BSAFE_NOMEMORY
+#define ERR_BSAFE3_TE_ATTRIBUTE_COUNT ERR_ASN1_INV_SYNTAX
+#define ERR_BSAFE3_TE_ATTRIBUTE_NOT_FOUND ERR_ASN1_INV_SYNTAX
+#define ERR_BSAFE3_TE_ATTRIBUTE_TAG ERR_ASN1_INV_SYNTAX
+#define ERR_BSAFE3_TE_ATTRIBUTE_TYPE ERR_BSAFE2_ATTRIBUTE_UNKNOWN
+#define ERR_BSAFE3_TE_ATTRIBUTE_VALUE ERR_ASN1_ILL_DATATYPE
+#define ERR_BSAFE3_TE_ATTRIBUTE_VALUE_LEN ERR_ASN1_ILL_DATALENGTH
+
+#define ERR_BSAFE3_TE_BEGIN_PEM ERR_BSAFE_INV_MSG_FORMAT
+#define ERR_BSAFE3_TE_BER_ENCODING ERR_ASN1_INV_SYNTAX
+
+#define ERR_BSAFE3_TE_CANCEL ERR_BSAFE_CANCELED
+#define ERR_BSAFE3_TE_CERT_ENCODING ERR_BSAFE_INV_CERT
+#define ERR_BSAFE3_TE_CERT_OBJ ERR_BSAFE_INV_CERT
+
+#define ERR_BSAFE3_TE_CO_SET ERR_BSAFE_BADCTX
+
+#define ERR_BSAFE3_TE_CRL_ENCODING ERR_BSAFE_INV_CRL
+#define ERR_BSAFE3_TE_CRL_OBJ ERR_BSAFE_INV_CRL
+
+#define ERR_BSAFE3_TE_DATA ERR_BSAFE_GENERIC_DATA
+#define ERR_BSAFE3_TE_DBASE ERR_BSAFE_BADCTX
+#define ERR_BSAFE3_TE_DEK_ALG_NOT_SUPPORTED ERR_BSAFE_UNSUPPORTED_CRYPTO_OP
+#define ERR_BSAFE3_TE_DEK_ALG_UNKNOWN ERR_BSAFE_UNSUPPORTED_CRYPTO_OP
+#define ERR_BSAFE3_TE_DIGEST_OBJ ERR_BSAFE_BADCTX
+#define ERR_BSAFE3_TE_ENHANCED_TEXT_STREAM ERR_BSAFE_DATA_STREAM
+
+#define ERR_BSAFE3_TE_EXPONENT_EVEN ERR_BSAFE_KEY_INV_FORMAT
+#define ERR_BSAFE3_TE_EXPONENT_LEN ERR_BSAFE_KEY_INV_FORMAT
+#define ERR_BSAFE3_TE_EXTENSIONS_OBJ ERR_BSAFE_INV_EXTENSIONS_OBJ
+#define ERR_BSAFE3_TE_EXTENSION_ALREADY_EXISTS ERR_BSAFE_CERT_EXT_EXISTS
+#define ERR_BSAFE3_TE_HARDWARE ERR_BSAFE_HARDWARE
+#define ERR_BSAFE3_TE_HEADER ERR_BSAFE_INV_MSG_FORMAT
+#define ERR_BSAFE3_TE_INDEX ERR_BSAFE4_TE_PARAMETER
+
+#define ERR_BSAFE4_TE_CERT_CHAIN ERR_BSAFE_MAKING_CERT_CHAIN
+#define ERR_BSAFE4_TE_INPUT_LEN ERR_BSAFE_GENERIC_DATA
+#define ERR_BSAFE4_TE_INPUT_STREAM ERR_BSAFE_DATA_STREAM
+
+#define ERR_BSAFE4_TE_IO ERR_BSAFE_DATA_STREAM
+#define ERR_BSAFE4_TE_LIST_OBJ ERR_BSAFE_BADCTX
+#define ERR_BSAFE4_TE_ME_SET ERR_BSAFE_BADCTX
+#define ERR_BSAFE4_TE_MESSAGE_SIGNATURE ERR_BSAFE_BAD_SIGNATURE
+#define ERR_BSAFE4_TE_MIC_ALG_NOT_SUPPORTED ERR_BSAFE_UNSUPPORTED_CRYPTO_OP
+#define ERR_BSAFE4_TE_MIC_ALG_UNKNOWN ERR_BSAFE_UNSUPPORTED_CRYPTO_OP
+#define ERR_BSAFE4_TE_MODULUS_LEN ERR_BSAFE_BAD_KEY_LENGTH
+#define ERR_BSAFE4_TE_NAME_OBJ ERR_BSAFE_BADCTX
+#define ERR_BSAFE4_TE_NEED_RANDOM ERR_BSAFE_BAD_RANDOM_STATE
+#define ERR_BSAFE4_TE_NOT_FOUND ERR_BSAFE_CERTCRL_NOT_FOUND
+#define ERR_BSAFE4_TE_NOT_ME (PKG_NSF+101) /* ERR_NOT_SEALED_FOR_YOU nsferr.h */
+#define ERR_BSAFE4_TE_NOT_SUPPORTED ERR_BSAFE_UNSUPPORTED_CRYPTO_OP
+#define ERR_BSAFE4_TE_OUTPUT_LEN ERR_BSAFE_TOOSMALL
+#define ERR_BSAFE4_TE_OUTPUT_STREAM ERR_BSAFE_DATA_STREAM
+
+#define ERR_BSAFE4_TE_PASSWORD (PKG_SECURE+8) /* ERR_SECURE_BADPASSWORD secerr.h */
+#define ERR_BSAFE4_TE_PBE_ALG_NOT_SUPPORTED ERR_BSAFE_UNSUPPORTED_CRYPTO_OP
+#define ERR_BSAFE4_TE_PBE_ALG_UNKNOWN ERR_BSAFE_UNSUPPORTED_CRYPTO_OP
+#define ERR_BSAFE4_TE_PKCS_INPUT_STREAM ERR_BSAFE_DATA_STREAM
+#define ERR_BSAFE4_TE_PKCS_OUTPUT_STREAM ERR_BSAFE_DATA_STREAM
+#define ERR_BSAFE4_TE_PKCS_STREAM ERR_BSAFE_DATA_STREAM
+
+#define ERR_BSAFE4_TE_PRIVATE_KEY ERR_BSAFE_KEY_INV_FORMAT
+#define ERR_BSAFE4_TE_PROCESS ERR_BSAFE4_TE_PARAMETER
+#define ERR_BSAFE4_TE_PROTECTED_DATA ERR_BSAFE_BADDATA
+#define ERR_BSAFE4_TE_PUBLIC_KEY ERR_BSAFE_KEY_INV_FORMAT
+#define ERR_BSAFE4_TE_RANDOM_OBJ ERR_BSAFE_BAD_RANDOM_STATE
+#define ERR_BSAFE4_TE_SIGNATURE_ALG_NOT_SUPPORTED ERR_BSAFE_UNSUPPORTED_CERTCRLSIG
+#define ERR_BSAFE5_TE_SIGNATURE_ALG_UNKNOWN ERR_BSAFE_UNSUPPORTED_CERTCRLSIG
+
+#define ERR_BSAFE5_TE_TEXT_ENCODING ERR_BSAFE_INV_MSG_FORMAT
+#define ERR_BSAFE5_TE_TEXT_STREAM ERR_BSAFE_DATA_STREAM
+#define ERR_BSAFE5_TE_TOKEN ERR_BSAFE4_TE_PARAMETER
+#define ERR_BSAFE5_TE_VALIDITY (PKG_SECURE+28) /* ERR_SECURE_EXPIRED_CERT secerr.h */
+#define ERR_BSAFE5_TE_YOU_SET ERR_BSAFE_BADCTX
+
+#define ERR_CERT_MALFORMED ERR_BSAFE_INV_CERT
+#define ERR_KEYRING_MUSTBE_CA ERR_BSAFE_MUSTBE_CERTIFIER
+
+
+#endif
+
+#if defined(OS400) && (__OS400_TGTVRM__ >= 510)
+#pragma datamodel(pop)
+#endif
+
diff --git a/protocols/LotusNotify/src/cnotesapi/include/extmgr.h b/protocols/LotusNotify/src/cnotesapi/include/extmgr.h
new file mode 100644
index 0000000000..8d7e746bf0
--- /dev/null
+++ b/protocols/LotusNotify/src/cnotesapi/include/extmgr.h
@@ -0,0 +1,492 @@
+
+#if defined(OS400) && (__OS400_TGTVRM__ >= 510)
+#pragma datamodel(P128)
+#endif
+
+/*********************************************************************/
+/* */
+/* Licensed Materials - Property of IBM */
+/* */
+/* L-GHUS-5VMPGW, L-GHUS-5S3PEE */
+/* (C) Copyright IBM Corp. 1995, 2005 All Rights Reserved */
+/* */
+/* US Government Users Restricted Rights - Use, duplication or */
+/* disclosure restricted by GSA ADP Schedule Contract with */
+/* IBM Corp. */
+/* */
+/*********************************************************************/
+
+
+
+/* Extension Manager for Notes */
+
+#ifndef EXMGR_DEFS
+#define EXMGR_DEFS
+
+#ifndef NSF_DATA_DEFS
+#include "nsfdata.h" /* We need DBHANDLE */
+#endif
+
+#ifndef NIF_DEFS
+#include "nif.h" /* We need HCOLLECTION */
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* Extension identifier */
+
+typedef WORD EID;
+
+/* handle passed back to identify registration */
+
+typedef DWORD HEMREGISTRATION;
+
+/* extension record; this data structure is passed to the callback routine */
+
+typedef struct
+ {
+ EID EId; /* identifier */
+ WORD NotificationType; /* EM_BEFORE or EM_AFTER */
+ STATUS Status; /* core error code */
+ VARARG_PTR Ap; /* ptr to args */
+ } EMRECORD;
+
+/* the callback; takes one argument */
+
+typedef STATUS (LNCALLBACKPTR EMHANDLER)(EMRECORD far *);
+
+/* Constants used in NotificationType */
+
+#define EM_BEFORE 0
+#define EM_AFTER 1
+
+/* Flags which can be passed to EMRegister */
+
+#define EM_REG_BEFORE 0x0001
+#define EM_REG_AFTER 0x0002
+
+/* prototypes */
+
+STATUS LNPUBLIC EMRegister(EID EmID, DWORD Flags, EMHANDLER Proc, WORD RecursionID, HEMREGISTRATION far *rethRegistration);
+STATUS LNPUBLIC EMDeregister(HEMREGISTRATION hRegistration);
+STATUS LNPUBLIC EMCreateRecursionID(WORD far *retRecursionID);
+
+
+#define EM_NSFDBCLOSESESSION 1
+#define EM_NSFDBCLOSE 2
+#define EM_NSFDBCREATE 3
+#define EM_NSFDBDELETE 4
+#define EM_NSFNOTEOPEN 5
+#define EM_NSFNOTECLOSE 6
+#define EM_NSFNOTECREATE 7
+#define EM_NSFNOTEDELETE 8
+#define EM_NSFNOTEOPENBYUNID 10
+#define EM_FTGETLASTINDEXTIME 11
+#define EM_FTINDEX 12
+#define EM_FTSEARCH 13
+#define EM_NIFFINDBYKEY 14
+#define EM_NIFFINDBYNAME 15
+#define EM_NIFOPENNOTE 17
+#define EM_NIFREADENTRIES 18
+#define EM_NIFUPDATECOLLECTION 20
+#define EM_NSFDBALLOCOBJECT 22
+#define EM_NSFDBCOMPACT 23
+#define EM_NSFDBDELETENOTES 24
+#define EM_NSFDBFREEOBJECT 25
+#define EM_NSFDBGETMODIFIEDNOTETABLE 26
+#define EM_NSFDBGETNOTEINFO 29
+#define EM_NSFDBGETNOTEINFOBYUNID 30
+#define EM_NSFDBGETOBJECTSIZE 31
+#define EM_NSFDBGETSPECIALNOTEID 32
+#define EM_NSFDBINFOGET 33
+#define EM_NSFDBINFOSET 34
+#define EM_NSFDBLOCATEBYREPLICAID 35
+#define EM_NSFDBMODIFIEDTIME 36
+#define EM_NSFDBREADOBJECT 37
+#define EM_NSFDBREALLOCOBJECT 39
+#define EM_NSFDBREPLICAINFOGET 40
+#define EM_NSFDBREPLICAINFOSET 41
+#define EM_NSFDBSPACEUSAGE 42
+#define EM_NSFDBSTAMPNOTES 43
+#define EM_NSFDBWRITEOBJECT 45
+#define EM_NSFNOTEUPDATE 47
+#define EM_NIFOPENCOLLECTION 50
+#define EM_NIFCLOSECOLLECTION 51
+#define EM_NSFDBGETBUILDVERSION 52
+#define EM_NSFDBRENAME 54
+#define EM_NSFDBITEMDEFTABLE 56
+#define EM_NSFDBREOPEN 59
+#define EM_NSFDBOPENEXTENDED 63
+#define EM_NSFNOTEOPENEXTENDED 64
+#define EM_TERMINATENSF 69
+#define EM_NSFNOTEDECRYPT 70
+#define EM_GETPASSWORD 73
+#define EM_SETPASSWORD 74
+#define EM_NSFCONFLICTHANDLER 75
+#define EM_MAILSENDNOTE 83
+#define EM_CLEARPASSWORD 90
+#define EM_NSFNOTEUPDATEXTENDED 102
+#define EM_SCHFREETIMESEARCH 105
+#define EM_SCHRETRIEVE 106
+#define EM_SCHSRVRETRIEVE 107
+#define EM_NSFDBCOMPACTEXTENDED 121
+#define EM_ADMINPPROCESSREQUEST 124
+#define EM_NIFGETCOLLECTIONDATA 126
+#define EM_NSFDBCOPYNOTE 127
+#define EM_NSFNOTECOPY 128
+#define EM_NSFNOTEATTACHFILE 129
+#define EM_NSFNOTEDETACHFILE 130
+#define EM_NSFNOTEEXTRACTFILE 131
+#define EM_NSFNOTEATTACHOLE2OBJECT 132
+#define EM_NSFNOTEDELETEOLE2OBJECT 133
+#define EM_NSFNOTEEXTRACTOLE2OBJECT 134
+#define EM_NSGETSERVERLIST 135
+#define EM_NSFDBCOPY 136
+#define EM_NSFDBCREATEANDCOPY 137
+#define EM_NSFDBCOPYACL 138
+#define EM_NSFDBCOPYTEMPLATEACL 139
+#define EM_NSFDBCREATEACLFROMTEMPLATE 140
+#define EM_NSFDBREADACL 141
+#define EM_NSFDBSTOREACL 142
+#define EM_NSFDBFILTER 143
+#define EM_FTDELETEINDEX 144
+#define EM_NSFNOTEGETINFO 145
+#define EM_NSFNOTESETINFO 146
+#define EM_NSFNOTECOMPUTEWITHFORM 147
+#define EM_NIFFINDDESIGNNOTE 148
+#define EM_NIFFINDPRIVATEDESIGNNOTE 149
+#define EM_NIFGETLASTMODIFIEDTIME 150
+#define EM_FTSEARCHEXT 160
+#define EM_NAMELOOKUP 161
+#define EM_NSFNOTEUPDATEMAILBOX 164
+#define EM_NIFFINDDESIGNNOTEEXT 167
+#define EM_AGENTOPEN 170
+#define EM_AGENTRUN 171
+#define EM_AGENTCLOSE 172
+#define EM_AGENTISENABLED 173
+#define EM_AGENTCREATERUNCONTEXT 175
+#define EM_AGENTDESTROYRUNCONTEXT 176
+#define EM_AGENTSETDOCUMENTCONTEXT 177
+#define EM_AGENTSETTIMEEXECUTIONLIMIT 178
+#define EM_AGENTQUERYSTDOUTBUFFER 179
+#define EM_AGENTREDIRECTSTDOUT 180
+#define EM_SECAUTHENTICATION 184
+#define EM_NAMELOOKUP2 185
+#define EM_NSFDBHASPROFILENOTECHANGED 198
+#define EM_NSFMARKREAD 208
+#define EM_NSFADDTOFOLDER 209
+#define EM_NSFDBSPACEUSAGESCALED 210 /* V6 */
+#define EM_NSFDBGETMAJMINVERSION 222 /* V5.09 */
+#define EM_ROUTERJOURNALMESSAGE 223 /* V6 */
+
+/* V6 SMTP hooks */
+#define EM_SMTPCONNECT 224
+#define EM_SMTPCOMMAND 225
+#define EM_SMTPMESSAGEACCEPT 226
+#define EM_SMTPDISCONNECT 227
+#define EM_NSFARCHIVECOPYNOTES 228
+#define EM_NSFARCHIVEDELETENOTES 229
+#define EM_NSFNOTEEXTRACTWITHCALLBACK 235
+#define EM_NSFDBSTAMPNOTESMULTIITEM 239
+#define EM_MEDIARECOVERY_NOTE 244
+
+/* These functions are not actually defined (thus their declarations are only
+ in comments) but illustrate the arguments for the corresponding extension
+ manager callouts.
+
+ EM_ROUTERJOURNALMESSAGE occurs when the router has received a message that has been
+ marked to be journalled.
+
+ STATUS LNPUBLIC JournalMessage(DBHANDLE hMailBoxHandle,
+ NOTEID NoteID);
+
+ EM_SETPASSWORD occurs when an ID file password is being set, either by
+ a user or by administrator action.
+
+ STATUS LNPUBLIC SetPassword (
+ DWORD MaxPwdLen, Longest password you may supply
+ DWORD far *retLength, Return the length of the password
+ char far *retPassword, Return the password here
+
+ char far *FileName, The name of the ID file
+ char far *OwnerName, The name of the owner of the ID file
+
+ DWORD DataLen, The old length of the extra ID info
+ BYTE far *Data, The old value of the extra ID info
+
+ DWORD MaxNewData, The max amount of extra ID info you may supply
+ DWORD far *retNewDataLen, Return the length of the new ID info
+ BYTE far *retNewData); Return the new ID info
+
+ EM_GETPASSWORD occurs when a user is about to be prompted for a password
+ to decrypt and ID file.
+
+ STATUS LNPUBLIC GetPassword (
+ DWORD MaxPwdLen, Longest password you may supply
+ DWORD far *retLength, Return the length of the password here
+ char far *retPassword, Return the password here
+
+ char far *FileName, The name of the ID file
+ char far *OwnerName, The name of the owner of the ID file
+
+ DWORD DataLen, The length of the extra ID info
+ BYTE far *Data); The extra ID info
+
+ EM_CLEARPASSWORD occurs when a password is to be "cleared" either due to
+ a timeout or because the user has pressed F5.
+
+ STATUS LNPUBLIC ClearPassword ();
+
+
+ STATUS LNPUBLIC ConflictHandler (
+ HANDLE hDb, Database Handle
+ HANDLE hOldNote, Original Note Handle
+ HANDLE hNewNote, New Note Handle
+ DWORD *pAction); Conflict Action to take
+
+ *pAction returns:
+ CONFLICT_ACTION_MERGE - Have Notes try to merge
+ CONFLICT_ACTION_HANDLE - User handled the conflict
+ (zero) - Proceed with Conflict in normal manner
+
+
+ EM_ADMINPPROCESSREQUEST occurs prior to and after the Administration Process has
+ processed a request on a server.
+
+ STATUS LNPUBLIC ProcessRequest (
+ NOTEHANDLE nhRequest, The handle of the Admin Request note
+ NOTEHANDLE nhResponse); The handle of the Admin Log note
+
+
+ EM_TERMINATENSF occurs when NSF service terminates for the process.
+
+ void LNPUBLIC TerminateNSF (void *unused_params);
+
+
+ EM_NSFNOTEUPDATEMAILBOX occurs when a NSFNoteUpdate is performed on
+ any and all mailbox databases (e.g. mail.box). This is true even if
+ multiple mailboxes are enabled in the server configuration document.
+ The arguments are identical to those used for EM_NSFNOTEUPDATE.
+
+
+ EM_NIFOPENNOTE opens a note by index position and optionally navigates.
+ It is used by the Notes Editor.
+
+ STATUS LNPUBLIC NIFOpenNote (
+ HCOLLECTION hCollection,
+ COLLECTIONPOSITION far *IndexPos,
+ WORD Navigator,
+ WORD FallbackNavigator,
+ NOTEID NoteID,
+ DWORD OpenFlags,
+ INDEXSPECIALINFO far *retIndexInfo,
+ HANDLE far *rethNote);
+
+
+ EM_NSFNOTEOPENEXTENDED is a Notes internal, extended form of NSFNoteOpen.
+
+ STATUS LNPUBLIC NSFNoteOpenExtended (
+ DBHANDLE hDB,
+ NOTEID NoteID,
+ DWORD flags,
+ DWORD SinceSeqNum,
+ BYTE *pKey,
+ HANDLE *rtn);
+
+
+ EM_MAILSENDNOTE is called when the Mailer sends an open note to recipients
+ listed in the note's header items.
+
+ STATUS LNPUBLIC MailSendNote (
+ HANDLE hNote,
+ void *internalViewDesc,
+ WORD Flags,
+ BOOL *Modified,
+ void *SendNoteCtx);
+
+
+ EM_NSFMARKREAD is called when a note is opened by the Notes client and marked READ.
+ Note that this does not include other mechanisms that could result in a note being
+ marked read, such as being read by the client on another replica.
+
+ STATUS LNPUBLIC NSFMarkRead(
+ DBHANDLE hDB, - Handle of database containing note being marked
+ HANDLE hNote, - Handle to note being marked read
+ NOTEID NoteID); - NoteID of the note being marked read
+
+
+ EM_NSFADDTOFOLDER is called when a note is being added or removed
+ from a folder. The IsAddOperation flag should be checked to determine
+ if this note is being added or removed from the folder.
+
+ STATUS LNPUBLIC NSFAddToFolder(
+ DBHANDLE hViewDB, - Handle of database containing folder
+ DBHANDLE hDataDB, - Handle of database containing notes being added to folder
+ NOTEID FolderNoteID, - NoteID of the folder note
+ NOTEID NoteID, - NoteID of the note being added to (removed from) the folder
+ UNID *NoteUNID, - UNID of the note being added to (removed from) the folder
+ BOOL IsAddOperation, - TRUE if note being added to the folder, FALSE if note being removed
+ TIMEDATE *RevisionTime); - Time of original folder addition (OPTIONAL - may be NULL)
+
+ EM_SMTPCONNECT is called when an inbound SMTP connection has been detected.
+
+ The Extension Manager EM_BEFORE notification type for the EM_SMTPCONNECT event occurs when an
+ inbound SMTP connection has been detected and prior to the execution of the internal Domino SMTP
+ restriction controls. Callback routine can implement their own anti-relay checks and bypass
+ Domino related checks through the use of PossibleRelay BOOL and return status of value NOERROR.
+ Return STATUS other than ERR_EM_CONTINUE or NOERROR sets AccessDenied flag which causes subsequent
+ commands to be rejected.
+
+ The Extension Manager EM_AFTER notification type for the EM_SMTPCONNECT event occurs after the SMTP
+ listener task has accepted the connection but prior to sending the SMTP greeting to the connecting host.
+
+ STATUS LNPUBLIC SMTPConnect(
+ DWORD SessionID, - Unique session identifier
+ char *RemoteIP, - NULL terminated string containing IP address of connecting host
+ char *RemoteHost, - NULL terminated string containing host name of connecting host if reverse DNS
+ lookup was successful. If lookup was unsuccessful, the string length will be zero.
+ BOOL &PossibleRelay, - Indicator whether connecting host should be treated as possible relay or not
+ char *Greeting, - Greeting that will be returned to the connecting host
+ - Greeting is NULL during EM_BEFORE notification
+ DWORD MaxGreetingLength); - Size of buffer allocated to modify Greeting
+
+ EM_SMTPCOMMAND is called whenever a SMTP command has been received by the SMTP task.
+
+ The Extension Manager EM_BEFORE notification type for the EM_SMTPCOMMAND event occurs whenever a SMTP
+ command has been received by the SMTP listener task but prior to the parsing of the command.
+
+ Domino allocates a buffer that can be used by callback routines for the EM_BEFORE notification to modify
+ the command and thus change internal Domino processing. NOERROR return status indicates to skip parsing
+ and execution of command. The default reply when STATUS is NOERROR is "250 OK". Return STATUS values
+ other than ERR_EM_CONTINUE and NOERROR from the EM_BEFORE notification results in the command being
+ rejected. A default error message will be generated by the Domino SMTP server, which can be modified by
+ the callback routine for the EM_AFTER notification. STATUS of ERR_EM_CONTINUE will continue normal Domino
+ processing.
+
+ SMTP response to the command entered can be modified during the callback routine of EM_AFTER notification.
+ Care must be taken not to change the reply code from success to failure or vice-versa as this will cause
+ the sender-SMTP and receiver-SMTP servers to be out of synch. Domino supplies a buffer that can
+ be used by the callback routine to change the SMTP response.
+
+ STATUS LNPUBLIC SMTPCommand(
+ DWORD SessionID, - Unique session identifier
+ char *Command, - NULL terminated string containing SMTP command and arguments received
+ DWORD MaxCommandLength, - Size of buffer allocated to modify Command
+ char *SMTPReply, - SMTP response that will be returned to the connecting host
+ - SMTPReply is NULL during EM_BEFORE notification
+ DWORD SMTPReplyLength); - Size of buffer allocated to modify SMTPReply
+
+ EM_SMTPMESSAGEACCEPT is called following the receipt of "end of mail data indicator", a line containing a single
+ period, and itemization of the MIME stream into an in-memory note.
+
+ Following the receipt of the "end of mail data indicator", the resulting stream is itemized to an
+ in-memory note. The Extension Manager EM_BEFORE notification type for the EM_SMTPMESSAGEACCEPT event
+ occurs following itemization but prior to adding the note to the mailbox. If the callback routine
+ returns STATUS of NOERROR, the Domino SMTP server will stop further processing of the message. By default
+ a success response is generated by core Domino code when NOERROR STATUS has been returned. It is also
+ possible for the callback routine to intercept the message and deposit to database where scans can be
+ performed. The Callback routine can make changes to the note in the EM_BEFORE event but should not
+ attempt to close the note as this is done by the core code.
+
+ The Extension Manager EM_AFTER notification type for the EM_SMTPMESSAGEACCEPT event occurs after the SMTP
+ listener task attempted to submit the message to the mailbox but prior to sending a reply. The Callback
+ routines for the EM_AFTER notification can change the reply returned to the connecting host however, care
+ must be taken not to change the reply code from success to error or vice-versa as this would cause the
+ sender-SMTP and receiver-SMTP servers to be out of synch.
+
+ STATUS LNPUBLIC SMTPMessageAccept(
+ DWORD SessionID, - Unique session identifier
+ NOTEHANDLE Note, - Note containing the itemized message
+ char *SMTPReply, - SMTP Response that will be returned to the connecting host
+ - SMTPReply is NULL during EM_BEFORE notification
+ DWORD SMTPReplyLength); - Size of buffer allocated to modify SMTPReply
+
+ EM_SMTPDISCONNECT is called when a SMTP connection is being torn down. This includes normal and abnormal disconnects,
+ such as when the QUIT command is issued or when a session times out.
+
+ STATUS LNPUBLIC SMTPDisconnect(
+ DWORD SessionID); - Unique session identifier
+
+
+ The following 2 archive calls are NOT defined
+
+ EM_NSFARCHIVEDELETENOTES is called after documents have been selected and copied to
+ the destination db if desired. It is time for archiving to delete the archived notes
+ that qualify from the source database
+
+ STATUS LNPUBLIC NSFArchiveDeleteNotes(
+ DBHANDLE hDB, - handle of the source db where notes will be deleted from
+ HANDLE hTempIDTable, - handle of the id table containing the notes ids to be deleted
+ DWORD dwFlags ); - none at this time
+
+
+ EM_NSFARCHIVECOPYNOTES is called after documents have been selected for archiving and
+ copies them from the source db to the specified destination db
+
+ STATUS LNPUBLIC NSFArchiveCopyNotes(
+ DBHANDLE hSrcDB, - dbhandle of the source db
+ DBHANDLE hDestDB, - dbhandle of the destination db
+ HANDLE hIdTable, - handle to the id table containing the note ids to be copied to the dest
+ DWORD dwFlags, - none at this time
+ TIMEDATE *ptdSrcMod, - pointer to a timedate for last modified time of source db
+ REPLFILESTATS *pStats); - pointer to a REPLFILESTATS strcuture containing the stats of the copy
+
+
+ The following functions ARE defined, but their extension manager callouts
+ have slightly different signatures than the standard mechanism because of
+ the fact that the function returns something other than STATUS. The
+ extension manager callout has an added argument which allows the callout
+ to write the return value of the API routine. For purposes of the callout,
+ it is as if the function signatures were as follows.
+
+ STATUS LNPUBLIC AgentIsEnabled(HAGENT hAgent, BOOL *return_value);
+
+ EM_SECAUTHENTICATION is called on the server after the Notes Authentication
+ succeeds but before the session is opened.
+
+ STATUS LNPUBLIC Authentication (WORD wEvent
+ ,SESSIONID SessionId
+ ,char far * pRemoteName
+ ,DWORD dwFlags
+ ,WORD wNetProtocol
+ ,char far * NetAddress
+ ,void far * vpNull
+ )
+
+
+
+ This function is called every time a note is encountered during database media recovery. The database being recovered can
+ not be changed in any way but the note can be, for example, copied off to a different database. This can be used, for example,
+ for salavaging the content of notes which are going to be deleted at a later point in the media recovery process.
+
+ STATUS LNPUBLIC NSFDbMediaRecoveryNote(DBHANDLE hDB, HANDLE hNote, BOOL IsInsert, BOOL IsUpdate, BOOL IsDelete)
+
+*/
+/* Authentication Extension Manager flags
+*/
+#define fAuthRoleServer ((DWORD) 0x00000001)
+#define fAuthRolePassthruServer ((DWORD) 0x00000002)
+#define fAuthClientViaPassthruServer ((DWORD) 0x00000004)
+
+/* Authentication Extension Manager events
+*/
+#define AUTHEM_StartAuthentication ((WORD) 0x0000)
+#define AUTHEM_Poll ((WORD) 0x0001)
+#define AUTHEM_Identify ((WORD) 0x0002)
+#define AUTHEM_Terminate ((WORD) 0x0003)
+
+#define MAXAUTHEMNAMELENGTH 1024
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* EXMGR_DEFS */
+
+
+#if defined(OS400) && (__OS400_TGTVRM__ >= 510)
+#pragma datamodel(pop)
+#endif
+
diff --git a/protocols/LotusNotify/src/cnotesapi/include/global.h b/protocols/LotusNotify/src/cnotesapi/include/global.h
new file mode 100644
index 0000000000..84aec8420c
--- /dev/null
+++ b/protocols/LotusNotify/src/cnotesapi/include/global.h
@@ -0,0 +1,1242 @@
+
+#if defined(OS400) && (__OS400_TGTVRM__ >= 510)
+#pragma datamodel(P128)
+#endif
+
+/*********************************************************************/
+/* */
+/* Licensed Materials - Property of IBM */
+/* */
+/* L-GHUS-5VMPGW, L-GHUS-5S3PEE */
+/* (C) Copyright IBM Corp. 1989, 2005 All Rights Reserved */
+/* */
+/* US Government Users Restricted Rights - Use, duplication or */
+/* disclosure restricted by GSA ADP Schedule Contract with */
+/* IBM Corp. */
+/* */
+/*********************************************************************/
+
+
+
+/* Global Definitions */
+
+#ifndef GLOBAL_DEFS
+#define GLOBAL_DEFS
+
+/* Define the specific operating system products we run on:
+* Currently defined as:
+*
+* - OS2_1x = IBM OS/2 16-bit V1.x (NOW DESUPPORTED)
+* - OS2_2x = IBM OS/2 32-bit V2.x
+* - NT = Microsoft NT operating system.
+* - DOSW16 = Microsoft (DOS-based) Windows/16 V3.x (and NOT UNIX-based Win16)
+* - MAC_68K = Apple Macintosh on Motorola 680x0 processors
+* - MAC_POWERPC = Apple Macintosh on PowerMac 60x processors
+* - SUN = Sun OS (Solaris 1.0) Unix
+* - SOLARIS = Sun Solaris 2.0 Unix
+* - SOLX86 = Sun Solaris 2.x Unix on Intel processors
+* - OS400 = i5/OS for IBM iSeries
+* - AIX = IBM AIX Unix
+* - OS390 = IBM OS/390
+* - HPUX = HP-UX
+* - ODT = SCO OpenDeskTop
+* - UNIXWARE = Novell UnixWare
+* - OSF = Digital Unix
+* - NLM = Novell Netware Loadable Module
+*
+* Define the operating system API (may be used on multiple operating systems)
+*
+* - W = Microsoft Windows API
+* - W16 = Microsoft 16-bit Windows API
+* - W32 = Microsoft 32-bit Windows API
+* - MIRAGE = Uses UNIX Mirage product which emulates Windows/16 API
+* - UNIX = UNIX API (common to all UNIX platforms)
+* - OS2 = OS/2 Base Kernel Services API (either V1.x or V2.x)
+* - PM = OS/2 Presentation Manager API (either V1.x or V2.x)
+* - DOS = DOS INT21 API
+* - MAC = Macintosh Toolbox API
+*
+* Define OS architecture
+*
+* - "PREEMPTIVE" - OS supports preemptive multitasking
+* - "SEMAPHORES" - OS supports semaphores protecting critical regions,
+* as opposed to simply using Yields as critical
+* region protection mechanism
+* - "SEGMENTATION" - Memory addresses stay same across reallocations
+* - "THREADS" - OS supported "threads" of execution that implicitly
+* share DS, allocated data and code.
+* - "SINGLE_INSTANCE_DLL_DS" - DS in DLLs is shared system-wide
+* (as opposed to each process having its own copy)
+* - "LOCAL" - Addressing of "Local" memory (NEAR or FAR)
+* - "NOGUI" - OS has no graphical interface (e.g., NLM or VMS)
+* - "ENABLE_TRANSACTIONS" - OS supports Transaction Tracking
+* - "UNICODE" - OS API requires UNICODE strings, not single-byte strings
+*
+* Define the ways our executables are linked together:
+*
+* - "LINKED_WITH_STATIC_DRIVERS"
+* The network,database,ix drivers are statically linked
+* into the base executables (either single executable or
+* single shared library), and are NOT dynamically loaded
+* into memory when configured by the user.
+* If not defined, then the drivers are dynamically loaded
+* into memory when needed via OSLoadLibrary.
+* This symbol is tested to determine whether to load
+* the library or simply call the statically linked driver
+* directly.
+* - "LINKED_UI_TOGETHER"
+* The user interface portion of the client product (nem,
+* desk, view, edit) are statically linked into a single
+* executable, rather than in separate shared library DLLs.
+* This symbol is tested if the various subprograms need
+* to share copies of variables such as "gi" rather than
+* each having their own copy of the same variable of the
+* same name (which would be necessary if each subprogram
+* is in its own DLL).
+* - "LINKED_EVERYTHING_TOGETHER"
+* The user interface portion is statically linked with
+* the back end portion into a gigantic single executable.
+* Used on platforms where import/export shared libraries
+* do not exist.
+* - "RUNTIME_LOAD_LIBRARY_SUPPORTED"
+* TRUE if OSLoadLibrary supports the ability to dynamically
+* load a library at runtime, and return its main entry point.
+* If FALSE, OSLoadLibrary will at least support connecting
+* to statically linked pseudo-libraries within our own
+* executable, but not to customer-written addin DLLs.
+*
+* Define the byte ordering scheme:
+*
+* - "BIG_ENDIAN_ORDER" - Bytes are ordered MSB to LSB (e.g. 68000)
+* - "LITTLE_ENDIAN_ORDER" - Bytes are ordered LSB to MSB (e.g. 8086, VAX)
+*
+* Define the machine limitations:
+*
+* - ODS_NEEDED = Machine cannot support byte-aligned references
+* and requires struct padding and aligned read/reads
+* - REQUIRED_ALIGNMENT = Alignment required by processor to store largest data type to avoid a bus trap (usually DWORD)
+* - NATURAL_ALIGNMENT = Natural compiler alignment of the largest data type (usually a pointer)
+* - MEMALLOC_ALIGNMENT = Memory Allocation alignment: same as NATURAL_ALIGNMENT except for OS400 with 64 bit pointers
+* - COMPILER_DWORD_ALIGNMENT = Compiler's alignment of a DWORD within a struct
+* - COMPILER_NUMBER_ALIGNMENT = Compiler's alignment of NUMBER (usually a double)
+* This is the alignment the compiler will use for the "Alignment_do_not_use"
+* field of the ALIGNED_NUMBER union.
+*
+* Define the type/capabilities of the compiler we are using.
+* Currently defined as:
+*
+* - "MSC" = Microsoft C
+* - "GCC" = Gnu C
+* - "SYMANTEC_C" = Symantec C/C++ running under MPW on the Mac. (No longer supported in V5)
+* - "MWERKS_C" = Metrowerks C/C++ running under MPW on the Mac.
+* - "MR_C" = Apple MrC running under MPW on the Mac. (obsolete)
+* - "PPC_C" = PPC C on the Mac or PowerMac. (obsolete)
+* - "IBM_C" = IBM Cset/2 on OS2 2.0
+* - "WATCOM_C" = WATCOM C/386 in any env, such as OS/2 2 or Netware
+* - "SUN_C" = Sun native C compiler
+* - "HP_C" = HP native C compiler
+* - "XLC_C" = IBM AIX native C compiler (obsolete)
+* - "OS390_C" = IBM MVS/ESA C/C++ compiler
+* - "UW_C" = UnixWare native C compiler
+* - "ZORTECH_CPP" = Zortech C++ compiler for OS/2
+* - "ILEC400" = OS/400 ILE C cross-compiler for AIX
+*
+* Define the configuration's official name, used in the undocumented
+* @Platform function for some our templates such as NAMES.NSF.
+*
+* - PLATFORM_NAME
+*
+* Define some datatypes which are considered standard by all modules:
+*
+* BYTE = unsigned 8 bit integer
+* SBYTE = signed 8 bit integer
+* WORD = unsigned 16 bit integer
+* SWORD = signed 16 bit integer
+* DWORD = unsigned 32 bit integer
+* LONG = signed 32 bit integer
+* BOOLBYTE= boolean value which occupies exactly 1 byte
+* STATUS = Notes-specific 16-bit error code and string resource identifier
+* NUMBER = A platform-independent IEEE-64 floating point number
+* char = A byte which is part of a LMBCS character string
+*
+* BOOL = boolean value (used in arguments, arbitrary size)
+* (DO NOT USE IN ON-DISK STRUCTURES - MACHINE DEPENDENT SIZE)
+* FLAG = boolean value, ONLY used in bit fields in structs (arbitrary size)
+* (DO NOT USE IN ON-DISK STRUCTURES - MACHINE DEPENDENT POSITION)
+* short = signed integer at least 8 bits wide
+* (DO NOT USE IN ON-DISK STRUCTURES - MACHINE DEPENDENT SIZE)
+* int = signed integer at least 16 bits wide
+* (DO NOT USE IN ON-DISK STRUCTURES - MACHINE DEPENDENT SIZE)
+* long = signed integer at least 32 bits wide
+* (DO NOT USE IN ON-DISK STRUCTURES - MACHINE DEPENDENT SIZE)
+* NCHAR = A platform-specific character (1 or 2 bytes depending if UNICODE is enabled)
+* (DO NOT USE IN ON-DISK STRUCTURES - MACHINE DEPENDENT SIZE)
+*/
+
+#if defined(DOSW16) || defined(DOS)
+ #ifdef _MSC_VER
+ #define MSC
+ #endif
+ #define LITTLE_ENDIAN_ORDER
+ #if defined(W) || defined(W16) || defined(DOSW16)
+ #ifndef W16
+ #define W16
+ #endif
+ #ifndef W
+ #define W
+ #endif
+ #ifndef DOSW16
+ #define DOSW16
+ #endif
+ #define SEGMENTATION
+ #define SEMAPHORES
+ #define SEMSPIN
+ #define PLATFORM_NAME "Windows/16"
+ #else
+ #define PLATFORM_NAME "MS-DOS"
+ #define NOGUI
+ #endif
+ #ifndef DOS
+ #define DOS
+ #endif
+ #define SINGLE_INSTANCE_DLL_DS
+ #define ODS_NEEDED FALSE
+ #define COMPILER_INT_SIZE 2
+ #define REQUIRED_ALIGNMENT 1
+ #define COMPILER_DWORD_ALIGNMENT 1
+ #define COMPILER_NUMBER_ALIGNMENT 1
+ #define VIM_USE_MSWIN
+#elif defined(OS400) /* This should appear before the OS2 test below, because that section tests for __IBMCPP__,
+ which our C++ compiler also generates */
+ #define PLATFORM_NAME "OS/400"
+ #ifndef UNIX
+ #define UNIX
+ #endif
+ #ifndef W32
+ #define W32 /* Compile for Windows 32 API - its emulated */
+ #endif
+ #ifndef W
+ #define W /* Compile for Windows 32 API - its emulated */
+ #endif
+ #if !defined(MIRAGE) && !defined(INTERNOTES)
+ #define MIRAGE
+ #endif
+ #ifndef HANDLE_IS_32BITS
+ #define HANDLE_IS_32BITS
+ #endif
+ #define BIG_ENDIAN_ORDER
+ #define PREEMPTIVE
+ #define SEMAPHORES
+ #define SEMALLOC
+ #define ODS_NEEDED TRUE
+ #define COMPILER_INT_SIZE 4
+ #ifdef OS400_64 /* OS400 with 64 bit pointers */
+ #define REQUIRED_ALIGNMENT 8
+ #define NATURAL_ALIGNMENT 8
+ #define MEMALLOC_ALIGNMENT 16 /* some pointers will still be 128 bits */
+ #else /* OS400 with 128 bit pointers */
+ #define REQUIRED_ALIGNMENT 16
+ #define NATURAL_ALIGNMENT 16
+ #endif
+ #define PTRISNOT32BIT
+ #define COMPILER_DWORD_ALIGNMENT 4
+ #define COMPILER_NUMBER_ALIGNMENT 8
+ #define VIM_USE_UNIX
+ #define THREADS
+ #ifndef NOGUI
+ #define NOGUI
+ #endif
+ #if defined(__ILEC400__) || defined(__AIXxiCC__) || defined(__AIXxxlC400__)
+ #define ILEC400
+ #endif
+#elif defined(OS2) || defined(OS2_2x) || defined(PM)
+ #ifndef OS2
+ #define OS2
+ #endif
+ #ifndef OS2_2x
+ #define OS2_2x
+ #endif
+ #ifndef PM
+ #define PM
+ #endif
+ #if defined(__IBMC__) || defined(__IBMCPP__)
+ #define IBM_C
+ #endif
+ #ifdef __WATCOMC__
+ #define WATCOM_C
+ #endif
+ #define PLATFORM_NAME "OS/2v2"
+ #define LITTLE_ENDIAN_ORDER
+ #define PREEMPTIVE
+ #define SEMAPHORES
+ #define SEMALLOC
+ #define THREADS
+ #define ODS_NEEDED FALSE
+ #define COMPILER_INT_SIZE 4
+ #define REQUIRED_ALIGNMENT 1
+ #define COMPILER_DWORD_ALIGNMENT 1
+ #define COMPILER_NUMBER_ALIGNMENT 1
+ #define VIM_USE_OS2_32
+#elif defined(OS2_1x)
+ #ifndef OS2
+ #define OS2
+ #endif
+ #ifndef OS2_1x
+ #define OS2_1x
+ #endif
+ #ifndef PM
+ #define PM
+ #endif
+ #define PLATFORM_NAME "OS/2v1"
+ #ifdef __ZTC__
+ #define ZORTECH_CPP
+ #endif
+ #define MSC
+ #define LITTLE_ENDIAN_ORDER
+ #define PREEMPTIVE
+ #define SEMAPHORES
+ #define SEGMENTATION
+ #define THREADS
+ #define ODS_NEEDED FALSE
+ #define COMPILER_INT_SIZE 2
+ #define REQUIRED_ALIGNMENT 1
+ #define COMPILER_DWORD_ALIGNMENT 1
+ #define COMPILER_NUMBER_ALIGNMENT 1
+ #define VIM_USE_OS2_16
+#elif defined(NT) || (defined(W32) && !defined(UNIX))
+ #ifndef W32
+ #define W32
+ #endif
+ #ifndef W
+ #define W
+ #endif
+ #ifndef NT
+ #define NT
+ #endif
+ #define PLATFORM_NAME "Windows/32"
+ #ifdef _MSC_VER
+ #define MSC
+ #endif
+ #if defined(__IBMC__) || defined(__IBMCPP__)
+ #define IBM_C
+ #endif
+ #define THREADS
+ #define LITTLE_ENDIAN_ORDER
+ #define PREEMPTIVE
+ #define SEMAPHORES
+ #define SEMALLOC
+ #ifdef _X86_
+ #define ODS_NEEDED FALSE
+ /* Suppress "used #pragma pack to change alignment" */
+ #pragma warning(disable:4103)
+ /* Note: If you change the packing, you must also change inc\globpack.h */
+ #pragma pack(1)
+ #define REQUIRED_ALIGNMENT 1
+ #define COMPILER_DWORD_ALIGNMENT 1
+ #define COMPILER_NUMBER_ALIGNMENT 1
+ #else
+ #define ODS_NEEDED TRUE
+ #define REQUIRED_ALIGNMENT 4
+ #define COMPILER_DWORD_ALIGNMENT 4
+ #define COMPILER_NUMBER_ALIGNMENT 4
+ #endif
+ #define COMPILER_INT_SIZE 4
+ #define VIM_USE_MSWIN_NT
+ #define OLEW32
+ /* Enable some OLE definitions which are only available for NT 4.0 and
+ above. The programmer must be careful not to use them on other
+ Win32 platforms.
+ */
+#ifndef _WIN32_WINNT
+ #define _WIN32_WINNT 0x0400
+#endif
+#elif defined(MAC) || defined(applec) || defined(__PPCC__) || defined(__MWERKS__) || defined(__SC__) || defined(__MRC__) || defined(THINK_C)
+ #ifndef MAC
+ #define MAC
+ #endif
+ /* We have dropped support for System 6. Turning on this switch causes
+ Apple's headers to explicitly generate inline traps into the MacOS
+ rather than statically linking glue code into our executable. This
+ does 2 things: A) reduces size of our app slightly, and B) makes it
+ possible for Apple to fix a bug in the code (since the code resides
+ in the MacOS itself rather than statically linked into our app). */
+ #ifndef SystemSevenOrLater
+ #define SystemSevenOrLater TRUE
+ #endif
+ #if defined(__MWERKS__) /* Metrowerks MPW compiler */
+ #ifdef __powerc
+ #ifndef MAC_POWERPC
+ #define MAC_POWERPC
+ #endif
+ #else
+ #ifndef MAC_68K
+ #define MAC_68K
+ #endif
+ #endif
+ #ifndef MWERKS_C
+ #define MWERKS_C
+ #endif
+ #elif defined(__PPCC__) /* Apple "Macintosh on RISC" PPC cross-dev MPW compiler */
+ #ifndef MAC_POWERPC
+ #define MAC_POWERPC
+ #endif
+ #ifndef PPC_C
+ #define PPC_C
+ #endif
+ #elif defined(__xlc) || defined(__xlC) /* IBM "XLC" PPC native AIX-based compiler */
+ #ifndef MAC_POWERPC
+ #define MAC_POWERPC
+ #endif
+ #ifndef XLC_C
+ #define XLC_C
+ #endif
+ #elif defined(_MSC_VER) /* Microsoft Visual C++ 2.0 cross-dev compiler */
+ #ifndef MAC_68K
+ #define MAC_68K
+ #endif
+ #ifndef MSC
+ #define MSC
+ #endif
+ #elif defined(__MRC__) /* Apple/Symantec MrC MPW compiler */
+ #ifndef MAC_POWERPC
+ #define MAC_POWERPC
+ #endif
+ #ifndef MR_C
+ #define MR_C
+ #endif
+ #elif defined(applec) /* 68K MPW compiler */
+ #if defined(__SC__)
+ #ifndef MAC_68K
+ #define MAC_68K
+ #endif
+ #ifndef SYMANTEC_C
+ #define SYMANTEC_C
+ #endif
+ #endif
+ #elif defined(__GNUC__) /* gcc compiler on Mac OS X */
+ #ifndef MAC_POWERPC
+ #define MAC_POWERPC
+ #endif
+ #elif !defined(THINK_C)
+ #error Unknown Mac development environment
+ #endif
+ #define PLATFORM_NAME "Macintosh"
+ #define BIG_ENDIAN_ORDER
+ #define THREADS
+ #define SEMAPHORES
+ #define SEMSPIN
+ #define ODS_NEEDED TRUE
+ #define COMPILER_INT_SIZE 4
+ #if defined(MAC_POWERPC) && defined(XLC_C) /* All other compilers use "-align mac68k" (2 byte alignment) */
+ #define REQUIRED_ALIGNMENT 1 /* PowerPC supports odd-byte addressing if truly required */
+ #define COMPILER_DWORD_ALIGNMENT 4 /* Compiler will pad DWORDs to DWORD boundary if possible */
+ #define COMPILER_NUMBER_ALIGNMENT 4
+ #else
+ #define REQUIRED_ALIGNMENT 1 /* 68020 or later CPUs only (not 68000) */
+ #define COMPILER_DWORD_ALIGNMENT 2 /* Compiler will pad DWORDs to WORD boundary, because any further alignment is unnecessary */
+ #define COMPILER_NUMBER_ALIGNMENT 2
+ #endif
+ #define VIM_USE_MAC
+ /* Tdanalzye is a rudimentary parser, that is failing to correctly parse this long #if #elif statements.
+ * It is re-processing the UNIX section after it has already processed the OS400 section and incorrectly
+ * using a COMPILER_NUMBER_ALIGNMENT of 4. So for now, add a redundant !OS400, until tdanalzye is fixed.
+ */
+#elif defined(UNIX) && !defined(OS400)
+ #ifndef W32
+ #define W32 /* Compile for Windows 32 API - its emulated */
+ #endif
+ #ifndef W
+ #define W /* Compile for Windows 16 API - its emulated */
+ #endif
+ #if !defined(MIRAGE) && !defined(INTERNOTES)
+ #define MIRAGE
+ #endif
+ #define PLATFORM_NAME "UNIX"
+ #if defined(AIX)
+ #define XLC_C
+ #elif defined(SUN) || defined(SOLARIS)
+ #define SUN_C
+ #elif defined(HPUX)
+ #define HP_C
+ #elif defined(OS390)
+ #define OS390_C
+ #elif defined(UNIXWARE)
+ #define UW_C
+ #elif defined(__osf__)
+ #if !defined(OSF)
+ #define OSF
+ #endif
+ #define DEC_C
+ #elif defined(LINUX)
+ #define GCC
+ #endif
+ #if (defined(ODT) || defined(SOLX86) || defined(UNIXWARE) || defined(OSF) || defined(LINUX)) && !defined(ZLINUX)
+ #define LITTLE_ENDIAN_ORDER
+ #else
+ #define BIG_ENDIAN_ORDER
+ #endif
+ #define PREEMPTIVE
+ #define SEMAPHORES
+ #define SEMALLOC
+ /* All UNIX type platforms except Solaris,HPUX, and AIX are 32 bit handle platforms */
+ /* This needs to be here so that it is also included in the SDK */
+ #if !(defined(SOLARIS) || defined(HPUX) || defined(SOLX86) || defined(AIX))
+ #ifndef HANDLE_IS_32BITS
+ #define HANDLE_IS_32BITS
+ #endif
+ #endif
+ #if (defined(SOLARIS) || defined(AIX) || defined (HPUX) || defined(OS390) || defined(LINUX)) && !defined(DISABLE_THREADS)
+ #define THREADS
+ #endif
+ /* ODS needed, even for ODT (on x86 machines), because X includes
+ don't support having the compiler set for tight packing (-Zp1),
+ that is, they assume padding. With padding enabled, we must use
+ ODS even when theoretically unncessary. Perhaps the X headers
+ can be kludged to explicitly pad so that this is unnecessary. */
+ #if defined(ODT_LATER)
+ #define COMPILER_INT_SIZE 4
+ #define REQUIRED_ALIGNMENT 1
+ #define COMPILER_DWORD_ALIGNMENT 2
+ #define COMPILER_NUMBER_ALIGNMENT 2
+ #else
+ #define ODS_NEEDED TRUE
+ #define COMPILER_INT_SIZE 4
+ #if defined(OSF)
+ #define REQUIRED_ALIGNMENT 8
+ #else
+ #define REQUIRED_ALIGNMENT 4
+ #endif
+ #define COMPILER_DWORD_ALIGNMENT 4
+ #if defined(SOLARIS) || defined(HPUX) || defined(OS390) || defined(ZLINUX)
+ #define COMPILER_NUMBER_ALIGNMENT 8
+ #else
+ #define COMPILER_NUMBER_ALIGNMENT 4
+ #endif
+ #endif
+ #define VIM_USE_UNIX
+
+#elif defined(NLM)
+ #ifdef __WATCOMC__
+ #define WATCOM_C
+ #endif
+ #ifdef _MSC_VER
+ #define MSC
+ #endif
+ #define PLATFORM_NAME "NetWare"
+ #define LITTLE_ENDIAN_ORDER
+ #define SEMAPHORES
+ #define SEMALLOC
+ #define THREADS
+ #define SINGLE_INSTANCE_DLL_DS
+ #define ODS_NEEDED FALSE
+ #define COMPILER_INT_SIZE 4
+ #define REQUIRED_ALIGNMENT 1
+ #define COMPILER_DWORD_ALIGNMENT 1
+ #define COMPILER_NUMBER_ALIGNMENT 1
+ #define NOGUI
+ #define ENABLE_TRANSACTIONS
+ #define VIM_USE_NLM
+#else
+ #error Must specify type of OS ("DOS", "OS2", etc) on C command line!
+#endif
+#if (defined(SOLARIS) || defined(AIX)) && defined(Enable_New_SpinLocks)
+ #define USE_COND_SLEEP_ON_SPINLOCK 1
+#endif
+
+
+/* Nullify the certain compiler keywords if not supported by compiler */
+
+#if !defined(MSC) || defined(NT) || defined(MAC)
+
+ #if !defined(MAC) /* On Mac, "pascal" (lowercase) is a reserved word */
+ #ifdef pascal
+ #undef pascal
+ #endif
+
+ #if defined(_MSC_VER) && _MSC_VER >= 800
+ #define pascal __stdcall
+ #else
+ #define pascal
+ #endif
+ #endif /* !defined(MAC) */
+
+ #if defined(MAC)
+ #define PASCAL
+ #endif
+
+ #ifndef PASCAL
+ #define PASCAL
+ #endif
+
+ #ifdef cdecl
+ #undef cdecl
+ #endif
+
+ #define cdecl
+
+ #if !defined(MWERKS_C) /* In MWERKS_C, "far" is a reserved word, and cannot appear in an #ifdef expression */
+ #ifdef far
+ #undef far
+ #endif
+ #endif
+
+ #define far
+
+ #ifndef FAR
+ #define FAR
+ #endif
+
+ #ifdef near
+ #undef near
+ #endif
+
+ #define near
+
+ #ifndef NEAR
+ #define NEAR
+ #endif
+
+ #ifdef huge
+ #undef huge
+ #endif
+
+ #define huge
+
+#endif /* !defined(MSC) || defined(NT) || defined(MAC) */
+
+/* Nullify C keywords that are not supported by some compilers */
+
+#if defined(GCC)
+#if !defined(LINUX) /* These two are already handled with latest GCC headers on LINUX */
+ #define volatile
+ #define signed
+ #define const
+#endif
+#elif defined(HP_C) && defined(__cplusplus)
+ #define signed
+#elif defined(SUN_C) && defined(__cplusplus)
+ #define signed
+#endif
+
+/* Remove certain definitions if the Netware header files have defined
+ them previously, potentially in conflict with OUR definitions */
+
+#ifdef NLM
+ #undef BYTE
+ #undef WORD
+ #undef LONG
+#endif
+
+
+
+
+/* Handle loading of os2def.h up-front, since everyone needs it. */
+
+#ifdef OS2
+ #ifndef APIENTRY
+ #include "os2def.h"
+ #include "bsedos.h"
+ #endif
+#endif
+
+/* Same goes for NT include files */
+
+#ifdef NT
+ #ifndef _WINDEF_
+ #ifndef RC_INVOKED
+ /* Save packing around inclusion of Microsoft headers, just to
+ protect ourselves against their failure to restore packing
+ if they change it. This may not be needed anymore... */
+ #pragma pack(push, WinIncludes)
+ /* Set packing to be 4, to temporarily workaround a bug in wincon.h
+ where Microsoft incorrectly assumes natural packing instead of
+ setting it explicitly. */
+ #pragma pack()
+ #endif
+
+ #undef PASCAL
+ #undef FAR
+ #undef NEAR
+
+ /* Windows.h defines WINVER, but we seldom include windows.h
+ when using other windows headers.
+ */
+ #ifndef WINVER
+ #define WINVER 0x0500
+ #endif
+
+ /* Determine the processor type as required by the following Windows
+ includes */
+
+ #if !defined(_PPC_) && !defined(_ALPHA_) && !defined(_MIPS_) && !defined(_X86_) && defined(_M_IX86)
+ #define _X86_
+ #endif
+
+ #if !defined(_PPC_) && !defined(_ALPHA_) && !defined(_X86_) && !defined(_MIPS_) && defined(_M_MRX000)
+ #define _MIPS_
+ #endif
+
+ #if !defined(_PPC_) && !defined(_ALPHA_) && !defined(_X86_) && !defined(_MIPS_) && defined(_M_ALPHA)
+ #define _ALPHA_
+ #endif
+
+ #if !defined(_PPC_) && !defined(_ALPHA_) && !defined(_X86_) && !defined(_MIPS_) && defined(_M_PPC)
+ #define _PPC_
+ #endif
+
+ #include <stdarg.h>
+ #define NOMINMAX
+ #include <windef.h>
+ #undef NOMINMAX
+ #include <winbase.h>
+ #include <WinVer.h>
+
+ #ifndef RC_INVOKED
+ #pragma pack(pop, WinIncludes)
+ #endif
+ #endif
+#endif
+
+
+#if defined(MAC)
+#if defined(MAC_OSX)
+ #include <Carbon/Carbon.h>
+#else
+ #include <MacTypes.h> /* Needed for basic "Handle", "Point", "Rect" typedefs */
+ #include <MacMemory.h> /* Needed for BlockMove() define */
+#endif
+#endif
+
+
+/* Determine what has been included BEFORE this module */
+
+#if defined(_INC_WINDOWS) /* WIN16 */ || defined(_WINDEF_) /* WIN32 */
+ #define WINDOWS_INCLUDED
+#endif
+
+#ifdef SEVERITY_NOERROR
+ #define OS2DEF_INCLUDED
+#endif
+
+
+
+/* Define datatypes which are also defined by other include files */
+
+#ifndef FAR
+ #define FAR far
+#endif
+#ifndef NEAR
+ #define NEAR near
+#endif
+#ifndef PASCAL
+ #define PASCAL pascal
+#endif
+
+#if !defined(OS2DEF_INCLUDED) && !defined(WINDOWS_INCLUDED)
+ #define VOID void
+ typedef unsigned char BYTE;
+ #if defined(LONGIS64BIT)
+ typedef int LONG;
+ #else
+ typedef long LONG;
+ #endif
+
+ #if defined(UNIX)
+ typedef int BOOL;
+ #elif defined(OS2_2x)
+ typedef unsigned long BOOL;
+ #elif defined(OS2_1x)
+ typedef unsigned short BOOL;
+ #elif defined(DOSW16)
+ typedef int BOOL;
+ #else
+ typedef short BOOL;
+ #endif
+ #define LOBYTE(w) ((BYTE)w)
+ #define HIBYTE(w) (((WORD)w >> 8) & 0xff)
+#endif
+
+#ifndef OS2DEF_INCLUDED
+ #ifndef _WINDEF_ /* USHORT, ULONG and UCHAR are already defined in windef.h */
+ typedef unsigned short int USHORT;
+ #if defined(LONGIS64BIT)
+ typedef unsigned int ULONG;
+ #else
+ typedef unsigned long ULONG;
+ #endif
+ typedef unsigned char UCHAR;
+ #endif /* _WINDEF_ */
+ #ifndef WINDOWS_INCLUDED /* This is also defined in windows.h */
+ typedef unsigned int UINT;
+ #endif
+#endif
+
+
+/* Define datatype which is used to represent a "resource file" */
+
+#ifndef HMODULE
+#if !defined(OS2) /* OS2 already defines this */
+ #define HMODULE HANDLE
+#endif
+#endif
+
+#if !defined(WINDOWS_INCLUDED)
+
+/* These symbols/typedefs ARE COPIED from WINDOWS.H, and are the
+ ONLY symbols that should be defined in this section! (This
+ is a help for modules that can't afford to include windows.h
+ and want to use a few of these helpful definitions. */
+
+ typedef unsigned short WORD; /* WORD = unsigned 16 bit integer */
+ #if defined(LONGIS64BIT)
+ typedef unsigned int DWORD; /* DWORD = unsigned 32 bit integer */
+ #else
+ typedef unsigned long DWORD;
+ #endif
+/* Windows defines a HANDLE as unsigned int, but the Mac needs it to be
+ unsigned short. In C, both are equivalent, but C++ is pickier */
+
+#if defined(DOSW16)
+ typedef unsigned int HANDLE; /* really a short, but compiler is picky */
+#elif defined(HANDLE_IS_32BITS)
+ typedef unsigned int HANDLE; /* 32-bit HANDLEs */
+#else
+ typedef unsigned short HANDLE;
+#endif
+
+
+ #define LOWORD(l) ((WORD)(DWORD)(l))
+ #define HIWORD(l) ((WORD)(((DWORD)(l) >> 16) & 0xffff))
+
+#else /* if WINDOWS_INCLUDED */
+
+ /* TEMPORARY: Fix a bug in the standard Windows LOWORD macro (see
+ also a copy of it above), which produces a C compiler warning
+ regarding loss of segment portion of a pointer. */
+
+ #undef LOWORD
+ #define LOWORD(l) ((WORD)(DWORD)(l))
+
+#endif
+
+
+
+
+/* Define our Notes-specific global data types */
+
+#define FLAG unsigned /* FLAG = 1-bit boolean value */
+ /* (Unsized, use ONLY in bitfields!) */
+#define BOOLBYTE BYTE /* BOOLBYTE = boolean used in DS */
+#define UBYTE BYTE /* UBYTE = unsigned 8 bit integer */
+#define SBYTE signed char /* SBYTE = signed 8 bit integer */
+#define SWORD signed short /* SWORD = signed 16 bit integer */
+
+typedef DWORD MEMHANDLE; /* MEMHANDLE = Handle returned by OSMemoryAllocate */
+#define NULLMEMHANDLE (MEMHANDLE) 0
+
+typedef WORD STATUS; /* STATUS = Status code (ERR_xxx) */
+ /* High byte is subsystem; */
+ /* Low byte is status code */
+typedef DWORD FONTID; /* Font identifier - see FONTID.H */
+
+typedef struct {
+ WORD width;
+ WORD height;
+} RECTSIZE;
+
+
+//commented for LotusNotify Miranga NG plugin beacouse of conflicts with miranda headers (struct LIST at m_system_cpp.h)
+///* List structure */
+//typedef struct {
+// USHORT ListEntries; /* list entries following */
+// /* now come the list entries */
+//} LIST;
+
+/* Range structure */
+
+typedef struct {
+ USHORT ListEntries; /* list entries following */
+ USHORT RangeEntries; /* range entries following */
+ /* now come the list entries */
+ /* now come the range entries */
+} RANGE;
+
+
+/* Basic time/date structure --
+ The following 2 structures are ONLY intended to be interpreted using
+ the "Time" package (see misc.h) conversion routines. These structures
+ are "bit-encoded", and cannot be parsed/interpreted easily. */
+
+typedef struct tagTIMEDATE {
+ DWORD Innards[2];
+} TIMEDATE;
+
+typedef struct { /* a timedate range entry */
+ TIMEDATE Lower;
+ TIMEDATE Upper;
+} TIMEDATE_PAIR;
+
+#ifndef OS2_2x /* OS2 2.x already defines this itself */
+#if defined(LONGIS64BIT)
+typedef long QWORD;
+#else
+//wsx22 change - commented typedef
+//http://social.msdn.microsoft.com/Forums/en/vcmfcatl/thread/ba3ce55a-dc91-4917-8bd6-c326595b4594
+//typedef struct {DWORD Dwords[2];} QWORD;
+#endif
+#endif
+
+/* Basic floating-point number structure --
+ This structure is EXACTLY the same format as a 64-bit IEEE floating
+ point number, usually defined in most C compilers as "double". */
+
+
+typedef double NUMBER; /* NSF floating type (IEEE 64-bit) */
+typedef NUMBER ALIGNED_NUMBER;
+#if defined(DOS) || defined(OS2) || defined(MAC) /* This doesn't work for NT, which has its own FLOAT */
+#define FLOAT NUMBER /* for pre-V3 backward compatibility ONLY */
+#define FLOAT_PAIR NUMBER_PAIR /* for pre-V3 backward compatibility ONLY */
+#endif /* DOS or OS2 */
+
+
+typedef struct { /* a float range entry */
+ NUMBER Lower;
+ NUMBER Upper;
+} NUMBER_PAIR;
+
+typedef NUMBER_PAIR ALIGNED_NUMBER_PAIR;
+
+/* This is the structure that defines a license number. Do not attempt
+ to interpret this structure too exactly, since it may change in future
+ releases. For now, simply treat the entire strucure as a unique ID. */
+
+typedef struct {
+ BYTE ID[5]; /* license number */
+ BYTE Product; /* product code, mfgr-specific */
+ BYTE Check[2]; /* validity check field, mfgr-specific */
+} LICENSEID;
+
+typedef WORD BLOCK; /* pool block handle */
+
+/* Define symbols for boolean true/false */
+
+#ifndef TRUE
+ #define FALSE 0
+ #define TRUE !FALSE
+#endif
+
+
+/* Define the NULL symbol (ignoring previous ones so that it is always a simple "0"). */
+
+#ifdef NULL
+#undef NULL
+#endif
+#define NULL 0
+
+/* Define the Notes calling convention macros. */
+
+#if !defined(OS2)
+
+#define LNPUBLIC FAR PASCAL /* Routines called from outside
+ a subsystem (includes routines
+ in the published API). */
+#define LNCALLBACK FAR PASCAL /* Routines specified as callbacks
+ within Notes or an API program */
+#if defined(OS390) && defined(__XPLINK__)
+#define LNCALLBACKPTR LNCALLBACK FAR * __callback /* Macro for defining a pointer to
+ a callback routine. __callback added
+ for XPLINK DLL to nonXPLINK DLL calls */
+#else
+#define LNCALLBACKPTR LNCALLBACK FAR * /* Macro for defining a pointer to
+ a callback routine */
+#endif /* OS390 */
+#define LNVARARGS FAR cdecl /* Routines with a variable number
+ of arguments */
+#else
+
+/* OS/2 requires separate macros because the ordering of function
+ modifiers for function pointer is different. This prevents us
+ from inserting _System in a uniform place (e.g. a replacemet
+ for PASCAL). See the comments above for their use.*/
+
+#define LNPUBLIC _System
+#define LNCALLBACK _System
+#define LNCALLBACKPTR * _System
+#define LNVARARGS _System
+#endif
+
+/* Define some obsolete macros that used to be used for OS/2 32-bit
+ programs that used the 16-bit Notes API. These macros are now
+ obsolete, but are here to help in backward compatibility for
+ these older programs. */
+
+#define NOTESMAIN LNPUBLIC
+#define NOTESAPI LNPUBLIC
+#define NOTESAPICDECL LNVARARGS
+#define NOTESCALLBACK LNCALLBACK
+#define NOTESCALLBACKPTR LNCALLBACKPTR
+#define NOTESPTR FAR *
+#define NOTESBOOL BOOL
+
+#ifdef NULLHANDLE
+#undef NULLHANDLE /* Override any existing defn (e.g. OS2 2.0) */
+#endif
+#define NULLHANDLE 0
+
+/* Define some miscellaneous constants */
+
+#ifndef MAXDWORD
+#define MAXDWORD ((DWORD) 0xffffffff)
+#endif
+#ifndef MAXWORD
+#define MAXWORD ((WORD) 0xffff)
+#endif
+#ifndef MAXBYTE
+#define MAXBYTE ((BYTE) 0xff)
+#endif
+
+#ifndef MAXINT
+#define MAXINT ((int) (((unsigned int) -1) >> 1))
+#endif
+
+#ifndef MININT
+#define MININT ((int) (~(unsigned int) MAXINT))
+#endif
+
+#ifndef BITS_PER_BYTE
+#define BITS_PER_BYTE 8
+#endif
+
+
+/* Define a platform-independent method of obtaining the address of
+ the "..." variable arguments in a "cdecl" "..." routine.
+
+ void far cdecl SampleRoutine(char *String, WORD LastNamedArgument, ...)
+ {
+ DWORD temp1;
+ WORD temp2;
+ VARARG_PTR ap;
+
+ VARARG_START(ap,LastNamedArgument); * Start out just past last named argument
+ temp1 = VARARG_GET(ap,DWORD); * Get next DWORD into temp1 and advance
+ temp2 = VARARG_PEEK(ap,WORD); * Peek at next WORD, but no advance
+ temp2 = VARARG_GET(ap,WORD); * Get next WORD into temp2 and advance
+ ...
+ }
+*/
+#define VARARG_ROUND_UP(n,unit) ((((n) + (unit) - 1) / (unit)) * (unit))
+
+#if defined(OSF) || (defined(NT) && defined(_ALPHA_)) || defined(LINUX) || defined(SOLARIS)
+#include <stdarg.h>
+#define VARARG_PTR va_list
+#elif defined(OS400)
+#include <stdarg.h>
+typedef struct
+ {
+ char* vaold;
+ char* vanew;
+ } VARARG_PTR;
+#else
+typedef char * VARARG_PTR;
+#endif
+
+/*
+ The C++ 3.0.1 compiler on X86 has a bug. The __builtin_va_arg_incr
+ doesn't work with short data type.
+ It works fine with 'cc'. So use the definition under 'LITTLE_ENDIAN_ORDER'
+*/
+#if defined(SOLARIS) && !defined(SOLX86)
+#define VARARG_START(_AP,_LASTNAMEDARG) \
+ ((_AP) = (char *) &__builtin_va_alist)
+#elif defined(SUN) && defined(GCC)
+#define VARARG_START(_AP,_LASTNAMEDARG) \
+ (__builtin_saveregs(), \
+ (_AP) = (char *) &(_LASTNAMEDARG) + sizeof(_LASTNAMEDARG))
+#elif defined(HPUX)
+#ifdef __GNUC__
+
+#define VARARG_START(_AP,_LASTNAMEDARG) \
+ (_AP = __builtin_saveregs())
+#else
+#ifdef __cplusplus
+#define VARARG_START(_AP,_LASTNAMEDARG) \
+ (_AP) = (char *) &(_LASTNAMEDARG);
+
+#else
+#define VARARG_START(_AP,_LASTNAMEDARG) \
+ (__builtin_va_start(_AP,&_LASTNAMEDARG), \
+ (_AP) = (char *) &(_LASTNAMEDARG))
+#endif
+#endif
+#elif defined(OSF) || defined(LINUX) || (defined(NT) && defined(_ALPHA_))
+#define VARARG_START(_AP,_LASTNAMEDARG) \
+ (va_start(_AP,_LASTNAMEDARG))
+#elif defined(OS400)
+#define VARARG_START(_AP, _LASTNAMEDARG) \
+ ( (_AP).vanew = ((char *) &(_LASTNAMEDARG)) + sizeof(_LASTNAMEDARG) )
+
+#elif defined(LITTLE_ENDIAN_ORDER) || defined(XLC_C)
+#define VARARG_START(_AP,_LASTNAMEDARG) \
+ ((_AP) = (char *) &(_LASTNAMEDARG) + VARARG_ROUND_UP(sizeof(_LASTNAMEDARG),sizeof(int)))
+#else /* BIG_ENDIAN_ORDER */
+#define VARARG_START(_AP,_LASTNAMEDARG) \
+ ((_AP) = (char *) &(_LASTNAMEDARG) + sizeof(_LASTNAMEDARG))
+#endif
+
+
+#if defined(SOLARIS) && !defined(SOLX86)
+#define VARARG_GET(_AP,_TYPE) \
+ ((_TYPE *)__builtin_va_arg_incr((_TYPE *)_AP))[0]
+#elif defined(HPUX)
+#define TYPE_MASK(_TYPE) (sizeof(_TYPE) > 4 ? 0xFFFFFFF8 : 0xFFFFFFFC)
+#define VARARG_GET(_AP,_TYPE) \
+ ((_AP) = (VARARG_PTR)((long)((_AP) - sizeof(int)) \
+ & TYPE_MASK(_TYPE)) , \
+ *(_TYPE *)((_AP) + ((8 - sizeof(_TYPE)) % 4)))
+#elif defined(GCC3)
+/* GCC3 doesn't allow variable arguments shorter than 4 bytes. If any argument is less than
+ 4 bytes and is passed through the parameter list (...), it will be converted to 4 bytes */
+#define VARARG_GET(_AP,_TYPE) \
+ ((sizeof(_TYPE) < sizeof(DWORD)) ? ((_TYPE) va_arg(_AP,DWORD)) : (va_arg(_AP,_TYPE)))
+
+#elif defined(OSF) || defined(LINUX) || (defined(NT) && defined(_ALPHA_))
+#define VARARG_GET(_AP,_TYPE) \
+ (va_arg(_AP,_TYPE))
+#elif defined(OS400)
+#define __VARARG_GET(_AP, _TYPE) \
+ ( (_AP).vaold = __bndup((_AP).vanew, _TYPE),\
+ (_AP).vanew = (_AP).vaold + sizeof(_TYPE), \
+ *(_TYPE *)((_AP).vaold ) )
+/* The C++ compiler will complain about the conversion of DWORD to a struct datatype. */
+/* e.g. typedef struct { WORD foo; WORD bar} FOOBAR VARARG_GET(ap, FOOBAR); So eliminate */
+/* this unnecessary cast. */
+#ifdef __cplusplus
+ #define __VARARG_GET1(_AP, _TYPE) \
+ ( (_AP).vaold = __bndup((_AP).vanew, DWORD),\
+ (_AP).vanew = (_AP).vaold + sizeof(DWORD), \
+ *(_TYPE *)((_AP).vaold + (sizeof(DWORD)- sizeof(_TYPE))) )
+#else
+ #define __VARARG_GET1(_AP, _TYPE) __VARARG_GET(_AP, DWORD)
+#endif
+
+#define VARARG_GET(_AP,_TYPE) \
+ (sizeof(_TYPE) < sizeof(DWORD) ? (_TYPE) __VARARG_GET1(_AP,_TYPE) : __VARARG_GET(_AP,_TYPE))
+#elif defined(LITTLE_ENDIAN_ORDER)
+#define VARARG_GET(_AP,_TYPE) \
+ ((_AP) += VARARG_ROUND_UP(sizeof(_TYPE),sizeof(int)), \
+ *(_TYPE *)((_AP) - VARARG_ROUND_UP(sizeof(_TYPE),sizeof(int))))
+#else /* BIG_ENDIAN_ORDER */
+#define VARARG_GET(_AP,_TYPE) \
+ ((_AP) += VARARG_ROUND_UP(sizeof(_TYPE),sizeof(int)), \
+ *(_TYPE *)((_AP) - sizeof(_TYPE)))
+#endif
+
+#if defined(HPUX)
+#define VARARG_PEEK(_AP,_TYPE) (*(_TYPE *)((VARARG_PTR)((long)((_AP) \
+ - sizeof(_TYPE)) & TYPE_MASK(_TYPE)) \
+ + ((8 - sizeof(_TYPE)) % 4)))
+#elif defined(NT) && defined(_ALPHA_)
+/* Just like va_arg from stdargs.h, but without the increment of _AP.offset */
+#define VARARG_PEEK(_AP,_TYPE) \
+ (*(_TYPE *)((_AP).a0 + (_AP).offset + (((int)sizeof(_TYPE) + 7) & -8)- \
+ ((__builtin_isfloat(_TYPE) && (_AP).offset <= (6 * 8)) ? \
+ (6 * 8) + 8 : ((int)sizeof(_TYPE) + 7) & -8)))
+#elif defined(OSF)
+
+/* Just like va_arg from stdargs.h, but without the increment of _AP.offset */
+#define VARARG_PEEK(_AP,_TYPE) \
+ (*(_TYPE *)((_AP)._a0 + (_AP)._offset + (((int)sizeof(_TYPE) + 7) & -8)- \
+ ((__builtin_isfloat(_TYPE) && (_AP)._offset <= (6 * 8)) ? \
+ (6 * 8) + 8 : ((int)sizeof(_TYPE) + 7) & -8)))
+
+#elif defined(OS400)
+/* Just like VARARG_GET, but without the increment of _AP.vanew */
+#define VARARG_PEEK(_AP,_TYPE) \
+ (sizeof(_TYPE) < sizeof(DWORD) ? (_TYPE)(*(DWORD *)__bndup((_AP).vanew,DWORD)) : (*(_TYPE *)(__bndup((_AP).vanew,_TYPE))))
+#elif defined(LITTLE_ENDIAN_ORDER)
+#define VARARG_PEEK(_AP,_TYPE) (*(_TYPE *)(_AP))
+#else /* BIG_ENDIAN_ORDER */
+#if defined(MAC)
+#define VARARG_PEEK(_AP,_TYPE) (*(_TYPE *)((_AP) + VARARG_ROUND_UP(sizeof(_TYPE),sizeof(int)) - sizeof(_TYPE)))
+#else
+#ifndef ZLINUX
+#define VARARG_PEEK(_AP,_TYPE) (*(_TYPE *)((CHAR*)(_AP) + VARARG_ROUND_UP(sizeof(_TYPE),sizeof(int)) - sizeof(_TYPE)))
+#endif
+#endif
+#endif
+
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ Platforms that strictly comply to the C standard do not allow passing of
+ variable argument lists by reference using '&' and '*' operators because
+ the standard states that you may get undetermined results. However, you
+ are allowed to pass a variable argument list without these operators. On
+ zLinux, whenever you pass a variable argument list the contents will always
+ be modified upon returning from the function passing it in as a parameter
+ (assuming some function below accesses the list). For these types of
+ platforms, define the following macros to just pass the list without using
+ the '&' operator. All platforms can still use a variable argument list
+ as a pointer by simply using the VARARG_PTR_P type.
+* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+#if defined(ZLINUX)
+typedef VARARG_PTR VARARG_PTR_P;
+#define VARARG_ADDR(_AAP) _AAP
+#define VARARG_DEREF(_AAP) _AAP
+#define VARARG_COPY __va_copy
+#else
+typedef VARARG_PTR * VARARG_PTR_P;
+#define VARARG_ADDR(_AAP) &_AAP
+#define VARARG_DEREF(_AAP) *_AAP
+#define VARARG_COPY(dest, src) (dest)=(src)
+#endif
+
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* Define entry point used by all "SDK" utility programs */
+
+STATUS LNPUBLIC NotesMain (int argc, char far *argv[]);
+
+/* Define routines indirectly (or directly) used by "SDK" utility programs */
+
+STATUS LNPUBLIC NotesInitIni (char far *pConfigFileName);
+STATUS LNPUBLIC NotesInit (void);
+STATUS LNPUBLIC NotesInitExtended (int argc, char far * far *argv);
+void LNPUBLIC NotesTerm (void);
+void LNPUBLIC NotesInitModule (HMODULE far *rethModule, HMODULE far *rethInstance, HMODULE far *rethPrevInstance);
+#ifdef NLM
+typedef void EXPORTED_LIBRARY_PROC(void);
+STATUS LNPUBLIC NotesLibraryMain (int argc, char far * far *argv, EXPORTED_LIBRARY_PROC initproc);
+#endif /* NLM */
+STATUS LNPUBLIC NotesInitThread (void);
+void LNPUBLIC NotesTermThread (void);
+
+#ifdef __cplusplus
+}
+#endif
+
+/* OBSOLETE symbol (used to be used to force bootstrap to be pulled in.
+ Now replaced by explicitly linking with notes0.obj and notesai0.obj). */
+
+#define NotesSDKMainModule
+
+/* Define error code packages */
+
+#include "globerr.h"
+#if defined(NT)
+#define ADMIN_PLATFORM /* Defined for Admin Client platforms */
+#endif
+#if defined (NT) && defined(_X86_)
+#define OLE_HTMLOBJ_PLATFORM
+#endif
+
+
+/* end of global definitions */
+
+#endif /* GLOBAL_DEFS */
+
+#if defined(OS400) && (__OS400_TGTVRM__ >= 510)
+#pragma datamodel(pop)
+#endif
+
diff --git a/protocols/LotusNotify/src/cnotesapi/include/globerr.h b/protocols/LotusNotify/src/cnotesapi/include/globerr.h
new file mode 100644
index 0000000000..07a0d3f895
--- /dev/null
+++ b/protocols/LotusNotify/src/cnotesapi/include/globerr.h
@@ -0,0 +1,443 @@
+
+#if defined(OS400) && (__OS400_TGTVRM__ >= 510)
+#pragma datamodel(P128)
+#endif
+
+/*********************************************************************/
+/* */
+/* Licensed Materials - Property of IBM */
+/* */
+/* L-GHUS-5VMPGW, L-GHUS-5S3PEE */
+/* (C) Copyright IBM Corp. 1989, 2005 All Rights Reserved */
+/* */
+/* US Government Users Restricted Rights - Use, duplication or */
+/* disclosure restricted by GSA ADP Schedule Contract with */
+/* IBM Corp. */
+/* */
+/*********************************************************************/
+
+
+#ifndef GLOBAL_ERROR_DEFS
+#define GLOBAL_ERROR_DEFS
+
+/* Define error code packages */
+
+
+#ifdef NOERROR
+#undef NOERROR
+#endif
+#define NOERROR 0
+
+#define PKG_MAIN 0x0000 /* Codes are limited to 0-63 */
+#define PKG_CCONSOLE 0x0040 /* Codes are limited to 0-31 */
+#define PKG_MAILMISC3 0x0060 /* Mailmisc3 codes starting from 0-31 */
+#define PKG_MINDER 0x0080 /* Minder limit to 0 - 95 */
+#define PKG_SERVER3 0x00E0 /* Codes are limited to 1 - 31 */
+#define PKG_OS 0x0100
+#define PKG_NSF 0x0200
+#define PKG_NIF 0x0300 /* NIF codes are limited to 0 - 127 */
+#define PKG_NSF2 0x0380 /* More NSF codes - limited to 0-127*/
+#define PKG_MISC 0x0400 /* Codes are limited to 0 - 191 */
+#define PKG_SERVER2 0x04C0 /* Codes are limited to 0 - 47 */
+#define PKG_THUNK 0x04F0 /* Codes are limited to 0 - 15 */
+#define PKG_FORMULA 0x0500 /* FORMULA codes are limited to 0-127 */
+#define PKG_NSF8 0x0580 /* AVAILABLE limit to 0 - 127 */
+#define PKG_ODS 0x0600 /* ODS codes, limited to 0-47 */
+#define PKG_LSXUI4 0x0630 /* LotusScript Front-end classes, 0 - 47 */
+#define PKG_AGENTS2 0x0660 /* for agents, limited to 0-31 */
+#define PKG_SCHUI 0x0680 /* Schedule UI codes are limited to 0 - 31 */
+#define PKG_BERT 0x06A0 /* BERT codes are limited to 0 - 31 */
+#define PKG_PLUGINS 0x06C0 /* plugin codes are limited to 0 - 15 */
+
+#define PKG_IMAIL 0x06D0 /* IMAIL Client 0 - 47 */
+
+#define PKG_PKIX 0x0700 /* codes 0 - 95 New CA/PKIX error codes - in pkcs12 dir */
+#define PKG_GT 0x0760 /* GraphTrends error codes 0 - 31 */
+#define PKG_NIF2 0x0780 /* Second nif error package 0-127 */
+#define PKG_CLIENT 0x0800 /* Client codes limited to 0 - 47 */
+#define PKG_LSXUI3 0x0830 /* more LSXUI ERROR codes limited to 0 - 15 */
+#define PKG_APC 0x0840 /* APC codes limited to 0 - 31 */
+#define PKG_DBMISC2 0x0860 /* DBMISC2 codes limited to 0 - 15 */
+#define PKG_TASK_LOADER 0x0870 /* Task Loader package */
+#define PKG_MAILMISC4 0x0880 /* Mail Misc limit to 0 - 127 */
+#define PKG_SERVER 0x0900
+#define PKG_NETWORK 0x0A00 /* If you split this range, fix IS_PKG_NETWORK below */
+#define PKG_WMISC_ERR 0x0B00 /* Codes are limited to 0 - 63 */
+#define PKG_ACTION 0x0B80 /* Codes are limited to 0 - 63 */
+#define PKG_ACTIONPANE 0x0BC0 /* Codes are limited to 0 - 63 */
+#define PKG_EDIT_ERR 0x0C00
+#define PKG_VIEW_ERR 0x0D00
+#define PKG_MAIL 0x0E00 /* MAIL errors are limited to 0-63 */
+#define PKG_BSAFE3 0x0E40 /* Limited to 0-31 */
+#define PKG_BSAFE4 0x0E60 /* Limited to 0-31 */
+#define PKG_CONV 0x0E80 /* CONV errors are limited to 0 - 31 */
+#define PKG_NSF4 0x0EA0 /* NSF4 errors are limited to 0 - 31 */
+#define PKG_FRAMDES 0x0EC0 /* Frame design errors limited to 0 - 31 */
+#define PKG_NETWORK3 0x0EE0 /* AVAILABLE codes are limited to 0 - 31 */
+#define PKG_FT 0x0F00 /* FT errors are limited to 0 - 63 */
+#define PKG_BSAFE5 0x0F40 /* Limited to 0-15 */
+#define PKG_DBMISC 0x0F50 /* 0 - 47 */
+#define PKG_NETWORK2 0x0F80 /* 0 - 127, if this changes, fix IS_PKG_NETWORK below */
+#define PKG_DEBUG 0x1000 /* Debug strings, like for DDE, limited to 0 - 79 */
+#define PKG_SSL 0x1040 /* SSL errors 0 - 15 */
+#define PKG_SERVER4 0x1050 /* SERVER4, limited to 0 - 15 */
+#define PKG_BOOKMARK 0x1060 /* BOOKMARK, limited to 0 - 15 */
+#define PKG_NSF5 0x1070 /* NSF5, limited to 0 - 15 */
+#define PKG_NEM_ERR 0x1080 /* NEM, limited to 0 - 127 */
+#define PKG_ROUTER 0x1100 /* Errors returned by ROUTERL, 0 - 79 */
+#define PKG_MAILMAN 0x1150 /* Errors returned by MAILMAN, 0 - 95 */
+#define PKG_LSBE 0x11b0 /* LSXBE errors, 0 - 47 */
+#define PKG_LSDO 0x11e0 /* LSDOE errors, 0 - 15 */
+#define PKG_LSXDB2 0x11f0 /* LSXDB2 errors, 0 - 15 */
+#define PKG_REG2 0x1200 /* REG2 errors, 0 - 127 */
+#define PKG_LSIDE 0x1280 /* ide specific errors 0 - 95 */
+#define PKG_HTML 0x12D0 /* html parser errors, 0 - 31 */
+#define PKG_SERVER5 0x12F0 /* PKG_SERVER5 limit to 0 - 15 */
+#define PKG_LOG 0x1300
+#define PKG_NSF3 0x1380 /* More NSF codes - limited to 0-127*/
+#define PKG_XPC 0x1400
+#define PKG_EVENT 0x1500 /* Event codes starting from 0-47 */
+#define PKG_FIDE 0x1530 /* Event codes starting from 0-31 */
+#define PKG_NETWORK4 0x1550 /* Limited to 0 - 15, if this changes, fix IS_PKG_NETWORK below */
+#define PKG_MAILMISC2 0x1560 /* Mailmisc2 codes starting from 0-31 */
+#define PKG_BCASE 0x1580 /* Briefcase codes are limited to 0 - 95 */
+#define PKG_SECURE2 0x15E0 /* Secure2 limit to 0 - 15 */
+#define PKG_BSAFE6 0x15F0 /* Bsafe codes are limited to 0 - 15 */
+#define PKG_REPL 0x1600 /* Errors returned by REPLSUB library, limited to 0 - 199 */
+#define PKG_ADMIN_ERR2 0x16C8 /* PKG_ADMIN_ERR2 limited to 0 - 55 */
+#define PKG_BSAFE 0x1700 /* BSAFE codes are limited to 0 - 151 */
+#define PKG_SERVER7 0x1798 /* PKG_SERVER7 limit to 0 - 103 */
+#define PKG_DESK_ERR 0x1800
+#define PKG_SECURE 0x1900
+#define PKG_AGENT 0x1A00 /* AGENT codes are limited to 0-63 */
+#define PKG_CCONSOLE2 0x1A50 /* CCONSOLE2 codes are limited to 0-15 */
+#define PKG_PLAT_STAT_ERR 0x1A60 /* Platform Statistics error package */
+#define PKG_AGENT1 0x1A70 /* AGENT1 codes are limited to 0-15 */
+#define PKG_AGENTS3 0x1A80 /* AGENTS3 codes are limited to 0-47 */
+#define PKG_AGENT2 0x1AB0 /* AGENT2 codes are limited to 0-79 */
+#define PKG_XML 0x1B00 /* XML codes: limit to 0 - 255 */
+#define PKG_NETDRV 0x1C00 /* If this PKG space is split, fix IS_PKG_NETWORK below */
+#define PKG_IMPORT 0x1D00 /* Used for all imports - see IMPKG_xxx below */
+#define PKG_EXPORT 0x1E00 /* Used for all exports - see EXPKG_xxx below */
+#define PKG_LSXUI2 0x1F00 /* LSXUI2 Codes are limited to 0 - 63 */
+#define PKG_REG 0x2000
+
+/* Following 8 groups used for native OS error codes, mapped by OSMapError
+ and translated by OSLoadString. These give better feedback in certain
+ cases, but should NEVER be interpreted if STS_REMOTE bit is set,
+ indicating that another OS on server might have generated the error! */
+
+#define PKG_NATIVE_FIRST 0x2100
+#define PKG_NATIVE_LAST 0x28FF
+
+#ifdef OS2
+#define PKG_OS2_BASE 0x2100 /* + status - 0x0000 (BSEERR base) */
+#define PKG_OS2_BASE2 0x2200 /* (BSEERR continued) */
+#define PKG_OS2_LANMAN 0x2300 /* + status - 0x0834=2100 (LANMAN base) */
+#define PKG_OS2_LANMAN2 0x2400 /* (LANMAN continued) */
+#define PKG_OS2_PMWIN 0x2500 /* + status - 0x1000 (PMWIN base) */
+#define PKG_OS2_PMGPI 0x2600 /* + status - 0x2000 (PMGPI base) */
+#define PKG_OS2_PMGPI2 0x2700 /* (GPI continued) */
+#define PKG_OS2_PMSPL 0x2800 /* + status - 0x4000 (PMSPL base) */
+#endif
+
+#define PKG_NSE 0x2900 /* Network script engine */
+#define PKG_NSF6 0x29B0 /* NSF6, limited to 0 - 15 */
+#define PKG_PERFSTAT 0x29C0 /* PERFSTAT error codes 0-31 */
+#define PKG_MISC2 0x29E0 /* MISC2 limit to 0 - 31 */
+#define PKG_NETDRVLCL 0x2A00 /* Used for all Network Drivers, if PKG space is split, fix IS_PKG_NETWORK below */
+#define PKG_NTI 0x2B00 /* Used for NTI and its new Net drivers */
+
+#define PKG_VIEWMAP 0x2C00 /* for ViewMap */
+#define PKG_BSAFE2 0x2CF0 /* for BSAFE x509 routines */
+
+#define PKG_REPL2 0x2D00 /* for remote debug 0-127 */
+#define PKG_RDBGERR 0x2D80 /* for remote debug err messages 0-127 */
+
+#define PKG_AGENTS 0x2E00 /* for agents, limit to 0 - 127 */
+#define PKG_DESK_ERR2 0x2E80 /* more Desk limit to 0 - 127 */
+#define PKG_LSCRIPT 0x2F00 /* LotusScript Interface, limit 0-127 */
+#define PKG_LSXUI 0x2F80 /* LotusScript Front-end classes, 0-127 */
+#define PKG_DSGN 0x3000 /* Database design package, 0-63 */
+#define PKG_SERVER6 0x3040 /* PKG_SERVER6 error codes 0 - 63 */
+#define PKG_ADMIN_ERR 0x3080 /* Admin facility, 0 - 127 */
+#define PKG_DBD 0x3100 /* database driver error codes, 0 - 199 */
+#define PKG_COMPILER7 0x31B8 /* More COMPILER codes, limited to 0-15 */
+#define PKG_NEWS 0x31C8 /* News classes, 0 - 15 */
+#define PKG_IMAIL_EXT 0x31D8 /* IMail database extensions 0 - 23 */
+#define PKG_DAEMON 0x31F0 /* CDaemon codes, 0 - 15 */
+#define PKG_COMPILER8 0x3200 /* More COMPILER codes, limit to 0 - 255 */
+#define PKG_ADDIN 0x3300 /* For use by mail gateways, etc. */
+#define PKG_EDIT_ERR2 0x3400 /* need additional block for edit */
+#define PKG_LSCRIPT2 0x3500 /* Lotusscript interface, limit 0 - 127 */
+#define PKG_ADMIN_ERR3 0x3580 /* PKG_ADMIN_ERR3 limited to 0 - 55 */
+#define PKG_DSGN2 0x35C0 /* PKG_DSGN2 limit to 0 - 63 */
+#define PKG_GRMISC 0x3600 /* Graphics Library 0-31 */
+#define PKG_VIMSMI 0x3620 /* VIM and SMI block codes 0-10 */
+#define PKG_WEB 0x3640 /* InterNotes client extensions 0-191 */
+#define PKG_ADDIN2 0x3700 /* For extensions to PKG_ADDIN */
+#define PKG_NSF9 0x3800 /* NSF9, limited to 0 - 255 */
+#define PKG_DESK_ERR4 0x3900 /* DESK error, limit to 0 - 127 */
+#define PKG_ORB 0x3980 /* ORB, limit to 0 - 63 */
+#define PKG_LSXUI5 0x39C0 /* LSXUI5 Codes are limited to 0 - 63 */
+#define PKG_HTTP 0x3A00 /* Web Server. limit to 0 - 199 */
+#define PKG_POP3 0x3AC8 /* POP3. 0 - 19 */
+#define PKG_MAILMISC 0x3ADC /* Mailmisc. 0 - 3 */
+#define PKG_SMTP 0x3AE0 /* SMTP. 0 - 7 */
+#define PKG_POP3C 0x3AE8 /* POP3 CLIENT. 0-2 */
+#define PKG_SMTPC 0x3AEB /* SMTP. 0 - 6 */
+#define PKG_MAILMISC1 0x3AF2 /* MAILMISC. 0 - 13 */
+#define PKG_DB2NSF 0x3B00 /* DB2NSF stuff */
+#define PKG_SMARTI 0x3C00 /* To make smart icon res unique */
+#define PKG_TOOLBAR PKG_SMARTI /* R6 Reuse smarticon pkg for new toolbars */
+#define PKG_OLE_ERR 0x3D00 /* OLE error codes 0-63*/
+ /* Note, PKG_OLE_ERR+0-53 were used in V3 */
+#define PKG_MISC3 0x3D40 /* PKG_MISC3 codes are limited to 0-31 */
+#define PKG_NSF7 0x3D60 /* PKG_NSF7 codes are limited to 0-31 */
+#define PKG_NETWORK5 0x3D80 /* Limited to 0-31, if this area changes, fix IS_PKG_NETWORK below */
+#define PKG_DESK_ERR3 0x3DA0 /* PKG_DESK_ERR3 are limited to 0-63 */
+#define PKG_EVENT2 0x3DE0 /* Event codes starting from 0-31 */
+/* #define PKG_OLE_CMD 0x3E00 OLE Api Command Descriptions - OBSOLETE in V5 */
+ /* Note, PKG_OLE_CMD+0-56 were used in V3 */
+#define PKG_JAVAWRAP 0x3E00 /* javawrap error codes 0-63 */
+#define PKG_ASSISTANT_ERR 0x3E40 /* Assistant codes limit to 0 - 63 */
+#define PKG_JSWRAP 0x3E80 /* javascript wrap error codes 0-63 */
+#define PKG_PRINT_ERR 0x3EC0 /* client print error codes limit to 0 - 63 */
+#define PKG_EDIT_ERR3 0x3F00 /* More editor codes */
+/* 3F00 IS THE LAST PACKAGE THAT CAN BE DEFINED FOR ERROR CODES!
+ * (LOOK FOR HOLES ABOVE). THE RANGE 0x4000-0x7FFF CANNOT BE USED.
+ */
+
+
+#define PKG_CODES 255
+
+
+/* Define offsets within PKG_NETDRVLCL for local network drivers */
+
+/* On the Unix, since tcp is compiled into Notes, their strings must have
+ unique IDs. We define a separate package for all drivers which are optional
+ and each optional driver package will have its own offsets for first string
+ as defined below. There is some room for expansion, but people adding
+ strings should be aware of the extent of their allocated ID space, and
+ change it here if necessary, afterwards recompiling all dependent drivers.
+ Under Windows and PM, since each ixport is a separate DLL with separate DS
+ space, all offsets are set to 0.
+*/
+
+#if defined(UNIX) || defined(MAC)
+
+#define NETPKG_TCP 0 /* Leave at least 20 string offsets for TCP */
+#define NETPKG_ATALK 20 /* Leave 35 codes for AppleTalk */
+#define NETPKG_NWSPX 55
+
+#else
+#define NETPKG_TCP 0
+#define NETPKG_ATALK 0
+#define NETPKG_NWSPX 0
+#define NETPKG_NETBIOS 0
+#endif
+
+
+/* Define offsets within PKG_IMPORT and PKG_EXPORT for import/exports */
+
+/* On the Mac, since all ixports are compiled into Notes, their strings must have unique IDs.
+ We avoid using a separate PKG for each by defining the offset of each ixport's first string below.
+ There is some room for expansion, but people adding strings should be aware of the extent
+ of their allocated ID space, and change it here if necessary, afterwards recompiling all
+ dependent ixports!
+ Under Windows and PM, since each ixport is a separate DLL with separate DS space,
+ all offsets are set to 0.
+ Since TARGA, W4W and WMF are not to be ported to the Mac, we don't currently bother with
+ defining offsets for them.
+*/
+
+#if defined(MAC) || defined(UNIX) /* On Mac & UNIX, we need to subdivide */
+
+#define IMPKG_IFL 0
+#define IMPKG_IPCX 50
+#define IMPKG_IPIC 60
+#define IMPKG_IRTF 70
+#define IMPKG_ISTF 80
+#define IMPKG_ISTR 90
+#define IMPKG_ITAB 100
+#define IMPKG_ITEXT 135
+#define IMPKG_ITIFF 145
+#define IMPKG_IWKSE 160
+#define IMPKG_IWKSV 180
+#define IMPKG_ALL 212 /* 18 common strings shared by all Iris IX modules */
+#define IMPKG_IBMP 230
+#define IMPKG_IGIF 235
+#define IMPKG_IW4W 240
+#define IMPKG_ISTRNGS 250
+#define IMPKG_IJPEG 252
+
+#define EXPKG_XCGM 0
+#define EXPKG_XRTF 10
+#define EXPKG_XSTF 20
+#define EXPKG_XSTR 65
+#define EXPKG_XTAB 90
+#define EXPKG_XTEXT 100
+#define EXPKG_XTIFF 110
+#define EXPKG_XWKS 120
+#define EXPKG_ALL 130 /* 20 common strings shared by all Iris IX modules */
+#define EXPKG_XW4W 150
+#define EXPKG_XVCRD 170
+#define EXPKG_XVCRD3 180
+#define EXPKG_XCSV 200
+
+#else /* PC versions - On PC, we don't subdivide - each has own DLL! */
+
+#define IMPKG_IFL 0
+#define IMPKG_IPCX 0
+#define IMPKG_IPIC 0
+#define IMPKG_IRTF 0
+#define IMPKG_ISTF 0
+#define IMPKG_ISTR 0
+#define IMPKG_ITAB 0
+#define IMPKG_ITARGA 0
+#define IMPKG_ITEXT 0
+#define IMPKG_ITIFF 0
+#define IMPKG_IWKSE 0
+#define IMPKG_IWKSV 0
+#define IMPKG_IWMF 0
+#define IMPKG_IBMP 0
+#define IMPKG_IGIF 0
+#define IMPKG_IW4W 0
+#define IMPKG_ISTRNGS 0
+#define IMPKG_IJPEG 0
+#define IMPKG_ALL 32 /* 18 common strings shared by all Iris IX modules */
+ /* (Reserve 0-32 for IX-specific strings) */
+
+#define EXPKG_XCGM 0
+#define EXPKG_XCSV 0
+#define EXPKG_XRTF 0
+#define EXPKG_XSTF 0
+#define EXPKG_XSTR 0
+#define EXPKG_XTAB 0
+#define EXPKG_XTEXT 0
+#define EXPKG_XTIFF 0
+#define EXPKG_XVCRD 0
+#define EXPKG_XVCRD3 0
+#define EXPKG_XW4W 0
+#define EXPKG_XWKS 0
+#define EXPKG_ALL 50 /* 20 common strings shared by all Iris IX modules */
+ /* (Reserve 0-50 for IX-specific strings) */
+
+#endif
+
+
+
+/* Define error code status flags. The top two bits of the error code
+ are reserved for this purpose */
+
+#define STS_DISPLAYED ((STATUS) 0x8000) /* error has already been displayed */
+#define ERROR_DISPLAYED(x) ((x) & STS_DISPLAYED)
+
+#define STS_REMOTE ((STATUS) 0x4000) /* error came from remote machine */
+#define ERROR_REMOTE(x) ((x) & STS_REMOTE)
+
+#define RAWBLK(x) ((STATUS) ((x)&~(STS_DISPLAYED|STS_REMOTE)))
+#define NOBLK(x) ((STATUS) ((x)&(STS_DISPLAYED|STS_REMOTE)))
+
+#define ERR_MASK 0x3fff
+#define PKG_MASK 0x3f00
+#define ERRNUM_MASK 0x00ff
+
+#define STRING_MASK 0x8000
+
+#define IS_STRING(x) ((x)&STRING_MASK ? TRUE : FALSE) /* is this code a string code? */
+
+/* Remove the DISPLAYED bit - use when logging errors to avoid overlap with string IDs that now (R6+) include the STS_DISPLAYED bit */
+#define ND(x) ((STATUS) ((x) & ~STS_DISPLAYED))
+
+#define ERR(x) ((STATUS) ((x) & ERR_MASK)) /* Use when comparing errors to a constant - if (ERR(error) == ERR_QUIT) */
+#define ERRNUM(x) ((STATUS) ((x) & ERRNUM_MASK)) /* Just the error number, no flags or pkg code. Doesn't work with new PKG codes */
+
+#define PKG(x) ((STATUS) ((x) & PKG_MASK)) /* Get the package code for errors only - obsolete given new pkg codes */
+#define IS_PKG(x,pkg) ((BOOL)(((PKG_MASK | pkg) & x) == pkg)) /* Is error x in PKG pkg? */
+
+/* Define memory allocator hints, which re-use the top 2 bits of
+ the BLK_ codes so that we didn't have to add a new argument to
+ OSMemAlloc() */
+
+#define MEM_SHARE ((WORD) 0x8000) /* Object may be used by multiple processes */
+#define MEM_GROWABLE ((WORD) 0x4000) /* Object may be OSMemRealloc'ed LARGER */
+
+
+/* Define macros which are used when defining error codes to provide text
+ for each error message. The macro normally generates nothing when
+ compiled by the C compiler, but will be defined to generate text when
+ used in the resource (.RC) file. (See also prestr.h.) */
+
+/* "errortext" designates a user-displayed message (success, error, warning).
+ This are translated, and may be shown to a user. There should be
+ online help for most of these messages. */
+
+#define errortext(code,text)
+
+/* "helptext" designates the "Menu Help" messages displayed on the top
+ line of the screen when you drag across a menu item. There is usually
+ also further online help associated with each of these menu items. */
+
+#define helptext(helpid,code,text)
+
+/* "stringtext" designates translatable text fragments that need to be
+ translated, but are not shown to the user as a "message" (error,
+ warning or otherwise). There should be no online help for these. */
+
+#define stringtext(code,text)
+
+/* "apitext" designates API-only messages. This could be translated
+ (for foreign API programmers) but NEVER shown to a user. */
+
+#define apitext(code,text)
+
+/* "debugtext" designates DEBUG-only messages. This is not to be
+ translated and never shown to a user. */
+
+#define debugtext(code,text)
+
+/* "internaltext" designates STATUS codes used to indicate a condition
+ passed between 2 subsystems, but NEVER displayed to a user. The text
+ associated with "internaltext" is NOT EVEN STORED in the executables,
+ and thus, never translated or shown to a user. */
+
+#define internaltext(code,text)
+
+/* "blocktext" designates DEBUG-only descriptions of internal storage
+ allocation types. This is not to be translated and never shown to a user. */
+
+#define blocktext(code,text)
+
+/* "semtext" designates DEBUG-only descriptions of internal semaphore
+ types. This is not to be translated and never shown to a user. */
+
+#define semtext(code,text)
+
+/* "donottranslatetext" designates text which must not be translated.
+ This text may be included in a resource file in order to facilitate
+ configuration changes, such as a string which controls program behavior.
+ Or it may be included in order to clearly indicate that the developer
+ intends for the text to remain untranslated.
+*/
+
+#define donottranslatetext(code,text)
+
+/* "limitedasciitext" designates text which is constrained to a limited
+ subset of ASCII characters. One use of this macro is for strings used as
+ part of Internet protocols which do not allow for non-ascii text.
+ The exact limitations will vary with usage, but will usually be
+ restricted to 7-bit ascii, excluding '\0'. These strings MAY be
+ translated to other languages, but must keep within the limited ascii
+ characters allowed. For example, translation into French is permitted,
+ but no accented characters may be used.
+*/
+#define limitedasciitext(code,text)
+
+#endif
+
+
+#if defined(OS400) && (__OS400_TGTVRM__ >= 510)
+#pragma datamodel(pop)
+#endif
+
diff --git a/protocols/LotusNotify/src/cnotesapi/include/misc.h b/protocols/LotusNotify/src/cnotesapi/include/misc.h
new file mode 100644
index 0000000000..2b6677ceb9
--- /dev/null
+++ b/protocols/LotusNotify/src/cnotesapi/include/misc.h
@@ -0,0 +1,413 @@
+
+#if defined(OS400) && (__OS400_TGTVRM__ >= 510)
+#pragma datamodel(P128)
+#endif
+
+/*********************************************************************/
+/* */
+/* Licensed Materials - Property of IBM */
+/* */
+/* L-GHUS-5RWNHM, L-GHUS-5RWNFH */
+/* (C) Copyright IBM Corp. 1989, 2005 All Rights Reserved */
+/* */
+/* US Government Users Restricted Rights - Use, duplication or */
+/* disclosure restricted by GSA ADP Schedule Contract with */
+/* IBM Corp. */
+/* */
+/*********************************************************************/
+
+
+
+/* Miscellaneous Package Global Definitions */
+
+#ifndef MISC_DEFS
+#define MISC_DEFS
+
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+
+/* Some useful constants */
+
+#define MAXALPHANUMBER 40
+#define MAXALPHATIMEDATE 80
+#define MAXALPHATIMEDATEPAIR (80 * 2 + 3)
+#define MAXSPRINTF 256
+#define MAXSOUNDEX (4+1) /* 4 chars plus null terminator */
+
+/* Flags for IntlTextCompare */
+
+#define INTL_ACCENT_SENSITIVE 0x00000001
+#define INTL_CASE_SENSITIVE 0x00000002
+
+
+/* time structure - NOTE: These fields MUST BE int's, NOT UNSIGNEDS! */
+
+typedef struct {
+ int year; /* 1-32767 */
+ int month; /* 1-12 */
+ int day; /* 1-31 */
+ int weekday; /* 1-7, Sunday is 1 */
+ int hour; /* 0-23 */
+ int minute; /* 0-59 */
+ int second; /* 0-59 */
+ int hundredth; /* 0-99 */
+ int dst; /* FALSE or TRUE */
+ int zone; /* -11 to +11 */
+ TIMEDATE GM;
+} TIME;
+
+/* Special encodings for TIMEDATE fields. Note that these are all in
+ HOST-SPECIFIC format, and must be used with TimeConstruct or
+ TimeExtractJulianDate or TimeExtractTicks! */
+
+#define ALLDAY 0xffffffffL /* put this in the TIME field */
+#define ANYDAY 0xffffffffL /* put this in the DATE field */
+#define TICKS_IN_DAY 8640000L /* 10msec ticks in a day */
+#define TICKS_IN_HOUR 360000L /* 10msec ticks in an hour */
+#define TICKS_IN_MINUTE 6000L /* 10msec ticks in a minute */
+#define TICKS_IN_SECOND 100L /* 10msec ticks in a second */
+#define SECS_IN_DAY 86400L /* seconds in a day */
+#define SECS_IN_WEEK 604800L /* seconds in a week */
+#define SECS_IN_MONTH 2592000L /* seconds in a month (30 days) */
+
+
+/* DTFlags values (do not change - these values are also stored on disk!) */
+
+#define DT_VALID 0x8000 /* Validity bit: If 1, use new DTFMT; if 0, use old TFMT */
+#define DT_4DIGITYEAR 0x0001 /* Require 4 digit year on INPUT (not output) */
+#define DT_ALPHAMONTH 0x0002 /* Require months be INPUT as letters, not digits (e.g. "jan", not 01) */
+#define DT_SHOWTIME 0x0004 /* Display time element on output */
+#define DT_SHOWDATE 0x0008 /* Display date element on output */
+#define DT_24HOUR 0x0040 /* Display time on output using 24 hour clock format */
+#define DT_STYLE_YMD 1 /* Date element order: Year, Month, Day, Day-of-week */
+#define DT_STYLE_MDY 2 /* Date element order: Day-of-week, Month, Day, Year */
+#define DT_STYLE_DMY 3 /* Date element order: Day-of-week, Day, Month, Year */
+#define DT_STYLE_MSK 0x000f0000 /* This is where we store the style value in DTFlags */
+#define DT_GET_STYLE(dwflag) ((dwflag & DT_STYLE_MSK) >> 0x10) /* Macro to retrieve the style value from DTFlags */
+#define DT_SET_STYLE(dwflag, style) (dwflag = ((dwflag & 0xfff0ffff) | (style << 0x10))) /* Macro to store the style value in DTFlags */
+
+/* DTFlags2 values (do not change - these values are also stored on disk!) */
+
+#define DT_USE_TFMT 0x0001 /* Use the 4.X format structure instead of this 5.X format structure */
+
+
+/* DTYearFmt values (do not change - these values are also stored on disk!) */
+
+#define DT_YFMT_YY 1 /* 2 digit year */
+#define DT_YFMT_YYYY 2 /* 4 digit year */
+/* The following DTYearFmt values are valid only for Imperial calendars */
+#define DT_YFMT_GE 3 /* Single letter (first letter ) of epoch name and 1 or 2 digit (no leading zeros) year */
+#define DT_YFMT_GEE 4 /* Single letter (first letter ) of epoch name and 2 digit (with leading zeros, if necessary) year */
+#define DT_YFMT_GGE 5
+#define DT_YFMT_GGEE 6 /* Abbreviated spelling and 2 digit (with leading zeros, if necessary) year */
+#define DT_YFMT_GGGE 7
+#define DT_YFMT_GGGEE 8 /* fully spelled out epoch name and 2 digit (with leading zeros, if necessary) year */
+
+/* DTDOWFmt values (Day-Of-Week) (do not change - these values are also stored on disk!) */
+
+#define DT_WFMT_WWW 1
+#define DT_WFMT_WWWW 2
+#define DT_WFMT_WWWP 3 /* 3 letter abbreviation inside parenthesis */
+#define DT_WFMT_WWWWP 4 /* Spelled out fully inside parenthesis */
+
+/* DTMonthFmt values (do not change - these values are also stored on disk!) */
+
+#define DT_MFMT_M 1
+#define DT_MFMT_MM 2
+#define DT_MFMT_MMM 3
+#define DT_MFMT_MMMM 4
+
+/* DTDayFmt values (do not change - these values are also stored on disk!) */
+
+#define DT_DFMT_D 1
+#define DT_DFMT_DD 2
+
+/* DTDShow values (controls what is shown on OUTPUT for date) */
+/* (do not change - these values are also stored on disk!) */
+
+#define DT_DSHOW_ALL 1
+#define DT_DSHOW_YM 2
+#define DT_DSHOW_WMD 3
+#define DT_DSHOW_W 4
+#define DT_DSHOW_M 5
+#define DT_DSHOW_MD 6
+#define DT_DSHOW_MDY 7
+#define DT_DSHOW_D 8
+#define DT_DSHOW_Y 9
+
+/* DTDSpecial bit values: Special handling of date OUTPUT */
+/* (do not change - these values are also stored on disk!) */
+
+#define DT_DSPEC_NONE 0 /* No special handling */
+#define DT_DSPEC_TODAY 0x0001 /* Use 'Today', 'Yesterday', 'Tomorrow', when possible */
+#define DT_DSPEC_Y4 0x0002 /* Always display year on OUTPUT as 4 digit year */
+#define DT_DSPEC_21Y4 0x0004 /* Output 2 digit year for this century; use 4 digit year for other century */
+#define DT_DSPEC_CURYR 0x0008 /* Display year when not the current year */
+
+/* DTTShow values (controls what to shown on OUTPUT for time) */
+/* (do not change - these values are also stored on disk!) */
+
+#define DT_TSHOW_H 1
+#define DT_TSHOW_HM 2
+#define DT_TSHOW_HMS 3
+#define DT_TSHOW_ALL 4
+
+/* Values for FTFMT "Preferences" field (do not change - these values are also stored on disk!) */
+
+#define NPREF_CLIENT 0 /* Get preferences from the client */
+#define NPREF_FIELD 1 /* Get preferences fromt the form or view */
+
+/* Date/Time formatting data */
+
+typedef struct {
+ BYTE Preferences; /* NPREF_xxx. Get preferences from the Client or from the Form/View? */
+ DWORD DTFlags;
+ DWORD DTFlags2; /* In case we need more room */
+ BYTE DTDOWFmt; /* Day-of-week format choice */
+ BYTE DTYearFmt; /* Year format choice */
+ BYTE DTMonthFmt; /* Month format choice */
+ BYTE DTDayFmt; /* Day format choice */
+ BYTE DTDShow; /* Date display choice */
+ BYTE DTTShow; /* Time display choice */
+ BYTE DTDSpecial; /* Date special display choice */
+ BYTE DTTZone; /* Time zone display choice */
+ char* DTDsep1; /* Date field separator string #1 */
+ char* DTDsep2; /* Date field separator string #2 */
+ char* DTDsep3; /* Date field separator string #3 */
+ char* DTTsep; /* Time field separator string */
+} DTFMT;
+
+
+/* Currency flags */
+
+#define NCURFMT_SYMFOLLOWS 0x0001 /* The currency symbol follows the value */
+#define NCURFMT_USESPACES 0x0002 /* Inset space between symbol and value */
+#define NCURFMT_ISOSYMUSED 0x0004 /* Using 3 letter ISO for currency symbol */
+
+/* Currency selection values */
+
+#define NCURFMT_COMMON 0
+#define NCURFMT_CUSTOM 1
+
+/* Number Format */
+
+#define NFMT_GENERAL 0 /* Number Formats */
+#define NFMT_FIXED 1
+#define NFMT_SCIENTIFIC 2
+#define NFMT_CURRENCY 3
+
+#define NATTR_PUNCTUATED 0x0001 /* Number Attributes */
+#define NATTR_PARENS 0x0002
+#define NATTR_PERCENT 0x0004
+#define NATTR_VARYING 0x0008
+
+typedef struct {
+ BYTE Digits; /* Number of decimal digits */
+ BYTE Format; /* Display Format */
+ BYTE Attributes; /* Display Attributes */
+ BYTE Unused;
+} NFMT;
+
+/* Time Format */
+
+#define TDFMT_FULL 0 /* year, month, and day */
+#define TDFMT_CPARTIAL 1 /* month and day, year if not this year */
+#define TDFMT_PARTIAL 2 /* month and day */
+#define TDFMT_DPARTIAL 3 /* year and month */
+#define TDFMT_FULL4 4 /* year(4digit), month, and day */
+#define TDFMT_CPARTIAL4 5 /* month and day, year(4digit) if not this year */
+#define TDFMT_DPARTIAL4 6 /* year(4digit) and month */
+#define TTFMT_FULL 0 /* hour, minute, and second */
+#define TTFMT_PARTIAL 1 /* hour and minute */
+#define TTFMT_HOUR 2 /* hour */
+#define TZFMT_NEVER 0 /* all times converted to THIS zone */
+#define TZFMT_SOMETIMES 1 /* show only when outside this zone */
+#define TZFMT_ALWAYS 2 /* show on all times, regardless */
+
+#define TSFMT_DATE 0 /* DATE */
+#define TSFMT_TIME 1 /* TIME */
+#define TSFMT_DATETIME 2 /* DATE TIME */
+#define TSFMT_CDATETIME 3 /* DATE TIME or TIME Today or TIME Yesterday */
+
+typedef struct {
+ BYTE Date; /* Date Display Format */
+ BYTE Time; /* Time Display Format */
+ BYTE Zone; /* Time Zone Display Format */
+ BYTE Structure; /* Overall Date/Time Structure */
+} TFMT;
+
+typedef MEMHANDLE INTLTIMEDATEHANDLE;
+
+/*
+ * Property values to set for converting an extended International TIMEDATE value.
+ */
+typedef enum
+{
+ AMStringProperty = 1,
+ PMStringProperty = 2
+} INTL_TIMEDATE_PROPERTY;
+
+
+/* function templates */
+
+BOOL LNPUBLIC TimeLocalToGM (TIME far *Time);
+BOOL LNPUBLIC TimeGMToLocal (TIME far *Time);
+BOOL LNPUBLIC TimeGMToLocalZone (TIME far *Time);
+int LNPUBLIC TimeDateCompare (const TIMEDATE far *t1, const TIMEDATE far *t2);
+int LNPUBLIC TimeDateCollate (const TIMEDATE far *t1, const TIMEDATE far *t2);
+DWORD LNPUBLIC TimeExtractJulianDate (const TIMEDATE far *);
+DWORD LNPUBLIC TimeExtractDate (const TIMEDATE far *);
+DWORD LNPUBLIC TimeExtractTicks (const TIMEDATE far *);
+void LNPUBLIC TimeExtractLocal (const TIMEDATE far *Time, BOOL fTime, TIMEDATE far *retTime);
+void LNPUBLIC TimeConstruct (DWORD Date, DWORD Time, TIMEDATE far *result);
+
+
+#define TIMEDATE_MINIMUM 0
+#define TIMEDATE_MAXIMUM 1
+#define TIMEDATE_WILDCARD 2
+void LNPUBLIC TimeConstant(WORD, TIMEDATE far *);
+
+#define TimeDateEqual(a,b) ((BOOL)TimeDateCollate(a,b)==0)
+#define TimeDateClear(a) (TimeConstant(TIMEDATE_MINIMUM, a))
+STATUS LNPUBLIC TimeDateIncrement (TIMEDATE far *Time, LONG Interval);
+LONG LNPUBLIC TimeDateDifference (const TIMEDATE far *t1, const TIMEDATE far *t2);
+void LNPUBLIC TimeDateDifferenceFloat (const TIMEDATE far *t1,
+ const TIMEDATE far *t2, NUMBER far *difference);
+BOOL LNPUBLIC TimeDateAdjust (TIMEDATE far *Time, int seconds, int minutes, int hours, int days, int months, int years);
+int LNPUBLIC IntlTextCompare(const void far *Str1, WORD Str1Len,
+ const void far *Str2, WORD Str2Len, DWORD Flags);
+STATUS LNPUBLIC ConvertTextToTIMEDATE (const void far *IntlFormat,
+ const TFMT far *TextFormat,
+ char far * far *Text,
+ WORD MaxLength,
+ TIMEDATE far *retTIMEDATE);
+/*
+ * Functions to allow TIMEDATE conversion on extended International Timedates.
+ */
+STATUS LNPUBLIC IntlTIMEDATECreateHandle(INTLTIMEDATEHANDLE *hTimeDateHandle);
+void LNPUBLIC IntlTIMEDATEDeleteHandle(INTLTIMEDATEHANDLE hTimeDateHandle);
+STATUS LNPUBLIC IntlTIMEDATESetValue(INTLTIMEDATEHANDLE hTimeDateHandle, INTL_TIMEDATE_PROPERTY prop, void *propValue);
+STATUS LNPUBLIC IntlTIMEDATEGetValue(INTLTIMEDATEHANDLE hTimeDateHandle, INTL_TIMEDATE_PROPERTY prop, WORD valueLen, void *retpropValue);
+STATUS LNPUBLIC IntlTIMEDATEConvertToText (INTLTIMEDATEHANDLE hTimeDateHandle, const void far *IntlFormat,
+ const DTFMT *ExtTextFormat, WORD DTFMTLen,
+ const TIMEDATE *InputTime, WORD TextBufferLength,
+ char *retTextBuffer, WORD *retTextLength);
+STATUS LNPUBLIC ConvertTextToTIMEDATEPAIR (const void far *IntlFormat,
+ const TFMT far *TextFormat,
+ char far * far *Text,
+ WORD MaxLength,
+ TIMEDATE_PAIR far *retTIMEDATE);
+STATUS LNPUBLIC ConvertTIMEDATEToText (const void far *IntlFormat,
+ const TFMT far *TextFormat,
+ const TIMEDATE far *InputTime,
+ char far *retTextBuffer,
+ WORD TextBufferLength,
+ WORD far *retTextLength);
+STATUS LNPUBLIC ConvertTIMEDATEPAIRToText (const void far *IntlFormat,
+ const TFMT far *TextFormat,
+ const TIMEDATE_PAIR far *InputTime,
+ char far *retTextBuffer,
+ WORD TextBufferLength,
+ WORD far *retTextLength);
+STATUS LNPUBLIC ConvertTextToFLOAT (const void far *IntlFormat,
+ const NFMT far *NumberFormat,
+ char far * far *ppInputText,
+ WORD InputTextMaxLength,
+ NUMBER far *retNumber);
+STATUS LNPUBLIC ConvertFLOATToText (const void far *IntlFormat,
+ const NFMT far *NumberFormat,
+ NUMBER far *Number,
+ char far *retTextBuffer,
+ WORD TextBufferLength,
+ WORD far *retTextLength);
+void LNPUBLIC Soundex (const char far *String, WORD StringLength, char far *retSoundexString);
+
+/* Abstract */
+
+/* chunk separator parameters */
+#define ABS_CHUNKBEGIN "ChunkBegin="
+#define ABS_CHUNKSEP "ChunkSep="
+#define ABS_CHUNKEND "ChunkEnd="
+
+/* abstraction commands */
+#define ABS_TEXTONLY "textonly "
+#define ABS_COUNTWORDS "countwords "
+#define ABS_SAVE "save "
+#define ABS_RESTORE "restore "
+#define ABS_TRYFIT "tryfit "
+#define ABS_ABBREV "abbrev "
+#define ABS_SORTCHUNKS "sortchunks "
+#define ABS_NOSTOPLIST "nostoplist "
+#define ABS_NOSIGLIST "nosiglist "
+#define ABS_USEDICT "ab-usedict "
+#define ABS_NODICT "ab-usedict=0 "
+#define ABS_DROPVOWELS "ab-dropvowels "
+#define ABS_KEEPVOWELS "ab-dropvowels=0 "
+#define ABS_TRIMWHITE "ab-trimwhite "
+#define ABS_NOTRIMWHITE "ab-trimwhite=0 "
+#define ABS_TRIMPUNCT "ab-trimpunct "
+#define ABS_NOTRIMPUNCT "ab-trimpunct=0 "
+#define ABS_DROPFIRSTVOWEL "ab-dropfirstvowels "
+#define ABS_KEEPFIRSTVOWEL "ab-dropfirstvowels=0 "
+
+
+STATUS LNPUBLIC Abstract(char far *szKeywords,
+ char far *szText,
+ DWORD maxAbstract,
+ char far *szAbstract,
+ DWORD far *retSize);
+
+
+STATUS LNPUBLIC SECHashPassword(WORD wPasswordLen,
+ BYTE *Password,
+ WORD wMaxDigestLen,
+ WORD *retDigestLen,
+ BYTE *retDigest,
+ DWORD ReservedFlags,
+ void *pReserved
+ );
+
+STATUS LNPUBLIC SECVerifyPassword(WORD wPasswordLen,
+ BYTE *Password,
+ WORD wDigestLen,
+ BYTE *Digest,
+ DWORD ReservedFlags,
+ void *pReserved
+ );
+
+/* Notes bitmap conversion routines and constants. Should be exposed in the CAPI
+ notescvt.c
+*/
+#define CONVERT_NOTESBITMAP_TO_GIF 0
+typedef STATUS (LNCALLBACKPTR pConvertNBmpWriter)(void *pWriterCtx, /* user defined writer context */
+ BYTE *bytes, /* data bytes */
+ DWORD byteCount, /* maxChunkSize or totalImageSizeInBytes */
+ DWORD totalImageSizeInBytes);
+STATUS LNPUBLIC ConvertNotesBitmapRead(MEMHANDLE *phConvertContext,
+ WORD cdSignature,
+ char far *pCDRecord,
+ DWORD recordLength
+ );
+STATUS LNPUBLIC ConvertNotesBitmap(MEMHANDLE hConvertContext, /* created by ConvertNotesBitmapRead */
+ WORD convertTo, /* CONVERT_NOTESBITMAP_TO_GIF */
+ DWORD maxChunkSize, /* if zero will pass entire bitmap in bytes parameter of pWriter function*/
+ pConvertNBmpWriter pWriter, /* user defined writer */
+ void *pWriterCtx /* context passed to user defined writer */
+ );
+STATUS LNPUBLIC ConvertNotesBitmapFree(MEMHANDLE *phConvertContext);
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* MISC_DEFS */
+
+#if defined(OS400) && (__OS400_TGTVRM__ >= 510)
+#pragma datamodel(pop)
+#endif
+
diff --git a/protocols/LotusNotify/src/cnotesapi/include/names.h b/protocols/LotusNotify/src/cnotesapi/include/names.h
new file mode 100644
index 0000000000..cac62dd0d0
--- /dev/null
+++ b/protocols/LotusNotify/src/cnotesapi/include/names.h
@@ -0,0 +1,177 @@
+
+#if defined(OS400) && (__OS400_TGTVRM__ >= 510)
+#pragma datamodel(P128)
+#endif
+
+/*********************************************************************/
+/* */
+/* Licensed Materials - Property of IBM */
+/* */
+/* L-GHUS-5VMPGW, L-GHUS-5S3PEE */
+/* (C) Copyright IBM Corp. 1989, 2004 All Rights Reserved */
+/* */
+/* US Government Users Restricted Rights - Use, duplication or */
+/* disclosure restricted by GSA ADP Schedule Contract with */
+/* IBM Corp. */
+/* */
+/*********************************************************************/
+
+
+#ifndef NAME_DEFS
+#define NAME_DEFS
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+ Definitions pertaining to naming and maximum name lengths
+*/
+
+/* Maximum name length constants. */
+
+/* MAXPATH is the maximum size of a full filespec, including the server and
+ port name (e.g. "NETBEUI!!!A Long Server Name/Iris!!dir1/dir2/file").
+
+ MAXPATH must be capable of representing a full filespec not only on
+ the local machine (that we're compiling for), but also capable of
+ representing a full filespec on any remote server on any other platform!
+
+ Because a full filespec, including fully expanded server names, can be
+ quite long, we have a policy that if the buffer limit is reached when
+ constructing a full path, OSPathConstruct (and others) return an error
+ to the caller, which gets reported to the user (rather than trying to
+ open a truncated filespec).
+
+ The maximum length includes the terminating null so these maximums
+ may be used in data declarations. However, in places where a size
+ is specified that indicates the maximum number of characters in the
+ name, then the appropriate number minus 1 should be used.
+*/
+
+/* Before V4, MAXPATH was 256 for MAC, NLM & UNIX. For others it was 100.
+ Win95 which is now supported by V4 has long filenames, requiring the
+ MAXPATH to be increased to 256. For old compatibility, we have defined
+ OLDMAXPATH which is the same definition of MAXPATH in V3 and below. The
+ MAXPATH define in V4 is now 256 for all platforms.
+*/
+
+#if defined(MAC) || defined(NLM) || defined(UNIX)
+#define OLDMAXPATH 256 /* Maximum pathname */
+#else
+#define OLDMAXPATH 100 /* Maximum pathname */
+#endif
+
+
+#if !defined(DOSW16)
+#ifdef MAXPATH
+#undef MAXPATH /* Remove previous definition, if any (e.g. UNIX headers) */
+#endif
+#define MAXPATH 256 /* Maximum pathname */
+#else
+#define MAXPATH 100 /* Maximum pathname */
+#endif
+
+/* MAXPATH_OLE is the maximum size of a full filespec within OLE, including
+ the server and port name. It is used within Notes OLE in areas where
+ the Notes API warning on MAXPATH does not apply.
+*/
+
+#if (defined(W32) && !defined(UNIX)) || defined(MAC)
+#define MAXPATH_OLE 260 /* Maximum pathname for OLE */
+#else
+#define MAXPATH_OLE 256 /* Maximum pathname for OLE */
+#endif
+
+
+#ifdef MAC
+/* Some Int'l Macs require more than 32 bytes for port name (have seen
+ at least 68 chars in a PCMCIA card name).
+ Note: for SDK concern, we made change for MAC only.
+*/
+#define MAXPORTNAME 64 /* Maximum port name */
+#else
+#define MAXPORTNAME 32 /* Maximum port name */
+#endif
+
+#define MAXUSERNAME 256 /* Maximum user name */
+#define MAXDOMAINNAME 32 /* Maximum management domain name */
+#define MAXDOMAINPATH 32+1+MAXUSERNAME /* Maximum management domain name component of address (LOTUS:CPD-QA-SERVER) */
+
+#define OLDFILETITLEMAX 33 /* Pre V5 Notefile title string MAX(ASCIZ) */
+#define FILETITLEMAX 97 /* Notefile title string MAX(ASCIZ) */
+
+#define DESIGN_LEVELS 2 /* Cascade can go only one */
+ /* level deep parent\sub */
+#define DESIGN_LEVEL_MAX 64 /* Maximum size of a level */
+
+#define DESIGN_NAME_MAX ((DESIGN_LEVEL_MAX+1)*DESIGN_LEVELS)
+ /* Guaranteed */
+ /* To be the greatest of */
+ /* Form, View or Macro */
+ /* length. NOTE: We need */
+ /* space for LEVELS-1 cascade */
+ /* characters and a NULL term. */
+ /* The +1 takes care of that. */
+
+#define DESIGN_FORM_MAX DESIGN_NAME_MAX /* Forms can cascade a level */
+#define DESIGN_VIEW_MAX DESIGN_NAME_MAX /* Views can cascade a level */
+#define DESIGN_MACRO_MAX DESIGN_NAME_MAX /* Macros can cascade a level */
+#define DESIGN_FIELD_MAX DESIGN_LEVEL_MAX+1 /* Fields cannot cascade */
+
+#define DESIGN_COMMENT_MAX 256 /* Design element comment max size. */
+#define DESIGN_ALL_NAMES_MAX 256 /* All names, including sysnonyms */
+#define DESIGN_FOLDER_MAX DESIGN_VIEW_MAX /* Same as for views */
+#define DESIGN_FOLDER_MAX_NAME DESIGN_LEVEL_MAX /* Same as for views */
+
+#define DESIGN_FLAGS_MAX 32
+
+
+/* Constants for names used in registering a new workstation/server. */
+
+#define MAXLOCATIONNAME 128
+#define MAXCOMMENTNAME 512
+#define MAX_ID_PASSWORD 64
+
+/* Constants used for applying/converting mail system types chosen during
+ user registration to the mailtype field in the person document. These
+ should be in the same order as the keyword values in this mail type field */
+
+
+#define MAILSYSTEM_NOTES 0
+#define MAILSYSTEM_CCMAIL 1
+#define MAILSYSTEM_VIMMAIL 2
+#define MAILSYSTEM_NONE 99
+/* Constants for Client Type. */
+
+#define CLIENTTYPE_FULL 0
+#define CLIENTTYPE_LIMITED 1
+#define CLIENTTYPE_DESKTOP 2
+
+
+
+#define MAXNETADR 64
+
+
+#define RESERVED_PRIV_PREFIX '(' /* Group names cannot begin with this */
+#define RESERVED_CLASS_PREFIX '[' /* Group names cannot begin with this */
+
+#ifdef MAC
+#define MAXFILETITLE 20
+#define MAXFILENAME 31
+#else
+#define MAXFILETITLE 12
+#define MAXFILENAME 12
+#endif
+
+
+#ifdef __cplusplus
+}
+#endif
+#endif
+
+
+#if defined(OS400) && (__OS400_TGTVRM__ >= 510)
+#pragma datamodel(pop)
+#endif
+
diff --git a/protocols/LotusNotify/src/cnotesapi/include/nif.h b/protocols/LotusNotify/src/cnotesapi/include/nif.h
new file mode 100644
index 0000000000..1969c4000b
--- /dev/null
+++ b/protocols/LotusNotify/src/cnotesapi/include/nif.h
@@ -0,0 +1,520 @@
+
+#if defined(OS400) && (__OS400_TGTVRM__ >= 510)
+#pragma datamodel(P128)
+#endif
+
+/*********************************************************************/
+/* */
+/* Licensed Materials - Property of IBM */
+/* */
+/* L-GHUS-5VMPGW, L-GHUS-5S3PEE */
+/* (C) Copyright IBM Corp. 1989, 2005 All Rights Reserved */
+/* */
+/* US Government Users Restricted Rights - Use, duplication or */
+/* disclosure restricted by GSA ADP Schedule Contract with */
+/* IBM Corp. */
+/* */
+/*********************************************************************/
+
+
+
+/* NIF manipulation routines & basic datatypes */
+
+#ifndef NIF_DEFS
+#define NIF_DEFS
+
+#ifndef NSF_DATA_DEFS
+#include "nsfdata.h" /* We need NOTEID */
+#endif
+
+#ifndef NSF_NOTE_DEFS
+#include "nsfnote.h" /* We need NOTE_CLASS_VIEW */
+#endif
+
+#ifndef POOL_DEFS
+#include "pool.h"
+#endif
+
+#ifndef STD_NAME_DEFS
+#include "stdnames.h"
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define DB2NIF_VERSION 11
+
+/* Collection handle */
+
+typedef WORD HCOLLECTION; /* Handle to NIF collection */
+#define NULLHCOLLECTION ( (HCOLLECTION) 0 )
+
+
+/* NIFOpenCollection "open" flags */
+
+#define OPEN_REBUILD_INDEX 0x0001 /* Throw away existing index and */
+ /* rebuild it from scratch */
+#define OPEN_NOUPDATE 0x0002 /* Do not update index or unread */
+ /* list as part of open (usually */
+ /* set by server when it does it */
+ /* incrementally instead). */
+#define OPEN_DO_NOT_CREATE 0x0004 /* If collection object has not yet */
+ /* been created, do NOT create it */
+ /* automatically, but instead return */
+ /* a special internal error called */
+ /* ERR_COLLECTION_NOT_CREATED */
+#define OPEN_SHARED_VIEW_NOTE 0x0010 /* Tells NIF to "own" the view note */
+ /* (which gets read while opening the */
+ /* collection) in memory, rather than */
+ /* the caller "owning" the view note */
+ /* by default. If this flag is specified */
+ /* on subsequent opens, and NIF currently */
+ /* owns a copy of the view note, it */
+ /* will just pass back the view note */
+ /* handle rather than re-reading it */
+ /* from disk/network. If specified, */
+ /* the the caller does NOT have to */
+ /* close the handle. If not specified, */
+ /* the caller gets a separate copy, */
+ /* and has to NSFNoteClose the */
+ /* handle when its done with it. */
+#define OPEN_REOPEN_COLLECTION 0x0020 /* Force re-open of collection and */
+ /* thus, re-read of view note. */
+ /* Also implicitly prevents sharing */
+ /* of collection handle, and thus */
+ /* prevents any sharing of associated */
+ /* structures such as unread lists, etc */
+
+
+/* Collection navigation directives */
+
+#define NAVIGATE_CURRENT 0 /* Remain at current position */
+ /* (reset position & return data) */
+#define NAVIGATE_PARENT 3 /* Up 1 level */
+#define NAVIGATE_CHILD 4 /* Down 1 level to first child */
+#define NAVIGATE_NEXT_PEER 5 /* Next node at our level */
+#define NAVIGATE_PREV_PEER 6 /* Prev node at our level */
+#define NAVIGATE_FIRST_PEER 7 /* First node at our level */
+#define NAVIGATE_LAST_PEER 8 /* Last node at our level */
+#define NAVIGATE_CURRENT_MAIN 11 /* Highest level non-category entry */
+#define NAVIGATE_NEXT_MAIN 12 /* CURRENT_MAIN, then NEXT_PEER */
+#define NAVIGATE_PREV_MAIN 13 /* CURRENT_MAIN, then PREV_PEER only if already there */
+#define NAVIGATE_NEXT_PARENT 19 /* PARENT, then NEXT_PEER */
+#define NAVIGATE_PREV_PARENT 20 /* PARENT, then PREV_PEER */
+
+#define NAVIGATE_NEXT 1 /* Next entry over entire tree */
+ /* (parent first, then children,...) */
+#define NAVIGATE_PREV 9 /* Previous entry over entire tree */
+ /* (opposite order of PREORDER) */
+#define NAVIGATE_ALL_DESCENDANTS 17 /* NEXT, but only descendants */
+ /* below NIFReadEntries StartPos */
+#define NAVIGATE_NEXT_UNREAD 10 /* NEXT, but only "unread" entries */
+#define NAVIGATE_NEXT_UNREAD_MAIN 18 /* NEXT_UNREAD, but stop at main note also */
+#define NAVIGATE_PREV_UNREAD_MAIN 34 /* Previous unread main. */
+#define NAVIGATE_PREV_UNREAD 21 /* PREV, but only "unread" entries */
+#define NAVIGATE_NEXT_SELECTED 14 /* NEXT, but only "selected" entries */
+#define NAVIGATE_PREV_SELECTED 22 /* PREV, but only "selected" entries */
+#define NAVIGATE_NEXT_SELECTED_MAIN 32 /* Next selected main. (Next unread */
+ /* main can be found above.) */
+#define NAVIGATE_PREV_SELECTED_MAIN 33 /* Previous selected main. */
+#define NAVIGATE_NEXT_EXPANDED 15 /* NEXT, but only "expanded" entries */
+#define NAVIGATE_PREV_EXPANDED 16 /* PREV, but only "expanded" entries */
+#define NAVIGATE_NEXT_EXPANDED_UNREAD 23 /* NEXT, but only "expanded" AND "unread" entries */
+#define NAVIGATE_PREV_EXPANDED_UNREAD 24 /* PREV, but only "expanded" AND "unread" entries */
+#define NAVIGATE_NEXT_EXPANDED_SELECTED 25 /* NEXT, but only "expanded" AND "selected" entries */
+#define NAVIGATE_PREV_EXPANDED_SELECTED 26 /* PREV, but only "expanded" AND "selected" entries */
+#define NAVIGATE_NEXT_EXPANDED_CATEGORY 27 /* NEXT, but only "expanded" AND "category" entries */
+#define NAVIGATE_PREV_EXPANDED_CATEGORY 28 /* PREV, but only "expanded" AND "category" entries */
+#define NAVIGATE_NEXT_EXP_NONCATEGORY 39 /* NEXT, but only "expanded" "non-category" entries */
+#define NAVIGATE_PREV_EXP_NONCATEGORY 40 /* PREV, but only "expanded" "non-category" entries */
+#define NAVIGATE_NEXT_HIT 29 /* NEXT, but only FTSearch "hit" entries */
+ /* (in the SAME ORDER as the hit's relevance ranking) */
+#define NAVIGATE_PREV_HIT 30 /* PREV, but only FTSearch "hit" entries */
+ /* (in the SAME ORDER as the hit's relevance ranking) */
+#define NAVIGATE_CURRENT_HIT 31 /* Remain at current position in hit's relevance rank array */
+ /* (in the order of the hit's relevance ranking) */
+#define NAVIGATE_NEXT_SELECTED_HIT 35 /* NEXT, but only "selected" and FTSearch "hit" entries */
+ /* (in the SAME ORDER as the hit's relevance ranking) */
+#define NAVIGATE_PREV_SELECTED_HIT 36 /* PREV, but only "selected" and FTSearch "hit" entries */
+ /* (in the SAME ORDER as the hit's relevance ranking) */
+#define NAVIGATE_NEXT_UNREAD_HIT 37 /* NEXT, but only "unread" and FTSearch "hit" entries */
+ /* (in the SAME ORDER as the hit's relevance ranking) */
+#define NAVIGATE_PREV_UNREAD_HIT 38 /* PREV, but only "unread" and FTSearch "hit" entries */
+ /* (in the SAME ORDER as the hit's relevance ranking) */
+#define NAVIGATE_NEXT_CATEGORY 41 /* NEXT, but only "category" entries */
+#define NAVIGATE_PREV_CATEGORY 42 /* PREV, but only "category" entries */
+#define NAVIGATE_NEXT_NONCATEGORY 43 /* NEXT, but only "non-category" entries */
+#define NAVIGATE_PREV_NONCATEGORY 44 /* PREV, but only "non-category" entries */
+
+#define NAVIGATE_MASK 0x007F /* Navigator code (see above) */
+
+
+/* Flag which can be used with ALL navigators which causes the navigation
+ to be limited to entries at a specific level (specified by the
+ field "MinLevel" in the collection position) or any higher levels
+ but never a level lower than the "MinLevel" level. Note that level 0
+ means the top level of the index, so the term "minimum level" really
+ means the "highest level" the navigation can move to.
+ This can be used to find all entries below a specific position
+ in the index, limiting yourself only to that subindex, and yet be
+ able to use any of the navigators to move around within that subindex.
+ This feature was added in Version 4 of Notes, so it cannot be used
+ with earlier Notes Servers. */
+
+#define NAVIGATE_MINLEVEL 0x0100 /* Honor "Minlevel" field in position */
+#define NAVIGATE_MAXLEVEL 0x0200 /* Honor "Maxlevel" field in position */
+
+/* This flag can be combined with any navigation directive to
+ prevent having a navigation (Skip) failure abort the (ReadEntries) operation.
+ For example, this is used by the Notes user interface when
+ getting the entries to display in the view, so that if an attempt is made to
+ skip past either end of the index (e.g. using PageUp/PageDown),
+ the skip will be left at the end of the index, and the return will return
+ whatever can be returned using the separate return navigator.
+
+ This flag is also used to get the "last" N entries of a view by setting the
+ Skip Navigator to NAVIGATE_NEXT | NAVIGATE_CONTINUE, setting the SkipCount to MAXDWORD,
+ setting the ReturnNavigator to NAVIGATE_PREV_EXPANDED, and setting the ReturnCount
+ to N (N must be greater than 0). */
+
+#define NAVIGATE_CONTINUE 0x8000 /* "Return" even if "Skip" error */
+
+/* Structure which describes statistics about the overall collection,
+ and can be requested using the READ_MASK_COLLECTIONSTATS flag. If
+ requested, this structure is returned at the beginning of the returned
+ ReadEntries buffer. */
+
+typedef struct
+ {
+ WORD TopLevelEntries; /* # top level entries (level 0) */
+ WORD spare[3]; /* 0 */
+ } COLLECTIONSTATS16;
+
+typedef struct
+ {
+ DWORD TopLevelEntries; /* # top level entries (level 0) */
+ DWORD spare; /* 0 */
+ } COLLECTIONSTATS;
+
+/* Structure which specifies collection index position. */
+
+#define MAXTUMBLERLEVELS_V2 8 /* Max. levels in hierarchy tree in V2 */
+#define MAXTUMBLERLEVELS 32 /* Max. levels in hierarchy tree */
+
+typedef struct
+ {
+ WORD Level; /* # levels -1 in tumbler */
+ /* (top level = 0) */
+ WORD Tumbler[MAXTUMBLERLEVELS_V2]; /* Current tumbler (1.2.3, etc) */
+ /* (an array of ordinal ranks) */
+ /* (0th entry = top level) */
+ } COLLECTIONPOSITION16;
+
+typedef struct
+ {
+ WORD Level; /* # levels -1 in tumbler */
+ /* (top level = 0) */
+ BYTE MinLevel; /* MINIMUM level that this position */
+ /* is allowed to be nagivated to. */
+ /* This is useful to navigate a */
+ /* subtree using all navigator codes. */
+ /* This field is IGNORED unless */
+ /* the NAVIGATE_MINLEVEL flag is */
+ /* enabled (for backward compat) */
+ BYTE MaxLevel; /* MAXIMUM level that this position */
+ /* is allowed to be nagivated to. */
+ /* This is useful to navigate a */
+ /* subtree using all navigator codes. */
+ /* This field is IGNORED unless */
+ /* the NAVIGATE_MAXLEVEL flag is */
+ /* enabled (for backward compat) */
+ DWORD Tumbler[MAXTUMBLERLEVELS]; /* Current tumbler (1.2.3, etc) */
+ /* (an array of ordinal ranks) */
+ /* (0th entry = top level) */
+ /* Actual number of array entries */
+ /* is Level+1 */
+ } COLLECTIONPOSITION;
+
+
+/* Macro which computes size of portion of COLLECTIONPOSITION structure
+ which is actually used. This is the size which is returned by
+ NIFReadEntries when READ_MASK_INDEXPOSITION is specified. */
+
+#define COLLECTIONPOSITIONSIZE16(p) (sizeof(WORD) * ((p)->Level+2))
+#define COLLECTIONPOSITIONSIZE(p) (sizeof(DWORD) * ((p)->Level+2))
+/* NIFReadEntries return mask flags
+
+ These flags specified what information is returned in the return
+ buffer. With the exception of READ_MASK_COLLECTIONSTATS, the
+ information which corresponds to each of the flags in this mask
+ are returned in the buffer, repeated for each index entry, in the
+ order in which the bits are listed here.
+
+ The return buffer consists of:
+
+ 1) COLLECTIONSTATS structure, if requested (READ_MASK_COLLECTIONSTATS).
+ This structure is returned only once at the beginning of the
+ buffer, and is not repeated for each index entry.
+
+ 2) Information about each index entry. Each flag requested a different
+ bit of information about the index entry. If more than one flag
+ is defined, the values follow each other, in the order in which
+ the bits are listed here. This portion repeats for as many
+ index entries as are requested.
+*/
+
+ /* Fixed length stuff */
+#define READ_MASK_NOTEID 0x00000001L /* NOTEID of entry */
+#define READ_MASK_NOTEUNID 0x00000002L /* UNID of entry */
+#define READ_MASK_NOTECLASS 0x00000004L /* WORD of "note class" */
+#define READ_MASK_INDEXSIBLINGS 0x00000008L /* DWORD/WORD of # siblings of entry */
+#define READ_MASK_INDEXCHILDREN 0x00000010L /* DWORD/WORD of # direct children of entry */
+#define READ_MASK_INDEXDESCENDANTS 0x00000020L /* DWORD/WORD of # descendants below entry */
+#define READ_MASK_INDEXANYUNREAD 0x00000040L /* WORD of TRUE if "unread" or */
+ /* "unread" descendants; else FALSE */
+#define READ_MASK_INDENTLEVELS 0x00000080L /* WORD of # levels that this */
+ /* entry should be indented in */
+ /* a formatted view. */
+ /* For category entries: */
+ /* # sub-levels that this */
+ /* category entry is within its */
+ /* Collation Descriptor. Used */
+ /* for multiple-level category */
+ /* columns (backslash-delimited). */
+ /* "0" for 1st level in this column, etc. */
+ /* For response entries: */
+ /* # levels that this response */
+ /* is below the "main note" level. */
+ /* For normal entries: 0 */
+#define READ_MASK_SCORE 0x00000200L /* Relavence "score" of entry */
+ /* (only used with FTSearch). */
+#define READ_MASK_INDEXUNREAD 0x00000400L /* WORD of TRUE if this entry (only) "unread" */
+
+
+ /* Stuff returned only once at beginning of return buffer */
+#define READ_MASK_COLLECTIONSTATS 0x00000100L /* Collection statistics (COLLECTIONSTATS/COLLECTIONSTATS16) */
+
+
+ /* Variable length stuff */
+#define READ_MASK_INDEXPOSITION 0x00004000L /* Truncated COLLECTIONPOSITION/COLLECTIONPOSITION16 */
+#define READ_MASK_SUMMARYVALUES 0x00002000L /* Summary buffer w/o item names */
+#define READ_MASK_SUMMARY 0x00008000L /* Summary buffer with item names */
+/* Structures which are used by NIFGetCollectionData to return data
+ about the collection. NOTE: If the COLLECTIONDATA structure changes,
+ nifods.c must change as well. */
+
+/* Definitions which are used by NIFGetCollectionData to return data about the collection. */
+
+#define PERCENTILE_COUNT 11
+
+#define PERCENTILE_0 0
+#define PERCENTILE_10 1
+#define PERCENTILE_20 2
+#define PERCENTILE_30 3
+#define PERCENTILE_40 4
+#define PERCENTILE_50 5
+#define PERCENTILE_60 6
+#define PERCENTILE_70 7
+#define PERCENTILE_80 8
+#define PERCENTILE_90 9
+#define PERCENTILE_100 10
+
+typedef struct
+ {
+ DWORD DocCount; /* Total number of documents in the collection */
+ DWORD DocTotalSize; /* Total number of bytes occupied by the documents in the collection */
+ DWORD BTreeLeafNodes; /* Number of B-Tree leaf nodes for this index. */
+ WORD BTreeDepth; /* Number of B-tree levels for this index. */
+ WORD Spare; /* Unused */
+ DWORD KeyOffset[PERCENTILE_COUNT]; /* Offset of ITEM_VALUE_TABLE for each 10th-percentile key value */
+ /* A series of ITEM_VALUE_TABLEs follows this structure. */
+ } COLLECTIONDATA;
+
+
+
+/* Flag in index entry's NOTEID to indicate (ghost) "category entry" */
+/* Note: this relies upon the fact that NOTEID_RESERVED is high bit! */
+
+#define NOTEID_CATEGORY 0x80000000L /* Bit 31 -> (ghost) "category entry" */
+#define NOTEID_CATEGORY_TOTAL 0xC0000000L /* Bit 31+30 -> (ghost) "grand total entry" */
+#define NOTEID_CATEGORY_INDENT 0x3F000000L /* Bits 24-29 -> category indent level within this column */
+#define NOTEID_CATEGORY_ID 0x00FFFFFFL /* Low 24 bits are unique category # */
+
+
+/* SignalFlags word returned by NIFReadEntries and V4+ NIFFindByKey */
+
+#define SIGNAL_DEFN_ITEM_MODIFIED 0x0001
+ /* At least one of the "definition" */
+ /* view items ($FORMULA, $COLLATION, */
+ /* or $FORMULACLASS) has been modified */
+ /* by another user since last ReadEntries. */
+ /* Upon receipt, you may wish to */
+ /* re-read the view note if up-to-date */
+ /* copies of these items are needed. */
+ /* Upon receipt, you may also wish to */
+ /* re-synchronize your index position */
+ /* and re-read the rebuilt index. */
+ /* Signal returned only ONCE per detection */
+#define SIGNAL_VIEW_ITEM_MODIFIED 0x0002
+ /* At least one of the non-"definition" */
+ /* view items ($TITLE,etc) has been */
+ /* modified since last ReadEntries. */
+ /* Upon receipt, you may wish to */
+ /* re-read the view note if up-to-date */
+ /* copies of these items are needed. */
+ /* Signal returned only ONCE per detection */
+#define SIGNAL_INDEX_MODIFIED 0x0004
+ /* Collection index has been modified */
+ /* by another user since last ReadEntries. */
+ /* Upon receipt, you may wish to */
+ /* re-synchronize your index position */
+ /* and re-read the modified index. */
+ /* Signal returned only ONCE per detection */
+#define SIGNAL_UNREADLIST_MODIFIED 0x0008
+ /* Unread list has been modified */
+ /* by another window using the same */
+ /* hCollection context */
+ /* Upon receipt, you may wish to */
+ /* repaint the window if the window */
+ /* contains the state of unread flags */
+ /* (This signal is never generated */
+ /* by NIF - only unread list users) */
+#define SIGNAL_DATABASE_MODIFIED 0x0010
+ /* Collection is not up to date */
+#define SIGNAL_MORE_TO_DO 0x0020
+ /* End of collection has not been reached */
+ /* due to buffer being too full. */
+ /* The ReadEntries should be repeated */
+ /* to continue reading the desired entries. */
+#define SIGNAL_VIEW_TIME_RELATIVE 0x0040
+ /* The view contains a time-relative formula */
+ /* (e.g., @Now). Use this flag to tell if the */
+ /* collection will EVER be up-to-date since */
+ /* time-relative views, by definition, are NEVER */
+ /* up-to-date. */
+#define SIGNAL_NOT_SUPPORTED 0x0080
+ /* Returned if signal flags are not supported */
+ /* This is used by NIFFindByKeyExtended when it */
+ /* is talking to a pre-V4 server that does not */
+ /* support signal flags for FindByKey */
+
+/* Mask that defines all "sharing conflicts", which are cases when
+ the database or collection has changed out from under the user. */
+
+#define SIGNAL_ANY_CONFLICT (SIGNAL_DEFN_ITEM_MODIFIED | \
+ SIGNAL_VIEW_ITEM_MODIFIED | \
+ SIGNAL_INDEX_MODIFIED | \
+ SIGNAL_UNREADLIST_MODIFIED | \
+ SIGNAL_DATABASE_MODIFIED)
+
+/* Mask that defines all "sharing conflicts" except for SIGNAL_DATABASE_MODIFIED.
+ This can be used in combination with SIGNAL_VIEW_TIME_RELATIVE to tell if
+ the database or collection has truly changed out from under the user or if the
+ view is a time-relative view which will NEVER be up-to-date. SIGNAL_DATABASE_MODIFIED
+ is always returned for a time-relative view to indicate that it is never up-to-date. */
+
+#define SIGNAL_ANY_NONDATA_CONFLICT (SIGNAL_DEFN_ITEM_MODIFIED | \
+ SIGNAL_VIEW_ITEM_MODIFIED | \
+ SIGNAL_INDEX_MODIFIED | \
+ SIGNAL_UNREADLIST_MODIFIED)
+
+/* NIFFindByKey "find" flags */
+
+#define FIND_PARTIAL 0x0001 /* Match only initial characters */
+ /* ("T" matches "Tim") */
+#define FIND_CASE_INSENSITIVE 0x0002 /* Case insensitive */
+ /* ("tim" matches "Tim") */
+#define FIND_RETURN_DWORD 0x0004 /* Input/Output is DWORD COLLECTIONPOSITION */
+#define FIND_ACCENT_INSENSITIVE 0x0008 /* Accent insensitive (ignore diacritical marks */
+#define FIND_UPDATE_IF_NOT_FOUND 0x0020 /* If key is not found, update collection */
+ /* and search again */
+
+/* At most one of the following four flags should be specified */
+#define FIND_LESS_THAN 0x0040 /* Find last entry less than the key value */
+#define FIND_FIRST_EQUAL 0x0000 /* Find first entry equal to the key value (if more than one) */
+#define FIND_LAST_EQUAL 0x0080 /* Find last entry equal to the key value (if more than one) */
+#define FIND_GREATER_THAN 0x00C0 /* Find first entry greater than the key value */
+#define FIND_EQUAL 0x0800 /* Qualifies LESS_THAN and GREATER_THAN to mean */
+ /* LESS_THAN_OR_EQUAL and GREATER_THAN_OR_EQUAL */
+#define FIND_COMPARE_MASK 0x08C0 /* Bitmask of the comparison flags defined above */
+
+#define FIND_RANGE_OVERLAP 0x0100 /* Overlapping ranges match, and values within a range match */
+#define FIND_RETURN_ANY_NON_CATEGORY_MATCH 0x0200
+ /* Return First Match at bottom level of
+ Categorized view (Doesn't have
+ to be first of duplicates */
+#define FIND_NONCATEGORY_ONLY 0x0400 /* Only match non-category entries */
+
+/* NIF public entry points */
+
+STATUS LNPUBLIC NIFOpenCollection (DBHANDLE hViewDB, DBHANDLE hDataDB,
+ NOTEID ViewNoteID, WORD OpenFlags,
+ HANDLE hUnreadList,
+ HCOLLECTION far *rethCollection,
+ NOTEHANDLE far *rethViewNote, UNID far *retViewUNID,
+ HANDLE far *rethCollapsedList,
+ HANDLE far *rethSelectedList);
+STATUS LNPUBLIC NIFCloseCollection (HCOLLECTION hCollection);
+STATUS LNPUBLIC NIFUpdateCollection (HCOLLECTION hCollection);
+
+STATUS LNPUBLIC NIFOpenCollectionWithUserNameList (DBHANDLE hViewDB, DBHANDLE hDataDB,
+ NOTEID ViewNoteID, WORD OpenFlags,
+ HANDLE hUnreadList,
+ HCOLLECTION far *rethCollection,
+ NOTEHANDLE far *rethViewNote, UNID far *retViewUNID,
+ HANDLE far *rethCollapsedList,
+ HANDLE far *rethSelectedList,
+ HANDLE nameList);
+STATUS LNPUBLIC NIFReadEntries (HCOLLECTION hCollection, COLLECTIONPOSITION far *IndexPos,
+ WORD SkipNavigator, DWORD SkipCount,
+ WORD ReturnNavigator, DWORD ReturnCount,
+ DWORD ReturnMask,
+ HANDLE far *rethBuffer, WORD far *retBufferLength,
+ DWORD far *retNumEntriesSkipped,
+ DWORD far *retNumEntriesReturned,
+ WORD far *retSignalFlags);
+
+STATUS LNPUBLIC NIFSetCollation(HCOLLECTION hCollection, WORD CollationNum);
+STATUS LNPUBLIC NIFGetCollation(HCOLLECTION hCollection, WORD *retCollationNum);
+
+
+STATUS LNPUBLIC NIFLocateNote (HCOLLECTION hCollection, COLLECTIONPOSITION far *IndexPos, NOTEID NoteID);
+STATUS LNPUBLIC NIFFindByKey (HCOLLECTION hCollection, void far *KeyBuffer,
+ WORD FindFlags,
+ COLLECTIONPOSITION far *retIndexPos,
+ DWORD far *retNumMatches);
+STATUS LNPUBLIC NIFFindByName (HCOLLECTION hCollection, const char far *Name, WORD FindFlags,
+ COLLECTIONPOSITION far *retIndexPos,
+ DWORD far *retNumMatches);
+
+STATUS LNPUBLIC NIFFindDesignNote (DBHANDLE hFile, const char far *Name, WORD Class, NOTEID far *retNoteID);
+#define NIFFindView(hFile,Name,retNoteID) NIFFindDesignNoteExt(hFile,Name,NOTE_CLASS_VIEW, DFLAGPAT_VIEWS_AND_FOLDERS, retNoteID, 0)
+#define NIFFindDesignNoteByName(hFile,Name,retNoteID) NIFFindDesignNote(hFile,Name,NOTE_CLASS_ALL,retNoteID) /* Only for V2 backward compatibility */
+
+STATUS LNPUBLIC NIFFindPrivateDesignNote (DBHANDLE hFile, const char far *Name, WORD Class, NOTEID far *retNoteID);
+#define NIFFindPrivateView(hFile,Name,retNoteID) NIFFindPrivateDesignNote(hFile,Name,NOTE_CLASS_VIEW,retNoteID)
+STATUS LNPUBLIC NIFGetCollectionData (HCOLLECTION hCollection,
+ HANDLE far *rethCollData);
+
+#define FIND_DESIGN_NOTE_PARTIAL 1 /* Find design note with a partial match. This means that
+ when you are looking for "Inbox" it will also
+ match on "($Inbox)". And when you are looking
+ for "All Escalated Bugs" it will match
+ "QA\All Escalated Bugs" */
+
+STATUS LNPUBLIC NIFFindDesignNoteExt (DBHANDLE hFile, const char far *Name, WORD Class, const char *pszFlagsPattern, NOTEID far *retNoteID, DWORD Options);
+void LNPUBLIC NIFGetLastModifiedTime (HCOLLECTION hCollection,
+ TIMEDATE far *retLastModifiedTime);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
+
+
+#if defined(OS400) && (__OS400_TGTVRM__ >= 510)
+#pragma datamodel(pop)
+#endif
+
diff --git a/protocols/LotusNotify/src/cnotesapi/include/nls.h b/protocols/LotusNotify/src/cnotesapi/include/nls.h
new file mode 100644
index 0000000000..5a3b7d7e97
--- /dev/null
+++ b/protocols/LotusNotify/src/cnotesapi/include/nls.h
@@ -0,0 +1,536 @@
+
+#if defined(OS400) && (__OS400_TGTVRM__ >= 510)
+#pragma datamodel(P128)
+#endif
+
+/*********************************************************************/
+/* */
+/* Licensed Materials - Property of IBM */
+/* */
+/* L-GHUS-5VMPGW, L-GHUS-5S3PEE */
+/* (C) Copyright IBM Corp. 1995, 2005 All Rights Reserved */
+/* */
+/* US Government Users Restricted Rights - Use, duplication or */
+/* disclosure restricted by GSA ADP Schedule Contract with */
+/* IBM Corp. */
+/* */
+/*********************************************************************/
+
+
+
+
+#if !defined(NLS_H)
+#define NLS_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+/********************************************************************
+** TYPES AND DEFINITIONS
+*/
+
+typedef WORD NLS_STATUS;
+
+typedef void NLS_INFO;
+typedef void far *NLS_PINFO;
+
+/********************************************************************
+** PROTOS
+*/
+
+NLS_STATUS LNPUBLIC NLS_load_charset (WORD CSID,
+ NLS_PINFO FAR * ppInfo);
+
+NLS_STATUS LNPUBLIC NLS_unload_charset (NLS_PINFO pInfo);
+
+NLS_STATUS LNPUBLIC NLS_translate (BYTE far * pString,
+ WORD Len,
+ BYTE far * pStringTarget,
+ WORD far * pSize,
+ WORD ControlFlags,
+ NLS_PINFO pInfo);
+
+NLS_STATUS LNPUBLIC NLS_find (BYTE far * far * ppString,
+ WORD Len,
+ const BYTE far * pSetOfChars,
+ WORD ControlFlags,
+ NLS_PINFO pInfo);
+
+NLS_STATUS LNPUBLIC NLS_find_substr (BYTE far * far * ppString,
+ WORD Len1,
+ const BYTE far * pSubString,
+ WORD Len2,
+ NLS_PINFO pInfo);
+
+NLS_STATUS LNPUBLIC NLS_get (BYTE far * far * ppString,
+ WORD Len,
+ BYTE far * pCharacter,
+ NLS_PINFO pInfo);
+
+WORD LNPUBLIC NLS_goto_next (BYTE far * far * ppString,
+ WORD Len,
+ NLS_PINFO pInfo);
+
+WORD LNPUBLIC NLS_goto_prev (BYTE far * far * ppString,
+ const BYTE far * pStrStart,
+ NLS_PINFO pInfo);
+WORD LNPUBLIC NLS_goto_next_word_end (BYTE far * far * ppString,
+ WORD Len,
+ NLS_PINFO pInfo);
+
+WORD LNPUBLIC NLS_goto_next_word_start(BYTE far * far * ppString,
+ WORD Len,
+ NLS_PINFO pInfo);
+
+WORD LNPUBLIC NLS_goto_next_break (BYTE far * far * ppString,
+ WORD Len,
+ NLS_PINFO pInfo);
+
+WORD LNPUBLIC NLS_goto_prev_word_end (BYTE far * far * ppString,
+ const BYTE far * pStrStart,
+ NLS_PINFO pInfo);
+
+WORD LNPUBLIC NLS_goto_prev_word_start(BYTE far * far * ppString,
+ const BYTE far * pStrStart,
+ NLS_PINFO pInfo);
+
+NLS_STATUS LNPUBLIC NLS_isalpha (const BYTE far * pCharacter,
+ NLS_PINFO pInfo);
+
+NLS_STATUS LNPUBLIC NLS_isalnum (const BYTE far * pCharacter,
+ NLS_PINFO pInfo);
+
+NLS_STATUS LNPUBLIC NLS_isarith (const BYTE far * pCharacter,
+ NLS_PINFO pInfo);
+
+NLS_STATUS LNPUBLIC NLS_iscntrl (const BYTE far * pCharacter,
+ NLS_PINFO pInfo);
+
+NLS_STATUS LNPUBLIC NLS_isdigit (const BYTE far * pCharacter,
+ NLS_PINFO pInfo);
+
+NLS_STATUS LNPUBLIC NLS_islower (const BYTE far * pCharacter,
+ NLS_PINFO pInfo);
+
+NLS_STATUS LNPUBLIC NLS_ispunct (const BYTE far * pCharacter,
+ NLS_PINFO pInfo);
+
+NLS_STATUS LNPUBLIC NLS_isspace (const BYTE far * pCharacter,
+ NLS_PINFO pInfo);
+
+NLS_STATUS LNPUBLIC NLS_isupper (const BYTE far * pCharacter,
+ NLS_PINFO pInfo);
+
+NLS_STATUS LNPUBLIC NLS_isleadbyte (BYTE Character,
+ NLS_PINFO pInfo);
+
+NLS_STATUS LNPUBLIC NLS_string_chars (const BYTE far * pString,
+ WORD NumBytes,
+ WORD far * pNumChars,
+ NLS_PINFO pInfo);
+
+NLS_STATUS LNPUBLIC NLS_string_bytes (const BYTE far * pString,
+ WORD NumChars,
+ WORD far * pNumBytes,
+ NLS_PINFO pInfo);
+NLS_STATUS LNPUBLIC NLS_put (BYTE far * far * ppString,
+ const BYTE far * pCharacter,
+ NLS_PINFO pInfo);
+
+NLS_STATUS LNPUBLIC NLS_put_term (BYTE far * far * ppString,
+ const BYTE far * pCharacter,
+ NLS_PINFO pInfo);
+
+/********************************************************************
+** RETURN CODES
+*/
+
+#define NLS_SUCCESS 0x0
+#define NLS_BADPARM 0xABAD
+#define NLS_BUFFERTOOSMALL 0xA000
+#define NLS_CHARSSTRIPPED 0x1000
+#define NLS_ENDOFSTRING 0x1001
+#define NLS_FALLBACKUSED 0x1002
+#define NLS_FILEINVALID 0xA001
+#define NLS_FILENOTFOUND 0xA002
+#define NLS_FINDFAILED 0x1005
+#define NLS_INVALIDCHARACTER 0xA003
+#define NLS_INVALIDDATA 0xA004
+#define NLS_INVALIDENTRY 0xA005
+#define NLS_INVALIDTABLE 0xA006
+#define NLS_PROPNOTFOUND 0x1003
+#define NLS_STARTOFSTRING 0x1004
+#define NLS_STRINGSIZECHANGED 0x1006
+#define NLS_TABLEHEADERINVALID 0xA007
+#define NLS_TABLENOTFOUND 0x1007
+
+/********************************************************************
+** FLAGS
+*/
+
+/* NLS_find */
+#define NLS_FIND_CHARINSET 1
+#define NLS_FIND_CHARNOTINSET 2
+/* NLS_translate */
+
+#define NLS_NONULLTERMINATE 0x1
+#define NLS_NULLTERMINATE 0x2
+#define NLS_STRIPUNKNOWN 0x4
+#define NLS_TARGETISLMBCS 0x8
+#define NLS_SOURCEISLMBCS 0x10
+#define NLS_TARGETISUNICODE 0x20
+#define NLS_SOURCEISUNICODE 0x40
+#define NLS_TARGETISPLATFORM 0x80
+#define NLS_SOURCEISPLATFORM 0x100
+
+
+/********************************************************************
+** MISC DEFINES
+*/
+
+#define NLS_NULLTERM (WORD) -1
+#define NLS_NULLTERM32 (DWORD) -1
+
+#define NLS_SIZEOFNULL 1 /* for LMBCS implementation */
+
+#define NLS_MAXBYTESPERCHAR 3
+
+#define NLS_MAXBYTESPERCHAR_WITH_SURROGATE 6
+#define NLS_MAXRATIO_XLATE_FROM_LMBCS 4
+#define NLS_MAXRATIO_XLATE_TO_LMBCS 3
+
+
+/********************************************************************
+** CHARACTER SET ID'S
+*/
+
+#if !defined(NLS_NOCHARSETIDS)
+
+#define NLS_CS_DEFAULT 0xFFFF
+#define NLS_CS_LICS 0x0000 /* Lotus Intl Char Set (WK1) */
+#define NLS_CS_IBMCP851 0x0001
+#define NLS_CS_IBMCP852 0x0002
+#define NLS_CS_IBMCP853 0x0003
+#define NLS_CS_IBMCP857 0x0004
+#define NLS_CS_IBMCP862 0x0005
+#define NLS_CS_IBMCP864 0x0006
+#define NLS_CS_IBMCP866 0x0007
+#define NLS_CS_IBMCP437 0x0008
+#define NLS_CS_IBMCP850 0x0009
+#define NLS_CS_IBMCP855 0x000A
+#define NLS_CS_IBMCP860 0x000B
+#define NLS_CS_IBMCP861 0x000C
+#define NLS_CS_IBMCP863 0x000D
+#define NLS_CS_IBMCP865 0x000E
+#define NLS_CS_IBMCP869 0x000F
+#define NLS_CS_IBMCP874 0x0090
+#define NLS_CS_IBMCP899 0x0011
+#define NLS_CS_IBMCP932 0x0012
+#define NLS_CS_IBMCP942 0x0012 /* 932 942 for Lotus */
+#define NLS_CS_IBMCP943 0x0012
+#define NLS_CS_IBMCP5039 0x0012
+#define NLS_CS_IBMCP891 0x0013
+#define NLS_CS_DECMCS 0x0014 /* DEC Multinational Char Set */
+
+#define NLS_CS_EUC 0x0017 /* Extended Unix Code */
+#define NLS_CS_KS 0x0018 /* Korean - KSC 5601 */
+#define NLS_CS_IBMCP949 0x0018
+#define NLS_CS_TCA 0x0019
+#define NLS_CS_BIG5 0x001A /* Taiwan Chinese - traditional */
+#define NLS_CS_IBMCP950 0x001A
+#define NLS_CS_GB 0x001B /* PRC Chinese - simplified */
+#define NLS_CS_IBMCP936 0x001B
+#define NLS_CS_NECESJIS 0x001C /* NEC Extended Shift-JIS */
+#define NLS_CS_ISO646 0x001F /* aka 'ASCII' */
+#define NLS_CS_ASCII 0x001F
+#define NLS_CS_ISO88591 0x0020 /* ISO Latin-1 */
+#define NLS_CS_IBMCP819 0x0020
+#define NLS_CS_ISO88592 0x0021 /* ISO Latin-2 (E. Europe) */
+#define NLS_CS_IBMCP912 0x0021
+#define NLS_CS_ISO88593 0x0022
+#define NLS_CS_ISO88594 0x0023
+#define NLS_CS_ISO88595 0x0024
+#define NLS_CS_IBMCP915 0x0024
+#define NLS_CS_ISO88596 0x0025
+#define NLS_CS_IBMCP1008 0x0025
+#define NLS_CS_ISO88597 0x0026
+#define NLS_CS_IBMCP813 0x0026
+#define NLS_CS_ISO88598 0x0027
+#define NLS_CS_IBMCP916 0x0027
+#define NLS_CS_ISO88599 0x0028
+#define NLS_CS_IBMCP920 0x0028
+
+#define NLS_CS_HPROMAN 0x0030 /* HP Roman (LaserJet) */
+#define NLS_CS_HPGREEK 0x0031 /* HP Roman (LaserJet) */
+#define NLS_CS_HPTURKISH 0x0032 /* HP Roman (LaserJet) */
+#define NLS_CS_HPHEBREW 0x0034
+#define NLS_CS_HPARABIC 0x0035
+#define NLS_CS_HPTHAI 0x0036
+#define NLS_CS_HPJAPAN 0x0037
+#define NLS_CS_HPKANA 0x0038
+#define NLS_CS_HPKOREA 0x0039
+#define NLS_CS_HPPRC 0x003A
+#define NLS_CS_HPROC 0x003B /* Traditional Chinese */
+
+
+#define NLS_CS_IBMCP37 0x0040 /* EBCDIC */
+#define NLS_CS_IBMCP273 0x0041
+#define NLS_CS_IBMCP278 0x0042
+#define NLS_CS_IBMCP280 0x0043
+#define NLS_CS_IBMCP284 0x0044
+#define NLS_CS_IBMCP285 0x0045
+#define NLS_CS_IBMCP290 0x0046
+#define NLS_CS_IBMCP297 0x0047
+#define NLS_CS_IBMCP500 0x0048
+#define NLS_CS_IBMCP277 0x004C
+#define NLS_CS_IBMCP1047 0x004D
+#define NLS_CS_IBMCP1250 0x0050 /* Windows ANSI */
+#define NLS_CS_IBMCP1251 0x0051
+#define NLS_CS_IBMCP1252 0x0052
+#define NLS_CS_ANSI 0X0052
+#define NLS_CS_IBMCP1253 0x0053
+#define NLS_CS_IBMCP1254 0x0054
+#define NLS_CS_IBMCP1255 0x0055
+#define NLS_CS_IBMCP1256 0x0056
+#define NLS_CS_IBMCP1257 0x0057
+#define NLS_CS_MACSCRIPT0 0x0060 /* Mac Roman */
+#define NLS_CS_MACSCRIPT1 NLS_CS_IBMCP932 /*0x0061*/
+#define NLS_CS_MACSCRIPT2 NLS_CS_GB /*0x0062*/
+#define NLS_CS_MACSCRIPT3 NLS_CS_KS /*0x0063*/
+#define NLS_CS_MACSCRIPT4 NLS_CS_ISO88596 /*0x0064*/
+#define NLS_CS_MACSCRIPT5 NLS_CS_ISO88598 /*0x0065*/
+#define NLS_CS_MACSCRIPT6 0x0066 /* cckSTRCharSetISO88597 */
+#define NLS_CS_MACSCRIPT7 0x0067 /* cckSTRCharSetISO88595 */
+#define NLS_CS_MACSCRIPT8 0x0068
+#define NLS_CS_MACSCRIPT9 0x0069
+#define NLS_CS_MACSCRIPT10 0x006A
+#define NLS_CS_MACSCRIPT11 0x006B
+#define NLS_CS_MACSCRIPT12 0x006C
+#define NLS_CS_MACSCRIPT13 0x006D
+#define NLS_CS_MACSCRIPT14 0x006E
+#define NLS_CS_MACSCRIPT15 0x006F
+#define NLS_CS_MACSCRIPT16 0x0070
+#define NLS_CS_MACSCRIPT17 0x0071
+#define NLS_CS_MACSCRIPT18 0x0072
+#define NLS_CS_MACSCRIPT19 0x0073
+#define NLS_CS_MACSCRIPT20 0x0074
+#define NLS_CS_MACSCRIPT21 0x0075
+#define NLS_CS_MACSCRIPT22 0x0076
+#define NLS_CS_MACSCRIPT23 0x0077
+#define NLS_CS_MACSCRIPT24 0x0078
+#define NLS_CS_MACSCRIPT25 0x0079
+#define NLS_CS_MACSCRIPT26 0x007A
+#define NLS_CS_MACSCRIPT27 0x007B
+#define NLS_CS_MACSCRIPT28 0x007C
+#define NLS_CS_MACSCRIPT29 0x007D
+#define NLS_CS_MACSCRIPT30 0x007E
+#define NLS_CS_MACSCRIPT31 0x007F
+#define NLS_CS_MACSCRIPT32 0x0080
+#define NLS_CS_MACSCRIPT0CROATIAN 0x0081
+#define NLS_CS_MACSCRIPT0GREEK 0x0082
+#define NLS_CS_MACSCRIPT0ICELANDIC 0x0083
+#define NLS_CS_MACSCRIPT0ROMANIAN 0x0084
+#define NLS_CS_MACSCRIPT0TURKISH 0x0085
+#define NLS_CS_THAI 0x0090 /* MS Thai Windows */
+#define NLS_CS_IBMCP1200 0x00A0 /* Unicode/ISO 10646 */
+#define NLS_CS_UNICODE 0x00A0
+#define NLS_CS_UNICODE 0x00A0
+#define NLS_CS_ISO10646 0x00A0 /* Also Unicode */
+#define NLS_CS_UTF7 0x00AA /* Unicode Transformation Formats */
+#define NLS_CS_UTF8 0x00AB
+#define NLS_CS_LMBCS10 0x0100 /* Version 1.0 is the only one */
+#define NLS_CS_LMBCS11 0x0101
+#define NLS_CS_LMBCS12 0x0102
+#define NLS_CS_LMBCS 0x0100
+#define NLS_CS_DECNRCUK 0x0A00 /* DEC National Replacement Char */
+#define NLS_CS_DECNRCDUTCH 0x0A01
+#define NLS_CS_DECNRCFINNISH 0x0A02
+#define NLS_CS_DECNRCFRENCH 0x0A03
+#define NLS_CS_DECNRCFRENCHCANADIAN 0x0A04
+#define NLS_CS_DECNRCGERMAN 0x0A05
+#define NLS_CS_DECNRCITALIAN 0x0A06
+#define NLS_CS_DECNRCNORWEGIANDANISH 0x0A07
+#define NLS_CS_DECNRCPORTUGUESE 0x0A08
+#define NLS_CS_DECNRCSPANISH 0x0A09
+#define NLS_CS_DECNRCSWEDISH 0x0A0A
+#define NLS_CS_DECNRCSWISS 0x0A0B
+#define NLS_CS_T61 0x0B00
+#define NLS_CS_T50 0x0B01
+#define NLS_CS_ASN1 0x0B10
+#define NLS_CS_IBMCP856 0x0C00
+#define NLS_CS_IBMCP1004 0x0C01
+#define NLS_CS_IBMCP1002 0x0CA0
+#define NLS_CS_IBMCP1003 0x0CA1
+#define NLS_CS_IBMCP1025 0x0CA2
+#define NLS_CS_IBMCP1026 0x0CA3
+#define NLS_CS_IBMCP1028 0x0CA4
+#define NLS_CS_IBMCP256 0x0CA5
+#define NLS_CS_IBMCP259 0x0CA6
+#define NLS_CS_IBMCP274 0x0CA7
+#define NLS_CS_IBMCP275 0x0CA8
+#define NLS_CS_IBMCP281 0x0CA9
+#define NLS_CS_IBMCP282 0x0CAA
+#define NLS_CS_IBMCP361 0x0CAB
+
+#define NLS_CS_IBMCP382 0x0CAD
+#define NLS_CS_IBMCP383 0x0CAE
+#define NLS_CS_IBMCP384 0x0CAF
+#define NLS_CS_IBMCP385 0x0CB0
+#define NLS_CS_IBMCP386 0x0CB1
+#define NLS_CS_IBMCP387 0x0CB2
+#define NLS_CS_IBMCP388 0x0CB3
+#define NLS_CS_IBMCP389 0x0CB4
+#define NLS_CS_IBMCP390 0x0CB5
+#define NLS_CS_IBMCP391 0x0CB6
+#define NLS_CS_IBMCP392 0x0CB7
+#define NLS_CS_IBMCP393 0x0CB8
+#define NLS_CS_IBMCP394 0x0CB9
+#define NLS_CS_IBMCP395 0x0CBA
+#define NLS_CS_IBMCP423 0x0CBB
+#define NLS_CS_IBMCP424 0x0CBC
+#define NLS_CS_IBMCP803 0x0CBD
+#define NLS_CS_IBMCP870 0x0CBE
+#define NLS_CS_IBMCP871 0x0CBF
+#define NLS_CS_IBMCP875 0x0CC0
+#define NLS_CS_IBMCP880 0x0CC1
+#define NLS_CS_IBMCP905 0x0CC2
+#define NLS_CS_IBMCP948 0x0CC4
+#define NLS_CS_IBMCP938 0x0CC5
+#define NLS_CS_IBMCP1381 NLS_CS_GB /* 0x0CC8 */
+#define NLS_CS_IBMCP1386 NLS_CS_GB
+#define NLS_CS_EACC 0x0CCB
+#define NLS_CS_ISO2022JP 0x0CCC /* do not use this. use JIS */
+#define NLS_CS_JIS 0x0CCD
+#define NLS_CS_CCCII 0x0CCE
+#define NLS_CS_XEROXCJK 0x0CCF
+#define NLS_CS_IBMCP944 0x0CD1
+#define NLS_CS_IBMCP934 0x0CD2
+#define NLS_CS_IBMCP737 0x0CE0
+#define NLS_CS_IBMCP775 0x0CE1
+#define NLS_CS_ISO6937 0x0CE2
+#define NLS_CS_BASE64 0x0CE3
+#define NLS_CS_JIS2 0x0CE4
+#define NLS_CS_EUCJ 0x0CE5
+#define NLS_CS_EUCT 0x0CE6
+#define NLS_CS_ISOKR 0x0CE7
+#define NLS_CS_EUCK NLS_CS_ISOKR
+#define NLS_CS_EUCC 0x0CE8
+
+#define NLS_CS_IA5JIS 0x0CE9 /* Dummy */
+
+#define NLS_CS_IBMCP921 0x0CEA /* Replacement for Lithuanian */
+#define NLS_CS_IBMCP922 0x0CEB /* More White Russian */
+
+#define NLS_CS_KOI8 0x0CEC /* Cyrillic Internet support */
+#define NLS_CS_IBMCP720 0x0CED
+
+#define NLS_CS_IBMCP1258 0x0CEE /* Windows Vietnamese */
+#define NLS_CS_ISO885910 0x0CEF /* Sami, etc. */
+
+#define NLS_CS_JP1TEXT 0x0CF0 /* OSI/JIS X 5003-1987 X.400 Japanese ISP */
+#define NLS_CS_VIQRI 0x0CF1 /* Vietnamese Quoted Readable*/
+#define NLS_CS_VISCII 0x0CF2 /* Vietnamese VISCII 1.1 */
+#define NLS_CS_VISCII1 0x0CF3 /* TCVN Viet 1 */
+#define NLS_CS_VISCII2 0x0CF4 /* TCVN Viet 2 */
+#define NLS_CS_IBMCP838 0x0CF5
+#define NLS_CS_IBMCP9030 NLS_CS_IBMCP838
+#define NLS_CS_IBMCP833 0x0CF7
+#define NLS_CS_IBMCP836 0x0CFA
+#define NLS_CS_IBMCP1027 0x0CFD
+#define NLS_CS_IBMCP420 0x0CFE
+#define NLS_CS_IBMCP918 0x0CFF
+#define NLS_CS_IBMCP1097 0x0D00
+#define NLS_CS_IBMCP1112 0x0D01
+#define NLS_CS_IBMCP1122 0x0D02
+#define NLS_CS_IBMCP1123 0x0D03
+#define NLS_CS_IBMCP1129 0x0D04
+#define NLS_CS_IBMCP1130 0x0D05
+#define NLS_CS_IBMCP1132 0x0D06
+#define NLS_CS_IBMCP1133 0x0D07
+
+#define NLS_CS_IBMCP806 0x0D08
+#define NLS_CS_IBMCP1137 0x0D09
+#define NLS_CS_VISCII3 0x0D0A /* Vietnamese TCVN3 */
+#define NLS_CS_TCVN3 NLS_CS_VISCII3
+
+#define NLS_CS_IBMCP858 0x0D10 /* Euro: 850 with D5 = Euro */
+#define NLS_CS_IBMCP1140 0x0D11 /* Euro version of CP37 */
+#define NLS_CS_IBMCP1141 0x0D12 /* Euro version of CP273 */
+#define NLS_CS_IBMCP1142 0x0D13 /* Euro version of CP277 */
+#define NLS_CS_IBMCP1143 0x0D14 /* Euro version of CP278 */
+#define NLS_CS_IBMCP1144 0x0D15 /* Euro version of CP280 */
+#define NLS_CS_IBMCP1145 0x0D16 /* Euro version of CP284 */
+#define NLS_CS_IBMCP1146 0x0D17 /* Euro version of CP285 */
+#define NLS_CS_IBMCP1147 0x0D18 /* Euro version of CP297 */
+#define NLS_CS_IBMCP1148 0x0D19 /* Euro version of CP500 */
+#define NLS_CS_IBMCP1149 0x0D1A /* Euro version of CP871 */
+#define NLS_CS_IBMCP924 0x0D1B /* EBCDIC Euro cp */
+#define NLS_CS_ISO88598i 0x0D1C /* logical bidi */
+#define NLS_CS_ISO88598e 0x0D1D /* explicit bidi */
+#define NLS_CS_ISCII 0x0D1E /* ISCII */
+#define NLS_CS_GB18030 0x0D31 /* GB18030 */
+
+/*****************************************************/
+/*** THIS RANGE RESERVED FOR EBCDIC DBCS CODEPAGES ***/
+#define NLS_CS_EBCDICDBCS_START 0x0E00
+
+/* Dual codepages - really these are CCSID's */
+#define NLS_CS_IBMCP930 0x0E00 /* Japan */
+#define NLS_CS_IBMCP933 0x0E01 /* Korea */
+#define NLS_CS_IBMCP935 0x0E02 /* PRC */
+#define NLS_CS_IBMCP937 0x0E03 /* Taiwan */
+#define NLS_CS_IBMCP939 0x0E04 /* Japan */
+#define NLS_CS_IBMCP931 0x0E05 /* PRC */
+#if defined(OS390)
+#define NLS_CS_IBMCP1388 0x0E06 /* PRC */
+#else
+#define NLS_CS_IBMCP1388 NLS_CS_IBMCP935
+#endif
+#define NLS_CS_IBMCP5026 NLS_CS_IBMCP930
+#define NLS_CS_IBMCP5035 NLS_CS_IBMCP939
+
+#define NLS_CS_MIXED_END 0x0E7F
+
+/* DBCS-only */
+#define NLS_CS_IBMCP300 0x0E80 /* Japan */
+#define NLS_CS_IBMCP834 0x0E81 /* Korea */
+#define NLS_CS_IBMCP835 0x0E82 /* Taiwan */
+#define NLS_CS_IBMCP837 0x0E83 /* PRC */
+#define NLS_CS_IBMCP930X 0x0E84 /* Japan */
+#define NLS_CS_IBMCP933X 0x0E85 /* Korea */
+#define NLS_CS_IBMCP935X 0x0E86 /* PRC */
+#define NLS_CS_IBMCP937X 0x0E87 /* Taiwan */
+#define NLS_CS_IBMCP939X 0x0E88 /* Japan */
+#define NLS_CS_IBMCP931X 0x0E89 /* PRC */
+#define NLS_CS_IBMCP1388X NLS_CS_IBMCP935X
+#define NLS_CS_IBMCP1364 0x0E8A /* Korea */
+#define NLS_CS_IBMCP1399 0x0E8B /* Japan */
+
+#define NLS_CS_EBCDICDBCS_END 0x0EFF
+/*****************************************************/
+
+#define NLS_CS_ANYCS 0xFFFE
+#define NLS_CS_NOCS 0xFFFF
+
+
+#endif /* #if !defined(NLS_NOCHARSETIDS) */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* if !defined(NLS_H) */
+
+
+
+
+
+
+
+
+#if defined(OS400) && (__OS400_TGTVRM__ >= 510)
+#pragma datamodel(pop)
+#endif
+
diff --git a/protocols/LotusNotify/src/cnotesapi/include/nsfdata.h b/protocols/LotusNotify/src/cnotesapi/include/nsfdata.h
new file mode 100644
index 0000000000..cf37d6e714
--- /dev/null
+++ b/protocols/LotusNotify/src/cnotesapi/include/nsfdata.h
@@ -0,0 +1,841 @@
+
+#if defined(OS400) && (__OS400_TGTVRM__ >= 510)
+#pragma datamodel(P128)
+#endif
+
+/*********************************************************************/
+/* */
+/* Licensed Materials - Property of IBM */
+/* */
+/* L-GHUS-5VMPGW, L-GHUS-5S3PEE */
+/* (C) Copyright IBM Corp. 1989, 2005 All Rights Reserved */
+/* */
+/* US Government Users Restricted Rights - Use, duplication or */
+/* disclosure restricted by GSA ADP Schedule Contract with */
+/* IBM Corp. */
+/* */
+/*********************************************************************/
+
+
+#ifndef NSF_DATA_DEFS
+#define NSF_DATA_DEFS
+
+#include "pool.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+/* Note Storage File Data Definitions */
+
+/* Define some synonyms for self-documentation of templates */
+
+#define DBHANDLE HANDLE
+#define NOTEHANDLE HANDLE
+#define ITEMDEFTABLEHANDLE HANDLE
+#define ITEMDEFTABLEEXTHANDLE HANDLE
+#define FORMULAHANDLE HANDLE
+typedef void far * HCOMPUTE;
+
+/* Reserved NoteIDs */
+
+#define NOTEID_RESERVED 0x80000000L /* Reserved Note ID, used for
+ categories in NIFReadEntries
+ and for deleted notes in a
+ lot of interfaces. */
+#define NOTEID_ADD 0x00000000L /* Reserved NoteID used as input
+ to NoteUpdate, to add a new
+ note (gets error if UNID assigned
+ to new note already exists). */
+#define NOTEID_ADD_OR_REPLACE 0x80000000L /* Reserved NoteID used as input
+ to NoteUpdate, to update if
+ note UNID already exists, or
+ add note if doesn't exist. */
+#define NOTEID_ADD_UNID 0x80000001L /* Reserved NoteID used as input
+ to NoteUpdate. Try to preserve
+ the specified note UNID, but if
+ it already exists, assign a new
+ one. (Note that the UNID in the
+ hNote IS updated.) */
+#define NOTEID_NULL_FOLDER 0x00000000L /* Used for null folder ids. */
+
+/* An RRV "file position" is defined to be a DWORD, 4 bytes long. */
+
+#define RRV_ALIGNMENT 4L /* most typical RRV alignment (DBTABLE.C) */
+#define RRV_DELETED NOTEID_RESERVED /* indicates a deleted note (DBTABLE.C) */
+
+#define NOTEID_NO_PARENT 0x00000000L /* Reserved Note ID, used to indicate
+ that this note has no parent in the
+ response hierarchy. */
+
+/* This is the structure that identifies a database. It is used for both
+ the creation date/time and the originator date/time. */
+
+typedef TIMEDATE DBID;
+
+/* This is the structure that identifies a note within a database. It is
+ simply a file position (RRV) that is guaranteed never to change WITHIN
+ this file. A replicated note, however, may have a different note id
+ in two separate files. */
+
+typedef DWORD NOTEID;
+
+/* This is the structure that identifies ALL replicas of the same note. The
+ "File" member contains a totally unique (random) number, generated at
+ the time the note is created. The "Note" member contains the date/time
+ when the very first copy of the note was stored into the first NSF. The
+ "Sequence" member is a sequence number used to keep track of the most
+ recent version of the note for replicated data purposes. The
+ "SequenceTime" member is a sequence number qualifier, that allows the
+ replicator to determine which note is later given identical Sequence's.
+ Both are required for the following reason. The sequence number is needed
+ to prevent someone from locking out future edits by setting the time/date
+ to the future. The sequence time qualifies the sequence number for two
+ reasons: 1) It prevents two concurrent updates from looking like
+ no update at all and 2) it forces all systems to reach the same decision
+ as to which update is the "latest" version.
+
+ Time/dates associated with notes:
+
+ OID.Note Can be Timedate when the note was created
+ (but not guaranteed to be - look for $CREATED
+ item first for note creation time)
+ Obtained by NSFNoteGetInfo(_NOTE_OID) or
+ OID in SEARCH_MATCH.
+ OID.SequenceTime Timedate of last revision
+ Obtained by NSFNoteGetInfo(_NOTE_OID) or
+ OID in SEARCH_MATCH.
+ NOTE.EditModified Timedate when added to (or last updated in)
+ this database.
+ (Obtained by NSFNoteGetInfo(_NOTE_MODIFIED) or
+ ID.Note in SEARCH_MATCH.
+
+
+*/
+
+#define MAXSEQNO 0x00FFFFFFL /* Maximum sequence number for a note */
+#define OID_SEQNO_MASK 0x00FFFFFFL /* Mask used to extract sequence # */
+#define OID_NO_REPLICATE 0x80000000L /* Never replicate outward, currently used ONLY for deleted stubs */
+
+typedef struct ORIGINATORID_tag {
+ DBID File; /* Unique (random) number */
+ /* (Even though this field is called "File", */
+ /* it doesn't have anything to do with the file!) */
+ TIMEDATE Note; /* Can be Original Note Creation time/date */
+ /* (see OID.Note comment above) */
+ /* (THE ABOVE 2 FIELDS MUST BE FIRST - UNID */
+ /* COPIED FROM HERE ASSUMED AT OFFSET 0) */
+ DWORD Sequence; /* LOW ORDER: sequence number, 1 for first version */
+ /* HIGH ORDER WORD: flags, as above */
+ TIMEDATE SequenceTime; /* time/date when sequence number was bumped */
+} ORIGINATORID; /* 28 bytes */
+
+#define OID ORIGINATORID
+
+
+/* Replication flags
+
+ NOTE: Please note the distinction between REPLFLG_DISABLE and
+ REPLFLG_NEVER_REPLICATE. The former is used to temporarily disable
+ replication. The latter is used to indicate that this database should
+ NEVER be replicated. The former may be set and cleared by the Notes
+ user interface. The latter is intended to be set programmatically
+ and SHOULD NEVER be able to be cleared by the user interface.
+
+ The latter was invented to avoid having to set the replica ID to
+ the known value of REPLICA_ID_NEVERREPLICATE. This latter method has
+ the failing that DBs that use it cannot have DocLinks to them. */
+
+/* 0x0001 spare was COPY_ACL */
+/* 0x0002 spare */
+#define REPLFLG_DISABLE 0x0004 /* Disable replication */
+#define REPLFLG_UNREADIFFNEW 0x0008 /* Mark unread only if newer note */
+#define REPLFLG_IGNORE_DELETES 0x0010 /* Don't propagate deleted notes when
+ replicating from this database */
+#define REPLFLG_HIDDEN_DESIGN 0x0020 /* UI does not allow perusal of Design */
+#define REPLFLG_DO_NOT_CATALOG 0x0040 /* Do not list in catalog */
+#define REPLFLG_CUTOFF_DELETE 0x0080 /* Auto-Delete documents prior to cutoff date */
+#define REPLFLG_NEVER_REPLICATE 0x0100 /* DB is not to be replicated at all */
+#define REPLFLG_ABSTRACT 0x0200 /* Abstract during replication */
+#define REPLFLG_DO_NOT_BROWSE 0x0400 /* Do not list in database add */
+#define REPLFLG_NO_CHRONOS 0x0800 /* Do not run chronos on database */
+#define REPLFLG_IGNORE_DEST_DELETES 0x1000 /* Don't replicate deleted notes
+ into destination database */
+#define REPLFLG_MULTIDB_INDEX 0x2000 /* Include in Multi Database indexing */
+#define REPLFLG_PRIORITY_LOW 0xC000 /* Low priority */
+#define REPLFLG_PRIORITY_MED 0x0000 /* Medium priority */
+#define REPLFLG_PRIORITY_HI 0x4000 /* High priority */
+#define REPLFLG_PRIORITY_SHIFT 14 /* Shift count for priority field */
+#define REPLFLG_PRIORITY_MASK 0x0003 /* Mask for priority field after shifting*/
+#define REPLFLG_PRIORITY_INVMASK 0x3fff /* Mask for clearing the field */
+#define REPLFLG_USED_MASK (0x4|0x8|0x10|0x40|0x80|0x100|0x200|0xC000|0x1000|0x2000|0x4000)
+
+
+/* Replication priority values are stored in the high bits of the
+ replication flags. The stored value is biased by -1 so that
+ an encoding of 0 represents medium priority (-1 is low and +1 is high).
+ The following macros make getting and setting the priority easy.
+ They return and accept normalized values of 0 - 2. */
+
+#define REPL_GET_PRIORITY(Flags) \
+ (((Flags >> REPLFLG_PRIORITY_SHIFT)+1) & REPLFLG_PRIORITY_MASK)
+#define REPL_SET_PRIORITY(Pri) \
+ (((Pri - 1) & REPLFLG_PRIORITY_MASK) << REPLFLG_PRIORITY_SHIFT)
+
+/* Reserved ReplicaID.Date. Used in ID.Date field in ReplicaID to escape
+ to reserved REPLICA_ID_xxx
+*/
+#define REPLICA_DATE_RESERVED 0 /* If used, see REPLICA_ID_xxx */
+
+/* Known Replica IDs. Used in ID.Time field in ReplicaID. Date
+ subfield must be REPLICA_DATE_RESERVED). NOTE: If you add to this list,
+ you should check the code in \catalog\search.c to see if the new one(s)
+ need to be added to that code (probably not - but worth checking).
+
+ The format is as follows. Least sig. byte is version number. 2nd
+ byte represents package code but is hard-coded to protect against
+ changes in the package code. Most sig. 2 bytes are reserved for future
+ use.
+*/
+#define REPLICA_ID_UNINITIALIZED 0x00000000 /* Uninitialized ID */
+#define REPLICA_ID_CATALOG 0x00003301 /* Database Catalog (Version 2) */
+#define REPLICA_ID_EVENT 0x00003302 /* Stats & Events Config DB */
+
+
+/* The following known replica ID is now obsolete. Although the replicator
+ still supports it, the problem is that DBs that use it cannot have
+ DocLinks to them. Instead use the replica flag REPLFLG_NEVER_REPLICATE. */
+#define REPLICA_ID_NEVERREPLICATE 0x00001601 /* Do not allow replicas */
+
+/* Number of times within cutoff interval that we purge deleted stubs.
+ For example, if the cutoff interval is 90 days, we purge every 30
+ days. */
+
+#define CUTOFF_CHANGES_DURING_INTERVAL 3
+
+/* This is the structure that identifies a replica database. */
+
+typedef struct {
+ TIMEDATE ID; /* ID that is same for all replica files */
+ WORD Flags; /* Replication flags */
+ WORD CutoffInterval; /* Automatic Replication Cutoff Interval (Days) */
+ TIMEDATE Cutoff; /* Replication cutoff date */
+} DBREPLICAINFO;
+
+
+typedef struct {
+ DWORD WarningThreshold; /* Database size warning threshold in kbyte units */
+ DWORD SizeLimit; /* Database size limit in kbyte units */
+ DWORD CurrentDbSize; /* Current size of database (in kbyte units) */
+ DWORD MaxDbSize; /* Max database file size possible (in kbyte units) */
+} DBQUOTAINFO;
+
+typedef struct {
+ DWORD WarningThreshold; /* Database size warning threshold in kbyte units */
+ DWORD SizeLimit; /* Database size limit in kbyte units */
+ DWORD CurrentDbSize; /* Current size of database (in kbyte units) */
+ DWORD MaxDbSize; /* Max database file size possible (in kbyte units) */
+ WORD QuotaMethod; /* Enforcement method - filesize or usage */
+ DWORD CurrentUsage; /* Current amount of space used in the database (in kbyte units) */
+ DWORD CurrentSizeUsed; /* Either CurrentDbSize, or CurrentUsage, depending on method in use */
+ DWORD Unused1; /* Reserved. Unused */
+ DWORD Unused2; /* Reserved. Unused */
+} DBQUOTAINFOEXT;
+
+
+/* This is the structure that globally identifies an INSTANCE of a note,
+ that is, if we are doing a SEARCH_ALL_VERSIONS, the one with the
+ latest modification date is the one that is the "most recent" instance. */
+
+typedef struct {
+ DBID File; /* database Creation time/date */
+ TIMEDATE Note; /* note Modification time/date */
+ NOTEID NoteID; /* note ID within database */
+} GLOBALINSTANCEID;
+
+/* This is the structure that universally (across all servers) describes
+ a note (ALL INSTANCES of the same note), but without the information
+ necessary to directly access the note in a given database. It is used
+ for referencing a specific note from another note (response notes and
+ hot buttons are examples of its use) by storing this structure in the
+ referencing note itself. It is intended to work properly on any server,
+ and even if the note being referenced is updated. Matching of notes
+ to other notes is done via the NIF machinery. */
+
+typedef struct UNIVERSALNOTEID_tag {
+ DBID File; /* Unique (random) number */
+ /* (Even though this field is called "File", */
+ /* it doesn't have anything to do with the file!) */
+ TIMEDATE Note; /* Can be Original Note Creation time/date */
+ /* (see OID.Note comment above) */
+} UNIVERSALNOTEID;
+
+#define UNID UNIVERSALNOTEID
+
+/* This is the structure that universally (across all servers) describes
+ a note LINK. */
+
+typedef struct {
+ TIMEDATE File; /* File's replica ID */
+ UNID View; /* View's Note Creation TIMEDATE */
+ UNID Note; /* Note's Creation TIMEDATE */
+} NOTELINK;
+
+
+/* Data Type Definitions. */
+
+
+/* Class definitions. Classes are defined to be the
+ "generic" classes of data type that the internal formula computation
+ mechanism recognizes when doing recalcs. */
+
+#define CLASS_NOCOMPUTE (0 << 8)
+#define CLASS_ERROR (1 << 8)
+#define CLASS_UNAVAILABLE (2 << 8)
+#define CLASS_NUMBER (3 << 8)
+#define CLASS_TIME (4 << 8)
+#define CLASS_TEXT (5 << 8)
+#define CLASS_FORMULA (6 << 8)
+#define CLASS_USERID (7 << 8)
+
+#define CLASS_MASK 0xff00
+
+/* All datatypes below are passed to NSF in either host (machine-specific
+ byte ordering and padding) or canonical form (Intel 86 packed form).
+ The format of each datatype, as it is passed to and from NSF functions,
+ is listed below in the comment field next to each of the data types.
+ (This host/canonical issue is NOT applicable to Intel86 machines,
+ because on that machine, they are the same and no conversion is required).
+ On all other machines, use the ODS subroutine package to perform
+ conversions of those datatypes in canonical format before they can
+ be interpreted. */
+
+/* "Computable" Data Types */
+
+#define TYPE_ERROR 0 + CLASS_ERROR /* Host form */
+#define TYPE_UNAVAILABLE 0 + CLASS_UNAVAILABLE /* Host form */
+#define TYPE_TEXT 0 + CLASS_TEXT /* Host form */
+#define TYPE_TEXT_LIST 1 + CLASS_TEXT /* Host form */
+#define TYPE_NUMBER 0 + CLASS_NUMBER /* Host form */
+#define TYPE_NUMBER_RANGE 1 + CLASS_NUMBER /* Host form */
+#define TYPE_TIME 0 + CLASS_TIME /* Host form */
+#define TYPE_TIME_RANGE 1 + CLASS_TIME /* Host form */
+#define TYPE_FORMULA 0 + CLASS_FORMULA /* Canonical form */
+#define TYPE_USERID 0 + CLASS_USERID /* Host form */
+
+/* "Non-Computable" Data Types */
+
+#define TYPE_INVALID_OR_UNKNOWN 0 + CLASS_NOCOMPUTE /* Host form */
+#define TYPE_COMPOSITE 1 + CLASS_NOCOMPUTE /* Canonical form, >64K handled by more than one item of same name concatenated */
+#define TYPE_COLLATION 2 + CLASS_NOCOMPUTE /* Canonical form */
+#define TYPE_OBJECT 3 + CLASS_NOCOMPUTE /* Canonical form */
+#define TYPE_NOTEREF_LIST 4 + CLASS_NOCOMPUTE /* Host form */
+#define TYPE_VIEW_FORMAT 5 + CLASS_NOCOMPUTE /* Canonical form */
+#define TYPE_ICON 6 + CLASS_NOCOMPUTE /* Canonical form */
+#define TYPE_NOTELINK_LIST 7 + CLASS_NOCOMPUTE /* Host form */
+#define TYPE_SIGNATURE 8 + CLASS_NOCOMPUTE /* Canonical form */
+#define TYPE_SEAL 9 + CLASS_NOCOMPUTE /* Canonical form */
+#define TYPE_SEALDATA 10 + CLASS_NOCOMPUTE /* Canonical form */
+#define TYPE_SEAL_LIST 11 + CLASS_NOCOMPUTE /* Canonical form */
+#define TYPE_HIGHLIGHTS 12 + CLASS_NOCOMPUTE /* Host form */
+#define TYPE_WORKSHEET_DATA 13 + CLASS_NOCOMPUTE /* Used ONLY by Chronicle product */
+ /* Canonical form */
+#define TYPE_USERDATA 14 + CLASS_NOCOMPUTE /* Arbitrary format data - see format below */
+ /* Canonical form */
+#define TYPE_QUERY 15 + CLASS_NOCOMPUTE /* Saved query CD records; Canonical form */
+#define TYPE_ACTION 16 + CLASS_NOCOMPUTE /* Saved action CD records; Canonical form */
+#define TYPE_ASSISTANT_INFO 17 + CLASS_NOCOMPUTE /* Saved assistant info */
+#define TYPE_VIEWMAP_DATASET 18 + CLASS_NOCOMPUTE /* Saved ViewMap dataset; Canonical form */
+#define TYPE_VIEWMAP_LAYOUT 19 + CLASS_NOCOMPUTE /* Saved ViewMap layout; Canonical form */
+#define TYPE_LSOBJECT 20 + CLASS_NOCOMPUTE /* Saved LS Object code for an agent. */
+#define TYPE_HTML 21 + CLASS_NOCOMPUTE /* LMBCS-encoded HTML, >64K handled by more than one item of same name concatenated */
+#define TYPE_SCHED_LIST 22 + CLASS_NOCOMPUTE /* Busy time schedule entries list; Host form */
+#define TYPE_CALENDAR_FORMAT 24 + CLASS_NOCOMPUTE /* Canonical form */
+#define TYPE_MIME_PART 25 + CLASS_NOCOMPUTE /* MIME body part; Canonical form */
+#define TYPE_RFC822_TEXT 2 + CLASS_TEXT /* RFC822( RFC2047) message header; Canonical form */
+
+/* This is the structure used for summary buffers */
+
+typedef struct {
+ USHORT Length; /* total length of this buffer */
+ USHORT Items; /* number of items in the table */
+ /* now come the ITEMs */
+ /* now comes the packed text */
+} ITEM_TABLE;
+
+typedef struct { /* used for item names and values */
+ USHORT NameLength; /* length of the item's name */
+ USHORT ValueLength; /* length of the value field */
+} ITEM;
+
+typedef struct {
+ USHORT Length; /* total length of this buffer */
+ USHORT Items; /* number of items in the table */
+ /* now comes an array of WORDS representing
+ the lengths of the item names. */
+ /* now comes the item names as packed text */
+} ITEM_NAME_TABLE;
+
+typedef struct {
+ USHORT Length; /* total length of this buffer */
+ USHORT Items; /* number of items in the table */
+ /* now comes an array of WORDS representing
+ the lengths of the item values. */
+ /* now comes the item values as packed bytes */
+} ITEM_VALUE_TABLE;
+
+/* Here is the format of the various LIST data types:
+
+ TYPE_TEXT_LIST:
+
+ LIST * list header *
+ USHORT ... * array of text string lengths following *
+ text * now comes the packed text for all strings *
+
+ TYPE_NUMBER_RANGE:
+
+ RANGE * range header *
+ NUMBER ... * array of NUMBERs *
+ NUMBER_PAIR ... * array of NUMBER_PAIRs *
+
+ TYPE_TIME_RANGE:
+
+ RANGE * range header *
+ TIMEDATE ... * array of time/date's *
+ TIMEDATE_PAIR ... * array of time/date pairs *
+
+ TYPE_NOTEREF_LIST:
+
+ LIST * list header *
+ UNIVERSALNOTEID * array of UNIVERSALNOTEIDs *
+
+
+ TYPE_NOTELINK_LIST:
+
+ LIST * list header *
+ NOTELINK * array of NOTELINKs *
+
+ TYPE_USERDATA:
+
+ BYTE Length * length of LMBCS "format-name" string *
+ char[Length]; * LMBCS "format-name" string used to distinguish *
+ * various formats of user data that follows. *
+ * ("format-name" string is NOT NULL-TERMINATED!) *
+ data * next is variable-length data that corresponds *
+ * to the format specified by the string *
+
+*/
+
+/* This is the data structure used for TYPE_OBJECT values */
+
+typedef struct {
+ WORD ObjectType; /* Type of object (OBJECT_xxx) */
+ DWORD RRV; /* Object ID of the object in THIS FILE */
+} OBJECT_DESCRIPTOR;
+
+/* These must be OR-ed into the ObjectType below in order to get the
+ desired behavior. Note that OBJECT_COLLECTION implicitly has
+ both of these bits implied, because that was the desired behavior
+ before these bits were invented. */
+
+#define OBJECT_NO_COPY 0x8000 /* do not copy object when updating to new note or database */
+#define OBJECT_PRESERVE 0x4000 /* keep object around even if hNote doesn't have it when NoteUpdating */
+#define OBJECT_PUBLIC 0x2000 /* Public access object being allocated. */
+
+/* Object Types, a sub-category of TYPE_OBJECT */
+
+#define OBJECT_FILE 0 /* File Attachment */
+#define OBJECT_FILTER_LEFTTODO 3 /* IDTable of "done" docs attached to filter */
+#define OBJECT_ASSIST_RUNDATA 8 /* Assistant run data object */
+#define OBJECT_UNKNOWN 0xffff /* Used as input to NSFDbGetObjectSize */
+
+/* File Attachment definitions */
+
+#define HOST_MASK 0x0f00 /* used for NSFNoteAttachFile Encoding arg */
+#define HOST_MSDOS (0 << 8)/* CRNL at EOL, optional ^Z at EOF */
+#define HOST_OLE (1 << 8)/* unknown internal representation, up to app */
+#define HOST_MAC (2 << 8)/* potentially has resource forks, etc. */
+#define HOST_UNKNOWN (3 << 8)/* came inbound thru a gateway */
+#define HOST_HPFS (4 << 8)/* HPFS. Contains EAs and long filenames */
+#define HOST_OLELIB (5 << 8)/* OLE 1 Library encapsulation */
+#define HOST_BYTEARRAY_EXT (6 << 8)/* OLE 2 ILockBytes byte array extent table */
+#define HOST_BYTEARRAY_PAGE (7 << 8)/* OLE 2 ILockBytes byte array page */
+#define HOST_CDSTORAGE (8 << 8)/* externally stored CD records */
+#define HOST_STREAM (9 << 8)/* Binary private stream */
+#define HOST_LINK (10 << 8)/* contains a RESOURCELINK to a named element */
+
+#define HOST_LOCAL 0x0f00 /* ONLY used as argument to NSFNoteAttachFile */
+ /* means "use MY os's HOST_ type */
+
+#define EFLAGS_MASK 0xf000 /* used for NSFNoteAttachFile encoding arg */
+#define EFLAGS_INDOC 0x1000 /* used to pass FILEFLAG_INDOC flag to NSFNoteAttachFile */
+#define EFLAGS_KEEPPATH 0x2000 /* don't strip off path in the filename */
+
+/* changed below from 0x00ff to 0x000f to make room for flags defined below */
+#define COMPRESS_MASK 0x000f /* used for NSFNoteAttachFile Encoding arg */
+#define COMPRESS_NONE 0 /* no compression */
+#define COMPRESS_HUFF 1 /* huffman encoding for compression */
+#define COMPRESS_LZ1 2 /* LZ1 compression */
+#define RECOMPRESS_HUFF 3 /* Huffman compression even if server supports LZ1 */
+
+#define NTATT_FTYPE_MASK 0x0070 /* File type mask */
+#define NTATT_FTYPE_FLAT 0x0000 /* Normal one fork file */
+#define NTATT_FTYPE_MACBIN 0x0010 /* MacBinaryII file */
+#define NTATT_FTYPE_EBCDIC 0x0020 /* EBCDIC flat file */
+#define NTATT_NODEALLOC 0x0080 /* Don't deallocate object when item is deleted */
+
+#define ATTRIB_READONLY 0x0001 /* file was read-only */
+#define ATTRIB_PRIVATE 0x0002 /* file was private or public */
+
+#define FILEFLAG_SIGN 0x0001 /* file object has object digest appended */
+#define FILEFLAG_INDOC 0x0002 /* file is represented by an editor run in the document */
+#define FILEFLAG_MIME 0x0004 /* file object has mime data appended */
+ /* and NSFDbGetObjectInfo, NSFDbCopyObject. */
+#define ENCODE_MASK 0x0038 /* file object has mime content transfer encoding */
+#define ENCODE_NONE (0 << 3)/* no encoding */
+#define ENCODE_BASE64 (1 << 3)/* base64 encoding */
+#define ENCODE_QP (2 << 3)/* quoted-printable encoding */
+#define ENCODE_UUENCODE (3 << 3)/* x-uuencode encoding */
+#define ENCODE_EXTENSION (4 << 3)/* unknown extension encoding */
+
+typedef struct {
+ OBJECT_DESCRIPTOR Header; /* object header */
+ WORD FileNameLength; /* length of file name */
+ WORD HostType; /* identifies type of text file delimeters (HOST_) */
+ WORD CompressionType; /* compression technique used (COMPRESS_) */
+ WORD FileAttributes; /* original file attributes (ATTRIB_) */
+ WORD Flags; /* miscellaneous flags (FILEFLAG_, ENCODE_) */
+ DWORD FileSize; /* original file size */
+ TIMEDATE FileCreated; /* original file date/time of creation, 0 if unknown */
+ TIMEDATE FileModified; /* original file date/time of modification */
+ /* Now comes the file name... It is the original */
+ /* RELATIVE file path with no device specifiers */
+} FILEOBJECT;
+
+typedef struct {
+ char FileCreator[4]; /* application that created the file */
+ char FileType[4]; /* type of file */
+ DWORD ResourcesStart; /* offset into the object at which resources begin */
+ DWORD ResourcesLen; /* length of the resources section in bytes */
+ WORD CompressionType; /* compression used for Mac resources */
+ DWORD Spare; /* 0 */
+} FILEOBJECT_MACEXT;
+
+typedef struct {
+ DWORD EAStart; /* offset into the object at which EAs begin */
+ DWORD EALen; /* length of EA section */
+ DWORD Spare; /* 0 */
+} FILEOBJECT_HPFSEXT;
+
+
+/* @SPECIAL Escape Codes */
+
+#define ESCBEGIN 0x7f
+#define ESCEND 0xff
+
+/* Index information structure passed into NSFTranslateSpecial to provide
+ index-related information for certain @INDEX functions, if specified. */
+
+
+typedef struct
+ {
+ DWORD IndexSiblings; /* # siblings of entry */
+ DWORD IndexChildren; /* # direct children of entry */
+ DWORD IndexDescendants; /* # descendants of entry */
+ WORD IndexAnyUnread; /* TRUE if entry "unread, or any descendants "unread" */
+ } INDEXSPECIALINFO;
+
+/* Calendar busy time schedule list structure */
+
+/* These are application ID's for the SCHED_LIST wApplicationID field.
+** This is used to interpret the application specific UserAttr field.
+** Notes ignores the UserAttr field, however application specific
+** information can be returned by application specific gateways.
+** If you need an ID, please register it with Lotus.
+*/
+#define SCHEDAPPLID_ORGANIZER2X 0x0001
+#define SCHEDAPPLID_ORGANIZER4X 0x0002
+#define SCHEDAPPLID_OV 0x0003
+
+
+/* Define the maximum number of schedule entries allowed per note item.
+** Calculated from maximum size of a note item (MAXONESEGSIZE) minus the size
+** of a sched list, divided by the size of a sched entry. Subtract 100 of
+** the number for some breathing room.
+**
+** The SCHED_LIST and SCHED_ENTRY are the preR6 data types. For R6 we used
+** the SCHED_LIST.Spare value to convey the length of the SCHED_ENTRY_EXT
+** data that follows. If .Spare is 0, the data that follows is SCHED_ENTRY,
+** NOT SCHED_ENTRY_EXT.
+** Now that we convey the length of each SCHED_ENTRY_EXT that follows (R6 and
+** later), we can easily extend SCHED_ENTRY_EXT w/o adversely affecting
+** previous clients since from R6 on the clients should be using
+** SCHED_LIST.Spare to do pointer shifts. For example, say in R7 we add
+** even more info to SCHED_ENTRY_EXT, we simply append it to the R6 definition
+** and adjust SCHED_LIST.Spare to reflect the new size. That way an R6 client
+** can get the info it needs/wants and can skip the 'newer' data that it
+** has no way of properly using/processing.
+**
+** Note: If the SCHED_LIST.Spare is 0 then a SCHED_ENTRY MUST follow.
+** If the SCHED_LIST.Spare is non-0 then a SCHED_ENTRY_EXT MUST follow.
+**
+** We are NOT allowing mixing of data types since it would only cause confusion
+** for older users! The system will return SCHED_LIST/SCHED_ENTRY data if it
+** detects that the caller is using the preR6 API calls (or is using the R6
+** API calls with a "preR6" flag to indicate old API call in use).
+*/
+
+#define MAXSCHEDLISTSIZE (MAXONESEGSIZE - 100 * sizeof(SCHED_ENTRY))
+#define MAXENTRIESPERSCHEDLIST ((MAXSCHEDLISTSIZE - sizeof (SCHED_LIST)) / sizeof(SCHED_ENTRY))
+
+typedef struct {
+ ALIGNED_NUMBER nLongitude; /* Longitude coordinate value */
+ ALIGNED_NUMBER nLatitude; /* Latitude coordinate value */
+} GEO_INFO;
+
+/* Scheduling list header */
+
+typedef struct {
+ DWORD NumEntries; /* Total number of schedule entries follow */
+ WORD wApplicationID; /* application id for UserAttr interpretation */
+ WORD Spare; /* PreR6: spare
+ ** R6: This now conveys the length of a single
+ ** SCHED_ENTRY_xxx that follows. Use this value
+ ** to skip entries that MAY be larger (ie: R7
+ ** extends SCHED_ENTRY_EXT by appending values
+ ** that R6 does not know about so SCHED_ENTRY_xxx
+ ** would actually be larger than the R6
+ ** SCHED_ENTRY_EXT
+ */
+ /* Now come the schedule entries...
+ ** IFF Spare==0 then SCHED_ENTRYs follow
+ ** Otherwise Spare==the length of the
+ ** SCHED_ENTRY_EXTs that follow
+ */
+} SCHED_LIST;
+
+/* Scheduling busy time entry */
+
+typedef struct {
+ UNID Unid; /* UNID of the entry */
+ TIMEDATE_PAIR Interval; /* Interval of the entry */
+ BYTE Attr; /* SCHED_ATTR_xxx attributes defined by Notes */
+ BYTE UserAttr; /* Application specific attributes */
+ BYTE spare[2];
+} SCHED_ENTRY;
+
+/* R6 scheduling busy time entry */
+
+typedef struct {
+ UNID Unid; /* UNID of the entry */
+ TIMEDATE_PAIR Interval; /* Interval of the entry */
+ BYTE Attr; /* SCHED_ATTR_xxx attributes defined by Notes */
+ BYTE UserAttr; /* Application specific attributes */
+ BYTE spare[2];
+
+ /* Everything above this point is the same as SCHED_ENTRY for preR6 clients!
+ ** Everything from here on down is R6 (or later) only!
+ */
+
+ UNID ApptUnid; /* ApptUNID of the entry */
+ DWORD dwEntrySize;/* Size of this entry (for future ease of expansion) */
+ GEO_INFO GEOInfo; /* Geographical coordinates of the entry */
+} SCHED_ENTRY_EXT;
+
+/* R6 Detailed busytime information is harvested and stored in a fairly
+** compact manner thanks to length encoding of everything. The format
+** is basically:
+**
+** SCHED_DETAIL_LIST (Detail list prefix header)
+** TEXT_LIST (of items that harvested and whose info follows)
+** SCHED_DETAIL_ENTRY (Actual harvested info per UNID)
+**
+** Since it may be desirable in the future to extend the detail format
+** the SCHED_DETAIL_xxx structures are length encoded. Any additional
+** SCHED_DETAIL_LIST (or 'overhead') extensions MUST be inserted between
+** the TEXT_LIST and the SCHED_DETAIL_ENTRY. Any additional
+** SCHED_DETAIL_ENTRY extensions MUST be inserted at the end of the
+** structure so that they can easily be trimmed off by older clients.
+**
+** Minor clarification for those nitpickers out there, the SCHED_DETAIL_ENTRY
+** is NOT just a single struct but is really composed of 2 parts, a
+** 'prefix' that contains all info common to that detail (ie: entry
+** UNID or flags) and then the actual data in an encoded form. That
+** form is described in greater detail below. A hierarchical view
+** of how the data is organzied (where indenting is used to
+** semi-convey 'containment') when 3 items are harvested for 2 UNIDs
+** would be:
+**
+** SCHED_DETAIL_LIST (Detail list header)
+** TEXT_LIST (of 3 item names that were harvested)
+** SCHED_DETAIL_ENTRY (Actual harvested info for UNID1)
+** SCHED_DETAIL_DATA (Actual item data)
+** SCHED_DETAIL_DATA (Actual item data)
+** SCHED_DETAIL_DATA (Actual item data)
+** SCHED_DETAIL_ENTRY (Actual harvested info for UNID2)
+** SCHED_DETAIL_DATA (Actual item data)
+** SCHED_DETAIL_DATA (Actual item data)
+** SCHED_DETAIL_DATA (Actual item data)
+**
+*/
+
+/* Flags used on SCHED_DETAIL_LIST */
+
+#define SCHED_DETAIL_LIST_ATTR_NODATA 0x01 /* List has no data */
+#define SCHED_DETAIL_LIST_ATTR_RESERVED2 0x02
+#define SCHED_DETAIL_LIST_ATTR_RESERVED3 0x04
+#define SCHED_DETAIL_LIST_ATTR_RESERVED4 0x08
+#define SCHED_DETAIL_LIST_ATTR_RESERVED5 0x10
+#define SCHED_DETAIL_LIST_ATTR_RESERVED6 0x20
+#define SCHED_DETAIL_LIST_ATTR_RESERVED7 0x40
+#define SCHED_DETAIL_LIST_ATTR_RESERVED8 0x80
+
+/* R6 Schedule detail list header */
+
+typedef struct {
+ WORD wHeaderLen; /* Length of THIS header, in case it
+ ** ever grows, so that new items can be
+ ** easily skipped
+ */
+ WORD wEntryLen; /* Length of THIS entire list and ALL of
+ ** its related data.
+ */
+ WORD wNumEntries; /* Number of entries that follow */
+ WORD wOffsetItems; /* Offset from list start to TEXT_LIST */
+ WORD wOffsetDetails; /* Offset from list start to SCHED_DETAIL_ENTRY */
+ BYTE Attr; /* SCHED_DETAIL_LIST_ATTR_xxx attributes */
+ BYTE bReserved; /* Reserved space/padding for ODS */
+
+ /* Now comes the TEXT_LIST that corresponds to the item names
+ ** and then comes the SCHED_DETAIL_ENTRY for each UNID
+ */
+} SCHED_DETAIL_LIST;
+
+/* Flags used on SCHED_DETAIL_ENTRY */
+
+#define SCHED_DETAIL_ENTRY_ATTR_PRIVATE 0x01 /* Entry is private */
+#define SCHED_DETAIL_ENTRY_ATTR_RESERVED2 0x02
+#define SCHED_DETAIL_ENTRY_ATTR_RESERVED3 0x04
+#define SCHED_DETAIL_ENTRY_ATTR_RESERVED4 0x08
+#define SCHED_DETAIL_ENTRY_ATTR_RESERVED5 0x10
+#define SCHED_DETAIL_ENTRY_ATTR_RESERVED6 0x20
+#define SCHED_DETAIL_ENTRY_ATTR_RESERVED7 0x40
+#define SCHED_DETAIL_ENTRY_ATTR_RESERVED8 0x80
+
+/* R6 Schedule detail list entry */
+
+typedef struct {
+ WORD wPrefixLen; /* Length of THIS prefix entry, in case it
+ ** ever grows, so that new items can be
+ ** easily skipped
+ */
+ WORD wEntryLen; /* Length of THIS entire entry and ALL of
+ ** its related data.
+ */
+ UNID Unid; /* UNID of the entry this is details of */
+ WORD wOffsetDetails; /* Offset from entry start to actual data */
+ BYTE Attr; /* SCHED_DETAIL_ENTRY_ATTR_xxx attributes (TBD) */
+ BYTE bReserved; /* Reserved space/padding for ODS */
+
+ /* Now comes the data that corresponds to the item values (1 per item name)
+ ** UNLESS dwEntryLen == wPrefixLen (which means NO details available
+ ** for this UNID)
+ */
+} SCHED_DETAIL_ENTRY;
+
+/* Flags used on SCHED_DETAIL_DATA */
+
+#define SCHED_DETAIL_DATA_ATTR_TRUNCATED 0x01 /* Used to indicate value is trunated */
+#define SCHED_DETAIL_DATA_ATTR_NOTFOUND 0x02 /* Item/value not found */
+#define SCHED_DETAIL_DATA_ATTR_RESERVED3 0x04
+#define SCHED_DETAIL_DATA_ATTR_RESERVED4 0x08
+#define SCHED_DETAIL_DATA_ATTR_RESERVED5 0x10
+#define SCHED_DETAIL_DATA_ATTR_RESERVED6 0x20
+#define SCHED_DETAIL_DATA_ATTR_RESERVED7 0x40
+#define SCHED_DETAIL_DATA_ATTR_RESERVED8 0x80
+
+/* R6 Schedule detail list actual data */
+
+typedef struct {
+ WORD wType; /* Notes data type for the data */
+ WORD wDataLen; /* Length of the data that immediately follows */
+ BYTE Attr; /* SCHED_DETAIL_DATA_ATTR_xxx attributes */
+ BYTE bReserved; /* Reserved space/padding for ODS */
+
+ /* Now comes the actual data that corresponds to the item values */
+} SCHED_DETAIL_DATA;
+
+/* Since we have new structs for R6, we have to have new MAXSCHEDxxx values */
+
+#define MAXSCHEDLISTEXTSIZE ( MAXONESEGSIZE - 100 * sizeof(SCHED_ENTRY_EXT) )
+#define MAXENTRIESPERSCHEDLISTEXT ( ( MAXSCHEDLISTEXTSIZE - sizeof(SCHED_LIST) ) / sizeof(SCHED_ENTRY_EXT) )
+
+/* The Attr field contains these bits. Note that if bit3 is set
+** then the entry will take up busy time.
+** The lower nibble of the attributes defines the the entry type.
+** NOTE: We are reserving the upper 4 bits of the Attr field for future use.
+
+*/
+#define SCHED_ATTR_FOREIGN_UNID 0x10 /* Used by gateways to return foreign UNIDs */
+#define SCHED_ATTR_REPEAT_EVENT 0x20 /* Used by V5 C&S to identify new repeating meetings */
+#define SCHED_ATTR_RESERVED4 0x40
+#define SCHED_ATTR_RESERVED8 0x80
+
+/* these are the entry type bits */
+#define SCHED_ATTR_TYPE_BITS 0x0F
+#define SCHED_ATTR_FREE_BASE 0x00
+#define SCHED_ATTR_BUSY_BASE 0x08
+
+/* Entry types that don't block off busy time */
+#define SCHED_ATTR_NULL (SCHED_ATTR_FREE_BASE + 0x00)
+#define SCHED_ATTR_PENCILED (SCHED_ATTR_FREE_BASE + 0x01)
+#define SCHED_ATTR_FREE_RESERVED2 (SCHED_ATTR_FREE_BASE + 0x02)
+#define SCHED_ATTR_FREE_RESERVED3 (SCHED_ATTR_FREE_BASE + 0x03)
+#define SCHED_ATTR_FREE_RESERVED4 (SCHED_ATTR_FREE_BASE + 0x04)
+#define SCHED_ATTR_FREE_RESERVED5 (SCHED_ATTR_FREE_BASE + 0x05)
+#define SCHED_ATTR_FREE_RESERVED6 (SCHED_ATTR_FREE_BASE + 0x06)
+#define SCHED_ATTR_FREE_RESERVED7 (SCHED_ATTR_FREE_BASE + 0x07)
+
+/* Entry types that block off busy time */
+#define SCHED_ATTR_APPT (SCHED_ATTR_BUSY_BASE + 0x00)
+#define SCHED_ATTR_NONWORK (SCHED_ATTR_BUSY_BASE + 0x01)
+#define SCHED_ATTR_BUSY_RESERVED2 (SCHED_ATTR_BUSY_BASE + 0x02)
+#define SCHED_ATTR_BUSY_RESERVED3 (SCHED_ATTR_BUSY_BASE + 0x03)
+#define SCHED_ATTR_BUSY_RESERVED4 (SCHED_ATTR_BUSY_BASE + 0x04)
+#define SCHED_ATTR_BUSY_RESERVED5 (SCHED_ATTR_BUSY_BASE + 0x05)
+#define SCHED_ATTR_BUSY_RESERVED6 (SCHED_ATTR_BUSY_BASE + 0x06)
+#define SCHED_ATTR_BUSY_RESERVED7 (SCHED_ATTR_BUSY_BASE + 0x07)
+
+
+#define SCHED_ATTR_TYPE(attr) ((attr) & SCHED_ATTR_TYPE_BITS)
+#define SCHED_ATTR_AVAILABLE(attr) (!((attr) & SCHED_ATTR_BUSY_BASE))
+
+
+/* Function templates */
+
+
+STATUS LNPUBLIC NSFTranslateSpecial(void far *InputString,
+ WORD InputStringLength,
+ void far *OutputString,
+ WORD OutputStringBufferLength,
+ NOTEID NoteID,
+ void far *IndexPosition,
+ INDEXSPECIALINFO far *IndexInfo,
+ HANDLE hUnreadList,
+ HANDLE hCollapsedList,
+ char far *FileTitle,
+ char far *ViewTitle,
+ WORD far *retLength);
+
+/* End of Note Storage File Data Definitions */
+
+#ifdef __cplusplus
+}
+#endif
+
+
+#endif
+
+#if defined(OS400) && (__OS400_TGTVRM__ >= 510)
+#pragma datamodel(pop)
+#endif
+
diff --git a/protocols/LotusNotify/src/cnotesapi/include/nsfdb.h b/protocols/LotusNotify/src/cnotesapi/include/nsfdb.h
new file mode 100644
index 0000000000..2978ab8178
--- /dev/null
+++ b/protocols/LotusNotify/src/cnotesapi/include/nsfdb.h
@@ -0,0 +1,924 @@
+
+#if defined(OS400) && (__OS400_TGTVRM__ >= 510)
+#pragma datamodel(P128)
+#endif
+
+/*********************************************************************/
+/* */
+/* Licensed Materials - Property of IBM */
+/* */
+/* L-GHUS-5RWNHM, L-GHUS-5RWNFH */
+/* (C) Copyright IBM Corp. 1989, 2005 All Rights Reserved */
+/* */
+/* US Government Users Restricted Rights - Use, duplication or */
+/* disclosure restricted by GSA ADP Schedule Contract with */
+/* IBM Corp. */
+/* */
+/*********************************************************************/
+
+
+#ifndef NSF_DB_DEFS
+#define NSF_DB_DEFS
+
+#ifndef NSF_DEFS
+#include "nsfdata.h"
+#endif
+
+#ifndef EVENT_DEFS
+#include "event.h"
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+/* Note Storage File Database Definitions */
+
+/* NSF File Information Buffer size. This buffer is defined to contain
+ Text (host format) that is NULL-TERMINATED. This is the ONLY null-terminated
+ field in all of NSF. */
+
+#define NSF_INFO_SIZE 128
+#define NSF_INFO_WILD_CARD_SERVER_CHAR '*'
+
+/* Define NSFDbOpenExtended option bits. These bits select individual
+ open options. */
+
+#define DBOPEN_WITH_SCAN_LOCK 0x0001 /* Open with scan lock to prevent
+ other opens with scan lock
+ (used by replicator) */
+#define DBOPEN_PURGE 0x0002 /* DbPurge while opening */
+#define DBOPEN_NO_USERINFO 0x0004 /* No user info may be available, so don't ask for it */
+#define DBOPEN_FORCE_FIXUP 0x0008 /* Force a database fixup */
+#define DBOPEN_FIXUP_FULL_NOTE_SCAN 0x0010 /* Scan all notes and all items (not incremental) */
+#define DBOPEN_FIXUP_NO_NOTE_DELETE 0x0020 /* Do not delete bad notes during note scan */
+#define DBOPEN_CLUSTER_FAILOVER 0x0080 /* If open fails try cluster failover */
+#define DBOPEN_CLOSE_SESS_ON_ERROR 0x0100 /* Close session on error paths */
+#define DBOPEN_NOLOG 0x0200 /* don't log errors - used when opening log database! */
+/* Define NSFDB2GetInfo infotypes */
+#define DB2NSF_INFO_IS_DB2_BACKED 1 /* Is database DB2-backed: 1/0 */
+#define DB2NSF_INFO_SCHEMA_NAME 2 /* Group schema containing NSFDB2 data */
+#define DB2NSF_INFO_TABLESPACE_NAME 3 /* Tablespace name */
+#define DB2NSF_INFO_TSID 4 /* Tablespace ID */
+#define DB2NSF_INFO_USERSCHEMA_NAME 5 /* Schema containing DAVs */
+#define DB2NSF_INFO_CLASS_DESC 6 /* NSFDB2 grouping class description */
+
+/* Define NSFDB2GetServerInfo infotypes */
+#define DB2NSF_SERVINFO_SERVER_DEFAULT_TYPE 1 /* Server default type: 'DB2' or 'NSF' */
+#define DB2NSF_SERVINFO_NSFDB2_CAPABLE 2 /* Can Domino serve NSFDB2 data? */
+#define DB2NSF_SERVINFO_DB2_DATABASE_NAME 3
+
+#define DBCOMPACT_NO_INDEXES 0x00000001 /* Don't preserve view indexes */
+#define DBCOMPACT_NO_LOCKOUT 0x00000002 /* Don't lock out database users */
+#define DBCOMPACT_REVERT_ODS 0x00000004 /* Revert current ODS to the previous ODS version */
+#define DBCOMPACT_MAX_4GB 0x00000020 /* Create new file with 4GB file size limit */
+#define DBCOMPACT_MAILBOX 0x00000080 /* Compact XXXX.BOX for mail router and other MTAs */
+#define DBCOMPACT_NO_INPLACE 0x00000100 /* Don't do in-place compaction */
+#define DBCOMPACT_DISABLE_UNREAD 0x00002000 /* Disable unread marks in destination database */
+#define DBCOMPACT_ENABLE_UNREAD 0x00004000 /* Reenable unread marks in destination database (default) */
+#define DBCOMPACT_DISABLE_RESPONSE_INFO 0x00008000 /* Disable response info in resulting database */
+#define DBCOMPACT_ENABLE_RESPONSE_INFO 0x00010000 /* Disable response info in resulting database (default) */
+#define DBCOMPACT_ENABLE_FORM_BKT_OPT 0x00020000 /* Enable form/bucket bitmap optimization */
+#define DBCOMPACT_DISABLE_FORM_BKT_OPT 0x00040000 /* Diable form/bucket bitmap optimization (default) */
+#define DBCOMPACT_IGNORE_ERRORS 0x00080000 /* Ignore errors encountered during compaction. That is,
+ make best effort to get something at the end */
+#define DBCOMPACT_RECOVER_SPACE_ONLY 0x00400000 /* If set, do only bitmap correction if in-place can be done */
+#define DBCOMPACT_ARCHIVE 0x00800000 /* Archive/delete, then compact the database */
+#define DBCOMPACT_ARCHIVE_ONLY 0x01000000 /* Just archive/delete, no need to compact */
+#define DBCOMPACT_RECOVER_ALL_SPACE 0x04000000 /* If set, always do full space recovery compaction */
+
+/* Define NSF DB Classes - These all begin with 0xf000 for no good
+ reason other than to ENSURE that callers of NSFDbCreate call the
+ routine with valid parameters, since in earlier versions of NSF
+ the argument to the call was typically 0. */
+
+#define DBCLASS_BY_EXTENSION 0 /* automatically figure it out */
+
+#define DBCLASS_NSFTESTFILE 0xff00
+#define DBCLASS_NOTEFILE 0xff01
+#define DBCLASS_DESKTOP 0xff02
+#define DBCLASS_NOTECLIPBOARD 0xff03
+#define DBCLASS_TEMPLATEFILE 0xff04
+#define DBCLASS_GIANTNOTEFILE 0xff05
+#define DBCLASS_HUGENOTEFILE 0xff06
+#define DBCLASS_ONEDOCFILE 0xff07 /* Not a mail message */
+#define DBCLASS_V2NOTEFILE 0xff08
+#define DBCLASS_ENCAPSMAILFILE 0xff09 /* Specifically used by alt mail */
+#define DBCLASS_LRGENCAPSMAILFILE 0xff0a /* Specifically used by alt mail */
+#define DBCLASS_V3NOTEFILE 0xff0b
+#define DBCLASS_OBJSTORE 0xff0c /* Object store */
+#define DBCLASS_V3ONEDOCFILE 0xff0d
+#define DBCLASS_V4NOTEFILE 0xff0e
+#define DBCLASS_V5NOTEFILE 0xff0f
+#define DBCLASS_V6NOTEFILE 0xff10
+
+#define DBCLASS_MASK 0x00ff
+#define DBCLASS_VALID_MASK 0xff00
+
+/* Define NSF Special Note ID Indices. The first 16 of these are reserved
+ for "default notes" in each of the 16 note classes. In order to access
+ these, use SPECIAL_ID_NOTE+NOTE_CLASS_XXX. This is generally used
+ when calling NSFDbGetSpecialNoteID. NOTE: NSFNoteOpen, NSFDbReadObject
+ and NSFDbWriteObject support reading special notes or objects directly
+ (without calling NSFDbGetSpecialNoteID). They use a DIFFERENT flag
+ with a similar name: NOTE_ID_SPECIAL (see nsfnote.h). Remember this
+ rule:
+
+ SPECIAL_ID_NOTE is a 16 bit mask and is used as a NoteClass argument.
+ NOTE_ID_SPECIAL is a 32 bit mask and is used as a NoteID or RRV argument.
+*/
+
+#define SPECIAL_ID_NOTE 0x8000 /* use in combination w/NOTE_CLASS
+ when calling NSFDbGetSpecialNoteID */
+/* Get/Set DbOption routines */
+STATUS LNPUBLIC NSFDbGetOptions (DBHANDLE hDB, DWORD far *retDbOptions);
+STATUS LNPUBLIC NSFDbSetOptions (DBHANDLE hDB, DWORD DbOptions, DWORD Mask);
+#define DBOPTION_FT_INDEX 0x00000001 /* Enable full text indexing */
+#define DBOPTION_IS_OBJSTORE 0x00000002 /* TRUE if database is being used
+ as an object store - for garbage collection */
+#define DBOPTION_USES_OBJSTORE 0x00000004 /* TRUE if database has notes which refer to an
+ object store - for garbage collection*/
+#define DBOPTION_OBJSTORE_NEVER 0x00000008 /* TRUE if NoteUpdate of notes in this db should
+ never use an object store. */
+#define DBOPTION_IS_LIBRARY 0x00000010 /* TRUE if database is a library */
+#define DBOPTION_UNIFORM_ACCESS 0x00000020 /* TRUE if uniform access control
+ across all replicas */
+#define DBOPTION_OBJSTORE_ALWAYS 0x00000040 /* TRUE if NoteUpdate of notes in this db should
+ always try to use an object store. */
+#define DBOPTION_NO_BGAGENT 0x00000200 /* TRUE if db has no background agent */
+#define DBOPTION_OUT_OF_SERVICE 0x00000400 /* TRUE is db is out-of-service, no new opens allowed. */
+#define DBOPTION_IS_PERSONALJOURNAL 0x00000800 /* TRUE if db is personal journal */
+#define DBOPTION_MARKED_FOR_DELETE 0x00001000 /* TRUE if db is marked for delete. no new opens allowed,
+ cldbdir will delete the database when ref count = 0 */
+#define DBOPTION_HAS_CALENDAR 0x00002000 /* TRUE if db stores calendar events */
+#define DBOPTION_IS_CATALOG_INDEX 0x00004000 /* TRUE if db is a catalog index */
+#define DBOPTION_IS_ADDRESS_BOOK 0x00008000 /* TRUE if db is an address book */
+#define DBOPTION_IS_SEARCH_SCOPE 0x00010000 /* TRUE if db is a "multi-db-search" repository */
+#define DBOPTION_IS_UA_CONFIDENTIAL 0x00020000 /* TRUE if db's user activity log is confidential, only
+ * viewable by designer and manager */
+#define DBOPTION_RARELY_USED_NAMES 0x00040000 /* TRUE if item names are to be treated as
+ * if the ITEM_RARELY_USED_NAME flag is set. */
+#define DBOPTION_IS_SITEDB 0x00080000 /* TRUE if db is a "multi-db-site" repository */
+/* This is the structure used for the Item Definition Table */
+
+typedef struct {
+ WORD Length; /* total length of this buffer */
+ WORD Items; /* number of items in the table */
+ /* now come the ITEM_DEFINITION structures */
+ /* now comes the packed text */
+} ITEM_DEFINITION_TABLE;
+
+typedef struct {
+ WORD Spare; /* Spare */
+ WORD ItemType; /* default data type of the item */
+ WORD NameLength; /* length of the item's name */
+} ITEM_DEFINITION;
+
+/* Database Activity Structure */
+
+typedef struct {
+ TIMEDATE First; /* Beginning of reporting period */
+ TIMEDATE Last; /* End of reporting period */
+ DWORD Uses; /* # of uses in reporting period */
+ DWORD Reads; /* # of reads in reporting period */
+ DWORD Writes; /* # of writes in reporting period */
+ DWORD PrevDayUses; /* # of uses in previous 24 hours */
+ DWORD PrevDayReads; /* # of reads in previous 24 hours */
+ DWORD PrevDayWrites; /* # of writes in previous 24 hours */
+ DWORD PrevWeekUses; /* # of uses in previous week */
+ DWORD PrevWeekReads; /* # of reads in previous week */
+ DWORD PrevWeekWrites; /* # of writes in previous week */
+ DWORD PrevMonthUses; /* # of uses in previous month */
+ DWORD PrevMonthReads; /* # of reads in previous month */
+ DWORD PrevMonthWrites; /* # of writes in previous month */
+} DBACTIVITY;
+
+typedef struct {
+ TIMEDATE Time; /* Time of record */
+ WORD Reads; /* # of data notes read */
+ WORD Writes; /* # of data notes written */
+ DWORD UserNameOffset; /* Offset of the user name from the beginning
+ of this memory block */
+ /* User names follow -- '\0' terminated */
+} DBACTIVITY_ENTRY;
+
+#define NSFDbGetActivityUserNamePtr(DbActivity, Index) \
+ (((char FAR *) DbActivity) + DbActivity[Index].UserNameOffset)
+
+/* Define NSF DB open modes */
+
+#define DB_LOADED 1 /* hDB refers to a normal database file */
+#define DB_DIRECTORY 2 /* hDB refers to a "directory" and not a file */
+
+/* Define argument to NSFDbInfoParse/Modify to manipulate components from DbInfo */
+
+#define INFOPARSE_TITLE 0
+#define INFOPARSE_CATEGORIES 1
+#define INFOPARSE_CLASS 2
+#define INFOPARSE_DESIGN_CLASS 3
+
+
+/* Array entry returned from NSFDbGetReplHistorySummary */
+
+typedef struct {
+ TIMEDATE ReplicationTime; /* Time returned from last replciation */
+ WORD AccessLevel; /* Access level at time of replication */
+ WORD AccessFlags; /* Access flags at time of replication */
+ WORD Direction; /* NEVER, SEND, RECEIVE */
+ DWORD ServerNameOffset; /* Server name offset in packed data */
+ WORD ServerNameLength; /* Server name length in packed data */
+ WORD FileNameLength; /* File name length in packed data */
+ /* Total server!!file length is */
+ /* ServerNameLength + FileNameLength + 2 */
+ /* to compensate for the !! separator */
+ WORD MoreInfo; /* contains MoreInfo from cache - includes complete replication flag */
+ WORD wSpare; /* Room for growth */
+ DWORD dwSpare; /* Room for growth */
+ /* Server/file name pairs follow as */
+ /* "<server name>!!<file name>" with */
+ /* NULL after each pairing */
+} REPLHIST_SUMMARY;
+
+/* Types for REPLHISTORY.Direction */
+
+#define DIRECTION_NEVER 0
+#define DIRECTION_SEND 1
+#define DIRECTION_RECEIVE 2
+
+/* Macros for accessing packed data following the REPLHISTORY_SUMMARY array.
+
+ NOTE: The server name pointer is NOT null-terminated, but the file name
+ pointer is. This is so the caller can use the "server file" string
+ directly.
+*/
+
+#define NSFGetSummaryServerNamePtr(Summary, Index) \
+ (((char FAR *) Summary) + Summary[Index].ServerNameOffset)
+#define NSFGetSummaryFileNamePtr(Summary, Index) \
+ (((char FAR *) Summary) + Summary[Index].ServerNameOffset + \
+ Summary[Index].ServerNameLength + 2)
+
+/* Option flags for NSFDbGetReplHistorySummary */
+
+#define REPLHIST_REMOVE_WILDCARDS 0x00000001L /* Don't copy wild card entries */
+#define REPLHIST_SORT_BY_DATE 0x00000002L /* Sort by date. Default is
+ by server name */
+#define REPLHIST_ONLY_COMPLETE 0x00000004L /* Only return complete entries */
+
+/* Structure returned from NSFDbGetMajMinVersion
+
+ NOTE: For release 5.0.4a, the values would be:
+
+ MajorVersion = 5
+ MinorVersion = 0
+ QMRNumber = 4
+ QMUNumber = 1
+
+*/
+typedef struct {
+ DWORD MajorVersion; /* Major version identifier */
+ DWORD MinorVersion; /* Minor version identifier */
+ DWORD QMRNumber; /* Maintenance Release identifier */
+ DWORD QMUNumber; /* Maintenance Update identifier */
+ DWORD HotfixNumber; /* Hotfixes installed on machine */
+ DWORD Flags; /* See BUILDVERFLAGS_xxx */
+ DWORD FixpackNumber; /* Fixpack version installed on machine */
+ DWORD Spare[2]; /* Room for growth */
+ } BUILDVERSION;
+
+/* Flags returned in the 'Flags' section of the BUILDVERSION structure */
+#define BLDVERFLAGS_NONPRODUCTION 0x00000001L /* Non-production style build (internal only). */
+
+
+/* Option flags for NSFDbCreateExtended */
+
+#define DBCREATE_LOCALSECURITY 0x0001
+#define DBCREATE_OBJSTORE_NEVER 0x0002
+#define DBCREATE_MAX_SPECIFIED 0x0004
+#define DBCREATE_NORESPONSE_INFO 0x0010 /* Don't support note hierarchy - ODS21 and up only */
+#define DBCREATE_NOUNREAD 0x0020 /* Don't maintain unread lists for this DB */
+#define DBCREATE_NO_FREE_OVERWRITE 0x0200 /* Skip overwriting freed disk buffer space */
+#define DBCREATE_FORM_BUCKET_OPT 0x0400 /* Maintain form/bucket bitmap */
+#define DBCREATE_DISABLE_TXN_LOGGING 0x0800 /* Disable transaction logging for this database if specified */
+#define DBCREATE_MAINTAIN_LAST_ACCESSED 0x1000 /* Enable maintaining last accessed time */
+#define DBCREATE_IS_MAILBOX 0x4000 /* TRUE if database is a mail[n].box database */
+#define DBCREATE_LARGE_UNKTABLE 0x8000 /* TRUE if database should allow "large" (>64K bytes) UNK table */
+
+
+/* Values for EncryptStrength of NSFDbCreateExtended */
+
+#define DBCREATE_ENCRYPT_NONE 0x00
+#define DBCREATE_ENCRYPT_SIMPLE 0x01
+#define DBCREATE_ENCRYPT_MEDIUM 0x02
+#define DBCREATE_ENCRYPT_STRONG 0x03
+/* NSFDbCreateExtendedWithOptions Option2 flags */
+
+/* NOTE: When you define a new Option2 flag, OR that flag into the
+ DBCREATE_UNDEFINED_OPTIONS2 definition below */
+
+#define DBCREATE_USE_SERVER_DEFAULT_DATASTORE 0x00000000
+#define DBCREATE_FORCE_NSF_DATASTORE 0x00000001
+#define DBCREATE_FORCE_DB2_DATASTORE 0x00000002
+
+#define DBCREATE_UNDEFINED_OPTIONS2 ~(DBCREATE_USE_SERVER_DEFAULT_DATASTORE | \
+ DBCREATE_FORCE_NSF_DATASTORE | \
+ DBCREATE_FORCE_DB2_DATASTORE | \
+ DBCREATE_OVERRIDE_ADMINP)
+
+
+STATUS LNPUBLIC NSFDbGetReplHistorySummary (DBHANDLE hDb, DWORD Flags,
+ HANDLE *rethSummary, DWORD * retNumEntries);
+
+STATUS LNPUBLIC NSFDbGetMajMinVersion (DBHANDLE hDb, BUILDVERSION far *retVersion);
+
+#if !defined(DB2GetInfo)
+STATUS LNPUBLIC NSFDB2GetInfo( DBHANDLE hDB, DWORD infotype, void far *buffer, DWORD *size );
+#endif
+
+/* \client\cldbinfo.c */
+#if !defined(DB2GetServerInfo)
+STATUS LNPUBLIC NSFDB2GetServerInfo( char *szServerName, DWORD infotype, void far *buffer, DWORD *size );
+#endif
+
+STATUS LNPUBLIC NSFDbIsDB2 (DBHANDLE hDB, BOOL *isDB2);
+
+/* Option flags for NSFDbCreateAndCopy */
+
+#define DBCOPY_REPLICA 0x00000001L
+#define DBCOPY_SUBCLASS_TEMPLATE 0x00000002L
+#define DBCOPY_DBINFO2 0x00000004L
+#define DBCOPY_SPECIAL_OBJECTS 0x00000008L
+#define DBCOPY_NO_ACL 0x00000010L
+#define DBCOPY_NO_FULLTEXT 0x00000020L
+#define DBCOPY_ENCRYPT_SIMPLE 0x00000040L
+#define DBCOPY_ENCRYPT_MEDIUM 0x00000080L
+#define DBCOPY_ENCRYPT_STRONG 0x00000100L
+#define DBCOPY_KEEP_NOTE_MODTIME 0x00000200L
+#define DBCOPY_REPLICA_NAMELIST 0x01000000L /* Copy the NameList (applicable only when DBCOPY_REPLICA is specified) */
+#define DBCOPY_DEST_IS_NSF 0x02000000L /* Destination is NSF-backed database */
+#define DBCOPY_DEST_IS_DB2 0x04000000L /* Destination is DB2-backed database */
+#define DBCOPY_OVERRIDE_DEST 0x08000000L /* Destination should override default if able to */
+
+
+STATUS LNPUBLIC NSFDbCopyExtended (DBHANDLE hSrcDB, DBHANDLE hDstDB,
+ TIMEDATE Since, WORD NoteClassMask, DWORD Flags,
+ TIMEDATE far *retUntil);
+STATUS LNPUBLIC NSFDbOpen (const char far *PathName, DBHANDLE far *rethDB);
+STATUS LNPUBLIC NSFDbOpenTemplate (const char far *PathName, DBHANDLE far *rethDB);
+STATUS LNPUBLIC NSFDbOpenExtended (const char far *PathName, WORD Options,
+ HANDLE hNames,
+ TIMEDATE far *ModifiedTime,
+ DBHANDLE far *rethDB,
+ TIMEDATE far *retDataModified,
+ TIMEDATE far *retNonDataModified);
+STATUS LNPUBLIC NSFDbOpenTemplateExtended (const char far *PathName, WORD Options,
+ HANDLE hNames,
+ TIMEDATE far *ModifiedTime,
+ DBHANDLE far *rethDB,
+ TIMEDATE far *retDataModified,
+ TIMEDATE far *retNonDataModified);
+STATUS LNPUBLIC NSFDbClose (DBHANDLE hDB);
+STATUS LNPUBLIC NSFDbCreate (const char far *PathName, USHORT DbClass, BOOL ForceCreation);
+STATUS LNPUBLIC NSFDbCreateObjectStore (const char far *PathName, BOOL ForceCreation);
+STATUS LNPUBLIC NSFDbDelete (const char far *PathName);
+STATUS LNPUBLIC NSFDbCreateExtended (const char far *PathName, WORD DbClass,
+ BOOL ForceCreation, WORD Options,
+ BYTE EncryptStrength, DWORD MaxFileSize);
+STATUS LNPUBLIC NSFDbCreateExtendedWithOptions(const char far *filename, WORD dbclass, BOOL force,
+ WORD Option, DWORD Option2, BYTE EncryptStrength, DWORD MaxFileSize,
+ const char far *String1, const char far *String2,
+ WORD ReservedListLength, WORD ReservedListCount, HANDLE hReservedList);
+STATUS LNPUBLIC NSFDbCreateWithUserNameList(const char far *PathName, WORD DbClass,
+ BOOL ForceCreation, WORD Options,
+ BYTE EncryptStrength, DWORD MaxFileSize, HANDLE hNamesList);
+STATUS LNPUBLIC NSFDbDeleteExtended (const char far *PathName, HANDLE hNameList);
+
+STATUS LNPUBLIC NSFDbCopy (DBHANDLE hSrcDB, DBHANDLE hDstDB, TIMEDATE Since, WORD NoteClassMask);
+STATUS LNPUBLIC NSFDbCopyNote (DBHANDLE hSrcDB, DBID far *SrcDbID, DBID far *SrcReplicaID,
+ NOTEID SrcNoteID,
+ DBHANDLE hDstDB, DBID far *DstDbID, DBID far *DstReplicaID,
+ NOTEID far *retDstNoteID, WORD far *retNoteClass);
+
+STATUS LNPUBLIC NSFDbCreateAndCopyExtended(const char far* srcDb,const char far* dstDb, WORD NoteClass, WORD limit,
+ DWORD flags, HANDLE hNames, DBHANDLE far* retHandle);
+STATUS LNPUBLIC NSFDbCreateAndCopy(const char far* srcDb,const char far* dstDb, WORD NoteClass, WORD limit, DWORD flags, DBHANDLE far* retHandle);
+STATUS LNPUBLIC NSFDbMarkInServiceExtended(const char far* dbPathPtr, HANDLE hNames);
+STATUS LNPUBLIC NSFDbMarkForDelete(const char far* dbPathPtr);
+STATUS LNPUBLIC NSFDbMarkInService(const char far* dbPathPtr);
+STATUS LNPUBLIC NSFDbMarkOutOfService(const char far* dbPathPtr);
+
+STATUS LNPUBLIC NSFDbCopyNoteExt(DBHANDLE hSrcDB,DBID *SrcDbID,DBID *SrcReplicaID,NOTEID SrcNoteID,
+ DBHANDLE hDstDB,DBID *DstDbID,DBID *DstReplicaID,
+ DWORD dwOpenFlags, DWORD dwUpdateFlags,
+ NOTEID *retDstNoteID,WORD *retNoteClass);
+STATUS LNPUBLIC NSFDbCopyACL (DBHANDLE hSrcDB, DBHANDLE hDstDB);
+STATUS LNPUBLIC NSFDbCopyTemplateACL (DBHANDLE hSrcDB, DBHANDLE hDstDB, char far *Manager, WORD DefaultAccessLevel);
+STATUS LNPUBLIC NSFDbCreateACLFromTemplate (DBHANDLE hNTF, DBHANDLE hNSF,
+ const char far *Manager, WORD DefaultAccess,
+ HANDLE far *rethACL);
+STATUS LNPUBLIC NSFDbStoreACL (DBHANDLE hDB, HANDLE hACL, DWORD ObjectID, WORD Method);
+STATUS LNPUBLIC NSFDbReadACL(DBHANDLE hDB, HANDLE far *rethACL);
+STATUS LNPUBLIC NSFDbGenerateOID (DBHANDLE hDB, OID far *retOID);
+STATUS LNPUBLIC NSFSetMaxPasswordAccess(DBHANDLE hDB, WORD Level);
+STATUS LNPUBLIC NSFGetMaxPasswordAccess(DBHANDLE hDB, WORD *retLevel);
+STATUS LNPUBLIC NSFDbModifiedTime (DBHANDLE hDB, TIMEDATE far *retDataModified, TIMEDATE far *retNonDataModified);
+STATUS LNPUBLIC NSFDbPathGet (DBHANDLE hDB, char far *retCanonicalPathName, char far *retExpandedPathName);
+STATUS LNPUBLIC NSFDbInfoGet (DBHANDLE hDB, char far *retBuffer);
+STATUS LNPUBLIC NSFDbInfoSet (DBHANDLE hDB, char far *Buffer);
+void LNPUBLIC NSFDbInfoParse(char far *Info, WORD What, char far *Buffer, WORD Length);
+void LNPUBLIC NSFDbInfoModify(char far *Info, WORD What, const char far *Buffer);
+STATUS LNPUBLIC NSFDbGetSpecialNoteID (DBHANDLE hDB, WORD Index, NOTEID far *retNoteID);
+STATUS LNPUBLIC NSFDbIDGet (DBHANDLE hDB, DBID far *retDbID);
+STATUS LNPUBLIC NSFDbReplicaInfoGet (DBHANDLE hDB, DBREPLICAINFO far *retReplicationInfo);
+STATUS LNPUBLIC NSFDbReplicaInfoSet (DBHANDLE hDB, DBREPLICAINFO far *ReplicationInfo);
+STATUS LNPUBLIC NSFDbReplicaInfoSetExtended (DBHANDLE hDB, DBREPLICAINFO far *ReplicationInfo, HANDLE hNamesList);
+STATUS LNPUBLIC NSFDbGetNoteInfo (DBHANDLE hDB, NOTEID NoteID,
+ OID far *retNoteOID,
+ TIMEDATE far *retModified,
+ WORD far *retNoteClass);
+STATUS LNPUBLIC NSFDbHasProfileNoteChanged(DBHANDLE hDB, NOTEID noteid, DWORD *pSeqNum, TIMEDATE *Since, BOOL *HasChanged, TIMEDATE *retModTime);
+#define DBQUOTA_NOT_SPECIFIED (-1)
+
+STATUS LNPUBLIC NSFDbQuotaGet (const char far *Filename, DBQUOTAINFO far *retQuotaInfo);
+STATUS LNPUBLIC NSFDbQuotaSetExt(const char far *Filename, DWORD Flags, DBQUOTAINFO far *QuotaInfo);
+
+STATUS LNPUBLIC NSFDbQuotaGethDB(DBHANDLE hDB, DBQUOTAINFOEXT *QuotaInfo) ;
+
+/* Options for quota detection,enforcement method */
+
+#define NSF_QUOTA_METHOD_DEFAULT 0L
+#define NSF_QUOTA_METHOD_USAGE 1L
+#define NSF_QUOTA_METHOD_FILESIZE 2L
+#define NSF_QUOTA_METHOD_FILESIZE_ADD 3L
+
+STATUS LNPUBLIC NSFDbFTSizeGet(const char far *Filename, DWORD *FTSize);
+STATUS LNPUBLIC NSFDbGetNoteInfoByUNID(DBHANDLE hDB, UNID far *pUNID,
+ NOTEID far *retNoteID, OID far *retOID,
+ TIMEDATE far *retModTime, WORD far *retClass);
+STATUS LNPUBLIC NSFDbGetModifiedNoteTable (DBHANDLE hDB, WORD NoteClassMask, TIMEDATE Since,
+ TIMEDATE far *retUntil,
+ HANDLE far *rethTable);
+STATUS LNPUBLIC NSFApplyModifiedNoteTable (HANDLE hModifiedNotes, HANDLE hTargetTable);
+STATUS LNPUBLIC NSFDbLocateByReplicaID (DBHANDLE hDB, DBID far *ReplicaID, char far *retPathName, WORD PathMaxLen);
+STATUS LNPUBLIC NSFDbStampNotes (DBHANDLE hDB, HANDLE hTable,
+ const char far *ItemName, WORD ItemNameLength,
+ void far *Data, WORD DataLength);
+STATUS LNPUBLIC NSFDbStampNotesMultiItem (DBHANDLE hDB, HANDLE hTable, HANDLE hInNote);
+STATUS LNPUBLIC NSFDbDeleteNotes (DBHANDLE hDB, HANDLE hTable, UNID far *retUNIDArray);
+STATUS LNPUBLIC NSFDbUserNameGet (DBHANDLE hDB, char far *retUserName, WORD BufferLength);
+STATUS LNPUBLIC NSFDbGetNamesList(DBHANDLE hDB, DWORD Flags, HANDLE *rethNamesList);
+void LNPUBLIC NSFDbAccessGet(DBHANDLE hDB, WORD far *retAccessLevel, WORD far *retAccessFlag);
+STATUS LNPUBLIC NSFDbRename (const char far *from, const char far *to);
+STATUS LNPUBLIC NSFDbClassGet (DBHANDLE hDB, WORD far *retClass);
+STATUS LNPUBLIC NSFDbModeGet (DBHANDLE hDB, USHORT far *retMode);
+STATUS LNPUBLIC NSFDbGetUserActivity(DBHANDLE hDB, DWORD Flags, DBACTIVITY far *retDbActivity,
+ HANDLE far *rethUserInfo, WORD far *retUserCount);
+STATUS LNPUBLIC NSFDbCloseSession (DBHANDLE hDB);
+STATUS LNPUBLIC NSFDbReopen (DBHANDLE hDB, DBHANDLE far *rethDB);
+STATUS LNPUBLIC NSFDbMajorMinorVersionGet (DBHANDLE hDB, WORD far *retMajorVersion,
+ WORD far *retMinorVersion);
+STATUS LNPUBLIC NSFDbItemDefTable (DBHANDLE hDB,ITEMDEFTABLEHANDLE far *retItemNameTable);
+STATUS LNPUBLIC NSFDbItemDefTableExt (DBHANDLE hDB,ITEMDEFTABLEEXTHANDLE far *retItemNameTable);
+STATUS LNPUBLIC NSFDbGetBuildVersion (DBHANDLE hDB,WORD far *retVersion);
+STATUS LNPUBLIC NSFDbSpaceUsage (DBHANDLE hDB, DWORD far *retAllocatedBytes, DWORD far *retFreeBytes);
+STATUS LNPUBLIC NSFDbSpaceUsageScaled (DBHANDLE hDB, DWORD far *retAllocatedGranules, DWORD far *retFreeGranules, DWORD far *retGranularity);
+DWORD LNPUBLIC NSFDbGetOpenDatabaseID (DBHANDLE hDB);
+STATUS LNPUBLIC NSFGetServerStats(char far *ServerName, char far *Facility, char far *StatName, HANDLE far *rethTable, DWORD far *retTableSize);
+STATUS LNPUBLIC NSFGetServerLatency(char far *ServerName, DWORD Timeout,
+ DWORD far *retClientToServerMS,
+ DWORD far *retServerToClientMS,
+ WORD far *ServerVersion);
+STATUS LNPUBLIC NSFRemoteConsole(char far *ServerName, char far *ConsoleCommand, HANDLE far *hResponseText);
+
+STATUS LNPUBLIC NSFBuildNamesList(char *UserName, DWORD dwFlags, HANDLE *rethNamesList);
+STATUS LNPUBLIC NSFDbClearReplHistory(DBHANDLE hDb, DWORD dwFlags);
+STATUS LNPUBLIC NSFDbGetModifiedUnreadTables(DBHANDLE hDB, char* UserName, WORD UserNameLen, TIMEDATE Since, TIMEDATE *Until, HANDLE *hRead, HANDLE *hUnread);
+STATUS LNPUBLIC NSFDbUpdateUnread (DBHANDLE hDataDB, HANDLE hUnreadList);
+STATUS LNPUBLIC NSFDbGetUnreadNoteTable(DBHANDLE hDB,
+ char far *UserName, WORD UserNameLength, BOOL fCreateIfNotAvailable,
+ HANDLE far *rethUnreadList);
+STATUS LNPUBLIC NSFDbGetUnreadNoteTable2(DBHANDLE hDB,
+ char far *UserName, WORD UserNameLength, BOOL fCreateIfNotAvailable, BOOL fUpdateUnread,
+ HANDLE far *rethUnreadList);
+STATUS LNPUBLIC NSFDbSetUnreadNoteTable(DBHANDLE hDB, char far *UserName, WORD UserNameLength,
+ BOOL fFlushToDisk, HANDLE hOriginalUnreadList, HANDLE hUnreadList);
+STATUS LNPUBLIC NSFDbGetObjectStoreID(DBHANDLE dbhandle, BOOL far *Specified, DBID far *ObjStoreReplicaID);
+STATUS LNPUBLIC NSFDbSetObjectStoreID(DBHANDLE dbhandle, DBID far *ObjStoreReplicaID);
+STATUS LNPUBLIC NSFDbFilter(DBHANDLE hFilterDB, NOTEHANDLE hFilterNote,
+ HANDLE hNotesToFilter, BOOL fIncremental,
+ void far *Reserved1, void far *Reserved2,
+ char far *DbTitle, char far *ViewTitle,
+ void far *Reserved3, void far *Reserved4,
+ HANDLE hDeletedList,
+ HANDLE hSelectedList);
+STATUS LNPUBLIC NSFDbCompact(const char far *Pathname, WORD Options, DWORD far *retStats);
+STATUS LNPUBLIC NSFDbCompactExtended(const char *Pathname, DWORD Options, DWORD *retStats);
+/* Define flags for NSFFolderGetIDTable */
+#define DB_GETIDTABLE_VALIDATE 0x00000001 /* If set, return only "validated" noteIDs */
+STATUS LNPUBLIC NSFFolderGetIDTable(HANDLE hViewDB, HANDLE hDataDB, NOTEID ViewNoteID, DWORD Flags, HANDLE *hTable);
+STATUS LNPUBLIC NSFGetFolderChanges(DBHANDLE hViewDB, DBHANDLE hDataDB, NOTEID ViewNoteID, TIMEDATE *Since, DWORD Flags,
+ HANDLE *AddedNoteTable, HANDLE *RemovedNoteTable);
+typedef STATUS (LNCALLBACKPTR NSFGETALLFOLDERCHANGESCALLBACK) (void *Param, UNID *NoteUNID, HANDLE AddedNoteTable, HANDLE RemovedNoteTable);
+STATUS LNPUBLIC NSFGetAllFolderChanges(HANDLE hViewDB, HANDLE hDataDB, TIMEDATE *Since, DWORD Flags,
+ NSFGETALLFOLDERCHANGESCALLBACK Callback, void *Param, TIMEDATE *Until);
+#define MAX_ITEMDEF_SEGMENTS 25
+
+typedef struct {
+ DWORD Items; /* number of items in the table */
+ DWORD ItemDefArray; /* Memory handle of ITEM_DEFINITION_EXT structures */
+ DWORD NumSegments; /* Number of non-null segments in ItemNameSegs */
+ HANDLE ItemNameSegs[MAX_ITEMDEF_SEGMENTS]; /* Segments of packed text */
+ DWORD ItemNameSegLengths[MAX_ITEMDEF_SEGMENTS];
+ /* Length of each non-null text segment */
+} ITEM_DEFINITION_TABLE_EXT;
+
+typedef struct {
+ DWORD ItemOffset; /* offset into ItemNameSegs to item name */
+ WORD ItemType; /* default data type of the item */
+ WORD ItemNameLength; /* length of the item's name */
+} ITEM_DEFINITION_EXT;
+
+typedef struct {
+ DWORD Items;
+ void *pItemDefArray;
+ char *ItemText[MAX_ITEMDEF_SEGMENTS];
+ DWORD NumSegments;
+ DWORD ItemNameSegLengths[MAX_ITEMDEF_SEGMENTS];
+} ITEM_DEFINITION_TABLE_LOCK;
+
+/* Accessor routines for item name table returned by NSFDbItemDefTableExt. */
+STATUS LNPUBLIC NSFItemDefExtLock(ITEM_DEFINITION_TABLE_EXT *ItemDefTable, ITEM_DEFINITION_TABLE_LOCK *ItemDefTableLock);
+STATUS LNPUBLIC NSFItemDefExtUnlock(ITEM_DEFINITION_TABLE_EXT *ItemDefTable, ITEM_DEFINITION_TABLE_LOCK *ItemDefTableLock);
+STATUS LNPUBLIC NSFItemDefExtFree(ITEM_DEFINITION_TABLE_EXT *ItemDeftable);
+STATUS LNPUBLIC NSFItemDefExtEntries(ITEM_DEFINITION_TABLE_LOCK *ItemDefTableLock, DWORD *NumEntries);
+STATUS LNPUBLIC NSFItemDefExtGetEntry(ITEM_DEFINITION_TABLE_LOCK *ItemDefTableLock, DWORD ItemNum,
+ WORD *ItemType, WORD *ItemLength, char **ItemName);
+
+STATUS LNPUBLIC NSFBackupStart(DBHANDLE hDB, DWORD Flags, HANDLE *BackupContext, DWORD *FileSizeLow, DWORD *FileSizeHigh);
+STATUS LNPUBLIC NSFBackupStop(DBHANDLE hDB, HANDLE BackupContext);
+#define BACKUPEND_ABORT 0x00000001 /* Abort curent database backup */
+STATUS LNPUBLIC NSFBackupEnd(DBHANDLE hDB, HANDLE BackupContext, DWORD Options);
+STATUS LNPUBLIC NSFBackupSetHighWaterMark(DBHANDLE hDB, HANDLE BackupContext,
+ DWORD HighWaterMarkLow, DWORD HighWaterMarkHigh);
+STATUS LNPUBLIC NSFBackupGetChangeInfoSize(DBHANDLE hDB,
+ HANDLE hBackupContext,
+ DWORD Flags,
+ DWORD *InfoSizeLow,
+ DWORD *InfoSizeHigh);
+STATUS LNPUBLIC NSFBackupGetNextChangeInfo(DBHANDLE hDB,
+ HANDLE hBackupContext,
+ DWORD Flags,
+ char * Buffer,
+ DWORD BufferSize,
+ DWORD *FilledSize);
+
+STATUS LNPUBLIC NSFBackupStartApplyChangeInfo(HANDLE *ApplyInfoContext,
+ char * CopyFilePath,
+ DWORD Flags,
+ DWORD InfoSizeLow,
+ DWORD InfoSizeHigh);
+
+STATUS LNPUBLIC NSFBackupApplyNextChangeInfo(
+ HANDLE ApplyInfoContext,
+ DWORD Flags,
+ char * Buffer,
+ DWORD BufferSize);
+#define APPLYEND_ABORT 0x00000001 /* Abort current change info appilcation */
+STATUS LNPUBLIC NSFBackupEndApplyChangeInfo(HANDLE ApplyInfoContext,
+ DWORD Flags);
+
+STATUS LNPUBLIC NSFBringDatabaseOnline(const char far * dbPath,
+ DWORD options);
+
+#define OFFLINE_NODELETE 0x00000001 /* Don't delete database file */
+#define OFFLINE_KEEP_ACCESS_ENTITIES 0x00000002 /* Don't delete DB2 access entities */
+
+STATUS LNPUBLIC NSFTakeDatabaseOffline(const char far * dbPath,
+ DWORD WaitTime,
+ DWORD options);
+STATUS LNPUBLIC NSFDbGetLogInfo(DBHANDLE hDb,
+ DWORD Flags,
+ BOOL * LOGGED,
+ UNID * LogID,
+ UNID * Dbiid,
+ DWORD * LogExtent);
+
+#define DB2BACKUP_FASTCONNECT 0x1
+#define DB2BACKUP_NEWREPLICA 0x2
+
+#define DB2BACKUP_COPY_REPLACE 0x8
+#define DB2BACKUP_COPY_DELETE_SRC 0x10
+#define DB2BACKUP_COPY_ISOLATE 0x20
+#define DB2BACKUP_COPY_CLOSE 0x40
+#define DB2BACKUP_COPY_NONRECOVERABLE 0x80
+#define DB2BACKUP_COPY_IGNORE_NIF 0x100
+#define DB2BACKUP_COPY_VENDOR_LOAD 0X200
+
+#define DB2BACKUP_LINKS_VERIFYEXISTING 0x01
+#define DB2BACKUP_LINKS_SCANSCHEMAS 0x02
+#define DB2BACKUP_LINKS_QUIET 0x04
+
+#define DB2BACKUP_NONSFID 0xffffffff
+
+STATUS LNPUBLIC NSFDB2ReconnectNotesDatabase(const char far * FullPath,
+ const char far * String1,
+ DWORD nsfid,
+ DWORD flags);
+
+STATUS LNPUBLIC NSFDB2RegenerateLinks (DWORD flags);
+
+STATUS LNPUBLIC NSFDB2ListNSFDB2Databases (HANDLE *pHDbList, void far **pDbList, const char far* tablespaceName);
+
+STATUS LNPUBLIC NSFDB2FastCopy(
+ const char far* srcDB2Database,
+ const char far* tgtDB2Database,
+ const char far* sourceNSF,
+ const char far* targetNSF,
+ const char far* groupName,
+ const char far* loadParameter,
+ DWORD WaitTime,
+ DWORD flags,
+ DWORD flags2);
+
+STATUS LNPUBLIC NSFDB2GetDbInfoValidity (const char* filePath,
+ char* Schema,
+ DWORD szSchema,
+ char* tableSpace,
+ DWORD szTableSpace,
+ char* actualTableSpace,
+ DWORD szActualTableSpace,
+ BOOL* schemaExists,
+ BOOL* tsExists,
+ BOOL* tsMismatch,
+ DWORD flags);
+/* Define NSF Group Properties */
+#define DB2NSF_GROUP_PROPERTY_CLASS 1
+
+STATUS LNPUBLIC NSFGetNSFDB2GroupProperty( const char* group, DWORD infotype, void far *buffer, DWORD *size);
+
+/* Definition of the log restore callback function that the backup */
+
+/* utility will have to provide for archive logging. */
+typedef STATUS (LNCALLBACKPTR LOGRESTORECALLBACKFUNCTION)(UNID *LogID, DWORD LogNumber, char *LogSegmentPathName);
+
+typedef enum {
+ MediaCallback_NoteUpdate = 0x01, /* Update of existing Note */
+ MediaCallback_NoteInsert = 0x02, /* Addition of new note */
+ MediaCallback_NoteDelete = 0x04, /* Delete of note */
+ MediaCallback_CLR = 0x08 /* Event is the undo of an action due to some failure */
+} MediaCallbackFlags;
+
+
+typedef struct {
+ WORD InfoSize; /* Size of this structure, use this to determine if future fields are avail */
+ NOTEID NoteId; /* NoteID for note being altered */
+ NOTEHANDLE hNote; /* Handle to note being retrieved */
+ TIMEDATE TranTime; /* Time the transaction ran for which you are being called */
+ char far* UserName; /* If avail, else a pointer to "" */
+ char far* PathName; /* Path & file name of DB */
+} NOTE_RESTORE_CALLBACK_INFO;
+
+/* Definition of the note restore callback function that the backup/archive */
+/* utility will have to provide for monitoring notes during Media Recovery */
+typedef STATUS (LNCALLBACKPTR NOTERESTORECALLBACKFUNCTION)( DWORD state_flags,
+ void far * userParm,
+ NOTE_RESTORE_CALLBACK_INFO far * info);
+
+
+/* Log archiving API for backup utilities to call */
+/* Possible values returned from NSFGetTransLogStyle */
+#define TRANSLOG_STYLE_CIRCULAR 0 /* Circular logging is in effect */
+#define TRANSLOG_STYLE_ARCHIVE 1 /* Archive logging is in effect */
+#define TRANSLOG_STYLE_LINEAR 2 /* Linear logging is in effect */
+STATUS LNPUBLIC NSFGetTransLogStyle(WORD far * LogType);
+STATUS LNPUBLIC NSFBeginArchivingLogs(void);
+STATUS LNPUBLIC NSFEndArchivingLogs(void);
+STATUS LNPUBLIC NSFGetFirstLogToArchive(UNID far * LogID, DWORD far * LogNumber, char far * LogPath);
+STATUS LNPUBLIC NSFGetNextLogToArchive(UNID far * LogID, DWORD far * LogNumber, char far * LogPath);
+STATUS LNPUBLIC NSFDoneArchivingLog(UNID far * LogID, DWORD far * LogSequenceNumber);
+/* Wait for any other media recovery to finish, vs. return immed if busy */
+#define DBRECOVER_WAIT 0x0001
+/* Make recovered db a new instance so it will not conflict with original */
+#define DBRECOVER_ZAP_ID 0x0002
+/* Refresh a backup to the current level, mutually exclusive with DBRECOVER_ZAP_ID */
+#define DBRECOVER_REFRESH_BACKUP 0x0004
+/* Recover database to a point in time, mutually exclusive with DBRECOVER_REFRESH_BACKUP */
+#define DBRECOVER_POINT_IN_TIME 0x0008
+/* Give recovered db a new replica id so it will not conflict with original */
+#define DBRECOVER_ZAP_REPLICAID 0x0010
+/* Make recovered db a new instance if another copy of the DB is on-line */
+#define DBRECOVER_ZAP_ID_IF_NECESSARY 0x0020
+/* Allow alternate path from which to recover old log extents */
+#define DBRECOVER_ALT_RETRIEVE_PATH 0x0040
+
+STATUS LNPUBLIC NSFRecoverDatabases(const char far * dbNames,
+ LOGRESTORECALLBACKFUNCTION restoreCB,
+ DWORD Flags, /* DBRECOVER_* flags */
+ WORD far * errDbIndex,
+ TIMEDATE far * recoveryTime);
+
+STATUS LNPUBLIC NSFRecoverDatabasesWithCallback(const char far * dbNames,
+ LOGRESTORECALLBACKFUNCTION restoreCB,
+ DWORD Flags, /* DBRECOVER_* flags */
+ WORD far * errDbIndex,
+ TIMEDATE far * recoveryTime,
+ NOTERESTORECALLBACKFUNCTION noteCB,
+ void far * userParm);
+
+
+/* rmmisc.cpp */
+
+/* Return BOOL if span specified, else actual amount of log to process */
+STATUS LNPUBLIC NSFIsNewBackupNeeded(const char far * dbName,
+ DWORD comfortSpan, /* Requested Pad Log span in K */
+ DWORD far * backupNeeded);
+STATUS LNPUBLIC NSFDbCreateNoteID(DBHANDLE hDB, BOOL fData, NOTEID *retNoteID);
+STATUS LNPUBLIC NSFDbAddItemName(DBHANDLE hDB, WORD type, char *string, WORD length, DWORD *rtnItemNumber);
+
+/* Database Hook Drivers
+*
+* NSF hook drivers enable the API programmer to construct a set of
+* subroutines, packaged as a DLL, that "hook" several NSF functions
+* related to reading, modifying, and deleting notes. The principal
+* application of these hook drivers is intended to be auditing, that is,
+* logging accesses to a database, however they can also be programmed
+* to modify the contents of the notes and/or refuse requests.
+*
+* Hook Driver Packaging and Concurrency Requirements
+*
+* Like all Notes low-level subsystems, hook drivers must obey strict
+* rules to fit into their computing environment:
+*
+* 1. The drivers should be available on multiple computing platforms
+*
+* 2. The drivers are packaged as Dynamic Link Libraries under
+* Windows, NT, and OS/2. Under Windows, the DEF file must specify the data
+* as being MOVEABLE SINGLE so that it doesn't occupy GlobalDOS memory, and
+* because Windows doesn't support multi-instance dynamic link libraries.
+* For NT and OS/2, we recommend MULTIPLE data, but you can use whatever you
+* wish.
+*
+* For all four environments, Notes uses either LoadLibrary or
+* DosLoadModule to load the driver. You must decide upon a mnemonic name
+* for your driver, a maximum of 7 characters that is preferably
+* nationality-neutral (obscure in all languages), such as NTAUDIT. In order
+* to load the library, Notes prefixes this name with
+* _ under Windows, $ under OS/2 1.x, I under OS/2 2, and N under NT,
+* and post-fixes the name with .DLL. The DLL is installed into Notes by
+* simply placing its executable into the Notes Program Directory.
+*
+* Notes automatically loads the hook drivers at initialization.
+* The list of hook drivers to be loaded is specified in NOTES.INI in a
+* variable called NSF_HOOKS with a comma separator. Thus, in order to load
+* three hook drivers, the variable might be specified as
+* NSF_HOOKS=drivera,driverb,driverc. Note that it isn't necessary to
+* specify the prefix character or the suffix .DLL.
+*
+* Because of instantiation requirements of the operating systems,
+* the library is loaded once per process. At load time, the first entry
+* point address (entry point @1) is obtained by ordinal, and the driver's
+* Init() function is invoked. The principal use of this function is to plug
+* a data structure with vectors to other hook driver subroutines,
+* including its Term() function which will be called by Notes when the
+* process exits (or performs NotesTerm()).
+*
+* Remember that in some environments (such as Windows), you must
+* export, in your DEF file, all of your functions that Notes will call
+* through these vectors. This is because Windows uses the fact that it's
+* exported to generate a thunk that sets up the DLL's DS appropriately on
+* all of these entry points.
+*
+* 3. All code executed by all entry points to the drivers must
+* be 100% re-entrant by both multiple threads within a single process and
+* multiple processes. In Windows, if you Yield() or make a call to a
+* Notes API function, you may also be preempted by another process that
+* does a hook driver call, so reentrancy is a requirement even in Windows.
+* (Notes makes heavy use of multiple threads and multiple processes, so
+* this must be treated as a required feature, not as something that can
+* be done "later".)
+*
+* Following is the data structure passed to your hook driver's Init routine.
+* When your routine is called, the hModule is filled in (just in case you
+* need it to load resources), and the rest of the vectors are zero'ed.
+* If you don't need to hook any of these vectors, leave them NULL. Otherwise,
+* plug the vectors in your Init routine.
+*
+*/
+
+//commented for LotusNotify Miranga NG plugin beacouse of conflicts with miranda headers (struct LIST at m_system_cpp.h)
+// typedef struct dbhookvec
+ // {
+
+ // /* Module handle of the hook library */
+
+ // HMODULE hModule;
+
+ // /* Initialization vector. This is simply a pointer to the routine
+ // exported as ordinal #1 in your DLL. You needn't plug this
+ // vector because it's plugged before calling through it to do
+ // driver initializations. This routine is called once for each
+ // process that does a NotesInit(). */
+
+ // STATUS (LNCALLBACKPTR Init)(struct dbhookvec far *vec);
+
+ // /* Termination vector. This is called once for each process that
+ // did an Init call, just prior to the process's exiting. */
+
+ // STATUS (LNCALLBACKPTR Term)(struct dbhookvec far *vec);
+
+ // /* Note open hook. This routine is called just AFTER a note is opened
+ // by the NSF subsystem. It is called for both local and remote
+ // databases. UserName is the name of the user doing the open.
+ // GroupList may be NULL, but when it's not it contains a list of
+ // the groups that the user is in. hDB and NoteID can be used
+ // to identify the database and note (use NSFDbPathGet to get the
+ // pathname of the database). OpenFlags are the flags originally
+ // passed into NSFNoteOpen. hNote is the handle to the note that
+ // is about to be returned to the caller. Your hook driver may
+ // modify the contents of the note, or may return an error from
+ // this routine if you wish to fail the open call. You may use any
+ // standard Notes error code to fail the call. */
+
+ // STATUS (LNCALLBACKPTR NoteOpen)(struct dbhookvec far *vec, char far *UserName, LIST far *GroupList, DBHANDLE hDB, NOTEID NoteID, NOTEHANDLE hNote, WORD OpenFlags);
+
+ // /* Note add/update hook, also handles deletion
+ // This routine is called just BEFORE a note is updated
+ // by the NSF subsystem. It is called for both local and remote
+ // databases. UserName is the name of the user doing the open.
+ // GroupList may be NULL, but when it's not it contains a list of
+ // the groups that the user is in. hDB and NoteID can be used
+ // to identify the database and note (use NSFDbPathGet to get the
+ // pathname of the database). pUpdateFlags is a pointer to a WORD
+ // of UpdateFlags originally passed into NSFNoteUpdate. The hook
+ // may examine and modify the UpdateFlags WORD before returning,
+ // thus modifying the flags that will be passed into NSFNoteUpdate.
+ // hNote is the handle to the note that is about to be updated.
+ // Your hook driver may modify the contents of the note, or may
+ // return an error from this routine if you wish to fail the update
+ // call. You may use any standard Notes error code to fail the call.
+ // Note that you can use the following algorithm to determine
+ // precisely the operation being performed:
+
+ // * if (NoteID == NOTEID_ADD
+ // * || NoteID == NOTEID_ADD_OR_REPLACE
+ // * || NoteID == NOTEID_ADD_UNID)
+ // * {
+ // * if ((*pUpdateFlags) & UPDATE_DELETED)
+ // * ; ** Adding a new "deleted note stub" to a database **
+ // * else
+ // * ; ** Adding a new document to a database **
+ // * }
+ // * else
+ // * {
+ // * if ((*pUpdateFlags) & UPDATE_DELETED)
+ // * ; ** Deleting an existing document from the database. **
+ // * ** Note that in this case, the contents of the hNote **
+ // * ** may be nil and should be disregarded; because of **
+ // * ** this, there's no way to tell the class of a note **
+ // * ** being deleted at this point **
+ // * else
+ // * ; ** Updating an existing document in the database **
+ // * }
+
+ // */
+
+ // STATUS (LNCALLBACKPTR NoteUpdate)(struct dbhookvec far *vec, char far *UserName, LIST far *GroupList, DBHANDLE hDB, NOTEID NoteID, NOTEHANDLE hNote, WORD far *pUpdateFlags);
+
+ // /* Note stamp (Categorization) hook.
+ // This routine is called just BEFORE a set of notes is Categorized
+ // by the NSF subsystem. It is called for both local and remote
+ // databases. UserName is the name of the user doing the categorization.
+ // GroupList may be NULL, but when it's not it contains a list of
+ // the groups that the user is in. hDB and hTable can be used
+ // to identify the database and notes (use NSFDbPathGet to get the
+ // pathname of the database). ItemName and Data indicate the data
+ // being used in the categorization. Your hook routine may return
+ // an error if you wish to fail the Stamp call. You may use any
+ // standard Notes error code to fail the call. */
+
+ // STATUS (LNCALLBACKPTR DbStampNotes)(struct dbhookvec far *vec, char far *UserName, LIST far *GroupList, DBHANDLE hDB, HANDLE hIDTable, char far *ItemName, WORD ItemNameLength, void far *Data, WORD Length);
+
+ // /* Flags used by Notes to describe the hook driver -- RESERVED */
+
+ // DWORD Flags;
+
+ // } DBHOOKVEC;
+
+STATUS LNPUBLIC NSFDbDirGet(DBHANDLE hDB, char *retDir);
+STATUS LNPUBLIC NSFDbIsLocallyEncrypted (DBHANDLE hDB, BOOL *pRetval);
+STATUS LNPUBLIC NSFGetOrgDir(char *UserName, char *retDir);
+
+/* End of Note Storage File Database Definitions */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
+
+
+#if defined(OS400) && (__OS400_TGTVRM__ >= 510)
+#pragma datamodel(pop)
+#endif
+
diff --git a/protocols/LotusNotify/src/cnotesapi/include/nsferr.h b/protocols/LotusNotify/src/cnotesapi/include/nsferr.h
new file mode 100644
index 0000000000..7796be85cf
--- /dev/null
+++ b/protocols/LotusNotify/src/cnotesapi/include/nsferr.h
@@ -0,0 +1,2663 @@
+
+#if defined(OS400) && (__OS400_TGTVRM__ >= 510)
+#pragma datamodel(P128)
+#endif
+
+/*********************************************************************/
+/* */
+/* Licensed Materials - Property of IBM */
+/* */
+/* L-GHUS-5VMPGW, L-GHUS-5S3PEE */
+/* (C) Copyright IBM Corp. 1989, 2005 All Rights Reserved */
+/* */
+/* US Government Users Restricted Rights - Use, duplication or */
+/* disclosure restricted by GSA ADP Schedule Contract with */
+/* IBM Corp. */
+/* */
+/*********************************************************************/
+
+
+#ifndef NSF_ERR_DEFS
+#define NSF_ERR_DEFS
+
+/* DB2 Note Storage File Error Code Definitions 0x3B00 */
+#ifndef NSF_STR_DEFS
+#include "nsfstr.h"
+#endif
+
+#define ERR_DB2NSF_NOT_IMPL PKG_DB2NSF+0
+ errortext(ERR_DB2NSF_NOT_IMPL, "This feature not yet implemented for DB2 based .nsf(s)")
+#define ERR_DB2NSF_FAILURE PKG_DB2NSF+1
+ errortext(ERR_DB2NSF_FAILURE, "General NSFDB2 error.")
+#define ERR_DB2NSF_CORRUPT PKG_DB2NSF+2
+ errortext(ERR_DB2NSF_CORRUPT, "Corrupt/invalid data found in DB2 - unable to continue")
+#define ERR_DB2NSF_CLI_ERROR PKG_DB2NSF+3
+ errortext(ERR_DB2NSF_CLI_ERROR, "DB2 CLI/SQL error")
+#define ERR_DB2NSF_INI PKG_DB2NSF+4
+ errortext(ERR_DB2NSF_INI, "Invalid or missing DB2/MI .ini file entries")
+#define ERR_DB2NSF_NAME_LENGTH PKG_DB2NSF+5
+ errortext(ERR_DB2NSF_NAME_LENGTH, "Name exceeds DB2 maximum identifier length")
+#define ERR_DB2NSF_BYPASS_XACT PKG_DB2NSF+6
+ errortext(ERR_DB2NSF_BYPASS_XACT, "Internal error - should not appear")
+#define ERR_DB2NSF_NO_BEGIN_XACT PKG_DB2NSF+7
+ errortext(ERR_DB2NSF_NO_BEGIN_XACT, "There is no active transaction to end")
+#define ERR_DB2NSF_PARMS_NEEDED PKG_DB2NSF+10
+ errortext(ERR_DB2NSF_PARMS_NEEDED, "Parameters needed for SQL-based view")
+#define ERR_DB2NSF_SUM_NOTE_SET PKG_DB2NSF+12
+ errortext(ERR_DB2NSF_SUM_NOTE_SET, "Unable to create selected DB2 note set.")
+#define ERR_DB2NSF_NIF_READONLY PKG_DB2NSF+13
+ errortext(ERR_DB2NSF_NIF_READONLY, "Update or commit of read-only DB2 NIF connection")
+#define ERR_DB2NSF_ACCESS_ROWLEN PKG_DB2NSF+14
+ errortext(ERR_DB2NSF_ACCESS_ROWLEN, "Column Length or Total Access Table Row Length exceeds maximum allowed by DB2.")
+#define ERR_DB2NSF_ACCESS_DEFTYPES PKG_DB2NSF+15
+ errortext( ERR_DB2NSF_ACCESS_DEFTYPES, "Incompatible DB2 data type and Notes data type or data format options, fieldname: ")
+#define ERR_DB2NSF_ACCESS_FIELDLEN PKG_DB2NSF+16
+ errortext( ERR_DB2NSF_ACCESS_FIELDLEN, "Access Table field data exceeds defined length")
+#define ERR_DB2NSF_INVALID_LENGTH_READ PKG_DB2NSF+17
+ errortext(ERR_DB2NSF_INVALID_LENGTH_READ, "Number of bytes read is smaller than expected.")
+#define ERR_DB2NSF_NOT_ENABLED_FOR_DB2 PKG_DB2NSF+18
+ errortext( ERR_DB2NSF_NOT_ENABLED_FOR_DB2, "Domino server is not DB2-enabled or DB2 services were unable to initialize when the server started up.")
+#define ERR_DB2NSF_CANNOT_USE_DATASTORE PKG_DB2NSF+19
+ errortext( ERR_DB2NSF_CANNOT_USE_DATASTORE, "You need Server Administrator access to use the requested datastore")
+#define ERR_DB2NSF_TABLESPACE_IN_USE PKG_DB2NSF+20
+ errortext( ERR_DB2NSF_TABLESPACE_IN_USE, "Requested tablespace already in use")
+#define ERR_DB2NSF_BAD_OPTIONS2_FLAGS PKG_DB2NSF+21
+ apitext( ERR_DB2NSF_BAD_OPTIONS2_FLAGS, "Invalid Options2 flags value")
+#define ERR_DB2NSF_INCONSISTENT_COLLECTION PKG_DB2NSF+22
+ apitext( ERR_DB2NSF_INCONSISTENT_COLLECTION, "DB2-based Collection is corrupt")
+#define ERR_DB2NSF_OPEN_NOT_ALLOWED PKG_DB2NSF+23
+ apitext( ERR_DB2NSF_OPEN_NOT_ALLOWED, "A DB2-based nsf cannot be opened locally. It must be opened through the DB2-enabled Domino Server.")
+#define ERR_DB2NSF_SERVICES_UNAVAILABLE PKG_DB2NSF+24
+ apitext( ERR_DB2NSF_SERVICES_UNAVAILABLE, "DB2 services may be unavailable or the DB2-based nsf may be corrupt.")
+#define ERR_DB2NSF_XLATE_POOLFULL PKG_DB2NSF+25
+ errortext( ERR_DB2NSF_XLATE_POOLFULL, "Insufficient memory - DB2 xlate pool is full.")
+#define ERR_DB2NSF_IMAP_NOT_SUPPORTED PKG_DB2NSF+26
+ apitext( ERR_DB2NSF_IMAP_NOT_SUPPORTED, "IMAP is not supported for DB2-based nsfs.")
+#define ERR_DB2NSF_NO_OVERRIDE_RIGHTS PKG_DB2NSF+27
+ apitext( ERR_DB2NSF_NO_OVERRIDE_RIGHTS, "User does not have datastore override rights.")
+#define ERR_DB2NSF_QUERY_TOO_LONG PKG_DB2NSF+28
+ apitext( ERR_DB2NSF_QUERY_TOO_LONG, "DB2 query exceeds maximum length." )
+#define ERR_DB2NSF_BUF_TOO_SMALL PKG_DB2NSF+29
+ apitext(ERR_DB2NSF_BUF_TOO_SMALL, "Allocated buffer too small")
+#define ERR_DB2NSF_INIT_FAILURE PKG_DB2NSF+30
+ apitext( ERR_DB2NSF_INIT_FAILURE, "Unable to initialize DB2 services. DB2-based nsfs will be unusable." )
+
+/* Error codes from the XML mapping file starting with 0x3B30*/
+#define ERR_DB2NSF_WARNING PKG_DB2NSF+48
+ errortext(ERR_DB2NSF_WARNING, "DB2-SQL warning exception.")
+#define ERR_DB2NSF_NODATA PKG_DB2NSF+49
+ errortext(ERR_DB2NSF_NODATA, "DB2-SQL no data exception.")
+#define ERR_DB2NSF_DYNAMIC_SQL PKG_DB2NSF+50
+ errortext(ERR_DB2NSF_DYNAMIC_SQL, "DB2-Dynamic SQL error.")
+#define ERR_DB2NSF_CONNECTION PKG_DB2NSF+51
+ errortext(ERR_DB2NSF_CONNECTION, "DB2-Connection Exception.")
+#define ERR_DB2NSF_TRIGGER PKG_DB2NSF+52
+ errortext(ERR_DB2NSF_TRIGGER, "DB2-Triggered action exception.")
+#define ERR_DB2NSF_FEATURE PKG_DB2NSF+53
+ errortext(ERR_DB2NSF_FEATURE, "DB2-Feature not supported.")
+#define ERR_DB2NSF_TYPE PKG_DB2NSF+54
+ errortext(ERR_DB2NSF_TYPE, "DB2-Invalid target type specification.")
+#define ERR_DB2NSF_SCHEMA PKG_DB2NSF+55
+ errortext(ERR_DB2NSF_SCHEMA, "DB2-Invalid Schema name list specification.")
+#define ERR_DB2NSF_TOKEN PKG_DB2NSF+56
+ errortext(ERR_DB2NSF_TOKEN, "DB2-Invalid token.")
+#define ERR_DB2NSF_0K00 PKG_DB2NSF+57
+ errortext(ERR_DB2NSF_0K00, "DB2-0K00 exception")
+#define ERR_DB2NSF_TRIG_PROHIBIT PKG_DB2NSF+58
+ errortext(ERR_DB2NSF_TRIG_PROHIBIT, "DB2-Prohibited statement encountered during trigger.")
+#define ERR_DB2NSF_CASE PKG_DB2NSF+59
+ errortext(ERR_DB2NSF_CASE, "DB2-Case not found for case statement.")
+#define ERR_DB2NSF_CARDINALITY PKG_DB2NSF+60
+ errortext(ERR_DB2NSF_CARDINALITY, "DB2-Cardinality violation.")
+#define ERR_DB2NSF_DATA PKG_DB2NSF+61
+ errortext(ERR_DB2NSF_DATA, "DB2-Data exception.")
+#define ERR_DB2NSF_CONSTRAINT PKG_DB2NSF+62
+ errortext(ERR_DB2NSF_CONSTRAINT, "DB2-Constraint violation.")
+#define ERR_DB2NSF_INV_CURS_STATE PKG_DB2NSF+63
+ errortext(ERR_DB2NSF_INV_CURS_STATE, "DB2-Invalid cursor state.")
+#define ERR_DB2NSF_INV_TRAN_STATE PKG_DB2NSF+64
+ errortext(ERR_DB2NSF_INV_TRAN_STATE, "DB2-Invalid transaction state.")
+#define ERR_DB2NSF_INV_STMT_ID PKG_DB2NSF+65
+ errortext(ERR_DB2NSF_INV_STMT_ID, "DB2-Invalid SQL statement identifier.")
+#define ERR_DB2NSF_INV_AUTH_SPEC PKG_DB2NSF+66
+ errortext(ERR_DB2NSF_INV_AUTH_SPEC, "DB2-Invalid authorization specification.")
+#define ERR_DB2NSF_INV_TRAN_TERMINATION PKG_DB2NSF+67
+ errortext(ERR_DB2NSF_INV_TRAN_TERMINATION, "DB2-Invalid transaction termination.")
+#define ERR_DB2NSF_INV_CONN_NAME PKG_DB2NSF+68
+ errortext(ERR_DB2NSF_INV_CONN_NAME, "DB2-Invalid connection name.")
+#define ERR_DB2NSF_INV_CURS_NAME PKG_DB2NSF+69
+ errortext(ERR_DB2NSF_INV_CURS_NAME, "DB2-Invalid cursor name.")
+#define ERR_DB2NSF_36001 PKG_DB2NSF+70
+ errortext(ERR_DB2NSF_36001, "DB2-36001 error.")
+#define ERR_DB2NSF_SYNTAX PKG_DB2NSF+71
+ errortext(ERR_DB2NSF_SYNTAX, "DB2-Syntax error.")
+#define ERR_DB2NSF_EXT_FUNC_EX PKG_DB2NSF+72
+ errortext(ERR_DB2NSF_EXT_FUNC_EX, "DB2-External function exception.")
+#define ERR_DB2NSF_EXT_FUNC_CALL_EX PKG_DB2NSF+73
+ errortext(ERR_DB2NSF_EXT_FUNC_CALL_EX, "DB2-External function call exception.")
+#define ERR_DB2NSF_SAVEP_EX PKG_DB2NSF+74
+ errortext(ERR_DB2NSF_SAVEP_EX, "DB2-Savepoint exception.")
+#define ERR_DB2NSF_SERIALIZATION PKG_DB2NSF+75
+ errortext(ERR_DB2NSF_SERIALIZATION, "DB2-Serialization failure.")
+#define ERR_DB2NSF_AUTHORIZATION PKG_DB2NSF+76
+ errortext(ERR_DB2NSF_AUTHORIZATION, "DB2-Authorization violation.")
+#define ERR_DB2NSF_VIEW_DEF PKG_DB2NSF+77
+ errortext(ERR_DB2NSF_VIEW_DEF, "DB2-View definition error.")
+#define ERR_DB2NSF_46XXX PKG_DB2NSF+78
+ errortext(ERR_DB2NSF_46XXX, "DB2-46XXX error.")
+#define ERR_DB2NSF_INV_APP_STATE PKG_DB2NSF+79
+ errortext(ERR_DB2NSF_INV_APP_STATE, "DB2-Invalid application state.")
+#define ERR_DB2NSF_DUP_UNDEF_NAME PKG_DB2NSF+80
+ errortext(ERR_DB2NSF_DUP_UNDEF_NAME, "DB2-Duplicate or undefined name.")
+#define ERR_DB2NSF_INV_OPERAND PKG_DB2NSF+81
+ errortext(ERR_DB2NSF_INV_OPERAND, "DB2-Invalid operand or inconsistent specification.")
+#define ERR_DB2NSF_LIMIT_EXCEEDED PKG_DB2NSF+82
+ errortext(ERR_DB2NSF_LIMIT_EXCEEDED, "DB2-SQL or Product limit exceeded.")
+#define ERR_DB2NSF_PREREQ_STATE PKG_DB2NSF+83
+ errortext(ERR_DB2NSF_PREREQ_STATE, "DB2-Object not in prerequisite state.")
+#define ERR_DB2NSF_MISC_RESTRICTIONS PKG_DB2NSF+84
+ errortext(ERR_DB2NSF_MISC_RESTRICTIONS, "DB2-Miscellaneous SQL or product restrictions.")
+#define ERR_DB2NSF_RESOURCE PKG_DB2NSF+85
+ errortext(ERR_DB2NSF_RESOURCE, "DB2-Resource not available or operator intervention.")
+#define ERR_DB2NSF_SYSTEM PKG_DB2NSF+86
+ errortext(ERR_DB2NSF_SYSTEM, "DB2-System error.")
+#define ERR_DB2NSF_NOXMLMAP PKG_DB2NSF+87
+ errortext(ERR_DB2NSF_NOXMLMAP, "File db2errmp.xml not found.")
+#define ERR_DB2NSF_MAPSUCCESS PKG_DB2NSF+88
+ errortext(ERR_DB2NSF_MAPSUCCESS, "The map for DB2 errors was successfully created.\n")
+#define ERR_DB2NSF_XML_PARSE PKG_DB2NSF+89
+ errortext(ERR_DB2NSF_XML_PARSE, "The parsing of XML DB2 error file failed; the map for DB2 errors was not created.")
+#define ERR_DB2NSF_GENERIC_FAILURE PKG_DB2NSF+90
+ errortext(ERR_DB2NSF_GENERIC_FAILURE, "DB2 NSF failure.")
+#define ERR_DB2NSF_ENABLED PKG_DB2NSF+91
+ stringtext(ERR_DB2NSF_ENABLED, "DB2 Server:|Not Enabled|Enabled|DB2 Access:")
+#define IDX_DB2_ENABLED_SERVER 1
+#define IDX_DB2_ENABLED_NOT_EN 2
+#define IDX_DB2_ENABLED_EN 3
+#define IDX_DB2_ENABLED_ACCESS 4
+#define ERR_DB2NSF_DB PKG_DB2NSF+92
+ stringtext(ERR_DB2NSF_DB, "DB2 Database: ")
+#define ERR_DB2NSF_BUFFERPOOL PKG_DB2NSF+93
+ errortext(ERR_DB2NSF_BUFFERPOOL, "DB2 - Buffer pool not allocated, using a buffer pool that may be too small.")
+#define ERR_DB2NSF_ENABLE_STR PKG_DB2NSF+94
+ errortext(ERR_DB2NSF_ENABLE_STR, "DB2 SERVER ENABLE LOG\n")
+#define ERR_DB2NSF_ENABLE_STATE PKG_DB2NSF+95
+ errortext(ERR_DB2NSF_ENABLE_STATE, "Server doc update|Notes.ini update|Server id update|Catalog node|Load DB2 Library|Create user account|Add DB2DOM group to SYSCTRL_GROUP|Send server doc update request to Admin Process")
+#define IDX_DB2_ENABLE_SRVDOC 1
+#define IDX_DB2_ENABLE_INI 2
+#define IDX_DB2_ENABLE_ID 3
+#define IDX_DB2_ENABLE_CATNODE 4
+#define IDX_DB2_ENABLE_LOADLIB 5
+#define IDX_DB2_ENABLE_USER 6
+#define IDX_DB2_ENABLE_GROUP 7
+#define IDX_DB2_ENABLE_SRVDOC_ADMINP 8
+
+#define ERR_DB2NSF_ENABLE_STATUS PKG_DB2NSF+96
+ errortext(ERR_DB2NSF_ENABLE_STATUS, "TASK -- |started\n|completed\n|failed with the preceding error(s)\n|%s%sfailed with error (%s)\n")
+#define IDX_DB2_ENABLE_TASK 1
+#define IDX_DB2_ENABLE_START 2
+#define IDX_DB2_ENABLE_COMP 3
+#define IDX_DB2_ENABLE_ERROR 4
+#define IDX_DB2_ENABLE_ERROR_STRING 5
+#define ERR_DB2NSF_XMLFILE PKG_DB2NSF+97
+ errortext(ERR_DB2NSF_XMLFILE, "The XML file db2errmp.xml might be incomplete or corrupt. A partial error map was created.")
+#define ERR_DB2NSF_TABLESPACE_MISSING PKG_DB2NSF+98
+ errortext(ERR_DB2NSF_TABLESPACE_MISSING, "Tablespace (%s) does not exist")
+#define ERR_DB2NSF_SCHEMA_MISSING PKG_DB2NSF+99
+ errortext(ERR_DB2NSF_SCHEMA_MISSING, "Schema (%s) does not exist")
+#define ERR_DB2NSF_DAVPOP_BUSY PKG_DB2NSF+100
+ errortext(ERR_DB2NSF_DAVPOP_BUSY, "DB2 Access View Populator is already handling this population request." )
+#define ERR_DB2NSF_XACL_NOT_SUPPORTED PKG_DB2NSF+101
+ errortext(ERR_DB2NSF_XACL_NOT_SUPPORTED, "Extended ACL is not supported for DB2-based nsfs." )
+#define ERR_DB2CREATE_TS PKG_DB2NSF+102
+ errortext(ERR_DB2CREATE_TS, "Tablespace container path is too long.")
+#define ERR_DB2LOAD_ACC_DEF PKG_DB2NSF+103
+ errortext(ERR_DB2LOAD_ACC_DEF, "Failed when loading the access definition.")
+#define ERR_DB2READ_NOTE PKG_DB2NSF+104
+ errortext(ERR_DB2READ_NOTE, "Failed when DB2 was reading a note.")
+#define ERR_DB2WRITE_RNOTE PKG_DB2NSF+105
+ errortext(ERR_DB2WRITE_RNOTE, "Failed when DB2 was writing a row in a note.")
+#define ERR_DB2GET_NSF_SIZE PKG_DB2NSF+106
+ errortext(ERR_DB2GET_NSF_SIZE, "Failed calculating DB2 NSF size.")
+#define ERR_DB2CREATEDB2 PKG_DB2NSF+107
+ errortext(ERR_DB2CREATEDB2, "Failed creating DB2 Database.")
+#define ERR_DB2NSF_WRONGSCHEMA PKG_DB2NSF+108
+ errortext(ERR_DB2NSF_WRONGSCHEMA, "DB2 Database has the incorrect schema level and cannot be used by this server." )
+#define ERR_DB2ACC_CN_NAME PKG_DB2NSF+109
+ errortext(ERR_DB2ACC_CN_NAME, "Failed to obtain full canonical name from person document." )
+#define ERR_DB2ACC_DB2_NAME PKG_DB2NSF+110
+ errortext(ERR_DB2ACC_DB2_NAME, "Failed to obtain DB2 account name from person document." )
+#define ERR_DB2_MULTIPLENAMES PKG_DB2NSF+111
+ errortext(ERR_DB2_MULTIPLENAMES, "Invalid DB2 user name mapping. Multiple Notes users mapped to a single DB2 user are not allowed. Contact your administrator.")
+#define ERR_DB2_DB2ACCESSMAPPEDERR PKG_DB2NSF+112
+ errortext(ERR_DB2_DB2ACCESSMAPPEDERR, "A DB2 Access Error occurred. Server log will contain more information.")
+#define ERR_DB2NSF_DB2_CFG_SET PKG_DB2NSF+113
+ errortext(ERR_DB2NSF_DB2_CFG_SET, "Error setting configuration parms for DB2 database." )
+#define ERR_DB2NSF_FORMAT PKG_DB2NSF+114
+ errortext(ERR_DB2NSF_FORMAT, "%s %s %s: %s - %s - %s" )
+
+/* there may be some available PKG_DB2NSF offsets above... */
+/* this is the *current* max; PKG_DB2NSF offsets range from 0 to 255 */
+#define ERR_DB2NSF_MAX PKG_DB2NSF+115
+ errortext(ERR_DB2NSF_MAX, "This is the last error message in the DB2NSF error range")
+
+/* #endif */
+
+/* End of Error Codes */
+
+/* Formula Compiler Error Codes */
+
+#define ERR_FORMULA_COMPILATION PKG_FORMULA+1
+ errortext(ERR_FORMULA_COMPILATION, "Formula Error")
+#define ERR_INVALID_OPERATOR PKG_FORMULA+2
+ errortext(ERR_INVALID_OPERATOR, "Invalid operator")
+#define ERR_INVALID_ARG_TYPE PKG_FORMULA+3
+ errortext(ERR_INVALID_ARG_TYPE, "Invalid type of argument")
+#define ERR_TOO_MANY_ARGS PKG_FORMULA+4
+ errortext(ERR_TOO_MANY_ARGS, "Too many arguments for @Function")
+#define ERR_FN_OR_OP_EXPECTED PKG_FORMULA+5
+ errortext(ERR_FN_OR_OP_EXPECTED, "@Function or operator expected, or @Function does not require an argument")
+#define ERR_INSUFFICIENT_ARGS PKG_FORMULA+6
+ errortext(ERR_INSUFFICIENT_ARGS, "Insufficient arguments for @Function")
+#define ERR_NOT_UNARY PKG_FORMULA+7
+ errortext(ERR_NOT_UNARY, "Inappropriate (unary) usage of an operator")
+#define ERR_NOT_BINARY PKG_FORMULA+8
+ errortext(ERR_NOT_BINARY, "Inappropriate (binary) usage of an operator")
+#define ERR_NESTED_ASSIGN PKG_FORMULA+9
+ errortext(ERR_NESTED_ASSIGN,"Assignment operators must not be preceded by other operators")
+#define ERR_PREMATURE_EOI PKG_FORMULA+10
+ errortext(ERR_PREMATURE_EOI,"Formula incomplete")
+#define ERR_OP_EXPECTED PKG_FORMULA+11
+ errortext(ERR_OP_EXPECTED, "An operator or semicolon was expected but none was encountered")
+#define ERR_INVALID_FORMULA PKG_FORMULA+12
+ errortext(ERR_INVALID_FORMULA, "Invalid formula structure")
+#define ERR_PAREN_EXPECTED PKG_FORMULA+13
+ errortext(ERR_PAREN_EXPECTED, "Left parenthesis expected")
+#define ERR_EXTRA_RPAREN PKG_FORMULA+14
+ errortext(ERR_EXTRA_RPAREN, "Extra right parenthesis")
+#define ERR_MISSING_RPAREN PKG_FORMULA+15
+ errortext(ERR_MISSING_RPAREN, "Missing right parenthesis")
+#define ERR_ASSIGNMENT_POS PKG_FORMULA+16
+ errortext(ERR_ASSIGNMENT_POS, "FIELD must be followed by a variable name and :=")
+#define ERR_ASSIGNMENT_TARGET PKG_FORMULA+17
+ errortext(ERR_ASSIGNMENT_TARGET, ":= must be immediately preceded by a field or variable name")
+#define ERR_ASSIGNMENT_MODIFIER PKG_FORMULA+18
+ errortext(ERR_ASSIGNMENT_MODIFIER, "Only ENVIRONMENT, DEFAULT, or FIELD can be used as a modifier to :=")
+#define ERR_MISSING_ASS_SEP PKG_FORMULA+19
+ errortext(ERR_MISSING_ASS_SEP, "Missing semicolon")
+#define ERR_REM_FORMAT PKG_FORMULA+20
+ errortext(ERR_REM_FORMAT, "REM must be followed by a quoted string containing the remark.")
+#define ERR_NO_MAIN_EXPRESSION PKG_FORMULA+21
+ errortext(ERR_NO_MAIN_EXPRESSION, "No main or selection expression in formula")
+#define ERR_NOT_A_FUNCTION PKG_FORMULA+22
+ errortext(ERR_NOT_A_FUNCTION, "Passing arguments to a non-@Function or to an @Function that doesn't require arguments")
+#define ERR_UNTERMINATED_LITERAL PKG_FORMULA+23
+ errortext(ERR_UNTERMINATED_LITERAL, "End of formula reached before end of quoted string, date/time or array accessor")
+#define ERR_IF_ODD_ARGS PKG_FORMULA+24
+ errortext(ERR_IF_ODD_ARGS, "@If must have an odd number of arguments")
+#define ERR_ONE_MAIN_EXPR PKG_FORMULA+25
+ errortext(ERR_ONE_MAIN_EXPR, "Only one SELECT expression is allowed")
+#define ERR_NO_FORMULA PKG_FORMULA+26
+ errortext(ERR_NO_FORMULA, "No formula specified")
+#define ERR_UNKNOWN_FUNCTION PKG_FORMULA+27
+ errortext(ERR_UNKNOWN_FUNCTION, "Unknown @Function")
+#define ERR_SUMMITEMS_MERGE PKG_FORMULA+28
+ debugtext(ERR_SUMMITEMS_MERGE, "EXPRESSION_SUMMITEMS present multiple times!")
+#define ERR_DUPLICATE_IVAR PKG_FORMULA+29
+ errortext(ERR_DUPLICATE_IVAR, "Variable already defined")
+#define ERR_ARGS_EXPECTED PKG_FORMULA+30
+ errortext(ERR_ARGS_EXPECTED, "@Function arguments expected but none were supplied")
+#define ERR_BIG_LITERAL PKG_FORMULA+31
+ errortext(ERR_BIG_LITERAL, "Quoted string is too long.")
+#define ERR_MISSING_ASS PKG_FORMULA+32
+ errortext(ERR_MISSING_ASS, ":= must be used in conjunction with FIELD, ENVIRONMENT, or DEFAULT")
+#define ERR_UNKNOWN_FKWD PKG_FORMULA+33
+ errortext(ERR_UNKNOWN_FKWD, "Unknown [KeyWord] for @Function")
+#define ERR_NO_SELECT_EXPR PKG_FORMULA+34
+ errortext(ERR_NO_SELECT_EXPR, "SELECT is inappropriate for this type of formula")
+#define ERR_FORMULA_HIDDEN PKG_FORMULA+35
+ errortext(ERR_FORMULA_HIDDEN, "Formula is hidden")
+#define ERR_IVAR_NAME_TOO_LONG PKG_FORMULA+36
+ errortext(ERR_IVAR_NAME_TOO_LONG, "Variable name is too long")
+#define ERR_EXTRA_BRACKET PKG_FORMULA+37
+ errortext(ERR_EXTRA_BRACKET, "Extra right bracket found")
+#define ERR_FIELD_HAS_NO_VALUE PKG_FORMULA+38
+ errortext(ERR_FIELD_HAS_NO_VALUE, "Field name requires a value")
+
+/* Compute Error Codes */
+
+#define ERR_OP_INVALID PKG_FORMULA+50
+ errortext(ERR_OP_INVALID, "Invalid formula: unknown function/operator")
+#define ERR_OP_UNIMPLEMENTED PKG_FORMULA+51
+ errortext(ERR_OP_UNIMPLEMENTED, "Invalid formula: unimplemented function/operator")
+#define ERR_INVALID_TYPE_FOR_OP PKG_FORMULA+52
+ errortext(ERR_INVALID_TYPE_FOR_OP, "Incorrect data type for operator or @Function")
+#define ERR_ARGS_INVALID PKG_FORMULA+53
+ errortext(ERR_ARGS_INVALID, "Invalid formula format: bad number of arguments")
+#define ERR_FORMULA_GENERATED PKG_FORMULA+54
+ errortext(ERR_FORMULA_GENERATED, "ERROR specified in formula")
+#define ERR_STRING_TOO_LONG PKG_FORMULA+55
+ errortext(ERR_STRING_TOO_LONG, "String values cannot be longer than 65535 bytes")
+#define ERR_NO_MAIN_RESULT PKG_FORMULA+56
+ errortext(ERR_NO_MAIN_RESULT, "unable to compute formula value")
+#define ERR_USERNAME PKG_FORMULA+57
+ errortext(ERR_USERNAME, "USERNAME is not configured properly")
+#define ERR_SUBSET PKG_FORMULA+58
+ errortext(ERR_SUBSET, "The second argument to @Subset must not be zero")
+#define ERR_FORMULA_EXEC PKG_FORMULA+59
+ errortext(ERR_FORMULA_EXEC, "Indirect Formula Computation not allowed")
+#define ERR_TEXT_EXPECTED PKG_FORMULA+60
+ errortext(ERR_TEXT_EXPECTED, "Incorrect data type for operator or @Function: Text expected")
+#define ERR_NUMBER_EXPECTED PKG_FORMULA+61
+ errortext(ERR_NUMBER_EXPECTED, "Incorrect data type for operator or @Function: Number expected")
+#define ERR_TIME_EXPECTED PKG_FORMULA+62
+ errortext(ERR_TIME_EXPECTED, "Incorrect data type for operator or @Function: Time/Date expected")
+#define ERR_NTD_EXPECTED PKG_FORMULA+63
+ errortext(ERR_NTD_EXPECTED, "Incorrect data type: Text, Number, or Time/Date expected")
+#define ERR_DATETIME_FMT PKG_FORMULA+64
+ errortext(ERR_DATETIME_FMT, "The @Date and @Time functions must have exactly 1, 3, or 6 arguments.")
+#define ERR_BINOP_TYPES PKG_FORMULA+65
+ errortext(ERR_BINOP_TYPES, "Comparison operators must be supplied two values of the same data type.")
+#define ERR_NONAMES PKG_FORMULA+66
+ errortext(ERR_NONAMES, "This view is obsolete and requires missing field list. Please edit and re-save the view.")
+#define ERR_COMPUTE_LOCALMEM PKG_FORMULA+67
+ errortext(ERR_COMPUTE_LOCALMEM, "Formula or value requires too much memory")
+#define ERR_COMPUTE_FULL PKG_FORMULA+68
+ errortext(ERR_COMPUTE_FULL, "Too many concurrent formula evaluations; please retry")
+#define ERR_COMPUTE_EXTENSION PKG_FORMULA+69
+ errortext(ERR_COMPUTE_EXTENSION,"Unknown @Function Extension")
+#define ERR_KEYWORD_EXPECTED PKG_FORMULA+70
+ errortext(ERR_KEYWORD_EXPECTED, "Incorrect data type for operator or @Function: [KeyWord] expected")
+#define ERR_KEYWORD_CONTEXT PKG_FORMULA+71
+ errortext(ERR_KEYWORD_CONTEXT, "The specified [KeyWord] is not appropriate when used with this @Function")
+#define ERR_PROMPT PKG_FORMULA+72
+ errortext(ERR_PROMPT, "The first argument to @Prompt must be between 1 and 6")
+#define ERR_TOTIME PKG_FORMULA+73
+ errortext(ERR_TOTIME, "The value cannot be converted to a Time/Date.")
+#define ERR_UNAVAILABLE PKG_FORMULA+74
+ internaltext(ERR_UNAVAILABLE, "formula has encountered @DeleteField or @Unavailable")
+#define ERR_TONUMBER PKG_FORMULA+75
+ errortext(ERR_TONUMBER, "The value cannot be converted to a Number.")
+#define ERR_GETDOCFIELD_NOTENOTFOUND PKG_FORMULA+76
+ errortext(ERR_GETDOCFIELD_NOTENOTFOUND, "Document could not be found.")
+#define ERR_COMPUTE_FIELD_TOO_BIG PKG_FORMULA+77
+ errortext(ERR_COMPUTE_FIELD_TOO_BIG,"Fields referenced or generated by a formula may not exceed 20,000 bytes.")
+#define ERR_ARCHIVE_NO_ARCH_CRITERA PKG_FORMULA+78
+ errortext(ERR_ARCHIVE_NO_ARCH_CRITERA,"No archive criteria found")
+#define ERR_DESCENDANTS PKG_FORMULA+79
+ errortext(ERR_DESCENDANTS,"This database must be compacted to support the use of @AllChildren or @AllDescendants in a formula.")
+#define ERR_PICK_LIST_STYLE PKG_FORMULA+80
+ errortext(ERR_PICK_LIST_STYLE, "The first argument to @PickList must specify a valid @PickList style.")
+#define ERR_STRING_BADUNID PKG_FORMULA+81
+ errortext(ERR_STRING_BADUNID, "Invalid UNID; UNID must be a 32-digit hex string.")
+#define ERR_ABSTRACT_BADSIZE PKG_FORMULA+82
+ errortext(ERR_ABSTRACT_BADSIZE, "The buffer size argument of @Abstract must be greater than zero")
+#define ERR_EXPLODE_BADRANGE PKG_FORMULA+83
+ errortext(ERR_EXPLODE_BADRANGE, "The time-date range argument of @Explode spans too many days")
+#define ERR_COMPUTE_LENGTH_WORD PKG_FORMULA+84
+ errortext(ERR_COMPUTE_LENGTH_WORD, "The result of a computation cannot exceed 65535 bytes")
+#define ERR_ADMIN_SELECTION PKG_FORMULA+85
+ errortext(ERR_ADMIN_SELECTION, "The currently selected note is not from the correct view.")
+#define ERR_URLHISTORY PKG_FORMULA+86
+ errortext(ERR_URLHISTORY, "The first argument to @URLHistory must be between 1 and 5")
+#define ERR_ADMIN_NO_REQ_FIELD PKG_FORMULA+87
+ errortext(ERR_ADMIN_NO_REQ_FIELD, "A selected note is missing a required field and cannot be acted upon by the Administration Process.")
+#define ERR_FUNCTION_CONTEXT PKG_FORMULA+88
+ errortext(ERR_FUNCTION_CONTEXT, "@Function is not valid in this context")
+#define ERR_FUNCTION_NOUICOMMANDS PKG_FORMULA+89
+ errortext(ERR_FUNCTION_NOUICOMMANDS, "@Commands and other UI functions are not allowed in this context")
+#define ERR_NSF_COMPUTE_NOASSIGN PKG_FORMULA+90
+ errortext(ERR_NSF_COMPUTE_NOASSIGN, "You are not allowed to modify fields in this context.")
+#define ERR_NSF_COMPUTE_NOSIDE PKG_FORMULA+91
+ errortext(ERR_NSF_COMPUTE_NOSIDE, "Formulas with side-effects are not allowed in this context.")
+#define LOG_MAILSEND_NO_MATCH PKG_FORMULA+92
+ errortext(LOG_MAILSEND_NO_MATCH, "Unable to send mail to %s, no match found in Name & Address Book(s)")
+#define LOG_MAILSEND_AMBIG_MATCH PKG_FORMULA+93
+ errortext(LOG_MAILSEND_AMBIG_MATCH, "Unable to send mail to %s, multiple matches found in Name & Address Book(s)")
+#define ERR_TOO_MANY_ELEMENTS PKG_FORMULA+94
+ errortext(ERR_TOO_MANY_ELEMENTS, "List values cannot have more than 65535 elements when storing in an item")
+#define ERR_ARRAY_INDEX PKG_FORMULA+95
+ errortext(ERR_ARRAY_INDEX, "Array index out of bounds")
+#define ERR_EVAL_RECURSION_DEPTH PKG_FORMULA+96
+ errortext(ERR_EVAL_RECURSION_DEPTH, "@Eval has exceeded the maximum number of recursive calls.")
+#define ERR_COMPUTE_RECURSE_LIMIT PKG_FORMULA+97
+ errortext(ERR_COMPUTE_RECURSE_LIMIT, "Too many recursive formula evaluations.")
+#define ERR_COMPUTE_TIMEOUT PKG_FORMULA+98
+ errortext(ERR_COMPUTE_TIMEOUT, "The formula has exceeded the maximum execution time.")
+#define ERR_COMPUTE_MEMORY_MAX PKG_FORMULA+99
+ errortext(ERR_COMPUTE_MEMORY_MAX, "The formula has exceeded the maximum allowable memory usage.")
+#define ERR_ARCHIVE_SRC_IS_DEST PKG_FORMULA+100
+ errortext(ERR_ARCHIVE_SRC_IS_DEST,"You are not allowed to archive to and from the same database.")
+#define ERR_ARC_NO_PROFILE PKG_FORMULA+101
+ errortext(ERR_ARC_NO_PROFILE, "Archive profile note not found.")
+
+#define ERR_ARCHIVE_NOT_MIN_SERVER_VER PKG_FORMULA+102
+ errortext(ERR_ARCHIVE_NOT_MIN_SERVER_VER, "This action is not supported on this version of the Domino Server.")
+#define ERR_ARCHIVE_FIELDS_NOT_SIGNED PKG_FORMULA+103
+ errortext(ERR_ARCHIVE_FIELDS_NOT_SIGNED, "All of the required fields in your archive settings have not been properly signed. Please re-save your archive settings to correct this problem.")
+
+#define ERR_ARCHIVE_FIELDS_NOT_FOUND PKG_FORMULA+104
+ errortext(ERR_ARCHIVE_FIELDS_NOT_FOUND, "All of the required fields in your archive settings have not been found. Please re-save your archive settings to correct this problem.")
+#define ERR_COMPUTE_CHARSET_CONVERSION PKG_FORMULA+105
+ errortext(ERR_COMPUTE_CHARSET_CONVERSION, "Error converting string from LMBCS to UNICODE")
+#define ERR_ARCHIVE_NOT_ON_SRC_SRV PKG_FORMULA+106
+ errortext(ERR_ARCHIVE_NOT_ON_SRC_SRV, "The source server specified in your archive settings is not this server. Archiving will not be performed.")
+#define ERR_CORRUPTED_COMPUTE_INSTANCE PKG_FORMULA+107
+ errortext(ERR_CORRUPTED_COMPUTE_INSTANCE, "Internal error: Corrupted formula instance detected")
+#define ERR_COMPUTE_STACK_OVERFLOW PKG_FORMULA+108
+ errortext(ERR_COMPUTE_STACK_OVERFLOW, "Stack overflow evaluating formula. Try simplifying the formula.")
+#define ERR_ARCHIVE_CRIT_NO_SUP_ON_SRC PKG_FORMULA+109
+ errortext(ERR_ARCHIVE_CRIT_NO_SUP_ON_SRC, "'Older than' selection criteria is not supported on the server chosen to archive from, because its version is prior to 7.0. One or more enabled criteria use this selection criteria and will not be executed.")
+
+/* Note PKG_FORMULA is limited to 0 - 127 */
+
+/* Note Storage File Error Code Definitions */
+
+#define ERR_RM_FAIL_RESTART_OPEN PKG_NSF+0
+ errortext(ERR_RM_FAIL_RESTART_OPEN, "Recovery Manager: Logged Database cannot be accessed during Restart/Media Recovery Phase")
+#define ERR_NOT_NSF PKG_NSF+1
+ errortext(ERR_NOT_NSF, "File is not a database")
+#define ERR_IGNORE_NOTE PKG_NSF+2
+ internaltext(ERR_IGNORE_NOTE, "ignore this note during copy")
+#define ERR_WRITEONLY PKG_NSF+3
+ errortext(ERR_WRITEONLY,"Write-only database")
+#define ERR_READONLY PKG_NSF+4
+ errortext(ERR_READONLY, "Read-only database")
+#define ERR_CONFLICT PKG_NSF+5
+ errortext(ERR_CONFLICT, "Someone else modified this document at the same time")
+#define ERR_STRUCT PKG_NSF+6
+ errortext(ERR_STRUCT, "The program cannot interpret this file due to an invalid structure")
+#define ERR_DOC_STRUCT PKG_NSF+7
+ errortext(ERR_DOC_STRUCT,"Document has invalid structure")
+#define ERR_VALUE_FLAGS PKG_NSF+8
+ internaltext(ERR_VALUE_FLAGS,"Invalid combination of flags")
+#define ERR_BUCKET_FULL PKG_NSF+9
+ errortext(ERR_BUCKET_FULL,"The text fields of the document are too large to be stored. Please reduce their size.")
+#define ERR_UNK PKG_NSF+10
+ internaltext(ERR_UNK, "UNK does not exist")
+#define ERR_BUCKET PKG_NSF+11
+ internaltext(ERR_BUCKET,"Invalid pos, not in BUCKET areas")
+#define ERR_BUCKET_NOT_IN_MEM PKG_NSF+12
+ internaltext(ERR_BUCKET_NOT_IN_MEM, "(bucket not found)")
+#define ERR_NO_FILE_SHARING PKG_NSF+13
+ errortext(ERR_NO_FILE_SHARING, "This database is currently being used by someone else. In order to share a Notes database, all users must use a Domino Server instead of a File Server.")
+#define ERR_NSF_NOTE_POOLFULL PKG_NSF+14
+ errortext(ERR_NSF_NOTE_POOLFULL, "Insufficient memory - Open Note Pool is full.")
+#define ERR_NOTE_EMPTY PKG_NSF+15
+ errortext(ERR_NOTE_EMPTY, "Document has nothing to undelete")
+#define ERR_NO_MORE_MATCHES PKG_NSF+16
+ internaltext(ERR_NO_MORE_MATCHES, "(Search status - no more to do)")
+#define ERR_FORMULA PKG_NSF+17
+ errortext(ERR_FORMULA, "Invalid formula format")
+#define ERR_RM_PARTIAL_WRITE_DETECTED PKG_NSF+18
+ errortext(ERR_RM_PARTIAL_WRITE_DETECTED, "Recovery Manager: Partial Write detected during Redo, marking database Corrupt.")
+#define ERR_OPERATOR PKG_NSF+19
+ errortext(ERR_OPERATOR, "Invalid operator for data type")
+#define ERR_NOTE_ID PKG_NSF+20
+ errortext(ERR_NOTE_ID, "Invalid document identifier")
+#define ERR_NEW_NAME_KEY PKG_NSF+21
+ internaltext(ERR_NEW_NAME_KEY,"New name key being added")
+#define ERR_EVENT_TOO_BIG PKG_NSF+22
+ apitext(ERR_EVENT_TOO_BIG,"Event struct size plus data is bigger than 256 bytes")
+#define DBD_NOCACHE_STRING PKG_NSF+23
+ stringtext(DBD_NOCACHE_STRING,"NoCache")
+#define ERR_DBD_TOO_MANY_DRIVERS PKG_NSF+24
+ errortext(ERR_DBD_TOO_MANY_DRIVERS,"You may not use that many different database drivers in any one application.")
+#define ERR_NSF_VERSION PKG_NSF+25
+ errortext(ERR_NSF_VERSION, "Invalid NSF version")
+#define ERR_SEARCH_FLAGS PKG_NSF+26
+ apitext(ERR_SEARCH_FLAGS, "Search flags are incompatible")
+#define ERR_FULL_RECALC PKG_NSF+27
+ internaltext(ERR_FULL_RECALC, "(full recalc necessary)")
+#define ERR_DIRECTORY PKG_NSF+28
+ errortext(ERR_DIRECTORY, "This function is inappropriate for file system directories.")
+#define ERR_NOT_DIRECTORY PKG_NSF+29
+ errortext(ERR_NOT_DIRECTORY, "This function is only appropriate for directories.")
+#define ERR_ITEM_DEF_TYPE PKG_NSF+30
+ internaltext(ERR_ITEM_DEF_TYPE, "Cannot add item def - type unknown")
+#define ERR_BUCKET_STRUCT PKG_NSF+31
+ internaltext(ERR_BUCKET_STRUCT, "Invalid structure in bucket")
+#define ERR_NOT_LOCAL PKG_NSF+32
+ apitext(ERR_NOT_LOCAL, "Function is not supported for remote databases")
+#define ERR_DUP_SUMM_ITEM PKG_NSF+33
+ errortext(ERR_DUP_SUMM_ITEM, "Duplicate field in document")
+#define ERR_ITEM_NOT_FOUND PKG_NSF+34
+ apitext(ERR_ITEM_NOT_FOUND,"Note item not found")
+#define ERR_ENTRY_NOT_FOUND PKG_NSF+35
+ apitext(ERR_ENTRY_NOT_FOUND, "Cache entry not found")
+#define ERR_FMARKER PKG_NSF+36
+ internaltext(ERR_FMARKER,"Missing formula marker in merge formula")
+#define ERR_NOTE_DELETED PKG_NSF+37
+ errortext(ERR_NOTE_DELETED, "Document has been deleted")
+#define ERR_UNK_TYPE PKG_NSF+38
+ errortext(ERR_UNK_TYPE, "Field type (UNK) stored in document is invalid")
+#define ERR_INVALID_NOTE PKG_NSF+39
+ errortext(ERR_INVALID_NOTE, "Invalid or nonexistent document")
+#define ERR_AUXCLASS PKG_NSF+40
+ internaltext(ERR_AUXCLASS, "Invalid usage of Auxiliary Class Field")
+#define ERR_NSFOPEN PKG_NSF+41
+ errortext(ERR_NSFOPEN, "Database is currently in use by you or another user")
+#define ERR_NOTE_NOT_EMPTY PKG_NSF+42
+ internaltext(ERR_NOTE_NOT_EMPTY,"note pool not deleted because it is not empty")
+#define ERR_NOTE_NONDISCARDABLE PKG_NSF+43
+ internaltext(ERR_NOTE_NONDISCARDABLE,"note pool not discardable")
+#define ERR_NOTE_DISCARDED PKG_NSF+44
+ internaltext(ERR_NOTE_DISCARDED,"note pool has been discarded")
+#define ERR_NSF_INFO_SIZE PKG_NSF+45
+ errortext(ERR_NSF_INFO_SIZE,"Database title is too large; please use a shorter title.")
+#define ERR_NSF_IN_USE PKG_NSF+46
+ errortext(ERR_NSF_IN_USE,"Cannot do that to an NSF that may be in use")
+#define ERR_INVALID_NAME PKG_NSF+47
+ errortext(ERR_INVALID_NAME,"Remote pathname must be relative to Data Directory")
+#define ERR_NSF_POOLFULL PKG_NSF+48
+ errortext(ERR_NSF_POOLFULL, "Insufficient memory - NSF pool is full.")
+#define ERR_SUMMARY_TOO_BIG PKG_NSF+49
+ errortext(ERR_SUMMARY_TOO_BIG,"Field is too large (32K) or View's column & selection formulas are too large")
+#define ERR_DBCLASS PKG_NSF+50
+ errortext(ERR_DBCLASS, "Invalid NSF Class")
+#define ERR_TOOHUGE PKG_NSF+51
+ errortext(ERR_TOOHUGE, "Object too large to allocate given file params")
+#define ERR_NIFNOTE PKG_NSF+52
+ errortext(ERR_NIFNOTE, "Cannot create document in this type of file")
+#define ERR_NOFILESPACE PKG_NSF+53
+ errortext(ERR_NOFILESPACE,"Cannot allocate database object - database space exhausted")
+#define ERR_BADOBJECT PKG_NSF+54
+ internaltext(ERR_BADOBJECT,"Invalid Object ID")
+#define ERR_TRANSLOG_MISSING_SEGS PKG_NSF+55
+ errortext(ERR_TRANSLOG_MISSING_SEGS, "Missing or damaged transaction log segment.")
+#define ERR_NSF_CORRUPT PKG_NSF+56
+ errortext(ERR_NSF_CORRUPT,"Database is corrupt -- Cannot allocate space")
+#define ERR_SOURCE_DB_CLOSED PKG_NSF+57
+ errortext(ERR_SOURCE_DB_CLOSED,"Cannot access the document's original database to copy attachments")
+#define ERR_ENCODING PKG_NSF+58
+ errortext(ERR_ENCODING,"Unknown type of compression technique")
+#define ERR_NO_CLIENT PKG_NSF+59
+ debugtext(ERR_NO_CLIENT,"Remote operations not allowed in standalone programs")
+#define ERR_NO_MODIFIED_NOTES PKG_NSF+60
+ errortext(ERR_NO_MODIFIED_NOTES,"No documents have been modified since specified time.")
+#define ERR_NO_STAMPED_NOTES PKG_NSF+61
+ errortext(ERR_NO_STAMPED_NOTES,"No documents were categorized")
+#define ERR_NO_ITEM_IN_NOTE PKG_NSF+62
+ internaltext(ERR_NO_ITEM_IN_NOTE,"(no such item in document)")
+#define ERR_ITEM_DATATYPE PKG_NSF+63
+ errortext(ERR_ITEM_DATATYPE,"field in note has wrong datatype")
+#define ERR_ITEM_LENGTH PKG_NSF+64
+ errortext(ERR_ITEM_LENGTH,"Field length stored in document is incorrect")
+#define ERR_BAD_PARAM PKG_NSF+65
+ internaltext(ERR_BAD_PARAM, "(invalid usage - see NSF documentation)")
+#define ERR_SPECIAL_ID PKG_NSF+66
+ errortext(ERR_SPECIAL_ID, "Special database object cannot be located")
+#define ERR_INVALID_ITEMLEN PKG_NSF+67
+ errortext(ERR_INVALID_ITEMLEN, "Document is damaged or obsolete (incorrect field length)")
+#define ERR_INVALID_ITEMTYPE PKG_NSF+68
+ errortext(ERR_INVALID_ITEMTYPE, "Document is damaged or obsolete (unrecognized data type)")
+#define ERR_COMPILER_LOAD PKG_NSF+69
+ errortext(ERR_COMPILER_LOAD, "Insufficient memory to load Formula Compiler/Decompiler, or cannot locate the appropriate program file")
+#define ERR_NOACCESS PKG_NSF+70
+ errortext(ERR_NOACCESS, "You are not authorized to perform that operation")
+#define ERR_NO_HELP_INDEX PKG_NSF+71
+ errortext(ERR_NO_HELP_INDEX, "Help Index cannot be located")
+#define ERR_HELP_SECTION PKG_NSF+72
+ errortext(ERR_HELP_SECTION, "Notes can't automatically display Help on this section, but you can open the Notes Help database and search its Index.")
+#define ERR_HELP_CATEGORY PKG_NSF+73
+ errortext(ERR_HELP_CATEGORY, "Notes can't automatically display Help on this subject, but you can open the Notes Help database and search its Index. For Help on server administration, add and open the Domino Administrator Help database.")
+#define ERR_HELP_TOOBIG PKG_NSF+74
+ internaltext(ERR_HELP_TOOBIG, "(help string too large)")
+#define ERR_OPEN_FILE PKG_NSF+75
+ errortext(ERR_OPEN_FILE, "You are not authorized to access that database")
+#define ERR_DEL_FILE PKG_NSF+76
+ errortext(ERR_DEL_FILE, "You are not authorized to delete that database")
+#define ERR_UPDATE_CLASS PKG_NSF+77
+ internaltext(ERR_UPDATE_CLASS, "(you cannot change the class of a note once stored)")
+#define ERR_NOT_AUTHOR PKG_NSF+78
+ errortext(ERR_NOT_AUTHOR, "You cannot update or delete the document(s) since you are not listed as an allowable Author for this document")
+#define ERR_OBJECT_TRUNCATED PKG_NSF+79
+ errortext(ERR_OBJECT_TRUNCATED, "File object is truncated - file may have been damaged")
+#define ERR_DBFREE_ARGS PKG_NSF+80
+ debugtext(ERR_DBFREE_ARGS, "(DbFree: Invalid Disk Position/Size)")
+#define ERR_NTUPDATE_0OID PKG_NSF+81
+ debugtext(ERR_NTUPDATE_0OID,"(NSFNoteUpdate: 0 OID field!)")
+#define ERR_NO_HELP_LINKS PKG_NSF+82
+ errortext(ERR_NO_HELP_LINKS,"Help Indexing Information is not available")
+#define ERR_FMARKERSRC PKG_NSF+83
+ apitext(ERR_FMARKERSRC, "Formula markers not allowed in merge source formula")
+#define ERR_EXISTS_DIR PKG_NSF+84
+ errortext(ERR_EXISTS_DIR, "Cannot create database - the specified filename is a directory")
+#define ERR_NTCREATE_LICENSE PKG_NSF+85
+ errortext(ERR_NTCREATE_LICENSE, "Cannot create a document without a valid user license")
+#define ERR_CREATE_FILE PKG_NSF+86
+ errortext(ERR_CREATE_FILE, "You are not authorized to create new databases on this server")
+#define ERR_CREATE_REP_FILE PKG_NSF+87
+ errortext(ERR_CREATE_REP_FILE,"You are not authorized to create new replica databases on this server")
+#define ERR_DIGEST_LENGTH PKG_NSF+88
+ debugtext(ERR_DIGEST_LENGTH,"Message digest overflowed buffer!")
+#define ERR_NOTE_NOT_SIGNED PKG_NSF+89
+ errortext(ERR_NOTE_NOT_SIGNED,"Document is not signed.")
+#define ERR_NOTE_INVSIG1 PKG_NSF+90
+ errortext(ERR_NOTE_INVSIG1, "Signature on document is invalid (digest length)")
+#define ERR_NOTE_INVSIG2 PKG_NSF+91
+ errortext(ERR_NOTE_INVSIG2, "Document has been modified or corrupted since signed! (data)")
+#define ERR_NOTE_INVSIG3 PKG_NSF+92
+ errortext(ERR_NOTE_INVSIG3,"You and signer have no Certificates in common; signer cannot be assumed to be trustworthy.")
+#define ERR_NOTE_INVSIG4 PKG_NSF+93
+ errortext(ERR_NOTE_INVSIG4, "Signature on document is invalid (certifier digest length)")
+#define ERR_NOTE_INVSIG5 PKG_NSF+94
+ errortext(ERR_NOTE_INVSIG5, "Signature has been modified or corrupted since document was signed!")
+#define ERR_NOTE_INVSIG6 PKG_NSF+95
+ errortext(ERR_NOTE_INVSIG6, "Signature on document is invalid (digest length)")
+#define ERR_NOTE_INVSIG7 PKG_NSF+96
+ errortext(ERR_NOTE_INVSIG7, "Document has been modified or corrupted since signed! (signature)")
+#define ERR_NOTE_BADATTSIGN PKG_NSF+97
+ errortext(ERR_NOTE_BADATTSIGN, "Attachment has been modified or corrupted since signed!")
+#define ERR_NOTE_NOT_SEALED PKG_NSF+98
+ errortext(ERR_NOTE_NOT_SEALED, "Document is not encrypted.")
+#define ERR_NOTE_ALREADY_SEALED PKG_NSF+99
+ errortext(ERR_NOTE_ALREADY_SEALED,"You cannot encrypt a document that is already encrypted.")
+#define ERR_NOEXTRACT_ENCRYPTED PKG_NSF+100
+ errortext(ERR_NOEXTRACT_ENCRYPTED,"You must supply the bulk decryption key in order to extract this file object.")
+#define ERR_NOT_SEALED_FOR_YOU PKG_NSF+101
+ errortext(ERR_NOT_SEALED_FOR_YOU,"You cannot access portions of this document because it is encrypted and was not intended for you, or you do not have the decryption key.")
+#define ERR_ALREADY_LOCKED PKG_NSF+102
+ errortext(ERR_ALREADY_LOCKED,"Database is currently being replicated or copied elsewhere")
+#define LOG_OVERDBSIZEWARNTHRESHOLD PKG_NSF+103
+ errortext(LOG_OVERDBSIZEWARNTHRESHOLD, "Warning, database %s has exceeded its warning size threshold of %d KB by %k.")
+#define ERR_DB_NOT_OPEN PKG_NSF+104
+ errortext(ERR_DB_NOT_OPEN,"Specified database is not currently open")
+#define ERR_STS_STRINGTOOLONG PKG_NSF+105
+ errortext(ERR_STS_STRINGTOOLONG,"Text search string is too long")
+#define ERR_NOACTIVITY PKG_NSF+106
+ errortext(ERR_NOACTIVITY, "User activity recording is disabled")
+#define ERR_FIELDNAME_TOO_LONG PKG_NSF+107
+ errortext(ERR_FIELDNAME_TOO_LONG,"Field names must be 250 characters or less")
+#define ERR_COMPHALT1 PKG_NSF+108
+ debugtext(ERR_COMPHALT1, "(not enough items written)")
+#define ERR_COMPHALT2 PKG_NSF+109
+ debugtext(ERR_COMPHALT2, "(incorrect length written)")
+#define ERR_COMPHALT3 PKG_NSF+110
+ debugtext(ERR_COMPHALT3, "(unevaluated default summary value)")
+#define ERR_NO_DELETED_NOTES PKG_NSF+111
+ errortext(ERR_NO_DELETED_NOTES,"No documents were deleted")
+#define ERR_DATA_ONLY PKG_NSF+112
+ internaltext(ERR_DATA_ONLY, "(only data notes may be deleted using this call)")
+#define ERR_REMOTE_UNID PKG_NSF+113
+ internaltext(ERR_REMOTE_UNID,"(you cannot obtain the UNIDs using this call to remote databases)")
+#define ERR_MISSING_PRIVS PKG_NSF+114
+ errortext(ERR_MISSING_PRIVS,"All privileges are required for this operation")
+#define ERR_INVALID_ITEMUNK PKG_NSF+115
+ errortext(ERR_INVALID_ITEMUNK, "Document is damaged or obsolete (unrecognized field)")
+#define ERR_FIXUP_DOC PKG_NSF+116
+ errortext(ERR_FIXUP_DOC, "Document NT%08lx in database %p is damaged: %e")
+#define ERR_FIXUP_DOC_DELETED PKG_NSF+117
+ errortext(ERR_FIXUP_DOC_DELETED,"Document (UNID OF%08lx:%08lx-ON%08lx:%08lx) in database %p has been deleted")
+#define ERR_INVALID_UNK_TBL PKG_NSF+118
+ errortext(ERR_INVALID_UNK_TBL, "Field name table (UNK table) is damaged")
+#define ERR_UNK_TBL_REPAIRED PKG_NSF+119
+ errortext(ERR_UNK_TBL_REPAIRED, "Field name table (UNK table) has been repaired")
+#define ERR_NO_NAMED_KEY PKG_NSF+120
+ errortext(ERR_NO_NAMED_KEY, "You cannot access portions of this document because it was encrypted and you do not have any of the keys")
+#define ERR_BAD_KEY_DATA PKG_NSF+121
+ errortext(ERR_BAD_KEY_DATA, "You are unable to decrypt this document because your key is incorrect")
+#define ERR_FIXUP_DOC_ITEM PKG_NSF+122
+ errortext(ERR_FIXUP_DOC_ITEM, "Document NT%08lx in database %p is damaged: %e (Field %s, Datatype %04x)")
+#define ERR_PURGING PKG_NSF+123
+ stringtext(ERR_PURGING, "Releasing unused storage in database %s...")
+#define ERR_PURGING_DOCS PKG_NSF+124
+ stringtext(ERR_PURGING_DOCS, "Purging old documents from database %s...")
+#define ERR_PURGE_QUERY PKG_NSF+125
+ errortext(ERR_PURGE_QUERY, "The Replication Cutoff Date indicates that documents before %z should be purged from the database %s. Would you like it to be done now?")
+#define ERR_ITEM_NAME_HUGE PKG_NSF+126
+ errortext(ERR_ITEM_NAME_HUGE, "You can only Sign documents whose Field names are < 512 bytes.")
+#define ERR_NO_ENCRYPT_FIELDS PKG_NSF+127
+ errortext(ERR_NO_ENCRYPT_FIELDS,"Document does not specify any fields to be encrypted")
+#define ERR_FIXING PKG_NSF+128
+ stringtext(ERR_FIXING, "Performing consistency check on %s...")
+#define ERR_OBJ_GONE PKG_NSF+129
+ errortext(ERR_OBJ_GONE, "Database object has been deleted")
+#define ERR_FORM_DELETED PKG_NSF+130
+ errortext(ERR_FORM_DELETED,"Form has been deleted")
+#define ERR_NULL_ITEM_HANDLE PKG_NSF+131
+ debugtext(ERR_NULL_ITEM_HANDLE,"NSFItemAppendByBLOCKID: bhValue of NULL")
+#define ERR_FIXUP_BUCKET_REPAIRED PKG_NSF+132
+ errortext(ERR_FIXUP_BUCKET_REPAIRED,"Partially-saved document in database %p has been deleted")
+#define ERR_FILEMAX PKG_NSF+133
+ errortext(ERR_FILEMAX, "Database (.nsf) has grown too large; use compact to reduce the file size or use use File New Replica to recreate your file with larger capacity.")
+#define ERR_NSF_CORRUPT2 PKG_NSF+134
+ errortext(ERR_NSF_CORRUPT2,"Database has been corrupted and can't be repaired; cannot open")
+#define ERR_NSF_UNKTBL2BIG PKG_NSF+135
+ errortext(ERR_NSF_UNKTBL2BIG,"Cannot store document - database has too many unique field names. Please set the 'Allow more fields in database' option or ask your administrator to compact the database.")
+#define ERR_FILEMAXV1 PKG_NSF+136
+ errortext(ERR_FILEMAXV1, "Notes Version 1 database (.nsf) has grown larger than 40MB; use File Replication New Replica to recreate your file as a Notes Version 4 database (.nsf) capable of 4GB.")
+#define ERR_DESKMAXV1 PKG_NSF+137
+ errortext(ERR_DESKMAXV1, "Notes Version 1 workspace file (DESKTOP.DSK) has grown larger than 1MB; you can delete DESKTOP.DSK if you wish a new one to be created that is capable of 50MB of private views.")
+#define ERR_DESKMAX PKG_NSF+138
+ errortext(ERR_DESKMAX, "Workspace file (DESKTOP.DSK) has grown too large; remove some of your private views or icons.")
+#define ERR_TBD PKG_NSF+139
+ errortext(ERR_TBD, "Function to-be-defined")
+#define ERR_BTNODE_TOO_SMALL PKG_NSF+140
+ errortext(ERR_BTNODE_TOO_SMALL, "B-tree node too small - Can't hold 3 entries")
+#define ERR_BTNODE_TOO_BIG PKG_NSF+141
+ errortext(ERR_BTNODE_TOO_BIG, "B-tree node is larger than the maximum slot size")
+#define ERR_INVALID_BTREE PKG_NSF+142
+ errortext(ERR_INVALID_BTREE, "B-tree structure is invalid")
+#define ERR_NO_BUFFER PKG_NSF+143
+#ifdef MAC
+ errortext(ERR_NO_BUFFER,"There is not enough memory for a view or database buffer. Please close any unneeded windows. You may also increase Notes' available memory by quitting and choosing 'Get Info...' from the Finder.")
+#else
+ errortext(ERR_NO_BUFFER,"There is not enough memory for a view or database buffer. Increase NSF_BUFFER_POOL_SIZE.")
+#endif
+#define ERR_INVALID_PAGE PKG_NSF+144
+ errortext(ERR_INVALID_PAGE, "Page format is incorrect")
+#define ERR_MAXBTDEPTH PKG_NSF+145
+ errortext(ERR_MAXBTDEPTH, "Maximum depth of b-tree index reached")
+#define ERR_SHARE_CONFLICT PKG_NSF+146
+ errortext(ERR_SHARE_CONFLICT, "Operation can't be performed while container is in use")
+#define ERR_BAD_SNO PKG_NSF+147
+ errortext(ERR_BAD_SNO, "Attempt to use an invalid slot number")
+#define ERR_RM_CANNOT_RECOVER PKG_NSF+148
+ errortext(ERR_RM_CANNOT_RECOVER, "Recovery Manager: Unable to recover DB")
+#define ERR_BAD_DBP PKG_NSF+149
+ errortext(ERR_BAD_DBP, "Attempt to use an invalid database pointer")
+#define ERR_BT_NOTOPEN PKG_NSF+150
+ errortext(ERR_BT_NOTOPEN, "B-tree index has not been opened")
+#define ERR_BAD_PNOVEC PKG_NSF+151
+ errortext(ERR_BAD_PNOVEC, "Invalid PNO vector - position == 0")
+#define ERR_NOTA_IDB PKG_NSF+152
+ debugtext(ERR_NOTA_IDB, "Block is not a IDB")
+#define ERR_NOTA_DBBUF PKG_NSF+153
+ debugtext(ERR_NOTA_DBBUF, "Block is not a DBBUF")
+#define ERR_NOTA_DBBUFCTL PKG_NSF+154
+ debugtext(ERR_NOTA_DBBUFCTL, "Block is not a DBBUFCTL")
+#define ERR_NOTA_DBCONT PKG_NSF+155
+ debugtext(ERR_NOTA_DBCONT, "Block is not a DBCONT")
+#define ERR_FILE_ALLOCATED PKG_NSF+156
+ errortext(ERR_FILE_ALLOCATED, "Container not found - new context allocated")
+#define ERR_NOTA_DBB_HASH PKG_NSF+157
+ debugtext(ERR_NOTA_DBB_HASH, "Block is not a DBB_HASH")
+#define ERR_NO_SPACE PKG_NSF+158
+ errortext(ERR_NO_SPACE, "No space on page for slot")
+#define ERR_INTEGRITY PKG_NSF+159
+ errortext(ERR_INTEGRITY, "The integrity of a database storage container has been lost - the container will be rebuilt.")
+#define ERR_NSF_NOV2 PKG_NSF+160
+ errortext(ERR_NSF_NOV2, "This function cannot be performed in conjunction with a Notes Version 2 Server")
+#define ERR_NSF_INTERRUPT PKG_NSF+161
+ errortext(ERR_NSF_INTERRUPT,"Your connection to the server unexpectedly dropped; please retry the operation")
+#define NSFSTR_LINK_STR1 PKG_NSF+162
+ stringtext(NSFSTR_LINK_STR1,"Database")
+#define NSFSTR_LINK_STR2 PKG_NSF+163
+ stringtext(NSFSTR_LINK_STR2,"View")
+#define NSFSTR_LINK_STR3 PKG_NSF+164
+ stringtext(NSFSTR_LINK_STR3,"Document")
+#define ERR_ALREADY_ALLOC PKG_NSF+165
+ internaltext(ERR_ALREADY_ALLOC, "(RRV already allocated)")
+#define ERR_COMPACT_MODE PKG_NSF+166
+ errortext(ERR_COMPACT_MODE, "Function cannot be performed while database is being compacted")
+#define ERR_DBD_NON_NOTES PKG_NSF+167
+ errortext(ERR_DBD_NON_NOTES,"You may not use that database driver")
+#define NSFSTR_COMPACT_PROGRESS PKG_NSF+168
+ stringtext(NSFSTR_COMPACT_PROGRESS,"Compacting database")
+#define STR_FILTER_NEVER PKG_NSF+169
+ stringtext(STR_FILTER_NEVER,"Never")
+#define STR_FILTER_HOURLY PKG_NSF+170
+ stringtext(STR_FILTER_HOURLY,"hourly")
+#define STR_FILTER_DAILY PKG_NSF+171
+ stringtext(STR_FILTER_DAILY,"daily")
+#define STR_FILTER_WEEKLY PKG_NSF+172
+ stringtext(STR_FILTER_WEEKLY,"weekly")
+#define ERR_OBJECT_LENGTH PKG_NSF+173
+ errortext(ERR_OBJECT_LENGTH,"Document attachment is invalid")
+#define ERR_BUFPOOL_TOO_SMALL PKG_NSF+174
+#ifdef MAC
+ errortext(ERR_BUFPOOL_TOO_SMALL,"Insufficient memory for a view or database buffer. Please close any unneeded windows. You may also increase Notes' available memory by quitting and choosing 'Get Info...' from the Finder.")
+#else
+ errortext(ERR_BUFPOOL_TOO_SMALL,"Insufficient memory for a view or database buffer.")
+#endif
+#define ERR_NSF_CORRUPT_RRVMAP PKG_NSF+175
+ errortext(ERR_NSF_CORRUPT_RRVMAP,"Database is damaged and can't be repaired (RRV buckets bad)")
+#define ERR_HDL_LVL0 PKG_NSF+176
+ errortext(ERR_HDL_LVL0, "Maximum number of concurrently open objects has been exceeded")
+#define ERR_HDL_PARAM PKG_NSF+177
+ errortext(ERR_HDL_PARAM, "No associated pointer to object")
+#define ERR_HDL_NULL PKG_NSF+178
+ errortext(ERR_HDL_NULL, "Null object handle")
+#define ERR_HDL_OOR PKG_NSF+179
+ errortext(ERR_HDL_OOR, "Object handle out of range")
+#define ERR_HDL_DEALLOC PKG_NSF+180
+ errortext(ERR_HDL_DEALLOC, "Object handle is invalid")
+#define ERR_CANNOT_OPEN_NSF PKG_NSF+181
+ errortext(ERR_CANNOT_OPEN_NSF, "File not found or not a Notes database")
+#define ERR_REALLOC_PNOVEC PKG_NSF+182
+ errortext(ERR_REALLOC_PNOVEC, "Unable to enlarge a view container. Increase NSF_BUFFER_POOL_SIZE.")
+#define ERR_BAD_PNO PKG_NSF+183
+ errortext(ERR_BAD_PNO, "Attempt to use an invalid page number")
+#define ERR_DUPLICATE_UNID PKG_NSF+184
+ errortext(ERR_DUPLICATE_UNID,"Database already contains a document with this ID (UNID)")
+#define ERR_DB_NOT_LOADED PKG_NSF+185
+ internaltext(ERR_DB_NOT_LOADED,"(DbDemandLoadByHandle must be called)")
+#define ERR_FIXUP_UNID_CHANGED PKG_NSF+186
+ errortext(ERR_FIXUP_UNID_CHANGED,"Document NT%08lx in database %p has been assigned a new UNID")
+#define ERR_NO_UNID_INDEX PKG_NSF+187
+ internaltext(ERR_NO_UNID_INDEX,"(UNID index has not been created or opened)")
+#define ERR_NSF_CORRUPT_UNIDIDX PKG_NSF+188
+ errortext(ERR_NSF_CORRUPT_UNIDIDX,"Database is damaged and can't be repaired (UNID index)")
+#define ERR_FIXUP_REBUILD_UNID PKG_NSF+189
+ errortext(ERR_FIXUP_REBUILD_UNID,"Rebuild UNID index in database %p")
+#define ERR_INVALID_EHASH PKG_NSF+190
+ errortext(ERR_INVALID_EHASH, "Extendible hash index structure is invalid")
+#define ERR_USERDATA_TRUNC PKG_NSF+191
+ errortext(ERR_USERDATA_TRUNC, "Container user data buffer will be truncated")
+#define ERR_EH_CORRUPT PKG_NSF+192
+ errortext(ERR_EH_CORRUPT, "Extendible hash index is corrupt and can't be used")
+#define ERR_CANT_CHANGE_UNID PKG_NSF+193
+ apitext(ERR_CANT_CHANGE_UNID,"Can't change document's UNID")
+#define ERR_EXP_DATE PKG_NSF+194
+ errortext(ERR_EXP_DATE, "Database's expiration date has passed")
+#define ERR_DUP_TPL PKG_NSF+195
+ errortext(ERR_DUP_TPL, "WARNING: Both %p and %p claim to be Design Template '%.*s'")
+#define ERR_CONTAINER_LIMIT PKG_NSF+196
+ errortext(ERR_CONTAINER_LIMIT, "Maximum size of a storage container reached")
+#define ERR_OBJECT_CANNOT_BE_ZERO PKG_NSF+197
+ errortext(ERR_OBJECT_CANNOT_BE_ZERO, "Object size cannot be zero")
+#define ERR_NOTE_INVSIG8 PKG_NSF+198
+ errortext(ERR_NOTE_INVSIG8, "The Address Book does not contain any cross certificates capable of validating the signature.")
+#define ERR_BC_POOL_FULL PKG_NSF+199
+ errortext(ERR_BC_POOL_FULL, "Insufficient memory - The NSF buffer control pool is full.")
+#define ERR_UPDATE_ATT PKG_NSF+200
+ errortext(ERR_UPDATE_ATT, "One or more of the source document's attachment are missing. Run Fixup to delete the document in the source database.")
+#define ERR_LINK_STR1 PKG_NSF+201
+ stringtext(ERR_LINK_STR1, "Database")
+#define ERR_LINK_STR2 PKG_NSF+202
+ stringtext(ERR_LINK_STR2, "View")
+#define ERR_LINK_STR3 PKG_NSF+203
+ stringtext(ERR_LINK_STR3, "Document")
+#define ERR_NSFOPENEXCLUSIVE PKG_NSF+204
+ errortext(ERR_NSFOPENEXCLUSIVE, "Database is being Compacted; Compact must finish before use.")
+/* The following status is 'sent' to the replicator via a break procedure */
+/* to partially cancel the replication. The replicator should stop */
+/* processing the current database and start processing the next database. */
+/* This is used by background/briefcase to skip to the next database in */
+/* the replication list. As it turns out, the replicator carries on for */
+/* errors other than CANCEL and SERVER_NOT_RESPONDING. It does not */
+/* specifically look for this error code. */
+#define ERR_SKIP PKG_NSF+205
+ errortext(ERR_SKIP, "Next operation started at your request")
+#define ERR_ASYNC_DELIVERY_SEQNO PKG_NSF+206
+ internaltext(ERR_ASYNC_DELIVERY_SEQNO,"(no need to do this transaction in V4)")
+#define ERR_DBCLOSE_THREAD PKG_NSF+207
+ errortext(ERR_DBCLOSE_THREAD,"NSFDbClose THREADID != NSFDbOpen THREADID!")
+#define ERR_EM_ILLEGALAID PKG_NSF+208
+ errortext(ERR_EM_ILLEGALAID,"Illegal or uninitialized addin id")
+#define ERR_EM_ILLEGAL PKG_NSF+209
+ errortext(ERR_EM_ILLEGAL,"Extension number out of bounds")
+#define ERR_EM_ILLEGALFLAGS PKG_NSF+210
+ errortext(ERR_EM_ILLEGALFLAGS,"Extension registration flags illegal")
+#define ERR_EM_TOOMANYADDINS PKG_NSF+211
+ errortext(ERR_EM_TOOMANYADDINS,"Extension Manager has maximum addins already")
+#define ERR_EM_NOTAUTHORIZED PKG_NSF+212
+ errortext(ERR_EM_NOTAUTHORIZED,"Not authorized to register extension")
+#define ERR_EM_CONTINUE PKG_NSF+213
+ internaltext(ERR_EM_CONTINUE,"continue")
+#define ERR_EVENTQUEUE_NOTOPENED PKG_NSF+214
+ errortext(ERR_EVENTQUEUE_NOTOPENED,"Event Manager Queue not opened")
+#define ERR_EVENTQNEEDS_RESET PKG_NSF+215
+ errortext(ERR_EVENTQNEEDS_RESET,"Event Manager data structures in error")
+#define ERR_EVENTQUEUE_ISFULL PKG_NSF+216
+ errortext(ERR_EVENTQUEUE_ISFULL,"Event Manager Queue is full")
+#define ERR_EVENTQUEUE_MEMORY PKG_NSF+217
+ errortext(ERR_EVENTQUEUE_MEMORY,"Event Manager Queue memory full")
+#define ERR_REPL_UPDATE_RACE PKG_NSF+218
+ errortext(ERR_REPL_UPDATE_RACE, "Multiple replicator update race")
+#define ERR_NO_INCR_UPDATE PKG_NSF+219
+ errortext(ERR_NO_INCR_UPDATE, "Incremental updates disallowed")
+#define ERR_NOTE_INVSIG9 PKG_NSF+220
+ errortext(ERR_NOTE_INVSIG9, "Signature on document is invalid (inconsistent field signatures)")
+#define ERR_BTVERIFY PKG_NSF+221
+ errortext(ERR_BTVERIFY, "NSF BT: Verification error in view %s in database %s. See NOTES.BRP for dump.")
+#define ERR_BTVERIFY_NODESIZE PKG_NSF+222
+ errortext(ERR_BTVERIFY_NODESIZE, "BTVerifyNode: ERROR in %s, node size is %d - expected %d")
+#define ERR_BTVERIFY_LEVEL PKG_NSF+223
+ errortext(ERR_BTVERIFY_LEVEL, "BTVerifyNode: ERROR in %s, level is %d - expected %d")
+#define ERR_BTVERIFY_PASTEND PKG_NSF+224
+ errortext(ERR_BTVERIFY_PASTEND, "BTVerifyNode: ERROR in %s, entry %d is past the end of the node")
+#define ERR_BTVERIFY_DATA_PASTEND PKG_NSF+225
+ errortext(ERR_BTVERIFY_DATA_PASTEND, "BTVerifyNode: ERROR in %s, Data for entry %d is past the end of the node")
+#define ERR_BTVERIFY_PIN_DATA PKG_NSF+226
+ errortext(ERR_BTVERIFY_PIN_DATA, "BTVerifyNode: ERROR %e pinning BT_DATA %s in node %s")
+#define ERR_BTVERIFY_LDATA_SIZE PKG_NSF+227
+ errortext(ERR_BTVERIFY_LDATA_SIZE, "BTVerifyNode: ERROR BT_DATA %s in node %s has size %d, sum of chunks is %d")
+#define ERR_BTVERIFY_UNPIN_DATA PKG_NSF+228
+ errortext(ERR_BTVERIFY_UNPIN_DATA, "BTVerifyNode: ERROR %e unpinning BT_DATA %s in node %s")
+#define ERR_BTVERIFY_CARDINALITY PKG_NSF+229
+ errortext(ERR_BTVERIFY_CARDINALITY, "BTVerifyNode: ERROR in %s, cardinality is %lu - expected %lu")
+#define ERR_BTVERIFY_MAXFALSE PKG_NSF+230
+ errortext(ERR_BTVERIFY_MAXFALSE, "BTVerifyNode: ERROR in %s, MaxEntry is FALSE - expected TRUE")
+#define ERR_BTVERIFY_MAXTRUE PKG_NSF+231
+ errortext(ERR_BTVERIFY_MAXTRUE, "BTVerifyNode: ERROR in %s, MaxEntry is TRUE - expected FALSE")
+#define ERR_BTVERIFY_MAXKEYSIZE PKG_NSF+232
+ errortext(ERR_BTVERIFY_MAXKEYSIZE, "BTVerifyNode: ERROR in %s, MaxKeySize is %d - expected %d")
+#define ERR_BTVERIFY_MAXKEYVALUE PKG_NSF+233
+ errortext(ERR_BTVERIFY_MAXKEYVALUE, "BTVerifyNode: ERROR in %s, maximum key value is wrong")
+#define ERR_BTVERIFY_PINSUBINDEX PKG_NSF+234
+ errortext(ERR_BTVERIFY_PINSUBINDEX, "BTVerifyNode: ERROR %e pinning sub-index descriptor %s in node %s")
+#define ERR_BTVERIFY_UNPINSUBINDEX PKG_NSF+235
+ errortext(ERR_BTVERIFY_UNPINSUBINDEX, "BTVerifyNode: ERROR %e unpinning sub-index descriptor %s in node %s")
+#define ERR_FILEEXT_INVALID_READCOUNT PKG_NSF+236
+ errortext(ERR_FILEEXT_INVALID_READCOUNT, "Extendable File object: invalid read count")
+#define ERR_FILEEXT_ALREADY_OPEN PKG_NSF+237
+ errortext(ERR_FILEEXT_ALREADY_OPEN, "Extendable File object: already open")
+#define ERR_FILEEXT_NOT_OPEN PKG_NSF+238
+ errortext(ERR_FILEEXT_NOT_OPEN, "Extendable File object: object must be open to perform this function")
+#define ERR_DIRMAN_NOT_INITIALIZED PKG_NSF+239
+ errortext(ERR_DIRMAN_NOT_INITIALIZED,"Directory Manager Not Initialized.")
+#define ERR_NOSTUB_HAS_RESPONSES PKG_NSF+240
+ errortext(ERR_NOSTUB_HAS_RESPONSES, "A note with responses cannot be deleted with UPDATE_NOSTUB")
+#define ERR_RESPONSE_CYCLE PKG_NSF+241
+ errortext(ERR_RESPONSE_CYCLE, "This operation creates a cycle in the response hierarchy")
+#define ERR_NSF_DIRMAN_POOLFULL PKG_NSF+242
+ errortext(ERR_NSF_DIRMAN_POOLFULL, "Insufficient memory - NSF directory manager pool is full.")
+#define ERR_NSF_BUF_POOLFULL PKG_NSF+243
+ errortext(ERR_NSF_BUF_POOLFULL, "Insufficient memory - NSF buffer pool is full. Increase the value of the NSF_BUFFER_POOL_SIZE environment variable.")
+#define ERR_EVENTQ_POOLFULL PKG_NSF+244
+ errortext(ERR_EVENTQ_POOLFULL, "Insufficient memory - Event Manager Pool is full.")
+#define ERR_DBINDEX_POOLFULL PKG_NSF+245
+ errortext(ERR_DBINDEX_POOLFULL, "Insufficient memory - too many databases on server - Database List Pool is full.")
+#define ERR_SYNC_POOLFULL PKG_NSF+246
+ errortext(ERR_SYNC_POOLFULL, "Insufficient memory - Database Sync Pool is full.")
+#define ERR_EM_POOLFULL PKG_NSF+247
+ errortext(ERR_EM_POOLFULL, "Insufficient memory - Extension Manager Data Pool is full.")
+#define ERR_LOCALSEC_DBOPENFAILURE PKG_NSF+248
+ errortext(ERR_LOCALSEC_DBOPENFAILURE, "This database has local access protection and you are not authorized to access it")
+#define ERR_LOCALSEC_NOTSUPPORTED PKG_NSF+249
+ errortext(ERR_LOCALSEC_NOTSUPPORTED, "The local security feature is not supported for the database or server")
+#define ERR_LOCALSEC_ALREADYSET PKG_NSF+250
+ errortext(ERR_LOCALSEC_ALREADYSET, "This database already has local security set up and can not be set again")
+#define ERR_LOCALSEC_NOUSERPUBKEY PKG_NSF+251
+ errortext(ERR_LOCALSEC_NOUSERPUBKEY, "Can not find the user or public key information in the Name and Address Book")
+#define ERR_LOCALSEC_INVALIDSTATE PKG_NSF+252
+ errortext(ERR_LOCALSEC_INVALIDSTATE, "Invalid local security state")
+#define ERR_FIXUP_DUP_DELETED PKG_NSF+253
+ errortext(ERR_FIXUP_DUP_DELETED,"A duplicate of document NT%08lx in database %p has been deleted")
+#define ERR_OVERDISKQUOTA PKG_NSF+254
+ errortext(ERR_OVERDISKQUOTA,"Unable to write to database because database would exceed its disk quota.")
+#define LOG_OVERDISKQUOTA PKG_NSF+255
+ errortext(LOG_OVERDISKQUOTA,"Unable to write to database - database %s would exceed its disk quota of %d KB by %k.")
+
+/* We're full here for PKG_NSF - Max is 255! Start using PKG_NSF2 below...*/
+
+
+/* More Note Storage File Error Code Definitions */
+
+#define NSFSTR_TRANSLOG_FORMATTING PKG_NSF2+0
+ stringtext(NSFSTR_TRANSLOG_FORMATTING, "Please wait, creating new transaction logs in directory: ")
+#define ERR_LOCAL_ENCRYPT_MUST_COMPACT PKG_NSF2+1
+ errortext(ERR_LOCAL_ENCRYPT_MUST_COMPACT, "You must compact the database in order to encrypt all documents.")
+#define ERR_LOCAL_DECRYPT_MUST_COMPACT PKG_NSF2+2
+ errortext(ERR_LOCAL_DECRYPT_MUST_COMPACT, "You must compact the database in order to decrypt all documents.")
+#define ERR_IS_OBJSTORE PKG_NSF2+3
+ errortext(ERR_IS_OBJSTORE, "The database required for this operation is an object store.")
+#define ERR_OBJSTORE_UPD_REPLICA PKG_NSF2+4
+ errortext(ERR_OBJSTORE_UPD_REPLICA, "The database and the object store for this update are replicas.")
+#define ERR_ITEM_MISMATCH PKG_NSF2+5
+ errortext(ERR_ITEM_MISMATCH, "An item's value or datatype differs from the same item in the object store note.")
+#define ERR_LOCALSEC_NEEDCOMPACT PKG_NSF2+6
+ errortext(ERR_LOCALSEC_NEEDCOMPACT, "You should compact your database in order to complete the local security setting")
+#define ERR_LOCALSEC_UNKNOWNMETHOD PKG_NSF2+7
+ errortext(ERR_LOCALSEC_UNKNOWNMETHOD, "The specified encryption method is invalid or not supported by this version of software")
+#define ERR_OBJSTORE_NOTSPLIT PKG_NSF2+8
+ errortext(ERR_OBJSTORE_NOTSPLIT, "Cannot split note (NoteID %d) between database %p and object store %p ")
+#define ERR_BAD_DBUHASHTBL_DELETION PKG_NSF2+9
+ internaltext(ERR_BAD_DBUHASHTBL_DELETION, "The wrong entry was deleted from the dbu hash table.")
+#define ERR_EM_MAX_EXTENSIONS PKG_NSF2+10
+ errortext(ERR_EM_MAX_EXTENSIONS, "Extension Manager exceeded maximum number of Recursion IDs")
+#define ERR_NAMED_OBJECT_CORRUPT PKG_NSF2+11
+ errortext(ERR_NAMED_OBJECT_CORRUPT, "Named Object corrupt.")
+#define ERR_COMPACT_INTERRUPTED PKG_NSF2+12
+ errortext(ERR_COMPACT_INTERRUPTED, "Compaction of the database was stopped prematurely because another user modified it while it was being compacted.")
+#define ERR_VALIDATION_FAILED PKG_NSF2+13
+ apitext(ERR_VALIDATION_FAILED, "Validation failed.")
+#define ERR_NSF_HEADER_CORRUPTED PKG_NSF2+14
+ errortext(ERR_NSF_HEADER_CORRUPTED, "The Notes database file header is corrupted")
+#define ERR_NO_SHARED_ITEMS PKG_NSF2+15
+ errortext(ERR_NO_SHARED_ITEMS, "The note contains no items that can be shared with the note in the object store.")
+#define ERR_LOCAL_ACCESS_AUTHN PKG_NSF2+16
+ errortext(ERR_LOCAL_ACCESS_AUTHN, "Your ID failed authentication check. Access is denied")
+#define ERR_IDTABLE_LENGTH_MISMATCH PKG_NSF2+17
+ errortext(ERR_IDTABLE_LENGTH_MISMATCH, "The internal length of the ID table does not match the length expected")
+#define ERR_FOLDER_DIRECTORY_CORRUPT PKG_NSF2+18
+ errortext(ERR_FOLDER_DIRECTORY_CORRUPT, "Folder is damaged. Please close and reopen database to repair it.")
+#define ERR_FOLDER_NOFREESPACE PKG_NSF2+19
+ errortext(ERR_FOLDER_NOFREESPACE, "Folder has no free space but should have.")
+#define ERR_REPL_BLOCK_FULL PKG_NSF2+20
+ errortext(ERR_REPL_BLOCK_FULL, "Folder replication block is full, will be reallocated.")
+#define ERR_ILLEGAL_FOLDER_COPY PKG_NSF2+21
+ errortext(ERR_ILLEGAL_FOLDER_COPY, "Source and destination folders must reside in same DB.")
+#define ERR_FOLDER_CORRUPT PKG_NSF2+22
+ errortext(ERR_FOLDER_CORRUPT, "Folder has been damaged. Please close and reopen database to have it repaired.")
+#define ERR_FOLDER_TOO_BIG PKG_NSF2+23
+ errortext(ERR_FOLDER_TOO_BIG, "Folder is larger than supported, cannot perform operation.")
+#define ERR_NO_FOLDER_REPLICATION PKG_NSF2+24
+ errortext(ERR_NO_FOLDER_REPLICATION, "Folder replication not supported by remote server.")
+#define ERR_TOO_MANY_FOLDER_UPDATES PKG_NSF2+25
+ errortext(ERR_TOO_MANY_FOLDER_UPDATES, "Too many folder additions or removals at one time")
+#define ERR_FOLDER_ACCESS_DENIED PKG_NSF2+26
+ errortext(ERR_FOLDER_ACCESS_DENIED, "No privilege to update folder")
+#define ERR_NOTE_CANT_BE_FOLDER PKG_NSF2+27
+ errortext(ERR_NOTE_CANT_BE_FOLDER, "Note must be public or private view to be a folder")
+#define ERR_MAXSIZE_NOTSUPPORTED PKG_NSF2+28
+ errortext(ERR_MAXSIZE_NOTSUPPORTED, "The server does not support Notes database with maximum size greater than 1 GB")
+#define ERR_OBJSTORE_NOACCESS PKG_NSF2+29
+ errortext(ERR_OBJSTORE_NOACCESS, "You do not have access to the object store that is used by this note")
+#define ERR_OBJSTORE_NOT_FOUND PKG_NSF2+30
+ errortext(ERR_OBJSTORE_NOT_FOUND, "The object store note that is used by this note was not found. Run the object store COLLECT task on this database.")
+#define ERR_CANNOT_OPEN_OBJSTORE PKG_NSF2+31
+ errortext(ERR_CANNOT_OPEN_OBJSTORE, "The object store that is used by this note was not found or is not a Notes database")
+#define ERR_OBJSTORE_NOTE_NOACCESS PKG_NSF2+32
+ errortext(ERR_OBJSTORE_NOTE_NOACCESS, "You do not have access to the object store note that is used by this note")
+#define ERR_OBJSTORE_NOTE_DELETED PKG_NSF2+33
+ errortext(ERR_OBJSTORE_NOTE_DELETED, "The object store note that is used by this note has been deleted. Run the object store COLLECT task on this database.")
+#define ERR_USER_HANDLED_CONFLICT PKG_NSF2+34
+ errortext(ERR_USER_HANDLED_CONFLICT,"User Has Handled their own Conflict.")
+#define ERR_FIXUP_GHOST PKG_NSF2+35
+ errortext(ERR_FIXUP_GHOST, "Fixed header of document NT%08lx in database %p so it will replicate properly.")
+#define ERR_INVALID_CD_FILE PKG_NSF2+36
+ errortext(ERR_INVALID_CD_FILE, "Incorrectly formatted Composite records in file.")
+#define ERR_FIXUP_FOUND_UNREADLIST PKG_NSF2+37
+ errortext(ERR_FIXUP_FOUND_UNREADLIST, "Unread list for user %a in database %p is damaged: %e")
+#define ERR_DELETE_ENTRY PKG_NSF2+38
+ errortext(ERR_DELETE_ENTRY, "Internal only - delete named table entry.")
+#define ERR_UPDATE_ENTRY PKG_NSF2+39
+ errortext(ERR_UPDATE_ENTRY, "Internal only - update named table entry.")
+#define ERR_TOO_MANY_FOLDERS PKG_NSF2+40
+ errortext(ERR_TOO_MANY_FOLDERS, "Exceeded maximum folder count in database.")
+#define ERR_FIXUP_DEL_UNREADLIST PKG_NSF2+41
+ errortext(ERR_FIXUP_DEL_UNREADLIST, "Unread list for user %a in database %p is damaged and has been deleted: %e")
+#define ERR_FIXUP_NAMEDNOTE PKG_NSF2+42
+ errortext(ERR_FIXUP_NAMEDNOTE, "Named note NT%08lx in database %p is damaged.")
+#define ERR_NSF_FOLDER_POOLFULL PKG_NSF2+43
+ errortext(ERR_NSF_FOLDER_POOLFULL, "Insufficient memory - NSF folder pool is full.")
+#define ERR_FIXUP_FOLDER_PURGED PKG_NSF2+44
+ errortext(ERR_FIXUP_FOLDER_PURGED, "Folder NT%08lx in database %p has been purged due to corruption: %s")
+#define ERR_FIXUP_FOLDER_IDTABLE PKG_NSF2+45
+ errortext(ERR_FIXUP_FOLDER_IDTABLE, "Folder NT%08lx in database %p has corrupt ID table, will be rebuilt. Error: %e.")
+#define ERR_FOLDERS_UPTODATE PKG_NSF2+46
+ errortext(ERR_FOLDERS_UPTODATE, "Folders in database are up to date")
+#define ERR_RTR_NOTSET PKG_NSF2+47
+ errortext(ERR_RTR_NOTSET, "RTR Context not set for this database")
+#define ERR_RTR_ALREADYSET PKG_NSF2+48
+ errortext(ERR_RTR_ALREADYSET, "RTR Context already set for this database")
+#define ERR_NSF_COMPUTE_NOENVIRONMENT PKG_NSF2+49
+ errortext(ERR_NSF_COMPUTE_NOENVIRONMENT, "You are not allowed to modify environment variables.")
+#define ERR_NSF_REMOTE_URL_QUEUE PKG_NSF2+50
+ errortext(ERR_NSF_REMOTE_URL_QUEUE, "Cannot queue a URL Note Open to a remote database.")
+#define ERR_NOTE_NOT_FOLDER PKG_NSF2+51
+ errortext(ERR_NOTE_NOT_FOLDER, "Attempt to perform folder operation on non-folder note.")
+#define ERR_NO_VIEWS_IN_OBJSTORE PKG_NSF2+52
+ errortext(ERR_NO_VIEWS_IN_OBJSTORE, "Views cannot be added to an object store.")
+#define ERR_NOTE_INVSIG10 PKG_NSF2+53
+ errortext(ERR_NOTE_INVSIG10, "Document has been modified or corrupted since signed! (extended signature)")
+#define ERR_NEEDS_FIXUP PKG_NSF2+54
+ errortext(ERR_NEEDS_FIXUP, "This database cannot be opened because a consistency check of it is needed.")
+#define ERR_FIXUP_IN_PROGRESS PKG_NSF2+55
+ errortext(ERR_FIXUP_IN_PROGRESS, "This database cannot be opened because a consistency check of it is in progress.")
+#define ERR_FILTER_CONTINUING PKG_NSF2+56
+ errortext(ERR_FILTER_CONTINUING, "Error running agent on NoteID %lu - %e. Continuing...")
+#define ERR_OBJSTORE_TITLE PKG_NSF2+57
+ errortext(ERR_OBJSTORE_TITLE, "Object Store for ")
+#define ERR_NSF_CORRUPT_ACL PKG_NSF2+58
+ errortext(ERR_NSF_CORRUPT_ACL, "Database ACL is damaged and can't be repaired.")
+#define ERR_CONTVERIFY_FREESPACEWRONG PKG_NSF2+59
+ errortext(ERR_CONTVERIFY_FREESPACEWRONG, "BufAllocSpace: Mismatch in free space, container: %d, (%s).")
+#define ERR_DBUHASH_POOLFULL PKG_NSF2+60
+ errortext(ERR_DBUHASH_POOLFULL, "NSF DBU hash table pool is full.")
+#define ERR_RSP_ADDTO_HIERFOLD PKG_NSF2+61
+ errortext(ERR_RSP_ADDTO_HIERFOLD, "To move a response document to a folder that shows response hierarchy you need to move the topmost parent of the response")
+#define ERR_RSP_REMFROM_HIERFOLD PKG_NSF2+62
+ errortext(ERR_RSP_REMFROM_HIERFOLD, "To remove a response document from a folder that shows response hierarchy you must also remove the topmost parent of the response")
+#define ERR_RSP_REMFROM_HIERFOLD_WARN PKG_NSF2+63
+ errortext(ERR_RSP_REMFROM_HIERFOLD_WARN, "All related response documents are being removed from this folder along with their parents.")
+#define ERR_RSP_ADDTO_HIERFOLD_WARN PKG_NSF2+64
+ errortext(ERR_RSP_ADDTO_HIERFOLD_WARN, "All related response documents are being added to this folder along with their parents.")
+#define NSFSTR_ENCRYPT_PROGRESS PKG_NSF2+65
+ stringtext(NSFSTR_ENCRYPT_PROGRESS,"Encrypting database")
+#define NSFSTR_DECRYPT_PROGRESS PKG_NSF2+66
+ stringtext(NSFSTR_DECRYPT_PROGRESS,"Decrypting database")
+#define ERR_NOT_OBJSTORE PKG_NSF2+67
+ errortext(ERR_NOT_OBJSTORE, "The object store required for this operation is not an object store.")
+#define ERR_VIEW_UPDATE PKG_NSF2+68
+ errortext(ERR_VIEW_UPDATE, "View and Design notes can only be deleted by using NIFUpdateNote or NIFDeleteNote.")
+#define ERR_NOTE_CLASS PKG_NSF2+69
+ errortext(ERR_NOTE_CLASS, "Document has invalid Note Class")
+#define ERR_RM_DOING_RESTART PKG_NSF2+70
+ errortext(ERR_RM_DOING_RESTART, "Recovery Manager: Recovery being performed for DB")
+#define ERR_BDB_CORRUPT PKG_NSF2+71
+ errortext(ERR_BDB_CORRUPT, "Database is damaged and can't be repaired (BDB)")
+#define ERR_INVALID_PARENT_NOTE PKG_NSF2+72
+ errortext(ERR_INVALID_PARENT_NOTE, "Invalid or nonexistent parent document")
+#define ERR_NOT_CHILD_NOTE PKG_NSF2+73
+ errortext(ERR_NOT_CHILD_NOTE, "This document is not a child of its parent document")
+#define ERR_LINK_FORMAT PKG_NSF2+74
+ errortext(ERR_LINK_FORMAT, "Notes Document Link is not formatted properly, or it is not a Notes Document Link")
+#define ERR_DB_MARKED_FOR_DELETE PKG_NSF2+75
+ errortext(ERR_DB_MARKED_FOR_DELETE, "This database has been marked for delete and cannot be modified")
+#define ERR_RETRY_RW PKG_NSF2+76
+ internaltext(ERR_RETRY_RW, "Retry this operation with the RW sem")
+#define ERR_UNAME_TEXT PKG_NSF2+77
+ errortext(ERR_UNAME_TEXT, "Invalid type of data for a Unique Document Name")
+#define ERR_UNAME_LENGTH PKG_NSF2+78
+ errortext(ERR_UNAME_LENGTH, "Unique Document Name is too long")
+#define ERR_UNAME_DIRFULL PKG_NSF2+79
+ errortext(ERR_UNAME_DIRFULL, "Insufficient space in Unique Document Name Directory Pool")
+#define ERR_UNAME_NO_DB PKG_NSF2+80
+ errortext(ERR_UNAME_NO_DB, "Document Database Not Found")
+#define ERR_UNAME_NO_DOC PKG_NSF2+81
+ errortext(ERR_UNAME_NO_DOC, "Document Not Found")
+#define ERR_NSF_SCHED_POOLFULL PKG_NSF2+82
+ errortext(ERR_NSF_SCHED_POOLFULL, "Insufficient memory - Schedule vpool is full.")
+#define ERR_NSF_NO_WEB_CACHE PKG_NSF2+83
+errortext( ERR_NSF_NO_WEB_CACHE, "The Web retriever database cache could not be opened. Please check your InterNotes Server value in your current location.")
+#define ERR_FIXUP_FOUND_HUGE_UNREADLIST PKG_NSF2+84
+ errortext(ERR_FIXUP_FOUND_HUGE_UNREADLIST, "Unread list for user %a in database %p is in the new format")
+#define ERR_FIXUP_UNLATCH_FAILED PKG_NSF2+85
+ errortext(ERR_FIXUP_UNLATCH_FAILED, "Unable to change unread list for user %a in database %p to the old format: %e")
+#define ERR_FIXUP_UNLATCHED PKG_NSF2+86
+ errortext(ERR_FIXUP_UNLATCHED, "Changed unread list for user %a in database %p to the old format")
+/* NOTE class names */
+#define ERR_NOTE_DESIGN_CLASS_NAME PKG_NSF2+87
+ errortext(ERR_NOTE_DESIGN_CLASS_NAME,"design")
+#define ERR_NOTE_VIEW_CLASS_NAME PKG_NSF2+88
+ errortext(ERR_NOTE_VIEW_CLASS_NAME, "view")
+#define ERR_NOTE_DVIEW_CLASS_NAME PKG_NSF2+89
+ errortext(ERR_NOTE_DVIEW_CLASS_NAME,"default view")
+#define ERR_NOTE_CLASS_NAME PKG_NSF2+90
+ errortext(ERR_NOTE_CLASS_NAME, "class")
+#define ERR_NOTE_DDESIGN_CLASS_NAME PKG_NSF2+91
+ errortext(ERR_NOTE_DDESIGN_CLASS_NAME,"default design")
+#define ERR_NOTE_PVIEW_CLASS_NAME PKG_NSF2+92
+ errortext(ERR_NOTE_PVIEW_CLASS_NAME,"private view")
+#define ERR_NOTE_NO_CLASS_NAME PKG_NSF2+93
+ errortext(ERR_NOTE_NO_CLASS_NAME, "private design")
+#define ERR_FTM_NOTSET PKG_NSF2+94
+ errortext(ERR_FTM_NOTSET, "FTM Context not set for this database")
+#define ERR_FTM_ALREADYSET PKG_NSF2+95
+ errortext(ERR_FTM_ALREADYSET, "FTM Context already set for this database")
+#define ERR_SCHOBJCNTNR PKG_NSF2+96
+ errortext(ERR_SCHOBJCNTNR, "schedule object container error")
+#define ERR_SCHOBJCNTNR_GATEWAY PKG_NSF2+97
+ errortext(ERR_SCHOBJCNTNR_GATEWAY, "schedule object container gateway error")
+#define ERR_SCHOBJCNTNR_PARTIAL PKG_NSF2+98
+ errortext(ERR_SCHOBJCNTNR_PARTIAL, "schedule container partially filled")
+#define ERR_SCHED_INVALIDDOMAIN PKG_NSF2+99
+ errortext(ERR_SCHED_INVALIDDOMAIN, "Invalid domain type for scheduling request")
+#define ERR_SCHED_NAMENOTUNIQUE PKG_NSF2+100
+ errortext(ERR_SCHED_NAMENOTUNIQUE, "User name in scheduling request not unique in Name and Address Book")
+#define ERR_SCHED_NOSUCHUSER PKG_NSF2+101
+ errortext(ERR_SCHED_NOSUCHUSER, "User name in scheduling request not found in Name and Address Book")
+#define ERR_SCHED_NOGROUP PKG_NSF2+102
+ errortext(ERR_SCHED_NOGROUP, "Error processing scheduling request, group name not supported")
+#define ERR_SCHED_DOMAINNOTFOUND PKG_NSF2+103
+ errortext(ERR_SCHED_DOMAINNOTFOUND, "Can't find domain document in Domino Directory for the scheduling request")
+#define ERR_SCHED_CANTFINDSCHEDULE PKG_NSF2+104
+ errortext(ERR_SCHED_CANTFINDSCHEDULE, "Can't find schedule record for requested user")
+#define ERR_SCHOBJ_NOCOMPOSITE PKG_NSF2+105
+ errortext(ERR_SCHOBJ_NOCOMPOSITE, "No composite schedule was generated")
+#define ERR_SCHOBJ_NOSCHEDLIST PKG_NSF2+106
+ errortext(ERR_SCHOBJ_NOSCHEDLIST, "No schedule list entry is available for this object")
+#define ERR_SCHOBJ_LOCALNOCOMPOSITE PKG_NSF2+107
+ errortext(ERR_SCHOBJ_LOCALNOCOMPOSITE, "No composite schedule was generated locally")
+#define ERR_SCHED_APPT_NOTFOUND PKG_NSF2+108
+ errortext(ERR_SCHED_APPT_NOTFOUND, "Appointment record not found")
+#define ERR_SCHRQST_TIMEOUT PKG_NSF2+109
+ errortext(ERR_SCHRQST_TIMEOUT, "schedule request timed out")
+#define ERR_SCHOBJ_NOTEXIST PKG_NSF2+110
+ errortext(ERR_SCHOBJ_NOTEXIST, "schedule object doesn't exist")
+#define ERR_SCHED_CHAIN_LOOP PKG_NSF2+111
+ errortext(ERR_SCHED_CHAIN_LOOP, "Schedule request chaining loop detected")
+#define ERR_NSF_CORRUPT_ECL PKG_NSF2+112
+ errortext(ERR_NSF_CORRUPT_ECL, "ECL is damaged and can't be repaired")
+#define ERR_NSF_COMPUTE_ECL_ABORT PKG_NSF2+113
+ errortext(ERR_NSF_COMPUTE_ECL_ABORT, "Operation aborted at your request")
+#define ERR_BITMAPCHECKSUM_BAD PKG_NSF2+114
+ errortext(ERR_BITMAPCHECKSUM_BAD, "Bitmap checksum is incorrect")
+#define ERR_BAD_BUCKETPOS PKG_NSF2+115
+ internaltext(ERR_BAD_BUCKETPOS, "Bad bucket position")
+#define ERR_DBCACHE_ENTRY_RESERVED PKG_NSF2+116
+ internaltext(ERR_DBCACHE_ENTRY_RESERVED, "DbCache entry reserved")
+#define ERR_BUCKET_CORRUPT PKG_NSF2+117
+ internaltext(ERR_BUCKET_CORRUPT, "Bucket is corrupt, perhaps partially written")
+#define ERR_RM_STOP_LOGGING PKG_NSF2+118
+ errortext(ERR_RM_STOP_LOGGING, "Recovery Manager: Transactional Logging being disabled after this restart")
+#define ERR_NSF_BUCKET_POOLFULL PKG_NSF2+119
+ errortext(ERR_NSF_BUCKET_POOLFULL, "Insufficient memory - NSF bucket buffer pool is full.")
+#define ERR_INVALID_BUCKET_TYPE PKG_NSF2+120
+ errortext(ERR_INVALID_BUCKET_TYPE, "Invalid Bucket Type")
+#define ERR_NETACCOUNT_LASTNAME PKG_NSF2+121
+ errortext(ERR_NETACCOUNT_LASTNAME, "A valid last name string must be supplied for the second parameter of @NetAccount")
+#define ERR_CANTINVALIDATE_BUFFER PKG_NSF2+122
+ internaltext(ERR_CANTINVALIDATE_BUFFER, "Can't invalidate buffer, pin count > 1")
+#define ERR_WRONG_PROCESSGROUP PKG_NSF2+123
+ internaltext(ERR_WRONG_PROCESSGROUP, "Ager is in wrong process group")
+#define ERR_ITEM_TIME_CORRUPT PKG_NSF2+124
+ internaltext(ERR_ITEM_TIME_CORRUPT, "Item does not have a valid time")
+#define ERR_SYNC_TIME_NOT_FOUND PKG_NSF2+125
+ internaltext(ERR_SYNC_TIME_NOT_FOUND, "Documents do not have a common revision time")
+#define STR_FREE_TIME_DB_TITLE PKG_NSF2+126
+ stringtext(STR_FREE_TIME_DB_TITLE, "Local free time info")
+#define ERR_SCHED_MULTIPLE_DOMAINS PKG_NSF2+127
+ errortext(ERR_SCHED_MULTIPLE_DOMAINS, "Warning: Multiple documents detected for domain '%s' in Domino Directory for the scheduling request.")
+/* PKG_NSF2 codes limited to 0-127 */
+
+
+#define ERR_TRANSLOG_NO_SPACE PKG_NSF3+0
+ errortext(ERR_TRANSLOG_NO_SPACE, "Insufficient disk space to create transaction log.")
+#define ERR_SCHED_QUERY_SMALLER_DATE_RANGE PKG_NSF3+1
+ errortext(ERR_SCHED_QUERY_SMALLER_DATE_RANGE, "The date range for this busy time query contains too much busy time data. Query a shorter range of days.")
+#define ERR_SCHED_RANGEFULL PKG_NSF3+2
+ errortext(ERR_SCHED_RANGEFULL, "The range is full.")
+#define ERR_SCHED_TOOMUCHDATA PKG_NSF3+3
+ errortext(ERR_SCHED_TOOMUCHDATA, "Too much data is being added to this object. Please break it up into chunks.")
+#define ERR_NULL_DBHANDLE PKG_NSF3+4
+ errortext(ERR_NULL_DBHANDLE, "The database handle is NULL")
+#define ERR_INVALID_BUCKET_NUMBER PKG_NSF3+5
+ errortext(ERR_INVALID_BUCKET_NUMBER,"Invalid Bucket Number")
+#define ERR_SCHED_WARNING PKG_NSF3+6
+ errortext(ERR_SCHED_WARNING, "Warning: schedule retrieval error for %s - ")
+#define ERR_PROFILE_ENUM_POOLFULL PKG_NSF3+7
+ errortext(ERR_PROFILE_ENUM_POOLFULL,"Profile document enumeration pool is full")
+#define ERR_OBJSTORE_NOT_ENCRYPTED PKG_NSF3+8
+ internaltext(ERR_OBJSTORE_NOT_ENCRYPTED,"Object Store not marked encrypted and must be")
+#define ERR_DBCACHE_TOO_BIG PKG_NSF3+9
+ errortext(ERR_DBCACHE_TOO_BIG, "NSF_DBCACHE_MAX_ENTRIES parameter too large, memory request failed")
+#define ERR_NOLOCKINPAGECOMPRESS PKG_NSF3+10
+ errortext(ERR_NOLOCKINPAGECOMPRESS,"Db write semaphore not held during attempted page compression")
+#define ERR_CANTDOINPLACECOMPACT PKG_NSF3+11
+ errortext(ERR_CANTDOINPLACECOMPACT,"In-place database compaction can only be done with V5 and beyond databases")
+#define ERR_NOBUCKETSKIMMING PKG_NSF3+12
+ errortext(ERR_NOBUCKETSKIMMING, "Operation cannot be performed at the current time - database compaction in progress.")
+#define ERR_CANTCOPYUNKTABLE PKG_NSF3+13
+ internaltext(ERR_CANTCOPYUNKTABLE, "Unable to copy UNK table")
+#define ERR_UBMPOOLFULL PKG_NSF3+14
+ errortext(ERR_UBMPOOLFULL,"The buffer pool is too full to bring in another page.")
+#define ERR_UBMPOOLMAXED PKG_NSF3+15
+ errortext(ERR_UBMPOOLMAXED,"The buffer pool is extremely full; delay the thread.")
+#define ERR_UBMBACKOFF PKG_NSF3+16
+ errortext(ERR_UBMBACKOFF,"Buffer manager clock failed to find a buffer. Retry pin operation.")
+#define ERR_UBMPAGENOTFOUND PKG_NSF3+17
+ errortext(ERR_UBMPAGENOTFOUND,"Page is not currently buffered.")
+#define ERR_UBMBADPAGESIZE PKG_NSF3+18
+ errortext(ERR_UBMBADPAGESIZE,"Page size requested is not allowed.")
+#define ERR_UBMGROUPTBLFULL PKG_NSF3+19
+ errortext(ERR_UBMGROUPTBLFULL,"Universal Buffer Manager group table is full.")
+#define ERR_UBMBADGROUPID PKG_NSF3+20
+ errortext(ERR_UBMBADGROUPID,"Using invalid (old) group id.")
+#define ERR_UBMPAGEPINNED PKG_NSF3+21
+ errortext(ERR_UBMPAGEPINNED,"Page pinned during group operation.")
+#define ERR_BKTDESCPAGE_CORRUPT PKG_NSF3+22
+ internaltext(ERR_BKTDESCPAGE_CORRUPT, "Bucket descriptor page is corrupt, perhaps partially written")
+#define ERR_UBMTEST PKG_NSF3+23
+ errortext(ERR_UBMTEST,"Miscellaneous error running testnsf for ubm.")
+#define ERR_NOINCREMENTALANTIFOLDER PKG_NSF3+24
+ errortext(ERR_NOINCREMENTALANTIFOLDER, "Anti-folder view must be rebuilt")
+#define ERR_UBMBADGAD PKG_NSF3+25
+ errortext(ERR_UBMBADGAD,"Group Access Data structure size is too large.")
+#define ERR_UBMNOGROUPINFO PKG_NSF3+26
+ errortext(ERR_UBMNOGROUPINFO,"Group Access Data cannot be found.")
+#define ERR_UBMNOSPACE PKG_NSF3+27
+ errortext(ERR_UBMNOSPACE,"Group Access Data bpool cannot be created.")
+#define ERR_CANNOT_COMPACT_DB_VERSION PKG_NSF3+28
+ errortext(ERR_CANNOT_COMPACT_DB_VERSION, "Cannot compact pre-V3 databases to V5 or later databases - use New Replica instead.")
+#define ERR_CANT_COMPACT_INDEX_VERSION PKG_NSF3+29
+ errortext(ERR_CANT_COMPACT_INDEX_VERSION, "Cannot compact database. Please use compact -d or updall -r followed by compact.")
+#define ERR_RRVBKT_CORRUPT PKG_NSF3+30
+ errortext(ERR_RRVBKT_CORRUPT, "RRV bucket is corrupt.")
+#define ERR_BITMAP_CORRUPT PKG_NSF3+31
+ errortext(ERR_BITMAP_CORRUPT, "Allocation bitmap is corrupt.")
+#define ERR_SALVAGE_FAILED PKG_NSF3+32
+ internaltext(ERR_SALVAGE_FAILED, "Salvage attempt failed, database severely corrupted.")
+#define ERR_UBMBUFFERTOOSMALL PKG_NSF3+33
+ errortext(ERR_UBMBUFFERTOOSMALL,"Group Data buffer provided by caller is too small.")
+#define ERR_UBMCANTLOCK PKG_NSF3+34
+ errortext(ERR_UBMCANTLOCK,"UBM I/O Method could not get conditional semaphore.")
+#define ERR_UBMNOFD PKG_NSF3+35
+ errortext(ERR_UBMNOFD,"UBM I/O Method thread does not have file open.")
+#define ERR_UBMWRITEBACKANDDISCARD PKG_NSF3+36
+ errortext(ERR_UBMWRITEBACKANDDISCARD,"Simultaneous setting of writeback and discard on buffer.")
+#define ERR_UBMTOOMANYPAGES PKG_NSF3+37
+ errortext(ERR_UBMTOOMANYPAGES,"Too many pages in prefetch page list - list truncated.")
+#define ERR_PAGE_PINNED PKG_NSF3+38
+ internaltext(ERR_PAGE_PINNED, "Operation cannot be performed because the page is pinned")
+#define ERR_UBMPAGENOTPINNED PKG_NSF3+39
+ errortext(ERR_UBMPAGENOTPINNED,"Trying to unpinned an unpinned page.")
+#define ERR_UBMBADGTABLESEG PKG_NSF3+40
+ errortext(ERR_UBMBADGTABLESEG,"Universal Buffer Manager group table segment is null.")
+#define ERR_NSF_CANT_BACKUP PKG_NSF3+41
+ errortext(ERR_NSF_CANT_BACKUP,"Cannot perform write due to error recording before image for full backup.")
+#define ERR_CANT_BACKUP_DURING_COMPACT PKG_NSF3+42
+ errortext(ERR_CANT_BACKUP_DURING_COMPACT, "Cannot backup a database while it is being compacted.")
+
+#define ERR_BAD_SUPERBLOCK PKG_NSF3+43
+ errortext(ERR_BAD_SUPERBLOCK, "SuperBlock is corrupt on disk - Restart recovery is required.")
+#define ERR_MQ_POOL_FULL PKG_NSF3+44
+ errortext(ERR_MQ_POOL_FULL,"Logger memory pool is full.")
+#define ERR_UNABLE_TO_RENAME PKG_NSF3+45
+ errortext(ERR_UNABLE_TO_RENAME, "Compaction failed: Unable to rename %p back to %p: %e - You must rename it yourself.")
+#define ERR_UNABLE_TO_DELETE PKG_NSF3+46
+ errortext(ERR_UNABLE_TO_DELETE, "Compaction failed: Unable to delete %p")
+#define ERR_DB_ALREADY_OPEN PKG_NSF3+47
+ errortext(ERR_DB_ALREADY_OPEN, "Database is already open")
+#define ERR_UNAME_NOT_UNIQUE PKG_NSF3+48
+ errortext(ERR_UNAME_NOT_UNIQUE, "Unique Document Name is already used")
+#define ERR_UNAME_ALREADY_NAMED PKG_NSF3+49
+ errortext(ERR_UNAME_ALREADY_NAMED, "Note already has a Unique Document Name")
+#define ERR_NOTE_ALREADY_OPEN PKG_NSF3+50
+ errortext(ERR_NOTE_ALREADY_OPEN, "Note is already open")
+#define ERR_FIXUP_FOLDER_PURGED_NO_DELETE PKG_NSF3+51
+ errortext(ERR_FIXUP_FOLDER_PURGED_NO_DELETE, "Folder %s (NT%08lx) in database %p is corrupted. This folder will be purged on the next access of this database: %s")
+#define ERR_UNABLE_TO_CREATE_MSGID PKG_NSF3+52
+ errortext(ERR_UNABLE_TO_CREATE_MSGID, "Unable to create a message-id")
+#define ERR_NNTP_IN_DB_INDEX PKG_NSF3+53
+ internaltext(ERR_NNTP_IN_DB_INDEX, "The News/NNTP database name was found in the db index")
+#define ERR_NNTP_NO_MORE_DBNAMES PKG_NSF3+54
+ errortext(ERR_NNTP_NO_MORE_DBNAMES, "Could not create a News/NNTP database name")
+#define ERR_NOTE_HIT_64K_COMPUTE_LIMIT PKG_NSF3+55
+ errortext(ERR_NOTE_HIT_64K_COMPUTE_LIMIT, "Note ID %lu has items that are causing the Compute subsystem to generate a 64K error. This note will not be included in search results.")
+#define ERR_NNTP_NEWSGROUP_EXISTS PKG_NSF3+56
+ errortext(ERR_NNTP_NEWSGROUP_EXISTS,"An NNTP Newsgroup of that name already exists")
+#define ERR_NNTP_BAD_NEWSGROUP_NAME PKG_NSF3+57
+ errortext(ERR_NNTP_BAD_NEWSGROUP_NAME,"Invalid characters in Newsgroup name")
+#define MSG_NNTP_ARCHIVE_HELPER PKG_NSF3+58
+ errortext(MSG_NNTP_ARCHIVE_HELPER, "An existing archive database has been specified. Please use the following options to specify what should be done to the original archive database.")
+#define ERR_NULL_NOTEHANDLE PKG_NSF3+59
+ errortext(ERR_NULL_NOTEHANDLE, "The note handle is NULL.")
+#define ERR_ITEM_NEWNAME_TOO_LONG PKG_NSF3+60
+ errortext(ERR_ITEM_NEWNAME_TOO_LONG,"The new item name is too long to fit over the existing name.")
+#define ERR_DBALLOC_SIZE_ZERO PKG_NSF3+61
+ errortext(ERR_DBALLOC_SIZE_ZERO, "Detected zero length file space allocation.")
+#define ERR_FILE_MODIFIED_ATOS PKG_NSF3+62
+ errortext(ERR_FILE_MODIFIED_ATOS, "File modified at operating-system level while cached, please retry open.")
+#define ERR_FIXUP_NEEDED PKG_NSF3+63
+ errortext(ERR_FIXUP_NEEDED, "Database Fixup needed: %s.")
+#define ERR_RM_FILTER_LOG_RECORD PKG_NSF3+64
+ internaltext(ERR_RM_FILTER_LOG_RECORD, "Recovery Manager: Filtered current Log Record")
+#define ERR_RM_FIXUP_DB PKG_NSF3+65
+ errortext(ERR_RM_FIXUP_DB, "Recovery Manager: Database is damaged and requires Fixup -j or Media Recovery")
+#define ERR_RM_DOT_ENTRY_NOT_FOUND PKG_NSF3+66
+ internaltext(ERR_RM_DOT_ENTRY_NOT_FOUND, "Recovery Manager: Dirty Object not found it table")
+#define ERR_RM_DOT_POOL_FAILURE PKG_NSF3+67
+ errortext(ERR_RM_DOT_POOL_FAILURE, "Recovery Manager: Insufficient memory - Dirty Object Pool is full")
+#define ERR_RM_LOG_FULL PKG_NSF3+68
+ errortext(ERR_RM_LOG_FULL, "Recovery Manager: Log File is Full, try again later")
+#define ERR_RM_GENERAL_FAILURE PKG_NSF3+69
+ errortext(ERR_RM_GENERAL_FAILURE, "Recovery Manager: General failure")
+#define ERR_LR_RECOVERY_FAILURE PKG_NSF3+70
+ errortext(ERR_LR_RECOVERY_FAILURE, "Recovery : General failure")
+#define ERR_ONLY_V5_DATABASES PKG_NSF3+71
+ errortext(ERR_ONLY_V5_DATABASES, "Function not supported for pre-R5 format databases")
+#define ERR_NBRO_CORRUPT PKG_NSF3+72
+ internaltext(ERR_NBRO_CORRUPT, "Non-bucketized response object is corrupt, perhaps partially written")
+#define ERR_NBNS_CORRUPT PKG_NSF3+73
+ internaltext(ERR_NBNS_CORRUPT, "Non-bucketized nonsummary data is corrupt, perhaps partially written")
+#define ERR_DUPLICATE_ATTACHMENT PKG_NSF3+74
+ errortext(ERR_DUPLICATE_ATTACHMENT, "Attachment found on more than one document.")
+#define ERR_UBMLASTUNPIN PKG_NSF3+75
+ errortext(ERR_UBMLASTUNPIN, "Attempted last unpin of discarded buffer under roll forward")
+#define ERR_RUN_FIXUP PKG_NSF3+76
+ errortext(ERR_RUN_FIXUP, "Please run Fixup on database and retry operation.")
+#define ERR_NOFOLDERREORG_DURING_COMPACT PKG_NSF3+77
+ errortext(ERR_NOFOLDERREORG_DURING_COMPACT, "Folders may not be reorganized during compaction, please retry.")
+#define ERR_MONITORS_NOT_ALLOWED PKG_NSF3+78
+ errortext(ERR_MONITORS_NOT_ALLOWED, "Monitors are not allowed on this database.")
+#define ERR_MORE_EVENTS PKG_NSF3+79
+ errortext(ERR_MORE_EVENTS, "More events are available for this client.")
+#define ERR_NO_SUCH_CLIENT PKG_NSF3+80
+ errortext(ERR_NO_SUCH_CLIENT, "Monitor client not known by server.")
+#define ERR_NSF_MONITOR_POOLFULL PKG_NSF3+81
+ errortext(ERR_NSF_MONITOR_POOLFULL, "Insufficient memory - NSF monitor pool is full.")
+#define ERR_MONITOR_ALREADY_REGISTERED PKG_NSF3+82
+ errortext(ERR_MONITOR_ALREADY_REGISTERED, "Monitor has already been registered, no action taken.")
+#define ERR_UNKNOWN_MONITOR_CLIENT PKG_NSF3+83
+ errortext(ERR_UNKNOWN_MONITOR_CLIENT, "Monitor client not known.")
+#define ERR_OLD_INDEX_VERSION PKG_NSF3+84
+ internaltext(ERR_OLD_INDEX_VERSION, "Encountered old index (container) version - ignoring.")
+#define ERR_IGNORE_SRFILL_ERROR PKG_NSF3+85
+ errortext(ERR_IGNORE_SRFILL_ERROR, "Note ID NT%08lx - %e. This note will not be included in search results.")
+#define ERR_OLE_STORAGE_TYPE PKG_NSF3+86
+ internaltext(ERR_OLE_STORAGE_TYPE, "OLE storage type not correct.")
+#define ERR_MIME_PART_EXPECTED PKG_NSF3+87
+ errortext(ERR_MIME_PART_EXPECTED, "Incorrect data type: MIME part expected.")
+#define ERR_MIME_PARSE_MORE_DATA PKG_NSF3+88
+ internaltext(ERR_MIME_PARSE_MORE_DATA,"Internal only - MIME parser needs more data.")
+#define ERR_MIME_PARSE_BAD_DATA PKG_NSF3+89
+ errortext(ERR_MIME_PARSE_BAD_DATA, "Incorrect format in MIME data.")
+#define ERR_MIME_PARSE_NOT_FOUND PKG_NSF3+90
+ internaltext(ERR_MIME_PARSE_NOT_FOUND,"Internal only - String not found in MIME data.")
+#define ERR_MIME_PART_OVERFLOW PKG_NSF3+91
+ errortext(ERR_MIME_PART_OVERFLOW, "Data too large for MIME part item.")
+#define ERR_NO_SUCH_TRANSLOG PKG_NSF3+92
+ errortext(ERR_NO_SUCH_TRANSLOG, "The specified transaction log file is not in the list of files to be archived.")
+#define ERR_NO_ARCHIVED_EXTENT PKG_NSF3+93
+ errortext(ERR_NO_ARCHIVED_EXTENT, "No extent on the archive list has been archived.")
+#define ERR_NO_TRANSLOGS_TO_ARCHIVE PKG_NSF3+94
+ errortext(ERR_NO_TRANSLOGS_TO_ARCHIVE, "No transaction log files are waiting to be archived.")
+#define ERR_RM_LOG_FORMAT PKG_NSF3+95
+ errortext(ERR_RM_LOG_FORMAT, "Recovery Manager: Log format not supported.")
+#define ERR_NO_ARCHIVE_SPECIFIED PKG_NSF3+96
+ errortext(ERR_NO_ARCHIVE_SPECIFIED, "No archive database specified")
+#define ERR_CONTAINER_CORRUPT PKG_NSF3+97
+ internaltext(ERR_CONTAINER_CORRUPT, "Database container is corrupt and must be rebuilt.")
+#define ERR_DBCACHE_CLOSED PKG_NSF3+98
+ internaltext(ERR_DBCACHE_CLOSED, "Db Cache is not open")
+#define ERR_RM_MQ_LOG_ERROR PKG_NSF3+99
+ errortext(ERR_RM_MQ_LOG_ERROR, "Recovery Manager: Error from Logging Subsystem.")
+#define ERR_NSF_CORRUPT_NAMEDOBJECT PKG_NSF3+100
+ errortext(ERR_NSF_CORRUPT_NAMEDOBJECT, "Database is damaged and can't be repaired (Named Object Table).")
+#define ERR_EH_DELETE_ENTRY PKG_NSF3+101
+ internaltext(ERR_EH_DELETE_ENTRY, "Internal only - delete ehash entry.")
+#define ERR_EH_UPDATE_ENTRY PKG_NSF3+102
+ internaltext(ERR_EH_UPDATE_ENTRY, "Internal only - update ehash entry.")
+#define ERR_RM_END_OF_LOG PKG_NSF3+103
+ internaltext(ERR_RM_END_OF_LOG, "Recovery Manager: Read past End of Log.")
+#define ERR_RM_SCAN_IN_PROGRESS PKG_NSF3+104
+ errortext(ERR_RM_SCAN_IN_PROGRESS, "Recovery Manager: Log scan in progress, try again later.")
+#define ERR_RM_LOG_SPACE_CRITICAL PKG_NSF3+105
+ errortext(ERR_RM_LOG_SPACE_CRITICAL, "Recovery Manager: Log space is becoming critical.")
+#define ERR_DBINUSE PKG_NSF3+106
+ errortext(ERR_DBINUSE, "The database is in use and cannot be taken off-line.")
+#define ERR_RM_LATE_BACKUP PKG_NSF3+107
+ errortext(ERR_RM_LATE_BACKUP, "Recovery Manager: Backup was later than recovery point in time.")
+
+#define STR_ARC_CREATED_BY PKG_NSF3+108
+ stringtext(STR_ARC_CREATED_BY, "\t%s (created by %s on %z)\n\n|\tError creating document link for note ID %lu : %s\n\n")
+#define IDX_ARC_DOCLINK_CREATED_BY 1
+#define IDX_ARC_DOCLINK_ERROR 2
+
+/* Use OSLoadSubString to load substrings - english total length<80! */
+#define STR_ARC_MISC PKG_NSF3+109
+ stringtext(STR_ARC_MISC, "Local| (Archive) |DocLink to|Archive Logs|day|days|Archive Logs for %s")
+
+#define IDX_ARC_VALUE_LOCAL 1
+#define IDX_ARC_MISC_TITLE 2
+#define IDX_ARC_MISC_LINK 3
+#define IDX_ARC_LOG_TITLE 4
+#define IDX_ARC_MISC_DAY 5
+#define IDX_ARC_MISC_DAYS 6
+#define IDX_ARC_LOG_TITLE_FOR 7
+
+#define STR_ARC_TRAILER_TITLE PKG_NSF3+110
+ stringtext(STR_ARC_TRAILER_TITLE, "Archive log for documents")
+#define STR_ARC_COMPLETED PKG_NSF3+111
+ stringtext(STR_ARC_COMPLETED, "from %a (%p) to %a (%p) completed successfully on %z.")
+#define STR_ARC_EXPIRED_DOCS PKG_NSF3+112
+ stringtext(STR_ARC_EXPIRED_DOCS, "Expired documents are archived after")
+#define STR_ARC_INACTIVE_DOCS PKG_NSF3+113
+ stringtext(STR_ARC_INACTIVE_DOCS, "Inactive documents are archived after")
+#define STR_ARC_MODIFIED_DOCS PKG_NSF3+114
+ stringtext(STR_ARC_MODIFIED_DOCS, "Modified documents are archived after")
+#define ERR_RM_OPEN_BACKUP PKG_NSF3+115
+ errortext(ERR_RM_OPEN_BACKUP, "Recovery Manager: You must restore or fixup a logged backup before use.")
+#define ERR_RM_DBIID_IN_USE PKG_NSF3+116
+ errortext(ERR_RM_DBIID_IN_USE, "Recovery Manager: Database ID already in use, must use fixup to reassign.")
+#define ERR_RM_DOWN_LEVEL PKG_NSF3+117
+ errortext(ERR_RM_DOWN_LEVEL, "Recovery Manager: Database is not latest copy.")
+#define ERR_RM_NOTE_LRFAILURE PKG_NSF3+118
+ errortext(ERR_RM_NOTE_LRFAILURE, "Recovery Manager: General Failure doing Note Undo/Redo.")
+#define ERR_RM_ZAPLSN_NEEDED PKG_NSF3+119
+ internaltext(ERR_RM_ZAPLSN_NEEDED, "Recovery Manager: Database from different log cannot be verified until normal open.")
+#define ERR_RM_RECD_TRUNCATED PKG_NSF3+120
+ internaltext(ERR_RM_RECD_TRUNCATED, "Recovery Manager: Warning - Log Record Read was Truncated.")
+#define ERR_DBOFFLINE PKG_NSF3+121
+ errortext(ERR_DBOFFLINE, "The database is being taken off-line and cannot be opened.")
+#define ERR_RM_RECOVER_NONBACKUP PKG_NSF3+122
+ errortext(ERR_RM_RECOVER_NONBACKUP, "Recovery Manager: Recovery only supported for Backup Files.")
+#define ERR_NO_ARCHIVELOG_SPECIFIED PKG_NSF3+123
+ errortext(ERR_NO_ARCHIVELOG_SPECIFIED, "No archive log database specified")
+#define ERR_NOT_LOCK_DB PKG_NSF3+124
+ errortext(ERR_NOT_LOCK_DB, "Attempted a lock operation on a DB that doesn't support locking")
+#define ERR_NOTE_LOCKED PKG_NSF3+125
+ errortext(ERR_NOTE_LOCKED, "The document is already locked by %s")
+#define ERR_RM_LOG_PARSE_TRUNCATED PKG_NSF3+126
+ internaltext(ERR_RM_LOG_PARSE_TRUNCATED, "Recovery Manager: Log parse of segments was truncated.")
+#define ERR_SERVER_NOT_TRANSLOGGED PKG_NSF3+127
+ errortext(ERR_SERVER_NOT_TRANSLOGGED, "Transactional Logging must be enabled for this function.")
+
+/* PKG_NSF3 codes limited to 0-127 */
+
+#define ERR_RM_SKIP_FIXUP PKG_NSF4+0
+ errortext(ERR_RM_SKIP_FIXUP, "Recovery Manager: Preserving backups by skipping fixup of logged DB without -j switch, DB=%p")
+#define ERR_TRANSLOG_NOT_ARCHIVED PKG_NSF4+1
+ internaltext(ERR_TRANSLOG_NOT_ARCHIVED, "Transaction log not archived.")
+#define ERR_RM_NEW_DBIID PKG_NSF4+2
+ errortext(ERR_RM_NEW_DBIID, "Recovery Manager: Assigning new DBIID for %p (need new backup for media recovery).")
+#define ERR_RM_MEDIA_RECOVERY PKG_NSF4+3
+ errortext(ERR_RM_MEDIA_RECOVERY, "Recovery Manager: Media Recovery complete for %p, last update applied %z.")
+#define ERR_BACKUP_ALREADY_IN_PROGRESS PKG_NSF4+4
+ errortext(ERR_BACKUP_ALREADY_IN_PROGRESS, "Attempt to backup a database that is currently being backed up.")
+#define ERR_NOT_DOING_BACKUP PKG_NSF4+5
+ errortext(ERR_NOT_DOING_BACKUP, "Requested operation only allowed while database is being backed up.")
+#define ERR_INVALID_CHANGE_INFO_CONTEXT PKG_NSF4+6
+ errortext(ERR_INVALID_CHANGE_INFO_CONTEXT, "Change3 Information Context is invalid.")
+#define ERR_CORRUPT_CHANGE_INFO PKG_NSF4+7
+ errortext(ERR_CORRUPT_CHANGE_INFO, "The change information is corrupt or not associated with this file.")
+#define ERR_RM_RESTART_RECOVERY PKG_NSF4+8
+ errortext(ERR_RM_RESTART_RECOVERY, "Recovery Manager: Restart Recovery complete. (%d/%d databases needed full/partial recovery)")
+#define ERR_RM_DUP_DBIID PKG_NSF4+9
+ errortext(ERR_RM_DUP_DBIID, "Recovery Manager: Warning duplicate DBIID detected: DB1=%p DB2=%p")
+#define ERR_RM_STATUS_ANALYSIS PKG_NSF4+10
+ errortext(ERR_RM_STATUS_ANALYSIS, "Restart Analysis")
+#define ERR_RM_DB_MISSING PKG_NSF4+11
+ errortext(ERR_RM_DB_MISSING, "Recovery Manager: Database Instance ID not found for what was")
+#define ERR_ADMIN_REQ_DB_NOT_INIT PKG_NSF4+12
+ errortext(ERR_ADMIN_REQ_DB_NOT_INIT,"The Administration Request Database cannot be opened; it has not yet been initialized by the Administration Process.")
+#define ERR_SELF_REFERENCING_DOCUMENT PKG_NSF4+13
+ errortext(ERR_SELF_REFERENCING_DOCUMENT ,"Attempt to create a self-referencing document.")
+#define ERR_TRANSLOG_ARCHIVE_IN_PROGRESS PKG_NSF4+14
+ errortext(ERR_TRANSLOG_ARCHIVE_IN_PROGRESS, "Archiving of transaction logs already in progress.")
+#define ERR_UBMCANTEVICT PKG_NSF4+15
+ errortext(ERR_UBMCANTEVICT, "UBM I/O Method could not evict page.")
+#define ERR_FILEDOCMAX PKG_NSF4+16
+ errortext(ERR_FILEDOCMAX, "Database (.nsf) has too many documents.")
+#define ERR_RM_STATUS_REDO PKG_NSF4+17
+ errortext(ERR_RM_STATUS_REDO, "Restart Replay")
+#define ERR_RM_STATUS_MREDO PKG_NSF4+18
+ errortext(ERR_RM_STATUS_MREDO, "Media Recovery Replay")
+#define ERR_EH_AT_MAX PKG_NSF4+19
+ internaltext(ERR_EH_AT_MAX, "Operation cannot be performed because ehash has reached max size.")
+#define ERR_EH_DATA_TOO_BIG PKG_NSF4+20
+ internaltext(ERR_EH_DATA_TOO_BIG, "Data is too large for ehash")
+#define ERR_STOP_ENUM PKG_NSF4+21
+ internaltext(ERR_STOP_ENUM, "Internal only - stop enumeration (of design notes, named object, ehash, etc)")
+#define ERR_BUFFER_TOO_SMALL PKG_NSF4+22
+ internaltext(ERR_BUFFER_TOO_SMALL, "Internal only - buffer caller provided is too small")
+#define STR_RM_CHECKPOINT_THREAD PKG_NSF4+23
+ stringtext(STR_RM_CHECKPOINT_THREAD, "Recovery Manager Checkpoint Thread")
+#define STR_RM_FLUSH_THREAD PKG_NSF4+24
+ stringtext(STR_RM_FLUSH_THREAD, "Recovery Manager DB Flushing Thread")
+#define ERR_CVS_INIT_FAILED PKG_NSF4+25
+ errortext(ERR_CVS_INIT_FAILED, "CVS initialization failed.")
+#define ERR_DUPLICATE_NOTEID PKG_NSF4+26
+ errortext(ERR_DUPLICATE_NOTEID, "Database already contains a document with this ID (NOTEID)")
+#define ERR_ARC_INCORRECT_PROFILE PKG_NSF4+27
+ errortext(ERR_ARC_INCORRECT_PROFILE, "Incorrect archive profile.")
+#define ERR_ARC_REQ_SRC_ACCESS PKG_NSF4+28
+ errortext(ERR_ARC_REQ_SRC_ACCESS, "Signer does not have the required access rights to the source database.")
+#define ERR_ARC_REQ_ARC_ACCESS PKG_NSF4+29
+ errortext(ERR_ARC_REQ_ARC_ACCESS, "Signer does not have the required access rights to the archive database.")
+#define ERR_ARC_INCORRECT_SVR PKG_NSF4+30
+ errortext(ERR_ARC_INCORRECT_SVR, "Archiving server not configured properly.")
+#define ERR_ARC_ARCFILE_NOT_ON_SVR PKG_NSF4+31
+ errortext(ERR_ARC_ARCFILE_NOT_ON_SVR, "Archive must be on archiving server.")
+
+/* PKG_NSF4 codes limited to 0-31 */
+
+#define ERR_ARC_NOT_ENABLED PKG_NSF5+0
+ errortext(ERR_ARC_NOT_ENABLED, "Archiving is not enabled.")
+
+#define ERR_QUOTA_LESS_THAN_WARNING PKG_NSF5+1
+ errortext(ERR_QUOTA_LESS_THAN_WARNING, "Cannot set quota to less than warning.")
+
+/* Use OSLoadSubString to load substrings - english total length<80!
+ Append strings onto this guy but don't delete or change the order */
+#define STR_ADDIN_NSF_GEN_MSG_1 PKG_NSF5+2
+ stringtext(STR_ADDIN_NSF_GEN_MSG_1,"Creating Administration Requests database")
+#define IDX_GEN_CREATE_ADMIN4 1
+
+#define ERR_ADDRESS_MISMATCH PKG_NSF5+3
+ errortext(ERR_ADDRESS_MISMATCH, "Signer address mismatch")
+
+#define ERR_MIXED_SECURITY PKG_NSF5+4
+ errortext(ERR_MIXED_SECURITY, "Cannot SMIME encrypt a note that has already been Notes signed or encrypted.")
+#define NSFSTR_TRANSLOG_DAMAGED PKG_NSF5+5
+ stringtext(NSFSTR_TRANSLOG_DAMAGED, "Transaction log is damaged!")
+#define NSFSTR_TRANSLOG_BAD_LOCATION PKG_NSF5+6
+ stringtext(NSFSTR_TRANSLOG_BAD_LOCATION, "Transaction log path does not exist or is not accessible.")
+#define NSFSTR_TRANSLOG_NEW_PATH PKG_NSF5+7
+ stringtext(NSFSTR_TRANSLOG_NEW_PATH,"Unable to create or access transaction log path")
+#define NSFSTR_TRANSLOG_OLD_PATH PKG_NSF5+8
+ stringtext(NSFSTR_TRANSLOG_OLD_PATH,"Path to transaction log does not match actual path, using old path. Please UPDATE SERVER RECORD.")
+#define ERR_DUPLICATE_UNK PKG_NSF5+9
+ internaltext(ERR_DUPLICATE_UNK, "Duplicate UNK found in UNK table")
+#define ERR_CMD_SHOW_NSFPOOL PKG_NSF5+10
+ stringtext(ERR_CMD_SHOW_NSFPOOL, "NSFPOOL")
+#define ERR_HELP_SHOW_NSFPOOL PKG_NSF5+11
+ stringtext(ERR_HELP_SHOW_NSFPOOL, "* Show the contents of the Server's NSF pool.")
+#define ERR_MIME_NO_822HDR_NAME PKG_NSF5+12
+ errortext(ERR_MIME_NO_822HDR_NAME, "Invalid or missing RFC822 header name.")
+#define ERR_MIME_NO_822HDR_DELIM PKG_NSF5+13
+ errortext(ERR_MIME_NO_822HDR_DELIM, "Invalid or missing RFC822 header delimiter.")
+#define ERR_AGER_FILE_OPEN_FAILED PKG_NSF5+14
+ internaltext(ERR_AGER_FILE_OPEN_FAILED, "Ager failed to open database.")
+#define ERR_CHILD_MUST_BE_DATA_NOTE PKG_NSF5+15
+ errortext(ERR_CHILD_MUST_BE_DATA_NOTE, "Children of DATA notes must be DATA notes.")
+
+ /* PKG_NSF5 codes limited to 0-15 */
+
+#define ERR_EM_SUCCESS PKG_NSF6+0
+ internaltext(ERR_EM_SUCCESS, "success")
+#define ERR_NSF_NOT_SUPPORTED PKG_NSF6+1
+ errortext(ERR_NSF_NOT_SUPPORTED, "This routine is not supported on this platform.")
+#define ERR_LOG_RESPONSE_CYCLE PKG_NSF6+2
+ errortext(ERR_LOG_RESPONSE_CYCLE, "This operation on %p (NoteID = %lu) creates a cycle in the response hierarchy")
+#define ERR_INVALID_BT_CONTEXT_SIG PKG_NSF6+3
+ errortext(ERR_INVALID_BT_CONTEXT_SIG, "Invalid btree context signature")
+#define ERR_INVALID_BT_ENTRY PKG_NSF6+4
+ errortext(ERR_INVALID_BT_ENTRY, "Invalid btree entry")
+#define ERR_INVALID_BT_LEVEL PKG_NSF6+5
+ errortext(ERR_INVALID_BT_LEVEL, "Invalid btree level")
+#define ERR_INVALID_BT_SIBLING_DIR PKG_NSF6+6
+ errortext(ERR_INVALID_BT_SIBLING_DIR, "Invalid btree sibling direction")
+#define ERR_CORRUPT_BT_CONTEXT_SIG PKG_NSF6+7
+ errortext(ERR_CORRUPT_BT_CONTEXT_SIG, "Btree context signature marked corrupt")
+#define ERR_NULL_BT_CONTEXT_SIG PKG_NSF6+8
+ errortext(ERR_NULL_BT_CONTEXT_SIG, "Btree context signature is NULL")
+#define ERR_INVALID_BT_NODESIZE PKG_NSF6+9
+ errortext(ERR_INVALID_BT_NODESIZE, "Invalid btree node size")
+#define ERR_INVALID_LONGDATA_SIZE PKG_NSF6+10
+ errortext(ERR_INVALID_LONGDATA_SIZE, "Invalid btree longdata size")
+#define ERR_BT_ENTRY_NOT_MAX PKG_NSF6+11
+ errortext(ERR_BT_ENTRY_NOT_MAX, "Invalid btree max entry")
+#define ERR_INVALID_BT_SUBINDEX_REFCNT PKG_NSF6+12
+ errortext(ERR_INVALID_BT_SUBINDEX_REFCNT, "Invalid btree subindex reference count")
+#define ERR_INVALID_BT_DESC_DATASIZE PKG_NSF6+13
+ errortext(ERR_INVALID_BT_DESC_DATASIZE, "Invalid btree descriptor data size")
+#define ERR_INVALID_BT_DATASIZE PKG_NSF6+14
+ errortext(ERR_INVALID_BT_DATASIZE, "Invalid btree entry data size")
+#define ERR_INVALID_BT_KEYSIZE PKG_NSF6+15
+ errortext(ERR_INVALID_BT_KEYSIZE, "Invalid btree entry key size")
+
+ /* PKG_NSF6 codes limited to 0-15 */
+
+#define ERR_BT_SPLIT_SLOTTED_NODE PKG_NSF7+0
+ errortext(ERR_BT_SPLIT_SLOTTED_NODE, "Invalid btree split of a slotted node")
+#define ERR_BT_SPLIT_POINT PKG_NSF7+1
+ errortext(ERR_BT_SPLIT_POINT, "Invalid btree split point")
+#define ERR_BT_BAD_POSITION PKG_NSF7+2
+ errortext(ERR_BT_BAD_POSITION, "Invalid btree node position")
+#define ERR_BT_DELETE_NONEMPTY_ROOT PKG_NSF7+3
+ errortext(ERR_BT_DELETE_NONEMPTY_ROOT, "Invalid btree delete of a nonempty root node")
+#define ERR_BT_TRAVERSAL_BROKEN PKG_NSF7+4
+ errortext(ERR_BT_TRAVERSAL_BROKEN, "Invalid btree traversal")
+#define ERR_BT_BAD_CARDINALITY PKG_NSF7+5
+ errortext(ERR_BT_BAD_CARDINALITY, "Invalid btree cardinality")
+#define ERR_INVALID_BT_DESC PKG_NSF7+6
+ errortext(ERR_INVALID_BT_DESC, "Invalid btree descriptor")
+#define ERR_INVALID_BT_ADDR PKG_NSF7+7
+ errortext(ERR_INVALID_BT_ADDR, "Invalid btree address")
+#define ERR_CMD_SET_SCOS PKG_NSF7+8
+ stringtext(ERR_CMD_SET_SCOS,"SCOS [Database Path] [Active/Inactive]")
+#define ERR_HELP_SET_SCOS PKG_NSF7+9
+ stringtext(ERR_HELP_SET_SCOS,"Activate/Inactivate SCOS database")
+#define ERR_ROUTER_SCOS_INVALID (PKG_NSF7+10)
+ errortext(ERR_ROUTER_SCOS_INVALID, "\nRouter: obsolete shared mail command.")
+#define ERR_SCOS_NUM_FILES_REQ PKG_NSF7+11
+ errortext(ERR_SCOS_NUM_FILES_REQ, "\nRequested files (%d) for %s exceeds the server maximum %d files.\nCreating: %d file(s).\n")
+#define ERR_SCOS_DIR_MAX_FILE_SPEC PKG_NSF7+12
+ errortext(ERR_SCOS_DIR_MAX_FILE_SPEC, "SCOS_DIR_MAX_FILES_%d")
+#define ERR_SCOS_DIR_MAX_SIZE_SPEC PKG_NSF7+13
+ errortext(ERR_SCOS_DIR_MAX_SIZE_SPEC, "SCOS_DIR_MAX_SIZE_MB_%d")
+#define ERR_SCOS_DIR_MAX_FILE_SIZE_SPEC PKG_NSF7+14
+ errortext(ERR_SCOS_DIR_MAX_FILE_SIZE_SPEC, "SCOS_DIR_MAX_FILE_SIZE_MB_%d")
+#define ERR_SCOS_NOT_RUNNING PKG_NSF7+15
+ errortext(ERR_SCOS_NOT_RUNNING, "The SCOS database is not running.\n")
+#define ERR_DBG_SHOW_HEAD PKG_NSF7+16
+ errortext(ERR_DBG_SHOW_HEAD,"\n\nDatabase\t\tAvailability\tState\t\t\tSize\n")
+#define ERR_NOTE_ALREADY_LOCKED_BY_LOCKER PKG_NSF7+17
+ errortext(ERR_NOTE_ALREADY_LOCKED_BY_LOCKER, "You already have the document locked")
+#define ERR_NOTE_NOT_LOCKED_BY_LOCKER PKG_NSF7+18
+ errortext(ERR_NOTE_NOT_LOCKED_BY_LOCKER, "The document is not locked by you")
+#define ERR_DBG_KB PKG_NSF7+19
+ errortext(ERR_DBG_KB, "KB")
+#define ERR_DBG_MB PKG_NSF7+20
+ errortext(ERR_DBG_MB, "MB")
+#define ERR_DBG_INV_PATH PKG_NSF7+21
+ errortext(ERR_DBG_INV_PATH, "\nInvalid path: %s")
+#define ERR_DBG_ACTIVE PKG_NSF7+22
+ errortext(ERR_DBG_ACTIVE, "Active ")
+#define ERR_DBG_INACTIVE PKG_NSF7+23
+ errortext(ERR_DBG_INACTIVE, "Inactive")
+#define ERR_NO_MORE_RRVS PKG_NSF7+24
+ errortext(ERR_NO_MORE_RRVS, "Cannot allocate RRV, please create new replica.")
+#define ERR_IMAP_ALREADYENABLED PKG_NSF7+25
+ errortext(ERR_IMAP_ALREADYENABLED, "Database is already IMAP enabled")
+#define ERR_IMAP_ALREADYDISABLED PKG_NSF7+26
+ errortext(ERR_IMAP_ALREADYDISABLED, "Database is already IMAP disabled")
+#define ERR_INVALID_FOLDER_REFCOUNT_OP PKG_NSF7+27
+ errortext(ERR_INVALID_FOLDER_REFCOUNT_OP, "Invalid folder refcount operation")
+#define ERR_NOACCESS_FOR_REPORCOPY PKG_NSF7+28
+ errortext(ERR_NOACCESS_FOR_REPORCOPY, "You are not authorized to replicate or copy data from this database.")
+#define ERR_DBG_OPEN_DELIVERY PKG_NSF7+29
+ errortext(ERR_DBG_OPEN_DELIVERY , "open for delivery ")
+#define ERR_DBG_CLOSED_DELIVERY PKG_NSF7+30
+ errortext(ERR_DBG_CLOSED_DELIVERY , "closed for delivery")
+#define ERR_DBG_TOTAL_SIZE PKG_NSF7+31
+ errortext(ERR_DBG_TOTAL_SIZE, "\n\nTotal Database Disk Size in Directory: %d.%02d MB")
+
+ /* PKG_NSF7 codes limited to 0-31 */
+
+#define ERR_DBG_AVAIL_SIZE PKG_NSF8+0
+ errortext(ERR_DBG_AVAIL_SIZE, "\nTotal Database Disk Available in Directory: %d.%02d MB")
+#define ERR_DBG_FREE_SIZE PKG_NSF8+1
+ errortext(ERR_DBG_FREE_SIZE, "\n\nTotal Database Internal Free Space for Directory: %d.%02d MB\n\n")
+#define ERR_DBG_ENABLED PKG_NSF8+2
+ errortext(ERR_DBG_ENABLED , "Enabled ")
+#define ERR_DBG_DISABLED PKG_NSF8+3
+ errortext(ERR_DBG_DISABLED , "Error ")
+#define ERR_SCOS_DIR PKG_NSF8+4
+ errortext(ERR_SCOS_DIR, "\nRequested zero files (%d), or max size (%d) for the SCOS directory %s.\n")
+#define ERR_SCOS_FILE_SIZE PKG_NSF8+5
+ errortext(ERR_SCOS_FILE_SIZE,"\nSCOS database specification out of range in the notes.ini file. The size of the database is in megabyte units.")
+#define ERR_SCOS_SIZE_FILES PKG_NSF8+6
+ errortext(ERR_SCOS_SIZE_FILES, "\nSCOS directory %s - total size (%d) exceeds maximum (%d).\n")
+#define ERR_SCOS_NO_DIR PKG_NSF8+7
+ errortext(ERR_SCOS_NO_DIR, "\nDirectory %s ignored, the directory (or link) does not exist.\n")
+#define ERR_DBG_INV_SPEC PKG_NSF8+8
+ errortext(ERR_DBG_INV_SPEC, "\nDirectory %s ignored, invalid specification - %s\n")
+#define ERR_SCOS_CREATE PKG_NSF8+9
+ errortext(ERR_SCOS_CREATE, "\nCreating SCOS file: %s.\n")
+#define ERR_DBG_DUPE PKG_NSF8+10
+ errortext(ERR_DBG_DUPE, "Duplicate")
+#define ERR_SCOS_NO_CREATE PKG_NSF8+11
+ errortext(ERR_SCOS_NO_CREATE, "\nCould not create SCOS database %s.\n")
+#define ERR_SCOS_DIR_SPEC PKG_NSF8+12
+ errortext(ERR_SCOS_DIR_SPEC, "SCOS_DIR_%d")
+#define ERR_SCOS_DIR_NUM_FILE_SPEC PKG_NSF8+13
+ errortext(ERR_SCOS_DIR_NUM_FILE_SPEC, "SCOS_DIR_ACTIVE_FILES_%d")
+#define ERR_DBG_SHOW_DIR PKG_NSF8+14
+ errortext(ERR_DBG_SHOW_DIR, "\n\nDirectory: %s - %s")
+#define ERR_DBG_SHOW_REQ PKG_NSF8+15
+ errortext(ERR_DBG_SHOW_REQ, "\nNumber of delivery databases requested: %d.\nNumber of databases: %d\nMaximum Directory Size: %d MB")
+#define ERR_CMD_SHOW_SCOS PKG_NSF8+16
+ stringtext(ERR_CMD_SHOW_SCOS,"SCOS")
+#define ERR_HELP_SHOW_SCOS PKG_NSF8+17
+ stringtext(ERR_HELP_SHOW_SCOS,"Single copy object store information")
+#define ERR_NSFIMAP_FOLDERSLIST_POOLFULL PKG_NSF8+18
+ errortext(ERR_NSFIMAP_FOLDERSLIST_POOLFULL, "AVL tree for IMAP folder names is full.")
+#define ERR_NSFIMAP_INVALID_ARG PKG_NSF8+19
+ errortext(ERR_NSFIMAP_INVALID_ARG, "Invalid IMAP command argument")
+#define ERR_NSFIMAP_INTERNAL_SEARCH (PKG_NSF8+20)
+ errortext(ERR_NSFIMAP_INTERNAL_SEARCH, "Internal IMAP search error")
+#define ERR_NSFIMAP_UNSUPPORTED_CHARSET (PKG_NSF8+21)
+ errortext(ERR_NSFIMAP_UNSUPPORTED_CHARSET, "Unsupported CHARSET")
+#define ERR_NSFIMAP_SEARCH_UNSUPPORTED_CRITERIA_SIZE (PKG_NSF8+22)
+ errortext(ERR_NSFIMAP_SEARCH_UNSUPPORTED_CRITERIA_SIZE, "Searching by size (SMALLER, LARGER) is not supported")
+#define ERR_NSFIMAP_SEARCH_UNSUPPORTED_CRITERIA (PKG_NSF8+23)
+ errortext(ERR_NSFIMAP_SEARCH_UNSUPPORTED_CRITERIA, "Unsupported search criteria")
+#define ERR_NOT_DBIMAP_ENABLED PKG_NSF8+24
+ errortext(ERR_NOT_DBIMAP_ENABLED, "the database has not been enabled for IMAP support")
+#define ERR_DBG_TOO_LARGE PKG_NSF8+25
+ errortext(ERR_DBG_TOO_LARGE , "\nTotal size of the databases in directory is too large.")
+#define ERR_IMAPFOLDER_NOT_FOUND PKG_NSF8+26
+ errortext(ERR_IMAPFOLDER_NOT_FOUND, "Folder not found in IMAP name space")
+#define ERR_INVALID_IMAP_FLAGS PKG_NSF8+27
+ errortext(ERR_INVALID_IMAP_FLAGS, "Invalid IMAP flags value")
+#define ERR_INVALID_DBIMAP_CMD PKG_NSF8+28
+ errortext(ERR_INVALID_DBIMAP_CMD, "Invalid IMAP command flag")
+#define ERR_EM_RELOAD_NOTE PKG_NSF8+29
+ internaltext(ERR_EM_RELOAD_NOTE, "Reload hNote after NSFNoteUpdate")
+#define ERR_SCOS_DUPE_FILE PKG_NSF8+30
+ errortext(ERR_SCOS_DUPE_FILE, "\nSCOS database ignored: %s duplicate name to: %s\n")
+#define ERR_NO_SERVER_FOR_DB PKG_NSF8+31
+ errortext(ERR_NO_SERVER_FOR_DB, "No server containing a replica of the database is available")
+#define ERR_DB_NOT_LOCATED PKG_NSF8+32
+ errortext(ERR_DB_NOT_LOCATED, "Database can not be located in the Cluster")
+#define ERR_ENTRY_NOT_HASHED PKG_NSF8+33
+ errortext(ERR_ENTRY_NOT_HASHED, "Entry is not Hashed")
+#define ERR_HASH_NOT_CLEANED PKG_NSF8+34
+ errortext(ERR_HASH_NOT_CLEANED, "There are no entries to be cleaned from Hash")
+#define ERR_NSFXACL_OBJXACL_NOT_FOUND PKG_NSF8+35
+ errortext(ERR_NSFXACL_OBJXACL_NOT_FOUND, "extended ACL not found in the object")
+#define ERR_NSF_XACL_POOLFULL PKG_NSF8+36
+ errortext(ERR_NSF_XACL_POOLFULL, "Insufficient memory - NSF extended ACL pool is full.")
+#define ERR_SERVER_NOT_CLUSTERED PKG_NSF8+37
+ errortext(ERR_SERVER_NOT_CLUSTERED, "Server is not in the Cluster")
+#define ERR_CLCACHE_NOT_INITIALIZED PKG_NSF8+38
+ errortext(ERR_CLCACHE_NOT_INITIALIZED, "NSF Cluster Name Cache is not initialized yet")
+#define ERR_NSF_XACL_UNIDREBUILD PKG_NSF8+39
+ errortext(ERR_NSF_XACL_UNIDREBUILD, "Extended access control option has changed. Rebuilding UNID Index in database %s...")
+#define ERR_XML_EXCEPTION PKG_NSF8+40
+ errortext(ERR_XML_EXCEPTION, "\nXML parser exception occurred")
+#define ERR_XML_BUF_TOO_SMALL PKG_NSF8+41
+ errortext(ERR_XML_BUF_TOO_SMALL, "\nAllocated buffer too small")
+#define ERR_XML_WRONG_NODE_TYPE PKG_NSF8+42
+ errortext(ERR_XML_WRONG_NODE_TYPE, "\nUnrecognized node type")
+#define ERR_XML_CANNOT_OPEN_FILE PKG_NSF8+43
+ errortext(ERR_XML_CANNOT_OPEN_FILE, "\nCannot open the file")
+#define ERR_NOINPLACECOMPACT PKG_NSF8+44
+ errortext(ERR_NOINPLACECOMPACT, "In-place database compaction could not be performed as requested")
+#define ERR_INVALID_SEQNUM PKG_NSF8+45
+ errortext(ERR_INVALID_SEQNUM, "Invalid IMAP sequence number")
+#define ERR_DN_NOT_FOUND PKG_NSF8+46
+ errortext(ERR_DN_NOT_FOUND, "Note DN not found")
+#define ERR_XML_ITEM_NOT_FOUND PKG_NSF8+47
+ errortext(ERR_XML_ITEM_NOT_FOUND, "\nNote Item could not be found")
+#define ERR_XML_ITEM_EXISTS PKG_NSF8+48
+ errortext(ERR_XML_ITEM_EXISTS, "\nNote Item already exists")
+#define ERR_XML_SAXEXCEPTION PKG_NSF8+49
+ errortext(ERR_XML_SAXEXCEPTION, "\nXML SAX parser exception")
+#define ERR_SCHED_CANT_LOOKUP_USER PKG_NSF8+50
+ errortext(ERR_SCHED_CANT_LOOKUP_USER, "Error looking up user %a in Domino Directory for scheduling request")
+#define ERR_SCHED_USER_NOT_IN_NAB PKG_NSF8+51
+ errortext(ERR_SCHED_USER_NOT_IN_NAB, "Cannot find user in Domino Directory")
+#define ERR_SCHED_MULTIPLE_USERS PKG_NSF8+52
+ errortext(ERR_SCHED_MULTIPLE_USERS, "Warning: Multiple matches found for %a in Domino Directory, using first one found")
+#define ERR_SCHED_USER_IS_FORWARDED PKG_NSF8+53
+ errortext(ERR_SCHED_USER_IS_FORWARDED, "User's mail is being forwarded to another location")
+#define ERR_SCHED_USER_NOT_IN_CALDOMAIN PKG_NSF8+54
+ errortext(ERR_SCHED_USER_NOT_IN_CALDOMAIN, "User's calendar is not in this domain")
+#define ERR_NO_MASTER_LOCK_DB PKG_NSF8+55
+ errortext(ERR_NO_MASTER_LOCK_DB, "Unable to connect to Master Lock Database")
+#define ERR_LOCK_PROMOTED PKG_NSF8+56
+ errortext(ERR_LOCK_PROMOTED, "A provisional lock in database '%s' has been promoted to a hard lock. Document link is attached to this message")
+#define ERR_LOCK_NOT_PROMOTED PKG_NSF8+57
+ errortext(ERR_LOCK_NOT_PROMOTED, "A provisional lock in database '%s' has NOT been promoted to a hard lock. There was a conflict detected. Your changes may be found in body of this message. A document link to the original document is attached to the end of the message")
+#define ERR_CHANGES_PROMOTED PKG_NSF8+58
+ errortext(ERR_CHANGES_PROMOTED, "Changes made to database '%s' have been incorporated into the database with no conflicts. Document link is attached to message")
+#define ERR_CHANGES_NOT_PROMOTED PKG_NSF8+59
+ errortext(ERR_CHANGES_NOT_PROMOTED, "Changes made to database '%s' have NOT been incorporated into the database. There was a conflict detected. Your changes may be found in body of this message. A document link to the original document is attached to the end of the message.")
+#define ERR_NO_CLHASH PKG_NSF8+60
+ errortext(ERR_NO_CLHASH, "Cluster Hash Table has not been Initialized yet")
+#define ERR_DUP_SINGLE_COPY_TEMPLATE PKG_NSF8+61
+ errortext(ERR_DUP_SINGLE_COPY_TEMPLATE, "Multiple single copy templates with the same name are not allowed.")
+#define ERR_SINGLE_COPY_TEMPLATE_NAME PKG_NSF8+62
+ errortext(ERR_SINGLE_COPY_TEMPLATE_NAME, "Single copy template must have a unique master template name, and the file name must end in '.nt*'.")
+#define ERR_RESYNC_SINGLE_COPY_TEMPLATE PKG_NSF8+63
+ errortext(ERR_RESYNC_SINGLE_COPY_TEMPLATE, "Need to run design refresh on database %s to bring it up to date with its single copy template.")
+#define ERR_FIXING_DONE PKG_NSF8+64
+ errortext(ERR_FIXING_DONE, "Completed consistency check on %s")
+#define ERR_LKMGR_NOT_FOUND PKG_NSF8+65
+ internaltext(ERR_LKMGR_NOT_FOUND, "Lock Manager: Lock Not Found")
+#define ERR_LKMGR_DEADLOCK PKG_NSF8+66
+ errortext(ERR_LKMGR_DEADLOCK, "Lock Manager: Deadlock detected, retry transaction latter")
+#define ERR_FALSE_DEADLOCK PKG_NSF8+67
+ internaltext(ERR_FALSE_DEADLOCK, "Lock Manager: False Deadlock detected")
+#define ERR_LKMGR_POOL_FAILURE PKG_NSF8+68
+ errortext(ERR_LKMGR_POOL_FAILURE, "Lock Manager: Insufficient memory - Lock Manager Pool is full")
+#define ERR_KEY_DELETED PKG_NSF8+69
+ internaltext(ERR_KEY_DELETED, "Found a Pseudo Deleted Key")
+#define ERR_FOLDERSLIST_TOO_BIG PKG_NSF8+70
+ errortext(ERR_FOLDERSLIST_TOO_BIG, "NSF Folders list for IMAP is too big")
+#define ERR_NSFXACL_INHERITED PKG_NSF8+71
+ errortext(ERR_NSFXACL_INHERITED, "Access Control Information was inherited from other object")
+#define ERR_ARCHIVE_NO_MATCH_FOR_SERVER PKG_NSF8+72
+ errortext(ERR_ARCHIVE_NO_MATCH_FOR_SERVER, "No match for server found")
+#define ERR_NOTE_DELETED_BY_RULE PKG_NSF8+73
+ errortext(ERR_NOTE_DELETED_BY_RULE, "Document has been rejected by mail rule")
+#define ERR_ARCHIVE_ON_SERVER_ENABLED PKG_NSF8+74
+ errortext(ERR_ARCHIVE_ON_SERVER_ENABLED, "Server based archiving enabled - unable to initiate archiving from local workstation")
+#define STR_LK_REPORTING_THREAD PKG_NSF8+75
+ internaltext(STR_LK_REPORTING_THREAD, "Lock Manager Reporting Thread")
+#define ERR_SCOS_DIR_NOT_CONFIGURED PKG_NSF8+76
+ errortext(ERR_SCOS_DIR_NOT_CONFIGURED, "SCOS_DIR_NOT_CONFIGURED_%d")
+#define ERR_DBG_CLOSED_CONFIG PKG_NSF8+77
+ errortext(ERR_DBG_CLOSED_CONFIG, "not configured ")
+#define ERR_DBG_SUMMARY_HDR PKG_NSF8+78
+ stringtext(ERR_DBG_SUMMARY_HDR, "\n\nDirectory\tAvailability\tRequested\t Actual\tMax Size\n\n")
+#define ERR_DBG_SUMMARY_INFO PKG_NSF8+79
+ stringtext(ERR_DBG_SUMMARY_INFO, "%s\n\t\t%s\t%d\t\t%d\t%d\n")
+#define ERR_DBG_SUMMARY_TAIL PKG_NSF8+80
+ stringtext(ERR_DBG_SUMMARY_TAIL, "\nTotals\t\t\t\t\t%d\t\t%d\t%d\n")
+#define ERR_SCOS_DIRLINK_CONFLICT PKG_NSF8+81
+ errortext(ERR_SCOS_DIRLINK_CONFLICT, "\nDirectory %s conflicts with SCOS directory link %s%s to directory %s.\n")
+#define ERR_DBG_DISABLED_DB PKG_NSF8+82
+ errortext(ERR_DBG_DISABLED_DB , "The object store database is disabled. ")
+#define ERR_SCOS_NUM_FILES_DIR PKG_NSF8+83
+ errortext(ERR_SCOS_NUM_FILES_DIR, "SCOS directory %s - the total number of specified files (%d) exceeds the maximum (%d).\n")
+#define ERR_ARCH_CANT_MOD_EFFECTIVE_POLICY PKG_NSF8+84
+ errortext(ERR_ARCH_CANT_MOD_EFFECTIVE_POLICY, "Cannot modify settings in the effective archive policy")
+#define ERR_NOT_AN_ADMINISTRATOR PKG_NSF8+85
+ errortext(ERR_NOT_AN_ADMINISTRATOR, "You must be a server administrator to perform this action")
+/* Logging for Roaming Users (NameLookupUserID) */
+#define STR_ROAMING_USER_ACCESS PKG_NSF8+86
+ errortext(STR_ROAMING_USER_ACCESS, "Roaming user %s password failed")
+#define ERR_RM_TRAN_NESTING PKG_NSF8+87
+ errortext(ERR_RM_TRAN_NESTING, "Recovery Manager: Transaction nesting exceeded supported maximum or no transaction in progress")
+#define ERR_RM_LONG_TRANSACTION_ABORT PKG_NSF8+88
+ errortext(ERR_RM_LONG_TRANSACTION_ABORT, "Recovery Manager: Transaction ran too long, must abort")
+#define ERR_ONLY_LOGGED_DATABASES PKG_NSF8+89
+ errortext(ERR_ONLY_LOGGED_DATABASES, "Function only supported for transaction logged databases")
+#define ERR_REPLACE PKG_NSF8+90
+ errortext(ERR_REPLACE,"Replace existing %p?")
+#define STR_SCOS_ONLINE_CFG PKG_NSF8+91
+ stringtext(STR_SCOS_ONLINE_CFG, "SCOS_ONLINE_%d")
+#define STR_SCOS_ACTIVE_CFG PKG_NSF8+92
+ stringtext(STR_SCOS_ACTIVE_CFG, "SCOS_ACTIVE_%d")
+#define STR_SCOS_OFFLINE PKG_NSF8+93
+ stringtext(STR_SCOS_OFFLINE, "offline ")
+#define ERR_DBG_DB_INACTIVE PKG_NSF8+94
+ errortext(ERR_DBG_DB_INACTIVE, "Object store database Inactive.")
+#define ERR_DBG_DIR_INACTIVE PKG_NSF8+95
+ errortext(ERR_DBG_DIR_INACTIVE, "Object store directory Inactive.")
+#define ERR_DBG_DIR_OFFLINE PKG_NSF8+96
+ errortext(ERR_DBG_DIR_OFFLINE, "Object store directory offline.")
+#define ERR_SOFTDELETE_EXPIRE_TIME PKG_NSF8+97
+ errortext(ERR_SOFTDELETE_EXPIRE_TIME, "Soft delete expire time must be a whole number greater than zero.")
+#define ERR_NOTE_INVSIG11 PKG_NSF8+98
+ errortext(ERR_NOTE_INVSIG11, "Data signature passed; object signature invalid")
+#define ERR_SWITCH_TO_COPYSTYLE PKG_NSF8+99
+ errortext(ERR_SWITCH_TO_COPYSTYLE, "Switching to copy-style compaction for %p due to unique fields names table size")
+#define ERR_USE_LARGEUNK_OR_COPYSTYLE PKG_NSF8+100
+ errortext(ERR_USE_LARGEUNK_OR_COPYSTYLE, "Unique field names table filling up for %p: Set 'Allow more fields in database' option or use copy-style compaction to reduce")
+#define ERR_USE_COPYSTYLE PKG_NSF8+101
+ errortext(ERR_USE_COPYSTYLE, "Unique field names table filling up for %p: Use copy-style compaction to reduce")
+#define ERR_IMAP_KEYWORD_TOO_LONG PKG_NSF8+102
+ errortext(ERR_IMAP_KEYWORD_TOO_LONG, "IMAP Keyword flag names cannot be longer than 31 bytes")
+#define ERR_DOCCACHE_POOLFULL PKG_NSF8+103
+ errortext(ERR_DOCCACHE_POOLFULL, "Insufficient memory - Document cache pool is full.")
+#define ERR_CANT_INIT_ASP_CONTEXT PKG_NSF8+104
+ errortext(ERR_CANT_INIT_ASP_CONTEXT, "Unable to initialize parse the DN %s")
+#define ERR_INVALID_ASP_USER_NAME PKG_NSF8+105
+ errortext(ERR_INVALID_ASP_USER_NAME, "%s is an invalid user name in an ASP configuration")
+#define ERR_EM_CONTINUE_VNOTE PKG_NSF8+106
+ internaltext(ERR_EM_CONTINUE_VNOTE, "Continue Virtual Note processing.")
+#define ERR_INVALID_VNOTE PKG_NSF8+107
+ errortext(ERR_INVALID_VNOTE, "Virtual Note has an invalid format.")
+#define ERR_COLLREBUILDEXTRACOL PKG_NSF8+108
+ errortext(ERR_COLLREBUILDEXTRACOL, "Informational, rebuilding view - external format note has been modified since last rebuild. (reading %s %s note Title:'%s')")
+#define ERR_TARGET_DB_CLOSED PKG_NSF8+109
+ errortext(ERR_TARGET_DB_CLOSED, "Cannot access the document's target database to copy attachments")
+#define ERR_NO_NOTE_UPDATE PKG_NSF8+110
+ errortext(ERR_NO_NOTE_UPDATE, "Cannot update note due to NOTE_FLAG2_NO_UPDATE being set")
+#define ERR_NO_NOTE_CHANGE PKG_NSF8+111
+ errortext(ERR_NO_NOTE_CHANGE, "Cannot modify note due to NOTE_FLAG2_NO_CHANGE being set")
+
+#define ERR_SIGNER_MUST_BE_POL_CREATOR_MOD (PKG_NSF8+112)
+ errortext(ERR_SIGNER_MUST_BE_POL_CREATOR_MOD, "The Policy and/or Settings Document assigned to you has been edited by an unauthorized person. Please notify your Administrator that you cannot proceed with the client setup.")
+#define ERR_POLICY_SIGNER_NOT_POL_CREATOR_MOD (PKG_NSF8+113)
+ errortext(ERR_POLICY_SIGNER_NOT_POL_CREATOR_MOD, "%s, the signer of policy document %s, does not have the required PolicyCreator or PolicyModifier role to the Domino Directory.")
+#define ERR_POLICY_SIGNATURE_MSG (PKG_NSF8+114)
+ errortext(ERR_POLICY_SIGNATURE_MSG, "The effective policy could not be derived - the following error was encountered while processing policy document %s: %e.")
+
+#define ERR_CANNOT_DELEGATE PKG_NSF8+115
+ errortext(ERR_CANNOT_DELEGATE,"You may not delegate to this person, as he/she has already been invited to this meeting. Please choose another delegee for this meeting.")
+
+#define ERR_MESSAGE_DO_NOT_DELIVER PKG_NSF8+116
+ errortext(ERR_MESSAGE_DO_NOT_DELIVER,"This message will not be delivered by the router because an error occurred in processing.")
+#define ERR_EH_PSEUDO_DELETED PKG_NSF8+117
+ internaltext(ERR_EH_PSEUDO_DELETED, "Key in Extensible hash exists but is flag deleted")
+
+#define ERR_NOTE_LOCKED_BYSOMEONE PKG_NSF8+118
+ errortext(ERR_NOTE_LOCKED_BYSOMEONE, "The document is already locked by someone else.")
+
+/* Logging for Roaming Users (NameLookupUserID) */
+#define STR_ROAMING_USER_ID_VIOLATION PKG_NSF8+119
+ errortext(STR_ROAMING_USER_ID_VIOLATION, "You are trying to access a roaming user id which has not been properly roamed. Please re-roam.")
+
+#define ERR_DBIMAP_MUST_BE_REENABLED PKG_NSF8+120
+ errortext(ERR_DBIMAP_MUST_BE_REENABLED, "Database %p must be re-enabled for IMAP support")
+
+#define ERR_ARC_REQ_SRC_USER_ACCESS PKG_NSF8+121
+ errortext(ERR_ARC_REQ_SRC_USER_ACCESS, "You do not have the required access rights to the source database.")
+#define ERR_ARC_REQ_ARC_USER_ACCESS PKG_NSF8+122
+ errortext(ERR_ARC_REQ_ARC_USER_ACCESS, "You do not have the required access rights to the archive database.")
+#define ERR_ARC_SETTINGS_SIGNATURE PKG_NSF8+123
+ errortext(ERR_ARC_SETTINGS_SIGNATURE, "Signature on archive settings is invalid")
+#define ERR_ARCHIVE_POLICY_PROHIBITED PKG_NSF8+124
+ errortext(ERR_ARCHIVE_POLICY_PROHIBITED , "Archiving is prohibited by a policy set by an administrator")
+
+#define ERR_IMAP_KEYWORDS_TOO_LARGE PKG_NSF8+125
+ errortext(ERR_IMAP_KEYWORDS_TOO_LARGE, "IMAP Keyword flags length cannot exceed 32 KB")
+
+#define ERR_ARC_RETRIEVE_SETTINGS PKG_NSF8+126
+ errortext(ERR_ARC_RETRIEVE_SETTINGS, "Unable to retrieve archiving settings")
+#define ERR_ARC_SELECTING_DOCS PKG_NSF8+127
+ errortext(ERR_ARC_SELECTING_DOCS, "Unable to select documents for archiving")
+
+/* PKG_NSF8 codes limited to 0-127 */
+
+#define ERR_ARC_COPY_DOCUMENTS PKG_NSF9+0
+ errortext(ERR_ARC_COPY_DOCUMENTS, "Unable to copy documents to archive database")
+#define ERR_ARC_DELETE_DOCUMENTS PKG_NSF9+1
+ errortext(ERR_ARC_DELETE_DOCUMENTS, "Unable to delete documents from source database")
+#define ERR_ARC_TRUNCATE_DOCUMENTS PKG_NSF9+2
+ errortext(ERR_ARC_TRUNCATE_DOCUMENTS, "Unable to truncate documents from source database")
+#define STR_ARC_ARCHIVING PKG_NSF9+3
+ stringtext(STR_ARC_ARCHIVING, "Archiving|Calendar Cleanup|Done.|done. %d docs deleted")
+#define IDX_ARCHIVING 1
+#define IDX_CAL_CLEANUP 2
+#define IDX_DONE 3
+#define IDX_DOCS_DEL 4
+#define STR_ARC_PROGRESS_STATES PKG_NSF9+4
+ stringtext(STR_ARC_PROGRESS_STATES, "%s|Retrieving settings|Creating Archive DB|Creating Log DB|Updating Log Design|Selecting Documents|Copying Documents|Deleting Documents|Truncating Documents|done. %d docs archived, %d docs deleted, %d docs truncated|Processing Documents for Preview")
+#define ERR_LOCATING_SCT PKG_NSF9+5
+ errortext(ERR_LOCATING_SCT, "The single copy template associated with this database cannot be located.")
+#define ERR_OPENING_SCT PKG_NSF9+6
+ errortext(ERR_OPENING_SCT, "Unable to open the single copy template associated with this database.")
+#define STR_ADDIN_NSF_DONTTRANS_MSG_1 PKG_NSF9+7
+ donottranslatetext(STR_ADDIN_NSF_DONTTRANS_MSG_1, "Administration Requests")
+#define ERR_EM_INVALID_CALLBACKPTR PKG_NSF9+8
+ errortext(ERR_EM_INVALID_CALLBACKPTR, "Extension registration contains NULL pointer to callback routine")
+#define IDX_GEN_ADMIN4_TITLE 1
+#define ERR_PAINDEX_CORRUPT PKG_NSF9+9
+ errortext(ERR_PAINDEX_CORRUPT, "Protected Attachments Index corrupt.")
+#define ERR_ARCHIVE_DATABASE_INVALID PKG_NSF9+10
+ errortext(ERR_ARCHIVE_DATABASE_INVALID, "Archive Database format is invalid")
+#define ERR_ARCHIVE_DATABASE_NO_MATCH_SRCREPID PKG_NSF9+11
+ errortext(ERR_ARCHIVE_DATABASE_NO_MATCH_SRCREPID, "Archive database specifies a different source database")
+#define ERR_OPT_UNREAD_SYNC PKG_NSF9+12
+ internaltext(ERR_OPT_UNREAD_SYNC, "Optimized unread synchronization performed.")
+#define ERR_NO_PROVISIONAL_ON_MASTERDB PKG_NSF9+13
+ errortext(ERR_NO_PROVISIONAL_ON_MASTERDB, "Provisional locks on the master lock database are not allowed")
+#define ERR_FILEEXT_FAILURE PKG_NSF9+14
+ errortext(ERR_FILEEXT_FAILURE, "Extendable File object: failure")
+#define ERR_URL_TOO_LONG PKG_NSF9+15
+ errortext(ERR_URL_TOO_LONG, "URL is too long")
+#define ERR_BACKUP_ABORTED PKG_NSF9+16
+ errortext(ERR_BACKUP_ABORTED, "Backup terminated due to timeout")
+#define ERR_PURGED_NOTES_MISSING PKG_NSF9+17
+ internaltext(ERR_PURGED_NOTES_MISSING, "Unable to determine what notes may have been purged before the search date")
+#define ERR_COMPACT_INTERRUPTED_MSG PKG_NSF9+18
+ errortext(ERR_COMPACT_INTERRUPTED_MSG, "Compaction of the database was stopped prematurely because another user modified it while it was being compacted (%s).")
+#define ERR_INSERT_DATANOTEID_TBL PKG_NSF9+19
+ errortext(ERR_INSERT_DATANOTEID_TBL, "Error inserting Note ID %X into data note ID table in %s: %e.")
+#define ERR_UNABLE_TO_BRING_ONLINE PKG_NSF9+20
+ errortext(ERR_UNABLE_TO_BRING_ONLINE, "Compaction failed: Unable to bring %p back online.")
+#define ERR_NSFIMAP_HAS_SUBFOLDERS PKG_NSF9+21
+ errortext(ERR_NSFIMAP_HAS_SUBFOLDERS, "One or more child mailbox(es) exists")
+#define ERR_CANT_CREATE_TEMPLATE PKG_NSF9+22
+ errortext(ERR_CANT_CREATE_TEMPLATE, "You do not have sufficient access to create master templates on this server.")
+#define ERR_DBU_WRONG_PROCESS PKG_NSF9+23
+ errortext(ERR_DBU_WRONG_PROCESS, "DBUs cannot be shared between Processes.")
+#define ERR_NSF_ARCH_SELDOCS_NOT_DELETED PKG_NSF9+24
+ errortext(ERR_NSF_ARCH_SELDOCS_NOT_DELETED, "Some of the selected documents were not deleted because they are still required in this database.")
+#define LOG_CREATING_DBDIRMAN_CACHE PKG_NSF9+25
+ errortext(LOG_CREATING_DBDIRMAN_CACHE, "Creating Database Directory Cache database (%s)...")
+#define ERR_TOO_MANY_RARELY_USED_ITEMS PKG_NSF9+26
+ errortext(ERR_TOO_MANY_RARELY_USED_ITEMS, "Cannot store document because it has too many unique field names.")
+#define ERR_NSF_UNABLE_TO_CHANGE_DBOPTION PKG_NSF9+27
+ errortext(ERR_NSF_UNABLE_TO_CHANGE_DBOPTION,"Cannot disable consistent access without turning off extended access control first.")
+#define ERR_SIGNDB_NOTE_CLASS_NOT_FOUND PKG_NSF9+28
+ errortext(ERR_SIGNDB_NOTE_CLASS_NOT_FOUND, "Specified note does not match note class requested.")
+#define ERR_DUPLICATE_TEMPLATE PKG_NSF9+29
+ errortext(ERR_DUPLICATE_TEMPLATE, "Cannot create template with duplicate name.")
+#define ERR_CACHEFAILURE PKG_NSF9+30
+ errortext(ERR_CACHEFAILURE, "An error has occurred which will affect performance. Please make a copy of the file %s and then delete the original which will correct the problem. Please report the problem to IBM.")
+#define ERR_DESIGN_REFRESH_NOT_ADMIN PKG_NSF9+32
+ errortext(ERR_DESIGN_REFRESH_NOT_ADMIN, "Design Refresh can only be done on the Administration server of this database.")
+#define ERR_ARCHIVING_NOT_ENABLED_ON_SVR PKG_NSF9+33
+ errortext(ERR_ARCHIVING_NOT_ENABLED_ON_SVR, "Server-based archiving not enabled on database.")
+#define ERR_BKTDSC_MODIFIED_BACKWARDS PKG_NSF9+34
+ errortext(ERR_BKTDSC_MODIFIED_BACKWARDS,"Bucket descriptor modified time is going backwards from %z to %z in %s.")
+#define ERR_CURRENT_UNIQUE_TIME PKG_NSF9+35
+ errortext(ERR_CURRENT_UNIQUE_TIME, "Database (%s) time is too far in the future.")
+#define ERR_FILEREAD PKG_NSF9+36
+ errortext(ERR_FILEREAD, "Hardware/OS error (%s) reading from database (%s), Length=%X (PID=%0X/TID=%0X)\n")
+#define ERR_FILEWRITE PKG_NSF9+37
+ errortext(ERR_FILEWRITE, "Hardware/OS error (%s) writing to database (%s), Length=%X (PID=%0X/TID=%0X)\n")
+#define ERR_NTUPDATE_MONITOR_ERROR PKG_NSF9+38
+ errortext(ERR_NTUPDATE_MONITOR_ERROR, "Monitor Error in Database %s:")
+#define ERR_NTUPDATE_FOLDER_ERROR PKG_NSF9+39
+ errortext(ERR_NTUPDATE_FOLDER_ERROR, "Unable to add note %x to folder in Database %s:")
+#define ERR_CMD_SHOW_MONITORPOOL PKG_NSF9+40
+ stringtext(ERR_CMD_SHOW_MONITORPOOL, "NSFMONITORPOOL")
+#define ERR_HELP_SHOW_MONITORPOOL PKG_NSF9+41
+ stringtext(ERR_HELP_SHOW_MONITORPOOL, "* Show the contents of the Server's MONITOR pool.")
+#define ERR_XACL_NOTSUPPORTED PKG_NSF9+42
+ errortext(ERR_XACL_NOTSUPPORTED, "The extended access control feature is not supported for the database.")
+#define ERR_DESIGN_IN_NAMOBJ PKG_NSF9+43
+ errortext(ERR_DESIGN_IN_NAMOBJ, "Design collection not in named object table.")
+#define ERR_DISK_SCOS PKG_NSF9+44
+ errortext(ERR_DISK_SCOS, "Insufficient disk space in shared mail directory.")
+#define ERR_FORCE_COMPACT PKG_NSF9+45
+ internaltext(ERR_FORCE_COMPACT, "Force compaction.")
+#define ERR_SUPERBLOCK_TOO_LARGE PKG_NSF9+46
+ internaltext(ERR_SUPERBLOCK_TOO_LARGE, "Superblock has exceeded its maximum allowable size.")
+#define ERR_CONFLICT_SCOS PKG_NSF9+47
+ errortext(ERR_CONFLICT_SCOS, "Shared mail note access conflict, retry in progress.")
+#define ERR_NOTE_MUST_BE_LOCKED_FOR_DELETE PKG_NSF9+48
+ errortext(ERR_NOTE_MUST_BE_LOCKED_FOR_DELETE, "Document locking is enabled. You must lock the document before deleting.")
+#define ERR_ARCHIVE_DEFAULT_PRIVATE_NAME_MOD PKG_NSF9+49
+ stringtext(ERR_ARCHIVE_DEFAULT_PRIVATE_NAME_MOD, "Default for Last Modified")
+#define ERR_ARCHIVE_DEFAULT_PRIVATE_NAME_LA PKG_NSF9+50
+ stringtext(ERR_ARCHIVE_DEFAULT_PRIVATE_NAME_LA, "Default for Last Accessed")
+#define ERR_ARCHIVE_DEFAULT_PRIVATE_NAME_EXP PKG_NSF9+51
+ stringtext(ERR_ARCHIVE_DEFAULT_PRIVATE_NAME_EXP, "Default for Expired")
+#define ERR_OVERWARNQUOTA PKG_NSF9+52
+ errortext(ERR_OVERWARNQUOTA, "Warning: Operation would put database over quota warning threshold.")
+#define LOG_CANT_CREATE_TEMPLATE PKG_NSF9+53
+ errortext(LOG_CANT_CREATE_TEMPLATE, "Attempt by %s to define database %s as template %s rejected.")
+#define LOG_DUPLICATE_TEMPLATE PKG_NSF9+54
+ errortext(LOG_DUPLICATE_TEMPLATE, "Attempt by %s to create duplicate template %s in database %s - rejected.")
+#define LOG_ALREADY_IS_A_CHILD PKG_NSF9+55
+ errortext(LOG_ALREADY_IS_A_CHILD, "Note %d already is a child of note %d in database %s.")
+#define ERR_NSF_MONITOR_EVENTSFULL PKG_NSF9+56
+ errortext(ERR_NSF_MONITOR_EVENTSFULL, "Insufficient memory - NSF monitor pool event space is full.")
+#define ERR_DBIMAP_FOLDER_UPDATE_FAILED PKG_NSF9+57
+ errortext(ERR_DBIMAP_FOLDER_UPDATE_FAILED, "Note NT%08lx was not updated in the IMAP btree for folder %s (NT%08lx) in database %s. Database should be re-enabled for IMAP support.")
+#define ERR_ARCHIVING_POLICY_EXISTS PKG_NSF9+58
+ errortext(ERR_ARCHIVING_POLICY_EXISTS, "An archive policy has been set by the administrator, cannot get archive settings.")
+#define STR_NSF_XACL_ENABLED PKG_NSF9+59
+ errortext(STR_NSF_XACL_ENABLED, "Extended access control feature is enabled for the database %s")
+#define STR_NSF_XACL_DISABLED PKG_NSF9+60
+ errortext(STR_NSF_XACL_DISABLED, "Extended access control feature is disabled for the database %s")
+#define ERR_NONSUMMARY_READAUTH PKG_NSF9+61
+ errortext(ERR_NONSUMMARY_READAUTH, "Update not allowed due to nonsummary author/reader names field. Saving may restrict access to this document.")
+
+#define ERR_BAD_IDTABLE_LENGTH PKG_NSF9+62
+ errortext(ERR_BAD_IDTABLE_LENGTH, "Bad idtable length detected in a super block.")
+#define ERR_DB_DELETE_IN_PROGRESS PKG_NSF9+63
+ errortext(ERR_DB_DELETE_IN_PROGRESS, "Database is being deleted.")
+
+#define ERR_ARCHIVE_LOG_TEMPLATE_NOT_FOUND PKG_NSF9+64
+ errortext(ERR_ARCHIVE_LOG_TEMPLATE_NOT_FOUND, "Archive log template (archlg50.ntf) not found, unable to create archive log database.")
+#define ERR_ARCHIVE_LOG_CREATE PKG_NSF9+65
+ errortext(ERR_ARCHIVE_LOG_CREATE, "Error creating archive log database")
+#define ERR_RM_LOGGER_RC PKG_NSF9+66
+ errortext(ERR_RM_LOGGER_RC, "Logger Failure: Func=%s RC=0x%08x File=%s\n")
+#define ERR_RM_UNDO_REDO_RC PKG_NSF9+67
+ errortext(ERR_RM_UNDO_REDO_RC, "Error from undo/redo LSN=%02x%02x%02x%02x-%02x%02x%02x%02x rc: %d %e Type=%02x/%02x DB=%s\n")
+#define ERR_INVALID_CONTAINER_OBJECT PKG_NSF9+68
+ errortext(ERR_INVALID_CONTAINER_OBJECT, "Container object is corrupt. Use compact -d to discard view indexes.")
+#define ERR_CMD_SHOW_DBG PKG_NSF9+69
+ stringtext(ERR_CMD_SHOW_DBG,"DBG")
+#define ERR_HELP_SHOW_DBG PKG_NSF9+70
+ stringtext(ERR_HELP_SHOW_DBG,"Database group information")
+#define ERR_LK_PER_TXN_LOCKS PKG_NSF9+71
+ errortext(ERR_LK_PER_TXN_LOCKS, "Maximum locks per explicit txn exceeded")
+#define ERR_LK_MAX_TXN_LOCKS PKG_NSF9+72
+ errortext(ERR_LK_MAX_TXN_LOCKS, "Maximum locks for explicit txns exceeded")
+#define ERR_RESOLVING_REF_NOTE PKG_NSF9+73
+ errortext(ERR_RESOLVING_REF_NOTE, "Error opening note unable to resolve the referenced note")
+#define ERR_CANNOT_SELECT_PROFILE_DOCS PKG_NSF9+74
+ stringtext(ERR_CANNOT_SELECT_PROFILE_DOCS, "Using a selection formula to filter profile documents is not supported by version 5 (or older) Domino servers.")
+#define ERR_NULL_PNOVEC_VARRAY PKG_NSF9+75
+ stringtext(ERR_NULL_PNOVEC_VARRAY, "Page vector array is NULL")
+#define ERR_CONT_REOPENED PKG_NSF9+76
+ stringtext(ERR_CONT_REOPENED, "Attempt to reopen an open container")
+#define ERR_UNREAD_LOG_CORRUPT PKG_NSF9+77
+ errortext(ERR_UNREAD_LOG_CORRUPT, "Unread Log is corrupt")
+#define ERR_FIXUP_FOUND_UNREADLOG PKG_NSF9+78
+ errortext(ERR_FIXUP_FOUND_UNREADLOG, "Unread activity log for user %a in database %p is damaged: %e")
+#define ERR_AUTHOR_UPDATED_ONLY_PROTECTED PKG_NSF9+79
+ errortext(ERR_AUTHOR_UPDATED_ONLY_PROTECTED, "NoteUpdate: ID[%s] with Author access tried to update *ONLY* protected fields, nothing updated; db=%s, NoteID=0x%lx\n")
+#define ERR_ARCHIVE_DEFAULT_PRIVATE_NAME_SELECTED PKG_NSF9+80
+ stringtext(ERR_ARCHIVE_DEFAULT_PRIVATE_NAME_SELECTED, "Default for Selected (no aging)")
+#define LOG_REALLOC_UNREAD_LOG PKG_NSF9+81
+ errortext(LOG_REALLOC_UNREAD_LOG, "Unread log for user %a in database %p is being reallocated. ReasonCode:%d")
+#define LOG_REALLOC_UNREAD_ALLUSER PKG_NSF9+82
+ errortext(LOG_REALLOC_UNREAD_ALLUSER, "Unread all-user for database %p is being reallocated. ReasonCode:%d")
+#define LOG_UNREAD_CHUNK_BAD PKG_NSF9+83
+ errortext(LOG_UNREAD_CHUNK_BAD, "Unread chunk %d for user %a in database %p is bad. Object: %x. ReasonCode:%d")
+#define LOG_UNREAD_REPLICATION_OPTION_CHG PKG_NSF9+84
+ errortext(LOG_UNREAD_REPLICATION_OPTION_CHG, "%s Database Option: %s for database %s")
+#define LOG_ALLUSER_BAD_LOG PKG_NSF9+85
+ errortext(LOG_ALLUSER_BAD_LOG, "Invalid Object in Unread All-User table for database %p. Removing reference for index %d. %e")
+#define LOG_DDM_LOOK_AT_UPDATE PKG_NSF9+86
+ errortext(LOG_DDM_LOOK_AT_UPDATE, "NSFNoteUpdate may be working on an interesting note ... %s, %a")
+#define ERR_RM_XA_ERROR PKG_NSF9+87
+ errortext(ERR_RM_XA_ERROR, "An error occurred accessing the db2 datasource, xa error = %d")
+#define ERR_DB2_ADMIN_CATALOG_NODE PKG_NSF9+89
+ errortext(ERR_DB2_ADMIN_CATALOG_NODE, "Error attempting to catalog node.")
+#define ERR_DB2_ADMIN_CATALOG_DBALIAS PKG_NSF9+90
+ errortext(ERR_DB2_ADMIN_CATALOG_DBALIAS, "Error attempting to catalog db alias.")
+#define ERR_BKTDESC_CORRUPT PKG_NSF9+91
+ errortext(ERR_BKTDESC_CORRUPT, "Bucket descriptor corrupt.")
+#define ERR_DB2_ADMIN_LIB_NOT_AVAILABLE PKG_NSF9+92
+ errortext(ERR_DB2_ADMIN_LIB_NOT_AVAILABLE, "The DB2 library is not available.")
+#define ERR_NSF_ALREADY_DB2NSF PKG_NSF9+93
+ errortext(ERR_NSF_ALREADY_DB2NSF, "The database is already stored in DB2.")
+/* Available PKG_NSF9+94 - 99 */
+#define NSF_DB2_CLP_SQL_NO_DATA PKG_NSF9+100
+ errortext(NSF_DB2_CLP_SQL_NO_DATA, "Data not found.")
+#define ERR_FIXING_WAIT PKG_NSF9+101
+ errortext(ERR_FIXING_WAIT, "Performing consistency check. Please wait...")
+#define ERR_DB2_ADMIN_CREATE_DB2_GROUP PKG_NSF9+102
+ errortext(ERR_DB2_ADMIN_CREATE_DB2_GROUP, "Error attempting to add group to SYSCTRL_GROUP.")
+
+#define LOG_UNREAD_ROLLBACK PKG_NSF9+103
+ errortext(LOG_UNREAD_ROLLBACK, "Rolling back Unread Log for user %a in database %p.")
+#define STR_RM_INDOUBTPROC_THREAD PKG_NSF9+104
+ stringtext(STR_RM_INDOUBTPROC_THREAD, "Recovery Manager Indoubt resolution Thread")
+
+#define NSF_DB2_LOCAL_ENCRYPTION_UNAVAILABLE PKG_NSF9+105
+ errortext(NSF_DB2_LOCAL_ENCRYPTION_UNAVAILABLE, "Local encryption is not supported for a DB2 backed Notes database. %s will not be locally encrypted by Domino in DB2.")
+#define ERR_DB2NSF_FEDERATION PKG_NSF9+106
+ errortext(ERR_DB2NSF_FEDERATION, "Unable to set up federation to alternate recovery database")
+
+#define ERR_MONITOR_TOO_MUCH_SUMMARY PKG_NSF9+108
+ errortext(ERR_MONITOR_TOO_MUCH_SUMMARY, "Too much summary data returned for monitor in %p")
+
+#define NSF_DB2BACKUP_SERVERRUNNING PKG_NSF9+109
+ errortext(NSF_DB2BACKUP_SERVERRUNNING, "This API function cannot be called if Domino is running")
+#define CONTEXT_DB2UPDATE_FILE_HEADER PKG_NSF9+110
+ errortext(CONTEXT_DB2UPDATE_FILE_HEADER, "Failed to update system Catalog table")
+#define CONTEXT_DB2READ_CATALOG PKG_NSF9+111
+ errortext(CONTEXT_DB2READ_CATALOG, "Failed to read system Catalog table")
+#define CONTEXT_DB2READ_SCHEMATABLES PKG_NSF9+112
+ errortext(CONTEXT_DB2READ_SCHEMATABLES, "Failed to query DB2 system catalog for tables belonging to schema")
+#define ERR_DB2NSF_NOTDB2BACKED PKG_NSF9+113
+ errortext(ERR_DB2NSF_NOTDB2BACKED, "Invalid NSFDB2 database.")
+#define ERR_DB2NSF_SRC_AND_DESTINATION PKG_NSF9+114
+ errortext(ERR_DB2NSF_SRC_AND_DESTINATION, "The source and destination file specification cannot be the same")
+#define CONTEXT_DB2NSF_SQL_COPY_FAILURE PKG_NSF9+115
+ errortext(CONTEXT_DB2NSF_SQL_COPY_FAILURE, "Unable to perform a fast copy/move to target")
+#define ERR_DB2NSF_TABLESPACE_INFO PKG_NSF9+116
+ errortext(ERR_DB2NSF_TABLESPACE_INFO, "Failed to obtain tablespace information.")
+#define ERR_DB2NSF_ODS_NOT_SUPPORTED PKG_NSF9+117
+ errortext(ERR_DB2NSF_ODS_NOT_SUPPORTED, "NSFDB2 Databases require Notes/Domino 6.0 or later database versions.")
+
+/* Available PKG_NSF9+118 - 123 */
+
+#define ERR_DB2_ADMIN_EN_ACCOUNT_YES_NO PKG_NSF9+124
+ errortext(ERR_DB2_ADMIN_EN_ACCOUNT_YES_NO, "Server could not update user accounts. If you have already set up the user accounts, press 'Continue' to continue. Otherwise press 'Stop' to stop.\n\nContinue?\n")
+
+#define ERR_DB2_UDF_ADMIN_ERROR_RET PKG_NSF9+125
+ errortext(ERR_DB2_UDF_ADMIN_ERROR_RET, "DB2 Access admin returned error.")
+#define ERR_DB2_UDF_ADMIN_DLL_RET PKG_NSF9+126
+ stringtext(ERR_DB2_UDF_ADMIN_DLL_RET, "%d UDF Admin DLL: %s.|Update connection completed|Update connection returned error|Read connection returned error")
+#define IDX_DB2_UDF_DLL_PREF 1
+#define IDX_DB2_UDF_DLL_UPDT_OK 2
+#define IDX_DB2_UDF_DLL_UPDT_ERR 3
+#define IDX_DB2_UDF_DLL_READ_ERR 4
+
+#define ERR_DB2_ADMIN_EN_USER_ERROR PKG_NSF9+127
+ stringtext(ERR_DB2_ADMIN_EN_USER_ERROR, "- DB2 Server Enable could not set up user account.\n")
+
+#define ERR_DB2_ADMIN_EN_GROUP_EXISTS PKG_NSF9+128
+ stringtext(ERR_DB2_ADMIN_EN_GROUP_EXISTS, "- The SYSCTRL_GROUP, '%s' already exists.\n")
+
+#define ERR_DB2_ADMIN_EN_GROUP_GROUP PKG_NSF9+129
+ stringtext(ERR_DB2_ADMIN_EN_GROUP_GROUP, "- The user must be added to the SYSCTRL_GROUP '%s'.\n")
+
+#define DB2_ENABLE_TOOL_RAN PKG_NSF9+130
+ stringtext(DB2_ENABLE_TOOL_RAN, "This server is already running on DB2. Please make any changes to the DB2 configuration in the server document.")
+
+#define LOG_IGNORE_OLD_UNREAD_REPL_OPS PKG_NSF9+131
+ errortext(LOG_IGNORE_OLD_UNREAD_REPL_OPS, "Ignoring Pre-Cutoff Unread Replication Activities for user %a in database %p.")
+#define LOG_IGNORE_FUTURE_UNREAD_REPL_OPS PKG_NSF9+132
+ errortext(LOG_IGNORE_FUTURE_UNREAD_REPL_OPS, "Ignoring Unread Replication Activities dated in the future for user %a in database %p.")
+
+#define ERR_DB2NSF_IDENTIFIER_INVALID PKG_NSF9+133
+ errortext(ERR_DB2NSF_IDENTIFIER_INVALID, "The identifier specified does not exist in DB2 or does not contain the requested NSFDB2 data.")
+
+#define ERR_DB2_ADMIN_EN_ACCOUNT_RIGHTS_ERR2 PKG_NSF9+134
+ stringtext(ERR_DB2_ADMIN_EN_ACCOUNT_RIGHTS_ERR2, "- You must create the user account.\n- You also need to create the group 'DB2DOM', if it doesn't exist, \n- and add the DB2 user to it.\n")
+
+#define ERR_DB2NSF_SCHEMA_INUSE PKG_NSF9+135
+ errortext(ERR_DB2NSF_SCHEMA_INUSE, "The schema specified is in use by another NSFDB2 database.")
+#define ERR_DB2NSF_CATALOG_UPDATE_FAILURE PKG_NSF9+136
+ errortext(ERR_DB2NSF_CATALOG_UPDATE_FAILURE, "Failed to update row in system CATALOG for database %s in schema %s.")
+
+#define ERR_DB2NSF_NONXA_CONNECT PKG_NSF9+137
+ errortext(ERR_DB2NSF_NONXA_CONNECT, "Failed to create a non-XA connection to DB2 database")
+#define ERR_DB2NSF_CATALOG_REMOVE_ROW PKG_NSF9+138
+ errortext(ERR_DB2NSF_CATALOG_REMOVE_ROW, "Row in system CATALOG table for database %s in schema %s is invalid and was removed")
+#define CONTEXT_DB2DAVPOP PKG_NSF9+139
+ errortext(CONTEXT_DB2DAVPOP, "Error encountered in the DB2 Access View Populator.")
+#define CONTEXT_DB2NSF_UAV_CLEAR PKG_NSF9+140
+ errortext(CONTEXT_DB2NSF_UAV_CLEAR, "Error clearing UAVROOT from related NSFDB2 databases.")
+#define LOG_UNREAD_WRITE_ERROR PKG_NSF9+141
+ errortext(LOG_UNREAD_WRITE_ERROR, "Error writing unread log for database %p. User %a. Error: %e.")
+#define CONTEXT_DB2NSF_UAV_EXEMPT PKG_NSF9+142
+ errortext(CONTEXT_DB2NSF_UAV_EXEMPT, "Error flagging NSFDB2 database as exempt from the UAV.")
+#define ERR_DB2NSF_ACCESS_DELETE PKG_NSF9+143
+ errortext(ERR_DB2NSF_ACCESS_DELETE, "The exported NSFDB2 database access table entities could not be dropped.")
+#define ERR_INT_CONSTRAINT PKG_NSF9+144
+ errortext(ERR_INT_CONSTRAINT, "Error saving non integral value to a DB2 Access View INTEGER column.")
+#define ERR_BAD_DAV PKG_NSF9+145
+ errortext(ERR_BAD_DAV, "Invalid Access View definition.")
+#define ERR_NO_DAV_FORMS PKG_NSF9+146
+ errortext(ERR_NO_DAV_FORMS, "Access View definition must be associated with one or more forms on the infobox for the DB2 Access View.")
+#define CONTEXT_UPDATE_NSFID PKG_NSF9+147
+ errortext(CONTEXT_UPDATE_NSFID, "Error encountered modifying NSFID value for table after a conflict was detected updating system CATALOG table")
+#define ERR_NSF_DBCREATE_DDM PKG_NSF9+148
+ errortext(ERR_NSF_DBCREATE_DDM, "Database creation error: %s")
+#define ERR_NSF_DBDELETE_DDM PKG_NSF9+149
+ errortext(ERR_NSF_DBDELETE_DDM, "Database deletion error: %s")
+#define ERR_NSF_DBOPEN_DDM PKG_NSF9+150
+ errortext(ERR_NSF_DBOPEN_DDM, "Database open error: %s")
+#define ERR_NSF_NOTEOPEN_DDM PKG_NSF9+151
+ errortext(ERR_NSF_NOTEOPEN_DDM, "Database note open error: %s")
+#define ERR_NSF_NOTEUPDATE_DDM PKG_NSF9+152
+ errortext(ERR_NSF_NOTEUPDATE_DDM, "Database note update error: %s")
+#define ERR_NSF_DBFILEREAD_DDM PKG_NSF9+153
+ errortext(ERR_NSF_DBFILEREAD_DDM, "Database file read error: %s")
+#define ERR_NSF_DBFILEWRITE_DDM PKG_NSF9+154
+ errortext(ERR_NSF_DBFILEWRITE_DDM, "Database file write error: %s")
+#define ERR_NSF_DBCORRUPT_DDM PKG_NSF9+155
+ errortext(ERR_NSF_DBCORRUPT_DDM, "Database marked corrupt: %s")
+#define ERR_NSF_DBOBJREAD_DDM PKG_NSF9+156
+ errortext(ERR_NSF_DBOBJREAD_DDM, "Database object read error: %s")
+#define ERR_NSF_DBOBJWRITE_DDM PKG_NSF9+157
+ errortext(ERR_NSF_DBOBJWRITE_DDM, "Database object write error: %s")
+#define ERR_DB2_ADMIN_EN_SRV_RESTART PKG_NSF9+158
+ errortext(ERR_DB2_ADMIN_EN_SRV_RESTART, "The Domino server is being restarted.\n")
+#define ERR_DB2_ADMIN_EN_USER_SYSCTRL PKG_NSF9+159
+ stringtext(ERR_DB2_ADMIN_EN_USER_SYSCTRL, "- Could not add user, '%s' to DB2 SYSCTRL group, '%s'.\n You must manually add user to DB2 SYSCTRL group\nor add DB2DOM group to DB2 SYSCTRL group.\n")
+#define ERR_DB2_USER_MAPPING PKG_NSF9+160
+ errortext(ERR_DB2_USER_MAPPING, "Missing Domino to DB2 user mapping.")
+#define CONTEXT_DB2NSF_CLEAN_CONN PKG_NSF9+161
+ errortext(CONTEXT_DB2NSF_CLEAN_CONN, "Error encountered while cleaning up DB2 connection." )
+#define ERR_NOT_A_DB2NSF PKG_NSF9+162
+ errortext(ERR_NOT_A_DB2NSF, "This action only available with DB2NSF databases.")
+#define ERR_DAV_COL_NAME_LEN PKG_NSF9+163
+ errortext(ERR_DAV_COL_NAME_LEN, "Field name length exceeds maximum column name length (30 bytes), Fieldname: ")
+#define ERR_DAV_NOGEN PKG_NSF9+164
+ errortext(ERR_DAV_NOGEN, "Current DB2 table is compatible with the Access View definition. No changes needed to be made in DB2.")
+#define ERR_DAV_DUPCOL PKG_NSF9+165
+ errortext(ERR_DAV_DUPCOL, "Access View definition contains duplicate field names.")
+#define ERR_DAV_NEEDSPOP PKG_NSF9+166
+ errortext(ERR_DAV_NEEDSPOP, "Access Definition created successfully. You must populate the view before the view will be available in DB2.")
+#define ERR_DAV_LENGTH_REQD PKG_NSF9+167
+ errortext(ERR_DAV_LENGTH_REQD, "Text fields cannot have DB2 length of 0." )
+#define ERR_DAV_NODROP PKG_NSF9+168
+ errortext(ERR_DAV_NODROP, "This Access View definition is not active in DB2. No changes needed to be made in DB2.")
+#define CONTEXT_DB2ADMIN_CLP PKG_NSF9+169
+ errortext(CONTEXT_DB2ADMIN_CLP, "Failure processing admin SQL command line request")
+#define ERR_DB2_QV_NO_RESULT_SET PKG_NSF9+170
+ errortext(ERR_DB2_QV_NO_RESULT_SET, "The given query cannot generate a result set and therefore has not been executed.")
+#define ERR_DB2ADMIN_NO_UDF_INFO PKG_NSF9+171
+ errortext(ERR_DB2ADMIN_NO_UDF_INFO, "'DB2 ACCESS SET' failed. Please make sure that the DB2 Access information in the DB2 tab of the Server Document is up to date.")
+#define ERR_DB2_EN_DUP_DB PKG_NSF9+172
+ errortext(ERR_DB2_EN_DUP_DB, "The database, %s, exists in the DB2 context you are using. You must select another DB2 database name.")
+#define CONTEXT_DAV_ACTION PKG_NSF9+173
+ errortext(CONTEXT_DAV_ACTION, "DAV Action SQL error." )
+#define ERR_DAV_TOOBIG PKG_NSF9+174
+ errortext(ERR_DAV_TOOBIG, "DB2 Access View definition exceeds maximum supported length." )
+#define ERR_SERVER_NOT_UDFENABLED PKG_NSF9+175
+ errortext(ERR_SERVER_NOT_UDFENABLED, "Domino server is not DB2 Access View enabled." )
+#define ERR_NO_DAV_ANON_ACCESS PKG_NSF9+176
+ errortext(ERR_NO_DAV_ANON_ACCESS, "No matching Notes user found for DB2 user and anonymous access is disabled." )
+#define ERR_DB2_BACKLEVEL PKG_NSF9+177
+ errortext(ERR_DB2_BACKLEVEL, "WARNING: Domino minimum DB2 installation requirement not met. Upgrade your DB2 installation.")
+#define LOG_DB2NSF_POLL_TASK_PURGE PKG_NSF9+178
+ stringtext(LOG_DB2NSF_POLL_TASK_PURGE, "Domino is now purging the DB2 schema %s and table space %s")
+
+#define STR_UDF_SETUP_START PKG_NSF9+179
+ errortext(STR_UDF_SETUP_START, "Please wait while the server sets up the information for the DB2 Access DLL (%a)." )
+#define STR_UDF_SET_USER_DOC PKG_NSF9+180
+ errortext(STR_UDF_SET_USER_DOC, "Create user document for the DB2 Access DLL (%a)." )
+#define STR_UDF_SETUP_COMPLETE PKG_NSF9+181
+ errortext(STR_UDF_SETUP_COMPLETE, "DB2 Access DLL setup complete.\n" )
+#define ERR_DB2ADMIN_UDF_PROP PKG_NSF9+182
+ errortext(ERR_DB2ADMIN_UDF_PROP, "'DB2 ACCESS SET' failed while attempting to set the following property: \n%s")
+#define ERR_DB2ADMIN_UDF_DB2_NOT PKG_NSF9+183
+ errortext(ERR_DB2ADMIN_UDF_DB2_NOT, "This server does not have DB2 Access set up.")
+#define ERR_DB2ADMIN_UDF_INFO PKG_NSF9+184
+ errortext(ERR_DB2ADMIN_UDF_INFO, "'DB2 ACCESS SET' failed while attempting to execute the following command: \n%s")
+#define ERR_DB2ADMIN_UDF_NO_PATH PKG_NSF9+185
+ errortext(ERR_DB2ADMIN_UDF_NO_PATH, "'DB2 ACCESS SET' failed. 'DB2UDFPATH' could not be found in notes.ini")
+#define ERR_DB2ADMIN_UDF_NO_SERVER PKG_NSF9+186
+ errortext(ERR_DB2ADMIN_UDF_NO_SERVER, "'DB2 ACCESS SET' failed. 'DB2UDFSERVER' could not be found in notes.ini")
+
+#define ERR_RRM_NOTSET PKG_NSF9+187
+ errortext(ERR_RRM_NOTSET, "RRM Context not set for this database")
+#define ERR_RRM_ALREADYSET PKG_NSF9+188
+ errortext(ERR_RRM_ALREADYSET, "RRM Context already set for this database")
+#define NSFSTR_DB2CREATE_MESSAGE PKG_NSF9+189
+ stringtext(NSFSTR_DB2CREATE_MESSAGE, "Creating DB2 database '%s' in DB2 Instance '%s' with username '%s'...")
+#define NSFSTR_DB2CONNECT_MESSAGE PKG_NSF9+190
+ stringtext(NSFSTR_DB2CONNECT_MESSAGE, "Connecting to DB2 database '%s' in DB2 Instance '%s' with username '%s'...")
+#define ERR_SINGLEVAL_CONSTRAINT PKG_NSF9+191
+ errortext(ERR_SINGLEVAL_CONSTRAINT, "Cannot save a multi-value item to a DB2 Access View defined as 'single value only'.")
+#define CONTEXT_DB2NSF_USER_ACTIVITY_LOG PKG_NSF9+192
+ errortext(CONTEXT_DB2NSF_USER_ACTIVITY_LOG, "Error encountered in the DB2 User Activity Log.")
+#define CONTEXT_DB2NSF_DELETE_PROP PKG_NSF9+193
+ errortext(CONTEXT_DB2NSF_DELETE_PROP, "Failed when DB2 was deleting properties.")
+#define ERR_DAV_BAD_COLNAME PKG_NSF9+194
+ errortext(ERR_DAV_BAD_COLNAME, "Access View definition has an invalid name. The DB2 Access View name and the DB2 column names must begin with a letter.")
+#define ERR_DAV_NOFIELDS PKG_NSF9+195
+ errortext(ERR_DAV_NOFIELDS, "Access View Definition does not contain any fields.")
+#define NSFSTR_DB2_NO_USERNAME_PASSWORD PKG_NSF9+196
+ stringtext(NSFSTR_DB2_NO_USERNAME_PASSWORD,"WARNING: Could not retrieve DB2 username and password from the server ID file.")
+#define ERR_NO_POP_REQUEST PKG_NSF9+197
+ errortext(ERR_NO_POP_REQUEST, "DB2 Access View population is not currently required." )
+#define MSG_DAVPOP_SUCCESS PKG_NSF9+198
+ stringtext(MSG_DAVPOP_SUCCESS, "DB2 Access View population started successfully." )
+#define LOG_DAVPOP_INFO PKG_NSF9+199
+ stringtext(LOG_DAVPOP_INFO,"Failed populating Access Table - NoteID: %lu, Field Name: %s." )
+
+#define ERR_DB2_ADMIN_EN_ACCOUNT_RIGHTS_ERR3 PKG_NSF9+200
+ errortext(ERR_DB2_ADMIN_EN_ACCOUNT_RIGHTS_ERR3, "- You must create the user account to access DB2.\n You may have already done this. If so ignore this and continue.\n")
+
+#define ERR_DB2_ADMIN_EN_INVALID_INSTANCE PKG_NSF9+201
+ errortext(ERR_DB2_ADMIN_EN_INVALID_INSTANCE, "- DB2 enablement could not attach to the specified instance. You may have entered an invalid instance name or are setting up for remote and not entering the host information.\n")
+
+#define ERR_DB2ADMIN_UDF_NO_ACCESS PKG_NSF9+202
+ errortext(ERR_DB2ADMIN_UDF_NO_ACCESS, "'DB2 ACCESS SET' failed. DB2 Access could not access server %a. Server returned (%e).")
+#define ERR_DB2_NULL_LOAD_COMPUTED_COLUMN PKG_NSF9+203
+ errortext(ERR_DB2_NULL_LOAD_COMPUTED_COLUMN, "NULL CLI Load performed on table with computed column")
+#define CONTEXT_DB2_NULLLOAD PKG_NSF9+204
+ errortext(CONTEXT_DB2_NULLLOAD, "NULL CLI Load having problems bulk erasing table data")
+#define CONTEXT_DB2_RECLAIM_SPACE PKG_NSF9+205
+ errortext(CONTEXT_DB2_RECLAIM_SPACE, "Problems reclaiming space in a tablespace container")
+#define NSFSTR_DB2ATTACH_MESSAGE PKG_NSF9+206
+ stringtext(NSFSTR_DB2ATTACH_MESSAGE, "Attaching to DB2 Instance '%s' with username '%s'...")
+#define ERR_DAV_RECREATE_NEEDED PKG_NSF9+207
+ errortext(ERR_DAV_RECREATE_NEEDED, "DB2 Access View needs to be recreated before population." )
+
+#define STR_UDF_SETUP_TEST_OK PKG_NSF9+208
+ errortext(STR_UDF_SETUP_TEST_OK, "DB2 Access successfully connected to %a." )
+
+#define STR_UDF_SETUP_TEST_START PKG_NSF9+209
+ errortext(STR_UDF_SETUP_TEST_START, "DB2 Access testing connection and access to %a." )
+
+#define STR_UDF_SETUP_TEST_CONN_FAIL PKG_NSF9+210
+ errortext(STR_UDF_SETUP_TEST_CONN_FAIL, "DB2 Access connection failed with error -> (%e)" )
+
+#define STR_UDF_SETUP_CONN_NO_CONFIG PKG_NSF9+211
+ errortext(STR_UDF_SETUP_CONN_NO_CONFIG, "DB2 Access is not configured on this server." )
+
+#define STR_UDF_SETUP_ITEM_LIST PKG_NSF9+212
+ stringtext(STR_UDF_SETUP_ITEM_LIST, "server document|NOTES.INI" )
+
+#define STR_UDF_SETUP_MISSING_ITEM PKG_NSF9+213
+ errortext(STR_UDF_SETUP_MISSING_ITEM, "DB2 Access is missing item '%s' from %s." )
+
+#define STR_UDF_SETUP_FOUND_ITEM PKG_NSF9+214
+ errortext(STR_UDF_SETUP_FOUND_ITEM, "DB2 Access successfully found item '%s'('%s') in %s." )
+
+#define ERR_UDF_SETUP_CONFIG_ERROR PKG_NSF9+215
+ errortext(ERR_UDF_SETUP_CONFIG_ERROR, "DB2 Access configuration errors. Please check the notes.ini and server document." )
+
+#define DB2_ENABLE_TOOL_SRV_DB2_AND_UDF PKG_NSF9+216
+ errortext(DB2_ENABLE_TOOL_SRV_DB2_AND_UDF, "DB2 and DB2 Access are set up." )
+
+#define STR_UDF_SETUP_MISSING_PER_DOC PKG_NSF9+217
+ errortext(STR_UDF_SETUP_MISSING_PER_DOC, "DB2 Access is missing person document." )
+
+#define ERR_DAV_INVALID_READER_LIST PKG_NSF9+218
+ errortext(ERR_DAV_INVALID_READER_LIST, "The reader list is corrupt.")
+#define DB2_ENABLE_TOOL_SRV_DB2_NOT_UDF PKG_NSF9+219
+ errortext(DB2_ENABLE_TOOL_SRV_DB2_NOT_UDF, "This server has DB2 but DB2 Access not set up.")
+#define ERR_DAV_MAXFIELDS PKG_NSF9+220
+ errortext(ERR_DAV_MAXFIELDS, "The maximum number of DB2 Access fields has been exceeded.")
+/* 221 IS FREE! */
+
+#define CONTEXT_TABLE_QUERY PKG_NSF9+222
+ errortext(CONTEXT_TABLE_QUERY, "Failed to query tables for schema")
+#define ERR_DAV_INVALID_DELIMITER PKG_NSF9+223
+ errortext(ERR_DAV_INVALID_DELIMITER, "Invalid multivalue delimiter.")
+#define STR_UDF_DROPFAILURE PKG_NSF9+224
+ stringtext(STR_UDF_DROPFAILURE, "Unable to remove some DB2 Access entities for schema %s. These will need to be manually dropped. ")
+#define STR_UDF_TYPEKEY PKG_NSF9+225
+ stringtext(STR_UDF_TYPEKEY, "Types are: 1=Table, 2=View, 3=Trigger, 4=Function, 5=Index\nThe items to be dropped can be obtained with the following query:")
+#define ERR_MONITORS_CLIENT_EVENTS PKG_NSF9+226
+ errortext(ERR_MONITORS_CLIENT_EVENTS, "Monitor client has exceeded maximum number of events")
+#define ERR_ARCHIVE_PRUNE_FLAG_NOT_SET PKG_NSF9+231
+ errortext(ERR_ARCHIVE_PRUNE_FLAG_NOT_SET, "Archive doc link detected in a document that does not have the pruned or abstracted flag set. NoteID=%x.\n")
+#define ERR_DESK_ARCHIVE_PRN_DOCS (PKG_NSF9+232)
+ errortext(ERR_DESK_ARCHIVE_PRN_DOCS, "Some documents were not archived because they had already been pruned. See the archive log for additional details.")
+#define ERR_DESK_ARCHIVE_NUM_PRN_DOCS (PKG_NSF9+233)
+ errortext(ERR_DESK_ARCHIVE_NUM_PRN_DOCS, "%d documents were not archived because they had already been pruned.")
+#define CONTEXT_DB2LOAD_RESTORE_DEF PKG_NSF9+234
+ errortext(CONTEXT_DB2LOAD_RESTORE_DEF, "Failed when restoring access definition.")
+#define ERR_TASK_DB2DEFERRED_QCREATEFAIL PKG_NSF9+235
+ stringtext(ERR_TASK_DB2DEFERRED_QCREATEFAIL, "Failed to create the DB2 deferred processing message queue")
+#define ERR_TASK_DB2DEFERRED_DB2ERR PKG_NSF9+236
+ errortext(ERR_TASK_DB2DEFERRED_DB2ERR, "DB2 deferred processing thread delayed due to DB2 errors")
+#define STR_UDF_REMOVE_WARNING PKG_NSF9+237
+ errortext(STR_UDF_REMOVE_WARNING, "Warning: %d Domino Access Views could not be removed.\n" )
+
+#define STR_UDF_REMOVE_COMPLETE PKG_NSF9+238
+ errortext(STR_UDF_REMOVE_COMPLETE, "DB2 Access successfully removed from server.\n" )
+
+#define ERR_DB2NSF_SCHEMAUPGRADEBLOCKED PKG_NSF9+239
+ errortext(ERR_DB2NSF_SCHEMAUPGRADEBLOCKED, "Upgrade to schema version %d disabled, set DEBUG_DB2_ALLOW_SCHEMA_UPGRADE=%d in notes.ini to enable." )
+
+#define ERR_ARCHIVE_BEHALFOF_NOT_SET PKG_NSF9+240
+ errortext(ERR_ARCHIVE_BEHALFOF_NOT_SET, "Error opening archive settings because item $OnBehalfOf exists but is not set")
+#define ERR_ARC_REQ_SRC_ACCESS_BEHALF PKG_NSF9+241
+ errortext(ERR_ARC_REQ_SRC_ACCESS_BEHALF, "OnBehalfOf user does not have the required access rights to the source database.")
+#define ERR_ARC_REQ_ARC_ACCESS_BEHALF PKG_NSF9+242
+ errortext(ERR_ARC_REQ_ARC_ACCESS_BEHALF, "OnBehalfOf user does not have the required access rights to the archive database.")
+#define NSFSTR_DB2DROP_MESSAGE PKG_NSF9+243
+ stringtext(NSFSTR_DB2DROP_MESSAGE, "Dropping DB2 database '%s' in DB2 Instance '%s' with username '%s'...")
+#define ERR_DB2_INVALID_LIB_PATH PKG_NSF9+244
+ errortext(ERR_DB2_INVALID_LIB_PATH, "\nThe DB2 library path may be invalid. \nPlease make sure you have entered the correct path to the DB2 libraries." )
+
+#define DB2_ENABLE_TOOL_INVALID_OS PKG_NSF9+245
+ errortext(DB2_ENABLE_TOOL_INVALID_OS, "This server is not on a supported platform. Only servers on Windows or AIX platforms support update to DB2.")
+#define ERR_RM_XA_ERROR_NOCODE PKG_NSF9+246
+ errortext(ERR_RM_XA_ERROR_NOCODE, "An error occurred accessing the db2 datasource.")
+#define ERR_DB2_LOG_FULL PKG_NSF9+247
+ errortext(ERR_DB2_LOG_FULL, "DB2 log full. Make sure your DB2 'LOGFILSIZ', 'LOGPRIMARY' and 'LOGSECOND' are large enough.")
+#define ERR_TASK_DESC_SCR PKG_NSF9+248
+ errortext(ERR_TASK_DESC_SCR, "Cluster Replication Cleanup Thread")
+#define ERR_DAV_BAD_UNK PKG_NSF9+249
+ errortext(ERR_DAV_BAD_UNK, "Access View Definition references an unknown form : ")
+#define ERR_IMAP_CONV_UNREAD_ERR PKG_NSF9+250
+ errortext(ERR_IMAP_CONV_UNREAD_ERR, "Cannot migrate R5 IMAP Seen flags to Unread marks.")
+
+#define ERR_DB2_ACCESS_CONN_NET_ADDR PKG_NSF9+251
+ errortext(ERR_DB2_ACCESS_CONN_NET_ADDR, "The optional network address (%s) for the connection record may be invalid. Please check using the 'Edit DB2 Access Connection' tool in the Domino Administration clients.")
+
+#define ERR_ARC_PREVIEW_DOCS PKG_NSF9+252
+ errortext(ERR_ARC_PREVIEW_DOCS, "Unable to process documents for archive preview")
+
+#define CONTEXT_GROUP_MGMT PKG_NSF9+253
+ errortext(CONTEXT_GROUP_MGMT, "Error managing DB2 groups")
+
+#define ERR_DB2_GROUP_ENTRIES PKG_NSF9+254
+ errortext(ERR_DB2_GROUP_ENTRIES, "There are no DB2 based Domino databases on this server.")
+
+#define DB2_ENABLE_TOOL_SRV_NOT_DB2 PKG_NSF9+255
+ stringtext(DB2_ENABLE_TOOL_SRV_NOT_DB2, "This server is not DB2 enabled.")
+/* PKG_NSF9 codes limited to 0-255 */
+
+/* End of Error Codes */
+
+/* PKG_DB2_STR codes limited to 0-127. */
+/* STRINGS ONLY *** These can not be sued for error codes *** STRINGS ONLY */
+
+#define STR_DB2_GROUP_SETSTATE PKG_DB2_STR+0
+ stringtext(STR_DB2_GROUP_SETSTATE, "opened|locked|%s has been %s.|%s could not be %s.|Group %s does not exist.|Group %s is already %s.")
+
+#define STR_DB2_GROUP_SETCLASS PKG_DB2_STR+1
+ stringtext(STR_DB2_GROUP_SETCLASS, "The class for %s has been set to '%s'.|The class for %s could not be set to '%s'.|This group is already named %s.")
+
+#define STR_DB2_GROUP_RENCLASS PKG_DB2_STR+2
+ stringtext(STR_DB2_GROUP_RENCLASS, "The class '%s' has been renamed to '%s'.|The class '%s' could not be renamed to '%s'.|Class %s does not exist.|The old and new class names are identical.")
+
+#define STR_DB2_GROUP_MOVE PKG_DB2_STR+3
+ stringtext(STR_DB2_GROUP_MOVE, "Database %s is being moved to group %s.|Database %s is being moved to a new group.|Database %s could not be moved to group %s: %e |Please try again later. ")
+
+#define STR_DB2_GROUP_LOCKED PKG_DB2_STR+4
+ stringtext(STR_DB2_GROUP_LOCKED, "Open|Locked|Full")
+
+#define ADMIN_DB2_ENABLE_EFFECT_RESTART PKG_DB2_STR+5
+ stringtext(ADMIN_DB2_ENABLE_EFFECT_RESTART, "\nDB2 enablement will not take effect until the server has been restarted.\n")
+
+#define ADMIN_DB2_ENABLE_EFFECT_RESTART1 PKG_DB2_STR+6
+ stringtext(ADMIN_DB2_ENABLE_EFFECT_RESTART1, "You may now restart the Domino server.\n")
+
+#define ADMIN_DB2_ENABLE_EFFECT_RESTART2 PKG_DB2_STR+7
+ stringtext(ADMIN_DB2_ENABLE_EFFECT_RESTART2, "You must wait for all the appropriated DB2 information to be updated in the server document and then restart the Domino server.")
+
+#define STR_DB2_GROUP_MOVE2 PKG_DB2_STR+8
+ stringtext(STR_DB2_GROUP_MOVE2, "Group %s does not exist.|Database %s does not exist.|Database %s is already in group %s.|Group %s is locked.|Group %s is full.")
+
+#define DB2STR_XA_RBROLLBACK PKG_DB2_STR+9
+ stringtext(DB2STR_XA_RBROLLBACK, "Rollback caused by unspecified reason.")
+#define DB2STR_XA_RBCOMMFAIL PKG_DB2_STR+10
+ stringtext(DB2STR_XA_RBCOMMFAIL, "Rollback caused by communication failure.")
+#define DB2STR_XA_RBDEADLOCK PKG_DB2_STR+11
+ stringtext(DB2STR_XA_RBDEADLOCK, "Deadlock detected.")
+#define DB2STR_XA_RBINTEGRITY PKG_DB2_STR+12
+ stringtext(DB2STR_XA_RBINTEGRITY, "An integrity error was detected.")
+#define DB2STR_XA_RBOTHER PKG_DB2_STR+13
+ stringtext(DB2STR_XA_RBOTHER, "The RM rolled back for unspecified reason.")
+#define DB2STR_XA_RBPROTO PKG_DB2_STR+14
+ stringtext(DB2STR_XA_RBPROTO, "A protocol error occurred in the RM.")
+#define DB2STR_XA_RBTIMEOUT PKG_DB2_STR+15
+ stringtext(DB2STR_XA_RBTIMEOUT, "The transaction took too long.")
+#define DB2STR_XA_RBTRANSIENT PKG_DB2_STR+16
+ stringtext(DB2STR_XA_RBTRANSIENT, "Retry the transaction.")
+#define DB2STR_XA_NOMIGRATE PKG_DB2_STR+17
+ stringtext(DB2STR_XA_NOMIGRATE, "Resumed in wrong thread.")
+#define DB2STR_XA_HEURHAZ PKG_DB2_STR+18
+ stringtext(DB2STR_XA_HEURHAZ, "The transaction branch may have been heuristically completed.")
+#define DB2STR_XA_HEURCOM PKG_DB2_STR+19
+ stringtext(DB2STR_XA_HEURCOM, "The transaction branch has been heuristically committed.")
+#define DB2STR_XA_HEURRB PKG_DB2_STR+20
+ stringtext(DB2STR_XA_HEURRB, "The transaction branch has been heuristically rolled back.")
+#define DB2STR_XA_HEURMIX PKG_DB2_STR+21
+ stringtext(DB2STR_XA_HEURMIX, "The transaction branch has been heuristically committed & rolled back.")
+#define DB2STR_XA_RETRY PKG_DB2_STR+22
+ stringtext(DB2STR_XA_RETRY, "Routine returned with no effect & may be reissued.")
+#define DB2STR_XA_RDONLY PKG_DB2_STR+23
+ stringtext(DB2STR_XA_RDONLY, "The transaction branch was read-only and has been committed.")
+#define DB2STR_XAER_ASYNC PKG_DB2_STR+24
+ stringtext(DB2STR_XAER_ASYNC, "An asynchronous operation already outstanding.")
+#define DB2STR_XAER_RMERR PKG_DB2_STR+25
+ stringtext(DB2STR_XAER_RMERR, "A RM error occurred.")
+#define DB2STR_XAER_NOTA PKG_DB2_STR+26
+ stringtext(DB2STR_XAER_NOTA, "The specified XID is not valid.")
+#define DB2STR_XAER_INVAL PKG_DB2_STR+27
+ stringtext(DB2STR_XAER_INVAL, "Invalid arguments were given.")
+#define DB2STR_XAER_PROTO PKG_DB2_STR+28
+ stringtext(DB2STR_XAER_PROTO, "Routine invoked in improper context.")
+#define DB2STR_XAER_RMFAIL PKG_DB2_STR+29
+ stringtext(DB2STR_XAER_RMFAIL, "RM unavailable.")
+#define DB2STR_XAER_DUPID PKG_DB2_STR+30
+ stringtext(DB2STR_XAER_DUPID, "The XID already exists.")
+#define DB2STR_XAER_OUTSIDE PKG_DB2_STR+31
+ stringtext(DB2STR_XAER_OUTSIDE, "The RM doing work outside of global transaction.")
+#define DB2STR_CREATE_DB_SUCCESS PKG_DB2_STR+32
+ stringtext(DB2STR_CREATE_DB_SUCCESS,"DB2 database %s successfully created with codepage/territory (%s/%s).")
+#define DB2STR_CFG_SET_ERR PKG_DB2_STR+33
+ stringtext(DB2STR_CFG_SET_ERR, "DB2NSFInit Error setting configuration parms for DB2 database %s sqlcode=%d.")
+#define DB2STR_CREATE_DB_ERR PKG_DB2_STR+34
+ stringtext(DB2STR_CREATE_DB_ERR, "DB2NSFInit Error creating DB2 database %s sqlcode=%d.")
+#define DB2STR_CREATE_SRV_TBLS_ERR PKG_DB2_STR+35
+ stringtext(DB2STR_CREATE_SRV_TBLS_ERR, "DB2NSFInit Error creating server tables for server %s.")
+#define DB2STR_SESS_ALLOC_ERR PKG_DB2_STR+36
+ stringtext(DB2STR_SESS_ALLOC_ERR, "DB2NSFInit Error allocating DB2 session.")
+
+#define STR_DB2_GROUP_DEFAULT PKG_DB2_STR+37
+ stringtext(STR_DB2_GROUP_DEFAULT, "Default")
+
+#define STR_DB2_GROUP_INPUT_INVALID PKG_DB2_STR+38
+ stringtext(STR_DB2_GROUP_INPUT_INVALID, "The group you have requested does not exist.")
+
+#define STR_DB2_DEF_GROUP_MOVE PKG_DB2_STR+39
+ stringtext(STR_DB2_DEF_GROUP_MOVE, "DB2 group move request for %s submitted to server %a.|DB2 group move of %s request failed: %e|DB2 group move of %s completed.")
+
+#define STR_DB2_COMPACT_DEFER PKG_DB2_STR+40
+ stringtext(STR_DB2_COMPACT_DEFER, "Skipping NSFDB2 database %s. DB2 reorg will be performed on tables in schemas %s and %s after NSF processing")
+#define STR_DB2_TABLESPACE_REDUCE PKG_DB2_STR+41
+ stringtext(STR_DB2_TABLESPACE_REDUCE, "The DB2 tablespace %s is being reduced by %d pages.")
+#define STR_DB2_TABLE_REORG_ALL PKG_DB2_STR+42
+ stringtext(STR_DB2_TABLE_REORG_ALL ,"Performing DB2 table and index reorgs for all NSFDB2 databases")
+#define STR_DB2_TABLE_REORG_DIR PKG_DB2_STR+43
+ stringtext(STR_DB2_TABLE_REORG_DIR ,"Performing DB2 table and index reorgs for all NSFDB2 databases contained in %s")
+#define STR_DB2_TABLE_REORG_TABLE1 PKG_DB2_STR+44
+ stringtext(STR_DB2_TABLE_REORG_TABLE1 ,"Performing DB2 table and index reorgs for schemas %s and %s")
+#define STR_DB2_TABLE_REORG_TABLE2 PKG_DB2_STR+45
+ stringtext(STR_DB2_TABLE_REORG_TABLE2 ,"Continuing DB2 reorgs on tables in user schema %s, if applicable")
+
+#define STR_DB2_DEF_GROUP_MOVE_GRP PKG_DB2_STR+46
+ stringtext(STR_DB2_DEF_GROUP_MOVE_GRP, "DB2 group move request for %s to group %s submitted to server %a.|DB2 group move of %s to group %s request failed: %e|DB2 group move of %s to group %s completed.")
+#define STR_DB2_STATS_RESET PKG_DB2_STR+47
+ stringtext(STR_DB2_STATS_RESET, "DB2NSF statistics were set to zero.")
+#define STR_DB2_LOBLOCATOR_EXTRA_FETCH PKG_DB2_STR+48
+ stringtext(STR_DB2_LOBLOCATOR_EXTRA_FETCH, "Extra DB2SQLFetch to free LOB locators->0x%x=%e")
+#define STR_DB2NSF_DBCFG_WARNING PKG_DB2_STR+49
+ stringtext(STR_DB2NSF_DBCFG_WARNING,"Warning: Modifying DB2 database configuration parameters for optimization...")
+#define STR_DB2NSF_DBMCFG_WARNING PKG_DB2_STR+50
+ stringtext(STR_DB2NSF_DBMCFG_WARNING,"Warning: Modifying DB2 database manager configuration parameters for optimization...")
+#define STR_DB2_KEY_WARNING PKG_DB2_STR+51
+ stringtext(STR_DB2_KEY_WARNING,"Warning: DB2 will not be accessible by Domino until you copy the DB2 Key file, %s, to the Domino binaries directory.")
+#endif
+
+
+#if defined(OS400) && (__OS400_TGTVRM__ >= 510)
+#pragma datamodel(pop)
+#endif
+
diff --git a/protocols/LotusNotify/src/cnotesapi/include/nsfnote.h b/protocols/LotusNotify/src/cnotesapi/include/nsfnote.h
new file mode 100644
index 0000000000..e02443ccae
--- /dev/null
+++ b/protocols/LotusNotify/src/cnotesapi/include/nsfnote.h
@@ -0,0 +1,551 @@
+
+#if defined(OS400) && (__OS400_TGTVRM__ >= 510)
+#pragma datamodel(P128)
+#endif
+
+/*********************************************************************/
+/* */
+/* Licensed Materials - Property of IBM */
+/* */
+/* L-GHUS-5VMPGW, L-GHUS-5S3PEE */
+/* (C) Copyright IBM Corp. 1989, 2005 All Rights Reserved */
+/* */
+/* US Government Users Restricted Rights - Use, duplication or */
+/* disclosure restricted by GSA ADP Schedule Contract with */
+/* IBM Corp. */
+/* */
+/*********************************************************************/
+
+
+
+#ifndef NSF_NOTE_DEFS
+#define NSF_NOTE_DEFS
+
+
+#ifndef NULLKFHANDLE
+typedef void far * KFHANDLE;
+#define NULLKFHANDLE ((KFHANDLE)0)
+#endif
+
+#ifndef NSF_DEFS
+#include "nsfdata.h"
+#endif
+
+#ifndef POOL_DEFS
+#include "pool.h"
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* Note Storage File Note Definitions */
+
+/* Item Flags */
+
+#define ITEM_SIGN 0x0001 /* This field will be signed if requested */
+#define ITEM_SEAL 0x0002 /* This field will be encrypted if requested */
+#define ITEM_SUMMARY 0x0004 /* This field can be referenced in a formula */
+#define ITEM_READWRITERS 0x0020 /* This field identifies subset of users that have read/write access */
+#define ITEM_NAMES 0x0040 /* This field contains user/group names */
+#define ITEM_PLACEHOLDER 0x0100 /* Simply add this item to "item name table", but do not store */
+#define ITEM_PROTECTED 0x0200 /* This field cannot be modified except by "owner" */
+#define ITEM_READERS 0x0400 /* This field identifies subset of users that have read access */
+#define ITEM_UNCHANGED 0x1000 /* Item is same as on-disk */
+
+/* If the following is ORed in with a note class, the resultant note ID
+ may be passed into NSFNoteOpen and may be treated as though you first
+ did an NSFGetSpecialNoteID followed by an NSFNoteOpen, all in a single
+ transaction. */
+
+#define NOTE_ID_SPECIAL 0xFFFF0000L
+
+/* Note Classifications */
+/* If NOTE_CLASS_DEFAULT is ORed with another note class, it is in
+ essence specifying that this is the default item in this class. There
+ should only be one DEFAULT note of each class that is ever updated,
+ although nothing in the NSF machinery prevents the caller from adding
+ more than one. The file header contains a table of the note IDs of
+ the default notes (for efficient access to them). Whenever a note
+ is updated that has the default bit set, the reference in the file
+ header is updated to reflect that fact.
+ WARNING: NOTE_CLASS_DOCUMENT CANNOT have a "default". This is precluded
+ by code in NSFNoteOpen to make it fast for data notes.
+*/
+
+#define NOTE_CLASS_DOCUMENT 0x0001 /* document note */
+#define NOTE_CLASS_DATA NOTE_CLASS_DOCUMENT /* old name for document note */
+#define NOTE_CLASS_INFO 0x0002 /* notefile info (help-about) note */
+#define NOTE_CLASS_FORM 0x0004 /* form note */
+#define NOTE_CLASS_VIEW 0x0008 /* view note */
+#define NOTE_CLASS_ICON 0x0010 /* icon note */
+#define NOTE_CLASS_DESIGN 0x0020 /* design note collection */
+#define NOTE_CLASS_ACL 0x0040 /* acl note */
+#define NOTE_CLASS_HELP_INDEX 0x0080 /* Notes product help index note */
+#define NOTE_CLASS_HELP 0x0100 /* designer's help note */
+#define NOTE_CLASS_FILTER 0x0200 /* filter note */
+#define NOTE_CLASS_FIELD 0x0400 /* field note */
+#define NOTE_CLASS_REPLFORMULA 0x0800 /* replication formula */
+#define NOTE_CLASS_PRIVATE 0x1000 /* Private design note, use $PrivateDesign view to locate/classify */
+
+
+#define NOTE_CLASS_DEFAULT 0x8000 /* MODIFIER - default version of each */
+
+#define NOTE_CLASS_NOTIFYDELETION NOTE_CLASS_DEFAULT /* see SEARCH_NOTIFYDELETIONS */
+#define NOTE_CLASS_ALL 0x7fff /* all note types */
+#define NOTE_CLASS_ALLNONDATA 0x7ffe /* all non-data notes */
+#define NOTE_CLASS_NONE 0x0000 /* no notes */
+
+#define NC_MASK_DB2_VISIBLE 0x0FFF /* all classes up to NOTE_CLASS_REPLFORMULA*/
+
+
+
+/* Define symbol for those note classes that allow only one such in a file */
+
+#define NOTE_CLASS_SINGLE_INSTANCE ( \
+ NOTE_CLASS_DESIGN | \
+ NOTE_CLASS_ACL | \
+ NOTE_CLASS_INFO | \
+ NOTE_CLASS_ICON | \
+ NOTE_CLASS_HELP_INDEX | \
+ 0)
+
+/* Note flag definitions */
+
+#define NOTE_SIGNED 0x0001 /* signed */
+#define NOTE_ENCRYPTED 0x0002 /* encrypted */
+
+/* Open Flag Definitions. These flags are passed to NSFNoteOpen. */
+
+#define OPEN_SUMMARY 0x0001 /* open only summary info */
+#define OPEN_NOVERIFYDEFAULT 0x0002 /* don't bother verifying default bit */
+#define OPEN_EXPAND 0x0004 /* expand data while opening */
+#define OPEN_NOOBJECTS 0x0008 /* don't include any objects */
+#define OPEN_SHARE 0x0020 /* open in a "shared" memory mode */
+#define OPEN_CANONICAL 0x0040 /* Return ALL item values in canonical form */
+#define OPEN_MARK_READ 0x0100 /* Mark unread if unread list is currently associated */
+#define OPEN_ABSTRACT 0x0200 /* Only open an abstract of large documents */
+#define OPEN_RESPONSE_ID_TABLE 0x1000 /* Return response ID table */
+#define OPEN_WITH_FOLDERS 0x00020000 /* Include folder objects - default is not to */
+#define OPEN_RAW_RFC822_TEXT 0x01000000 /* If set, leave TYPE_RFC822_TEXT items in native
+ format. Otherwise, convert to TYPE_TEXT/TYPE_TIME. */
+#define OPEN_RAW_MIME_PART 0x02000000 /* If set, leave TYPE_MIME_PART items in native
+ format. Otherwise, convert to TYPE_COMPOSITE. */
+#define OPEN_RAW_MIME (OPEN_RAW_RFC822_TEXT | OPEN_RAW_MIME_PART)
+
+/* Update Flag Definitions. These flags are passed to NSFNoteUpdate and
+ NSFNoteDelete. See also NOTEID_xxx special definitions in nsfdata.h. */
+
+#define UPDATE_FORCE 0x0001 /* update even if ERR_CONFLICT */
+#define UPDATE_NAME_KEY_WARNING 0x0002 /* give error if new field name defined */
+#define UPDATE_NOCOMMIT 0x0004 /* do NOT do a database commit after update */
+#define UPDATE_NOREVISION 0x0100 /* do NOT maintain revision history */
+#define UPDATE_NOSTUB 0x0200 /* update body but leave no trace of note in file if deleted */
+#define UPDATE_INCREMENTAL 0x4000 /* Compute incremental note info */
+#define UPDATE_DELETED 0x8000 /* update body DELETED */
+
+#define UPDATE_DUPLICATES 0 /* Obsolete; but in SDK */
+
+/* Conflict Handler defines */
+#define CONFLICT_ACTION_MERGE 1
+#define CONFLICT_ACTION_HANDLED 2
+
+#define UPDATE_SHARE_SECOND 0x00200000L /* Split the second update of this note with the object store */
+#define UPDATE_SHARE_OBJECTS 0x00400000L /* Share objects only, not non-summary items, with the object store */
+#define NOTE_LOCK_STATUS 0x00000008 /* Return status of lock */
+#define NOTE_LOCK_HARD 0x00000010 /* Take out a hard note lock */
+#define NOTE_LOCK_PROVISIONAL 0x00000020 /* Take out a provisional hard note lock */
+/* Structure returned from NSFNoteDecrypt which can be used to decrypt
+ file attachment objects, which are not decrypted until necessary. */
+
+typedef struct
+ {
+ BYTE Byte1;
+ WORD Word1;
+ BYTE Text[16];
+ }
+ ENCRYPTION_KEY;
+
+
+/* Flags returned (beginning in V3) in the _NOTE_FLAGS */
+
+#define NOTE_FLAG_READONLY 0x0001 /* TRUE if document cannot be updated */
+#define NOTE_FLAG_ABSTRACTED 0x0002 /* missing some data */
+#define NOTE_FLAG_INCREMENTAL 0x0004 /* Incremental note (place holders) */
+#define NOTE_FLAG_LINKED 0x0020 /* Note contains linked items or linked objects */
+#define NOTE_FLAG_INCREMENTAL_FULL 0x0040 /* Incremental type note Fully opened (NO place holders)
+ This type of note is meant to retain the
+ Item sequence numbers */
+#define NOTE_FLAG_CANONICAL 0x4000 /* Note is (opened) in canonical form */
+
+/* Note structure member IDs for NSFNoteGet&SetInfo. */
+
+#define _NOTE_DB 0 /* IDs for NSFNoteGet&SetInfo */
+#define _NOTE_ID 1 /* (When adding new values, see the */
+#define _NOTE_OID 2 /* table in NTINFO.C */
+#define _NOTE_CLASS 3
+#define _NOTE_MODIFIED 4
+#define _NOTE_PRIVILEGES 5 /* For pre-V3 compatibility. Should use $Readers item */
+#define _NOTE_FLAGS 7
+#define _NOTE_ACCESSED 8
+#define _NOTE_PARENT_NOTEID 10 /* For response hierarchy */
+#define _NOTE_RESPONSE_COUNT 11 /* For response hierarchy */
+#define _NOTE_RESPONSES 12 /* For response hierarchy */
+#define _NOTE_ADDED_TO_FILE 13 /* For AddedToFile time */
+#define _NOTE_OBJSTORE_DB 14 /* DBHANDLE of object store used by linked items */
+
+
+/* EncryptFlags used in NSFNoteCopyAndEncrypt */
+
+#define ENCRYPT_WITH_USER_PUBLIC_KEY 0x0001
+#define ENCRYPT_SMIME_IF_MIME_PRESENT 0x0002
+#define ENCRYPT_SMIME_NO_SENDER 0x0004
+#define ENCRYPT_SMIME_TRUST_ALL_CERTS 0x0008
+
+#define SIGN_NOTES_IF_MIME_PRESENT 0x00000001
+
+/* DecryptFlags used in NSFNoteDecrypt */
+
+#define DECRYPT_ATTACHMENTS_IN_PLACE 0x0001
+
+/* Flags used for NSFNoteExtractFileExt */
+
+#define NTEXT_RESONLY 0x0001 /* If a Mac attachment, extract resource fork only. */
+#define NTEXT_FTYPE_MASK 0x0070 /* File type mask */
+#define NTEXT_FTYPE_FLAT 0x0000 /* Normal one fork file */
+#define NTEXT_FTYPE_MACBIN 0x0010 /* MacBinaryII file */
+#define NTEXT_RAWMIME 0x0080 /* Do not decode MIME content transfer encoding */
+#define NTEXT_IGNORE_HUFF2 0x0100 /* Ignore checksum mismatch and save data anyway */
+
+/* Possible return values from the callback routine specified in
+ NSFNoteComputeWithForm() */
+
+#define CWF_ABORT 1
+#define CWF_NEXT_FIELD 2
+#define CWF_RECHECK_FIELD 3
+
+/* Possible validation phases for NSFNoteComputeWithForm() */
+
+#define CWF_DV_FORMULA 1
+#define CWF_IT_FORMULA 2
+#define CWF_IV_FORMULA 3
+#define CWF_COMPUTED_FORMULA 4
+#define CWF_DATATYPE_CONVERSION 5
+#define CWF_COMPUTED_FORMULA_LOAD CWF_COMPUTED_FORMULA
+#define CWF_COMPUTED_FORMULA_SAVE 6
+
+/* Function pointer type for NSFNoteComputeWithForm() callback */
+
+typedef WORD (LNCALLBACKPTR CWF_ERROR_PROC) (const void far *pCDField,
+ WORD phase, STATUS error,
+ HANDLE ErrorText,
+ WORD wErrorTextSize,
+ void far *ctx);
+
+/* Options to NSFNoteComputeWithForm() */
+
+#define CWF_CONTINUE_ON_ERROR 0x0001 /* Ignore compute errors */
+
+
+/* function templates */
+
+STATUS LNPUBLIC NSFItemAppend (NOTEHANDLE hNote, WORD ItemFlags,
+ const char far *Name, WORD NameLength,
+ WORD DataType,
+ const void far *Value, DWORD ValueLength);
+STATUS LNPUBLIC NSFItemAppendByBLOCKID (NOTEHANDLE hNote, WORD ItemFlags,
+ const char far *Name, WORD NameLength,
+ BLOCKID bhValue, DWORD ValueLength,
+ BLOCKID far *retbhItem);
+
+
+STATUS LNPUBLIC NSFItemAppendObject (NOTEHANDLE hNote, WORD ItemFlags,
+ const char far *Name, WORD NameLength,
+ BLOCKID bhValue, DWORD ValueLength, BOOL fDealloc);
+
+STATUS LNPUBLIC NSFItemDelete (NOTEHANDLE hNote, const char far *Name, WORD NameLength);
+STATUS LNPUBLIC NSFItemDeleteByBLOCKID (NOTEHANDLE hNote, BLOCKID bhItem);
+
+STATUS LNPUBLIC NSFItemRealloc (BLOCKID bhItem, BLOCKID far *bhValue, DWORD ValueLength);
+
+STATUS LNPUBLIC NSFItemCopy (NOTEHANDLE hNote, BLOCKID bhItem);
+STATUS LNPUBLIC NSFItemInfo (NOTEHANDLE hNote,
+ const char far *Name, WORD NameLength,
+ BLOCKID far *retbhItem,
+ WORD far *retDataType,
+ BLOCKID far *retbhValue,
+ DWORD far *retValueLength);
+
+#define NSFItemIsPresent(hNote, Name, NameLength) \
+ ((BOOL) (NSFItemInfo(hNote, Name, NameLength, NULL, NULL, NULL, NULL) == NOERROR))
+
+STATUS LNPUBLIC NSFItemInfoNext (NOTEHANDLE hNote, BLOCKID NextItem,
+ const char far *Name, WORD NameLength,
+ BLOCKID far *retbhItem,
+ WORD far *retDataType,
+ BLOCKID far *retbhValue,
+ DWORD far *retValueLength);
+
+STATUS LNPUBLIC NSFItemInfoPrev (NOTEHANDLE hNote, BLOCKID CurrItem,
+ const char far *Name, WORD NameLength,
+ BLOCKID far *retbhItem,
+ WORD far *retDataType,
+ BLOCKID far *retbhValue,
+ DWORD far *retValueLength);
+
+void LNPUBLIC NSFItemQuery (NOTEHANDLE hNote, BLOCKID bhItem,
+ char far *retItemName, WORD ItemNameBufferLength,
+ WORD far *retItemNameLength,
+ WORD far *retItemFlags,
+ WORD far *retDataType,
+ BLOCKID far *retbhValue, DWORD far *retValueLength);
+
+void LNPUBLIC NSFItemQueryEx (NOTEHANDLE hNote, BLOCKID bhItem,
+ char *retItemName, WORD ItemNameBufferLength,
+ WORD *retItemNameLength,
+ WORD *retItemFlags,
+ WORD *retDataType,
+ BLOCKID *retbhValue, DWORD *retValueLength,
+ BYTE *retSeqByte, BYTE *retDupItemID);
+
+WORD LNPUBLIC NSFItemGetText (NOTEHANDLE hNote, const char far *ItemName, char far *retBuffer, WORD BufferLength);
+BOOL LNPUBLIC NSFItemGetTime (NOTEHANDLE hNote, const char far *ItemName, TIMEDATE far *retTime);
+BOOL LNPUBLIC NSFItemGetNumber (NOTEHANDLE hNote, const char far *ItemName, NUMBER far *retNumber);
+LONG LNPUBLIC NSFItemGetLong (NOTEHANDLE hNote, const char far *ItemName, LONG DefaultNumber);
+
+STATUS LNPUBLIC NSFItemSetText (NOTEHANDLE hNote, const char far *ItemName, const char far *Text, WORD TextLength);
+
+
+STATUS LNPUBLIC NSFItemSetTextSummary (NOTEHANDLE hNote, const char far *ItemName, const char far *Text, WORD TextLength, BOOL Summary);
+STATUS LNPUBLIC NSFItemSetTime (NOTEHANDLE hNote, const char far *ItemName, const TIMEDATE far *Time);
+STATUS LNPUBLIC NSFItemSetNumber (NOTEHANDLE hNote, const char far *ItemName, const NUMBER far *Number);
+
+WORD LNPUBLIC NSFItemGetTextListEntries (NOTEHANDLE hNote, const char far *ItemName);
+WORD LNPUBLIC NSFItemGetTextListEntry (NOTEHANDLE hNote, const char far *ItemName, WORD EntryPos, char far *retBuffer, WORD BufferLength);
+STATUS LNPUBLIC NSFItemCreateTextList (NOTEHANDLE hNote, const char far *ItemName, const char far *Text, WORD TextLength);
+STATUS LNPUBLIC NSFItemAppendTextList (NOTEHANDLE hNote, const char far *ItemName, const char far *Text, WORD TextLength, BOOL fAllowDuplicates);
+
+STATUS LNPUBLIC NSFItemGetModifiedTime(HANDLE hNote, const char *ItemName, WORD ItemNameLength, DWORD Flags, TIMEDATE *retTime);
+STATUS LNPUBLIC NSFItemGetModifiedTimeByBLOCKID (HANDLE hNote, BLOCKID bhItem, DWORD Flags, TIMEDATE *retTime);
+
+
+
+BOOL LNPUBLIC NSFItemTextEqual(NOTEHANDLE hNote, const char far *ItemName, const char far *Text, WORD TextLength, BOOL fCaseSensitive);
+BOOL LNPUBLIC NSFItemTimeCompare(NOTEHANDLE hNote, const char far *ItemName, const TIMEDATE far *Time, int far *retVal);
+BOOL LNPUBLIC NSFItemLongCompare(NOTEHANDLE hNote, const char far *ItemName, long Value, int far *retVal);
+
+WORD LNPUBLIC NSFItemConvertValueToText (WORD DataType, BLOCKID bhValue, DWORD ValueLength, char far *retBuffer, WORD BufferLength, char SepChar);
+WORD LNPUBLIC NSFItemConvertToText (NOTEHANDLE hNote, const char far *ItemName, char far *retBuffer, WORD BufferLength, char SepChar);
+
+BOOL LNPUBLIC NSFGetSummaryValue (const void far *SummaryBuffer, const char far *Name, char far *retValue, WORD ValueBufferLength);
+BOOL LNPUBLIC NSFLocateSummaryValue (const void far *SummaryBuffer, const char far *Name,
+ void far *retValuePointer,
+ WORD far *retValueLength,
+ WORD far *retDataType);
+typedef STATUS (LNCALLBACKPTR NSFITEMSCANPROC)(WORD Spare, WORD ItemFlags,
+ char far *Name, WORD NameLength,
+ void far *Value, DWORD ValueLength,
+ void far *RoutineParameter);
+STATUS LNPUBLIC NSFItemScan (NOTEHANDLE hNote,
+ NSFITEMSCANPROC ActionRoutine,
+ void far *RoutineParameter);
+void LNPUBLIC NSFNoteGetInfo (NOTEHANDLE hNote, WORD Type, void far *Value);
+void LNPUBLIC NSFNoteSetInfo (NOTEHANDLE hNote, WORD Type, void far *Value);
+STATUS LNPUBLIC NSFNoteContract (NOTEHANDLE hNote);
+STATUS LNPUBLIC NSFNoteClose (NOTEHANDLE hNote);
+STATUS LNPUBLIC NSFNoteCreate (DBHANDLE hDB, NOTEHANDLE far *rethNote);
+STATUS LNPUBLIC NSFNoteDelete (DBHANDLE hDB, NOTEID NoteID, WORD UpdateFlags);
+STATUS LNPUBLIC NSFNoteDeleteExtended(DBHANDLE hDB, NOTEID NoteID, DWORD UpdateFlags);
+STATUS LNPUBLIC NSFDbNoteLock (DBHANDLE hDB, NOTEID NoteID, DWORD Flags, char *pLockers, HANDLE *rethLockers, DWORD *retLength);
+STATUS LNPUBLIC NSFDbNoteUnlock (DBHANDLE hDB, NOTEID NoteID, DWORD Flags);
+STATUS LNPUBLIC NSFNoteOpenWithLock (DBHANDLE hDB, NOTEID NoteID, DWORD LockFlags, DWORD OpenFlags, char *pLockers, HANDLE *rethLockers, DWORD *retLength, NOTEHANDLE far *rethNote);
+STATUS LNPUBLIC NSFNoteOpen (DBHANDLE hDB, NOTEID NoteID, WORD OpenFlags, NOTEHANDLE far *rethNote);
+STATUS LNPUBLIC NSFNoteOpenExt(DBHANDLE hDB, NOTEID NoteID, DWORD flags, NOTEHANDLE *rethNote);
+STATUS LNPUBLIC NSFNoteHardDelete(DBHANDLE hDB, NOTEID NoteID, DWORD Reserved);
+STATUS LNPUBLIC NSFNoteOpenSoftDelete(DBHANDLE hDB, NOTEID NoteID, DWORD Reserved, NOTEHANDLE *rethNote);
+#define GETNOTES_PRESERVE_ORDER 0x00000001 /* Preserve order of notes in NoteID list */
+#define GETNOTES_SEND_OBJECTS 0x00000002 /* Send (copiable) objects along with note */
+#define GETNOTES_ORDER_BY_SIZE 0x00000004 /* Order returned notes by (approximate) ascending size */
+#define GETNOTES_CONTINUE_ON_ERROR 0x00000008 /* Continue to next on list if error encountered */
+#define GETNOTES_GET_FOLDER_ADDS 0x00000010 /* Enable folder-add callback function after the note-level callback */
+#define GETNOTES_APPLY_FOLDER_ADDS 0x00000020 /* Apply folder ops directly - don't bother using callback */
+#define GETNOTES_NO_STREAMING 0x00000040 /* Don't stream - used primarily for testing purposes */
+typedef STATUS (LNCALLBACKPTR NSFGETNOTESCALLBACK) (void *Param, DWORD TotalSizeLow, DWORD TotalSizeHigh);
+typedef STATUS (LNCALLBACKPTR NSFNOTEOPENCALLBACK) (void *Param, NOTEHANDLE hNote, DWORD NoteID, STATUS status);
+typedef STATUS (LNCALLBACKPTR NSFOBJECTALLOCCALLBACK) (void *Param, NOTEHANDLE hNote, NOTEID OldRRV, STATUS status, DWORD ObjectSize);
+typedef STATUS (LNCALLBACKPTR NSFOBJECTWRITECALLBACK) (void *Param, NOTEHANDLE hNote, NOTEID OldRRV, STATUS status, BYTE *Buffer, DWORD BufferSize);
+typedef STATUS (LNCALLBACKPTR NSFFOLDERADDCALLBACK) (void *Param, UNID *NoteUNID, HANDLE OpBlock, DWORD OpBlockSize);
+STATUS LNPUBLIC NSFDbGetNotes(DBHANDLE hDB, DWORD NumNotes, NOTEID *NoteID, DWORD *NoteOpenFlags, DWORD *SinceSeqNum,
+ DWORD ControlFlags, DBHANDLE hObjectDB, void *CallbackParam,
+ NSFGETNOTESCALLBACK GetNotesCallback,
+ NSFNOTEOPENCALLBACK NoteOpenCallback,
+ NSFOBJECTALLOCCALLBACK ObjectAllocCallback,
+ NSFOBJECTWRITECALLBACK ObjectWriteCallback,
+ TIMEDATE *FolderSinceTime,
+ NSFFOLDERADDCALLBACK FolderAddCallback);
+STATUS LNPUBLIC NSFNoteOpenByUNID(DBHANDLE hDB, UNID far *pUNID, WORD flags, NOTEHANDLE far *rethNote);
+STATUS LNPUBLIC NSFNoteUpdate (NOTEHANDLE hNote, WORD UpdateFlags);
+STATUS LNPUBLIC NSFNoteUpdateExtended (NOTEHANDLE hNote, DWORD UpdateFlags);
+STATUS LNPUBLIC NSFNoteComputeWithForm (NOTEHANDLE hNote, NOTEHANDLE hFormNote,
+ DWORD dwFlags, CWF_ERROR_PROC ErrorRoutine,
+ void far *CallersContext);
+
+STATUS LNPUBLIC NSFNoteAttachFile (NOTEHANDLE hNOTE,
+ const char far *ItemName, WORD ItemNameLength,
+ const char far *PathName,
+ const char far *OriginalPathName,
+ WORD Encoding);
+STATUS LNPUBLIC NSFNoteExtractFile (NOTEHANDLE hNote, BLOCKID bhItem,
+ const char far *FileName,
+ ENCRYPTION_KEY far *DecryptionKey);
+STATUS LNPUBLIC NSFNoteExtractFileExt (NOTEHANDLE hNote, BLOCKID bhItem,
+ const char far *FileName,
+ ENCRYPTION_KEY far *DecryptionKey,
+ WORD wFlags);
+typedef STATUS (LNCALLBACKPTR NOTEEXTRACTCALLBACK)(const BYTE *bytes, DWORD length, void far *pParam);
+STATUS LNPUBLIC NSFNoteExtractWithCallback(NOTEHANDLE hNote, BLOCKID bhItem, ENCRYPTION_KEY far *DecryptionKey,
+ WORD wFlags, NOTEEXTRACTCALLBACK pNoteExtractCallback,
+ void far *pParam);
+
+STATUS LNPUBLIC NSFNoteDetachFile (NOTEHANDLE hNote, BLOCKID bhItem);
+BOOL LNPUBLIC NSFNoteHasObjects (NOTEHANDLE hNote, BLOCKID far *bhFirstObjectItem);
+STATUS LNPUBLIC NSFNoteGetAuthor (NOTEHANDLE hNote, char far *retName, WORD far *retNameLength,
+ BOOL far *retIsItMe);
+STATUS LNPUBLIC NSFNoteCopy (NOTEHANDLE hSrcNote, NOTEHANDLE far *rethDstNote);
+STATUS LNPUBLIC NSFNoteSignExt(NOTEHANDLE hNote,
+ const char far *SignatureItemName,
+ WORD ItemCount, HANDLE hItemIDs);
+STATUS LNPUBLIC NSFNoteSign (NOTEHANDLE hNote);
+STATUS LNPUBLIC NSFComputeObjectDigest(HANDLE hNote, BLOCKID bItem);
+STATUS LNPUBLIC NSFNoteSignExt3(NOTEHANDLE hNote,
+ KFHANDLE hKFC,
+ const char far *SignatureItemName,
+ WORD ItemCount, HANDLE hItemIDs,
+ DWORD Flags, DWORD Reserved,
+ void *pReserved);
+STATUS LNPUBLIC NSFNoteInspectSignatureExt2 (NOTEHANDLE hNote,
+ KFHANDLE hKFC,
+ char far *pzSigItemName,
+ TIMEDATE far *retWhenSigned,
+ char far *retSigner, char far *retCertifier,
+ WORD *retItemCount,
+ HANDLE *rethItemIDs,
+ DWORD Reserved,
+ void *pReserved);
+
+STATUS LNPUBLIC NSFHotSpotSign(BYTE *pSource, DWORD dwSourceLength, BYTE *pObject, DWORD dwObjectLength, HANDLE *hSigData, DWORD *dwSigLength);
+STATUS LNPUBLIC NSFNoteSignHotspots(NOTEHANDLE hNote, DWORD dwFlags, BOOL *retfSigned);
+STATUS LNPUBLIC NSFNoteVerifySignature (NOTEHANDLE hNote,
+ char far *Reserved,
+ TIMEDATE far *retWhenSigned,
+ char far *retSigner, char far *retCertifier);
+STATUS LNPUBLIC NSFVerifyFileObjSignature (DBHANDLE hDB, BLOCKID bhItem);
+STATUS LNPUBLIC NSFNoteUnsign (NOTEHANDLE hNote);
+STATUS LNPUBLIC NSFNoteCopyAndEncrypt (NOTEHANDLE hSrcNote, WORD EncryptFlags, NOTEHANDLE far *rethDstNote);
+STATUS LNPUBLIC NSFNoteCopyAndEncryptExt2 (NOTEHANDLE hSrcNote, KFHANDLE hKFC, WORD EncryptFlags, NOTEHANDLE far *rethDstNote, DWORD Reserved, void *pReserved);
+STATUS LNPUBLIC NSFNoteDecrypt (NOTEHANDLE hNote, WORD DecryptFlags, ENCRYPTION_KEY far *retKeyForAttachments);
+STATUS LNPUBLIC NSFNoteDecryptExt2 (NOTEHANDLE hNote, KFHANDLE hKFC, WORD DecryptFlags, ENCRYPTION_KEY far *retKeyForAttachments, DWORD Reserved, void *pReserved);
+
+/* Profile note routines. */
+
+STATUS LNPUBLIC NSFProfileOpen(
+ DBHANDLE hDB, const char *ProfileName, WORD ProfileNameLength,
+ const char *UserName, WORD UserNameLength, BOOL CopyProfile,
+ NOTEHANDLE *rethProfileNote);
+STATUS LNPUBLIC NSFProfileDelete(
+ DBHANDLE hDB, const char *ProfileName, WORD ProfileNameLength,
+ const char *UserName, WORD UserNameLength);
+STATUS LNPUBLIC NSFProfileUpdate(
+ NOTEHANDLE hProfile,
+ const char *ProfileName, WORD ProfileNameLength,
+ const char *UserName, WORD UserNameLength);
+typedef STATUS (LNCALLBACKPTR NSFPROFILEENUMPROC)(
+ DBHANDLE hDB,
+ void far *Ctx,
+ char *ProfileName,
+ WORD ProfileNameLength,
+ char *UserName,
+ WORD UserNameLength,
+ NOTEID ProfileNoteID);
+STATUS LNPUBLIC NSFProfileEnum(
+ DBHANDLE hDB, const char *ProfileName, WORD ProfileNameLength,
+ NSFPROFILEENUMPROC Callback,
+ void *CallbackCtx, DWORD Flags);
+STATUS LNPUBLIC NSFProfileGetField(
+ DBHANDLE hDB, const char *ProfileName, WORD ProfileNameLength,
+ const char *UserName, WORD UserNameLength,
+ const char *FieldName, WORD FieldNameLength,
+ WORD *retDatatype, BLOCKID *retbhValue, DWORD *retValueLength);
+STATUS LNPUBLIC NSFProfileSetField(
+ DBHANDLE hDB, const char *ProfileName, WORD ProfileNameLength,
+ const char *UserName, WORD UserNameLength,
+ const char *FieldName, WORD FieldNameLength,
+ WORD Datatype, void *Value, DWORD ValueLength);
+
+
+BOOL LNPUBLIC NSFNoteIsSignedOrSealed (NOTEHANDLE hNote, BOOL far *retfSigned, BOOL far *retfSealed);
+STATUS LNPUBLIC NSFNoteCheck (HANDLE hNote);
+
+STATUS LNPUBLIC NSFNoteFindDivergenceTime(NOTEHANDLE hNote1, NOTEHANDLE hNote2, DWORD dwFlags, TIMEDATE *tdLastSyncTime);
+STATUS LNPUBLIC NSFNoteFindMatchingItem (NOTEHANDLE hNote1, BLOCKID bhItem1, NOTEHANDLE hNote2, DWORD dwFlags, BLOCKID *retbhItem2);
+
+
+/* External (text) link routines */
+
+#define LINKFLAG_ADD_TEMPORARY 0x00000002L
+#define LINKFLAG_NO_REPL_SEARCH 0x00000004L
+
+STATUS LNPUBLIC NSFNoteLinkFromText(HANDLE hLinkText, WORD LinkTextLength,
+ NOTELINK far *NoteLink,
+ char far *ServerHint,
+ char far *LinkText, WORD MaxLinkText,
+ DWORD far *retFlags);
+STATUS LNPUBLIC NSFNoteLinkToText(char far *Title,
+ NOTELINK far *NoteLink,
+ char far *ServerHint,
+ char far *LinkText,
+ HANDLE far *phLinkText,
+ WORD far *pLinkTextLength,
+ DWORD Flags);
+
+/* End of Note Storage File Note Definitions */
+
+STATUS LNPUBLIC NSFNoteLSCompile ( DBHANDLE hDB,
+ NOTEHANDLE hNote,
+ DWORD dwFlags );
+
+/* Extended version with callback for compile errors. Note that the callback
+ function only gets called for the first error in each LotusScript module.
+ There may be more than one module in a note. */
+
+typedef struct
+{
+ WORD Version; /* allows for future expansion - currently always 1 */
+ WORD Line; /* source line number of error, relative to LotusScript
+ module containing the error, if applicable */
+ const char* pErrText; /* error text */
+ const char* pErrFile; /* file name, if applicable */
+} LSCOMPILE_ERR_INFO;
+
+typedef STATUS (LNCALLBACKPTR LSCOMPILEERRPROC)(
+ const LSCOMPILE_ERR_INFO* pInfo, /* error info - see above */
+ void* pCtx); /* caller's pCtx argument from NSFNoteLSCompileExt */
+
+STATUS LNPUBLIC NSFNoteLSCompileExt ( DBHANDLE hDB,
+ NOTEHANDLE hNote,
+ DWORD dwFlags,
+ LSCOMPILEERRPROC pfnErrProc, /* callback function for compile errors */
+ void* pCtx ); /* caller's context argument, passed to callback */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
+
+
+
+#if defined(OS400) && (__OS400_TGTVRM__ >= 510)
+#pragma datamodel(pop)
+#endif
+
diff --git a/protocols/LotusNotify/src/cnotesapi/include/nsfsearc.h b/protocols/LotusNotify/src/cnotesapi/include/nsfsearc.h
new file mode 100644
index 0000000000..18eb363d03
--- /dev/null
+++ b/protocols/LotusNotify/src/cnotesapi/include/nsfsearc.h
@@ -0,0 +1,181 @@
+
+#if defined(OS400) && (__OS400_TGTVRM__ >= 510)
+#pragma datamodel(P128)
+#endif
+
+/*********************************************************************/
+/* */
+/* Licensed Materials - Property of IBM */
+/* */
+/* L-GHUS-5VMPGW, L-GHUS-5S3PEE */
+/* (C) Copyright IBM Corp. 1989, 2005 All Rights Reserved */
+/* */
+/* US Government Users Restricted Rights - Use, duplication or */
+/* disclosure restricted by GSA ADP Schedule Contract with */
+/* IBM Corp. */
+/* */
+/*********************************************************************/
+
+
+
+/* Note Storage File Search Package Definitions */
+
+#ifndef NSF_SEARCH_DEFS
+#define NSF_SEARCH_DEFS
+
+#ifndef NSF_DEFS
+#include "nsfdata.h"
+#endif
+
+#ifndef MISC_DEFS
+#include "misc.h"
+#endif
+
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+/* Search Flag Definitions */
+
+#define SEARCH_ALL_VERSIONS 0x0001 /* Include deleted and non-matching notes in search */
+ /* (ALWAYS "ON" in partial searches!) */
+#define SEARCH_SUMMARY 0x0002 /* TRUE to return summary buffer with each match */
+#define SEARCH_FILETYPE 0x0004 /* For directory mode file type filtering */
+ /* If set, "NoteClassMask" is treated */
+ /* as a FILE_xxx mask for directory filtering */
+#define SEARCH_NOTIFYDELETIONS 0x0010 /* Set NOTE_CLASS_NOTIFYDELETION bit of NoteClass for deleted notes */
+#define SEARCH_ALLPRIVS 0x0040 /* return error if we don't have full privileges */
+#define SEARCH_SESSION_USERNAME 0x0400 /* Use current session's user name, not server's */
+#define SEARCH_NOABSTRACTS 0x1000 /* Filter out "Truncated" documents */
+#define SEARCH_DATAONLY_FORMULA 0x4000 /* Search formula applies only to
+ data notes, i.e., others match */
+
+/* This descriptor is embedded in the search queue entry. Note: The
+ information returned in the "summary" field is always returned in
+ machine-independent canonical form.
+
+ Note: In DIRECTORY searches, the following information is returned
+ in the SEARCH_MATCH structure (build 86 & later only):
+
+ OriginatorID.File NSF modified time (later of data & non-data modified time)
+ OriginatorID.Note 0 (unused)
+ OriginatorID.SequenceTime NSF's Replica ID (Used by NSFMakeReplicaFormula)
+ ID.Note NSF's Replica ID
+ ID.File NSF's DBID
+*/
+
+/* SERetFlags values (bit-field) */
+
+#define SE_FNOMATCH 0x00 /* does not match formula (deleted or updated) */
+#define SE_FMATCH 0x01 /* matches formula */
+#define SE_FTRUNCATED 0x02 /* document truncated */
+#define SE_FPURGED 0x04 /* note has been purged. Returned only when SEARCH_INCLUDE_PURGED is used */
+#define SE_FNOPURGE 0x08 /* note has no purge status. Returned only when SEARCH_FULL_DATACUTOFF is used */
+#define SE_FSOFTDELETED 0x10 /* if SEARCH_NOTIFYDELETIONS: note is soft deleted; NoteClass&NOTE_CLASS_NOTIFYDELETION also on (off for hard delete) */
+
+/* If recompiling a V3 API application and you used the MatchesFormula field
+ the following code change should be made:
+
+ For V3:
+
+ 1) if (SearchMatch.MatchesFormula == SE_FMATCH)
+ 2) if (SearchMatch.MatchesFormula == SE_FNOMATCH)
+ 3) if (SearchMatch.MatchesFormula != SE_FMATCH) is equivalent to 2)
+ 4) if (SearchMatch.MatchesFormula != SE_FNOMATCH) is equivalent to 1)
+
+ For V4
+
+ 1) if (SearchMatch.SERetFlags & SE_FMATCH)
+ 2) if (!(SearchMatch.SERetFlags & SE_FMATCH))
+*/
+
+typedef struct {
+ GLOBALINSTANCEID ID; /* identity of the note within the file */
+ ORIGINATORID OriginatorID; /* identity of the note in the universe */
+ WORD NoteClass; /* class of the note */
+ BYTE SERetFlags; /* MUST check for SE_FMATCH! */
+ BYTE Privileges; /* note privileges */
+ WORD SummaryLength; /* length of the summary information */
+ /* 54 bytes to here */
+ /* now comes an ITEM_TABLE with Summary Info */
+} SEARCH_MATCH;
+
+
+/* function templates */
+
+
+typedef STATUS (LNCALLBACKPTR NSFSEARCHPROC)
+ (void far *EnumRoutineParameter,
+ SEARCH_MATCH far *SearchMatch,
+ ITEM_TABLE far *SummaryBuffer);
+
+STATUS LNPUBLIC NSFSearch (DBHANDLE hDB,
+ FORMULAHANDLE hFormula,
+ char far *ViewTitle,
+ WORD SearchFlags,
+ WORD NoteClassMask,
+ TIMEDATE far *Since,
+ NSFSEARCHPROC EnumRoutine,
+ void far *EnumRoutineParameter,
+ TIMEDATE far *retUntil);
+STATUS LNPUBLIC NSFSearchWithUserNameList (DBHANDLE hDB,
+ FORMULAHANDLE hFormula,
+ char far *ViewTitle,
+ WORD SearchFlags,
+ WORD NoteClassMask,
+ TIMEDATE far *Since,
+ NSFSEARCHPROC EnumRoutine,
+ void far *EnumRoutineParameter,
+ TIMEDATE far *retUntil,
+ HANDLE nameList);
+
+
+/* Formula compilation functions */
+
+STATUS LNPUBLIC NSFFormulaCompile (char far *FormulaName, WORD FormulaNameLength,
+ const char far *FormulaText, WORD FormulaTextLength,
+ FORMULAHANDLE far *rethFormula,
+ WORD far *retFormulaLength,
+ STATUS far *retCompileError,
+ WORD far *retCompileErrorLine,
+ WORD far *retCompileErrorColumn,
+ WORD far *retCompileErrorOffset,
+ WORD far *retCompileErrorLength);
+STATUS LNPUBLIC NSFFormulaDecompile(char far *pFormulaBuffer,
+ BOOL fSelectionFormula,
+ HANDLE far *rethFormulaText,
+ WORD far *retFormulaTextLength);
+STATUS LNPUBLIC NSFFormulaMerge(FORMULAHANDLE hSrcFormula, FORMULAHANDLE hDestFormula);
+STATUS LNPUBLIC NSFFormulaSummaryItem(FORMULAHANDLE hFormula, const char far *ItemName, WORD ItemNameLength);
+STATUS LNPUBLIC NSFFormulaGetSize(FORMULAHANDLE hFormula, WORD far *retFormulaLength);
+
+/* Formula computation (evaluation) functions */
+
+STATUS LNPUBLIC NSFComputeStart(WORD Flags,
+ void far *pCompiledFormula,
+ HCOMPUTE far *rethCompute);
+
+STATUS LNPUBLIC NSFComputeStop(HCOMPUTE hCompute);
+STATUS LNPUBLIC NSFComputeEvaluate(HCOMPUTE hCompute,
+ NOTEHANDLE hNote,
+ HANDLE far *rethResult,
+ WORD far *retResultLength,
+ BOOL far *retNoteMatchesFormula,
+ BOOL far *retNoteShouldBeDeleted,
+ BOOL far *retNoteModified);
+
+/* End of Note Storage File Search Package Definitions */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
+
+
+#if defined(OS400) && (__OS400_TGTVRM__ >= 510)
+#pragma datamodel(pop)
+#endif
+
diff --git a/protocols/LotusNotify/src/cnotesapi/include/nsfstr.h b/protocols/LotusNotify/src/cnotesapi/include/nsfstr.h
new file mode 100644
index 0000000000..5f6c666a57
--- /dev/null
+++ b/protocols/LotusNotify/src/cnotesapi/include/nsfstr.h
@@ -0,0 +1,257 @@
+
+#if defined(OS400) && (__OS400_TGTVRM__ >= 510)
+#pragma datamodel(P128)
+#endif
+
+/*********************************************************************/
+/* */
+/* Licensed Materials - Property of IBM */
+/* */
+/* L-GHUS-5VMPGW, L-GHUS-5S3PEE */
+/* (C) Copyright IBM Corp. 2005 All Rights Reserved */
+/* */
+/* US Government Users Restricted Rights - Use, duplication or */
+/* disclosure restricted by GSA ADP Schedule Contract with */
+/* IBM Corp. */
+/* */
+/*********************************************************************/
+
+
+#ifndef NSF_STR_DEFS
+#define NSF_STR_DEFS
+
+#ifndef NSF_ERR_DEFS
+#include "nsferr.h"
+#endif
+
+/* errorContext strings for error logging 0 - 255 */
+#define CONTEXT_DB2NSF_INIT PKG_NSF_STR+1
+ stringtext(CONTEXT_DB2NSF_INIT, "Failed during DB2NSF initialization.")
+#define CONTEXT_DB2DROPDB2 PKG_NSF_STR+3
+ stringtext(CONTEXT_DB2DROPDB2, "Failed dropping DB2 Database.")
+#define CONTEXT_DB2CREATE_SERV_TAB PKG_NSF_STR+4
+ stringtext(CONTEXT_DB2CREATE_SERV_TAB, "Failed creating DB2 server table.")
+#define CONTEXT_DB2DROP_SERV_TAB PKG_NSF_STR+5
+ stringtext(CONTEXT_DB2DROP_SERV_TAB, "Failed dropping DB2 server table.")
+#define CONTEXT_DB2CREATE_FILE_TAB PKG_NSF_STR+6
+ stringtext(CONTEXT_DB2CREATE_FILE_TAB, "Failed creating DB2 file table.")
+#define CONTEXT_DB2DROP_FILE_TAB PKG_NSF_STR+7
+ stringtext(CONTEXT_DB2DROP_FILE_TAB, "Failed dropping DB2 file table.")
+#define CONTEXT_DB2WRITE_OBJ_HEADER PKG_NSF_STR+8
+ stringtext(CONTEXT_DB2WRITE_OBJ_HEADER, "Failed writing DB2 object header.")
+#define CONTEXT_DB2READ_OBJ_HEADER PKG_NSF_STR+9
+ stringtext(CONTEXT_DB2READ_OBJ_HEADER, "Failed reading DB2 object header.")
+#define CONTEXT_DB2MODIFY_OBJ_HEADER PKG_NSF_STR+10
+ stringtext(CONTEXT_DB2MODIFY_OBJ_HEADER, "Failed modifying DB2 object header.")
+#define CONTEXT_DB2WRITE_OBJ PKG_NSF_STR+11
+ stringtext(CONTEXT_DB2WRITE_OBJ, "Failed writing DB2 object.")
+#define CONTEXT_DB2CLEAR_OBJ PKG_NSF_STR+12
+ stringtext(CONTEXT_DB2CLEAR_OBJ, "Failed clearing DB2 object.")
+#define CONTEXT_DB2READ_OBJ PKG_NSF_STR+13
+ stringtext(CONTEXT_DB2READ_OBJ, "Failed reading DB2 object.")
+#define CONTEXT_DB2DELETE_OBJ PKG_NSF_STR+14
+ stringtext(CONTEXT_DB2DELETE_OBJ, "Failed deleting DB2 object.")
+#define CONTEXT_DB2MODIFY_RRV PKG_NSF_STR+15
+ stringtext(CONTEXT_DB2MODIFY_RRV, "Failed modifying the RRV (record relocation vector).")
+#define CONTEXT_DB2WRITE_OBJ_INFO PKG_NSF_STR+16
+ stringtext(CONTEXT_DB2WRITE_OBJ_INFO, "Failed writing DB2 object info.")
+#define CONTEXT_DB2I_U_NOBJ PKG_NSF_STR+17
+ stringtext(CONTEXT_DB2I_U_NOBJ, "Failed inserting or updating DB2 named object.")
+#define CONTEXT_DB2DEL_NOBJ PKG_NSF_STR+18
+ stringtext(CONTEXT_DB2DEL_NOBJ, "Failed deleting DB2 named object.")
+#define CONTEXT_DB2READ_NOBJ PKG_NSF_STR+19
+ stringtext(CONTEXT_DB2READ_NOBJ, "Failed reading DB2 named object.")
+#define CONTEXT_DB2ENUM_NOBJ PKG_NSF_STR+20
+ stringtext(CONTEXT_DB2ENUM_NOBJ, "Failed enumerating DB2 named object.")
+#define CONTEXT_DB2RECOVER_FHEADER PKG_NSF_STR+21
+ stringtext(CONTEXT_DB2RECOVER_FHEADER, "Failed when DB2 was recovering the file header.")
+#define CONTEXT_DB2WRITE_FILE_HEADER PKG_NSF_STR+22
+ stringtext(CONTEXT_DB2WRITE_FILE_HEADER, "Failed writing DB2 file header.")
+#define CONTEXT_DB2CREATE_FILE_HEADER PKG_NSF_STR+23
+ stringtext(CONTEXT_DB2CREATE_FILE_HEADER, "Failed creating DB2 file header.")
+#define CONTEXT_DB2DELETE_CATALOG_ENT PKG_NSF_STR+24
+ stringtext(CONTEXT_DB2DELETE_CATALOG_ENT, "Failed deleting DB2 catalog entry.")
+#define CONTEXT_DB2READ_UNK PKG_NSF_STR+25
+ stringtext(CONTEXT_DB2READ_UNK, "Failed when DB2 was reading UNK table.")
+#define CONTEXT_DB2WRITE_UNK PKG_NSF_STR+26
+ stringtext(CONTEXT_DB2WRITE_UNK, "Failed when DB2 was writing UNK table.")
+#define CONTEXT_DB2REFRESH_DIR PKG_NSF_STR+27
+ stringtext(CONTEXT_DB2REFRESH_DIR, "Failed when DB2 was refreshing directory.")
+#define CONTEXT_DB2CONNPOOL_INIT PKG_NSF_STR+28
+ stringtext(CONTEXT_DB2CONNPOOL_INIT, "Failed when DB2 was initializing the connection pool.")
+#define CONTEXT_DB2CP_CREATE_ENT PKG_NSF_STR+29
+ stringtext(CONTEXT_DB2CP_CREATE_ENT, "Failed when DB2 was creating an entry in the connection pool.")
+#define CONTEXT_DB2CP_FREE_ENT PKG_NSF_STR+30
+ stringtext(CONTEXT_DB2CP_FREE_ENT, "Failed when DB2 was freeing an entry in the connection pool.")
+#define CONTEXT_DB2GET_NSF_SCH PKG_NSF_STR+31
+ stringtext(CONTEXT_DB2GET_NSF_SCH, "Failed when DB2 was getting NSF Schema.")
+#define CONTEXT_DB2GET_NSF_TBS PKG_NSF_STR+32
+ stringtext(CONTEXT_DB2GET_NSF_TBS, "Failed when DB2 was getting NSF TableSpace.")
+#define CONTEXT_DB2TERM_SHR_CONN PKG_NSF_STR+33
+ stringtext(CONTEXT_DB2TERM_SHR_CONN, "Failed when DB2 was terminating shared connections.")
+#define CONTEXT_DB2INIT_SHR_CONN PKG_NSF_STR+34
+ stringtext(CONTEXT_DB2INIT_SHR_CONN, "Failed when DB2 was initializing shared connections.")
+#define CONTEXT_DB2EXIST_NSF PKG_NSF_STR+35
+ stringtext(CONTEXT_DB2EXIST_NSF, "Failed when DB2 was checking the existence of NSF.")
+#define CONTEXT_DB2EXIST_NSFIDENT PKG_NSF_STR+36
+ stringtext(CONTEXT_DB2EXIST_NSFIDENT, "Failed when DB2 checked for NSF identifier.")
+#define CONTEXT_DB2SET_ISOLATION PKG_NSF_STR+37
+ stringtext(CONTEXT_DB2SET_ISOLATION, "Failed when setting DB2 isolation level.")
+#define CONTEXT_DB2ALLOC_SESSION PKG_NSF_STR+38
+ stringtext(CONTEXT_DB2ALLOC_SESSION, "Failed when DB2 was allocating the session.")
+#define CONTEXT_DB2CREATE_SAVEPT PKG_NSF_STR+39
+ stringtext(CONTEXT_DB2CREATE_SAVEPT, "Failed when DB2 was creating save points.")
+#define CONTEXT_DB2ROLLB_SAVEPT PKG_NSF_STR+40
+ stringtext(CONTEXT_DB2ROLLB_SAVEPT, "Failed when DB2 was rolling back save points.")
+#define CONTEXT_DB2RELEASE_SAVEPT PKG_NSF_STR+41
+ stringtext(CONTEXT_DB2RELEASE_SAVEPT, "Failed when DB2 was releasing save points.")
+#define CONTEXT_DB2GET_HSTMT PKG_NSF_STR+42
+ stringtext(CONTEXT_DB2GET_HSTMT, "Failed when DB2 was getting statement handle.")
+#define CONTEXT_DB2UPD_FILE_PATH PKG_NSF_STR+43
+ stringtext(CONTEXT_DB2UPD_FILE_PATH, "Failed when DB2 was updating file paths.")
+#define CONTEXT_DB2EXEC_NIFCONNECT PKG_NSF_STR+44
+ stringtext(CONTEXT_DB2EXEC_NIFCONNECT, "Failed when DB2 was executing NIFConnect.")
+#define CONTEXT_DB2GET_PROP PKG_NSF_STR+45
+ stringtext(CONTEXT_DB2GET_PROP, "Failed when DB2 was getting properties.")
+#define CONTEXT_DB2SET_PROP_SRCTARG PKG_NSF_STR+46
+ stringtext(CONTEXT_DB2SET_PROP_SRCTARG, "Failed when DB2 was setting properties.")
+#define CONTEXT_DB2GET_PROP_BLOB PKG_NSF_STR+47
+ stringtext(CONTEXT_DB2GET_PROP_BLOB, "Failed when DB2 was getting blobs.")
+#define CONTEXT_DB2CLOSE_CURSOR PKG_NSF_STR+48
+ stringtext(CONTEXT_DB2CLOSE_CURSOR, "Failed when DB2 was closing cursor.")
+#define CONTEXT_DB2READ_NOTE PKG_NSF_STR+49
+ stringtext(CONTEXT_DB2READ_NOTE, "Failed when DB2 was reading a note.")
+#define CONTEXT_DB2WRITE_RNOTE PKG_NSF_STR+50
+ stringtext(CONTEXT_DB2WRITE_RNOTE, "Failed when DB2 was writing a row in a note.")
+#define CONTEXT_DB2DELETE_RNOTE PKG_NSF_STR+51
+ stringtext(CONTEXT_DB2DELETE_RNOTE, "Failed when DB2 was deleting a row in a note.")
+#define CONTEXT_DB2SEL_NSUMMARY PKG_NSF_STR+52
+ stringtext(CONTEXT_DB2SEL_NSUMMARY, "Failed when DB2 was selecting note summary set from ID table.")
+#define CONTEXT_DB2SEL_NSUMMARY_SET PKG_NSF_STR+53
+ stringtext(CONTEXT_DB2SEL_NSUMMARY_SET, "Failed when DB2 was selecting note summary set.")
+#define CONTEXT_DB2SEL_NOTE PKG_NSF_STR+54
+ stringtext(CONTEXT_DB2SEL_NOTE, "Failed when DB2 was selecting a note.")
+#define CONTEXT_DB2GET_NOTE_SROW PKG_NSF_STR+55
+ stringtext(CONTEXT_DB2GET_NOTE_SROW, "Failed when DB2 was fetching a note summary row.")
+#define CONTEXT_DB2GET_NOTE PKG_NSF_STR+56
+ stringtext(CONTEXT_DB2GET_NOTE, "Failed when DB2 was fetching a note.")
+#define CONTEXT_DB2UNID_FINDE PKG_NSF_STR+57
+ stringtext(CONTEXT_DB2UNID_FINDE, "Failed when DB2 was looking for UNID entry.")
+#define CONTEXT_DB2_FINDE_BYNID PKG_NSF_STR+58
+ stringtext(CONTEXT_DB2_FINDE_BYNID, "Failed when DB2 was looking for an entry by note id.")
+#define MSG_DB2NSF_SCHEMA_UPGRADING PKG_NSF_STR+59
+ stringtext(MSG_DB2NSF_SCHEMA_UPGRADING,"Upgrading schema for DB2NSF %s. This may take several minutes." )
+#define CONTEXT_DB2DELETE_QUEUE_ENT PKG_NSF_STR+60
+ stringtext(CONTEXT_DB2DELETE_QUEUE_ENT, "Failed deleting DB2 queue entry.")
+#define CONTEXT_DB2RELOCATE_TS PKG_NSF_STR+61
+ stringtext(CONTEXT_DB2RELOCATE_TS, "Failed to Relocate tablespace container.")
+#define ERR_DB2NSF_QUIESCED PKG_NSF_STR+62
+ stringtext(ERR_DB2NSF_QUIESCED, "Unable to Connect to quiesced database.")
+#define CONTEXT_DB2COLLECT_COLINFO PKG_NSF_STR+63
+ stringtext(CONTEXT_DB2COLLECT_COLINFO, "Failed when DB2 was collecting column info.")
+#define CONTEXT_DB2PAIFIND_ENTRY PKG_NSF_STR+64
+ stringtext(CONTEXT_DB2PAIFIND_ENTRY, "Failed when DB2 was finding a named object entry.")
+#define CONTEXT_DB2PAIFIND_COUNT PKG_NSF_STR+65
+ stringtext(CONTEXT_DB2PAIFIND_COUNT, "Failed when DB2 was finding the count of named object entries.")
+#define CONTEXT_DB2PAI_INS_UPD PKG_NSF_STR+66
+ stringtext(CONTEXT_DB2PAI_INS_UPD, "Failed when DB2 was inserting/updating a named object entry.")
+#define CONTEXT_DB2PAI_DELETE PKG_NSF_STR+67
+ stringtext(CONTEXT_DB2PAI_DELETE, "Failed when DB2 was deleting a named object entry.")
+#define CONTEXT_DB2CREATE_TAB PKG_NSF_STR+68
+ stringtext(CONTEXT_DB2CREATE_TAB, "Failed when creating DB2 table.")
+#define CONTEXT_DB2CREATE_VIEW PKG_NSF_STR+69
+ stringtext(CONTEXT_DB2CREATE_VIEW, "Failed when creating DB2 view.")
+#define CONTEXT_DB2CREATE_DEL PKG_NSF_STR+70
+ stringtext(CONTEXT_DB2CREATE_DEL, "Failed when creating DB2 delete.")
+#define CONTEXT_DB2CREATE_DELTRIG PKG_NSF_STR+71
+ stringtext(CONTEXT_DB2CREATE_DELTRIG, "Failed when creating DB2 delete trigger.")
+#define CONTEXT_DB2CREATE_INS PKG_NSF_STR+72
+ stringtext(CONTEXT_DB2CREATE_INS, "Failed when creating DB2 insert.")
+#define CONTEXT_DB2CREATE_INSTRIG PKG_NSF_STR+73
+ stringtext(CONTEXT_DB2CREATE_INSTRIG, "Failed when creating DB2 insert trigger.")
+#define CONTEXT_DB2CREATE_UPD PKG_NSF_STR+74
+ stringtext(CONTEXT_DB2CREATE_UPD, "Failed when creating DB2 update.")
+#define CONTEXT_DB2CREATE_UPDTRIG PKG_NSF_STR+75
+ stringtext(CONTEXT_DB2CREATE_UPDTRIG, "Failed when creating DB2 update trigger.")
+#define CONTEXT_DB2LOAD_ACC_DEF PKG_NSF_STR+76
+ stringtext(CONTEXT_DB2LOAD_ACC_DEF, "Failed when loading the access definition.")
+#define CONTEXT_DB2CREATE_EXPTAB PKG_NSF_STR+77
+ stringtext(CONTEXT_DB2CREATE_EXPTAB, "Failed when creating DB2 export table.")
+#define CONTEXT_DB2INS_MAPENT PKG_NSF_STR+78
+ stringtext(CONTEXT_DB2INS_MAPENT, "Failed when inserting DB2 map entry.")
+#define CONTEXT_DB2DROP_EXPTAB PKG_NSF_STR+79
+ stringtext(CONTEXT_DB2DROP_EXPTAB, "Failed when dropping DB2 export table.")
+#define CONTEXT_DB2DROP_EXPENT PKG_NSF_STR+80
+ stringtext(CONTEXT_DB2DROP_EXPENT, "Failed when dropping DB2 exported entity.")
+#define CONTEXT_DB2LOAD_ACCTAB PKG_NSF_STR+81
+ stringtext(CONTEXT_DB2LOAD_ACCTAB, "Failed when loading the access definition records in the table.")
+#define CONTEXT_DB2INS_ACCTAB PKG_NSF_STR+82
+ stringtext(CONTEXT_DB2INS_ACCTAB, "Failed when inserting in the access table.")
+#define CONTEXT_DB2INS_ACCTAB_ROW PKG_NSF_STR+83
+ stringtext(CONTEXT_DB2INS_ACCTAB_ROW, "Failed when inserting an access table row.")
+#define CONTEXT_DB2UPD_ACCTAB PKG_NSF_STR+84
+ stringtext(CONTEXT_DB2UPD_ACCTAB, "Failed when updating the access table.")
+#define CONTEXT_DB2DEL_FROM_ACCTAB PKG_NSF_STR+85
+ stringtext(CONTEXT_DB2DEL_FROM_ACCTAB, "Failed when deleting from access table.")
+#define CONTEXT_DB2LOAD_SB_PROP PKG_NSF_STR+86
+ stringtext(CONTEXT_DB2LOAD_SB_PROP, "Failed loading super block property.")
+#define CONTEXT_DB2WRITE_SB_PROP PKG_NSF_STR+87
+ stringtext(CONTEXT_DB2WRITE_SB_PROP, "Failed writing super block property.")
+#define CONTEXT_DB2TERM_SCONN PKG_NSF_STR+88
+ stringtext(CONTEXT_DB2TERM_SCONN, "Failed terminating shared connections.")
+#define CONTEXT_DB2FREE_NSUMSET PKG_NSF_STR+89
+ stringtext(CONTEXT_DB2FREE_NSUMSET, "Failed when DB2 was freeing note summary set.")
+/* AVAILABLE */
+#define CONTEXT_DB2READ_FILE_HEADER PKG_NSF_STR+93
+ stringtext(CONTEXT_DB2READ_FILE_HEADER, "Failed reading DB2 file header.")
+#define CONTEXT_DB2FREE_HSTMT PKG_NSF_STR+94
+ stringtext(CONTEXT_DB2FREE_HSTMT, "Failed when DB2 was freeing statement handle.")
+#define CONTEXT_DB2_ENABLE_UDF PKG_NSF_STR+95
+ stringtext(CONTEXT_DB2_ENABLE_UDF, "Failed to enable user defined functions.")
+#define CONTEXT_DB2_ADMIN_UDF PKG_NSF_STR+96
+ stringtext(CONTEXT_DB2_ADMIN_UDF, "Failed while administering DB2 Access DLL.")
+#define CONTEXT_DB2GRPSEM PKG_NSF_STR+97
+ stringtext(CONTEXT_DB2GRPSEM, "Error encountered in group semaphore management." )
+#define CONTEXT_DB2_QUERY_VIEWS PKG_NSF_STR+98
+ stringtext(CONTEXT_DB2_QUERY_VIEWS, "Error encountered in DB2 Query Views" )
+#define CONTEXT_DB2RECOVER_SOFT_DEL_LIST PKG_NSF_STR+99
+ stringtext(CONTEXT_DB2RECOVER_SOFT_DEL_LIST, "Failed recovering DB2 soft deleted note list.")
+#define CONTEXT_DB2CATALOG PKG_NSF_STR+100
+ stringtext(CONTEXT_DB2CATALOG, "Error creating DB2 catalog entry" )
+#define MSG_DB2NSF_CATALOG_UPGRADED PKG_NSF_STR+101
+ stringtext(MSG_DB2NSF_CATALOG_UPGRADED,"Successfully upgraded schema %s from Version %s to Version %s." )
+#define CONTEXT_TABLE_SCHEMA_UPGRADE PKG_NSF_STR+102
+ stringtext(CONTEXT_TABLE_SCHEMA_UPGRADE, "Error upgrading table schema: " )
+#define MSG_DB2NSF_SCHEMA_UPGRADED PKG_NSF_STR+103
+ stringtext(MSG_DB2NSF_SCHEMA_UPGRADED,"Successfully upgraded tables for schema %s from Version %s to Version %s." )
+#define CONTEXT_DB2EXTEND_TS PKG_NSF_STR+104
+ stringtext(CONTEXT_DB2EXTEND_TS, "Failed to extend tablespace." )
+#define CONTEXT_DB2GET_NSF_SIZE PKG_NSF_STR+105
+ stringtext(CONTEXT_DB2GET_NSF_SIZE, "Failed calculating DB2 NSF size.")
+
+#define MSG_DB2_DEFAULT_BANNER PKG_NSF_STR+106
+ stringtext(MSG_DB2_DEFAULT_BANNER, "%n--default----------------%n")
+#define MSG_DB2_HANDLELOCATIONPRINT_TAG PKG_NSF_STR+107
+ stringtext(MSG_DB2_HANDLELOCATIONPRINT_TAG, " cliRC= %d, line=%d, file=%s%n")
+#define MSG_DB2_HANDLEDIAGNOSTICPRINT_TAG PKG_NSF_STR+108
+ stringtext(MSG_DB2_HANDLEDIAGNOSTICPRINT_TAG,"%n%5d SQLSTATE= %s, Native Error Code= %ld, message:")
+#define MSG_DB2_DB2READNOTE1 PKG_NSF_STR+109
+ stringtext(MSG_DB2_DB2READNOTE1, "Error reading note (NoteID: NT%08lx) (Schema: %s)%n")
+#define MSG_DB2_DB2WRITENOTE1 PKG_NSF_STR+110
+ stringtext(MSG_DB2_DB2WRITENOTE1, "Error writing note (NoteID: NT%08lx)(schema: %s)%n")
+#define MSG_DB2_DB2DELETENOTE1 PKG_NSF_STR+111
+ stringtext(MSG_DB2_DB2DELETENOTE1, "Error deleting note (NoteID: NT%08lx)%n")
+
+/* there may be some available PKG_NSF_STR offsets above... */
+
+/* this is the *current* max; PKG_NSF_STR has an offset range of 0 - 127 */
+#define STR_NSF_STR_MAX PKG_NSF_STR+112
+ stringtext(STR_NSF_STR_MAX, "This is the last error message in the NSF_STR range")
+
+#endif /*NSF_STR_DEFS*/
+
+
+#if defined(OS400) && (__OS400_TGTVRM__ >= 510)
+#pragma datamodel(pop)
+#endif
+
diff --git a/protocols/LotusNotify/src/cnotesapi/include/osenv.h b/protocols/LotusNotify/src/cnotesapi/include/osenv.h
new file mode 100644
index 0000000000..d2cdb6e943
--- /dev/null
+++ b/protocols/LotusNotify/src/cnotesapi/include/osenv.h
@@ -0,0 +1,76 @@
+
+#if defined(OS400) && (__OS400_TGTVRM__ >= 510)
+#pragma datamodel(P128)
+#endif
+
+/*********************************************************************/
+/* */
+/* Licensed Materials - Property of IBM */
+/* */
+/* L-GHUS-5VMPGW, L-GHUS-5S3PEE */
+/* (C) Copyright IBM Corp. 1991, 2004 All Rights Reserved */
+/* */
+/* US Government Users Restricted Rights - Use, duplication or */
+/* disclosure restricted by GSA ADP Schedule Contract with */
+/* IBM Corp. */
+/* */
+/*********************************************************************/
+
+
+#ifndef ENV_DEFS
+#define ENV_DEFS
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* Size of the buffer used to hold the environment variable values (i.e., it
+ excludes the variable name) but including the trailing null terminator.
+
+ NOTE: The largest known example of an environment variable value is a
+ max'ed out COMx=... (the modem init strings can be large, and
+ there's plenty of them).
+*/
+#define MAXENVVALUE 256
+
+/* Used to preface ini variables that are different between OSs which may */
+/* share the same INI file. */
+
+#if defined(PM)
+#define OS_PREFIX "PM"
+#elif defined(W)
+#define OS_PREFIX "WIN"
+#else
+#define OS_PREFIX "" /* Only necessary to distinguish */
+ /* between entries used in a multi */
+ /* OS environment with a single NOTES.INI */
+#endif
+/* Environment variable package */
+#define NATIVE "Native"
+/* System temp directory constants */
+#define TEMP_DIR_PREFIX "notes"
+#define TEMP_DIR_SUFFIX_LEN 6 /* If changing, must change TEMP_DIR_SUFFIX_FORMATSPEC to match */
+#define TEMP_DIR_SUFFIX_FORMATSPEC "%06x"
+#define TEMP_DIR_DEFAULT_SUFFIX "G00000"
+#define TEMP_DIR_SUFFIX_MAX_VALUE 0x00FFFFFF
+
+BOOL LNPUBLIC OSGetEnvironmentString (const char far *VariableName, char far *retValueBuffer, WORD BufferLength);
+long LNPUBLIC OSGetEnvironmentLong (const char far *VariableName);
+#define OSGetEnvironmentInt(s) ((int) OSGetEnvironmentLong(s))
+
+void LNPUBLIC OSSetEnvironmentVariable (const char far *VariableName, const char far *Value);
+void LNPUBLIC OSSetEnvironmentInt (const char far *VariableName, int Value);
+
+#ifdef __cplusplus
+}
+#endif
+
+
+#endif
+
+
+
+#if defined(OS400) && (__OS400_TGTVRM__ >= 510)
+#pragma datamodel(pop)
+#endif
+
diff --git a/protocols/LotusNotify/src/cnotesapi/include/osmisc.h b/protocols/LotusNotify/src/cnotesapi/include/osmisc.h
new file mode 100644
index 0000000000..e7214bc971
--- /dev/null
+++ b/protocols/LotusNotify/src/cnotesapi/include/osmisc.h
@@ -0,0 +1,109 @@
+
+#if defined(OS400) && (__OS400_TGTVRM__ >= 510)
+#pragma datamodel(P128)
+#endif
+
+/*********************************************************************/
+/* */
+/* Licensed Materials - Property of IBM */
+/* */
+/* L-GHUS-5VMPGW, L-GHUS-5S3PEE */
+/* (C) Copyright IBM Corp. 1989, 2005 All Rights Reserved */
+/* */
+/* US Government Users Restricted Rights - Use, duplication or */
+/* disclosure restricted by GSA ADP Schedule Contract with */
+/* IBM Corp. */
+/* */
+/*********************************************************************/
+
+
+
+#ifndef OSMISC_DEFS
+#define OSMISC_DEFS
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+#ifndef NLS_H
+#include "nls.h" /* Need NLS_PINFO */
+#endif
+
+/* String resource loading routine */
+
+WORD LNPUBLIC OSLoadString (HMODULE hModule, STATUS StringCode, char far *retBuffer, WORD BufferLength);
+/* Charsets used with OSTranslate */
+
+#define OS_TRANSLATE_NATIVE_TO_LMBCS 0 /* Translate platform-specific to LMBCS */
+#define OS_TRANSLATE_LMBCS_TO_NATIVE 1 /* Translate LMBCS to platform-specific */
+#define OS_TRANSLATE_LOWER_TO_UPPER 3 /* current int'l case table */
+#define OS_TRANSLATE_UPPER_TO_LOWER 4 /* current int'l case table */
+#define OS_TRANSLATE_UNACCENT 5 /* int'l unaccenting table */
+
+#ifdef DOS
+#define OS_TRANSLATE_OSNATIVE_TO_LMBCS 7 /* Used in DOS (codepage) */
+#define OS_TRANSLATE_LMBCS_TO_OSNATIVE 8 /* Used in DOS */
+#elif defined (OS2)
+#define OS_TRANSLATE_OSNATIVE_TO_LMBCS OS_TRANSLATE_NATIVE_TO_LMBCS
+#define OS_TRANSLATE_LMBCS_TO_OSNATIVE OS_TRANSLATE_LMBCS_TO_NATIVE
+#else
+#define OS_TRANSLATE_OSNATIVE_TO_LMBCS OS_TRANSLATE_NATIVE_TO_LMBCS
+#define OS_TRANSLATE_LMBCS_TO_OSNATIVE OS_TRANSLATE_LMBCS_TO_NATIVE
+#endif
+
+#if defined(DOS) || defined(OS2)
+#define OS_TRANSLATE_LMBCS_TO_ASCII 13
+#else
+#define OS_TRANSLATE_LMBCS_TO_ASCII 11
+#endif
+
+#define OS_TRANSLATE_LMBCS_TO_UNICODE 20
+#define OS_TRANSLATE_LMBCS_TO_UTF8 22
+#define OS_TRANSLATE_UNICODE_TO_LMBCS 23
+#define OS_TRANSLATE_UTF8_TO_LMBCS 24
+
+
+/* Character Set Translation Routines */
+
+WORD LNPUBLIC OSTranslate(WORD TranslateMode, const char far *In, WORD InLength, char far *Out, WORD OutLength);
+
+/* Dynamic link library portable load routines */
+
+STATUS LNPUBLIC OSLoadLibrary (const char far *LibraryName, DWORD Flags, HMODULE far *rethModule, void far *retEntryPoint);
+void LNPUBLIC OSFreeLibrary (HMODULE);
+#define OS_LOADPROG_ICONIC 0x0001 /* Don't show application window */
+#define OS_LOADPROG_BACKGROUND 0x0002 /* Don't bring to the foreground */
+#define OS_LOADPROG_DEBUG 0x0004 /* Start with QNC */
+#define OS_LOADPROG_DETACHED 0x0008 /* Don't wait around for this process to exit */
+#define OS_LOADPROG_ASSOCIATE 0x0010 /* Look for a file type association */
+#define OS_LOADPROG_PRIORITY_LOW 0x0020 /* Start process with a lower priority */
+#define OS_LOADPROG_SHELL_SCRIPT_USE_EXECVP 0x0040 /* Flag to signal a shell script, so we can use execvp instead of execv. Currently on use only on AIX */
+#define OS_LOADPROG_OPEN_WITH 0x0080 /* Flag to add the necessary things to do an open with command. Currently on use only on NT */
+
+
+STATUS LNPUBLIC OSLoadProgram (char far *filename, char far *WorkingDir, char far *Arguments, WORD Flags);
+
+/* Routine used in non-premptive platforms to simulate it. */
+
+#ifdef PREEMPTIVE
+#define OSPreemptOccasionally()
+#else
+void LNPUBLIC OSPreemptOccasionally (void);
+#endif
+/* Notes-specific NLS definitions */
+
+NLS_PINFO LNPUBLIC OSGetLMBCSCLS(void);
+NLS_PINFO LNPUBLIC OSGetNativeCLS(void);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
+
+
+#if defined(OS400) && (__OS400_TGTVRM__ >= 510)
+#pragma datamodel(pop)
+#endif
+
diff --git a/protocols/LotusNotify/src/cnotesapi/include/pool.h b/protocols/LotusNotify/src/cnotesapi/include/pool.h
new file mode 100644
index 0000000000..91b415c039
--- /dev/null
+++ b/protocols/LotusNotify/src/cnotesapi/include/pool.h
@@ -0,0 +1,88 @@
+
+#if defined(OS400) && (__OS400_TGTVRM__ >= 510)
+#pragma datamodel(P128)
+#endif
+
+/*********************************************************************/
+/* */
+/* Licensed Materials - Property of IBM */
+/* */
+/* L-GHUS-5VMPGW, L-GHUS-5S3PEE */
+/* (C) Copyright IBM Corp. 1989, 2005 All Rights Reserved */
+/* */
+/* US Government Users Restricted Rights - Use, duplication or */
+/* disclosure restricted by GSA ADP Schedule Contract with */
+/* IBM Corp. */
+/* */
+/*********************************************************************/
+
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifndef POOL_DEFS
+#define POOL_DEFS
+
+
+/* A datatype which identifies a block within a segment */
+
+typedef DWORD DBLOCK; /* dpool block handle */
+
+#define NULLBLOCK (BLOCK) 0
+#define NULLDBLOCK (DBLOCK) 0
+
+
+/* A structure containing a pool handle and block offset */
+
+typedef struct /* Pointer to any block in any pool */
+ {
+ HANDLE pool; /* pool handle */
+ BLOCK block; /* block handle */
+ } BLOCKID;
+
+typedef struct /* Pointer to any block in any pool */
+ {
+ HANDLE pool; /* pool handle */
+ DBLOCK block; /* block handle */
+ } DBLOCKID;
+
+#define ISNULLBLOCKID(x) (((x).pool==NULLHANDLE)&&((x).block==NULLBLOCK))
+
+/* Macro functions */
+
+
+#define OSLockBlock(type,blockid) \
+ ((type far *)(OSLock(char,(blockid).pool) + (blockid).block))
+
+#define OSUnlockBlock(blockid) \
+ OSUnlockObject((blockid).pool)
+
+#define OSSwitchBlock(ptr,thisid,nextid) \
+ { \
+ if ((thisid).pool != (nextid).pool) \
+ { \
+ if ((thisid).pool != NULLHANDLE) \
+ OSUnlockBlock((thisid)); \
+ ptr = OSLockBlock(void,(nextid)); \
+ } \
+ else \
+ { \
+ register char **pptr = (char **) &(ptr); \
+ *pptr = *pptr + (LONG)((nextid).block - (thisid).block); \
+ } \
+ (thisid) = (nextid); \
+ }
+
+
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+
+
+#if defined(OS400) && (__OS400_TGTVRM__ >= 510)
+#pragma datamodel(pop)
+#endif
+
diff --git a/protocols/LotusNotify/src/cnotesapi/include/stdnames.h b/protocols/LotusNotify/src/cnotesapi/include/stdnames.h
new file mode 100644
index 0000000000..2638570c29
--- /dev/null
+++ b/protocols/LotusNotify/src/cnotesapi/include/stdnames.h
@@ -0,0 +1,6175 @@
+
+#if defined(OS400) && (__OS400_TGTVRM__ >= 510)
+#pragma datamodel(P128)
+#endif
+
+/*********************************************************************/
+/* */
+/* Licensed Materials - Property of IBM */
+/* */
+/* L-GHUS-5VMPGW, L-GHUS-5S3PEE */
+/* (C) Copyright IBM Corp. 1989, 2005 All Rights Reserved */
+/* */
+/* US Government Users Restricted Rights - Use, duplication or */
+/* disclosure restricted by GSA ADP Schedule Contract with */
+/* IBM Corp. */
+/* */
+/*********************************************************************/
+
+
+#ifndef STD_NAME_DEFS
+#define STD_NAME_DEFS
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* Standard NSF Field Name/Value Definitions for the Notes product */
+
+/* Very global field names */
+
+#define FIELD_TITLE "$TITLE"
+#define FIELD_FORM "Form"
+#define FIELD_TYPE_TYPE "Type"
+#define FIELD_LINK "$REF"
+#define FIELD_UPDATED_BY "$UpdatedBy"
+#define FIELD_NAMELIST "$NameList"
+#define FIELD_NAMED "$Name"
+#define FIELD_URL "URL" /* used when copying link to clipboard */
+#define FIELD_UNAME "$UName" /* Universal UNID/Name */
+#define FIELD_CREATED "$Created" /* Created date, if specified overrides UNID created date for @Created */
+#define FIELD_NAVIGATE_URL "$NavigateToURL"/* used to pass a URL to an embedded web browser control */
+#define FIELD_RELOAD_REFRESH "$ReloadRefresh"/* used to pass reload/refresh info to embedded web browser control */
+#define DESIGN_CLASS "$Class"
+#define DESIGN_MODIFIED "$Modified"
+#define DESIGN_COMMENT FILTER_COMMENT_ITEM
+#define DESIGN_READERS "$Readers" /* Text list of users allowed to read note */
+#define FIELD_ANONYMOUS "$Anonymous" /* Indicates an anonymous document. */
+#define DESIGN_UPDATERS "$Updaters" /* Text list of users allowed to update the folder note */
+#define FIELD_NOPURGE "$NoPurge" /* Note should never be purged. */
+#define DESIGN_RETAIN_FIELDS "$RetainFields" /* Text list of fields to retain in a
+ design refresh */
+#define FIELD_ORIG_SIZE "$OrigSize" /* Size of entire note. Set for
+ abstracted note to give user
+ info on whether they want to
+ download the whole message or
+ not. */
+#define FIELD_LANGUAGE "$LANGUAGE" /* Used to specify the language of the note */
+#define FIELD_VIEWLOCALE "$VIEWCOLLATION"
+#define FIELD_BASE_TEMPLATE_VERSION "$TemplateBuild"
+#define FIELD_BASE_TEMPLATE_NAME "$TemplateBuildName"
+#define FIELD_BASE_TEMPLATE_DATE "$TemplateBuildDate"
+#define FIELD_NO_SOFT_DELETE "$NoSoftDelete" /* Override soft delete on a per-note basis */
+#define FIELD_HIDEINFO "$HideInfo" /* If present in design element, its design is hidden and this item contains the mod time before hiding. */
+
+/* Public Access definitions */
+#define FIELD_PUBLICROLE "$P" /* Reader List role name for public users */
+#define FIELD_PUBLICACCESS "$PublicAccess" /* Note has public access if ACL_FLAG_PUBLICREADER is set. */
+#define FORM_FIELD_PUBLICACCESS "$FormPublicAccess" /* Form Note has public access if ACL_FLAG_PUBLICREADER is set. */
+#define FIELD_PUBLICACCESS_ENABLED '1'
+
+#define FIELD_LOGVIEWUPDATES "$LogViewUpdates" /* NIF will log all incremental view updates */
+#define FIELD_LOGVIEWUPDATES_ENABLED '1'
+
+/* Pseudo item names (don't exist in Notes) recognized by NAMELookup */
+
+#define ITEM_NOTEID "$$NoteID" /* a NAMELookup item to be returned */
+#define ITEM_DBNAME "$$DBName" /* address book this entry was found in */
+#define ITEM_DBINDEX "$$DBIndex" /* 1-based db index upon primary NAB and ABs listed in MAB */
+#define ITEM_MODIFIEDTIME "$$ModifiedTime" /* TIMEDATE this entry was last modified */
+#define ITEM_DOMAINTYPE "$$DomainType" /* either NOTES or LDAP */
+#define ITEM_UNID "$$UNID" /* a NAMELookup item to be returned */
+#define ITEM_READERLIST "$$Readers" /* Return the readers list */
+#define ITEM_NOTESDN "$$NotesDN" /* A notes style distinquished name,
+ only returned from LDAP address books */
+#define ITEM_ORIGINAL_LDAP_DN "$$OriginalLDAPDN" /* Original LDAP DN (non-normalized) */
+
+#define ITEM_LTPAUSERNAME "$$LTPAUsername" /* The name that should be used (in preference
+ to the DN) to build an LTPA token for
+ single sign on support. */
+
+
+
+
+/* field definitions for Data Connection Resources */
+
+#define FIELD_DCR_CLASS "$DCRClass" /* e.g. RDBMS, ERP */
+#define FIELD_DCR_GEN_PROPS "$DCRGenProps" /* generic connector properties */
+#define FIELD_DCR_CUS_PROPS "$DCRCusProps" /* custom connector properties */
+#define FIELD_DCR_CUS_DESCS "$DCRCusDescs" /* descriptors for custom props */
+#define DCR_METADATA_RECORD "$DCRMetadata" /* NSFSearch item id for summary buffer */
+#define DCR_METADATA_SEARCH "$DCRCatalog" /* Special id used as NSFSearch trigger */
+
+/* define order of generic properties in FIELD_DCR_GEN_PROPS */
+#define DCR_GPROP_TYPE 0
+#define DCR_GPROP_SERVER 1
+#define DCR_GPROP_DATABASE 2
+#define DCR_GPROP_USERNAME 3
+#define DCR_GPROP_PASSWORD 4
+#define DCR_GPROP_MD_OWNER 5
+#define DCR_GPROP_MD_NAME 6
+#define DCR_GPROP_CONNECTIONS 7
+#define DCR_GPROP_FLAGS 8
+#define DCR_GPROP_OPEN_PROC 9
+#define DCR_GPROP_UPDATE_PROC 10
+#define DCR_GPROP_CREATE_PROC 11
+#define DCR_GPROP_DELETE_PROC 12
+#define DCR_GPROP_LAST DCR_GPROP_DELETE_PROC
+
+/* Flag definitions for Data Connection Resources: misc properties */
+#define DCR_FLAG_TABLE 'T'
+#define DCR_FLAG_VIEW 'V'
+#define DCR_FLAG_PROC 'P'
+#define DCR_FLAG_UPDATE_CHANGED_FIELDS 'u'
+#define DCR_FLAG_BLOCK_KEY_FIELD_UPDATES 'b'
+#define DCR_FLAG_CONFLICT_DETECTION 'c'
+#define DCR_FLAG_FIELD_DECS_ERRORS 'e'
+#define DCR_FLAG_DISABLE_HTTP_CACHING 'h'
+#define DCR_FLAG_IGNORE_MISSING_RECORD 'i' /* On missing record */
+#define DCR_FLAG_CREATE_EXTERNAL_RECORD 'x'
+#define DCR_FLAG_TRUNCATE_PRECISION 'p' /* On data conflict */
+#define DCR_FLAG_TRUNCATE_DATA 'd'
+#define DCR_FLAG_TRIM_ALL_FIELDS 'a' /* Space trimming */
+#define DCR_FLAG_TRIM_NON_KEY_FIELDS 'k'
+
+
+/* Define Private note field name, and define the known types */
+
+#define FIELD_PRIVATE_TYPE "$Private"
+
+#define FIELD_PRIVATE_TYPE_QUERY 'q'
+#define FIELD_PRIVATE_TYPE_AGENT 'a'
+#define FIELD_PRIVATE_TYPE_VIEW 'v'
+#define FIELD_PRIVATE_TYPE_FOLDER 'f'
+
+/* The following items are inserted into a note which cannot be saved to its
+ Some special named notes. These values are stored in the FIELD_NAMED item to
+ identify a named note. */
+
+#define NAMEDNOTE_PRIVATEDESIGN "$PrivateDesign"
+#define NAMEDNOTE_PROFILE "$Profile"
+#define NAMEDNOTE_IMAP_DELETED_ENTRY "$IMAPResyncDE"
+#define NAMEDNOTE_POP_DELETED_ENTRY "$PopDE"
+
+
+/* The following definitions of for the public directory profile note */
+#define NAMEDNOTE_PUBLICDIRECTORYPROFILE "directoryprofile"
+#define LEDNAME_ITEM "LedName"
+#define TRUST_DIRCAT_ITEM "TrustDircat"
+#define DIRECTORY_DOMAIN_ITEM "Domain"
+#define SECURE_INETPASSWORDS_ITEM "SecureInetPasswords"
+#define ADMIN_LDAPSERVER_ITEM "AdminLDAPServer"
+
+/* The following items are inserted into a note which cannot be saved to its
+ original database due to network failure. When the failure can be
+ remedied, the note is read back into memory and fixed up to point
+ to correct database. At that point the items are removed. */
+
+#define PENDINGNAME "NOTEPEND"
+#define PENDINGSAVE_LINK_ITEM "$ORIGLINK"
+#define PENDINGSAVE_FILENAME_ITEM "$ORIGFILE"
+
+/* Designer minimum version */
+/* "minimum version" means "you need at least this version to safely save
+ this design element." */
+
+#define DESIGNER_VERSION "$DesignerVersion"
+
+#define DESIGNER_MIN_VERSION_5 "5"
+#define DESIGNER_MIN_VERSION_6 "6"
+#define DESIGNER_MIN_VERSION_6_5 "6.5"
+#define DESIGNER_MIN_VERSION_7 "7"
+#define DESIGNER_MIN_VERSION_8 "8"
+#define DESIGNER_MIN_VERSION_9 "9"
+#define DESIGNER_MIN_VERSION_10 "A"
+
+/* Design flags */
+
+#define DESIGN_FLAGS "$Flags"
+
+/* Please keep these flags in alphabetic order (based on the flag itself) so that
+ we can easily tell which flags to use next. Note that some of these flags apply
+ to a particular NOTE_CLASS; others apply to all design elements. The comments
+ indicate which is which. In theory, flags that apply to two different NOTE_CLASSes
+ could overlap, but for now, try to make each flag unique. */
+
+#define DESIGN_FLAG_ADD 'A' /* FORM: Indicates that a subform is in the add subform list */
+#define DESIGN_FLAG_ANTIFOLDER 'a' /* VIEW: Indicates that a view is an antifolder view */
+#define DESIGN_FLAG_BACKGROUND_FILTER 'B' /* FILTER: Indicates FILTER_TYPE_BACKGROUND is asserted */
+#define DESIGN_FLAG_INITBYDESIGNONLY 'b' /* VIEW: Indicates view can be initially built only by designer and above */
+#define DESIGN_FLAG_NO_COMPOSE 'C' /* FORM: Indicates a form that is used only for */
+ /* query by form (not on compose menu). */
+#define DESIGN_FLAG_CALENDAR_VIEW 'c' /* VIEW: Indicates a form is a calendar style view. */
+#define DESIGN_FLAG_NO_QUERY 'D' /* FORM: Indicates a form that should not be used in query by form */
+#define DESIGN_FLAG_DEFAULT_DESIGN 'd' /* ALL: Indicates the default design note for it's class (used for VIEW) */
+#define DESIGN_FLAG_MAIL_FILTER 'E' /* FILTER: Indicates FILTER_TYPE_MAIL is asserted */
+#define DESIGN_FLAG_PUBLICANTIFOLDER 'e' /* VIEW: Indicates that a view is a public antifolder view */
+#define DESIGN_FLAG_FOLDER_VIEW 'F' /* VIEW: This is a V4 folder view. */
+#define DESIGN_FLAG_V4AGENT 'f' /* FILTER: This is a V4 agent */
+#define DESIGN_FLAG_VIEWMAP 'G' /* VIEW: This is ViewMap/GraphicView/Navigator */
+#define DESIGN_FLAG_FILE 'g' /* FORM: file design element */
+#define DESIGN_FLAG_OTHER_DLG 'H' /* ALL: Indicates a form that is placed in Other... dialog */
+#define DESIGN_FLAG_JAVASCRIPT_LIBRARY 'h' /* Javascript library. */
+#define DESIGN_FLAG_V4PASTE_AGENT 'I' /* FILTER: This is a V4 paste agent */
+#define DESIGN_FLAG_IMAGE_RESOURCE 'i' /* FORM: Note is a shared image resource */
+#define DESIGN_FLAG_JAVA_AGENT 'J' /* FILTER: If its Java */
+#define DESIGN_FLAG_JAVA_AGENT_WITH_SOURCE 'j' /* FILTER: If it is a java agent with java source code. */
+#define DESIGN_FLAG_MOBILE_DIGEST 'K' /* to keep mobile digests out of form lists */
+#define DESIGN_FLAG_CONNECTION_RESOURCE 'k' /* Data Connection Resource (DCR) for 3rd party database */
+#define DESIGN_FLAG_LOTUSSCRIPT_AGENT 'L' /* FILTER: If its LOTUSSCRIPT */
+#define DESIGN_FLAG_DELETED_DOCS 'l' /* VIEW: Indicates that a view is a deleted documents view */
+#define DESIGN_FLAG_QUERY_MACRO_FILTER 'M' /* FILTER: Stored FT query AND macro */
+#define DESIGN_FLAG_SITEMAP 'm' /* FILTER: This is a site(m)ap. */
+#define DESIGN_FLAG_NEW 'N' /* FORM: Indicates that a subform is listed when making a new form.*/
+#define DESIGN_FLAG_HIDE_FROM_NOTES 'n' /* ALL: notes stamped with this flag
+ will be hidden from Notes clients
+ We need a separate value here
+ because it is possible to be
+ hidden from V4 AND to be hidden
+ from Notes, and clearing one
+ should not clear the other */
+#define DESIGN_FLAG_QUERY_V4_OBJECT 'O' /* FILTER: Indicates V4 search bar query object - used in addition to 'Q' */
+#define DESIGN_FLAG_PRIVATE_STOREDESK 'o' /* VIEW: If Private_1stUse, store the private view in desktop */
+#define DESIGN_FLAG_PRESERVE 'P' /* ALL: related to data dictionary */
+#define DESIGN_FLAG_PRIVATE_1STUSE 'p' /* VIEW: This is a private copy of a private on first use view. */
+#define DESIGN_FLAG_QUERY_FILTER 'Q' /* FILTER: Indicates full text query ONLY, no filter macro */
+#define DESIGN_FLAG_AGENT_SHOWINSEARCH 'q' /* FILTER: Search part of this agent should be shown in search bar */
+#define DESIGN_FLAG_REPLACE_SPECIAL 'R' /* SPECIAL: this flag is the opposite of DESIGN_FLAG_PRESERVE, used
+ only for the 'About' and 'Using' notes + the icon bitmap in the icon note */
+#define DESIGN_FLAG_PROPAGATE_NOCHANGE 'r' /* DESIGN: this flag is used to propagate the prohibition of design change */
+#define DESIGN_FLAG_V4BACKGROUND_MACRO 'S' /* FILTER: This is a V4 background agent */
+#define DESIGN_FLAG_SCRIPTLIB 's' /* FILTER: A database global script library note */
+#define DESIGN_FLAG_VIEW_CATEGORIZED 'T' /* VIEW: Indicates a view that is categorized on the categories field */
+#define DESIGN_FLAG_DATABASESCRIPT 't' /* FILTER: A database script note */
+#define DESIGN_FLAG_SUBFORM 'U' /* FORM: Indicates that a form is a subform.*/
+#define DESIGN_FLAG_AGENT_RUNASWEBUSER 'u' /* FILTER: Indicates agent should run as effective user on web */
+#define DESIGN_FLAG_AGENT_RUNASINVOKER 'u' /* FILTER: Indicates agent should run as invoker (generalize the
+ web user notion, reuse the flag */
+#define DESIGN_FLAG_PRIVATE_IN_DB 'V' /* ALL: This is a private element stored in the database */
+#define DESIGN_FLAG_IMAGE_WELL 'v' /* FORM: Used with 'i' to indicate the image is an image well.
+ Used for images with images across, not images down.
+ 'v' looks like a bucket */
+#define DESIGN_FLAG_WEBPAGE 'W' /* FORM: Note is a WEBPAGE */
+#define DESIGN_FLAG_HIDE_FROM_WEB 'w' /* ALL: notes stamped with this flag
+ will be hidden from WEB clients */
+/* WARNING: A formula that build Design Collecion relies on the fact that Agent Data's
+ $Flags is the only Desing Collection element whose $Flags="X" */
+#define DESIGN_FLAG_V4AGENT_DATA 'X' /* FILTER: This is a V4 agent data note */
+#define DESIGN_FLAG_SUBFORM_NORENDER 'x' /* SUBFORM: indicates whether
+ we should render a subform in
+ the parent form */
+#define DESIGN_FLAG_NO_MENU 'Y' /* ALL: Indicates that folder/view/etc. should be hidden from menu. */
+#define DESIGN_FLAG_SACTIONS 'y' /* Shared actions note */
+#define DESIGN_FLAG_MULTILINGUAL_PRESERVE_HIDDEN 'Z' /* ALL: Used to indicate design element was hidden */
+ /* before the 'Notes Global Designer' modified it. */
+ /* (used with the "!" flag) */
+#define DESIGN_FLAG_SERVLET 'z' /* FILTER: this is a servlet, not an agent! */
+#define DESIGN_FLAG_ACCESSVIEW 'z' /* FORM: reuse obsoleted servlet flag */
+
+#define DESIGN_FLAG_FRAMESET '#' /* FORM: Indicates that this is a frameset note */
+#define DESIGN_FLAG_MULTILINGUAL_ELEMENT '!'/* ALL: Indicates this design element supports the */
+ /* 'Notes Global Designer' multilingual addin */
+#define DESIGN_FLAG_JAVA_RESOURCE '@' /* FORM: Note is a shared Java resource */
+#define DESIGN_FLAG_STYLESHEET_RESOURCE '=' /* Style Sheet Resource (SSR) */
+#define DESIGN_FLAG_WEBSERVICE '{' /* FILTER: web service design element */
+#define DESIGN_FLAG_SHARED_COL '^' /* VIEW: shared column design element */
+
+#define DESIGN_FLAG_HIDE_FROM_MOBILE '1' /* hide this element from mobile clients */
+#define DESIGN_FLAG_HIDE_FROM_PORTAL '2' /* hide from portal */
+
+#define DESIGN_FLAG_HIDE_FROM_V3 '3' /* ALL: notes stamped with this flag
+ will be hidden from V3 client */
+#define DESIGN_FLAG_HIDE_FROM_V4 '4' /* ALL: notes stamped with this flag
+ will be hidden from V4 client */
+#define DESIGN_FLAG_HIDE_FROM_V5 '5' /* FILTER: 'Q5'= hide from V4.5 search list */
+ /* ALL OTHER: notes stamped with this flag
+ will be hidden from V5 client */
+#define DESIGN_FLAG_HIDE_FROM_V6 '6' /* ALL: notes stamped with this flag
+ will be hidden from V6 client */
+#define DESIGN_FLAG_HIDE_FROM_V7 '7' /* ALL: notes stamped with this flag
+ will be hidden from V7 client */
+#define DESIGN_FLAG_HIDE_FROM_V8 '8' /* ALL: notes stamped with this flag
+ will be hidden from V8 client */
+#define DESIGN_FLAG_HIDE_FROM_V9 '9' /* ALL: notes stamped with this flag
+ will be hidden from V9 client */
+#define DESIGN_FLAG_MUTILINGUAL_HIDE '0' /* ALL: notes stamped with this flag
+ will be hidden from the client
+ usage is for different language
+ versions of the design list to be
+ hidden completely */
+#define DESIGN_FLAG_WEBHYBRIDDB '%' /* shimmer design docs */
+
+#define DESIGN_FLAG_READONLY '&' /* for files, at least for starters */
+#define DESIGN_FLAG_NEEDSREFRESH '$' /* for files, at least for now */
+#define DESIGN_FLAG_HTMLFILE '>' /* this design element is an html file */
+#define DESIGN_FLAG_JSP '<' // this design element is a jsp
+#define DESIGN_FLAG_QUERYVIEW '<' // VIEW - Query View in design list
+#define DESIGN_FLAG_DIRECTORY '/' /* this file element is a directory */
+
+#define DESIGN_FLAG_PRINTFORM '?' /* FORM - used for printing. */
+#define DESIGN_FLAG_HIDEFROMDESIGNLIST '~' /* keep this thing out of a design list */
+#define DESIGN_FLAG_HIDEONLYFROMDESIGNLIST '}' /* keep this thing out of a design list but allow users to view doc using it */
+
+/* These are the flags that help determine the type of a design element.
+ These flags are used to sub-class the note classes, and cannot be
+ changed once they are created (for example, there is no way to change
+ a form into a subform). */
+
+#define DESIGN_FLAGS_SUBCLASS "UW#yi@GFXstmzk=Kg%{^"
+
+/* These are the flags that can be used to distinguish between two
+ design elements that have the same class, subclass (see DESIGN_FLAGS_SUBCLASS),
+ and name. */
+
+#define DESIGN_FLAGS_DISTINGUISH "nw123456789"
+
+/* '+' = ANY of the flags, '-' = NONE of the flags, '*' = ALL of the flags */
+/* '(+-*' = a combination of the above. */
+/* Example: "(+AB-C*DE" = (A OR B) AND (NOT C) AND (D AND E) */
+/* Note: be sure to have +-* placeholders even if no flags for some. */
+/* ie: "(+-C*DE" = (NOT C) AND (D AND E). */
+/* Note: "(+-Q*" is equivalent to "-Q" */
+
+#define DFLAGPAT_V4SEARCHBAR "(+Qq-Bst5nmz*"/* display things editable at V4 search bar; version filtering */
+#define DFLAGPAT_SEARCHBAR "(+QM-st5nmz*" /* display things editable at search bar; version filtering */
+
+#define DFLAGPAT_VIEWFORM "-FQMUGXWy#i@0nKg~%z^" /* display things editable with dialog box; version filtering */
+#define DFLAGPAT_VIEWFORM_MENUABLE "-FQMUGXWy#i@40nKg~%z^}" /* display things showable on the menu */
+#define DFLAGPAT_VIEWFORM_ALL_VERSIONS "-FQMUGXWy#i@Kg~%z^}" /* display things editable with dialog box; no version filtering (for design) */
+#define DFLAGPAT_PRINTFORM_ALL_VERSIONS "+?" /* display things editable with dialog box; no version filtering (for design) */
+
+#define DFLAGPAT_TOOLSRUNMACRO "-QXMBESIst5nmz{"/* display things that are runnable; version filtering */
+#define DFLAGPAT_AGENTSLIST "-QXstmz{" /* display things that show up in agents list. No version filtering (for design) */
+#define DFLAGPAT_PASTEAGENTS "+I" /* select only paste agents */
+#define DFLAGPAT_SCRIPTLIB "+sh" /* display only database global script libraries */
+#define DFLAGPAT_SCRIPTLIB_LS "(+s-jh*" /* display only database global LotusScript script libraries */
+#define DFLAGPAT_SCRIPTLIB_JAVA "*sj" /* display only database global Java script libraries */
+#define DFLAGPAT_SCRIPTLIB_JS "+h" /* display only database global Javascript script libraries */
+#define DFLAGPAT_DATABASESCRIPT "+t" /* display only database level script */
+
+#define DFLAGPAT_SUBFORM "(+U-40n*" /* display only subforms; version filtering */
+#define DFLAGPAT_SUBFORM_DESIGN "(+U-40*" /* display only subforms; for design mode, version filtering */
+#define DFLAGPAT_SUBFORM_ALL_VERSIONS "+U" /* only subforms; no version filtering */
+#define DFLAGPAT_DBRUNMACRO "+BS" /* run all background filters */
+#define DFLAGPAT_COMPOSE "-C40n" /* display forms that belong in compose menu; version filtering */
+#define DFLAGPAT_NOHIDDENNOTES "-n" /* select elements not hidden from notes */
+#define DFLAGPAT_NOHIDDENWEB "-w" /* select elements not hidden from web */
+#define DFLAGPAT_QUERYBYFORM "-DU40nyz{" /* display forms that appear in query by form; version filtering */
+#define DFLAGPAT_PRESERVE "+P" /* related to data dictionary; no version filtering */
+#define DFLAGPAT_SUBADD "(+-40*UA" /* subforms in the add subform list; no version filtering */
+#define DFLAGPAT_SUBNEW "(+-40*UN" /* subforms that are listed when making a new form.*/
+#define DFLAGPAT_VIEW "-FG40n^" /* display only views */
+#define DFLAGPAT_VIEW_DESIGN "-FG40^" /* display only views, ignore hidden from notes */
+#define DFLAGPAT_NOTHIDDEN "-40n" /* design element is not hidden*/
+#define DFLAGPAT_FOLDER "(+-04n*F" /* display only folders; version filtering */
+#define DFLAGPAT_FOLDER_DESIGN "(+-04*F" /* display only folders; version filtering, ignore hidden notes */
+#define DFLAGPAT_FOLDER_ALL_VERSIONS "*F"/* display only folders; no version filtering (for design) */
+#define DFLAGPAT_CALENDAR "*c" /* display only calendar-style views */
+#define DFLAGPAT_SHAREDVIEWS "-FGV^40n" /* display only shared views */
+#define DFLAGPAT_SHAREDVIEWSFOLDERS "-G^V40p" /* display only shared views and folder; all notes & web */
+#define DFLAGPAT_SHAREDWEBVIEWS "-FGV40wp^" /* display only shared views not hidden from web */
+#define DFLAGPAT_SHAREDWEBVIEWSFOLDERS "-GV40wp^" /* display only shared views and folders not hidden from web */
+#define DFLAGPAT_VIEWS_AND_FOLDERS "-G40n^" /* display only views and folder; version filtering */
+#define DFLAGPAT_VIEWS_AND_FOLDERS_DESIGN "-G40^" /* display only views and folder; all notes & web */
+#define DFLAGPAT_SHARED_COLS "(+-*^" /* display only shared columns */
+
+#define DFLAGPAT_VIEWMAP "(+-04n*G" /* display only GraphicViews; version filtering */
+#define DFLAGPAT_VIEWMAP_ALL_VERSIONS "*G" /* display only GraphicViews; no version filtering (for design) */
+#define DFLAGPAT_VIEWMAPWEB "(+-04w*G" /* display only GraphicViews available to web; version filtering */
+#define DFLAGPAT_VIEWMAP_DESIGN "(+-04*G" /* display only GraphicViews; all notes & web navs */
+
+#define DFLAGPAT_WEBPAGE "(+-*W" /* display WebPages */
+#define DFLAGPAT_WEBPAGE_NOTES "(+W-n*" /* display WebPages available to notes client */
+#define DFLAGPAT_WEBPAGE_WEB "(+W-w*" /* display WebPages available to web client */
+#define DFLAGPAT_OTHER_DLG "(+-04n*H" /* display forms that belong in compose menu */
+#define DFLAGPAT_CATEGORIZED_VIEW "(+-04n*T" /* display only categorized views */
+
+#define DFLAGPAT_DEFAULT_DESIGN "+d" /* detect default design note for it's class (used for VIEW) */
+#define DFLAGPAT_FRAMESET "(+-*#" /* display only Frameset notes */
+#define DFLAGPAT_FRAMESET_NOTES "(+#-n*" /* Frameset notes available to notes client */
+#define DFLAGPAT_FRAMESET_WEB "(+#-w*" /* Frameset notes available to web client */
+#define DFLAGPAT_SITEMAP "+m" /* SiteMap notes (actually, "mQ345") */
+#define DFLAGPAT_SITEMAP_NOTES "(+m-n*" /* sitemap notes available to notes client */
+#define DFLAGPAT_SITEMAP_WEB "(+m-w*" /* sitemap notes available to web client */
+#define DFLAGPAT_IMAGE_RESOURCE "+i" /* display only shared image resources */
+#define DFLAGPAT_IMAGE_RES_NOTES "(+i-n*" /* display only notes visible images */
+#define DFLAGPAT_IMAGE_RES_WEB "(+i-w*" /* display only web visible images */
+#define DFLAGPAT_IMAGE_WELL_RESOURCE "(+-*iv" /* display only shared image resources that
+ have more than one image across */
+#define DFLAGPAT_IMAGE_WELL_NOTES "(+-n*iv" /* display only shared image resources that
+ have more than one image across - notes only */
+#define DFLAGPAT_IMAGE_WELL_WEB "(+-w*iv" /* display only shared image resources that
+ have more than one image across - web only */
+#define DFLAGPAT_JAVA_RESOURCE "+@" /* display only shared Java resources */
+#define DFLAGPAT_JAVA_RESOURCE_NOTES "(+@-n*" /* display only shared Java resources visible to notes */
+#define DFLAGPAT_JAVA_RESOURCE_WEB "(+@-w*" /* display only shared Java resources visible to web */
+
+#define DFLAGPAT_DATA_CONNECTION_RESOURCE "+k" /* display only shared data connection resources */
+#define DFLAGPAT_DB2ACCESSVIEW "+z" /* display only db2 access views */
+
+#define DFLAGPAT_STYLE_SHEET_RESOURCE "+=" /* display only shared style sheet resources */
+#define DFLAGPAT_STYLE_SHEETS_NOTES "(+=-n*" /* display only notes visible style sheets */
+#define DFLAGPAT_STYLE_SHEETS_WEB "(+=-w*" /* display only web visible style sheets */
+#define DFLAGPAT_FILE "+g" /* display only files */
+#define DFLAGPAT_FILE_DL "(+g-~*" /* list of files that should show in file DL */
+#define DFLAGPAT_FILE_NOTES "(+g-n*" /* list of notes only files */
+#define DFLAGPAT_FILE_WEB "(+g-w*" /* list of web only files */
+#define DFLAGPAT_HTMLFILES "(+-*g>" /* display only html files */
+#define DFLAGPAT_HTMLFILES_NOTES "(+-n*g>" /* htmlfiles that are notes visible */
+#define DFLAGPAT_HTMLFILES_WEB "(+-w*g>" /* htmlfiles that are web visible */
+#define DFLAGPAT_FILE_ELEMS "(+gi=-/*" /* files plus images plus style sheets with no directory elements */
+
+#define DFLAGPAT_SERVLET "+z" /* servlets */
+#define DFLAGPAT_SERVLET_NOTES "(+z-n*" /* servlets not hidden from notes */
+#define DFLAGPAT_SERVLET_WEB "(+z-w*" /* servlets not hidden from the web */
+
+#define DFLAGPAT_WEBSERVICE "+{" /* web service */
+#define DFLAGPAT_JAVA_WEBSERVICE "(+Jj-*{" /* java web services */
+#define DFLAGPAT_LS_WEBSERVICE "*{L" /* lotusscript web services */
+
+#define DFLAGPAT_JSP "(+-*g<" /* display only JSP's */
+
+/* Shared actions must be visible to both Notes and the Web since there is
+ only one of these puppies - there is no list in the designer to get at
+ more than one. However, for completeness, I'll make the appropriate
+ patterns for the day we may want to have separateness. */
+
+#define DFLAGPAT_SACTIONS_DESIGN "+y"
+#define DFLAGPAT_SACTIONS_WEB "(+-0*y"
+#define DFLAGPAT_SACTIONS_NOTES "(+-0*y"
+
+
+/* Web server patterns */
+#define DFLAGPAT_NONWEB "+w70stVXp^" /* elements that are never used on the web */
+#define DFLAGPAT_NONWEB_EXCLUDE "-w70stVXp^" /* same flags as DFLAGPAT_NONWEB */
+/* For the rest, no need to include flags from DFLAGPAT_NONWEB, since
+ these flags are excluded in an initial pass. (see insrv\inotes\ndesdict.cpp) */
+#define DFLAGPAT_AGENTSWEB "(+-QXstmz{*" /* agents that can be run from the web */
+#define DFLAGPAT_AGNTORWEBSVCWEB "(+-QXstmz*" /* agents or web services that can be run from the web */
+#define DFLAGPAT_WEBSERVICEWEB "+{" /* web services that can be run from the web */
+#define DFLAGPAT_FORMSWEB "-U#Wi@y" /* forms usable from the web */
+#define DFLAGPAT_SUBFORMSWEB "+U" /* subforms usable from the web */
+#define DFLAGPAT_FRAMESETSWEB "+#" /* frameset from the web */
+#define DFLAGPAT_PAGESWEB "+W" /* web pages from the web */
+#define DFLAGPAT_VIEWSWEB "-G" /* views usable from the web */
+#define DFLAGPAT_NAVIGATORSWEB "+G" /* navigators usable from the web */
+#define DFLAGPAT_SHAREDFIELDSWEB "*" /* shared fields usable from the web */
+#define DFLAGPAT_ALLWEB "*" /* all design elements */
+#define DFLAGPAT_NO_FILERES_DIRS "-/" /* all design elements excluding file resource directories*/
+#define DFLAGPAT_FIRSTPATTERNCHAR "(+-*" /* patterns start with one of these */
+#define DFLAGPAT_WEBHYBRIDDB "+%" /* all WebHybridDb design elements */
+
+/* a new flags field that (will be) in the design collection. $Flags is just
+ so full that we need some wiggle room!! */
+#define DESIGN_FLAGS_EXTENDED "$FlagsExt" /* because we're just gonna need it */
+#define DESIGN_FLAGEXT_FILE_DEPLOYABLE 'D' /* for web apps, this file is ready for primetime */
+#define DESIGN_FLAGEXT_DONTREFRESH_ON_REDEPLOY 'R' /* for web apps, this file should not be replaced on redeploy */
+#define DESIGN_FLAGEXT_NOTE_HAS_DAVPROPERTIES 'P' /* for WebDAV resources. The note has a dead properties in the $DavProperties field */
+#define DESIGN_FLAGEXT_NOTE_HAS_MSPROPERTIES 'M' /* for WebDAV: indicates that certain MS properties are among the dead properites */
+#define DESIGN_FLAGEXT_DAVLOCKNULL 'N' /* for WebDAV lock null resources */
+#define DESIGN_FLAGEXT_WEBDAV_HIDDEN 'H' /* for WebDAV: the note is hidden */
+#define DESIGN_FLAGEXT_DAVCOMPUTEFORM 'C' /* for davs, a compute with form dav */
+#define DESIGN_FLAGEXT_DAVATTACH 'A' /* for davs, this one supports attachments */
+#define DESIGN_FLAGEXT_DAVGMTNORMAL 'Z' /* for davs, this one GMT normalizes */
+#define DESIGN_FLAGEXT_JAVADEBUG 'D' /* can reuse D because old use is obsolete */
+#define DESIGN_FLAGEXT_PROFILE 'F' /* profile code running in this note */
+
+/* DAV item names */
+#define DESIGN_DAV_CFNAME "$DAVComputeForm"
+#define DESIGN_DAV_ATTVIEW "$DAVAttachView"
+#define DESIGN_DAV_FLDS "$DAVFldDesc"
+#define DESIGN_DAV_FLDS_LIVE "$DAVLiveFlds"
+
+/* The agent flag is stored in the new flag so the info is not removed by older Designers when the user edits the agent */
+#define DESIGN_FLAGEXT_AGENT_ACTIVATABLE 'a' /* if the agent is activatable, if it is missing it is not */
+
+/* Compute-defined item names that are actually pseudo-items, requested
+ by NIF, that cause Compute to return some info. These are not actually
+ in any document, and if they are, will probably not work properly. */
+
+#define FIELD_COMPUTE_READERS "$C1$"
+
+/* Mail note item names */
+
+#define MAIL_MESSAGETYPE_ITEM "MessageType" /* Message type. */
+#define MAIL_MESSAGE_TYPE_ITEM "$MessageType" /* $MessageType item name */
+#define MAIL_SENDTO_ITEM "SendTo" /* SendTo item name */
+#define MAIL_COPYTO_ITEM "CopyTo" /* CopyTo item name */
+#define MAIL_REPLYTO_ITEM "ReplyTo" /* ReplyTo, used for agents */
+#define MAIL_REPLYDATE_ITEM "ReplyDate" /* ReplyDate item name */
+#define MAIL_RESPONSETO_ITEM "ResponseTo" /* ResponseTo, used for agents */
+#define MAIL_FROM_ITEM "From" /* From item name */
+#define MAIL_FROMDOMAIN_ITEM "FromDomain" /* From domain item name */
+#define MAIL_SUBJECT_ITEM "Subject" /* Subject item name */
+#define MAIL_DISPLAY_SUBJECT_ITEM "DisplaySubject" /* Used by reply form */
+#define MAIL_COMPOSEDDATE_ITEM "ComposedDate" /* Composed date item name */
+#define MAIL_POSTEDDATE_ITEM "PostedDate" /* Posted date item name */
+#define MAIL_BODY_ITEM "Body" /* Body item name */
+#define MAIL_INTENDEDRECIPIENT_ITEM "IntendedRecipient" /* Intended recipient item */
+#define MAIL_ALTINTENDEDRECIPIENT_ITEM "AltIntendedRecipient" /* Alternate Intended recipient item */
+#define MAIL_LANGINTENDEDRECIPIENT_ITEM "$LangIntendedRecipient" /* Language Tag Intended Recipient */
+#define MAIL_FAILUREREASON_ITEM "FailureReason" /* Failure reason item */
+#define MAIL_DEADFAILUREREASON_ITEM "DeadFailureReason" /* DEAD Failure reason item */
+#define MAIL_RECIPIENTS_ITEM "Recipients" /* Recipients list item */
+#define MAIL_ROUTINGSTATE_ITEM "RoutingState" /* Routing state */
+#define MAIL_ROUTINGSTATEBY_ITEM "RoutingStateBy" /* Routing state changed by indicator */
+#define MAIL_SAVED_FORM_ITEM "MailSavedForm" /* Delivery report saved form name item */
+#define MAIL_BLINDCOPYTO_ITEM "BlindCopyTo" /* Blind copy to item name */
+#define MAIL_DELIVERYPRIORITY_ITEM "DeliveryPriority" /* Delivery priority item name */
+#define MAIL_DELIVERYREPORT_ITEM "DeliveryReport" /* Delivery report request item name */
+#define MAIL_DELIVEREDDATE_ITEM "DeliveredDate" /* Delivered date item name */
+#define MAIL_DELIVERYDATE_ITEM "DeliveryDate" /* Delivery date item name (Confirmation Reports only) */
+#define MAIL_FORM_ITEM FIELD_FORM /* Form name item */
+#define MAIL_REPLY_FORM_ITEM "ReplyForm" /* Reply form, used for agents */
+#define MAIL_CATEGORIES_ITEM "Categories" /* Categories field */
+#define MAIL_FROM_CATEGORIES_ITEM "FromCategories" /* Sender's Categories field */
+#define MAIL_ROUTE_SERVERS_ITEM "RouteServers" /* List of servers routed thru */
+#define MAIL_ROUTE_TIME_ITEM "RouteTimes" /* List of TIMEDATE_PAIRS describing holding times */
+#define MAIL_RECIP_GROUPS_EXP_ITEM "RecipientGroupsExpanded" /* List of recipient group names that have been expanded */
+#define MAIL_RETURNRECEIPT_ITEM "ReturnReceipt" /* Return receipt requested? */
+#define MAIL_NAMED_ENCKEY_ITEM "NamedEncryptionKey" /* Named encryption key. */
+#define MAIL_ROUTE_HOPS_ITEM "$Hops" /* Number of routing hops still allowed. */
+#define MAIL_CORRELATION_ITEM "$Correlation" /* Arbitrary delivery report correlation value. */
+#define MAIL_FORMAT_ITEM "MailFormat" /* (E)ncapsulated */
+ /* (T)ext */
+ /* (B)oth */
+#define MAIL_TMP_FROM_ITEM "TmpFromItem" /*temp mail from item*/
+#define MAIL_IMPORTANCE_ITEM "Importance" /* Send Priority/Importance item */
+#define MAIL_QUALRECIPIENTS_ITEM "QualRecipients" /* Fully qualified Recipients list item */
+#define MAIL_ORIGNALPATH_ITEM "OriginalPath" /* Original routing path (copy of original message's FromDomain) */
+#define MAIL_TRACE_ITEM "$Trace" /* Identifies message as a trace file */
+#define MAIL_ORIG_ITEM "$Orig" /* Global Id used for Billing */
+#define MAIL_DELIVER_LOOPS_ITEM "$Loops" /* Number of forwarding loops still allowed. */
+#define MAIL_CLUSTERFAILOVER_ITEM "$MailClusterFailover" /* Server name mail was delivered to after cluster failover */
+#define MAIL_UIDL_ITEM "MailPop3UIDL"
+#define MAIL_ENTERSENDTO_ITEM "EnterSendTo" /* Enter SendTo item name */
+#define MAIL_ENTERCOPYTO_ITEM "EnterCopyTo" /* Enter CopyTo item name */
+#define MAIL_ENTERBLINDCOPYTO_ITEM "EnterBlindCopyTo" /* Enter Blind copy to item name */
+#define MAIL_INETSENDTO_ITEM "INetSendTo" /* Internet SendTo item name */
+#define MAIL_INETCOPYTO_ITEM "INetCopyTo" /* Internet CopyTo item name */
+#define MAIL_INETBLINDCOPYTO_ITEM "INetBlindCopyTo" /* Internet Blind copy to item name */
+#define MAIL_ALTSENDTO_ITEM "AltSendTo" /* Alternate Name SendTo item name */
+#define MAIL_ALTCOPYTO_ITEM "AltCopyTo" /* Alternate Name CopyTo item name */
+#define MAIL_ALTBLINDCOPYTO_ITEM "AltBlindCopyTo" /* Alternet Blind copy to item name */
+#define MAIL_ALTREPLYTO_ITEM "$AltReplyTo" /* Alternate Reply To item name */
+#define MAIL_LANGREPLYTO_ITEM "$LangReplyTo" /* Language Tag Reply To*/
+#define MAIL_ALTPRINCIPAL_ITEM "$AltPrincipal" /* Alternate Principal item name */
+#define MAIL_LANGPRINCIPAL_ITEM "$LangPrincipal" /* Language tag Principal */
+#define MAIL_INETFROM_ITEM "INetFrom" /* Internet From item name */
+#define MAIL_ALTFROM_ITEM "AltFrom" /* Alternate Name From item name */
+#define MAIL_LANGFROM_ITEM "$LangFrom" /* Language Tag From item name */
+#define MAIL_DONOTHOLD_ITEM "$DoNotHold" /* To prevent holding non-deliverable mail */
+#define MAIL_STORAGETO_ITEM "$StorageTo" /* Storage type To */
+#define MAIL_STORAGECC_ITEM "$StorageCc" /* Storage type Cc */
+#define MAIL_STORAGEBCC_ITEM "$StorageBcc" /* Storage type Bcc */
+#define MAIL_LANGTO_ITEM "$LangTo" /* Language tag To */
+#define MAIL_LANGCC_ITEM "$LangCc" /* Language tag Cc */
+#define MAIL_LANGBCC_ITEM "$LangBcc" /* Language tag Bcc */
+#define MAIL_VIEWICON_ITEM "_ViewIcon" /* Contains icon number for mail view. Displays in first icon column, from left */
+#define MAIL_VIEWICON2_ITEM "_ViewIcon2" /* Contains icon number for mail view. Displays in second icon column, from left */
+#define MAIL_EXCLUDEFROMVIEW_ITEM "ExcludeFromView" /* View(s) to exclude note from in mail file */
+#define MAIL_PRINCIPAL_ITEM "Principal" /* Mail file from which a note was sent */
+#define MAIL_ALTNAMELANGUAGETAGS_ITEM "$NameLanguageTags" /* Language Tags item. Single list of Lang Tags for set of current recipients. No Dups. */
+#define MAIL_INETREPLYTO_ITEM "$INetReplyTo" /* Internet ReplyTo item name */
+#define MAIL_INETPRINCIPAL_ITEM "$INetPrincipal" /* Internet Principal item name */
+#define MAIL_MAILER_ITEM "$Mailer" /* Name and version number of the Mailer which sent the message */
+#define MAIL_ID_ITEM "$MessageID" /* Unique ID of this message */
+#define ITEM_NAME_DONOTMODIFYINVITEES "tmpDoNotModifyInvitees" /*prevents invitees from being changed on freetime control */
+#define MAIL_CS_INVITE_WAS_DELEGATED_TO_US "MeetingInviteWasDelegatedToUs" /* Meeting invitation was delegate to us*/
+#define MAIL_CS_INVITE_WAS_DELEGATED_OFF "MeetingInviteWasDelegatedOff" /* Meeting invitation was delegate to us*/
+
+#define ITEM_NAME_DESIGN_TEMP_COLLATION "TmpViewDesignCollation"
+
+#define MAIL_APPARENTLY_FROM_ITEM "Apparently_From"
+#define MAIL_APPARENTLY_TO_ITEM "Apparently_To"
+#define MAIL_DISPOSITION_NOTIFICATION_TO_ITEM "Disposition_Notification_To"
+#define MAIL_ORIGINAL_BCC_ITEM "Originalbcc"
+#define MAIL_ORIGINAL_CC_ITEM "Originalcc"
+#define MAIL_ORIGINAL_FROM_ITEM "OriginalFrom"
+#define MAIL_ORIGINAL_PRINCIPAL_ITEM "OriginalPrincipal"
+#define MAIL_ORIGINAL_REPLY_TO_ITEM "OriginalReplyTo"
+#define MAIL_ORIGINAL_TO_ITEM "OriginalTo"
+#define MAIL_RECEIVED_ITEM "Received"
+#define MAIL_RESENT_BCC_ITEM "Resent_bcc"
+#define MAIL_RESENT_CC_ITEM "Resent_cc"
+#define MAIL_RESENT_DATE_ITEM "Resent_Date"
+#define MAIL_RESENT_FROM_ITEM "Resent_From"
+#define MAIL_RESENT_MESSAGE_ID_ITEM "Resent_Message_ID"
+#define MAIL_RESENT_REPLY_TO_ITEM "Resent_Reply_To"
+#define MAIL_RESENT_SENDER_ITEM "Resent_Sender"
+#define MAIL_RESENT_TO_ITEM "Resent_To"
+#define MAIL_RETURN_RECEIPT_TO_ITEM "Return_Receipt_To"
+#define MAIL_SENDER_ITEM "Sender"
+#define MAIL_MIME_VERSION "MIME_Version"
+#define MAIL_IMAP_RFC822_SIZE "IMAP_RFC822Size"
+#define MAIL_IMAP_BODYSTRUCTURE "IMAP_BodyStruct"
+#define MAIL_CONTENT_TYPE "$Content_Type"
+#define MAIL_FIRST_PASS "MailFirstPass"
+#define MAIL_MOODS_ITEM "$Moods"
+#define MAIL_SENDERTAG_ITEM "SenderTag"
+#define MAIL_TMPSENDERTAG_ITEM "tmpSenderTag"
+#define MAIL_DISCLAIMED_ITEM "$Disclaimed"
+
+#define MAILBOX_ADMIN_ROLE "[MailboxAdmin]"
+
+#define MAIL_GURU_SCORE_ITEM "DSFScore"
+#define MAIL_GURU_RCPT_ITEM "DSFRcpt"
+#define MAIL_GURU_TO_ITEM "DSFTo"
+#define MAIL_GURU_FROM_ITEM "DSFFrom"
+#define MAIL_GURUVOTE_REPORT_ITEM "DSFVoteReport"
+#define MAIL_GURUVOTE_VOTE_ITEM "DSFVoteVote"
+
+#define MAIL_DNSBL_FILTER_ITEM "$DNSBLSite" /* Blacklist tag */
+#define MAIL_DNSWL_FILTER_ITEM "$DNSWLSite" /* Whitelist tag */
+#define MAIL_FILTER_ACTIONS_ITEM "$FilterActions"
+#define MAIL_FILTER_BY_ITEM "$FilterBy"
+#define MAIL_SENDTO_NONRESPONDERS "Non_Responders"
+#define MAIL_CS_LOOPING_FACTOR "LoopingFactor" /*temp note item to identify for the template
+ whether a notice has "looped" (I delegated this
+ meeting off and it's come back) or cross-delegate
+ (two people have delegated an invitation for the
+ same meeting to me) */
+#define MAIL_REPLYFORWARD_ITEM "$RespondedTo" /* text item, value = 1 if replied, 2 = forwarded, 3 = both */
+#define MAIL_REPLYFORWARD_NONE "0"
+#define MAIL_REPLYFORWARD_REPLY "1"
+#define MAIL_REPLYFORWARD_FORWARD "2"
+#define MAIL_REPLYFORWARD_REPLYFORWARD "3"
+
+/* POP3 view names */
+#define MAIL_POP3_UIDL_VIEW "($POP3UIDL)"
+
+/* Appointment form item names */
+
+#define MAIL_APPT_BUSYNAME_ITEM "$BusyName" /* Person/resource the appointment is for */
+#define MAIL_APPT_STARTTIME_ITEM "StartDateTime" /* Start time of appointment */
+#define MAIL_APPT_ENDTIME_ITEM "EndDateTime" /* End time of appointment */
+#define MAIL_APPT_SEQUENCE_ITEM "$Sequence" /* Sequence # of updates */
+#define MAIL_APPT_BUSYPRIORITY_ITEM "$BusyPriority" /* Busy/Penciled-in/etc. */
+#define MAIL_APPT_ATTENDEE_ITEM "Attendees" /* List of people for which the following items apply */
+#define MAIL_APPT_ATTENDEE_STATE_ITEM "ORGState" /* Chairman, attendee, resource */
+#define MAIL_APPT_ATTENDEE_STATUS_ITEM "ORGStatus" /* Deleted, etc. */
+#define MAIL_APPT_ATTENDEE_OPTIONAL_ITEM "OPTIONAL" /* If TRUE, attendee is optional */
+#define MAIL_APPT_PREV_BUSYNAME_ITEM "$PrevBusyName" /* Previous Person/resource(s) the appointment is for */
+#define RESOURCE_NAMESPACE_RESOURCES "($RLookup)" /* View containing resources sorted by name */
+#define RESOURCE_NAMESPACE_RESERVATIONS "($FindReservation)" /* View containing reservations by name and apptunid */
+#define RESOURCE_NAMESPACE_WAITINGAPPROVAL "($FindWaitingApproval)" /* Like $FindReservation but contains those waiting for approval */
+#define MAIL_REPEAT_LOOKUP_NAMESPACE "($RepeatLookup)" /* View containing repeat replies/updates */
+#define MAIL_REPEAT_INSTANCE_LOOKUP_NAMESPACE "($RepeatInstanceLookup)" /* View containing repeat instances */
+#define MAIL_JOURNALLING_FLAG_ITEM "$JournalResponsibility" /* If present, message should be journalled. The
+ * value indicates if it should be journalled locally
+ * or on another server. */
+
+
+#define JOURNALLING_FLAG_DONT_JOURNAL 0
+#define JOURNALLING_FLAG_LOCAL_JOURNAL 1
+#define JOURNALLING_FLAG_REMOTE_JOURNAL 2
+#define JOURNALLING_FLAG_JOURNAL_COMPLETE 3
+#define JOURNALLING_FLAG_DONT_JOURNAL_STR "0"
+#define JOURNALLING_FLAG_LOCAL_JOURNAL_STR "1"
+#define JOURNALLING_FLAG_REMOTE_JOURNAL_STR "2"
+#define JOURNALLING_FLAG_JOURNAL_COMPLETE_STR "3"
+#define MAIL_JOURNALLING_TEMPLATE_NAME "mailjrn.ntf"
+
+#define MAIL_ROUTINGSTATEBY_ROUTER_STR "1"
+#define MAIL_ROUTINGSTATEBY_RULE_STR "2"
+
+/* Internet Message Note items and definitions (for Internet Mail and Internet News) */
+
+#define IMSG_RFC822_FILENAME_ITEM "$IntMailMsgFileName" /* Name of the attachment that contains the BLOB. */
+ /* This contains the string 'Mail' because of */
+ /* history and changing it now would affect existing */
+ /* databases and code. */
+
+#define IMSG_ITEMIZE_ERROR_ITEM "$ItemizeError" /* non-zero if an error occurred during itemize. if an */
+ /* error occurs, the original internet message is at- */
+ /* tached to the message (IMSG_RFC822_FILENAME_ITEM) */
+ /* and the error text is stuffed into the message's body*/
+ /* item. */
+
+#define MAIL_TMP_MESSAGE_ID_DOMAIN "LocalDomain" /* Used as a place holder on constructed MessageIDs */
+
+#define MAIL_MIME_CHARSET "MIMEMailCharset" /* field with charset value */
+#define MAIL_MIME_HEADER_CHARSET "MIMEMailHeaderCharset" /* Charset for headers: upper 16 bit: charset, lower 16 bit: Encoding */
+
+/*
+ * Person documents contain an item (MessageStorage) which indicates each person's preference for how
+ * messages delivered to them will be stored. Definitions of the valid values for this item are named
+ * IMSG_PREFERENCE_XXX.
+ *
+ * Mail messages contain an item ($MessageStorage) which indicates the actual storage format of the
+ * message if it has been converted. Definitions of the valid values for this item are named
+ * IMSG_STORAGE_XXX. This item is deleted from messages when they are delivered by the router.
+ *
+ * Routines which store messages or convert messages accept arguments which specify the required
+ * storage format. These routines accept values named IMSG_STORAGE_XXX.
+ *
+ * As a performance optimization for the router, there is another item which can exist on a note
+ * which indicates that the note is stored in native MIME. This item is $NoteHasNativeMIME.
+ */
+
+#define IMSG_STORAGE_ITEM "$MessageStorage" /* Describes how mail is stored. See IMSG_STORAGE_XXX */
+
+#define IMSG_STORAGE_UNKNOWN 0xFF /* can't find storage type */
+#define IMSG_STORAGE_CDRECORDS 0 /* Store as cd records only */
+#define IMSG_STORAGE_CDRECORDS_AND_RFC822 1 /* Store as cd records & attachment of original message */
+#define IMSG_STORAGE_RFC822 2 /* Store original message as attachment (no cdrecords) */
+#define IMSG_STORAGE_NATIVE_MIME 3 /* Store headers & parts as separate items (without conversion) or CD */
+#define IMSG_STORAGE_HAIKU 4 /* Store for Haiku users only */
+/* Be sure to update count (IMSG_STORAGE_FORMATS) if new formats are added */
+
+#define IMSG_STORAGE_FORMATS 5 /* Count of known storage formats */
+
+#define IMSG_PREFERENCE_UNKNOWN 0xFF /* can't find preference type */
+#define IMSG_PREFERENCE_NOTES 0 /* V4->CD, V5->CD or MIME */
+#define IMSG_PREFERENCE_NOTES_AND_MIME 1 /* V4->CD and MIME blob, V5->CD or MIME */
+#define IMSG_PREFERENCE_MIME 2 /* V4->MIME blob only, V5->Native MIME */
+#define IMSG_PREFERENCE_HAIKU 3 /* V4->N/A, V5->Native MIME+Haiku fields */
+
+#define IMSG_PREFERENCE_FORMATS 4 /* Count of known preference formats */
+
+#define IMSG_RFC822_MSG_SIZE_ITEM "$RFC822MessageSize" /* Message size field (used by POP3 client) */
+#define IMSG_RFC822_MSG_FILE_NAME "$RFC822.eml" /* Attached "MIME BLOB" name */
+#define IMSG_SMTP_ORIGINATOR_ITEM "SMTPOriginator" /* RFC821 message originator */
+#define IMSG_SMTP_RET_HDRS_ITEM "SMTPReturnHdrs" /* If HDRS, return only headers with non DSN */
+#define IMSG_SMTP_RET_HDRS_HDRS "HDRS"
+#define IMSG_SMTP_ENVID_ITEM "SMTPEnvid" /* If ESMTP DSN is supported, ENVID to relay */
+#define IMSG_SMTP_DSN_RCPTS_ITEM "SMTPDSNRecipients" /* If ESMTP DSN is supported, per rcpt info */
+#define IMSG_SMTP_DSN_DELIVERY_STATUS "SMTPDSNDeliveryStatus" /* RFC822 formatted delivery status */
+#define IMSG_SMTP_DSN_DELIVERY_REASON "SMTPDSNDeliveryReason" /* RFC822 free form (i.e., prose) delivery information */
+#define IMSG_SMTP_DSN_RECEIVED_ITEM "SMTPRcvd" /* Received items from the embedded rfc822 message in a Delivery Status Report */
+#define IMSG_SMTP_DSN_TYPE_ITEM "SMTPDSNType" /* Type of delivery status report (failed, delayed, relayed etc. */
+#define IMSG_SMTP_DSN_DATE_ITEM "SMTPDSNDate" /* Posted Date of the delivery status report */
+#define IMSG_SMTP_DSN_TYPE_FAILED_STR "0"
+#define IMSG_SMTP_DSN_TYPE_DELAYED_STR "1"
+#define IMSG_SMTP_DSN_TYPE_DELIVERED_STR "2"
+#define IMSG_SMTP_DSN_TYPE_RELAYED_STR "3"
+#define IMSG_SMTP_DSN_TYPE_EXPANDED_STR "4"
+
+#define ITEM_MIMEHEADERS "$MIMEHeaders"
+#define ITEM_MIMETRACK "$MIMETrack"
+#define ITEM_MIME_ENCAPSULATED "$MIMEEncapsulated"
+#define ITEM_IS_NATIVE_MIME "$NoteHasNativeMIME"
+#define ITEM_NOT_FROM_NOTES "$SMTPNotFromNotes"
+#define ITEM_KEEP_NOTES_ITEMS "$SMTPKeepNotesItems"
+
+#define ITEM_HEADERS_CONVERTED "$ExportHeadersConverted"
+
+/* Calendar profile form related */
+
+/* On a profile are eight fields that relate to when a users is available:
+
+ The AvailableDays item corresponds to the checkboxes allowing the user
+ to choose which days of the week they work. The resulting item
+ will be a textlist which contains the days of the week that they
+ work.
+ For the days of the week that the user does work, the time ranges are
+ read and for each day and assimilated into one item in the busytime
+ database that represents the days and time the user or resource
+ is available for scheduling.
+ The item is encoded as follows:
+ DateTime.Lower.Date - a day that corresponds to the day of the week
+ .Time - start time of an interval for that day the user works
+ .Upper.Date - the same day as the Lower
+ .Time - end time of an interval for that day the user works
+
+ These values will repeat for the various times during the day for
+ every day of the week that the user works.
+
+ (i.e. The default configuration will be: (for Monday through Friday)
+
+ A Monday, 9:00 AM - A Monday, 12:00 PM
+ A Monday, 1:00 PM - A Monday, 5:00 PM)
+
+ NOTE: The encoding does not care which real date is used, it just
+ determines what day of the week the date correspondes to..
+*/
+
+#define MAIL_CALENDAR_PROFILE_WORKDAYS_ITEM "$WorkDays"
+#define MAIL_CALENDAR_PROFILE_WORK_AVAILABLEDAYS_ITEM "$AvailableDays"
+#define MAIL_CALENDAR_PROFILE_TZDISPLAY_ITEM "fDisplayAltTimeZone"
+#define MAIL_CALENDAR_PROFILE_CURTIMEZONE_ITEM "CurrentTimeZone"
+#define MAIL_CALENDAR_PROFILE_ALTTIMEZONE_ITEM "AltTimeZone"
+#define MAIL_CALENDAR_PROFILE_CURTIMEZONELBL_ITEM "CurrentTZLabel"
+#define MAIL_CALENDAR_PROFILE_ROLLINGVIEW_ITEM "$RollingView"
+#define MAIL_CALENDAR_PROFILE_ALTTIMEZONELBL_ITEM "AltTZLabel"
+#define MAIL_CALENDAR_PROFILE_OWNER_ITEM "Owner" /* Owner field in calendar profile form */
+#define MAIL_CALENDAR_PROFILE_ALTOWNER_ITEM "AltOwner" /* AltOwner field in calendar profile form */
+#define MAIL_CALENDAR_PROFILE_LANGOWNER_ITEM "$LangOwner" /* LangOwner field in calendar profile form */
+#define MAIL_CALENDAR_PROFILE_WORK_WEEKDAYPREFIX "$Times"
+#define MAIL_CALENDAR_PROFILE_WORK_WEEKDAYSUFFIX ""
+#define MAIL_CALENDAR_PROFILE_WORK_SUNDAY_ITEM "$Times1"
+#define MAIL_CALENDAR_PROFILE_WORK_MONDAY_ITEM "$Times2"
+#define MAIL_CALENDAR_PROFILE_WORK_TUESDAY_ITEM "$Times3"
+#define MAIL_CALENDAR_PROFILE_WORK_WEDNESDAY_ITEM "$Times4"
+#define MAIL_CALENDAR_PROFILE_WORK_THURSDAY_ITEM "$Times5"
+#define MAIL_CALENDAR_PROFILE_WORK_FRIDAY_ITEM "$Times6"
+#define MAIL_CALENDAR_PROFILE_WORK_SATURDAY_ITEM "$Times7"
+#define MAIL_CALENDAR_PROFILE_ENABLE_ALARMS_ITEM "EnableAlarms"
+#define MAIL_CALENDAR_PROFILE_APPROVALLIST_ITEM "$ApprovalList"
+#define MAIL_CALENDAR_PROFILE_DEFAULTDURATION_ITEM "DefaultDuration"
+#define MAIL_CALENDAR_PROFILE_EXCLUDEFROMALL_ITEM "ExcludeFromAll"
+#define MAIL_CALENDAR_PROFILE_EXCLUDEFROMSENT_ITEM "ExcludeFromSent"
+#define MAIL_CALENDAR_PROFILE_FORWARDINVITEENOTIFICATIONTO_ITEM "CalForwardInviteeNotificationTo"
+#define MAIL_CALENDAR_PROFILE_FORWARDCHAIRNOTIFICATIONTO_ITEM "CalForwardChairNotificationTo"
+#define MAIL_CALENDAR_PROFILE_FORWARDNOTIFICATIONPRIVATEMODE_ITEM "CalForwardPrivateMode"
+#define MAIL_CALENDAR_PROFILE_AUTOPROCESSLIST_ITEM "AutoprocessUserList"
+#define MAIL_CALENDAR_PROFILE_AUTOPROCESSTYPE_ITEM "AutoprocessType"
+#define MAIL_CALENDAR_PROFILE_AUTOPROCESSFORWARDTO_ITEM "AutoprocessForwardTo"
+#define MAIL_CALENDAR_PROFILE_AUTOPROCESSMTGS_ITEM "AutoprocessMeetings"
+#define MAIL_CALENDAR_PROFILE_AUTOPROCESSCONFLICTOPTIONS_ITEM "AutoprocessConflictOptions"
+#define MAIL_CALENDAR_PROFILE_AUTOPROCESS_ITEMCONFLICTOPTIONS_ITEM "AutoprocessItemConflictOptions"
+#define MAIL_CALENDAR_PROFILE_V45AUTOPROCESSLIST_ITEM "MeetingsPeople"
+#define MAIL_CALENDAR_PROFILE_AUTOREMOVEFROMINBOX_ITEM "AutoRemoveFromInbox"
+#define MAIL_CALENDAR_PROFILE_ALARMSENABLED_ITEM "EnableAlarms"
+#define MAIL_CALENDAR_PROFILE_ALARMAPPTLEAD_ITEM "AppointmentLead"
+#define MAIL_CALENDAR_PROFILE_ALARMANNLEAD_ITEM "AnniversaryLead"
+#define MAIL_CALENDAR_PROFILE_ALARMEVENTLEAD_ITEM "EventLead"
+#define MAIL_CALENDAR_PROFILE_ALARMREMINDERLEAD_ITEM "ReminderLead"
+#define MAIL_CALENDAR_PROFILE_ALARMTODOLEAD_ITEM "TaskLead"
+/* Tasks are now called ToDos. Define the old deprecated name as alias to new */
+#define MAIL_CALENDAR_PROFILE_ALARMTASKLEAD_ITEM MAIL_CALENDAR_PROFILE_ALARMTODOLEAD_ITEM
+#define MAIL_CALENDAR_PROFILE_ALARMAPPTENABLED_ITEM "SetAlarmAppointment"
+#define MAIL_CALENDAR_PROFILE_ALARMANNENABLED_ITEM "SetAlarmAnniversary"
+#define MAIL_CALENDAR_PROFILE_ALARMEVENTENABLED_ITEM "SetAlarmEvent"
+#define MAIL_CALENDAR_PROFILE_ALARMREMINDERENABLED_ITEM "SetAlarmReminder"
+#define MAIL_CALENDAR_PROFILE_ALARMTODOENABLED_ITEM "SetAlarmTask"
+/* Tasks are now called ToDos. Define the old deprecated name as alias to new */
+#define MAIL_CALENDAR_PROFILE_ALARMTASKENABLED_ITEM MAIL_CALENDAR_PROFILE_ALARMTODOENABLED_ITEM
+#define MAIL_CALENDAR_PROFILE_ALARMITEM_DISABLED '0'
+#define MAIL_CALENDAR_PROFILE_ALARMITEM_ENABLED '1'
+#define MAIL_CALENDAR_PROFILE_CONFLICT_APPOINTMENT_ITEM "ConflictMeeting"
+#define MAIL_CALENDAR_PROFILE_CONFLICT_ANNIVERSARY_ITEM "ConflictAnniversary"
+#define MAIL_CALENDAR_PROFILE_CONFLICT_EVENT_ITEM "ConflictEvent"
+#define MAIL_CALENDAR_PROFILE_CONFLICTITEM_DISABLED '0'
+#define MAIL_CALENDAR_PROFILE_CONFLICTITEM_ENABLED '1'
+#define MAIL_CALENDAR_PROFILE_PREVENTREPLIESINBOX_ITEM "PreventRepliesFromInbox"
+#define MAIL_CALENDAR_PROFILE_CALENDARMANAGER_ITEM "CalendarManager"
+#define MAIL_CALENDAR_PROFILE_MANAGECALENDARSFOR_ITEM "ManageCalendarsFor"
+#define MAIL_CALENDAR_PROFILE_BUSYTIMEHARVESTOPTOUT_ITEM "BusyTimeHarvestOptOut"
+#define MAIL_CALENDAR_PROFILE_BUSYTIMEHARVESTOPTOUT_DISABLED '0'
+#define MAIL_CALENDAR_PROFILE_BUSYTIMEHARVESTOPTOUT_DISABLED_STR "0"
+#define MAIL_CALENDAR_PROFILE_BUSYTIMEHARVESTOPTOUT_ENABLED '1'
+#define MAIL_CALENDAR_PROFILE_BUSYTIMEHARVESTOPTOUT_ENABLED_STR "1"
+#define MAIL_CALENDAR_PROFILE_ALLOWBUSYDETAILSACCESS_ITEM "AllowBusyDetailsAccess"
+#define MAIL_CALENDAR_PROFILE_DETAILINDEX_ITEM "DetailIndex"
+#define MAIL_CALENDAR_PROFILE_DETAILPREFIX "Detail_"
+#define MAIL_CALENDAR_PROFILE_EXTERNAL_ADDRESS "ExternalAddress"
+#define MAIL_CALENDAR_PROFILE_ALWAYS_AVAILABLE "AlwaysAvailable"
+#define MAIL_CALENDAR_PROFILE_CONTROVERSIALFIELDS_ITEM "ControversialFields" /* Controversial Calendar details to harvest */
+
+
+/* Mail delegation profile form related */
+
+#define MAIL_DELEGATION_PROFILE_OWNER_ITEM "Owner"
+#define MAIL_DELEGATION_ALLOWBUSYACCESS_ITEM "AllowBusyAccess"
+#define MAIL_DELEGATION_ALLOWDETAILACCESS_ITEM "AllowDetailAccess"
+#define MAIL_DELEGATION_DISABLEALLDETAILACCESS_ITEM "DisableAllDetailAccess"
+
+#define MAIL_UIDL_ITEM "MailPop3UIDL"
+
+/*BEGIN_SAMETIME*/
+/* Online meeting (Sametime) Calendaring & Scheduling related item names */
+#define MAIL_CS_ST_ONLINEPLACETORESERVE_ITEM "OnlinePlaceToReserve"
+#define MAIL_CS_ST_ONLINEPLACE_ITEM "OnlinePlace"
+
+#define MAIL_CS_ST_SAMETIMESERVER_ITEM "SametimeServer"
+#define MAIL_CS_ST_ONLINEMEETINGFLAG_ITEM "OnlineMeetingFlag"
+#define MAIL_CS_ST_MEETINGTYPE_ITEM "MeetingType"
+#define MAIL_CS_ST_RESTRICTEDTOINVITELIST_ITEM "RestrictToInviteList"
+#define MAIL_CS_ST_RESTRICTEDTOINVITEFLAG_ITEM "RestrictAttendence"
+#define MAIL_CS_ST_ALLOWATTACHMENTVIEWING_ITEM "AllowAttachmentViewing"
+#define MAIL_CS_ST_WHITEBOARDCONTENT_ITEM "WhiteBoardContent"
+#define MAIL_CS_ST_APPTUNIDURL_ITEM "ApptUNIDURL"
+#define MAIL_CS_ST_CONFERENCEDATABASE_ITEM "ConferenceDatabase"
+#define MAIL_CS_ST_ONLINEMEETINGFLAG_ITEM "OnlineMeetingFlag"
+#define MAIL_CS_ST_FILELIST_ITEM "FileList"
+#define MAIL_CS_ST_SENDATTACHMENTS_ITEM "SendAttachments"
+#define MAIL_CS_ST_AUDIOVIDEOFLAGS_ITEM "AudioVideoFlags"
+#define MAIL_CS_ST_SAMETIMESERVERNETADDRESS_ITEM "SametimeServerNetAddress"
+#define MAIL_CS_ST_MODERATOR_ITEM "Moderator"
+#define MAIL_CS_ST_PRESENTERS_ITEM "Presenters"
+#define MAIL_CS_ST_MEETINGPASSWORD_ITEM "MeetingPassword"
+#define MAIL_CS_ST_ONLINEMEETING_ITEM "OnlineMeeting"
+
+/* Saved transcript related item names */
+#define IM_TRANSCRIPT_ITEM "$IMTranscript"
+#define IM_ORIGINATOR_ITEM "$IMOriginator"
+
+/*END_SAMETIME*/
+
+
+
+
+/* Calendaring & Scheduling related item names */
+#define MAIL_CS_PERSONAL_NOTES_ITEM "Notes" /* Personal meeting notes item */
+#define MAIL_CS_KEEPPOSTED_ITEM "KeepPosted" /* Determines if participant wants to be kept notified of updates */
+#define MAIL_CS_KEEPPOSTED_DISABLED '0'
+#define MAIL_CS_KEEPPOSTED_ENABLED '1'
+
+#define MAIL_CS_SEQUENCENUM_ITEM "SequenceNum" /* Sequence # of event notice */
+#define MAIL_CS_UPDATE_SEQUENCENUM_ITEM "UpdateSeq" /* Update sequence # of event */
+
+#define MAIL_CS_NOTICETYPE_ITEM "NoticeType" /* Type of notice being sent */
+#define MAIL_CS_ORIGINAL_NOTICETYPE_ITEM "OriginalNoticeType"
+
+#define MAIL_CS_ASSIGNSTATE_ITEM "AssignState" /* Used by todos for communicating status */
+#define MAIL_CS_CSVERSION_ITEM "$CSVersion"
+#define MAIL_CS_APPOINTMENTTYPE_ITEM "AppointmentType"
+#define MAIL_CS_TODOTYPE_ITEM "TaskType" /* The type of todo. Item is "TaskType" for backwards compat */
+/* Tasks are now called ToDos. Define the old deprecated name as alias to new */
+#define MAIL_CS_TASKTYPE_ITEM MAIL_CS_TODOTYPE_ITEM
+#define MAIL_CS_CHAIR_ITEM "Chair"
+#define MAIL_CS_CHAIRDOMAIN_ITEM "ChairDomain"
+#define MAIL_CS_DELEGATOR_ITEM "Delegator"
+#define MAIL_CS_ALTDELEGATOR_ITEM "AltDelegator"
+#define MAIL_CS_LANGDELEGATOR_ITEM "$LangDelegator"
+#define MAIL_CS_DELEGATETO_ITEM "Delegee"
+#define MAIL_CS_REQUIREDATTENDEES_ITEM "RequiredAttendees"
+#define MAIL_CS_OPTIONALATTENDEES_ITEM "OptionalAttendees"
+#define MAIL_CS_FYIATTENDEES_ITEM "FYIAttendees"
+#define MAIL_CS_REQUIREDASSIGNEES_ITEM "AssignedTo"
+#define MAIL_CS_OPTIONALASSIGNEES_ITEM "OptionalAssignedTo"
+#define MAIL_CS_ALTCHAIR_ITEM "AltChair"
+#define MAIL_CS_LANGCHAIR_ITEM "$LangChair"
+#define MAIL_CS_FYIASSIGNEES_ITEM "FYIAssignedTo"
+#define MAIL_CS_ROOMTORESERVE_ITEM "RoomToReserve"
+#define MAIL_CS_ROOM_ITEM "Room"
+#define MAIL_CS_RESOURCESTORESERVE_ITEM "Resources"
+#define MAIL_CS_RESOURCES_ITEM "RequiredResources"
+#define MAIL_CS_BOOKFREETIME_ITEM "BookFreeTime"
+#define MAIL_CS_BOOKFREETIME_DISABLED '0'
+#define MAIL_CS_BOOKFREETIME_ENABLED '1'
+#define MAIL_CS_REMOVEDNAMES_ITEM "Uninvited"
+#define MAIL_CS_TOREMOVENAMES_ITEM "tmpRemoveNames"
+#define MAIL_CS_TOREMOVERRNAMES_ITEM "tmpRemoveRRNames"
+#define MAIL_CS_TMPOWNER_ITEM "tmpOwner"
+#define MAIL_CS_TOPIC_ITEM "Topic"
+#define MAIL_CS_DUESTATE_ITEM "DueState"
+#define MAIL_CS_RESOURCENAME_ITEM "ResourceName"
+#define MAIL_CS_STATUS_ITEM "Status"
+#define MAIL_CS_STARTDATE_ITEM "StartDate"
+#define MAIL_CS_STARTTIME_ITEM "StartTime"
+#define MAIL_CS_STARTTIMEZONE_ITEM "StartTimeZone"
+#define MAIL_CS_ENDDATE_ITEM "EndDate"
+#define MAIL_CS_ENDTIME_ITEM "EndTime"
+#define MAIL_CS_ENDTIMEZONE_ITEM "EndTimeZone"
+#define MAIL_CS_DUEDATETIME_ITEM "DueDateTime"
+#define MAIL_CS_APPENDSTARTTIME_ITEM "AppendStartTime"
+#define MAIL_CS_APPENDENDTIME_ITEM "AppendEndTime"
+#define MAIL_CS_APPTUNID_ITEM "ApptUNID"
+#define MAIL_CS_CALENDARDATETIME_ITEM "CalendarDateTime"
+#define MAIL_CS_TIMERANGE_ITEM "TimeRange"
+#define MAIL_CS_NEWDATE_ITEM "NewDate"
+#define MAIL_CS_NEWTIMERANGE_ITEM "NewTimeRange"
+#define MAIL_CS_NEWROOM_ITEM "NewRoom"
+#define MAIL_CS_NEWSTARTDATE_ITEM "NewStartDate"
+#define MAIL_CS_NEWSTARTTIME_ITEM "NewStartTime"
+#define MAIL_CS_NEWENDDATE_ITEM "NewEndDate"
+#define MAIL_CS_NEWENDTIME_ITEM "NewEndTime"
+#define MAIL_CS_NEWSTARTTIMEZONE_ITEM "NewStartTimeZone"
+#define MAIL_CS_NEWENDTIMEZONE_ITEM "NewEndTimeZone"
+#define MAIL_CS_BROADCAST_ITEM "Broadcast"
+#define MAIL_CS_BROADCAST_DISABLED '0'
+#define MAIL_CS_BROADCAST_ENABLED '1'
+#define MAIL_CS_DUEDATE_ITEM "DueDate"
+#define MAIL_CS_FLAGS_ITEM "$CSFlags"
+#define MAIL_CS_MAILINDB_ITEM "MailInDatabaseList"
+#define MAIL_CS_GROUP_REFRESHMODE_ITEM "$GroupScheduleRefreshMode"
+#define MAIL_CS_REFRESH_OPTIMAL '0'
+#define MAIL_CS_REFRESH_FULL '1'
+#define MAIL_CS_LEGEND_ENABLED_ITEM "$GroupScheduleShowLegend"
+#define MAIL_CS_LEGEND_DISABLED '0'
+#define MAIL_CS_LEGEND_ENABLED '1'
+#define MAIL_CS_COMPLETEDDATETIME_ITEM "CompletedDateTime"
+#define MAIL_CS_PREVENTREPLIES_ITEM "$PreventReplies"
+#define MAIL_CS_PREVENTREPLIES_DISABLED '0'
+#define MAIL_CS_PREVENTREPLIES_ENABLED '1'
+#define MAIL_CS_RESERVATION_PURPOSE_ITEM "Purpose"
+#define MAIL_CS_PREVDELEGEE_ITEM "PrevDelegee"
+#define MAIL_CS_PREVENTDELEGATION_ITEM "PreventDelegate"
+#define MAIL_CS_PREVENTDELEGATION_DISABLED '0'
+#define MAIL_CS_PREVENTDELEGATION_ENABLED '1'
+#define MAIL_CS_PREVENTCOUNTER_ITEM "PreventCounter"
+#define MAIL_CS_RESOURCEOWNER_ITEM "ResourceOwner"
+#define MAIL_CS_ALTREQUIRED_ITEM "AltRequiredNames"
+#define MAIL_CS_ALTOPTIONAL_ITEM "AltOptionalNames"
+#define MAIL_CS_ALTFYI_ITEM "AltFYINames"
+#define MAIL_CS_ALTDELEGATETO_ITEM "AltDelegeeName"
+#define MAIL_CS_LANGDELEGATETO_ITEM "$LangDelegee"
+#define MAIL_CS_INETREQUIRED_ITEM "INetRequiredNames"
+#define MAIL_CS_INETOPTIONAL_ITEM "INetOptionalNames"
+#define MAIL_CS_INETFYI_ITEM "INetFYINames"
+#define MAIL_CS_STORAGEREQUIRED_ITEM "StorageRequiredNames"
+#define MAIL_CS_STORAGEOPTIONAL_ITEM "StorageOptionalNames"
+#define MAIL_CS_STORAGEFYI_ITEM "StorageFYINames"
+#define MAIL_CS_STATUS_UPDATE "StatusUpdate" /* contains comment for accept/decline/delegate with comment */
+#define MAIL_CS_TRACK_ITEM "$CSTrack"
+#define MAIL_CS_MANAGEDFOR_ITEM "ManagedFor"
+#define MAIL_CS_AUTOPROCESSINFO_ITEM "$AutoprocessInfo"
+#define MAIL_CS_ACTIONTYPE_ITEM "ActionType" /* Contains action in progress for Managed Update */
+#define MAIL_CS_MGRSECTION_ITEM "CalendarMgrSection"
+#define MAIL_CS_COPYITEMS "$CSCopyItems"
+#define MAIL_CS_SENDMEMOFROM_ITEM "$CSMemoFrom"
+#define MAIL_CS_ORIGINAL_DELEGATOR "OriginalDelegator"
+#define MAIL_CS_DELEGATETO_LIST "DelegateToList"
+
+#define MAIL_CS_WI_MODIFIED_ITEM "$WFModified" /* Used to indicate which Watched Items have been modified*/
+#define MAIL_CS_WISL_ITEM "$CSWISL" /* Watched Item Sequence List */
+#define MAIL_CS_WATCHEDITEMS_ITEM "$WatchedItems" /* Tells us which items are supposed to be watched */
+#define MAIL_CS_NO_TZONE_ITEM "NoTZInfo" /* Used to indicate that there is no Timezone info on the note (TZ info was introduced in R6) */
+
+#define MAIL_CS_MINIVIEW_ITEM "$MiniView" /* if one, notice appears in the miniview */
+ /* if zero or empty value, notice does not appear in the miniview */
+#define MAIL_CS_MINIVIEW_YES '1'
+#define MAIL_CS_MINIVIEW_NO '0'
+
+#define MAIL_CS_FROMPREFERREDLANG_ITEM "$FromPreferredLanguage"
+
+#define MAIL_CS_RNR_REQUEST_STATUS_ITEM "RQStatus" /* R7: R&R Request status item */
+#define MAIL_CS_RNR_REQUEST_TENTATIVE 'T' /* R7: Tenatively booked; awaiting RnRMgr approval */
+#define MAIL_CS_RNR_REQUEST_ACCEPTED 'A' /* R7: Accepted; approved and processed by RnRMgr */
+#define MAIL_CS_RNR_REQUEST_REJECTED 'R' /* R7: Rejected; denied by RnRMgr */
+#define MAIL_CS_RNR_REQUEST_PROCESSED 'P' /* R7: Processed; belongs outside R&R so it was processed by RnRMgr */
+
+#define MAIL_CS_RNR_BLOCKER_ITEM "$CSBlocker" /* R7: R&R Request 'blocker' indicator item, put on R7 request that
+ ** blocks other reservations beyond a particular date.
+ */
+
+#define RNR_SERVER_PROFILE_FORM "ServerProfile" /* R7: R&R Server Profile form name */
+
+/* The following are new R&R related items / values for D7 related to the new
+** RnRMgr and R&R autoprocessing and server status. They are used on R&R server
+** profile docs stored in the busytime dB OR in CLDBDIR.NSF
+*/
+#define RNR_SERVER_FULLYINIT_ITEM "FullyInitd" /* R7: R&R Server fully initialized status */
+#define RNR_SERVER_FULLYINIT_YES 'Y' /* R7: R&R Server is "fully initialized" */
+#define RNR_SERVER_FULLYINIT_NO 'N' /* R7: R&R Server is NOT "fully initialized" */
+
+#define RNR_SERVER_TOOKCONTROL_ITEM "TookControl" /* R7: TIMEDATE when R&R Server took autoprocessing control */
+#define RNR_SERVER_RETURNCONTROL_ITEM "ReturnControl" /* R7: TIMEDATE when R&R Server returned autoprocessing control
+ ** to the Home Server.
+ */
+#define RNR_DECLINE_REASON_ITEM "DeclineReason" /* R5(?): Item indication why, typically, owner rejected the reservation.
+ ** For R7 we now have RnRMgr adding text such as 'Invalid interval...', etc
+ */
+
+/* C&S Repeating Entry item names */
+
+#define MAIL_CS_ORGREPEAT_ITEM "OrgRepeat"
+#define MAIL_CS_ORGTABLE_ITEM "OrgTable"
+#define MAIL_CS_ORGCONFIDENTIAL_ITEM "OrgConfidential"
+#define MAIL_CS_REPEATS_ITEM "Repeats"
+#define MAIL_CS_REPEAT_DATES_ITEM "RepeatDates"
+#define MAIL_CS_REPEAT_END_DATES_ITEM "RepeatEndDates" /* new with Notes6 */
+#define MAIL_CS_REPEAT_INSTANCE_DATES_ITEM "RepeatInstanceDates"
+#define MAIL_CS_REPEAT_BASE_DATE_ITEM "OriginalStartDate"
+#define MAIL_CS_REPEAT_START_DATE_ITEM "RepeatStartDate"
+#define MAIL_CS_REPEAT_FOR_ITEM "RepeatFor"
+#define MAIL_CS_REPEAT_FORUNIT_ITEM "RepeatForUnit"
+#define MAIL_CS_REPEAT_UNIT_ITEM "RepeatUnit"
+#define MAIL_CS_REPEAT_ADJUST_ITEM "RepeatAdjust"
+#define MAIL_CS_REPEAT_UNTIL_ITEM "RepeatUntil"
+#define MAIL_CS_REPEAT_INTERVAL_ITEM "RepeatInterval"
+#define MAIL_CS_REPEAT_CUSTOM_ITEM "RepeatCustom"
+#define MAIL_CS_REPEAT_WEEKENDS_ITEM "RepeatWeekends"
+#define MAIL_CS_REPEAT_HOW_ITEM "RepeatHow"
+#define MAIL_CS_REPEAT_STARTFROMEND_ITEM "RepeatFromEnd"
+#define MAIL_CS_REPEAT_IDS_ITEM "RepeatIds"
+#define MAIL_CS_REPEAT_LOOKUP_ITEM "$RepeatLookup"
+#define MAIL_CS_REPEAT_CHANGEWHICH_ITEM "RescheduleWhich"
+#define MAIL_CS_REPEAT_CHANGEINSTANCEDATES_ITEM "RescheduleInstanceDates" /* new with Notes6 */
+#define MAIL_CS_REPEAT_CHANGESTARTDATETIMES_ITEM "RescheduleStartDateTimes" /* new with Notes6 */
+#define MAIL_CS_REPEAT_CHANGEENDDATETIMES_ITEM "RescheduleEndDateTimes" /* new with Notes6 */
+#define MAIL_CS_REPEAT_ORIGINALENDDATE_ITEM "OriginalEndDate"
+#define MAIL_CS_REPEAT_PARENTREPEATDATES_ITEM "ParentRepeatDates"
+#define MAIL_CS_REPEAT_PARENTREPEATINSTANCEDATES_ITEM "ParentRepeatInstanceDates"
+#define MAIL_CS_REPEAT_INSTANCE_LOOKUP_ITEM "$RepeatInstanceLookup"
+#define MAIL_CS_REPEAT_CACHEINSTANCE_ITEM "$RepeatCacheInstanceDate"
+#define MAIL_CS_REPEAT_CONFLICTDATES_ITEM "tmpRepeatConflictDates"
+#define MAIL_CS_ORIGINAL_STARTTIMEZONE_ITEM "OriginalStartTimeZone"
+#define MAIL_CS_ORIGINAL_ENDTIMEZONE_ITEM "OriginalEndTimeZone"
+#define MAIL_CS_REPEAT_RESCHEDULEOPTION "tmpRepeatAdvancedOption"
+#define MAIL_CS_REPEAT_SELECTEDDATES "tmpSelectedDateList"
+#define MAIL_CS_REPEAT_SELECTEDSTARTDATES "tmpSelectedStartDateList"
+#define MAIL_CS_REPEAT_SELECTEDENDDATES "tmpSelectedEndDateList"
+
+/* Notes 4 specific CS fields */
+
+#define MAIL_CS_4_TO_5UPGRADE "$CS4to5upgrade"
+#define MAIL_CS_4_TO_5NOT_GERMANE "$CS4to5UpGradeNotGermane"
+#define MAIL_CS_4_TO_5UPGRADE_DRAFT "$CS4to5upgrade_draft"
+#define MAIL_CS_4_REMINDER_TIME "ReminderTime"
+#define MAIL_CS_4_DURATION "Duration"
+#define MAIL_CS_4_ORGDONTDOUBLEBOOK "ORGDONTDOUBLEBOOK"
+#define MAIL_CS_4_INVITEE_NAME "InviteeName"
+
+/* C&S Alarm item names */
+
+#define MAIL_CS_ALARMENABLED_ITEM "$Alarm"
+#define MAIL_CS_ALARMSOUND_ITEM "$AlarmSound"
+#define MAIL_CS_ALARMDESCRIPTION_ITEM "$AlarmDescription"
+#define MAIL_CS_ALARMSENDTO_ITEM "$AlarmSendTo"
+#define MAIL_CS_ALARMOFFSET_ITEM "$AlarmOffset"
+#define MAIL_CS_ALARMTIME_ITEM "$AlarmTime"
+#define MAIL_CS_ALARMDISABLED_ITEM "$AlarmDisabled"
+#define MAIL_CS_ALARMDISABLED_DISABLED '0'
+#define MAIL_CS_ALARMDISABLED_ENABLED '1'
+#define MAIL_CS_ALARMOFFSETUNIT_ITEM "$AlarmUnit"
+#define MAIL_CS_ALARMMAILOPTIONS_ITEM "$AlarmMemoOptions"
+
+
+/* POP3 view names */
+#define MAIL_POP3_UIDL_VIEW "($POP3UIDL)"
+#define POP3_VIEW "($POP3)"
+
+/* Quota form item names */
+
+#define MAIL_QUOTA_ACTION_ITEM "$QuotaAction" /* Action taken on original message causing quota report */
+#define MAIL_QUOTA_REPORT_ITEM "$QuotaType" /* Over warning or over quota report */
+#define MAIL_QUOTA_ORIG_SIZE_ITEM "$QuotaOrigMsgSize" /* Size of original note triggering a quota report. */
+#define MAIL_QUOTA_ORIG_SUBJECT_ITEM "$QuotaOrigSubject" /* Original Subject */
+#define MAIL_QUOTA_ORIG_FROM_ITEM "$QuotaOrigFrom" /* Original From item */
+#define MAIL_QUOTA_ORIG_SENDTO_ITEM "$QuotaOrigSendTo" /* Original SendTo item */
+#define MAIL_QUOTA_ORIG_COPYTO_ITEM "$QuotaOrigCopyTo" /* Original CopyTo item */
+#define MAIL_QUOTA_ORIG_BCCTO_ITEM "$QuotaOrigBccTo" /* Original BlindCopyTo item */
+#define MAIL_QUOTA_SIZELIMIT_ITEM "$QuotaSizeLimit" /* DB sizelimit in k bytes */
+#define MAIL_QUOTA_WARNINGTHRESHOLD_ITEM "$QuotaWarningThreshold" /* DB warning threshold in k bytes */
+#define MAIL_QUOTA_CURRENTUSAGE_ITEM "$QuotaCurrentUsage" /* Current amount of DB usage k bytes */
+#define MAIL_QUOTA_METHOD_ITEM "$QuotaMethod" /* Quota enforcement method - filesize or usage*/
+#define MAIL_QUOTA_CURRENTSIZE_ITEM "$QuotaCurrentDbSize" /* Current DB size in k bytes */
+#define MAIL_ADMIN_TEXT_ITEM "$MailAdminText" /* Administrator specified text content */
+#define MAIL_QUOTA_WARNING_TIME_ITEM "$QuotaLastWarningTime" /* Last warning report time */
+#define MAIL_QUOTA_ERROR_TIME_ITEM "$QuotaLastErrorTime" /* Last time of error quota report */
+
+/* Mail form names */
+
+#define MAIL_MEMO_FORM "Memo" /* Standard memo */
+#define MAIL_REPLY_FORM "Reply" /* Standard memo reply */
+#define MAIL_REPLY_WITH_HISTORY_FORM "Reply With History" /* Standard reply w/history memo */
+#define MAIL_PHONEMESSAGE_FORM "Phone Message" /* Phone message */
+#define MAIL_DELIVERYREPORT_FORM "Delivery Report" /* Delivery report form name */
+#define MAIL_NONDELIVERYREPORT_FORM "NonDelivery Report" /* Non-Delivery report form name */
+#define MAIL_RETURNRECEIPT_FORM "Return Receipt" /* Return Receipt form name */
+#define MAIL_DATABASEENTRY_FORM "Database Entry" /* mailin database entry form for libraries */
+#define MAIL_TRACEREPORT_FORM "Trace Report" /* Trace report form name */
+#define MAIL_QUOTAREPORT_FORM "Quota Report" /* Quota report form name */
+#define MAIL_CALENDAR_PROFILE_FORM "CalendarProfile" /* Calendar profile form name */
+#define MAIL_DELEGATION_PROFILE_FORM "DelegationProfile" /* Delegation profile form name */
+#define MAIL_APPOINTMENT_FORM "Appointment" /* C & S Appointment form name */
+#define MAIL_NOTICE_FORM "Notice" /* C & S Meeting Notice form name */
+#define MAIL_RESOURCE_RESERVATION_FORM "Reservation" /* C & S Resource reservation form name */
+#define MAIL_RESOURCE_PROFILE_FORM "Resource" /* C & S Calendar resource profile form name */
+#define MAIL_TODO_FORM "Task" /* C & S Todo form name */
+#define MAIL_REPEAT_CACHE_FORM "RepeatCache" /* C&S Repeat Cache profile note name */
+#define MAIL_TODO_NOTICE_FORM "TaskNotice" /* C&S Todo notice workflow form */
+
+/* Tasks are now called ToDos. Define the old deprecated names as alias to new.
+ * The actual form names, e.g., "Task" have not changed to allow on-disk
+ * backwards compatibility
+ */
+#define MAIL_TASK_FORM MAIL_TODO_FORM
+#define MAIL_TASK_NOTICE_FORM MAIL_TODO_NOTICE_FORM
+
+#define MAIL_MAILRULE_FORM "Mailrule"
+
+
+/* Address Book - "Person" form item names */
+
+#define MAIL_PERSON_FORM "Person" /* Form and type name */
+#define MAIL_FORMTYPE_ITEM "Type" /* Form type */
+#define MAIL_FULLNAME_ITEM "FullName" /* Full name */
+#define MAIL_FIRSTNAME_ITEM "FirstName" /* First name */
+#define MAIL_LASTNAME_ITEM "LastName" /* Last name */
+#define MAIL_RANAME_ITEM "RAName" /* RA name */
+#define MAIL_MIDDLEINITIAL_ITEM "MiddleInitial" /* Middle initial or name */
+#define MAIL_SHORTNAME_ITEM "ShortName" /* Short name (for mail gateways) */
+#define MAIL_INTERNETADDRESS_ITEM "InternetAddress" /* InternetAddress */
+#define MAIL_OWNER_ITEM "Owner" /* Entry owner name */
+#define MAIL_MAILSYSTEM_ITEM "MailSystem" /* Mail system item (keyword field: 1,2,3,4) */
+#define MAIL_MAILSERVER_ITEM "MailServer" /* Mail server name */
+#define MAIL_MAILFILE_ITEM "MailFile" /* Mail file name */
+#define MAIL_MAILDOMAIN_ITEM "MailDomain" /* Mail domain name */
+#define MAIL_MAILADDRESS_ITEM "MailAddress" /* Mail auto-forwarding address */
+#define MAIL_PUBLICKEY_ITEM "PublicKey" /* Public encryption key */
+#define MAIL_CERTIFICATE_ITEM "Certificate" /* Public encryption key */
+#define MAIL_ROLLOVER_CERT_ITEM "RolloverCert" /* Key rollover cert */
+#define MAIL_USERCERTIFICATE_ITEM "UserCertificate" /* X.509 Public encryption key */
+#define MAIL_LOCATION_ITEM "Location" /* Location field */
+#define MAIL_COMMENT_ITEM "Comment" /* Comment field */
+#define MAIL_USERID_ATTACHMENT "UserID" /* User ID attachment file name */
+#define MAIL_SERVERID_ATTACHMENT "ServerID" /* Server ID attachment file name */
+#define MAIL_CALENDARDOMAIN_ITEM "CalendarDomain" /* User's calendar domain override */
+#define MAIL_NETUSERNAME_ITEM "NetUserName" /* Network Acct Name (for dir synching) */
+#define MAIL_HTTPPASSWORD_ITEM "HTTPPassword" /* http password */
+#define MAIL_HASHVERSION_ITEM "$SecurePassword" /* Flag that indicates NoteUpdate should hash HTTPPassword field */
+#define MAIL_STORAGE_ITEM "MessageStorage" /* Specifies how user wants to store the mail. See IMSG_PREFERENCE_XXX */
+#define MAIL_OFFICEPHONE_ITEM "OfficePhoneNumber" /* Office phone number */
+#define MAIL_COMPANYNAME_ITEM "CompanyName" /* Company name */
+#define MAIL_COUNTRY_ITEM "Country" /* Country */
+#define MAIL_DEPARTMENT_ITEM "Department" /* Department */
+#define MAIL_OTHER_EMAIL1 "MiscPhone1"
+#define MAIL_OTHER_EMAIL2 "MiscPhone2"
+#define MAIL_OTHER_EMAIL3 "MiscPhone3"
+#define MAIL_BIRTHDAY "Birthday"
+#define MAIL_ANNIVERSARY "Anniversary"
+
+#define MAIL_ALTFULLNAME_ITEM "AltFullName" /* Alternate FullName */
+#define MAIL_ALTFULLNAMELANGUAGE_ITEM "AltFullNameLanguage" /* Language Tag. */
+#define MAIL_PROPALTCOMMONNAME_ITEM "ProposedAltCommonName" /* Proposed Alternate CommonName */
+#define MAIL_PROPALTORGUNIT_ITEM "ProposedAltOrgUnit" /* Proposed Alternate OrgUnit */
+#define MAIL_PROPALTFULLNAMELANGUAGE_ITEM "ProposedAltFullNameLanguage" /* Proposed Language Tag. */
+
+#define HTTP_PASSWORD_ITEM "HTTPPassword" /* http password */
+#define HTTP_PASSWORD_CHANGE_DATE_ITEM "HTTPPasswordChangeDate" /* http password last change date*/
+#define HTTP_PASSWORD_CHANGE_INTERVAL_ITEM "HTTPPasswordChangeInterval" /* http password change interval*/
+#define HTTP_PASSWORD_OPTIONS_ITEM "HTTPPasswordOptions" /* http password options */
+#define HTTP_PASSWORD_QUAILITY_ITEM "HTTPPasswordQuality" /* http password quality */
+#define HTTP_PASSWORD_NOTES_SYNC_ITEM "HTTPPasswordNotesSync" /* Sync Notes pw with http pw */
+
+/* Address Book - Mail-in "Database" form item names. Uses Person form
+ fields: FullName, MailServer, MailFile, and MailDomain" */
+
+#define MAIL_MAILINDATABASE_FORM "Database" /* Form and type name */
+#define MAIL_DESCRIPTION_ITEM "Description" /* Mail-in db description item */
+#define MAIL_HAIKU_ITEM "$QuickPlace" /* QuickPlace mail database */
+
+/* MAPI specific items */
+
+#define MAIL_MAPI_MSGFLAGS_ITEM "$MapiMessageFlags" /* MAPI IMessage PR_MESSAGE_FLAGS Property */
+#define MAIL_MAPI_MSGCLASS_ITEM "$MapiMessageClass" /* MAPI IMessage PR_MESSAGE_CLASS Property */
+#define MAIL_MAPI_STATUS_ITEM "$MapiStatus" /* MAPI PR_MSG_STATUS, PR_STATUS Properties */
+#define MAIL_MAPI_ACCESS_ITEM "$MapiAccess" /* MAPI PR_ACCESS, PR_ACCESS_LEVEL Properties */
+#define MAIL_MAPI_TO_ADDRTYPE_ITEM "$MapiSendToAddrType"/* MAPI Recip PR_ADDRTYPE Property for To List */
+#define MAIL_MAPI_CC_ADDRTYPE_ITEM "$MapiSendCcAddrType"/* MAPI Recip PR_ADDRTYPE Property for Cc List*/
+#define MAIL_MAPI_BCC_ADDRTYPE_ITEM "$MapiSendBccAddrType"/* MAPI Recip PR_ADDRTYPE Property for Bcc List*/
+#define MAIL_MAPI_TO_RESP_ITEM "$MapiSendToResponsibility"/* MAPI Recip PR_RESPONSIBILITY Property for To List */
+#define MAIL_MAPI_CC_RESP_ITEM "$MapiSendCcResponsibility"/* MAPI Recip PR_RESPONSIBILITY Property for Cc List */
+#define MAIL_MAPI_BCC_RESP_ITEM "$MapiSendBccResponsibility"/* MAPI Recip PR_RESPONSIBILITY Property for Bcc List */
+#define MAIL_MAPI_TO_EID_ITEM "$MapiSendToEID" /* MAPI Recip PR_ENTRYID Property for To List */
+#define MAIL_MAPI_CC_EID_ITEM "$MapiSendCcEID" /* MAPI Recip PR_ENTRYID Property for Cc List */
+#define MAIL_MAPI_BCC_EID_ITEM "$MapiSendBccEID" /* MAPI Recip PR_ENTRYID Property for Bcc List */
+#define MAIL_MAPI_TO_OT_ITEM "$MapiSendToObjType" /* MAPI Recip PR_OBJECT_TYPE Property for To List */
+#define MAIL_MAPI_CC_OT_ITEM "$MapiSendCcObjType" /* MAPI Recip PR_OBJECT_TYPE Property for Cc List */
+#define MAIL_MAPI_BCC_OT_ITEM "$MapiSendBccObjType" /* MAPI Recip PR_OBJECT_TYPE Property for Bcc List */
+#define MAIL_MAPI_TO_TRACKSTATUS_ITEM "$MapiSendToTrackStatus"/* MAPI Recip PR_RECIPIENT_TRACKSTATUS Property for To List */
+#define MAIL_MAPI_CC_TRACKSTATUS_ITEM "$MapiSendCcTrackStatus"/* MAPI Recip PR_RECIPIENT_TRACKSTATUS Property for Cc List */
+#define MAIL_MAPI_BCC_TRACKSTATUS_ITEM "$MapiSendBccTrackStatus"/* MAPI Recip PR_RECIPIENT_TRACKSTATUS Property for Bcc List */
+#define MAIL_MAPI_TO_FLAGS_ITEM "$MapiSendToFlags" /* MAPI Recip PR_RECIPIENT_FLAGS Property for To List */
+#define MAIL_MAPI_CC_FLAGS_ITEM "$MapiSendCcFlags" /* MAPI Recip PR_RECIPIENT_FLAGS Property for Cc List */
+#define MAIL_MAPI_BCC_FLAGS_ITEM "$MapiSendBccFlags"/* MAPI Recip PR_RECIPIENT_FLAGS Property for Bcc List */
+#define MAIL_MAPI_TO_TSTIME_ITEM "$MapiSendToTSTime"/* MAPI Recip PR_RECIPIENT_TRACKSTATUS_TIME Property for To List */
+#define MAIL_MAPI_CC_TSTIME_ITEM "$MapiSendCcTSTime"/* MAPI Recip PR_RECIPIENT_TRACKSTATUS_TIME Property for Cc List */
+#define MAIL_MAPI_BCC_TSTIME_ITEM "$MapiSendBccTSTime"/* MAPI Recip PR_RECIPIENT_TRACKSTATUS_TIME Property for Bcc List */
+#define MAIL_MAPI_TO_ADDR_ITEM "$MapiSendToAddr" /* MAPI Recip PR_EMAIL_ADDRESS Property for To List */
+#define MAIL_MAPI_CC_ADDR_ITEM "$MapiSendCcAddr" /* MAPI Recip PR_EMAIL_ADDRESS Property for Cc List */
+#define MAIL_MAPI_BCC_ADDR_ITEM "$MapiSendBccAddr" /* MAPI Recip PR_EMAIL_ADDRESS Property for Bcc List */
+#define MAIL_MAPI_SENDER_EID_ITEM "$MapiSenderEID" /* MAPI Sender PR_ENTRYID Property */
+#define MAIL_MAPI_SENDER_ADDRTYPE_ITEM "$MapiSenderAddrType" /* MAPI Sender PR_ADDRTYPE Property */
+#define MAIL_MAPI_SENDER_ADDR_ITEM "$MapiSenderAddr"/* MAPI Sender PR_EMAIL_ADDR Property */
+#define MAIL_MAPI_SENDER_SEARCHKEY_ITEM "$MapiSenderSearchKey" /* MAPI Sender PR_SEARCH_KEY Property */
+#define MAIL_MAPI_SENDER_NAME_ITEM "$MapiSenderName"/* MAPI Sender PR_DISPLAY_NAME Property */
+#define MAPI_MAPI_CONTAINER_CLASS_ITEM "$MapiContainerClass" /* MAPI Folder PR_CONTAINER_CLASS Property */
+
+/* Roaming user specific field names*/
+#define MAIL_USERDIC "UserDic" /*the user's personal dictionary item*/
+#define USERDIC_FORMAT "UserDicFormat" /*format of the user dictionary 0 - MAC 1- PC */
+
+/* Summary item names used to store NNTP information. */
+
+#define NNTP_MESSAGE_ID_ITEM_NAME "$UName"
+#define NNTP_FROM_ITEM_NAME "$8"
+#define NNTP_SUBJECT_ITEM_NAME "$9"
+#define NNTP_DATE_ITEM_NAME "$10"
+#define NNTP_REFERENCES_ITEM_NAME "$11"
+#define NNTP_PATH_ITEM_NAME "Path"
+#define NNTP_DISTRIBUTIONS_ITEM_NAME "Distribution"
+#define NNTP_SIZE_ITEM_NAME "NNTP_Size"
+#define NNTP_LINES_ITEM_NAME "Lines"
+#define NNTP_ISLMBCS_ITEM_NAME "$18"
+
+/* NNTP Client item names */
+
+#define NNTPCL_OUTGOING_ITEM "Outgoing"
+#define NNTPCL_NEWSREADER_ITEM "$Newsreader"
+#define NNTPCL_NEWSGROUPS_ITEM "Newsgroups"
+#define NNTPCL_OUTBOX_VIEW "($ArticlesToPost)"
+
+/* Client Type */
+
+#define FIELD_CLIENTTYPE "ClientType" /* Client Type - Full or Limited Notes */
+
+/* Standard Subform Item Name. */
+
+#define SUBFORM_ITEM_NAME "$SubForms"
+#define SUBFORM_REPIDS_ITEM_NAME "$SubForm_RepIDs"
+
+/* Define field name common to Server, Person, and Certifier forms */
+
+#define KFM_ITEM_CHANGE_REQUEST "ChangeRequest"
+#define KFM_ITEM_CHANGE_REQUEST_DATE "ChangeRequestDate"
+
+
+/* Certifier and Cross-certificate Address Book lookup definitions */
+
+#define KFM_FORM_CERTIFIER "Certifier"
+#define KFM_FORM_CROSSCERTIFICATE "CrossCertificate"
+
+#define KFM_ITEM_NAMECOMBO "NameCombo"
+#define KFM_ITEM_ORGCOMBO "OrgCombo"
+#define KFM_ITEM_ISSUEDTO "IssuedTo"
+#define KFM_ITEM_ISSUEDBY "IssuedBy"
+#define KFM_ITEM_CERTIFICATE "Certificate"
+#define KFM_ITEM_USER_CERTIFICATE "UserCertificate"
+ /* Some additional items are */
+ /* the same as those defined */
+ /* for the "Person" form */
+
+#define KFM_ITEM_CERT_NOENC "Certificate_NoEnc"
+ /* Public encryption key */
+ /* to be used for signature */
+ /* checking only and not for*/
+ /* sending encrypted mail */
+
+#define KFM_ITEM_PUBLICKEY "PublicKey" /* Public encryption key */
+ /* for flat names. */
+#define KFM_ITEM_INET_PUBKEY "INetPublicKey"
+ /* Public key to be used for*/
+ /* "View level" internet */
+ /* certification. */
+
+
+#define CERTIFIERNAMESSPACE "$Certifiers"
+#define LOCAL_CERTIFIERNAMESSPACE "1\\$Certifiers"
+#define CERTIFIERSNAMESSPACE "$Certifiers"
+#define CROSSCERTBYROOTNAMESSPACE "$CrossCertByRoot"
+#define CROSSCERTBYNAMENAMESSPACE "$CrossCertByName"
+
+
+#define KFM_CROSSCERT_ITEM_ISSUEDTO 0
+#define KFM_CROSSCERT_ITEM_ISSUEDBY 1
+#define KFM_CROSSCERT_ITEM_CERTIFICATE 2
+#define KFM_CROSSCERT_ITEM_CERT_NOENC 3
+#define KFM_CROSSCERT_ITEM_NOTEID 4
+#define KFM_CROSSCERT_LOOKUPITEMCOUNT 5
+#define KFM_CROSSCERT_LOOKUPITEMS "IssuedTo\0IssuedBy\0Certificate\0Certificate_NoEnc\0$$NoteID"
+
+#define KFM_CERTIFIER_ITEM_ISSUEDTO 0
+#define KFM_CERTIFIER_ITEM_ISSUEDBY 1
+#define KFM_CERTIFIER_ITEM_CERTIFICATE 2
+#define KFM_CERTIFIER_ITEM_CERT_NOENC 3
+#define KFM_CERTIFIER_LOOKUPITEMCOUNT 4
+#define KFM_CERTIFIER_LOOKUPITEMS "IssuedTo\0IssuedBy\0Certificate\0Certificate_NoEnc"
+
+/* Names for Wired In Cross Certificates
+*/
+#define NOTES_TEMPLATE_DEVELOPER_ID "CN=Lotus Notes Template Development/O=Lotus Notes"
+#define NOTES_COMPANION_ID "O=Lotus Notes Companion Products"
+#define NOTES_WHOSAYS_ID "Notes"
+#define BINARYTREE_TEMPLATE_DEVELOPER_ID "CN=BT Mail and Calendar Migration Tools/O=Lotus Notes Companion Products"
+#define SAMETIME_TEMPLATE_DEVELOPER_ID "CN=Sametime Development/O=Lotus Notes Companion Products"
+#define LOTUSFAX_TEMPLATE_DEVELOPER_ID "CN=Lotus Fax Development/O=Lotus Notes Companion Products"
+#define LOTUSUNICOMM_TEMPLATE_DEVELOPER_ID "CN=Domino Unified Communications Services/O=Lotus Notes Companion Products"
+
+/* ECL Owner Key for admin ecl updates
+ * When this is encoutered on the client during eclrefresh it is replaced
+ * with the current users name to allow admins to define current user rights
+ */
+#define ECL_KEY_FOR_ECL_OWNER_NAME "<ECLOwner>"
+
+/* Lookup items for Network Authentication check.
+
+ NOTE: These items are no longer referenced by the Notes Authentication code.
+ However, some NETAUTH_... symbols are referenced by miscellaneous code
+ (change as TESTNSF) so we won't delete them here just yet.
+
+ LATER: We should search out and destroy all references.
+*/
+
+#define NETAUTH_ITEM_CERTIFICATE 0
+#define NETAUTH_ITEM_CERT_NOENC 1
+#define NETAUTH_ITEM_PUBLIC_KEY 2
+#define NETAUTH_ITEM_CHANGEREQUEST 3
+#define NETAUTH_ITEM_USERCERTIFICATE 4
+#define NETAUTH_LOOKUPITEMCOUNT 5
+
+#define NETAUTH_LOOKUPITEMS "Certificate\0Certificate_NoEnc\0PublicKey\0ChangeRequest\0ChangeRequestDate\0UserCertificate"
+
+#define NETAUTH_NAMESPACE_USERS "($Users)"
+#define NETAUTH_NAMESPACE_SERVERS "($Servers)"
+#define NETAUTH_NAMESPACE_SERVERSORUSERS "($Servers)\0($Users)"
+#define NETAUTH_NAMESPACE_USERSORSERVERS "($Users)\0($Servers)"
+#define NETAUTH_NAMESPACE_CERTIFIERS "($Certifiers)"
+#define NETAUTH_NAMESPACE_XCERTBYROOT "($CrossCertByRoot)"
+
+/* Lookup items for KFMGetPublicKey
+*
+* NOTE: Code knows that the last view may not be present (in the case
+* of a Personal N&A book), so $Servers must be last and the code must
+* be changed if any others become optional.
+*/
+
+#define KFM_GETPUB_VIEWS "($Users)\0($Certifiers)\0($Servers)"
+#define KFM_GETPUB_NUMVIEWS 3
+#define KFM_GETPUB_FIELDS "Certificate\0Certificate_NoEnc\0PublicKey\0UserCertificate"
+#define KFM_GETPUB_NUMFIELDS 4
+
+
+/* BSAFE NAMELookup Items */
+#define SEC_AUTH_ITEMS_LIST \
+ \
+"\
+$$NoteID\0\
+$$DBName\0\
+\
+Certificate\0\
+Certificate_NoEnc\0\
+PublicKey\0\
+UserCertificate\0\
+\
+ChangeRequest\0\
+ChangeRequestDate\0\
+\
+ClientType\0\
+\
+PasswordChangeInterval\0\
+PasswordChangeDate\0\
+PasswordDigest\0\
+PasswordGracePeriod\0\
+\
+CheckPassword\0\
+\
+HTTPPasswordChangeDate\0\
+HTTPPassword\0\
+\
+Policy\0\
+Profiles\0\
+ClntDgst\0\
+NewMailClientUpdateFlag\0\
+RoamingUserUpdateFlag\0\
+\
+ServerName\0\
+\
+NewRoamStatUpdtFl\0\
+RoamStatDwnFl\0\
+MailDomain\0\
+\
+PKMinWidth\0\
+PKMaxWidth\0\
+PKDefWidth\0\
+PKMaxAge\0\
+PKMinDate\0\
+PKDueDate\0\
+PKPriority\0\
+PKOldKeyDays\0\
+\
+$$ModifiedTime\0"
+
+#define SEC_AUTH_ITEM_NOTEID 0
+#define SEC_AUTH_ITEM_DBNAME 1
+
+#define SEC_AUTH_ITEM_CERTIFICATE 2
+#define SEC_AUTH_ITEM_CERT_NOENC 3
+#define SEC_AUTH_ITEM_PUBLIC_KEY 4
+#define SEC_AUTH_ITEM_USER_CERT 5
+
+#define SEC_AUTH_ITEM_CHANGE_REQUEST 6
+#define SEC_AUTH_ITEM_CHANGE_REQUEST_DATE 7
+
+#define SEC_AUTH_ITEM_CLIENT_TYPE 8
+
+#define SEC_AUTH_ITEM_NOTESPW_CHANGEINTERVAL 9
+#define SEC_AUTH_ITEM_NOTESPW_CHANGEDATE 10
+#define SEC_AUTH_ITEM_NOTESPW_DIGEST 11
+#define SEC_AUTH_ITEM_NOTESPW_GRACEPERIOD 12
+
+#define SEC_AUTH_ITEM_NOTESPW_CHECK 13
+
+#define SEC_AUTH_ITEM_HTTPCHANGEDATE 14
+#define SEC_AUTH_ITEM_HTTPPASSWORD 15
+
+#define SEC_AUTH_ITEM_POLICY 16
+#define SEC_AUTH_ITEM_PROFILES 17
+#define SEC_AUTH_ITEM_CLIENTDIGEST 18
+#define SEC_AUTH_ITEM_FLAG_NEWMAIL 19
+#define SEC_AUTH_ITEM_FLAG_ROAMING 20
+
+#define SEC_AUTH_ITEM_SERVERNAME 21
+
+#define SEC_AUTH_ITEM_FLAG_NEWROAMING 22
+#define SEC_AUTH_ITEM_FLAG_ROAMINGDOWN 23
+#define SEC_AUTH_ITEM_MAILDOMAIN 24
+
+#define SEC_AUTH_ITEM_PUBKEY_MINWIDTH 25
+#define SEC_AUTH_ITEM_PUBKEY_MAXWIDTH 26
+#define SEC_AUTH_ITEM_PUBKEY_DEFWIDTH 27
+#define SEC_AUTH_ITEM_PUBKEY_MAXAGE 28
+#define SEC_AUTH_ITEM_PUBKEY_MINDATE 29
+#define SEC_AUTH_ITEM_PUBKEY_DUEDATE 30
+#define SEC_AUTH_ITEM_PUBKEY_PRIORITY 31
+#define SEC_AUTH_ITEM_PUBKEY_OLDKEYDAYS 32
+
+#define SEC_AUTH_ITEM_MODIFIED_TIME 33
+
+#define SEC_AUTH_ITEMS_COUNT 34
+
+#define SEC_CERTTAB_ITEMS_LIST \
+"\
+$$NoteID\0\
+$$DBName\0\
+\
+Certificate\0\
+Certificate_NoEnc\0\
+PublicKey\0\
+UserCertificate\0\
+ChangeRequest\0\
+\
+CertificateType\0\
+IsHostedOrg\0\
+OrgDatabaseDir\0\
+OrgPolicy\0\
+RegistrationAuthorities\0\
+\
+RecoveryInfo\0\
+RolloverCert\0\
+\
+GlobalDomainDocument"
+
+#define SEC_CERTTAB_ITEM_NOTEID 0
+#define SEC_CERTTAB_ITEM_DBNAME 1
+
+#define SEC_CERTTAB_ITEM_CERTIFICATE 2
+#define SEC_CERTTAB_ITEM_CERT_NOENC 3
+#define SEC_CERTTAB_ITEM_PUBLIC_KEY 4
+#define SEC_CERTTAB_ITEM_USER_CERT 5
+#define SEC_CERTTAB_ITEM_CHANGE_REQUEST 6
+
+#define SEC_CERTTAB_ITEM_CERTIFICATE_TYPE 7 /* really "Certifier Type" */
+#define SEC_CERTTAB_ITEM_IS_HOSTED_ORG 8
+#define SEC_CERTTAB_ITEM_ORG_DATABASE_DIR 9
+#define SEC_CERTTAB_ITEM_ORG_POLICY 10
+#define SEC_CERTTAB_ITEM_RAS 11
+
+#define SEC_CERTTAB_ITEM_RECOVERY_INFO 12
+#define SEC_CERTTAB_ITEM_ROLLOVER_CERT 13
+
+#define SEC_CERTTAB_ITEM_GLOBALDOMAIN_DOC 14
+
+
+#define SEC_CERTTAB_ITEMS_COUNT 15
+
+
+#define ADMINP_NAB_ITEMS_LIST \
+"\
+$$NoteID\0\
+$$DBName\0\
+\
+Certificate\0\
+Certificate_NoEnc\0\
+PublicKey\0\
+UserCertificate\0\
+ChangeRequest"
+
+#define ADMINP_NAB_ITEM_NOTEID 0
+#define ADMINP_NAB_ITEM_DBNAME 1
+
+#define ADMINP_NAB_ITEM_CERTIFICATE 2
+#define ADMINP_NAB_ITEM_CERT_NOENC 3
+#define ADMINP_NAB_ITEM_PUBLIC_KEY 4
+#define ADMINP_NAB_ITEM_USER_CERT 5
+#define ADMINP_NAB_ITEM_CHANGE_REQUEST 6
+
+#define ADMINP_NAB_ITEMS_COUNT 7
+
+#define NET_GROUP_ITEMS_LIST \
+"\
+$$NoteID\0\
+$$DBName\0\
+\
+Certificate\0\
+Certificate_NoEnc\0\
+PublicKey\0\
+UserCertificate\0\
+ChangeRequest"
+
+#define NET_GROUP_ITEM_NOTEID 0
+#define NET_GROUP_ITEM_DBNAME 1
+
+#define NET_GROUP_ITEM_CERTIFICATE 2
+#define NET_GROUP_ITEM_CERT_NOENC 3
+#define NET_GROUP_ITEM_PUBLIC_KEY 4
+#define NET_GROUP_ITEM_USER_CERT 5
+#define NET_GROUP_ITEM_CHANGE_REQUEST 6
+
+#define NET_GROUP_ITEMS_COUNT 7
+
+
+/* S/MIME items in address book records. */
+#define SMIME_USER_CAPABILITIES_ITEM "SmimeUserCapabilities"
+
+/* Address Book - Items and names used by security panel */
+
+#define SECPANEL_PERSONDOCITEM_NAME 0
+#define SECPANEL_PERSONDOCITEM_SHNAME 1
+#define SECPANEL_PERSONDOCITEM_INETADDR 2
+#define SECPANEL_PERSONDOCITEM_ENCRMAIL 3
+#define SECPANEL_PERSONDOCITEM_STOREMAIL 4
+#define SECPANEL_PERSONDOCITEM_CHECKPASSWORD 5
+#define SECPANEL_PERSONDOCITEM_PASS_GRACE_PERIOD 6
+#define SECPANEL_PERSONDOCITEM_PASS_CHANGE_INTERVAL 7
+#define SECPANEL_PERSONLOOKUPITEMCOUNT 8
+#define SECPANEL_PERSONLOOKUPITEMS "FullName\0ShortName\0InternetAddress\0EncryptIncomingMail\0MessageStorage\0CheckPassword\0PasswordGracePeriod\0PasswordChangeInterval"
+
+/* Userless NAB definitions */
+#define USERLESS_FORMULA "Type!=\"Person\" & Type != \"Database\" & Type != \"Group\" & (@IsUnAvailable(FullName) | @IsAvailable(CfgDoc) | Type = \"Certifier\")"
+#define USERLESS_FORMULA_V2 "Type!=\"Person\" & Type != \"Database\" & Type != \"Group\" & (@IsUnAvailable(FullName) | @IsAvailable(ConfigDocument) | Type = \"Certifier\")"
+#define USERLESS_FORMULA_V1 "((Type!=\"Person\" & Type != \"Database\" & Type != \"Group\" ) & (@IsUnAvailable(FullName ) & Type != \"Certifier\")) | @IsAvailable(CfgDoc)"
+#define USERLESS_FORMULA_V3 "((Type!=\"Person\" & Type != \"Database\" & Type != \"Group\" ) & (@IsUnAvailable(FullName ) & Type != \"Certifier\")) | @IsAvailable(ConfigDocument)"
+
+
+#define FILE_ID_VIEW "$FileIdentifications"
+
+/* Lookup items for Profiles */
+
+#define PROFILENAMESSPACE "$Profiles"
+#define PROFILENAME "ProfileName"
+#define PROFILES_ITEM "Profiles"
+
+/* dblink fields in the Setup Profile note */
+#define PROFILE_DATABASELINK_ITEM "DatabaseLinks"
+#define PROFILE_REPLICALINK_ITEM "ReplicaLinks"
+#define PROFILE_LNABLINK_ITEM "LNABLinks"
+#define POLICY_WELCOMELINK_ITEM "WelcomeLink"
+
+/* Smart Upgrade Tracking Options in Desktop Settings Policy */
+#define POLICY_DESKTOP_SU_LOCATION_ITEM "SULoc"
+#define POLICY_DESKTOP_SU_REMOVE_ITEM "SURem"
+#define POLICY_DESKTOP_SU_RETENTION_ITEM "SUDays"
+
+/* Diagnostic Collection Options in Destop Settings Policy */
+#define POLICY_DESKTOP_LOCATION_ITEM "DCLoc"
+#define POLICY_DESKTOP_LOCATION_ITEM_IP "DCLoc$IP"
+#define POLICY_DESKTOP_LOCATION_ITEM_PO "DCLoc$PO"
+#define POLICY_DESKTOP_PROMPT_ITEM "DCPmpt"
+#define POLICY_DESKTOP_PROMPT_ITEM_IP "DCPmpt$IP"
+#define POLICY_DESKTOP_PROMPT_ITEM_PO "DCPmpt$PO"
+#define POLICY_DESKTOP_REMOVE_ITEM "DCRem"
+#define POLICY_DESKTOP_REMOVE_ITEM_IP "DCRem$IP"
+#define POLICY_DESKTOP_REMOVE_ITEM_PO "DCRem$PO"
+#define POLICY_DESKTOP_CRASHCOMMENTS_ITEM "DCCom"
+#define POLICY_DESKTOP_CRASHCOMMENTS_ITEM_IP "DCCom$IP"
+#define POLICY_DESKTOP_CRASHCOMMENTS_ITEM_PO "DCCom$PO"
+#define POLICY_DESKTOP_CRASHMSGSIZE_ITEM "DCMsgSize"
+#define POLICY_DESKTOP_CRASHMSGSIZE_ITEM_IP "DCMsgSize$IP"
+#define POLICY_DESKTOP_CRASHMSGSIZE_ITEM_PO "DCMsgSize$PO"
+#define POLICY_DESKTOP_CRASHNSDSIZE_ITEM "DCNSDSize"
+#define POLICY_DESKTOP_CRASHNSDSIZE_ITEM_IP "DCNSDSize$IP"
+#define POLICY_DESKTOP_CRASHNSDSIZE_ITEM_PO "DCNSDSize$PO"
+#define POLICY_DESKTOP_DEBUGOUTFILE_ITEM "DCDO"
+#define POLICY_DESKTOP_DEBUGOUTFILE_ITEM_IP "DCDO$IP"
+#define POLICY_DESKTOP_DEBUGOUTFILE_ITEM_PO "DCDO$PO"
+#define POLICY_DESKTOP_RETENTION_ITEM "DCDays"
+#define POLICY_DESKTOP_RETENTION_ITEM_IP "DCDays$IP"
+#define POLICY_DESKTOP_RETENTION_ITEM_PO "DCDays$PO"
+#define POLICY_DESKTOP_ADC_FILES_ITEM "DCFiles"
+#define POLICY_DESKTOP_ADC_FILES_ITEM_IP "DCFiles$IP"
+#define POLICY_DESKTOP_ADC_FILES_ITEM_PO "DCFiles$PO"
+
+/* Address Book - "Server" form item names */
+
+#define MAIL_SERVER_FORM "Server" /* Form and type name */
+#define MAIL_SERVERNAME_ITEM "ServerName" /* Server name */
+#define MAIL_DOMAINNAME_ITEM "Domain" /* Domain server is in */
+#define MAIL_NETWORKNAME_ITEM "Network" /* Network server is on */
+#define MAIL_ADMINNAME_ITEM "Administrator" /* Server's administrator(s) */
+#define MAIL_SERVERTITLE_ITEM "ServerTitle" /* Server title */
+#define MAIL_SERVERPORTS_ITEM "Ports" /* Enabled ports in server record */
+#define MAIL_SMTPLISTENER_ITEM "SMTPListenerEnabled" /* Does this server run an SMTP listener? */
+#define MAIL_FULLHOSTNAME_ITEM "SMTPFullHostDomain" /* Host name of the server */
+#define MAIL_NETADDRESSES_ITEM "NetAddresses" /* Network Addresses */
+
+/* Address Book - "Certifier" form item names */
+
+#define MAIL_CERTIFIER_TYPE "Certifier" /* Document type of "Certifier" */
+#define MAIL_CERTIFIERTYPE_ITEM "Type" /* Certifier type */
+#define MAIL_CERTIFIERISSUEDTO_ITEM "IssuedTo" /* Certifier issued to (to get Org Name) */
+#define MAIL_CERTIFIERGLOBALDOMAIN_ITEM "GlobalDomainDocument" /* Name of Global Domain for organization */
+#define MAIL_CERTIFIERISORG_ITEM "IsHostedOrg" /* is certifier an organization */
+#define MAIL_CERTIFIERDBSTORAGE_ITEM "OrgDatabaseDir" /* storage location of organization */
+#define MAIL_CERTIFIERPOLICY_ITEM "OrgPolicy" /* explicit policy for organization */
+
+/* Address Book - "X400Server" form item names */
+
+#define MAIL_X400_SERVER_FORM "Server" /* Form and type name */
+#define MAIL_X400_SERVERNAME_ITEM "X400ServerName" /* X400 MTA server name */
+#define MAIL_X400_MTANAME_ITEM "X400MTAName" /* X400 MTA name */
+#define MAIL_X400_GLOBAL_DOMAIN_ITEM "X400GlobalDomain" /* Global domain identifier */
+#define MAIL_X400_COUNTRY_ITEM "X400Country" /* Country name */
+#define MAIL_X400_ADMD_ITEM "X400ADMD" /* Administration Management Domain name*/
+#define MAIL_X400_PRMD_ITEM "X400Domain" /* Private Domain name */
+#define MAIL_X400_CREDENTIALS_ITEM "X400Credentials" /* MTA credentials */
+#define MAIL_X400_SUPP_APP_CONTEXTS_ITEM "X400SupportedApplicationContexts" /* Supported app. contexts */
+#define MAIL_X400_DEL_CONTENT_LENGTH_ITEM "X400DeliverContentLength" /* Delivery content length */
+#define MAIL_X400_DEL_CONTENT_TYPE_ITEM "X400DeliverContentTypes" /* Delivery content types */
+#define MAIL_X400_PSEL_ITEM "X400PSEL" /* Presentation selector */
+#define MAIL_X400_SSEL_ITEM "X400SSEL" /* Session selector */
+#define MAIL_X400_TSEL_ITEM "X400TSEL" /* Transport selector */
+#define MAIL_X400_IPADDRESS_ITEM "X400IPAddress" /* Network IP address for the MTA */
+#define MAIL_X400_X121ADDRESS_ITEM "X400X121Address" /* X.121 Network address for the MTA */
+
+/* Address Book - "Domain" form item names */
+
+#define MAIL_DOMAIN_FORM "Domain" /* Form and type name */
+#define MAIL_DOMAINTYPE_ITEM "DomainType" /* Domain type */
+#define MAIL_DOMAINADJDOMAINNAME_ITEM "AdjacentDomainName" /* Adjacent domain name */
+#define MAIL_DOMAINDOMAINNAME_ITEM "DomainName" /* Domain name */
+#define MAIL_DOMAINNEXTDOMAIN_ITEM "NextDomain" /* Next domain to domain */
+#define MAIL_DOMAINMAILSERVER_ITEM "MailServer" /* Server containing mailbox */
+#define MAIL_DOMAINMAILFILE_ITEM "MailFile" /* File name of mailbox */
+#define MAIL_DOMAINALLOW_ITEM "AllowFromDomains" /* Allow list */
+#define MAIL_DOMAINDENY_ITEM "DenyFromDomains" /* Deny list */
+#define MAIL_DOMAINCALENDARSERVER_ITEM "CalendarServer" /* Calendar gateway server */
+#define MAIL_DOMAINCALENDARSYSTEM_ITEM "CalendarSystem" /* Calendar gateway system */
+
+
+#define MAIL_DOMAINCALENDARDETAILS_ITEM "CalDtls" /* Calendar details to harvest */
+#define MAIL_DOMAINNONCONTROVERSIALFIELDS_ITEM "CalDtls" /* Non-Controversial Calendar details to harvest */
+
+/* Address Book - "Connection" form item names */
+
+#define MAIL_LOCAL_CONNECTION_FORM "Local" /* Local Connection form name */
+#define MAIL_REMOTE_CONNECTION_FORM "Remote" /* Remote Connection form name */
+#define MAIL_CONNECTION_TYPE "Connection" /* Connection entry type */
+#define MAIL_CONNECTION_TYPE_ITEM "ConnectionType" /* Connection type item */
+#define MAIL_SOURCE_ITEM "Source" /* Source computer name */
+#define MAIL_SOURCEDOMAIN_ITEM "SourceDomain" /* Source domain name */
+#define MAIL_DESTINATION_ITEM "Destination" /* Destination computer name */
+#define MAIL_DESTINATIONDOMAIN_ITEM "DestinationDomain" /* Destination domain name */
+#define MAIL_PORTNAME_ITEM "PortName" /* Port name */
+#define MAIL_PHONENUMBER_ITEM "PhoneNumber" /* Phone number */
+#define MAIL_COUNTRYCODE_ITEM "Country" /* Phone number */
+#define MAIL_AREACODE_ITEM "AreaCode" /* Phone number */
+#define MAIL_AREACODEINPUT_ITEM "AreaCodeInput" /* Phone number */
+#define MAIL_ENABLED_ITEM "Enabled" /* Enabled/disabled item */
+#define MAIL_TASKS_ITEM "Tasks" /* Tasks item */
+#define MAIL_INTERVAL_ITEM "Interval" /* Interval item */
+#define MAIL_SCHEDULE_ITEM "Schedule" /* Schedule item */
+#define MAIL_COST_ITEM "Cost" /* Routing cost item */
+#define MAIL_REPLICATION_TYPE_ITEM "RepType" /* Replication type, e.g. pull/pull */
+#define MAIL_LINKINFO_ITEM "LinkInfo" /* For X.25 conn recs */
+#define MAIL_PASSTHRUSERVER_ITEM "PassthruServer" /* For passthru conn recs */
+#define MAIL_LOCALPHONENUMBER_ITEM "LocalPhoneNumber" /* set this in connrec for form compute */
+
+/* Address Book - "Group" form item names */
+
+#define MAIL_GROUP_FORM "Group" /* Form and type name */
+#define MAIL_GROUP_TYPE "GroupType" /* Form and type name */
+#define MAIL_LISTNAME_ITEM "ListName" /* Distribution list name */
+#define MAIL_LISTDESCRIPTION_ITEM "ListDescription" /* Distribution list name */
+#define MAIL_MEMBERS_ITEM "Members" /* Members names name */
+#define MAIL_LISTADMINISTRATOR_ITEM "Administrator" /* Group administrator */
+/* Part of SPR GOTO54JT5Q - Need this to get list owner for LDAP Group details display */
+#define MAIL_LISTOWNER_ITEM "ListOwner" /* List owner */
+/* Part of SPR GOTO54JT5Q - Need this to get administrator for LDAP Group details display */
+#define MAIL_LISTADMIN_ITEM "LocalAdmin" /* Group administrator */
+
+/* Address Book - "External Domain Network Information" form item names */
+
+#define MAIL_EXTERNAL_DOMAIN_NETWORK_INFORMATION_FORM "ExternalDomainNetworkInformation" /* Form and type name */
+
+/* Address Book - "User Setup Profile" form item names */
+
+#define PROFILE_FORM "Profile" /* Form and type name */
+
+/* Address Book - "Holiday" form item names */
+
+#define HOLIDAY_FORM "Holiday" /* Form and type name */
+
+/* Address Book - "(Alternate Language Personal Information)" form item names */
+
+#define LDAP_ALT_LANGUAGE_PERSONAL_INFO_FORM "AltLanguagePersonalInfo" /* Form and type name */
+
+/* Address Book - "(FileProtection)" form item names */
+
+#define FILE_PROTECTION_FORM "FileProtection" /* Form and type name */
+
+/* Address Book - "(Mapping)" form item names */
+
+#define MAPPING_FORM "Mapping" /* Form and type name */
+
+/* Address Book - "(Virtual Server)" form item names */
+
+#define VIRTUAL_SERVER_FORM "VirtualServer" /* Form and type name */
+
+/* Address Book - "Users" name space, items, and names */
+/* Address Book - local $Users namespace */
+#define LOCAL_USERNAMESSPACE "1\\$Users"
+#define USERNAMESSPACE "$Users"
+#define USERNAMESSPACE_ALT "($Users)"
+#define TYPEAHEADNAMESSPACE "$NamesFieldLookup"
+
+/* DB2 - domudf namelookup items */
+#define DB2_NAMELOOKUPITEMCOUNT 2
+#define DB2_NAMELOOKUPITEMS "FullName\0DB2UserName"
+
+#define MAIL_NAMELOOKUPITEMCOUNT 17
+#define MAIL_NAMELOOKUPSIMPLEITEMCOUNT 12 /* Excludes PublicKey */
+#define MAIL_LOCALNAMELOOKUPSIMPLEITEMCOUNT 13 /* Includes LNAB Entry */
+#define MAIL_LOCALNAMELOOKUPITEMCOUNT 19 /* Includes LNAB fields */
+
+#define MAIL_NAMELOOKUPITEMS \
+"FullName\0MailDomain\0MailAddress\0Location\0ListName\0Members\0InternetAddress\0AltFullName\0MessageStorage\0AltFullNameLanguage\0\
+$$NoteID\0$$DBName\0$$LNAB\0PublicKey\0Certificate\0UserCertificate\0$$LNABHasCertificates\0$$LNABHasUserCertificates\0SmimeUserCapabilities\0"
+
+#define FULLNAMEITEM 0
+#define DOMAINNAMEITEM 1
+#define MAILADDRESSITEM 2
+#define LOCATIONITEM 3
+#define LISTNAMEITEM 4
+#define MEMBERSITEM 5
+#define INTERNETADDRESSITEM 6
+#define ALTFULLNAMEITEM 7
+#define STORAGETYPEITEM 8
+#define ALTFULLNAMELANGUAGEITEM 9
+#define NOTEIDITEM 10
+#define DBNAMEITEM 11
+#define LNABENTRY 12
+#define PUBLICKEYITEM 13
+#define CERTIFICATEITEM 14
+#define USERCERTIFICATEITEM 15
+#define HASCERTIFICATEITEM 16
+#define HASUSERCERTIFICATEITEM 17
+#define SMIMECAPABILITYITEM 18
+
+
+/* Mail Group Expansion NAMELookup items (router\expander.c) */
+#define MAIL_GEX_NAMELOOKUPITEMCOUNT 5
+#define MAIL_GEX_NAMELOOKUPITEMS "FullName\0ListName\0Members\0MailAddress\0$$Readers"
+#define GEX_FULLNAMEITEM 0
+#define GEX_LISTNAMEITEM 1
+#define GEX_MEMBERSITEM 2
+#define GEX_MAILADDRESSITEM 3
+#define GEX_READERSITEM 4
+
+/* Lightweight Address book definitions */
+#define LNAB_ENTRY_Y 'Y'
+#define LNAB_ENTRY_YES "Y"
+#define LNAB_ENTRY_NO "N"
+#define LNAB_ENTRY_ITEM "$$LNAB"
+#define LNAB_HASCERTIFICATES_ITEM "$$LNABHasCertificates"
+#define LNAB_HASUSERCERTIFICATES_ITEM "$$LNABHasUserCertificates"
+#define FIELD_JIT_ITEM "$$JIT"
+#define FIELD_JITFAILED_ITEM "$$JITFailed"
+
+#define FIELD_FROM_BOOKMARK_ITEM "$$FromBookmark"
+#define FIELD_SAVE_NOTE_CLASS_ITEM "$$SaveNoteClass"
+#define FIELD_OUTLINE_POSITION_ITEM "OutlinePosition"
+
+#define MAIL_DELIVERYLOOKUPITEMCOUNT 12
+#define MAIL_DELIVERYSIMPLEITEMCOUNT 7 /* Excludes PublicKey */
+#define MAIL_DELIVERYLOOKUPITEMS \
+"FullName\0MailAddress\0MailServer\0MailFile\0ShortName\0ListName\0$$Readers\0\
+PublicKey\0EncryptIncomingMail\0MailDomain\0Certificate\0UserCertificate"
+
+#define MAIL_DELIVERYFULLNAMEITEM 0
+#define MAIL_DELIVERYMAILADDRESSITEM 1
+#define MAIL_DELIVERYMAILSERVERITEM 2
+#define MAIL_DELIVERYMAILFILEITEM 3
+#define MAIL_DELIVERYSHORTNAMEITEM 4
+#define MAIL_DELIVERYLISTNAMEITEM 5
+#define MAIL_DELIVERYREADERSITEM 6
+#define MAIL_DELIVERYPUBLICINFO 7
+#define MAIL_DELIVERYENCRYPTINCOMING 8
+#define MAIL_DELIVERYMAILDOMAINITEM 9
+#define MAIL_DELIVERYCERTIFICATEITEM 10
+#define MAIL_DELIVERYUSERCERTIFICATEITEM 11
+
+
+/* Address Book - "Domains" name space, items, and names */
+
+#define DOMAINNAMESSPACE "$Domains"
+#define ALIASDOMAINNAMESSPACE "($Domains)"
+
+#define MAIL_DOMAINLOOKUPITEMS "DomainName\0NextDomain\0MailServer\0MailFile"
+#define MAIL_DOMAINNAMEITEM 0
+#define MAIL_DOMAINNEXTDOMAINITEM 1
+#define MAIL_DOMAINMAILSERVERITEM 2
+#define MAIL_DOMAINMAILFILEITEM 3
+#define MAIL_DOMAINLOOKUPITEMCOUNT 4
+
+#define MAIL_DEFAULTGLOBALDOMAIN_ITEM "DefaultGlobalDomain"
+#define MAIL_SMTPDOMAINSUFFIXES_ITEM "SMTPDomainSuffixes"
+#define MAIL_GLOBALDOMAIN_ITEM "GlobalDomain"
+#define MAIL_SMTPADDRESSFORMAT_ITEM "SMTP822Format"
+#define MAIL_SMTPNOTESDOMAININCLUDED_ITEM "SMTPNotesDomainIncluded"
+#define MAIL_SMTPNOTESDOMAINSEPCHAR_ITEM "SMTPNotesDomainSepChar"
+#define MAIL_SMTPNOTESDOMAINPOS_ITEM "SMTPNotesDomainPos"
+#define MAIL_SMTPADDRLOOKUP_ITEM "SMTPAddrLookup"
+#define MAIL_SMTPLOCALPART_ITEM "SMTPLocalPart"
+#define MAIL_SMTPNOTESDOMAINLIST_ITEM "NotesDomainList"
+#define MAIL_SMTPALIASSEPCHAR_ITEM "DomainSeparatorChar"
+#define MAIL_SMTPADDRFORMAT_ADDRONLY '1'
+#define MAIL_SMTPADDRFORMAT_NAMEANDADDR '2'
+#define MAIL_SMTPLOCALPART_FULL '0'
+#define MAIL_SMTPLOCALPART_INTEGER_FULL 0
+#define MAIL_SMTPLOCALDOMAINSINCLUDED_99 "99"
+#define MAIL_SMTPLOCALDOMAINSINCLUDED_1 "1"
+#define MAIL_SMTPLOCALDOMAINSINCLUDED_0 "0"
+#define MAIL_SMTPLOCALPART_CN '1'
+#define MAIL_SMTPLOCALPART_INTEGER_CN 1
+#define MAIL_SMTPLOCALPART_SHORTNAME '2'
+#define MAIL_SMTPLOCALPART_INTEGER_SHORTNAME 2
+#define MAIL_SMTPLOCALDOMAINPOS_LEFT '1'
+#define MAIL_SMTPLOCALDOMAINPOS_RIGHT '2'
+#define MAIL_SMTPLOCALDOMAINSEPCHAR '%'
+#define MAIL_SMTPLOCALDOMAINS_NONE 0
+#define MAIL_SMTPLOCALDOMAINS_ONE 1
+#define MAIL_SMTPLOCALDOMAINS_ALL 127
+#define MAIL_SMTPADDRLOOKUP_DISABLED '0'
+#define MAIL_SMTPADDRLOOKUP_ENABLED '1'
+
+#define SMTPMTA_SUBFORM "$SMTPServerFormSubForm" /* Used by setup */
+
+/* Address Book - "Servers" name space, items, and names */
+
+#define SERVERNAMESSPACE "$Servers"
+#define SERVERNAMESSPACE_1 "1\\$Servers"
+#define DIRECTORIESNAMESSPACE "$Directories"
+#define DIRECTORIESNAMESSPACE_1 "1\\$Directories"
+
+
+#define MAIL_SERVERLOOKUPITEMS "ServerName\0Domain\0Network"
+#define MAIL_SERVERNAMEITEM 0
+#define MAIL_SERVERDOMAINITEM 1
+#define MAIL_SERVERNETWORKITEM 2
+#define MAIL_SERVERLOOKUPITEMCOUNT 3
+
+/* Address Book - "$People" name space, items, and names */
+
+#define MAIL_PEOPLENAMESPACE "$People"
+
+#define MAIL_PEOPLELOOKUPITEMS "FullName"
+#define MAIL_PEOPLEFULLNAMEITEM 0
+#define MAIL_PEOPLELOOKUPITEMCOUNT 1
+
+/* Address Book - "$Groups" name space, items, and names */
+
+#define MAIL_GROUPSNAMESPACE "$Groups"
+#define MAIL_GROUPSNAMESPACE_1 "1\\$Groups"
+
+#define REGISTER_GROUPSNAMESPACE "($RegisterGroups)"
+
+
+/* Group type definitions */
+#define GROUP_TYPE_MULTIPURPOSE '0'
+#define GROUP_TYPE_MAILONLY '1'
+#define GROUP_TYPE_ACCESSCONTROL '2'
+#define GROUP_TYPE_DENYLIST '3'
+
+#define MAIL_GROUPSLOOKUPITEMCOUNT 1
+#define MAIL_GROUPSLOOKUPITEMS "ListName"
+#define MAIL_GROUPSGROUPNAMEITEM 0
+
+/* Address Book - "$NameFieldLookup" name space, items, and names (Typeahead) */
+#define LOCAL_MAIL_NAMEFIELD_LOOKUP "1\\$NamesFieldLookup"
+#define MAIL_NAMEFIELD_LOOKUP "$NamesFieldLookup"
+#define TYPEAHEAD_STATUS_ITEM "TypeaheadStatus"
+#define DISABLE_TYPEAHEAD "DISABLE_TYPEAHEAD"
+
+/* Address Book - Name field composite lookup */
+
+#define MAIL_NAMEFIELD_COMPOSITE_NAMESSPACE "$Users\0$Groups\0$ServersLookup"
+#define NAMEFIELDCOMPOSITENAMESPACES 3
+
+/* Address Book - Server lookup */
+
+#define MAIL_SERVERSLOOKUP_NAMESSPACE "$ServersLookup"
+
+#define SERVERGROUPS_NAMESSPACE "($ServerGroups)"
+
+
+
+/* Address Book - public views displayed by the admin subprogram */
+
+#define ADMIN_GROUPS_VIEW "Groups"
+#define ADMIN_PEOPLE_VIEW "People"
+#define ADMIN_SERVERS_VIEW "Servers"
+#define ADMIN_CONFIGURATIONS_VIEW "Configurations"
+#define ADMIN_WEBCONFIGURATIONS_VIEW "WebConfigurations"
+#define ADMIN_CONNECTIONS_VIEW "Connections"
+#define ADMIN_PROGRAMS_VIEW "Programs"
+#define ADMIN_DOMAINS_VIEW "Domains"
+#define ADMIN_CLUSTERS_VIEW "Clusters"
+#define ADMIN_CERTIFICATES_VIEW "Certificates"
+#define ADMIN_LICENSES_VIEW "Licenses"
+#define ADMIN_HOLIDAYS_VIEW "Holidays"
+#define HIDDEN_HOLIDAYS_VIEW "($Holidays)"
+#define HIDDEN_NOTESINI_VIEW "($ServerParameters)"
+#define ADMIN_EXT_DOMAIN_NET_INFO_VIEW "ExternalDomainNetworkInformation"
+#define ADMIN_REP_EVENTS_VIEW "Replication Events"
+#define ADMIN_MAIL_USERS "Mail Users"
+#define ADMIN_MAILBOX_VIEW "Mail"
+#define ADMIN_POLICIES_VIEW "Policies"
+#define ADMIN_SETTINGS_VIEW "Settings"
+#define ADMIN_DIRECTORIES_VIEW "Directories"
+#define ADMIN_AGGDIRCFG_VIEW "AggregateDirConfig"
+#define ADMIN_CERT_AUTH_VIEW "Server\\Certificate Authorities"
+#define ADMIN_FILE_ID_VIEW "FileIdentifications"
+#define ADMIN_HOSTED_ORGS_VIEW "HostedOrganizations"
+#define ADMIN_SITES_VIEW "InternetSites"
+#define ADMIN_CERT_EXP_VIEW "PeopleCertExpiration"
+
+/* Address Book - Items and names used by Admin Panel */
+
+#define ADMIN_SERVERTYPEITEM 0
+#define ADMIN_SERVERNAMEITEM 1
+#define ADMIN_SERVERTITLEITEM 2
+#define ADMIN_SERVERDOMAINITEM 3
+#define ADMIN_SERVERNETWORKITEM 4
+#define ADMIN_SERVERCLUSTERNAMEITEM 5
+#define ADMIN_SERVERADMINISTRATORITEM 6
+#define ADMIN_SERVERVERSIONITEM 7
+#define ADMIN_SERVEROSITEM 8
+#define ADMIN_SERVERHOSTNAMEITEM 9
+#define ADMIN_SERVERDB2INSTANCEITEM 10
+#define ADMIN_SERVERDB2DIRECTORYITEM 11
+#define ADMIN_SERVERDB2DATABASEITEM 12
+#define ADMIN_SERVERDB2SCHEMAITEM 13
+#define ADMIN_SERVERDB2HOSTITEM 14
+#define ADMIN_SERVERDB2PORTITEM 15
+#define ADMIN_SERVERDB2DEFAULTITEM 16
+#define ADMIN_SERVERDB2UDFSRVITEM 17
+#define ADMIN_SERVERDB2UDFPATHITEM 18
+#define ADMIN_SERVERDB2ACCESSITEM 19
+#define ADMIN_SERVERLOOKUPITEMCOUNT 20
+#define ADMIN_SERVERLOOKUPITEMS "Type\0ServerName\0ServerTitle\0Domain\0Network\0ClusterName\0Administrator\0ServerBuildNumber\0ServerPlatform\0SMTPFullHostDomain\0DB2Inst\0DB2Dir\0DB2Db\0DB2Sche\0DB2Host\0DB2Port\0DB2Def\0DB2UDFSrv\0DB2UDFPath\0DB2AccessServer"
+
+#define ADMIN_SERVERGROUPLISTITEM 0
+#define ADMIN_SERVERGROUPLOOKUPITEMCOUNT 1
+#define ADMIN_SERVERGROUPLOOKUPITEMS "ListName"
+
+
+/* Address Book - Items and names outputted to admindata.xml for the Java controller */
+
+#define ADMINDATA_SERVERTYPEITEM 0
+#define ADMINDATA_SERVERNAMEITEM 1
+#define ADMINDATA_SERVERTITLEITEM 2
+#define ADMINDATA_SERVERDOMAINITEM 3
+#define ADMINDATA_SERVERNETWORKITEM 4
+#define ADMINDATA_SERVERCLUSTERNAMEITEM 5
+#define ADMINDATA_SERVERADMINISTRATORITEM 6
+#define ADMINDATA_SERVERVERSIONITEM 7
+#define ADMINDATA_SERVEROSITEM 8
+#define ADMINDATA_SERVERHOSTNAMEITEM 9
+#define ADMINDATA_SERVERCONTROLLERIP 10
+#define ADMINDATA_SERVERCONTROLLERPORT 11
+#define ADMINDATA_SERVERDB2ACCESSITEM 12
+#define ADMINDATA_SERVERDB2SCHEMAITEM 13
+#define ADMINDATA_SERVERLOOKUPITEMCOUNT 14
+#define ADMINDATA_SERVERLOOKUPITEMS "Type\0ServerName\0ServerTitle\0Domain\0Network\0ClusterName\0Administrator\0ServerBuildNumber\0ServerPlatform\0SMTPFullHostDomain\0DC_IP_Address\0DC_Port\0DB2AccessServer\0DB2Sche"
+
+/* Databases opened and displayed by the admin subprogram */
+
+#define ADMIN_LOG_FILE "log.nsf"
+#define ADMIN_CATALOG5_FILE "catalog.nsf"
+#define ADMIN_CATALOG_FILE "catalog.nsf"
+#define ADMIN_EVENTS_FILE "statrep.nsf"
+#define ADMIN_EVENT4_CONFIG_FILE "events4.nsf"
+#define ADMIN_EVENT4_SAV_FILE "events4.sav" /* In R5, we save off the users EVENTS4.NSF as EVENTS4.SAV */
+#define ADMIN_EVENT_CONFIG_FILE "events4.nsf"
+#define ADMIN_EVENT_CONFIG_TEMPLATE "events4.ntf"
+#define ADMIN_CERT_LOG_FILE "certlog.nsf"
+#define ADMIN_CERT_LOG_TEMPLATE "certlog.ntf"
+#define ADMIN_WEB_LOG_FILE "domlog.nsf"
+#define ADMIN_WEBCONFIG_FILE "domcfg.nsf"
+#define ADMIN_CERT_CA_FILE "certca.nsf"
+#define ADMIN_CERT_SRV_FILE "certsrv.nsf"
+#define ADMIN_REPORTS "reports.nsf"
+#define ADMIN_DECS_CFG "decsadm.nsf"
+#define ADMIN_DOLS_CFG "doladmin.nsf"
+#define ADMIN_FILE "domadmin.nsf"
+#define ADMIN_LDAP_SCHEMA "schema.nsf"
+#define ADMIN_LDAP_R5_SCHEMA "schema50.nsf"
+#define ADMIN_SMART_UPDATE_FILE "smupdate.nsf"
+#define ADMIN_LICENSE_TRK_FILE "userlicenses.nsf"
+#define ADMIN_CERT_PUB_FILE "certpub.nsf"
+#define ADMIN_CERT_REQ_FILE "certreq.nsf"
+
+#define ADMIN_FAULTREPORTS_FILE "lndfr.nsf"
+#define ADMIN_FAULTREPORTS_TEMPLATE "lndfr.ntf"
+
+#define ADMIN_REPORT_FORM "faReport"
+
+/* SMTP MTA files */
+#define ADMIN_SMTP_BOX "smtp.box"
+#define ADMIN_SMTP_IQ "smtpibwq.box"
+#define ADMIN_SMTP_OQ "smtpobwq.box"
+
+/* cc:Mail MTA files */
+#define ADMIN_CCMTA_BOX "ccmail.box"
+#define ADMIN_CCMTA_WQ "ccmcwq.box"
+
+/* X.400 MTA files */
+#define ADMIN_X400_BOX "x400.box"
+#define ADMIN_X400_DEAD "dead.box"
+#define ADMIN_X400_LOG "x400log.nsf"
+#define ADMIN_X400_MADMAN "madman.nsf"
+
+/* Softswitch files */
+#define ADMIN_SSW "ssw.nsf"
+
+/* Defense Messaging System files */
+#define ADMIN_DMS_BOX "dms.box"
+#define ADMIN_DMS_HOLD "dmshold.box"
+
+/* MTA Config dbs */
+#define ADMIN_MTA_CFG "mtatbls.nsf" /* MTA configuration tables, used by smtp, ccmail and x400 mta */
+#define ADMIN_MTA_FORMS "mtaforms.nsf" /* MTA forms, also used by all mta's */
+
+/* View in MAB used by admin */
+#define ADMIN_DA_VIEW "Directory Assistance"
+
+/* Schedule items in the events4.nsf */
+
+#define EVENT_SCHED_TYPE_ITEM "$sched.def"
+#define EVENT_SCHED_INTERVAL_UNIT_ITEM "$sched.unit"
+#define EVENT_SCHED_INTERVAL_ITEM "$sched.freq"
+#define EVENT_SCHED_24X7_ITEM "$sched.always"
+#define EVENT_SCHED_WEEKDAYS_ITEM "$sched.days"
+#define EVENT_SCHED_WEEKDAY_ITEM "$sched.single.day"
+#define EVENT_SCHED_START_HOURS_ITEM "$sched.start"
+#define EVENT_SCHED_END_HOURS_ITEM "$sched.end"
+#define EVENT_SCHED_TIME_ITEM "$sched.spec.time"
+#define EVENT_SCHED_MONTHDAY_ITEM "$sched.dom"
+#define EVENT_SCHED_MISS_ITEM "$sched.miss"
+
+#define EVENT_PROBE_INTERVAL_SECONDS 1
+#define EVENT_PROBE_INTERVAL_MINUTES 2
+#define EVENT_PROBE_DEFAULT_WEEKLY_DAY "2"
+#define EVENT_PROBE_DEFAULT_MONTH_DAY "1"
+
+#define EVENT_PROBE_TARGETSERVERS "TargetServers"
+#define EVENT_PROBE_PROBESERVER "ProbeServer"
+
+#define EVENT_PROBE_MISS_IGNORE 1
+#define EVENT_PROBE_MISS_STARTUP 2
+#define EVENT_PROBE_MISS_SCHED 3
+
+#define EVENT_PROBE_INTERVAL_SCHED 1
+#define EVENT_PROBE_DAILY_SCHED 2
+#define EVENT_PROBE_WEEKLY_SCHED 3
+#define EVENT_PROBE_MONTHLY_SCHED 4
+
+#define EVENT_PROBE_APP_ITEM "ProbeApp"
+#define EVENT_PROBE_DESCRIPTION_ITEM "description"
+#define EVENT_PROBE_AREA_ITEM "DNTType"
+#define EVENT_PROBE_AREA_SUBTYPE_ITEM "SubType"
+#define EVENT_PROBE_DLLNAME_ITEM "probedll"
+#define EVENT_PROBE_DLLFUNC_ITEM "func"
+#define EVENT_PROBE_DISABLED_ITEM "Disabled"
+#define EVENT_PROBE_PUID_ITEM "puid"
+#define EVENT_PROBE_FORM_ITEM "Form"
+
+#define ISPY_MAIL_FAIL_TIMEOUT "msg.nrpc.timeout.fail"
+#define ISPY_MAIL_WARN_HIGH_TIMEOUT "msg.nrpc.timeout.warn.high"
+#define ISPY_MAIL_WARN_LOW_TIMEOUT "msg.nrpc.timeout.warn.low"
+#define ISPY_MAIL_FAIL_ENABLE "msg.nrpc.fail.enable"
+#define ISPY_MAIL_WARN_HIGH_ENABLE "msg.nrpc.warn.high.enable"
+#define ISPY_MAIL_WARN_LOW_ENABLE "msg.nrpc.warn.low.enable"
+#define ISPY_MAIL_TARGET_RECIPIENT "msg.targetrecipient"
+#define ISPY_MAIL_MAIL_STATISTIC_NAME "MailProbeStatisticName"
+#define ISPY_MAIL_SOURCE_SERVER "SourceServerName"
+#define ISPY_MAIL_ALL_SELF_MONITOR "AllSelfMonitor"
+#define ISPY_MAIL_SHOW_HOPS "ShowHops"
+#define ISPY_PROBE_METHOD "ProbeMethod"
+
+#define ISPY_TCP_TARGET_SERVER "TargetServerName"
+#define ISPY_TCP_TCP_TIMEOUT "TCPTimeOut"
+#define ISPY_TCP_SSL_TIMEOUT "SSLTimeOut"
+#define ISPY_TCP_HTTP_URL "HTTPUrl"
+#define ISPY_TCP_HTTP_URL_FETCH "HTTPUrlFetch"
+#define ISPY_TCP_HTTPSSL_URL "HTTPSSLUrl"
+#define ISPY_TCP_HTTPSSL_URL_FETCH "HTTPSSLUrlFetch"
+#define ISPY_TCP_NNTP_COMMAND_SEND "NNTPCommandSend"
+#define ISPY_TCP_NNTP_COMMAND "NNTPCommand"
+#define ISPY_TCP_NNTP_PARAMETERS "NNTPParameters"
+#define ISPY_TCP_NNTP_GROUP "NNTPGroup"
+#define ISPY_TCP_NNTPSSL_COMMAND_SEND "NNTPSSLCommandSend"
+#define ISPY_TCP_NNTPSSL_COMMAND "NNTPSSLCommand"
+#define ISPY_TCP_NNTPSSL_PARAMETERS "NNTPSSLParameters"
+#define ISPY_TCP_NNTPSSL_GROUP "NNTPSSLGroup"
+#define ISPY_TCP_SOURCE_SERVER "SourceServerName"
+#define ISPY_TCP_ALL_SELF_MONITOR "AllSelfMonitor"
+#define ISPY_TCP_SERVICES "Services"
+#define ISPY_TCP_ALL_SERVICES "AllServices"
+#define ISPY_TCP_ALL_TARGET_SERVERS "AllTargetServers"
+
+#define ISPY_MAIL_POLLER_FUNC "GetMailPollerProbe"
+#define ISPY_TCP_POLLER_FUNC "GetTCPPollerProbe"
+
+#define EVENT_PROBE_TARGETDBS "TargetDbs"
+
+#define DDM_PROBE_TYPE_AGENT 0
+#define DDM_PROBE_TYPE_APPLICATION 1
+#define DDM_PROBE_TYPE_DIRECTORIES 2
+#define DDM_PROBE_TYPE_MESSAGING 3
+#define DDM_PROBE_TYPE_REPLICATION 4
+#define DDM_PROBE_TYPE_SECURITY 5
+#define DDM_PROBE_TYPE_WEB 6
+#define DDM_PROBE_TYPE_ADMINP 7
+
+#define DDM_PROBE_TEXT_AGENT "application code" /* formerlly "agent", made more inclusive for applets,web services */
+#define DDM_PROBE_TEXT_APPLICATION "application"
+#define DDM_PROBE_TEXT_DATABASE "database"
+#define DDM_PROBE_TEXT_DIRECTORIES "directory"
+#define DDM_PROBE_TEXT_MESSAGING "messaging"
+#define DDM_PROBE_TEXT_OS "operating system"
+#define DDM_PROBE_TEXT_REPLICATION "replication"
+#define DDM_PROBE_TEXT_SECURITY "security"
+#define DDM_PROBE_TEXT_WEB "web"
+#define DDM_PROBE_TEXT_ADMINP "server"
+
+#define DDM_PROBE_SUBTYPE_TEXT_COMPACT "compact"
+#define DDM_PROBE_SUBTYPE_TEXT_DB "Database"
+#define DDM_PROBE_SUBTYPE_TEXT_DESIGN "design"
+#define DDM_PROBE_SUBTYPE_TEXT_CONFIG "Configuration"
+#define DDM_PROBE_SUBTYPE_TEXT_BPCONFIG "bestpractices"
+#define DDM_PROBE_SUBTYPE_TEXT_CONFIGREVIEW "review"
+#define DDM_PROBE_SUBTYPE_TEXT_DBREVIEW "dbreview"
+#define DDM_PROBE_SUBTYPE_TEXT_ADMINP "adminp"
+
+
+#define DIR_PROBE_SUBTYPE_TEXT_LDAP_VIEW_UPDATE "ldapviewupdate"
+#define DIR_PROBE_SUBTYPE_TEXT_LDAP_SEARCH_RESPONSE "ldapsearchresponse"
+#define DIR_PROBE_SUBTYPE_TEXT_DA_SEARCH_RESPONSE "secldapsearchresponse"
+#define DIR_PROBE_SUBTYPE_TEXT_DD_SEARCH_RESPONSE "nrpcsearchresponse"
+#define DIR_PROBE_SUBTYPE_TEXT_AVAILABILITY "availability"
+#define DIR_PROBE_SUBTYPE_TEXT_AGGREGATION "aggregation"
+#define DIR_PROBE_SUBTYPE_TEXT_AGGREGATION_SCHED "aggregationsched"
+#define DIR_PROBE_TARGET_TEXT_NAMES_VIEW_UPDATE "NamesViewUpdate"
+
+#define DDM_TSK_CHECK_FUNC "GetLegacyProbeTaskCheck"
+#define DDM_SRV_ACCESS_FUNC "GetLegacyProbeServerAccess"
+#define DDM_FILE_CHECK_FUNC "GetLegacyProbeFileCheck"
+
+#define DDM_TARGET_PORT "TargetPort"
+#define DDM_TARGET_DOMAIN "TargetDomain"
+#define DDM_TARGET_REPID "TargetReplicaID"
+
+#define DDM_JS_APP_EVENT 0
+#define DDM_JS_APP_ISPY 1
+#define DDM_JS_APP_COUNT 2
+
+#define EVENT_PROBE_APP_EVENT 1
+#define EVENT_PROBE_APP_ISPY 2
+#define EVENT_PROBE_APP_EMBEDDED 3
+
+#define EVENT_PROBE_TARGET_SPECIAL_PREFIX '$'
+/* DDM special target servers */
+#define EVENT_PROBE_SERVER_SPECIAL_ADMIN "$AdminServer"
+#define EVENT_PROBE_SERVER_SPECIAL_LDAPSERVER "$LDAPServer"
+#define EVENT_PROBE_SERVER_SPECIAL_AGGSERVER_SCHED "$ScheduledDircatServer"
+#define EVENT_PROBE_SERVER_SPECIAL_IMAPSERVER "$IMAPServer"
+#define EVENT_PROBE_SERVER_SPECIAL_POP3SERVER "$POP3Server"
+#define EVENT_PROBE_SERVER_SPECIAL_SMTPINSERVER "$SMTPInServer"
+#define EVENT_PROBE_SERVER_SPECIAL_MAILROUTINGSERVER "$MailRoutingServer"
+
+#define EVENTS_DDM_PROBE_VIEW "($DDMConfig)"
+
+#define DDM_REPL_FLAGS_PULL 0x0001
+#define DDM_REPL_FLAGS_PUSH 0x0002
+
+#define DDM_REPL_FLAGS_NOTE_CONFLICT 0x0004
+#define DDM_REPL_FLAGS_NOTE_ERR 0x0008
+#define DDM_REPL_FLAGS_DISABLE_ON_ORIG 0x0010
+#define DDM_REPL_FLAGS_DISABLE_ON_TARG 0x0020
+#define DDM_REPL_FLAGS_NOTE_NONDATA 0x0040
+
+#define DDM_CONFIG_CHECK_TYPE_REPLCHECK 0x0001
+#define DDM_CONFIG_CHECK_TYPE_ERROR 0x0002
+#define DDM_REPL_FLAGS_NOTE_CONFLICT 0x0004
+
+/* View in events5 displayed by the monitor subprogram */
+
+#define ADMIN_STATSEL_VIEW "($StatSelection)"
+#define ADMIN_NUM_STATSEL_VIEW "($NumericalStatSelection)"
+#define ADMIN_STATISTIC_VIEW "($StatisticsPer)"
+#define ADMIN_NUMBER_TYPE "Number"
+#define EVENTS_VIEW "($Events)"
+#define ADMIN_NUM_STATSEL_R5_VIEW "($R5Statistics)"
+#define ADMIN_NUM_STATSEL_R6_VIEW "($D6Statistics)"
+
+#define ADMIN_TRENDS_ALL_VIEW "($StatTrendsAll)"
+#define ADMIN_TRENDS_SERVERS_VIEW "($StatTrendsServer)"
+#define ADMIN_TRENDS_DAILY_VIEW "($StatTrendsServerDaily)"
+#define ADMIN_TRENDS_HOURLY_VIEW "($StatTrendsServerHourly)"
+#define ADMIN_TRENDS_DB_VIEW "($StatTrendsDatabase)"
+#define ADMIN_TRENDS_USERS_VIEW "($StatTrendsUser)"
+#define ADMIN_TRENDS_PROFILE_VIEW "($StatTrendsActivityProfile)"
+#define ADMIN_TRENDS_CONNECTIONS_VIEW "($StatTrendsConnections)"
+#define ADMIN_LOADBAL_VIEW "($LoadBalanceStats)"
+#define ADMIN_LOADBAL_PROFILES_VIEW "($LoadBalanceProfiles)"
+
+#define ADMIN_STATNAME_ITEM "StatName"
+#define ADMIN_HASTRENDED_ITEM "HasTrended"
+#define ADMIN_HASPRIME_ITEM "HasPrime"
+#define ADMIN_UNITS_ITEM "Units"
+#define ADMIN_DESCRIPTION_ITEM "Description"
+#define ADMIN_PROFILESTAT_ITEM "IsProfileStat"
+#define ADMIN_LOADBALSTAT_ITEM "IsLoadBalance"
+#define ADMIN_LOADBALCAT_ITEM "LoadBalancingCategory"
+#define ADMIN_LOADBALNAME_ITEM "LoadBalanceName"
+#define ADMIN_COMPOSITESTATS_ITEM "CompositeStats"
+
+#define ADMIN_NUMBERLIST_TYPE "NumberList"
+#define ADMIN_TEXTLIST_TYPE "TextList"
+#define ADMIN_TEXT_TYPE "Text"
+#define ADMIN_TIMEDATE_TYPE "Time"
+#define ADMIN_SMART_UPDT_LINK_ITEM "SmartUpdDBLink"
+#define ADMIN_SU_GOVERNOR_ENABLED "SUGEnabled"
+#define ADMIN_SU_GOVERNOR_MAX_USER "SUGMaxUser"
+
+
+/* Form and view in domadmin used by trends charts */
+#define ADMIN_TRENDS_PROFILES_FORM "GraphTrendsProfile"
+#define ADMIN_TRENDS_PROFILES_VIEW "($GraphTrendsProfiles)"
+
+/* Trends profile types */
+#define ADMIN_TRENDS_PROFILE_SERVER "Server"
+#define ADMIN_TRENDS_PROFILE_DB "Database"
+#define ADMIN_TRENDS_PROFILE_USER "User"
+#define ADMIN_TRENDS_PROFILE_CONNECTION "Connection"
+#define ADMIN_TRENDS_PROFILE_HISTORY "History"
+#define ADMIN_TRENDS_PROFILE_DAILY "Daily"
+#define ADMIN_TRENDS_PROFILE_HOURLY "Hourly"
+#define ADMIN_TRENDS_PROFILE_ACTIVITY "Activity"
+
+/* Database containing UNAME database directory */
+
+#define UNAME_FILE "unames.nsf"
+
+/* Address Book - "ServerAccess" namespace, items, and names */
+
+#define ACCESS_GROUPS_NAMESPACE "$ServerAccess"
+#define ACCESS_GROUPS_NAMESPACE_1 "1\\$ServerAccess"
+
+#define MAIL_GROUPS_NAMESPACE "$MailGroups"
+#define MAIL_GROUPS_NAMESPACE_1 "1\\$MailGroups"
+
+#define ACCESS_ITEM_LISTNAME 0
+#define ACCESS_ITEM_DBINDEX 1
+#define ACCESS_ITEM_DOMAINTYPE 2
+#define ACCESS_GROUPEXP_LOOKUPITEMCOUNT 3
+#define ACCESS_LISTNAME_ITEM "ListName"
+#define ACCESS_GROUPEXP_LOOKUPITEMS "ListName\0$$DBIndex\0$$DomainType"
+
+/* Address Book - $Users name space, to look up server access */
+
+#define ACCESS_LOOKUP_ITEMS "FullName"
+#define ACCESS_ITEM_FULLNAME 0
+#define ACCESS_ITEM_COUNT 1
+
+/* Address Book -- $Adminp name space, for admin proxy agent */
+#define ADMINP_NAMESPACE "$Adminp"
+
+/* Address Book configuration parameters for the administration process */
+#define ADMINP_CONFIG_MAX_THREADS "AdminPMaxThreads" /* number */
+#define ADMINP_CONFIG_INTERVAL "AdminPInterval" /* number */
+#define ADMINP_CONFIG_DAILY_TIME "AdminPDailyTime" /* time */
+#define ADMINP_CONFIG_WEEK_DAYS "AdminPWeekDays" /* text list */
+#define ADMINP_CONFIG_DELAYED_TIME "AdminPDelayedTime"/* time */
+#define ADMINP_CONFIG_DEL_MAIL_FILE "AdminPMailFileDelInt" /* number */
+#define ADMINP_CONFIG_SUSPEND_RANGE "AdminPSuspendRange" /* timedate range */
+#define ADMINP_CONFIG_SAVE_NRESP "AdminPLogSetting"
+#define ADMINP_CONFIG_NAME_CHANGE_X "AdminPNameChangeExpiration"
+
+#define ADMINP_LOCAL_ADMIN "LocalAdmin"
+#define ADMINP_ALLOW_ACCESS "AllowAccess"
+#define ADMINP_DENY_ACCESS "DenyAccess"
+#define ADMINP_CREATE_ACCESS "CreateAccess"
+#define ADMINP_REPLICA_ACCESS "ReplicaAccess"
+#define ADMINP_PT_ACCESS "PTAccess"
+#define ADMINP_PT_CLIENTS "PTClients"
+#define ADMINP_PT_CALLERS "PTCallers"
+#define ADMINP_PT_TARGETS "PTTargets"
+#define ADMINP_LIST_OWNER "ListOwner"
+#define ADMINP_PASSTHRU_SERVER "PassthruServer"
+#define ADMINP_SMTP_ADMINISTRATOR "SMTPAdministrator"
+#define ADMINP_GROUP_TYPE "GroupType"
+#define ADMINP_PRIVATE_LIST "PrivateList"
+#define ADMINP_RESTRICTED_LIST "RestrictedList"
+#define ADMINP_UNRESTRICTED_LIST "UnrestrictedList"
+#define ADMINP_SERVERS_CPU_COUNT "ServerCPUCount"
+#define ADMINP_X509_CERT_PRESENT "$X509CertIsPresent"
+#define ADMINP_CCMAIL_ADMINISTRATOR "CCMAdmin"
+#define ADMINP_REQUESTING_SERVER_ITEM "RequestingServer"
+
+#define ADMINP_ACCESS_SERVER_INPUT_ITEM "AccessServerInput"
+#define ADMINP_ALLOW_NOTES_ADDR_ITEM "AllowNotesAddressesToMail"
+#define ADMINP_DENY_NOTES_ADDR_ITEM "DenyNotesAddressesToMail"
+#define ADMINP_NOI_RESTRICTED_ITEM "NOIRestrictedList"
+#define ADMINP_NOI_UNRESTRICTED_ITEM "NOIUnrestrictedList"
+#define ADMINP_REPORT_RECIPIENTS_ITEM "ReportRecipients"
+
+#define ADMINP_STATS_CPU_COUNT "CPU.Count"
+#define ADMINP_SERVER_PLATFORM "ServerPlatform"
+#define ADMINP_SERVER_DIRECTORY_NAME "ServerDirectoryName"
+#define ADMINP_SERVER_CONFIG_NAB "CfgNABonly"
+
+#define ADMINP_PROFILE_NOTEID "%NoteID"
+#define ADMINP_PROFILE_SIGNATURE_ITEM "$Sig_Signature"
+#define ADMINP_XDOMAIN_TRUSTED_ADMINS_ITEM "CrossDomainTrustedAdmins"
+#define ADMINP_DIR_PROFILE_NAME "DirectoryProfile"
+
+/* values for resource database */
+#define ADMINP_RESOURCE_DOCUMENT "Resource"
+#define ADMINP_RESOURCE_NAME_ITEM "ResourceName"
+#define ADMINP_PROGRAM_FORM "Program"
+
+/* known values of fields in the proxy database document form */
+#define AdminpDelete "0"
+#define AdminpRenameInTheACL "1"
+#define AdminpCopyPublicKey "2"
+#define AdminpStoreServerVersion "3"
+#define AdminpRenameServerInNAB "4"
+#define AdminpRenameUserInNAB "5"
+#define AdminpMoveUserInHier "6"
+#define AdminpDeleteStats "7"
+#define AdminpInitiateNABChange "8"
+#define AdminpRecertServerInNAB "9"
+#define AdminpRecertUserInNAB "10"
+#define AdminpServerClusterAdd "11"
+#define AdminpServerClusterRemove "12"
+#define AdminpCreateReplicas "13"
+#define AdminpMoveReplicas "14"
+#define AdminpPendedDeleteForMove "15"
+#define AdminpDeleteInPersonDocs "16"
+#define AdminpDeleteInTheACL "17"
+#define AdminpDeleteInReadersAuthors "18"
+#define AdminpRenameInPersonDocs "19"
+#define AdminpRenameInReadersAuthors "20"
+#define AdminpDeleteMailFile "21"
+#define AdminpApproveMailFileInfo "22"
+#define AdminpDeleteUnlinkedMailFile "23"
+#define AdminpCreateMailFile "24"
+#define AdminpMonitorMovedReplica "25"
+#define AdminpDeleteChangeRequests "26"
+#define AdminpGetMailFileInfo "27"
+#define AdminpRequestDeleteMailFile "28"
+#define AdminpResourceAdd "29"
+#define AdminpResourceDelete "30"
+#define AdminpApproveResourceDelete "31"
+#define AdminpCreateReplicasCheckAccess "32"
+#define AdminpMoveReplicasCheckAccess "33"
+#define AdminpSetPasswordFields "34"
+#define AdminpUpdateUserPW "35"
+#define AdminpUpdateServerPW "36"
+#define AdminpSetMABField "37"
+#define AdminpRenamePersonInFreeTime "38"
+#define AdminpRenamePersonInMailFile "39"
+#define AdminpRenameGroupInNAB "40"
+#define AdminpRenameGroupInPersonDocs "41"
+#define AdminpRenameGroupInTheACL "42"
+#define AdminpRenameGroupInReadersAuthors "43"
+#define AdminpAddPersonsX509Certificate "44"
+#define AdminpCheckMailServersAccess "45"
+#define AdminpUpgradeUser "46"
+#define AdminpCopyExternalDomainAddresses "47"
+#define AdminpPromoteMailServersAccess "48"
+#define AdminpCreateNewMailFileReplica "49"
+#define AdminpAddNewMailFileFields "50"
+#define AdminpMonitorNewMailFileFields "51"
+#define AdminpReplaceMailFileFields "52"
+#define AdminpLastPushToNewMailServer "53"
+#define AdminpDeletePersonInNAB "54"
+#define AdminpDeleteServerInNAB "55"
+#define AdminpDeleteGroupInNAB "56"
+#define AdminpDelegateMailFile "57"
+#define AdminpApproveDeletePersonInNAB "58"
+#define AdminpApproveDeleteServerInNAB "59"
+#define AdminpApproveRenamePersonInNAB "60"
+#define AdminpApproveRenameServerInNAB "61"
+#define AdminpResourceModify "62"
+#define AdminpUpdateNetworkTables "63"
+#define AdminpCreateISPYMailInDb "64"
+#define AdminpNCMoveReplicasCheckAccess "65"
+#define AdminpNCMoveReplicas "66"
+#define AdminpStoreServerCPUCount "67"
+#define AdminpRenamePersonInUnreadList "68"
+#define AdminpDeleteReplicaAfterMove "69"
+#define AdminpSetDNSFullHostName "70"
+#define AdminpStoreServerPlatform "71"
+#define AdminpApproveDeleteDesignElements "72"
+#define AdminpRequestDeleteDesignElements "73"
+#define AdminpDeleteDesignElements "74"
+#define AdminpApproveDeleteMovedReplica "75"
+#define AdminpRequestDeleteMovedReplica "76"
+#define AdminpSetDomainCatalog "77"
+#define AdminpWebDelegateMailFile "78"
+#define AdminpGetFileInfo "79"
+#define AdminpRequestDeleteFile "80"
+#define AdminpDeleteFile "81"
+#define AdminpApproveFileInfo "82"
+#define AdminpSetWebAdminFields "83"
+#define AdminpAcceleratedCreateReplica "84"
+#define AdminpSetConfigNAB "85"
+#define AdminpStoreServerDirectoryName "86"
+#define AdminpCreateRoamingUserRoamingFiles "87"
+#define AdminpPromoteRoamingServersAccess "88"
+#define AdminpReplaceRoamingServerField "89"
+#define AdminpMonitorMovedRoamingReplica "90"
+#define AdminpCreateRoamingReplStubs "91"
+#define AdminpRemoveRoamingUserRoamingFiles "92"
+#define AdminpCheckRoamingServerAccess "93"
+#define AdminpCreateRoamingReplicas "94"
+#define AdminpCertPublicationRequest "95"
+#define AdminpCrlPublicationRequest "96"
+#define AdminpUserModifyRequest "97"
+#define AdminpCertRemoveRequest "98"
+#define AdminpPolicyPublicationRequest "99"
+#define AdminpLastPushToNewRoamingServer "100"
+#define AdminpSignDatabase "101"
+#define AdminpCAConfigPublicationRequest "102"
+#define AdminpCrlRemoveRequest "103"
+#define AdminpDelegateIMAPMailFiles "104"
+#define AdminpCAConfigToBeSigned "105"
+#define AdminpRejectRenameUserInNAB "106"
+#define AdminpRetractNameChange "107"
+#define AdminpEnableMailAgent "108"
+#define AdminpReportServerUse "109"
+#define AdminpRejectRetractNameChange "110"
+#define AdminpDeleteServerFromCatalog "111"
+#define AdminpCopyTrendsRecord "112"
+#define AdminpDeletePolicy "113"
+#define AdminpApproveRetractNameChange "114"
+#define AdminpApproveRecertify "115"
+#define AdminpApproveNameChange "116"
+#define AdminpApproveNewPublicKeys "117"
+#define AdminpInitiateWebNameChange "118"
+#define AdminpRenameWebNameInTheACL "119"
+#define AdminpRenameWebNameInNAB "120"
+#define AdminpRenameWebNameInPersonDocs "121"
+#define AdminpRenameWebNameInReadersAuthors "122"
+#define AdminpRenameWebNameInFreeTime "123"
+#define AdminpRenameWebNameInMailFile "124"
+#define AdminpRenameWebNameInUnreadList "125"
+#define AdminpRemoveNameChangeInLDAPDir "126"
+#define AdminpChangeHTTPPasswordRequest "127"
+#define AdminpDefineServerMonitorQuery "128"
+#define AdminpCollectServerMonitorData "129"
+#define AdminpConsolidateServerMonitorData "130"
+#define AdminpCreateIMAPDelegations "131"
+#define AdminpDeleteHostedOrg "132"
+#define AdminpUpdateRoamingState "133"
+#define AdminpUpdateRoamingFields "134"
+#define AdminpCreateHostedOrgStorage "135"
+#define AdminpRecertCrossCert "136"
+#define AdminpCreateObjStore "137"
+#define AdminpDeleteHostedOrgStorageGetInfo "138"
+#define AdminpApproveDeleteHostedOrgStorage "139"
+#define AdminpDeleteHostedOrgStorage "140"
+#define AdminpRecertCAInNAB "141"
+#define AdminpFindNameInDomain "142"
+#define AdminpVerifyHostedOrgStorage "143"
+#define AdminpAddGroup "144"
+#define AdminpRecoveryIdRequest "145"
+#define AdminpPublishRecoveryInfo "146"
+#define AdminpDeletePersonInUnreadList "147"
+#define AdminpMonitorRoamingReplStubs "148"
+#define AdminpDelegateOnAdminServer "149"
+#define AdminpCreateReplicasCheckExeTime "150"
+#define AdminpMoveReplicasCheckExeTime "151"
+#define AdminpMoveMailCheckExeTime "152"
+#define AdminpNCMoveReplicasCheckExeTime "153"
+#define AdminpRegNewUserWithPolicy "154"
+#define AdminpRegNewUser "155"
+#define AdminpUpdateServerKeyring "156"
+#define AdminpEnableSSLPorts "157"
+#define AdminpNewAgentsMachine "158"
+#define AdminpXCertPublicationRequest "159"
+#define AdminpWebEnableMailAgent "160"
+#define AdminpUpdateReplicaSettings "161"
+#define AdminpRenameInSharedAgents "162"
+#define AdminpWebMailSetSoftDeletionTime "163"
+#define AdminpRenameInAgentsReadersField "164"
+#define AdminpDeleteInAgentsReadersField "165"
+#define AdminpMonitorServerSSLStatus "166"
+#define AdminpDelegateOnHomeServer "167"
+#define AdminpSetFaultRecoverySettings "168"
+#define AdminpCertNewServerKey "169"
+#define AdminpCertNewPersonKey "170"
+#define AdminpCertNewCertifierKey "171"
+#define AdminpAddDB2ToServerDoc "172"
+#define AdminpMonitorDB2ReplStub "173"
+#define AdminpDB2SetID "174"
+#define AdminpDB2MoveContainer "175"
+#define AdminpRenamePersonInDesignElements "176"
+#define AdminpDeletePersonInDesignElements "177"
+#define AdminpDB2AccessConnection "178"
+#define AdminpRenameWebNameInDesignElements "179"
+#define AdminpRenameGroupInDesignElements "180"
+
+#define AdminpDeleteWord 0
+#define AdminpRenameInTheACLWord 1
+#define AdminpCopyPublicKeyWord 2
+#define AdminpStoreServerVersionWord 3
+#define AdminpRenameServerInNABWord 4
+#define AdminpRenameUserInNABWord 5
+#define AdminpMoveUserInHierWord 6
+#define AdminpDeleteStatsWord 7
+#define AdminpInitiateNABChangeWord 8
+#define AdminpRecertServerInNABWord 9
+#define AdminpRecertUserInNABWord 10
+#define AdminpServerClusterAddWord 11
+#define AdminpServerClusterRemoveWord 12
+#define AdminpCreateReplicasWord 13
+#define AdminpMoveReplicasWord 14
+#define AdminpPendedDeleteForMoveWord 15
+#define AdminpDeleteInPersonDocsWord 16
+#define AdminpDeleteInTheACLWord 17
+#define AdminpDeleteInReadersAuthorsWord 18
+#define AdminpRenameInPersonDocsWord 19
+#define AdminpRenameInReadersAuthorsWord 20
+#define AdminpDeleteMailFileWord 21
+#define AdminpApproveMailFileInfoWord 22
+#define AdminpDeleteUnlinkedMailFileWord 23
+#define AdminpCreateMailFileWord 24
+#define AdminpMonitorMovedReplicaWord 25
+#define AdminpDeleteChangeRequestsWord 26
+#define AdminpGetMailFileInfoWord 27
+#define AdminpRequestDeleteMailFileWord 28
+#define AdminpResourceAddWord 29
+#define AdminpResourceDeleteWord 30
+#define AdminpApproveResourceDeleteWord 31
+#define AdminpCreateReplicasCheckAccessWord 32
+#define AdminpMoveReplicasCheckAccessWord 33
+#define AdminpSetPasswordFieldsWord 34
+#define AdminpUpdateUserPWWord 35
+#define AdminpUpdateServerPWWord 36
+#define AdminpSetMABFieldWord 37
+#define AdminpRenamePersonInFreeTimeWord 38
+#define AdminpRenamePersonInMailFileWord 39
+#define AdminpRenameGroupInNABWord 40
+#define AdminpRenameGroupInPersonDocsWord 41
+#define AdminpRenameGroupInTheACLWord 42
+#define AdminpRenameGroupInReadersAuthorsWord 43
+#define AdminpAddPersonsX509CertificateWord 44
+
+#define AdminpNewAdminpRequestFormat 45
+
+#define AdminpCheckMailServersAccessWord 45
+#define AdminpUpgradeUserWord 46
+#define AdminpCopyExternalDomainAddressesWord 47
+#define AdminpPromoteMailServersAccessWord 48
+#define AdminpCreateNewMailFileReplicaWord 49
+#define AdminpAddNewMailFileFieldsWord 50
+#define AdminpMonitorNewMailFileFieldsWord 51
+#define AdminpReplaceMailFileFieldsWord 52
+#define AdminpLastPushToNewMailServerWord 53
+#define AdminpDeletePersonInNABWord 54
+#define AdminpDeleteServerInNABWord 55
+#define AdminpDeleteGroupInNABWord 56
+#define AdminpDelegateMailFileWord 57
+#define AdminpApproveDeletePersonInNABWord 58
+#define AdminpApproveDeleteServerInNABWord 59
+#define AdminpApproveRenamePersonInNABWord 60
+#define AdminpApproveRenameServerInNABWord 61
+#define AdminpResourceModifyWord 62
+#define AdminpUpdateNetworkTablesWord 63
+#define AdminpCreateISPYMailInDbWord 64
+#define AdminpNCMoveReplicasCheckAccessWord 65
+#define AdminpNCMoveReplicasWord 66
+#define AdminpStoreServerCPUCountWord 67
+#define AdminpRenamePersonInUnreadListWord 68
+#define AdminpDeleteReplicaAfterMoveWord 69
+#define AdminpSetDNSFullHostNameWord 70
+#define AdminpStoreServerPlatformWord 71
+#define AdminpApproveDeleteDesignElementsWord 72
+#define AdminpRequestDeleteDesignElementsWord 73
+#define AdminpDeleteDesignElementsWord 74
+#define AdminpApproveDeleteMovedReplicaWord 75
+#define AdminpRequestDeleteMovedReplicaWord 76
+#define AdminpSetDomainCatalogWord 77
+#define AdminpWebDelegateMailFileWord 78
+#define AdminpGetFileInfoWord 79
+#define AdminpRequestDeleteFileWord 80
+#define AdminpDeleteFileWord 81
+#define AdminpApproveFileInfoWord 82
+#define AdminpSetWebAdminFieldsWord 83
+#define AdminpAcceleratedCreateReplicaWord 84
+#define AdminpSetConfigNABWord 85
+#define AdminpStoreServerDirectoryNameWord 86
+#define AdminpCreateRoamingUserRoamingFilesWord 87
+#define AdminpPromoteRoamingServersAccessWord 88
+#define AdminpReplaceRoamingServerFieldWord 89
+#define AdminpMonitorMovedRoamingReplicaWord 90
+#define AdminpCreateRoamingReplStubsWord 91
+#define AdminpRemoveRoamingUserRoamingFilesWord 92
+#define AdminpCheckRoamingServerAccessWord 93
+#define AdminpCreateRoamingReplicasWord 94
+#define AdminpCertPublicationRequestWord 95
+#define AdminpCrlPublicationRequestWord 96 /* AdminpCrlPublicationRequestWord */
+#define AdminpUserModifyRequestWord 97
+#define AdminpCertRemoveRequestWord 98
+#define AdminpPolicyPublicationRequestWord 99
+#define AdminpLastPushToNewRoamingServerWord 100
+#define AdminpSignDatabaseWord 101
+#define AdminpCAConfigPublicationRequestWord 102 /* AdminpCAConfigPublicationRequestWord */
+#define AdminpCrlRemoveRequestWord 103
+#define AdminpDelegateIMAPMailFilesWord 104
+#define AdminpCAConfigToBeSignedWord 105
+#define AdminpRejectRenameUserInNABWord 106
+#define AdminpRetractNameChangeWord 107
+#define AdminpEnableMailAgentWord 108
+#define AdminpReportServerUseWord 109
+#define AdminpRejectRetractNameChangeWord 110
+#define AdminpDeleteServerFromCatalogWord 111
+#define AdminpCopyTrendsRecordWord 112
+#define AdminpDeletePolicyWord 113
+#define AdminpApproveRetractNameChangeWord 114
+#define AdminpApproveRecertifyWord 115
+#define AdminpApproveNameChangeWord 116
+#define AdminpApproveNewPublicKeysWord 117
+#define AdminpInitiateWebNameChangeWord 118
+#define AdminpRenameWebNameInTheACLWord 119
+#define AdminpRenameWebNameInNABWord 120
+#define AdminpRenameWebNameInPersonDocsWord 121
+#define AdminpRenameWebNameInReadersAuthorsWord 122
+#define AdminpRenameWebNameInFreeTimeWord 123
+#define AdminpRenameWebNameInMailFileWord 124
+#define AdminpRenameWebNameInUnreadListWord 125
+#define AdminpRemoveNameChangeInLDAPDirWord 126
+#define AdminpChangeHTTPPasswordRequestWord 127
+#define AdminpDefineServerMonitorQueryWord 128
+#define AdminpCollectServerMonitorDataWord 129
+#define AdminpConsolidateServerMonitorDataWord 130
+#define AdminpCreateIMAPDelegationsWord 131
+#define AdminpDeleteHostedOrgWord 132
+#define AdminpUpdateRoamingStateWord 133
+#define AdminpUpdateRoamingFieldsWord 134
+#define AdminpCreateHostedOrgStorageWord 135
+#define AdminpRecertCrossCertWord 136
+#define AdminpCreateObjStoreWord 137
+#define AdminpDeleteHostedOrgStorageGetInfoWord 138
+#define AdminpApproveDeleteHostedOrgStorageWord 139
+#define AdminpDeleteHostedOrgStorageWord 140
+#define AdminpRecertCAInNABWord 141
+#define AdminpFindNameInDomainWord 142
+#define AdminpVerifyHostedOrgStorageWord 143
+#define AdminpAddGroupWord 144
+#define AdminpRecoveryIdRequestWord 145
+#define AdminpPublishRecoveryInfoWord 146
+#define AdminpDeletePersonInUnreadListWord 147
+#define AdminpMonitorRoamingReplStubsWord 148
+#define AdminpDelegateOnAdminServerWord 149
+#define AdminpCreateReplicasCheckExeTimeWord 150
+#define AdminpMoveReplicasCheckExeTimeWord 151
+#define AdminpMoveMailCheckExeTimeWord 152
+#define AdminpNCMoveReplicasCheckExeTimeWord 153
+#define AdminpRegNewUserWithPolicyWord 154
+#define AdminpRegNewUserWord 155
+#define AdminpUpdateServerKeyringWord 156
+#define AdminpEnableSSLPortsWord 157
+#define AdminpNewAgentsMachineWord 158
+#define AdminpXCertPublicationRequestWord 159
+#define AdminpWebEnableMailAgentWord 160
+#define AdminpUpdateReplicaSettingsWord 161
+#define AdminpRenameInSharedAgentsWord 162
+#define AdminpWebMailSetSoftDeletionTimeWord 163
+#define AdminpRenameInAgentsReadersFieldWord 164
+#define AdminpDeleteInAgentsReadersFieldWord 165
+#define AdminpMonitorServerSSLStatusWord 166
+#define AdminpDelegateOnHomeServerWord 167
+#define AdminpSetFaultRecoverySettingsWord 168
+#define AdminpCertNewServerKeyWord 169
+#define AdminpCertNewPersonKeyWord 170
+#define AdminpCertNewCertifierKeyWord 171
+#define AdminpAddDB2ToServerDocWord 172
+#define AdminpMonitorDB2ReplStubWord 173
+#define AdminpDB2SetIDWord 174
+#define AdminpDB2MoveContainerWord 175
+#define AdminpRenamePersonInDesignElementsWord 176
+#define AdminpDeletePersonInDesignElementsWord 177
+#define AdminpDB2AccessConnectionWord 178
+#define AdminpRenameWebNameInDesignElementsWord 179
+#define AdminpRenameGroupInDesignElementsWord 180
+
+#define ADMINP "Adminp"
+#define ADMINP_ALL_SERVERS "*"
+#define ADMINP_DELETE_MAIL_FILE_ON_HOME_SERVER "1"
+#define ADMINP_DELETE_MAIL_FILE_REPLICAS "2"
+#define ADMINP_DELETE_ONE_MAIL_FILE_REPLICA "3"
+#define ADMINP_DELETE_FILE_REPLICAS "4"
+#define ADMINP_DELETE_ONE_FILE_REPLICA "5"
+#define ADMINP_DISABLED "0"
+#define ADMINP_ENABLED "1"
+
+/* defines for "AdminpChangeHTTPPasswordRequest" sub-functions */
+#define ADMINP_CHANGE_HTTP_PASSWORD_NEW 0
+#define ADMINP_CHANGE_HTTP_PASSWORD_SYNC 1
+
+/* the view we use from the proxy database */
+#define ADMINP_MAIN_VIEW "All Requests by Action"
+#define ADMINP_BY_SERVER_RESPONSES_VIEW "($LoggedEvents)"
+#define ADMINP_ANY_SERVER_RESPONSES_VIEW "($LoggedAdminServerEvents)"
+#define ADMINP_REQUESTS_VIEW "($Requests)"
+#define ADMINP_RENAME_IN_ACL_DELETE_VIEW "($RenameInACLAndDeleteRequests)"
+#define ADMINP_RECEIVED_REQUESTS_VIEW "($ReceivedRequests)"
+#define ADMINP_RECEIVE_CONFIG_VIEW "($ReceiveCrossDomainRequests)"
+#define ADMINP_SUBMIT_CONFIG_VIEW "($SubmitCrossDomainRequests)"
+#define ADMINP_ORIG_UNID_VIEW "$Requests by UNID"
+
+/* fields in the proxy database document form */
+
+#define ADMINP_PROXY_DOCUMENT "AdminRequest"
+#define ADMINP_PROXY_XDOMAIN_DOCUMENT "CrossDomainAdminRequest"
+#define ADMINP_DOC_SERVER_ITEM "ProxyServer"
+#define ADMINP_ROAMING_SERVER_ITEM "ProxyRoamingServer"
+#define ADMINP_ACTION_ITEM "ProxyAction"
+#define ADMINP_DOC_SERVER_BUILD_NUMBER_ITEM "ProxyServerBuildNumber"
+#define ADMINP_DOC_SOURCE_SERVER_ITEM "ProxySourceServer"
+#define ADMINP_DOC_DEST_SERVER_ITEM "ProxyDestinationServer"
+#define ADMINP_DOC_CLUSTER_NAME_ITEM "ProxyClusterName"
+#define ADMINP_NAME_LIST_ITEM "ProxyNameList"
+#define ADMINP_DOC_AUTHOR_ITEM "ProxyAuthor"
+#define ADMINP_DOC_PROCESS_ITEM "ProxyProcess"
+#define ADMINP_DOC_TARGET_CERTIFIER_ITEM "ProxyTargetCertifier"
+#define ADMINP_DOC_CERTIFICATE_ITEM "ProxyCertificate"
+#define ADMINP_DOC_ROLLOVER_CERT_ITEM "ProxyRolloverCert"
+#define ADMINP_DOC_CHANGE_REQUEST_ITEM "ProxyChangeRequest"
+#define ADMINP_DOC_CHANGE_SIGNATURE_ITEM "ProxyChangeSignature"
+#define ADMINP_DOC_REPLICA_ID_ITEM "ProxyReplicaId"
+#define ADMINP_ROAMING_DB_REPIDS "ProxyRoamingReplicaIds"
+#define ADMINP_ROAMING_DB_LIST "ProxyRoamingReplicaList"
+#define ADMINP_ROAMING_DB_DISPLAY_LIST "ProxyRoamingPendingReplicaList"
+#define ADMINP_ROAMING_DB_PROMOTE_LIST "ProxyRoamingPromoteServerList"
+#define ADMINP_ROAMING_DB_REMOVE_LIST "ProxyRoamingRemoveReplicaList"
+#define ADMINP_DOC_DATABASE_PATH_ITEM "ProxyDatabasePath"
+#define ADMINP_ROAMING_DATABASE_PATH_ITEM "ProxyRoamingDatabasePath"
+#define ADMINP_ROAMING_DATABASE_DEST_PATH_ITEM "ProxyRoamingDestDatabasePath"
+#define ADMINP_ROAMING_ADDRESS_BOOK_ITEM "ProxyRoamingAddressBook"
+#define ADMINP_ROAMING_STATE_CHANGE_ITEM "ProxyRoamingStateChange"
+#define ADMINP_ROAMING_MODE_ITEM "ProxyRoamingMode"
+#define ADMINP_ROAMING_SETTING_ITEM "ProxyRoamingSetting"
+#define ADMINP_ROAMING_CLEANUP_PERIOD_ITEM "ProxyRoamingCleanupPeriod"
+#define ADMINP_ROAMING_ID_IN_NAB_ITEM "ProxyRoamingIdInNab"
+#define ADMINP_ROAMING_CLIENT_PROMPT_ITEM "ProxyRoamingClientPrompt"
+#define ADMINP_DOC_DATABASE_SOURCE_PATH_ITEM "ProxyDatabaseSourcePath"
+#define ADMINP_DATABASE_DESTINATION_PATH_ITEM "ProxyDestinationDatabasePath"
+#define ADMINP_DOC_DATABASE_NAME_ITEM "ProxyDatabaseName"
+#define ADMINP_DOC_COMMENTS_ITEM "ProxyRequestComments"
+#define ADMINP_DOC_DELETE_MAIL_FILE_ITEM "ProxyDeleteMailfile"
+#define ADMINP_DOC_DELETE_FILE_ITEM "ProxyDeleteFile"
+#define ADMINP_DOC_HOME_SERVER_ITEM "ProxyHomeServer"
+#define ADMINP_DOC_EXECUTION_TIME_ITEM "ProxyExecutionTime"
+#define ADMINP_DOC_MAIL_SERVER_ITEM "ProxySourceServer"
+#define ADMINP_DOC_DATABASE_ACL_ITEM "ProxyDatabaseACL"
+#define ADMINP_DOC_DATABASE_CLASS_ITEM "ProxyDatabaseTemplateName"
+#define ADMINP_DOC_RESOURCE_SITE_ITEM "ProxyResourceSite"
+#define ADMINP_DOC_RESOURCE_TYPE_ITEM "ProxyResourceType"
+#define ADMINP_DOC_RESOURCE_CAPACITY_ITEM "ProxyResourceCapacity"
+#define ADMINP_DOC_RESOURCE_DESCRIPTION_ITEM "ProxyResourceDescription"
+#define ADMINP_DOC_RESOURCE_DOMAIN_ITEM "ProxyResourceDomain"
+#define ADMINP_DOC_PASS_PASSWORD_ITEM "ProxyPassword"
+#define ADMINP_DOC_PASS_CHECK_PASSWORD_ITEM "ProxyPasswordCheck"
+#define ADMINP_DOC_PASS_GRACE_PERIOD_ITEM "ProxyPasswordGracePeriod"
+#define ADMINP_DOC_PASS_CHANGE_INTERVAL_ITEM "ProxyPasswordChangeInterval"
+#define ADMINP_DOC_PASS_QUALITY_IS_LENGTH_ITEM "ProxyPasswordQualityIsLength"
+#define ADMINP_DOC_PASS_QUALITY_ITEM "ProxyPasswordQuality"
+#define ADMINP_DOC_PASS_HISTORY_COUNT_ITEM "ProxyPasswordHistoryCount"
+#define ADMINP_DOC_PASS_HTTP_GRACE_PERIOD_ITEM "ProxyHTTPPasswordGracePeriod"
+#define ADMINP_DOC_PASS_HTTP_CHANGE_INTERVAL_ITEM "ProxyHTTPPasswordChangeInterval"
+#define ADMINP_DOC_PASS_HTTP_OPTIONS_ITEM "ProxyHTTPPasswordOptions"
+#define ADMINP_DOC_PASS_HTTP_QUALITY_ITEM "ProxyHTTPPasswordQuality"
+#define ADMINP_DOC_PASS_HTTP_FUNCTION_ITEM "ProxyHTTPPasswordFunction"
+#define ADMINP_DOC_PASS_HTTP_SYNCH_ITEM "ProxyHTTPPasswordNotesSync"
+#define ADMINP_DOC_PASS_HTTP_QUALITY_IS_LENGTH_ITEM "ProxyHTTPPasswordQualityIsLength"
+#define ADMINP_DOC_APPROVAL_FLAG_ITEM "ApprovalFlag"
+#define ADMINP_DOC_IMMEDIATE_FLAG_ITEM "ProxyImmediateFlag"
+#define ADMINP_NEW_GROUP_NAME_ITEM "ProxyNewGroupName"
+#define ADMINP_DOC_PERSONS_CERT_ITEM "ProxyUserCertificate"
+#define ADMINP_NAME_IN_X509_CERT_ITEM "ProxyNameInX509Certificate"
+#define ADMINP_DOC_DISPLAY_DESIGN_ELEMENTS_ITEM "ProxyDesignElementList"
+#define ADMINP_DOC_PRIVATE_DESIGN_ELEMENTS_ITEM "$ProxyPrivateDesignElements"
+#define ADMINP_DOC_DELETED_OBJECT_ITEM "$ProxyDeletedObject"
+#define ADMINP_DOC_MOVE_MAIL_DELETE_ITEM "$ProxyMoveMailDelete"
+#define ADMINP_DOC_ACL_FLAG_ITEM "ACLFlag"
+#define ADMINP_DOC_APPROVED_ITEM "$ProxyApproved"
+#define ADMINP_NAME_IN_CRL_ISSUEDBY_ITEM "ProxyNameInCRLIssuedBy"
+#define ADMINP_DOC_CERTIFIERS_CRL_ITEM "ProxyCertifierCrl"
+#define ADMINP_PUBLISH_REQUESTOR_NOTEID_ITEM "ProxyRequestorNoteId"
+#define ADMINP_CERTIFICATE_TYPE_ITEM "ProxyCertificateType"
+#define ADMINP_PUBLISH_ACTION_ITEM "ProxyPublishAction"
+#define ADMINP_PA_NAME_ITEM "ProxyPAName"
+#define ADMINP_DOC_FALLBACK_REQUEST_ITEM "ProxyReplicaFallbackRequest"
+#define ADMINP_FORMAT_PREF_INCOMING_MAIL_ITEM "ProxyFormatPrefIncomingMail"
+#define ADMINP_ENCRYPT_INCOMING_MAIL_ITEM "ProxyEncryptIncomingMail"
+#define ADMINP_INTERNET_PASSWORD_DIGEST_ITEM "ProxyInternetPasswordDigest"
+#define ADMINP_USERNAME_ITEM "ProxyUserName"
+#define ADMINP_ACCOUNT_ITEM "ProxyAccountName"
+#define ADMINP_POLICY_NAME_ITEM "ProxyPolicyName"
+#define ADMINP_POLICY_DB_NAME_ITEM "ProxyPolicyDBName"
+#define ADMINP_POLICY_DB_ATTACHMENT_ITEM "ProxyPolicyDBAttachment"
+#define ADMINP_POLICY_RA_LIST_ITEM "RegistrationAuthorities"
+#define ADMINP_POLICY_CA_LIST_ITEM "CAAdministrators"
+#define ADMINP_POLICY_CCS_STAMP_ITEM "ProxyPolicyCCSStamp"
+#define ADMINP_POLICY_SERVERNAME_ITEM "ProxyPolicyServerName"
+#define ADMINP_POLICY_LOCKID_ITEM "ProxyPolicyLockId"
+#define ADMINP_POLICY_ICLNAME_ITEM "ProxyPolicyICLName"
+#define ADMINP_PUBLISH_FLAGS_ITEM "ProxyPublishFlags"
+#define ADMINP_PUBLISH_CERT_FIELD_ITEM "ProxyPublishCertField"
+#define ADMINP_DOC_CLUSTER_MATES "ProxyClusterMates"
+#define ADMINP_DOC_CLUSTER_MATES_PATH "ProxyClusterMatesPath"
+#define ADMINP_DOC_CLUSTER_DELETE_REP "ProxyClusterDeleteRep"
+#define ADMINP_DOC_IMAP_DELEGATEES_ITEM "ProxyIMAPDelegatees"
+#define ADMINP_DOC_IMAP_MAILFILES_ITEM "ProxyIMAPDelegateesMailFiles"
+#define ADMINP_DOC_SECNAB_PATH_ITEM "ProxySecondaryDirectoryPath"
+#define ADMINP_DOC_SECNAB_NAME_ITEM "ProxySecondaryDirectoryName"
+#define ADMINP_DOC_SECNAB_REPLICA_ID_ITEM "ProxySecondaryDirectoryReplicaId"
+#define ADMINP_DOC_RETRACT_NAME_UNID_ITEM "ProxyRetractNameChangeUNID"
+#define ADMINP_NEW_WEB_NAME_ITEM "ProxyNewWebName"
+#define ADMINP_DOC_NEW_WEB_FIRST_NAME_ITEM "ProxyNewWebFirstName"
+#define ADMINP_DOC_NEW_WEB_MI_ITEM "ProxyNewWebMI"
+#define ADMINP_DOC_NEW_WEB_LAST_NAME_ITEM "ProxyNewWebLastName"
+#define ADMINP_NEW_HTTPPASSWORD_ITEM "ProxyNewHTPPPassword"
+#define ADMINP_OLD_HTTPPASSWORD_ITEM "ProxyOldHTPPPassword"
+#define ADMINP_DOC_TASK_TYPE_LIST_ITEM "ProxyTaskTypes"
+#define ADMINP_DOC_TASK_SEVERITY_ITEM "ProxyTaskSeverity"
+#define ADMINP_DOC_STATS_TYPE_LIST_ITEM "ProxyStatisticTypes"
+#define ADMINP_DOC_SMON_SERVERS_ITEM "ProxyMonitoredServer"
+#define ADMINP_DOC_STATREP_SERVER_ITEM "ProxyStaterepServer"
+#define ADMINP_DOC_SMON_TIMEFRAME_START_ITEM "ProxyMonitorTimeFrameStart"
+#define ADMINP_DOC_SMON_TIMEFRAME_END_ITEM "ProxyMonitorTimeFrameEnd"
+#define ADMINP_DOC_SMON_PARENT_UNID_ITEM "ProxyMonitorParentUNID"
+#define ADMINP_DOC_SERVER_RESTARTS_ITEM "ProxyServerRestarts"
+#define ADMINP_DOC_IGNORE_STATISTICS_ITEM "ProxyIgnoreTheseStatistics"
+#define ADMINP_DOC_IGNORE_EVENTS_ITEM "ProxyIgnoreTheseEvents"
+#define ADMINP_DOC_DIRECTORY_SERVER_NAME_ITEM "ProxyDirectoryServerName"
+#define ADMINP_DOC_DIRECTORY_NAME_ITEM "ProxyDirectoryName"
+#define ADMINP_DOC_DIRECTORY_TITLE_ITEM "ProxyDirectoryTitle"
+#define ADMINP_DOC_DIRECTORY_REPLICA_ID_ITEM "$ProxyDirectoryReplicaId"
+#define ADMINP_DOC_DIRECTORY_NOTE_UNID_ITEM "ProxyDirectoryNoteUNID"
+#define ADMINP_DOC_MAIL_SERVER_DNS_ITEM "ProxyMailServerDNS"
+#define ADMINP_DOC_MAIL_DOMAIN_ITEM "ProxyMailDomain"
+#define ADMINP_DOC_IS_WEB_MAIL_USER_ITEM "ProxyIsWebMailUser"
+#define ADMINP_DOC_HOSTED_ORG_ITEM "ProxyHostedOrg"
+#define ADMINP_DOC_HOSTED_ORG_ACTION_ITEM "ProxyHostedOrgAction"
+#define ADMINP_DOC_HOSTED_ORG_STORAGE_ITEM "ProxyHostedOrgStorage"
+#define ADMINP_DOC_WEB_NAME_CHANGE_EXPIRE_ITEM "ProxyWebNameChangeExpires"
+#define ADMINP_DOC_SHORT_NAME_ITEM "ProxyShortName"
+#define ADMINP_DOC_INTERNET_ADDRESS_ITEM "ProxyInternetAddress"
+#define ADMINP_DOC_NEW_DOMAIN_ITEM "ProxyNewDomain"
+#define ADMINP_DOC_OLD_DOMAIN_ITEM "ProxyOldDomain"
+#define ADMINP_HTTP_PASSWORD_SYNC_DATE_ITEM "ProxyHTTPSyncDate"
+#define ADMINP_DOC_AGENT_TO_SIGN_ITEM "ProxyAgentToSign"
+#define ADMINP_NEW_RESOURCE_NAME_ITEM "ProxyNewResourceName"
+#define ADMINP_DOC_RETIRE_DB_ITEM "ProxyRetireDb"
+#define ADMINP_CASCADE_DESIGN_ELEMENTS_ITEM "ProxyCascadeDesignElements"
+#define ADMINP_DOC_CREATE_TRENDS_REQ "ProxyCreateTrends"
+#define ADMINP_MAJOR_VERSION_NUMBER "MajVer"
+#define ADMINP_MINOR_VERSION_NUMBER "MinVer"
+#define ADMINP_QMR_VERSION_NUMBER "QMRVer"
+#define ADMINP_QMU_VERSION_NUMBER "QMUVer"
+#define ADMINP_HOT_VERSION_NUMBER "HotVer"
+#define ADMINP_FIXP_VERSION_NUMBER "FixPVer"
+#define ADMINP_FLAGS_VERSION_NUMBER "FlagsVer"
+#define ADMINP_DOC_MEMBER_LIST_ITEM "ProxyMemberList"
+#define ADMINP_DOC_AGENT_ACTIVATABLE_ITEM "ProxyAgentActivatable"
+#define ADMINP_DOC_AGENT_ENABLE_ITEM "ProxyAgentEnable"
+#define ADMINP_RECOVERY_INFO "RecoveryInfo"
+#define ADMINP_RECOVERY_INFO_TIMESTAMP "RecoveryInfoTimeStamp"
+#define ADMINP_CLIENT_HASH "ClntDgst"
+#define ADMINP_CLIENT_RECORD_DYNCONFIG "ClientInfoDynconfig"
+#define ADMINP_PROXY_MAINTAIN_DBQUOTA "ProxyMaintainDBQuota"
+#define ADMINP_DBQUOTA_WARNING_ITEM "ProxyDBQuotaWarning"
+#define ADMINP_DBQUOTA_LIMIT_ITEM "ProxyDBQuotaLimit"
+#define ADMINP_DB2_DEFAULT_ITEM "ProxyDB2Default"
+#define ADMINP_DB2_RESTART_ITEM "ProxyDB2RestartServer"
+#define ADMINP_DB2_ACCESS_COMMAND "ProxyDB2AccessCommand"
+#define ADMINP_DB2_ACCESS_DESTSRV "ProxyDB2AccessDestServer"
+#define ADMINP_DB2_ACCESS_DESTDOM "ProxyDB2AccessDestDomain"
+#define ADMINP_DB2_ACCESS_SRCSRV "ProxyDB2AccessSrcServer"
+#define ADMINP_DB2_ACCESS_SRCDOM "ProxyDB2AccessSrcDomain"
+#define ADMINP_DB2_ACCESS_OPTNET "ProxyDB2AccessOptNetAddress"
+#define ADMINP_DB2_ACCESS_PORTNAM "ProxyDB2AccessPortName"
+
+/* fields in the delete hosted organization adminp request */
+#define ADMINP_ORG_NAME_ITEM "Fullname"
+#define ADMINP_ORG_DIR_ITEM "Pathname"
+
+/* fields in the proxy database log form */
+#define ADMINP_PROXY_LOG "AdminLog"
+#define ADMINP_LOG_ACTION_REQUESTOR_ITEM "ProxyActionRequestor"
+#define ADMINP_LOG_SERVER_NAME_ITEM "ProxyServerName"
+#define ADMINP_LOG_ACTION_START_TIME_ITEM "ActionStartTime"
+#define ADMINP_LOG_ACTION_END_TIME_ITEM "ActionEndTime"
+#define ADMINP_LOG_DB_LIST_ITEM "ProxyDbList"
+#define ADMINP_LOG_STATUS_ITEM "ProxyStatus"
+#define ADMINP_LOG_STATUS_CODES_ITEM "ProxyStatusCodes"
+#define ADMINP_LOG_MODIFIED_RESPONSE_ITEM "ModifiedFlag"
+#define ADMINP_LOG_SHOW_MODIFIED_ITEM "ShowModified"
+#define ADMINP_LOG_OLD_NAME_ITEM "OldName"
+#define ADMINP_LOG_NEW_NAME_ITEM "NewName"
+#define ADMINP_LOG_ACTION_COMMENTS_ITEM "ActionComments"
+#define ADMINP_LOG_SHOW_ERROR "ErrorFlag"
+#define ADMINP_LOG_REPLICA_CREATION_TIME "ReplicaCreationTime"
+#define ADMINP_LOG_CREATED_DELETE_REQUEST "DeleteRequestCreated"
+#define ADMINP_LOG_SIGNED_NOTES "ProxySignedDocs"
+#define ADMINP_LOG_IN_PROGRESS "AdminPInProgress"
+#define ADMINP_LOG_SENT_TO_DOMAINS "ProxySentToDomains"
+#define ADMINP_LOG_ADD_IN_NAME "ProxyAddInProcess"
+#define ADMINP_LOG_ADD_IN_SIGNER "ProxyAddInSigner"
+#define ADMINP_LOG_PRIVATE_AGENTS "ProxyPrivateAgents"
+#define ADMINP_LOG_PRIVATE_FOLDERS "ProxyPrivateFolders"
+#define ADMINP_LOG_PRIVATE_VIEWS "ProxyPrivateViews"
+#define ADMINP_LOG_SHARED_AGENTS "ProxySharedAgents"
+#define ADMINP_LOG_NAME_EXPIRATION_ITEM "ProxyNameExpiration"
+#define ADMINP_LOG_ERROR_DBS "$AdminpErrorDbs"
+#define ADMINP_LOG_NO_ERROR_DBS "$AdminpNoErrorDbs"
+#define ADMINP_LOG_DESIGN_DBS "$AdminpDesignDbs"
+#define ADMINP_LOG_DESIGN_DB_LINKS "$AdminpDesignDbLinks"
+#define ADMINP_LOG_AGENT_REPLY_TO "$AgentReplyTo"
+#define ADMINP_LOG_RETRY_TIME_ITEM "ProxyRetryTime"
+#define ADMINP_LOG_ORG_LIST "ProxyOrgList"
+#define ADMINP_LOG_FOUND_IN_ECL "ProxyFoundECLDocs"
+#define ADMINP_LOG_SHARED_FOLDERS "ProxySharedFolders"
+#define ADMINP_LOG_SHARED_VIEWS "ProxySharedViews"
+#define ADMINP_LOG_SHARED_AGENTS_MODIFIED "ProxySharedAgentsModified"
+#define ADMINP_LOG_SHARED_FORMS "ProxySharedForms"
+#define ADMINP_LOG_UNSCHEDULED_AGENTS "ProxyUnscheduledAgents"
+#define ADMINP_LOG_AGENTS_WITH_READERS "ProxyAgentsWithReaders"
+#define ADMINP_LOG_DIRECTORY_ERROR_ITEM "ProxyDirectoryError"
+#define ADMINP_LOG_DIRECTORY_NOERROR_ITEM "ProxyDirectoryNoError"
+#define ADMINP_LOG_DIR_ERROR_DISP_ITEM "ProxyDirectoryErrorDisp"
+#define ADMINP_LOG_FOUND_IN_DIRECTORY "ProxyFoundNABDocs"
+#define ADMINP_LOG_LAST_ENTRY_REMOVED_ITEM "ProxyLastEntryRemoved"
+#define ADMINP_LOG_EXPIRED_NAME_CHANGES "ProxyExpiredNameChanges"
+
+/* fields in the proxy database profiles */
+
+#define ADMINP_PROFILE_TO_DOMAINS "ToDomains"
+#define ADMINP_PROFILE_FROM_DOMAINS "FromDomains"
+#define ADMINP_PROFILE_INBOUND_REP_SERVERS "InboundReplicaServers"
+#define ADMINP_PROFILE_OUTBOUND_REP_SERVERS "OutboundReplicaServers"
+#define ADMINP_PROFILE_OUTBOUND_REP_DOMAINS "OutboundReplicaDomains"
+#define ADMINP_INBOUND_APPROVED_SIGNERS "InboundApprovedSigners"
+#define ADMINP_OUTBOUND_APPROVED_SIGNERS "OutboundApprovedSigners"
+
+/* fields in the new user registration requests */
+/* REG_USER_INFO fields */
+#define ADMINP_NEW_USER_ORG_UNIT_ITEM "ProxyNewUserOrgUnit"
+#define ADMINP_NEW_USER_ALTORG_UNIT_ITEM "ProxyNewUserAltOrgUnit"
+#define ADMINP_NEW_USER_ALTNAME_ITEM "ProxyNewUserAltName"
+#define ADMINP_NEW_USER_ALTLANGUAGE_ITEM "ProxyNewUserAltLanguageName"
+#define ADMINP_NEW_USER_FIRST_NAME_ITEM "ProxyNewUserFirstName"
+#define ADMINP_NEW_USER_MIDDLE_NAME_ITEM "ProxyNewUserMiddleName"
+#define ADMINP_NEW_USER_LAST_NAME_ITEM "ProxyNewUserLastName"
+#define ADMINP_NEW_USER_PASSWORD_ITEM "ProxyNewUserPassword"
+#define ADMINP_NEW_USER_PASSWORD_QUALITY_ITEM "ProxyNewUserPasswordQuality"
+#define ADMINP_NEW_USER_SHORT_NAME_ITEM "ProxyNewUserShortName"
+#define ADMINP_NEW_USER_IADDRESS_ITEM "ProxyNewUserInternetAddress"
+#define ADMINP_NEW_USER_PREFLANGUAGE_ITEM "ProxyNewUserPrefLanguage"
+
+/* REG_MAIL_INFO fields */
+#define ADMINP_NEW_USER_MAIL_SYSTEM_ITEM "ProxyNewUserMailSystem"
+#define ADMINP_NEW_USER_MAIL_OWNER_ACCESS_ITEM "ProxyNewUserMailOwnerAccess"
+#define ADMINP_NEW_USER_DBQUOTA_LIMIT_ITEM "ProxyNewUserDbQuotaSizeLimit"
+#define ADMINP_NEW_USER_DBQUOTA_WARNING_ITEM "ProxyNewUserDbQuotaWarningThreshold"
+#define ADMINP_NEW_USER_MAIL_SERVER_ITEM "ProxyNewUserMailServer"
+#define ADMINP_NEW_USER_MAIL_FILE_ITEM "ProxyNewUserMailFile"
+#define ADMINP_NEW_USER_MAIL_TEMPLATE_ITEM "ProxyNewUserMailTemplate"
+#define ADMINP_NEW_USER_MAIL_FORWARD_ITEM "ProxyNewUserMailForwardAddress"
+#define ADMINP_NEW_USER_MAIL_MANAGER_ITEM "ProxyNewUserMailManager"
+#define ADMINP_NEW_USER_MAIL_REP_SERVERS_ITEM "ProxyNewUserMailReplicaServers"
+
+/* REG_ROAMING_INFO fields */
+#define ADMINP_NEW_USER_ROAMING_SERVER_ITEM "ProxyNewUserRoamingServer"
+#define ADMINP_NEW_USER_ROAMING_SUBDIR_ITEM "ProxyNewUserRoamingSubDir"
+#define ADMINP_NEW_USER_ROAMN_DB_ITEM "ProxyNewUserRoamingDB"
+#define ADMINP_NEW_USER_ROAMN_MODE_ITEM "ProxyNewUserRoamingMode"
+#define ADMINP_NEW_USER_ROAMN_CLEANUP_MODE_ITEM "ProxyNewUserRoamingCleanupMode"
+#define ADMINP_NEW_USER_ROAMN_CLEANUP_PERIOD_ITEM "ProxyNewUserRoamingCleanupPeriod"
+#define ADMINP_NEW_USER_ROAMN_REP_SERVERS_ITEM "ProxyNewUserRoamingReplicaServers"
+
+#define ADMINP_NEW_USER_IDTYPE_ITEM "ProxyNewUserIDType"
+#define ADMINP_NEW_USER_IDEXPIRATION_ITEM "ProxyNewUserIDExpiration"
+#define ADMINP_NEW_USER_GROUPS_ITEM "ProxyNewUserGroups"
+#define ADMINP_NEW_USER_ID_ITEM "ProxyNewUserIDFile"
+#define ADMINP_NEW_USER_LOCATION_ITEM "ProxyNewUserLocation"
+#define ADMINP_NEW_USER_COMMENT_ITEM "ProxyNewUserComment"
+#define ADMINP_NEW_USER_PROFILE_ITEM "ProxyNewUserProfile"
+#define ADMINP_NEW_USER_LOCAL_ADMIN_ITEM "ProxyNewUserLocalAdmin"
+#define ADMINP_NEW_USER_FLAGS_ITEM "ProxyNewUserFlags"
+#define ADMINP_NEW_USER_EXTFLAGS_ITEM "ProxyNewUserExtFlags"
+
+/* server keyring update request */
+#define ADMINP_PRIVATE_KEY_ITEM "ProxyPrivateKey"
+#define ADMINP_KEYRING_PASSWORD_ITEM "ProxyKeyringPassword"
+#define ADMINP_KEYRING_FILE_ITEM "ProxyKeyringFile"
+#define ADMINP_SUBJECT_ITEM "ProxySubjectName"
+#define ADMINP_ISSUER_ITEM "ProxyIssuerName"
+
+/* fields in the proxy database log form */
+#define ADMINP_PROXY_NAMEINDIR_REPORT "AdminNameInDirRpt"
+#define ADMINP_PROXY_NAMEINACL_REPORT "AdminNameInAclRpt"
+#define ADMINP_PROXY_NAMEINAGENT_REPORT "AdminNameInAgentRpt"
+#define ADMINP_PROXY_NAMEINFOLDER_REPORT "AdminNameInFolderRpt"
+#define ADMINP_PROXY_NAMEINNAMEFLD_REPORT "AdminNameInNamesFldRpt"
+#define ADMINP_PROXY_NAMEINXACL_REPORT "AdminNameInxAclRpt"
+#define ADMINP_PROXY_NAMEINECL_REPORT "AdminNameInEclRpt"
+#define ADMINP_PROXY_NAMEINPOLICY_REPORT "AdminNameInPolicyRpt"
+
+#define ADMINP_MAIL_FILE_TITLE_ITEM ADMINP_DOC_DATABASE_NAME_ITEM
+
+/* generic admin4.nsf fields */
+#define ADMINP_PROXY_TEXT_ITEM_1 "ProxyTextItem1"
+#define ADMINP_PROXY_TEXT_ITEM_2 "ProxyTextItem2"
+#define ADMINP_PROXY_TEXT_ITEM_3 "ProxyTextItem3"
+#define ADMINP_PROXY_TEXT_ITEM_4 "ProxyTextItem4"
+#define ADMINP_PROXY_TEXT_ITEM_5 "ProxyTextItem5"
+#define ADMINP_PROXY_TEXT_ITEM_6 "ProxyTextItem6"
+#define ADMINP_PROXY_TEXT_ITEM_7 "ProxyTextItem7"
+#define ADMINP_PROXY_TEXT_ITEM_8 "ProxyTextItem8"
+#define ADMINP_PROXY_TEXT_ITEM_9 "ProxyTextItem9"
+#define ADMINP_PROXY_TEXT_ITEM_10 "ProxyTextItem10"
+
+#define ADMINP_PROXY_DATE_ITEM_1 "ProxyDateItem1"
+#define ADMINP_PROXY_DATE_ITEM_2 "ProxyDateItem2"
+#define ADMINP_PROXY_DATE_ITEM_3 "ProxyDateItem3"
+
+#define ADMINP_PROXY_NUM_ITEM_1 "ProxyNumItem1"
+#define ADMINP_PROXY_NUM_ITEM_2 "ProxyNumItem2"
+
+#define ADMINP_PROXY_CREATE_FT_INDEX "ProxyCreateFullTextIndex"
+#define ADMINP_PROXY_PACKED_FTI_OPTIONS "ProxyPackedFullTextIndexOptions"
+#define ADMINP_PROXY_COPY_ACL "ProxyCopyACL"
+#define ADMINP_PROXY_PACKED_ACL "ProxyPackedACL"
+#define ADMINP_PROXY_PACKED_ACL_HISTORY "ProxyPackedACLHistory"
+#define ADMINP_PROXY_PACKED_ACL_HISTORY_COUNT "ProxyPackedACLHistoryCount"
+#define ADMINP_PROXY_LINK_DEST_TO_SCOS "ProxyLinkDestinationToSCOS"
+#define ADMINP_PROXY_MAILFILE_ACCESS "ProxyMailfileAccessLevel"
+#define ADMINP_PROXY_MAILREPLICA_SERVERS "ProxyMailReplicaServers"
+#define ADMINP_PROXY_ROAMNREPLICA_SERVERS "ProxyRoamingReplicaServers"
+#define ADMINP_PROXY_OVERRIDE_DEF_DATASTORE "ProxyOverrideDefaultDatastore"
+#define ADMINP_PROXY_DB2_PASSWORD_ITEM "ProxyDB2Password"
+#define ADMINP_PROXY_ALTERNATE_NAME_ITEM "ProxyAlternateName"
+#define ADMINP_PROXY_ALTERNATE_NAME_TAG_ITEM "ProxyAlternateNameTag"
+
+/* name and address book fields and field values adminp needs */
+#define ADMINP_NAB_SERVER_BUILD_NUMBER "ServerBuildNumber"
+#define ADMINP_NAB_DENY_ACCESS_GROUP "3"
+
+#define ADMINP_NAB_PASS_CHECK_PASSWORD "CheckPassword"
+#define ADMINP_NAB_PASS_GRACE_PERIOD "PasswordGracePeriod"
+#define ADMINP_NAB_PASS_CHANGE_INTERVAL "PasswordChangeInterval"
+#define ADMINP_NAB_PASS_QUALITY "PasswordQuality"
+#define ADMINP_NAB_PASS_QUALITY_IS_LENGTH "PwdQltyIsLen"
+#define ADMINP_NAB_PASS_HISTORY_COUNT "PwdHistCnt"
+#define ADMINP_NAB_PASS_WEB_GRACE_PERIOD "HTTPPasswordGracePeriod"
+#define ADMINP_NAB_PASS_WEB_CHANGE_INTERVAL "HTTPPasswordChangeInterval"
+#define ADMINP_NAB_PASS_WEB_OPTIONS "HTTPPasswordOptions"
+#define ADMINP_NAB_PASS_WEB_QUALITY "HTTPPasswordQuality"
+#define ADMINP_NAB_PASS_WEB_SYNCH "HTTPPasswordNotesSync"
+#define ADMINP_NAB_PASS_WEB_QUALITY_IS_LENGTH "HTTPPasswordQualityIsLength"
+#define ADMINP_NAB_PASS_WEB_FORCE_CHANGE "HTTPPasswordForceChange"
+
+#define ADMINP_NAB_MASTER_ADDRESS_BOOK "MasterAddressBook"
+
+#define ADMINP_SERVER_CONNECTION_FORM "Server\\Connection"
+#define ADMINP_NETWORK_CONNECTION_FORM "Network Connection"
+#define ADMINP_REMOTE_CONNECTION_X25_FORM "Remote Connection (X25)"
+#define ADMINP_REMOTE_CONNECTION_ISDN_FORM "Remote Connection (ISDN)"
+
+/* address book stuff for resources used by adminp */
+#define ADMINP_NAB_RESOURCE_FLAG_ITEM "ResourceFlag"
+#define ADMINP_NAB_DOCUMENT_ACCESS_ITEM "DocumentAccess"
+#define ADMINP_NAB_RESOURCE_CAPACITY_ITEM "ResourceCapacity"
+#define ADMINP_NAB_RESOURCE_TYPE_ITEM "ResourceType"
+#define ADMINP_NAB_RESOURCE_TYPE_ROOM "1"
+#define ADMINP_NAB_RESOURCE_TYPE_RESOURCE "2"
+#define ADMINP_NAB_RESOURCE_DOMAIN_ITEM "MailDomain"
+#define ADMINP_NAB_RESOURCE_CONFERENCE_DB_ITEM "ConfDB"
+#define ADMINP_NAB_RESOURCE_AFLAG_ITEM "AudioFlg"
+#define ADMINP_NAB_RESOURCE_VFLAG_ITEM "VidFlg"
+#define ADMINP_NAB_RESOURCE_AVFLAG_ITEM "AVFlg"
+#define ADMINP_NAB_RESOURCE_AVSELLIST_ITEM "AVSlctLst"
+
+/* address book stuff used for name change retraction */
+#define ADMINP_NAB_OLD_MAIL_CERTIFICATE_ITEM "AdminpOldCertificate"
+#define ADMINP_NAB_OLD_MAIL_FIRSTNAME_ITEM "AdminpOldFirstName"
+#define ADMINP_NAB_OLD_MAIL_LASTNAME_ITEM "AdminpOldLastName"
+#define ADMINP_NAB_OLD_MAIL_MIDDLEINITIAL_ITEM "AdminpOldMI"
+#define ADMINP_NAB_OLD_MAIL_FULLNAME_ITEM "AdminpOldFullName"
+#define ADMINP_NAB_OLD_MAIL_OWNER_ITEM "AdminpOldOwner"
+#define ADMINP_NAB_OLD_MAIL_ALTFULLNAME_ITEM "AdminpOldAltFullName"
+#define ADMINP_NAB_OLD_MAIL_ALTFULLNAMELANGUAGE_ITEM "AdminpOldAltFullNameLanguage"
+#define ADMINP_NAB_OLD_MAIL_INTERNETADDRESS_ITEM "AdminpOldInternetAddress"
+#define ADMINP_NAB_OLD_MAIL_SHORTNAME_ITEM "AdminpOldShortName"
+
+#define ADMINP_NAB_OLD_WEB_NAME_ITEM "$AdminpOldWebName"
+#define ADMINP_NAB_OLD_WEB_NAME_EXPIRES_ITEM "$AdminpOldWebNameExpires"
+
+#define ADMINP_EVENT_TYPE_ITEM "Type"
+
+#define TARGETSERVERSNAMESPACE "$TargetServers"
+#define MESSAGESBYTYPENAMESPACE "$MessagesByType"
+
+#define EVENT_TARGET_SERVER_NAME_ITEM "TargetServerName"
+#define EVENT_COLLECTING_SERVER_ITEM "SourceServerName"
+#define EVENT_REMOTE_DESTINATION_DB_ITEM "RemoteDestinationDb"
+#define EVENT_ORIGINAL_TEXT_ITEM "OriginalText"
+#define EVENT_SEVERITY_ITEM "Severity"
+#define EVENT_MONITOR_NUMBER_ITEM "MonitorNumber"
+#define EVENT_CODE_ITEM "Code"
+#define EVENT_TEXT_MATCH_ITEM "EventTextMatch"
+
+#define EVENT_UNSPECIFIED_SERVERS "2"
+#define EVENT_ALL_SERVERS "1"
+
+#define RESOURCES_NAMESPACE "$Resources"
+#define RESOURCES_VIEW "($Resources)"
+#define ROOMS_NAMESPACE "$Rooms"
+#define ROOMS_VIEW "($Rooms)"
+#define ROOMS_PICKLIST_COLUMN 1
+#define RESOURCES_PICKLIST_COLUMN 2
+
+/* SPR DDEY4ZSN4K - Add Online Meeting addressing support */
+#define ONLINE_MEETINGS_NAMESPACE "$OnlineMeetingPlaces"
+#define ONLINE_MEETINGS_VIEW "($OnlineMeetingPlaces)"
+#define ONLINE_MEETINGS_PICKLIST_COLUMN 1
+
+#define ADMINP_FLAG_SET "1"
+#define ADMINP_DOCUMENT_ACCESS_SET "[NetModifier]"
+#define ADMINP_ROOM "1"
+#define ADMINP_RESOURCE "2"
+#define ADMINP_ONLINE_RESOURCE '3'
+
+#define USER_MODIFIER "[UserModifier]"
+#define POLICY_CREATOR "[PolicyCreator]"
+#define POLICY_MODIFIER "[PolicyModifier]"
+#define GROUP_MODIFIER "[GroupModifier]"
+#define GROUP_CREATOR "[GroupCreator]"
+
+
+/* address book stuff for move mail file */
+#define ADMINP_NEW_MAILFILE_ITEM "NewMailFile"
+#define ADMINP_NEW_MAILSERVER_ITEM "NewMailServer"
+#define ADMINP_OLD_MAILFILE_ITEM "OldMailFile"
+#define ADMINP_OLD_MAILSERVER_ITEM "OldMailServer"
+#define ADMINP_NEW_MAIL_CLIENT_UPDATE_ITEM "NewMailClientUpdateFlag"
+/* address book stuff for roaming user delete, move, and status change */
+#define ADMINP_ROAMING_STATUS_UPDATE_ITEM "RoamingStatusUpdateItem"
+#define ADMINP_NEW_ROAMINGSTATUS_UPDATE_ITEM "NewRoamStatUpdtFl"
+#define ADMINP_NEW_ROAMINGSTATUS_DOWNGRD_ITEM "RoamStatDwnFl"
+#define ADMINP_OLD_ROAMINGSERVER_ITEM "OldRoamSrvr"
+#define ADMINP_OLD_ROAMINGDIRECTORY_ITEM "OldRoamDir"
+#define ADMINP_ROAM_UPGRADE_CASCADE_INFO "RoamUpgdCscdInfo" /* Item name for Request cascade information list */
+#define ADMINP_ROAM_MOVE_CASCADE_INFO "RoamMoveCscdInfo" /* Item name for Request cascade information list */
+#define ADMINP_MAIL_MOVE_CASCADE_INFO "MailMoveCscdInfo" /* Item name for Request cascade information list */
+
+/* Original Request information for Blocking cascaded requests */
+#define ADMINP_ORIGINATING_REQUEST_UNID "ProxyOriginatingRequestUNID"
+#define ADMINP_ORIGINATING_UNID ADMINP_ORIGINATING_REQUEST_UNID
+#define ADMINP_ORIGINATING_REQUEST_AUTHORID "ProxyOriginatingAuthor"
+#define ADMINP_SAVED_ORIGINATING_REQUEST_AUTHORID ADMINP_ORIGINATING_REQUEST_AUTHORID
+#define ADMINP_ORIGINATING_REQUEST_FULLNAME "FullName"
+#define ADMINP_ORIGINATING_REQUEST_ORG "ProxyOriginatingOrganization"
+#define ADMINP_ORIGINATING_REQUEST_INTERNET_DOMAIN "ProxyOriginatingInternetDomain"
+#define ADMINP_ORIGINATING_REQUEST_EXPECTED_LIST "ProxyOriginatingReqsExpected"
+#define ADMINP_ORIGINATING_REQUEST_POSSIBLE_LIST "ProxyOriginatingReqsPossible"
+#define ADMINP_ORIGINATING_TIMEDATE_ITEM "ProxyOriginatingTimeDate"
+
+#define ADMINP_SERV_MON_QUERY "ServMonQuery"
+#define ADMINP_SERV_MON_REPORT "ServMonReport"
+#define ADMINP_SERV_MON_SERV_LIST_ITEM "Server.List"
+#define ADMINP_SERV_MON_RESTRICTED_SERV_LIST_ITEM "Server.Restricted.List"
+
+#define ADMINP_SERV_MON_STAT_RESULTS "ServMonStats"
+#define ADMINP_SERV_MON_STAT_CATEGORY_ITEM "StatisticCategory"
+#define ADMINP_SERV_MON_STAT_NAME_ITEM "Statistic.Name"
+#define ADMINP_SERV_MON_STAT_MIN_ITEM "Statistic.Min.Value"
+#define ADMINP_SERV_MON_STAT_MIN_TD_ITEM "Statistic.Min.Time"
+#define ADMINP_SERV_MON_STAT_MAX_ITEM "Statistic.Max.Value"
+#define ADMINP_SERV_MON_STAT_MAX_TD_ITEM "Statistic.Max.Time"
+#define ADMINP_SERV_MON_STAT_ZEROVAL_ITEM "Statistic.Zero.Value"
+#define ADMINP_SERV_MON_STAT_ZEROVAL_TD_ITEM "Statistic.Zero.Time"
+#define ADMINP_SERV_MON_STAT_MINDELTA_ITEM "Statistic.Min.Difference"
+#define ADMINP_SERV_MON_STAT_MINDELTA_TERM1_ITEM "Statistic.Min.Diff.Term1"
+#define ADMINP_SERV_MON_STAT_MINDELTA_TERM2_ITEM "Statistic.Min.Diff.Term2"
+#define ADMINP_SERV_MON_STAT_MINDELTA_LOW_TD_ITEM "Statistic.Min.Difference.Low"
+#define ADMINP_SERV_MON_STAT_MINDELTA_UPP_TD_ITEM "Statistic.Min.Difference.High"
+#define ADMINP_SERV_MON_STAT_MAXDELTA_ITEM "Statistic.Max.Difference"
+#define ADMINP_SERV_MON_STAT_MAXDELTA_TERM1_ITEM "Statistic.Max.Diff.Term1"
+#define ADMINP_SERV_MON_STAT_MAXDELTA_TERM2_ITEM "Statistic.Max.Diff.Term2"
+#define ADMINP_SERV_MON_STAT_MAXDELTA_LOW_TD_ITEM "Statistic.Max.Difference.Low"
+#define ADMINP_SERV_MON_STAT_MAXDELTA_UPP_TD_ITEM "Statistic.Max.Difference.High"
+#define ADMINP_SERV_MON_STAT_ZERODELTA_ITEM "Statistic.Zero.Difference"
+#define ADMINP_SERV_MON_STAT_ZERODELTA_LOW_TD_ITEM "Statistic.Zero.Difference.Low"
+#define ADMINP_SERV_MON_STAT_ZERODELTA_UPP_TD_ITEM "Statistic.Zero.Difference.High"
+
+#define ADMINP_SERV_MON_EVENT_RESULTS "ServMonResults"
+#define ADMINP_SERV_MON_EVENT_STATUS_ITEM "Event.Name"
+#define ADMINP_SERV_MON_EVENT_TYPE_ITEM "Event.Type"
+#define ADMINP_SERV_MON_EVENT_ADDIN_ITEM "Event.Addin"
+#define ADMINP_SERV_MON_EVENT_SEVERITY_ITEM "Event.Severity"
+#define ADMINP_SERV_MON_EVENT_COUNT_ITEM "Event.Count"
+#define ADMINP_SERV_MON_EVENT_ERROR_MSG_ITEM "Event.Error.Message"
+
+#define ADMINP_CATALOG_NO_NAMES "0"
+#define ADMINP_CATALOG_READERS_AUTHORS "1"
+#define ADMINP_CATALOG_NAMES "2"
+
+/* Address Book - local $Programs namespace */
+#define LOCAL_PROGRAMS_NAMESPACE "1\\$Programs"
+#define PROGRAMSNAMESPACE "$Programs"
+#define PROG_CMD_LINE_ITEM "CmdLine"
+
+/* Address Book - local $Locations namespace */
+#define LOCAL_LOCATIONS_NAMESPACE "1\\$Locations"
+#define LOCATIONSNAMESPACE "$Locations"
+
+/* Address Book - local $Connections namespace */
+#define LOCAL_CONNECTIONS_NAMESPACE "1\\$Connections"
+#define CONNECTIONSNAMESPACE "$Connections"
+
+
+/* Address Book - "Connections" namespace */
+
+
+#define SOURCE_WILDCARD "*"
+
+#define NAME_CONNECTIONLOOKUPITEMCOUNT 9
+#define NAME_CONNECTIONLOOKUPITEMS "Source\0SourceDomain\0Destination\0DestinationDomain\0PortName\0Tasks\0Enabled\0Cost\0ConnectionType"
+#define NAME_CONNECTIONSRCITEM 0
+#define NAME_CONNECTIONSRCDOMAINITEM 1
+#define NAME_CONNECTIONDSTITEM 2
+#define NAME_CONNECTIONDSTDOMAINITEM 3
+#define NAME_CONNECTIONPORTITEM 4
+#define NAME_CONNECTIONTASKSITEM 5
+#define NAME_CONNECTIONENABLEDITEM 6
+#define NAME_CONNECTIONCOSTITEM 7
+#define NAME_CONNECTIONTYPEITEM 8
+
+#define DIALNAMELOOKUPITEMCOUNT 5
+#define DIALNAMELOOKUPITEMS "Destination\0PhoneNumber\0PortName\0LinkInfo\0LinkScriptInfo\0CreditCardPrefix\0CreditCardSuffix"
+#define DESTINATIONNAMEITEM 0
+#define PHONENUMBERITEM 1
+#define PORTNAMEITEM 2
+#define LINKINFOITEM 3
+#define LINKSCRIPTITEM 4
+#define CARDPREFIXITEM 5
+#define CARDSUFFIXITEM 6
+
+#define PT_NAMELOOKUPITEMCOUNT 3 /* For Passthru */
+#define PT_NAMELOOKUPITEMS "Destination\0PassthruServer\0Source"
+#define PT_NAMEITEM_DST 0
+#define PT_NAMEITEM_VIA 1
+#define PT_NAMEITEM_SRC 2
+
+/* Address Book - "Connections" Application field values */
+
+#define ROUTER_APPNAME "Mail Routing" /* Router application name */
+#define PULL_ROUTER_APPNAME "Pull Routing" /* Pull Routing application name */
+#define X400_APPNAME "X400 Mail Routing" /* X.400 MTA application name */
+#define CCMAIL_APPNAME "ccMail Routing" /* ccMail MTA application name */
+#define SMTP_APPNAME "SMTP Mail Routing" /* SMTP MTA application name */
+#define REPL_APPNAME "Replication" /* Replicator application name */
+#define RUNPGM_APPLNAME "Run Program" /* Run program application name */
+#define WKSREP_APPNAME "WksRep" /* Workstation Rep/Briefcase application name */
+#define WKSREPHI_APPNAME "WksRepHI" /* High-priority Rep/Briefcase application name */
+#define CLREPL_APPNAME "Cluster Replication" /* Cluster Replicator application name */
+#define NNTP_APPNAME "NNTP Feed" /* NNTP Feed application name */
+#define DIRCAT_APPNAME "Directory Cataloger" /* DIrectory Catalog Aggregator */
+#define DOMAIN_INDEXER_APPNAME "Domain Indexer" /* Domain Indexer */
+#define AUTODIALER_APPNAME "AutoDialer" /* AutoDialer */
+#define AMGR_APPNAME "Run Agent" /* Agent manager name */
+#define EVENT_APPNAME "Event Monitor"
+#define RUNJAVA_APPNAME "runjava" /* shell to run java class as an add in */
+#define ISPY_APPNAME "ISpy" /* a runjava task */
+#define RMEVAL_APPNAME "RMEval" /* a runjava task */
+#define COMPACT_APPNAME "Compact" /* Database compactor */
+#define DESIGN_APPNAME "Designer" /* Database design */
+#define COLLECTOR_APPNAME "Statistic Collector" /* Statistic Collector */
+
+/* Connection record items not defined above */
+
+#define CONNREC_USAGE_PRIORITY_ITEM "ConnectionRecordFirst" /* "Normal" use connection record first */
+#define CONNREC_LOCATION "ConnectionLocation" /* only for locations */
+#define CONNREC_OPTIONAL_NET_ADDRESS_ITEM "OptionalNetworkAddress" /* Optional network address field */
+#define CONNREC_REMOTE_DTE_ADDRESS_ITEM "RemoteDTEAddress" /* DTE address for X.25 */
+#define CONNREC_FCODE1_ITEM "fcode_1" /* X.25 facility code */
+#define CONNREC_FCODE2_ITEM "fcode_2" /* X.25 facility code */
+#define CONNREC_FCODE3_ITEM "fcode_3" /* X.25 facility code */
+#define CONNREC_FCODE4_ITEM "fcode_4" /* X.25 facility code */
+#define CONNREC_FVAL1_ITEM "fval_1" /* X.25 facility code value */
+#define CONNREC_FVAL2_ITEM "fval_2" /* X.25 facility code value */
+#define CONNREC_FVAL3_ITEM "fval_3" /* X.25 facility code value */
+#define CONNREC_FVAL4_ITEM "fval_4" /* X.25 facility code value */
+#define CONNREC_SCRIPTNAME_ITEM "ScriptName" /* Login script filename */
+#define CONNREC_LINKSCRIPT_INFO_ITEM "LinkScriptInfo" /* Login script information */
+#define CONNREC_SCRIPTARG1_ITEM "ScriptArg1" /* Login script argument */
+#define CONNREC_SCRIPTARG2_ITEM "ScriptArg2" /* Login script argument */
+#define CONNREC_SCRIPTARG3_ITEM "ScriptArg3" /* Login script argument */
+#define CONNREC_SCRIPTARG4_ITEM "ScriptArg4" /* Login script argument */
+#define CONNREC_WEEKDAYS_ITEM "WeekDays" /* Call schedule WeekDays item */
+#define CONNREC_REP_PRIORITY_ITEM "RepPriority" /* Replication priority item */
+#define CONNREC_REP_TYPE_ITEM "RepType" /* Replication type item */
+#define CONNREC_REP_FILELIST_ITEM "Filenames" /* Replication filename list item */
+#define CONNREC_REP_EXCLUDE_FILELIST_ITEM "ExclFNames" /* Excluse the list in "Filenames" item */
+#define CONNREC_REP_TIME_LIMIT_ITEM "TimeLimit" /* Replication time limit item */
+#define CONNREC_NNTP_TYPE_ITEM "NNTPFeedType" /* NNTP Feed type item */
+#define CONNREC_NNTP_AUTH_ITEM "NNTPAuthentication" /* NNTP Authentication item */
+#define CONNREC_NNTP_ENCRYPT_ITEM "NNTPChannelEncrypt" /* NNTP channel encrypt item */
+#define CONNREC_NNTP_CREATE_DBS_ITEM "NNTPCreateUsenetDBs" /* NNTP create db's item */
+#define CONNREC_NNTP_NEWSGROUP_SUBDIR_ITEM "NNTPNewsgroupSubDir" /* NNTP newsgroup subdirectory item */
+#define CONNREC_NNTP_NEWSGROUPS_ITEM "NNTPNewsgroups" /* NNTP newsgroups item */
+#define CONNREC_NNTP_SITES_ITEM "NNTPSites" /* NNTP sites item */
+#define CONNREC_NNTP_TIMELIMIT_ITEM "NNTPTimeLimit" /* NNTP Feed time limit item */
+#define CONNREC_NNTP_USER_ITEM "NNTPUserName" /* NNTP user name for feed */
+#define CONNREC_NNTP_PASSWD_ITEM "NNTPPassword" /* NNTP password for feed */
+#define CONNREC_DIALUP_SERVER_NAME_ITEM "DialViaName" /* Dial Up Server name item */
+#define CONNREC_CONNECTION_MODE_ITEM "ConnectionMode" /* Direct or Dial-Up connection mode */
+#define CONNREC_ROUTING_TYPE_ITEM "RouterType"
+#define CONNREC_ROUTING_SMTPPULL_ITEM "SMTPPullRouting" /* will be enabled if SMTP Push/Pull or Pull Only */
+#define CONNREC_PULL_TIMEOUT_ITEM "PullRoutingTimeout" /* Time to wait for an acknowledgement of the pull request */
+#define CONNREC_PULL_THIS_SERVER "PullThisServer" /* Include this server in pull request */
+#define CONNREC_PULL_ALL_PRIMARY "PullAllPrimary" /* Include all primary internet domains in pull request */
+#define CONNREC_PULL_ALL_ALTERNATE "PullAllAlternates" /* Include all alternate internet domains in pull request */
+#define CONNREC_PULL_CHOOSE_SPECIFIC "PullChooseSpecific" /* Include list specified in PullSpecificList in pull request */
+#define CONNREC_PULL_SPECIFIC_LIST "PullSpecificList" /* Include list of domains in pull request */
+
+
+/* Connection record Mail Routing types */
+
+#define CONNRECMAILTYPE_PUSHWAIT 0
+#define CONNRECMAILTYPE_PULLPUSH 1
+#define CONNRECMAILTYPE_PULL 2
+#define CONNRECMAILTYPE_PUSH 3
+
+/* Connection record types */
+
+#define CONNRECTYPE_NETWORK '0'
+#define CONNRECTYPE_REMOTE '1'
+#define CONNRECTYPE_PASSTHRU '2'
+#define CONNRECTYPE_REMOTE_LAN_SERVICE '5'
+#define CONNRECTYPE_X25 '6'
+#define CONNRECTYPE_ISDN '7'
+#define CONNRECTYPE_HUNT_GROUP '9'
+#define CONNRECTYPE_NNTP 'a'
+
+/* Network connection record item names */
+
+#define CONNREC_TYPE "ConnectionType"
+#define CONNREC_SOURCE "Source"
+#define CONNREC_DESTINATION "Destination"
+#define CONNREC_PORT "PortName"
+#define CONNREC_LANPORT "LanPortName"
+#define CONNREC_ADDRESS "OptionalNetworkAddress"
+#define CONNREC_COMMENTS "Comments"
+#define CONNREC_ENABLED "Enabled"
+
+#define CONNREC_RLAN_SERVICE "RemoteLanService"
+#define CONNREC_RLAN_DRIVERS "DisplayDriverList"
+#define CONNREC_RLAN_STATIC "StaticTag"
+#define CONNREC_RLAN_ITEMS "RLANItems"
+#define CONNREC_RLAN_NAME "RLANTag"
+#define CONNREC_RLAN_LOGIN "RLAN1"
+#define CONNREC_RLAN_PASSWORD "RLAN2"
+#define CONNREC_RLAN_NUMBER "RLAN3"
+#define CONNREC_RLAN_DOMAIN "RLAN7"
+#define CONNREC_RLAN_ITEMS_RAS "7"
+
+#define CONNREC_LANSERVICEDISPLAY "LANSERVICEDISPLAY"
+#define CONNREC_RLAN_ORIGINAL_SERVICE "OriginalService"
+
+#define CONNREC_RLAN_SERVICE_RAS_TEXT "RAS"
+#define CONNREC_RLAN_SERVICE_ARA_TEXT "ARA"
+
+/* Connection record precedence */
+#define CONNRECFIRST '1'
+#define CONNRECLOW '0'
+
+/* Connection modes */
+
+#define CONNREC_MODE_DIALUP 1
+#define CONNREC_MODE_DIRECT 0
+
+/* Authentication types */
+
+#define CONNREC_AUTH_NONE 0
+#define CONNREC_AUTH_PASSWORD 1
+
+
+/* Connection record fields required for Phonebook feature */
+
+#define CONNREC_LAN_PORTNAME "LanPortName"
+#define CONNREC_DIAL_AREA_CODE "DialAreaCode"
+#define CONNREC_LOCAL_PHONE_NUMBER "LocalPhoneNumber"
+#define CONNREC_REMOTE_PORT_NAME "RemotePortName"
+#define CONNREC_ACCOUNTNAME "ConnectionAccount"
+
+/* Address Book - "Connections" (and other views) Enabled field values */
+
+#define KWD_DISABLED "Disabled" /* Obsolete */
+#define KWD_NO "No" /* Obsolete */
+#define VALUE_NO '0'
+#define VALUE_DISABLED '0'
+#define VALUE_ENABLED '1'
+#define VALUE_STARTUP '2'
+
+/* Account form/view stuff in personal address book */
+
+#define ACCOUNTSNAMESPACE "$Accounts"
+
+/* fields in the form */
+#define ACCOUNT_FORM "Account"
+#define ACCOUNT_NAME "AccountName"
+#define ACCOUNT_SERVERNAME "AccountServer"
+#define ACCOUNT_USERNAME "AccountLoginName"
+#define ACCOUNT_PASSWORD "AccountPassword"
+#define ACCOUNT_PROTOCOL "AccountProtocol"
+#define ACCOUNT_FILENAME "AccountFilename"
+#define ACCOUNT_SSL "SSLStatus"
+#define ACCOUNT_LOCATION "AccountLocation"
+#define ACCOUNT_CONNECTION "ConnectionMode"
+#define ACCOUNT_PORT "AccountPortNumber"
+#define ACCOUNT_POPDELMAIL "PopDeleteMail"
+#define ACCOUNT_SSLSITECERTS "SSLSiteCerts"
+#define ACCOUNT_SSLEXPIREDCERTS "SSLExpiredCerts"
+#define ACCOUNT_SSLPROTOCOLVER "SSLProtocolVersion"
+#define ACCOUNT_SSLSENDCERTS "SSLSendCertificates"
+#define ACCOUNT_SSLSERVERAUTH "SSLServerAuthenticate"
+#define ACCOUNT_IMAPDRAFT "IMAPDrafts"
+#define ACCOUNT_IMAPSENT "IMAPSent"
+#define ACCOUNT_REPLHISTORY "AccountReplicationHistory"
+#define ACCOUNT_REPLICAS "AccountReplicas"
+#define ACCOUNT_IMAPFIRSTOPEN "IMAPFirstOpen"
+#define ACCOUNT_IMAPDELMAIL "IMAPDeleteMail"
+#define ACCOUNT_REPL_MAX_PULL "AccountReplicationMaxPull"
+
+#define ACCOUNT_SSL_ON "1"
+#define ACCOUNT_SSL_OFF "0"
+
+/* used to get appropriate accounts for NAMELookups */
+#define ACCOUNT_LOOKUPITEMS "AccountName\0AccountProtocol\0AccountLocation\0AccountFilename\0AccountServer\0IMAPMode\0%AccountFileList"
+#define ACCOUNT_NAMEITEM 0
+#define ACCOUNT_PROTOCOLITEM 1
+#define ACCOUNT_LOCATIONITEM 2
+#define ACCOUNT_DATABASEITEM 3 /* This is the proxy file name only */
+#define ACCOUNT_SERVERITEM 4
+#define ACCOUNT_IMAPMODEITEM 5
+#define ACCOUNT_FILELISTITEM 6 /* This is a list including the proxy file name and all replicas */
+#define ACCOUNT_LOOKUPITEMCOUNT 7
+
+/* Address Book views used by Mail Address in V3. */
+
+#define PEOPLE_GROUPS_FLAT_VIEW "($PeopleGroupsFlat)"
+
+/* Address Book view and column used by Mail Address in V4. */
+
+#define PEOPLE_GROUPS_HIER_VIEW "($PeopleGroupsHier)"
+#define MAIL_ADDRESS_VIEW "($PeopleGroupsFlat)"
+#define PEOPLE_GROUPS_CORP_HIER_VIEW "($PeopleGroupsCorpHier)"
+#define PEOPLE_GROUPS_BY_LANG_VIEW "($PeopleGroupsByLang)"
+
+#define MAIL_ADDRESS_PICKLIST_COLUMN 2
+#define MAIL_NAME_PICKLIST_COLUMN 3
+
+#define MAIL_ADDRESS_NAME_COLUMN "NPName"
+#define MAIL_ADDRESS_ADDRESS_COLUMN "MAMailAddress"
+#define MAIL_ADDRESS_ALT_NAME_COLUMN "AltFullName"
+
+#define EXTENDED_ACCESS_CONTROL_VIEW "($XACL)"
+
+
+/* ($PeoplesGroupsHier) column position, be careful with modifying these.
+ LDAP server uses this view and assumes these positions */
+#define MAIL_ADDRESS_HIER_COLUMN 3
+#define MAIL_NAME_HIER_COLUMN 4
+#define MAIL_NAME_HIER_TYPE 5
+#define MAIL_NAME_HIER_PUBLICKEY 6
+#define MAIL_HIER_MAILADDRESS "$25"
+#define MAIL_HIER_CN "$11"
+#define MAIL_HIER_DN "$24" /* This name had changed to "NPName" in R5.0
+ but has changed back because of compatibility */
+#define USERS_FULLNAME_COLUMN "$23" /* Users Full/List Name column named */
+
+/* #define MAIL_HIER_DN "NPName" */
+#define MAIL_HIER_TYPE "Type"
+#define MAIL_HIER_PUBLICKEY "$20"
+
+/* Person record field names */
+#define PERSON_HOME_STREETADDRESS "StreetAddress"
+#define PERSON_HOME_CITY "City"
+#define PERSON_HOME_STATE "State"
+#define PERSON_HOME_ZIP "Zip"
+#define PERSON_HOME_COUNTRY "Country"
+#define PERSON_HOME_FAX "HomeFAXPhoneNumber"
+#define PERSON_SPOUSE "Spouse"
+#define PERSON_CHILDREN "Children"
+#define PERSON_OFFICE_STREETADDRESS "OfficeStreetAddress"
+#define PERSON_OFFICE_CITY "OfficeCity"
+#define PERSON_OFFICE_STATE "OfficeState"
+#define PERSON_OFFICE_ZIP "OfficeZip"
+#define PERSON_OFFICE_COUNTRY "OfficeCountry"
+#define PERSON_OFFICE_FAX "OfficeFAXPhoneNumber"
+#define PERSON_OFFICE_NUMBER "OfficeNumber"
+#define PERSON_GENERATION_QUALIFIER "Suffix"
+#define PERSON_PERSONAL_TITLE "Title"
+#define PERSON_JOB_TITLE "JobTitle"
+#define PERSON_MANAGER "Manager"
+#define PERSON_CELL_PHONE "CellPhoneNumber"
+#define PERSON_PAGER "PhoneNumber_6"
+#define PERSON_ASSISTANT "Assistant"
+#define PERSON_ENCRYPT_INCOMING_MAIL "EncryptIncomingMail"
+#define PERSON_X400_ADDRESS "x400Address"
+#define PERSON_WEB_SITE "WebSite"
+#define PERSON_EMPLOYEE_ID "EmployeeID"
+#define PERSON_ALTFULLNAMESORT "AltFullNameSort" /* Phonetic Name */
+#define PERSON_PERSONAL_PAGER "PersPager"
+#define PERSON_BRIEFCASE "Briefcase"
+
+
+/* Address Book view used by ServerConfig (to refresh Notes.INI parameters). */
+
+#define SERVER_CONFIG_NAMESPACE "$ServerConfig"
+#define SERVER_CONFIG_NAMESPACE_1 "1\\$ServerConfig"
+#define SERVER_CONFIG_VIEW "($ServerConfig)"
+#define SERVER_ACCESS_VIEW "($ServerAccess)"
+
+/* Server Configuration form items */
+#define SERVER_CONFIG_FORM "ServerConfig"
+#define CONFIG_SERVERNAME_ITEM "ServerName" /* Server name */
+#define CONFIG_MAILEXT_ITEM "MailExternalSMTP"
+
+/* LDAP related definitions */
+#define LDAP_ACCESS_CONTROL_ITEM "LDAPAccessControl"
+#define LDAP_MAXENTRIES_ITEM "LDAPMaxEntries"
+#define LDAP_MINCHAR_ITEM "LDAPMinChar"
+#define LDAP_TIMEOUT_ITEM "LDAPTimeout"
+#define LDAP_PORT_ITEM "LDAP_Port"
+#define LDAP_PORTSTATUS_ITEM "LDAP_PortStatus"
+#define LDAP_SSLPORT_ITEM "LDAP_SSLPort"
+#define LDAP_SSLSTATUS_ITEM "LDAP_SSLStatus"
+#define LDAP_USESSL_ITEM "LDAP_UseSSL"
+#define LDAP_TCP_NAME_PASSWORD_ITEM "LDAP_TCPNP"
+#define LDAP_ALLOWANONYMOUS_ITEM "LDAP_AllowAnonymous"
+#define LDAP_ENFORCE_ACCESS_ITEM "LDAP_EnforceAccess"
+#define LDAP_SEARCH_ITEM "LDAP_Search"
+#define LDAP_AUTHENTICATION_TYPE_ITEM "LDAP_AuthenticationType"
+#define LDAP_GET_CLIENT_CERT_ITEM "LDAP_SSLCert"
+#define LDAP_SSL_NAME_PASSWORD_ITEM "LDAP_SSLNP"
+#define LDAP_SSLANONYMOUS_ITEM "LDAP_SSLAnonymous"
+#define LDAP_CONFIG_FORM "($LDAPSettings)"
+#define LDAP_AMBIGUOUS_WRITE_ITEM "LDAPAmbiguousWrite"
+#define LDAP_CLIENT_ACCESS_ITEM "LDAPAllowWriteAccess"
+#define LDAP_OPTIMIZEVIEW_ITEM "LDAPOptimizeSearch"
+#define LDAP_QUERYEXTENDEDOBJECT_ITEM "LDAPOptimizeSearch" /* "LDAPQueryExtendedObjects" - Post R5.0 */
+#define LDAP_QUERYALTLANG_ITEM "LDAPQueryAltLangInfo"
+#define LDAP_VIEW_TYPE "%LDAPType"
+#define LDAP_EXTENDED_OBJECTCLASS_ITEM "$objectclass"
+#define LDAP_ENFORCE_SCHEMA_ITEM "LDAPEnfrcSchema"
+#define LDAP_FT_INDEX_ITEM "LDAPFTI"
+#define LDAP_MAXREFERRALS_ITEM "LDAPMaxRefs"
+#define LDAP_UTF8RESULTS_ITEM "LDAPUTF8Res"
+#define LDAP_STRICTRFCADHERENCE_ITEM "LDAPStrictRFC"
+#define LDAP_LOGFIELDSIZELIMIT_ITEM "LDAPLogFldSzLim"
+#define LDAP_DEREFALIASESENABLED_ITEM "LDAPDerefAliasesEnabled"
+
+
+/* LDAP View names */
+#define LDAP_CN_VIEW "($LDAPCN)"
+#define LDAP_CN_VIEW_ALT "$LDAPCN"
+#define LDAP_S_VIEW "($LDAPS)"
+#define LDAP_G_VIEW "($LDAPG)"
+#define LDAP_HIER_VIEW "($LDAPHIER)"
+#define LDAP_RDN_HIER_VIEW "($LDAPRDNHIER)"
+#define HIGH_SECURITY_AUTH_VIEW "($HIGH_SECURITY_AUTH)"
+#define LDAP_ALIAS_VIEW "($LDAPAlias)"
+
+/* LDAP Directory Assistance defines */
+#define DA_LDAPURL_ITEM "LDAPURL" /* LDAP Server Flag */
+#define DA_LDAP_MAX_URL_LEN 256
+
+#define DA_LDAPADMINDN_ITEM "LDAPAdminDN"
+#define DA_LDAPADMINPASSWORD_ITEM "LDAPAdminPassword"
+
+#define DA_LDAPPORT_ITEM "LDAPPort" /* LDAP Port Number */
+
+/* Column names */
+#define LDAP_DN_COLUMN "%DN"
+
+
+#define MSG_CONFIG_FORM "($MessagingSettings)"
+#define CAT_CONFIG_FORM "($CatalogerSettings)"
+
+
+/* Address Book - Items used for Message Tracking Configuration */
+
+#define MT_ENABLED_ITEM "MTEnabled"
+#define MT_NOTRACKING_FOR_ITEM "MTNoTrackingFor"
+#define MT_ALLOWEDTO_TRACK_ITEM "MTAllowTracking"
+#define MT_SUBJECTS_ENABLED_ITEM "MTLogSubjects"
+#define MT_NOSUBJECTS_FOR_ITEM "MTNoSubjectsFor"
+#define MT_ALLOWEDTO_TRACKSUBJECTS_ITEM "MTAllowSubjects"
+#define MT_ALLOWEDTO_CAUSEDIALING_ITEM "MTCallers"
+#define MT_COLLECTOR_INTERVAL_ITEM "MTInterval"
+#define MT_MAXRESPONSES "MTMaxResponses"
+
+/* Address Book - Items used for Mail Journalling Configuration */
+#define MAIL_JOURNALLING_ENABLED_ITEM "JrnlEnbld"
+#define MAIL_JOURNALLING_METHOD_ITEM "JrnlMthd"
+#define MAIL_JOURNALLING_DB_NAME_ITEM "JrnlDBName"
+#define MAIL_JOURNALLING_DESTINATION_ITEM "JrnlDest"
+#define MAIL_JOURNALLING_SCOS_ITEM "JournallingSCOSReconsitute"
+#define MAIL_JOURNALLING_ENCRYPT_EXCL_ITEM "JrnlFldEncryptExcl"
+#define MAIL_JOURNALLING_CERTIFICATE_ITEM "JrnlCert"
+#define MAIL_JOURNALLING_DB_METHOD_ITEM "JrnlDBMthd"
+#define MAIL_JOURNALLING_DB_SIZE_ITEM "JrnlDBSz"
+#define MAIL_JOURNALLING_DB_PURGE_INT_ITEM "JrnlDBPurgeInt"
+#define MAIL_JOURNALLING_PERIODICITY_ITEM "JrnlDBPrd"
+
+/* Address Book & INI - Items used for Transactional Logging Configuration INI */
+
+#define TRANSLOG_STATUS "TRANSLOG_Status"
+#define TRANSLOG_PATH "TRANSLOG_Path"
+#define TRANSLOG_MAXSIZE "TRANSLOG_MaxSize"
+#define TRANSLOG_PERFORMANCE "TRANSLOG_Performance"
+#define TRANSLOG_STYLE "TRANSLOG_Style"
+#define TRANSLOG_USEALL "TRANSLOG_UseAll"
+#define TRANSLOG_AUTOFIXUP "TRANSLOG_AutoFixup"
+#define TRANSLOG_RECREATE_LOGCTRL "TRANSLOG_Recreate_Logctrl"
+#define TRANSLOG_MEDIAONLY "TRANSLOG_MediaOnly"
+
+/* Address Book & INI - Items used for shared mail server doc and Configuration INI */
+#define SCOS_DIR_DEF "SCOS_DIR_1"
+#define SCOS_DIR_ACTIVE_DEF "SCOS_DIR_ACTIVE_FILES_1"
+
+/* Address Book & INI - Items used for quota enforcement server doc and Configuration INI */
+#define NSF_QUOTA_METHOD_INI "NSF_QUOTA_METHOD"
+#define NSF_QUOTA_METHOD_DOC "QtaMthd"
+
+/* Address Book & INI - Items used to keep compute in check */
+#define FORMULA_TIMEOUT "FormulaTimeout"
+
+/* Address Book - Items and names used by name server */
+
+#define NS_SERVERNAMEITEM 0
+#define NS_SERVERTITLEITEM 1
+#define NS_SERVERNETWORKITEM 2
+#define NS_SERVERNETADDRESSESITEM 3
+#define NS_SERVERPORTSITEM 4
+#define NS_SERVERLOOKUPITEMCOUNT 5
+#define NS_SERVERLOOKUPITEMS "ServerName\0ServerTitle\0Network\0NetAddresses\0Ports"
+
+/* Address Book - Items and names used by DbQuotaSet to verify access */
+
+#define DBQUOTA_SERVERADMINITEM 0
+#define DBQUOTA_SERVERLOOKUPITEMCOUNT 1
+#define DBQUOTA_SERVERLOOKUPITEMS "Administrator"
+
+/* Address Book - Items and names used by server during initialization */
+
+#define INIT_SERVERNAMEITEM 0
+#define INIT_SERVERTITLEITEM 1
+#define INIT_SERVERADMINITEM 2
+
+#define INIT_SERVERCERTIFICATE 3
+#define INIT_SERVERCHANGEREQUEST 4
+
+#define INIT_SERVERALLOWITEM 5
+#define INIT_SERVERDENYITEM 6
+#define INIT_SERVERCREATEITEM 7
+#define INIT_SERVERREPLICAITEM 8
+
+#define INIT_SERVERPTTARGETITEM 9
+#define INIT_SERVERPTCLIENTITEM 10
+#define INIT_SERVERPTCALLERITEM 11
+#define INIT_SERVERPTACCESSITEM 12
+
+#define INIT_SERVER_WHITELIST 13
+#define INIT_SERVER_WHITELISTLOG 14
+#define INIT_SERVER_ANONYMOUSACCESS 15
+
+#define INIT_SERVER_BUILDNUMBER 16
+/*
+*/
+#define INIT_SERVER_MAJORVERSION 17
+#define INIT_SERVER_MINORVERSION 18
+#define INIT_SERVER_QMRVERSION 19
+#define INIT_SERVER_QMUVERSION 20
+#define INIT_SERVER_HOTFIXVERSION 21
+#define INIT_SERVER_FIXPVERSION 22
+#define INIT_SERVER_FLAGSVERSION 23
+/*
+*/
+#define INIT_SERVERRESTRICTEDLIST 24
+#define INIT_SERVERUNRESTRICTEDLIST 25
+
+#define INIT_SERVER_CHECK_CLIENT_PW 26
+#define INIT_SERVER_CLUSTERNAME 27
+
+#define INIT_SERVERMONITORALLOWLIST 28
+#define INIT_SERVERMONITORDENYLIST 29
+
+#define INIT_SERVERSMTPENABLED 30
+
+#define INIT_TRANSLOG_STATUS 31 /* Items used for Transactional Logging Configuration */
+#define INIT_TRANSLOG_PATH 32
+#define INIT_TRANSLOG_MAXSIZE 33
+#define INIT_TRANSLOG_PERFORMANCE 34
+#define INIT_TRANSLOG_STYLE 35
+#define INIT_TRANSLOG_USEALL 36
+#define INIT_TRANSLOG_AUTOFIXUP 37
+
+#define INIT_SERVER_MIN_NOTES_PW 38
+#define INIT_SERVER_ENABLE_HTTPSYNC 39
+#define INIT_QUOTA_METHOD 40
+#define INIT_FORMULA_TIMEOUT 41
+
+#define INIT_SERVER_PUBKEY_MINWIDTH 42
+#define INIT_SERVER_PUBKEY_MAXWIDTH 43
+#define INIT_SERVER_PUBKEY_DEFWIDTH 44
+#define INIT_SERVER_PUBKEY_MAXAGE 45
+#define INIT_SERVER_PUBKEY_MINDATE 46
+#define INIT_SERVER_PUBKEY_DUEDATE 47
+#define INIT_SERVER_PUBKEY_PRIORITY 48
+#define INIT_SERVER_PUBKEY_OLDKEYDAYS 49
+
+#define INIT_DB2_ITEM_INIT 50
+#define INIT_DB2_ITEM_DIRECTORY 51
+#define INIT_DB2_ITEM_INSTANCE 52
+#define INIT_DB2_ITEM_DB 53
+#define INIT_DB2_ITEM_SCHEMA 54
+#define INIT_DB2_ITEM_DEFAULT 55
+#define INIT_DB2_ITEM_PREF 56
+#define INIT_DB2_ITEM_UDFSRV 57
+#define INIT_DB2_ITEM_UDFPATH 58
+#define INIT_DB2_ITEM_DB2GRPMAX 59
+
+#define INIT_SERVERLOOKUPITEMCOUNT 60
+#define INIT_SERVERLOOKUPITEMS \
+"ServerName\0ServerTitle\0Administrator\0\
+Certificate\0ChangeRequest\0\
+AllowAccess\0DenyAccess\0CreateAccess\0ReplicaAccess\0\
+PTTargets\0PTClients\0PTCallers\0PTAccess\0\
+WhiteList\0WhiteListLog\0AnonymousAccess\0\
+ServerBuildNumber\0MajVer\0MinVer\0QMRVer\0QMUVer\0HotVer\0FixPVer\0FlagsVer\0\
+RestrictedList\0UnrestrictedList\0\
+ServerCheckPasswords\0ClusterName\0AllowMonitors\0DenyMonitors\0\
+SMTPListenerEnabled\0\
+TRANSLOG_Status\0TRANSLOG_Path\0TRANSLOG_MaxSize\0TRANSLOG_Performance\0\
+TRANSLOG_Style\0TRANSLOG_UseAll\0TRANSLOG_AutoFixup\0\
+MinumumNotesPW\0EnableHTTPSyncWithNotesPW\0QtaMthd\0FormulaTimeOut\0\
+PKMinWidth\0\
+PKMaxWidth\0\
+PKDefWidth\0\
+PKMaxAge\0\
+PKMinDate\0\
+PKDueDate\0\
+PKPriority\0\
+PKOldKeyDays\0\
+DB2Init\0\
+DB2Dir\0\
+DB2Inst\0\
+DB2Db\0\
+DB2Sche\0\
+DB2Def\0\
+DB2Pref\0\
+DB2UDFSrv\0\
+DB2UDFPath\0\
+DB2GroupMax\0"
+
+/* Address Book - Items and names used by cconsole to verify access */
+
+#define CCONSOLE_SERVERADMINITEM 0
+#define CCONSOLE_SERVERLOOKUPITEMCOUNT 1
+#define CCONSOLE_SERVERLOOKUPITEMS "Administrator"
+
+/*
+ * Address Book - Items and names used by Assist to verify agent execution
+ * access.
+ */
+
+#define ASSIST_PRIVATE_ITEM 0
+#define ASSIST_RESTRICTED_ITEM 1
+#define ASSIST_UNRESTRICTED_ITEM 2
+#define ASSIST_START_ITEM 3
+#define ASSIST_END_ITEM 4
+#define ASSIST_MAX_START_ITEM 5
+#define ASSIST_MAX_END_ITEM 6
+
+#define ASSIST_LOOKUP_AMGR_ITEM_COUNT 7
+#define ASSIST_LOOKUP_AMGR_ITEMS "PrivateList\0RestrictedList\0UnrestrictedList\0StartTime\0EndTime\0MaxStartTime\0MaxEndTime"
+
+#define ASSIST_PRIVATE_LIST_NAME "PRIVATE_LIST"
+#define ASSIST_RESTRICTED_LIST_NAME "RESTRICTED_LIST"
+#define ASSIST_UNRESTRICTED_LIST_NAME "UNRESTRICTED_LIST"
+
+/*
+ * Address Book - Items and names used by Agent Manager to verify agent
+ * execution access.
+ */
+
+#define AMGR_RELOAD_ITEM 0
+#define AMGR_NORMAL_START_ITEM 1
+#define AMGR_NORMAL_END_ITEM 2
+#define AMGR_NORMAL_CONCURRENT_TASKS_ITEM 3
+#define AMGR_NORMAL_MAX_EXECUTION_ITEM 4
+#define AMGR_NORMAL_PERCENT_TIME_ITEM 5
+#define AMGR_MAX_START_ITEM 6
+#define AMGR_MAX_END_ITEM 7
+#define AMGR_MAX_CONCURRENT_TASKS_ITEM 8
+#define AMGR_MAX_MAX_EXECUTION_ITEM 9
+#define AMGR_MAX_PERCENT_TIME_ITEM 10
+#define AMGR_CREATE_DB_ITEM 11
+#define AMGR_PRIVATE_ITEM 12
+#define AMGR_RESTRICTED_ITEM 13
+#define AMGR_UNRESTRICTED_ITEM 14
+#define AMGR_ALLOWACCESS_ITEM 15
+#define AMGR_DENYACCESS_ITEM 16
+#define AMGR_CREATEREPLICA_DB_ITEM 17
+#define AMGR_SERVERS_NOTEID_ITEM 18 /* expanded lookup to include servers id note */
+#define AMGR_SERVERS_NAPATH_ITEM 19 /* expanded lookup to include N&A path */
+
+
+#define AMGR_LOOKUP_ITEM_COUNT 18
+#define AMGR_LOOKUP_ITEMS \
+"ReloadTime\0StartTime\0EndTime\0ConcurrentAgents\0MaxExecution\0\
+PercentTime\0MaxStartTime\0MaxEndTime\0MaxConcurrentAgents\0\
+MaxMaxExecution\0MaxPercentTime\0CreateAccess\0PrivateList\0\
+RestrictedList\0UnrestrictedList\0AllowAccess\0DenyAccess\0\
+ReplicaAccess"
+
+/* extended lookup used for web agents and synch new mail agents, i.e. API based invocation */
+#define AMGR_EXT_LOOKUP_ITEM_COUNT 20
+#define AMGR_EXT_LOOKUP_ITEMS \
+"ReloadTime\0StartTime\0EndTime\0ConcurrentAgents\0MaxExecution\0\
+PercentTime\0MaxStartTime\0MaxEndTime\0MaxConcurrentAgents\0\
+MaxMaxExecution\0MaxPercentTime\0CreateAccess\0PrivateList\0\
+RestrictedList\0UnrestrictedList\0AllowAccess\0DenyAccess\0\
+ReplicaAccess\0$$NoteId\0$$DBName"
+
+/* Address book - Contains port configuration and other parameters used by
+ * DIIOP process.
+ */
+#define DIIOP_TCP_PORT_STR "IIOP_Port"
+#define DIIOP_TCP_PORT_STATUS_STR "IIOP_PortStatus"
+#define DIIOP_SSL_PORT_STR "IIOP_SSLPort"
+#define DIIOP_SSL_PORT_STATUS_STR "IIOP_SSLStatus"
+#define DIIOP_IOR_HOST_STR "IIOP_IORHost"
+#define DIIOP_IDLE_MINS_ALLOWED_STR "IIOP_IdleMinsAllowed"
+#define DIIOP_EXTERNAL_HTML_DIR_STR "IIOP_HtmlDir"
+#define HTTP_HTML_DIR_STR "HTTP_HtmlDir"
+#define HTTP_SSL_KEYFILE_STR "HTTP_SSLKeyFile"
+
+#define INTERNET_AUTH_VIEW "HTTP_AuthView"
+
+
+/* Address book - Items used by the Domino back-end objects for security
+ * configuration
+ */
+
+#define LSBE_BROWSE_FLAG 0
+#define LSBE_VIEW 1
+#define LSBE_IIOP_TCP_NAME_AND_PASSWD 2
+#define LSBE_IIOP_TCP_ANONYMOUS 3
+#define LSBE_IIOP_SSL_NAME_AND_PASSWD 4
+#define LSBE_IIOP_SSL_ANONYMOUS 5
+#define LSBE_HTTP_SESSION_AUTH 6
+#define LSBE_HTTP_SSO_CONFIG 7
+
+#define LSBE_SECURITY_ITEM_COUNT 8
+#define LSBE_SECURITY_ITEMS "HTTP_DatabaseBrowsing\0HTTP_AuthView\0\
+IIOP_TCPNP\0IIOP_AllowAnonymous\0\
+IIOP_SSLNP\0IIOP_SSLAnonymous\0HTTP_enableSessionAuth\0HTTP_SSOCfg"
+
+/* Address book - Items used by the Domino back-end objects for getting person
+ * information
+ */
+#define LSBE_HTTPPASSWORD 0
+#define LSBE_FULLNAME 1
+#define LSBE_ALTFULLNAME 2
+#define LSBE_ALTFULLNAMELANG 3
+#define LSBE_DOMAINTYPE 4
+#define LSBE_PERSON_ITEM_COUNT 5
+#define LSBE_FULL_PERSON_ITEMS "HTTPPassword\0FullName\0AltFullName\0AltFullNameLanguage\0$$DomainType\0$$DBIndex"
+#define LSBE_LIM_PERSON_ITEMS "HTTPPassword\0%DN\0AltFullName\0AltFullNameLanguage\0$$DomainType\0$$DBIndex"
+
+/* Address book - Lightweight third-party Authentication Items
+ */
+
+#define LTPA_SVITEMS "HTTP_enableSessionAuth\0HTTP_WebSSOConfig"
+#define LTPA_SVITEM_SESSIONAUTH 0
+#define LTPA_SVITEM_WEBSSOCONFIG 1
+#define LTPA_SVITEMS_COUNT 2
+
+#define LTPA_NAMESPACE "($WebSSOConfigs)"
+
+#define LTPA_WSTOKENNAME "LtpaToken"
+
+#define LTPA_TOKENNAME "Ltpa_TokenName"
+#define LTPA_TOKENDOMAIN "Ltpa_TokenDomain"
+#define LTPA_TOKENEXPR "Ltpa_TokenExpiration"
+#define LTPA_DOMSECRET "Ltpa_DominoSecret"
+#define LTPA_DOMSECRETNEXT "Ltpa_DominoSecretNext"
+#define LTPA_DOMSECRETPREV "Ltpa_DominoSecretPrev"
+#define LTPA_WSENABLED "Ltpa_WSEnabled"
+#define LTPA_WS3DESDATA "Ltpa_WS3DESData"
+#define LTPA_WSRSADATA "Ltpa_WSRSAData"
+#define LTPA_WSREALM "Ltpa_WSRealm"
+#define LTPA_WSVERSION "Ltpa_WSVersion"
+#define LTPA_ROLLOVERENABLED "Ltpa_RolloverEnabled"
+#define LTPA_LASTROLLOVERDATE "Ltpa_LastRolloverDate"
+#define LTPA_IDLETIMEOUTMAX "Ltpa_IdleTimeoutMax"
+#define LTPA_IDLETIMEOUTMIN "Ltpa_IdleTimeoutMin"
+#define LTPA_NAMEMAPPING "Ltpa_MapNm"
+
+#define LTPA_MAXTOKENLEN 2048
+#define LTPA_MAXTOKENNAMELEN 64
+#define LTPA_MAXTOKENDOMAINLEN MAX_TCP_HOST_NAME
+#define LTPA_MAXWSREALMLEN 256
+
+
+/* Address book - Items used by Calendaring & Scheduling for user lookup
+ and domain lookup. */
+
+#define SCHED_USERLOOKUPITEMCOUNT 6
+#define SCHED_USERLOOKUPITEMS "FullName\0ListName\0MailAddress\0MailDomain\0MailServer\0CalendarDomain"
+#define SCHED_USERLOOKUPFULLNAMEITEM 0
+#define SCHED_USERLOOKUPLISTNAMEITEM 1
+#define SCHED_USERLOOKUPMAILADDRESSITEM 2
+#define SCHED_USERLOOKUPMAILDOMAINITEM 3
+#define SCHED_USERLOOKUPMAILSERVERITEM 4
+#define SCHED_USERLOOKUPCALENDARDOMAINITEM 5
+
+#define SCHED_DOMAINLOOKUPITEMCOUNT 3
+#define SCHED_DOMAINLOOKUPITEMS "DomainType\0CalendarServer\0CalendarSystem"
+#define SCHED_DOMAINLOOKUPDOMAINTYPEITEM 0
+#define SCHED_DOMAINLOOKUPCALENDARSERVERITEM 1
+#define SCHED_DOMAINLOOKUPCALENDARSYSTEMITEM 2
+
+#define SCHEDULE_MGR_LOOKUP_ITEM_COUNT 7
+#define SCHEDULE_MGR_LOOKUP_ITEMS "FullName\0MailServer\0MailFile\0MailDomain\0CalendarDomain\0Type\0MailAddress"
+#define SCHEDULE_MGR_LOOKUP_ITEM_MAILSERVER 1
+#define SCHEDULE_MGR_LOOKUP_ITEM_MAILFILE 2
+#define SCHEDULE_MGR_LOOKUP_ITEM_MAILDOMAIN 3
+#define SCHEDULE_MGR_LOOKUP_ITEM_CALENDARDOMAIN 4
+#define SCHEDULE_MGR_LOOKUP_ITEM_TYPE 5
+#define SCHEDULE_MGR_LOOKUP_ITEM_MAILADDRESS 6
+
+/* View note item names */
+
+#define VIEW_TITLE_ITEM FIELD_TITLE /* Title */
+#define VIEW_COLLECTION_ITEM "$Collection" /* Contains object ID */
+#define VIEW_CONTAINER_ITEM "$ViewContainer" /* Contains storage object ID */
+#define VIEW_FORMULA_ITEM "$Formula" /* Selection formula buffer */
+#define VIEW_FORMULA_TIME_ITEM "$FormulaTV" /* If present, formula is "time-relative" (@NOW-based) */
+#define VIEW_CLASSES_ITEM "$FormulaClass" /* Formula note classes */
+#define VIEW_COLLATION_ITEM "$Collation" /* Collation buffer */
+#define VIEW_TOTALS_ITEM "$Totals" /* Subtotalling specification */
+#define VIEW_VIEW_FORMAT_ITEM "$ViewFormat" /* View table format item */
+#define VIEW_INDEX_ITEM "$Index" /* Index disposition options */
+#define VIEW_DESIGN_VER_ITEM_V2 "$DesignVersion" /* Design note version, for V2 backward compatibility */
+#define VIEW_DESIGN_VER_ITEM "$Version" /* Design note version */
+#define VIEW_NOTEREF_ITEM FIELD_LINK /* Note Reference item */
+#define VIEW_CONFLICT_ITEM "$Conflict" /* Replication update conflict */
+#define VIEW_FORM_FORMULA_ITEM "$FormFormula" /* Form Formula */
+#define VIEW_COMMENT_ITEM "$Comment" /* View comment. */
+#define VIEW_SELQUERY_ITEM "$SelQuery" /* View selection query object */
+#define VIEW_LASTSEENUID_ITEM "$LastSeenUID" /* Internet Replication Last Seen UID */
+#define ITEM_NAME_REFOPT "$RefOptions" /* ALlow a ref to original
+ note to be included. */
+#define VIEW_FORMAT_CUSTOMIZE_ITEM "$CustomViewFormat"
+#define VIEW_INHERITED_FROM_ITEM "$ViewInheritedFrom" /* what was this view/folder based on */
+#define VIEW_SQLQUERY_ITEM "$ViewSQLQuery" /* SQL Query for View Selection */
+
+/* Calendar view print customization items... */
+#define VIEW_FORMAT_CALDAYPRINT_ITEM "$CalDayPrintCustomFormat"
+#define VIEW_FORMAT_CALWEEKPRINT_ITEM "$CalWeekPrintCustomFormat"
+#define VIEW_FORMAT_CALMONTHPRINT_ITEM "$CalMonthPrintCustomFormat"
+#define VIEW_FORMAT_CALWORKWEEKPRINT_ITEM "$CalWorkWeekPrintCustomFormat"
+#define VIEW_FORMAT_CALROLLINGPRINT_ITEM "$CalRollingPrintCustomFormat"
+#define VIEW_FORMAT_CALLISTPRINT_ITEM "$CalListPrintCustomFormat"
+
+/* Some custom view information stored in bookmark cache. */
+#define VIEW_FORMAT_CUSTOM_FLAGS_ITEM "$ViewCustomFlags"
+#define VIEW_FORMAT_CUSTOM_NEWESTMAIL_TIME "$NewestMailTime" /* what time the last refresh was done. */
+#define VIEW_FORMAT_CUSTOM_NEWESTMAIL_UNID "$NewestMailUNID" /* what is the unid of topmost newest mail */
+
+/* Calendar style view items */
+
+#define VIEW_CALENDAR_FORMAT_ITEM "$CalendarFormat" /* Calendar View format item */
+
+#define VIEW_FORMAT_DAILY_CAL_ITEM "$DailyCalViewFormat"
+#define VIEW_FORMAT_WEEKLY_CAL_ITEM "$WeeklyCalViewFormat"
+#define VIEW_FORMAT_MONTHLY_CAL_ITEM "$MonthlyCalViewFormat"
+#define VIEW_FORMAT_ROLLING_CAL_ITEM "$RollingCalViewFormat"
+#define VIEW_FORMAT_LIST_CAL_ITEM "$ListCalViewFormat"
+
+/* Folder-related view items */
+/* Pre-build 126 items, can be removed before V4 ship - only exposed internally */
+#define VIEW_UNID_SELECTION_ITEM "$UNIDSelection" /* List of UNID's which are in view. */
+#define VIEW_USE_UNID_SELECTION_ITEM "$UseUNIDSelection" /* If present, uses UNID selection table. */
+
+#define VIEW_FOLDER_OBJECT "$FolderObject" /* If present, is ODS version of FOHEADER and
+ set of entries, see dbfolder.h. The view
+ may have additional items with suffixes
+ on this item name, e.g., $FolderObject1 */
+#define VIEW_FOLDER_IDTABLE "$FolderIDTable" /* If present, is ID table representing the
+ contents of the folder */
+#define VIEW_ANTIFOLDER_IDTABLE "$AntiFolderIDTable"
+#define VIEW_VIEWLOGGING "$ViewLogging" /* If present, states whether to log backing btree */
+
+
+/* Used only within NSF for single copy template */
+#define NOTE_REFERENCE_ITEM "$NoteReference" /* Reference to template note that this note inherits from */
+
+
+/* Hidden view name prefix/postfix strings. */
+
+#define HIDDEN_VIEW_NAME_PREFIX "("
+#define HIDDEN_VIEW_NAME_POSTFIX ")"
+
+/* ViewMap note item names */
+
+#define VIEWMAP_DATASET_ITEM "$ViewMapDataset" /* Contains ViewMap dataset data */
+#define VIEWMAP_LAYOUT_ITEM "$ViewMapLayout" /* Contains layout objects */
+#define VIEWMAP_IMAGEMAP_ITEM "$NavImagemap" /* Contains the navigator's imagemap */
+
+/* UName special fields */
+
+#define UNAME_PATH_ITEM "Path"
+#define UNAME_SERVER_ITEM "Server"
+#define UNAME_DB_ITEM "Database"
+
+/* Actions */
+
+#define ACTION_ITEM "$ACTIONS"
+#define V5ACTION_ITEM "$V5ACTIONS"
+
+/* Filter note item names */
+
+#define FILTER_TYPE_ITEM "$Type"
+#define FILTER_COMMENT_ITEM "$Comment"
+#define FILTER_FORMULA_ITEM "$Formula" /* Required */
+#define FILTER_FORMULA2_ITEM "$Formula2" /* Second one, optional */
+#define FILTER_SCAN_ITEM "$Scan" /* all in view, selected in view, all in db, unread in db */
+#define FILTER_HIGHLIGHT_ITEM "$Highlight" /* '1' if hilites enabled, '0' to remove */
+#define FILTER_QUERY_ITEM "$Query" /* Full text query string used to refine notes to do */
+#define FILTER_OPERATION_ITEM "$Operation" /* update, create new, select */
+#define FILTER_PERIOD_ITEM "$Period" /* hourly, daily, or weekly */
+#define FILTER_LEFTTODO_ITEM "$LeftToDo" /* Data structure describing what's left to do */
+#define FILTER_MACHINE_ITEM "$MachineName" /* name of machine on which this background filter may run */
+
+/* filter types */
+
+#define FILTER_TYPE_MENU 0
+#define FILTER_TYPE_BACKGROUND 1
+#define FILTER_TYPE_MAIL 2
+#define FILTER_TYPE_ONCE 3
+
+/* filter scan options */
+
+#define FILTER_SCAN_ALL 0
+#define FILTER_SCAN_UNREAD 1
+#define FILTER_SCAN_VIEW 2
+#define FILTER_SCAN_SELECTED 3
+#define FILTER_SCAN_MAIL 4
+#define FILTER_SCAN_NEW 5
+
+#define FILTER_OP_UPDATE 0
+#define FILTER_OP_SELECT 1
+#define FILTER_OP_NEW_COPY 2
+
+/* filter periods */
+
+#define PERIOD_HOURLY 0
+#define PERIOD_DAILY 1
+#define PERIOD_WEEKLY 2
+#define PERIOD_DISABLED 3
+
+/* Query note item names. */
+
+/* If the user has typed in a query, it is stored in $SimpleQuery; If
+ the user has created a query using the Query Builder, it is stored
+ in the $Builder... fields. */
+
+#define QUERY_SIMPLEQUERY_ITEM "$SimpleQuery" /* simple query */
+#define QUERY_BUILDERQUERY_ITEM "$BuilderQuery" /* Query Builder: text list of */
+ /* different portions of query: */
+ /* any of these, all of these, */
+ /* none of these, author */
+
+#define QUERY_BUILDERDATE_ITEM "$BuilderDate" /* Date before or after */
+#define QUERY_BUILDERFLAGS_ITEM "$BuilderFlags" /* query builder flags */
+#define QUERY_FIELDQUERY_ITEM "$FieldQuery" /* query by form query */
+
+#define QUERY_FIELDACTION_ITEM "$FieldAction" /* action by form struct */
+#define QUERY_FORMULAACTION_ITEM "$FormulaAction" /* @function action formula */
+
+#define QUERY_BUILDERFLAG_NEAR 'N' /* Apply near to 'all of these' */
+#define QUERY_BUILDERFLAG_DATEBEFORE 'B' /* Before $BuilderDate (as opposed to after) */
+
+/* V4 Search Bar queries */
+
+#define QUERY_V4_OBJECTQUERY_ITEM "$V4QueryObject" /* Query object built by the V4 Search Builder */
+#define QUERY_V4_OPTIONS_ITEM "$V4QueryOptions" /* Query options from the V4 Search Builder */
+
+/* V4 Assistants */
+
+#define ASSIST_INFO_ITEM "$AssistInfo" /* info (TYPE_ASSISTANT_INFO) */
+#define ASSIST_TYPE_ITEM "$AssistType" /* Type of assistant - related to action type */
+#define ASSIST_QUERY_ITEM "$AssistQuery" /* assistant query item */
+#define ASSIST_ACTION_ITEM "$AssistAction" /* assistant action item */
+#define ASSIST_LASTRUN_ITEM "$AssistLastRun" /* TimeDate of last run */
+#define ASSIST_DOCCOUNT_ITEM "$AssistDocCount" /* Number of docs run on last run */
+#define ASSIST_RUNINFO_ITEM "$AssistRunInfo" /* Run information object */
+#define ASSIST_EXACTION_ITEM "$AssistAction_Ex" /* assistant action item - extra data */
+#define ASSIST_VERSION_ITEM "$AssistVersion" /* TIMEDATE of when the agent design
+ (as opposed to enable/disable state)
+ was changed */
+#define ASSIST_FORMAT_VER "$AssistFormatVer" /* format of the agent structure */
+#define ASSIST_FORMAT_VER5040 "05040" /* introduced in 5.04 */
+#define ASSIST_FORMAT_VER5030 "05030" /* introduced in 5.03 */
+
+
+/* Types for ASSIST_TYPE_ITEM - the following defines are used to determine
+ * what type of assistant we are dealing with -- ie, what is the main
+ * action type that the user has defined. The formula ones are for
+ * backwards compatability with V3.
+ * See ods.h for the SIG_ACTION_xxx values used for regular V4 generic agents.
+ */
+
+#define ASSIST_SIG_ACTION_NONE -1 /* No action defined */
+/* formula, update only -FILTER_OP_UPDATE 0 */
+/* formula, select only -FILTER_OP_SELECT 1 */
+/* formula, new copy -FILTER_OP_NEW_COPY 2 */
+
+/* The default search form and default action forms are used by query by form
+ and action by form. */
+
+#define DEFAULT_QUERY_BY_FORM "$DefaultSearch"
+#define DEFAULT_ACTION_BY_FORM "$DefaultAction"
+
+/* Misc Flags */
+
+#define ASSIST_FLAG_ENABLED 'E'
+#define ASSIST_FLAG_DISABLED 'D'
+#define ASSIST_FLAG_NEWCOPY 'N'
+#define ASSIST_FLAG_HIDDEN 'H'
+#define ASSIST_FLAG_PRIVATE 'P'
+#define ASSIST_FLAG_THREAD 'T'
+#define ASSIST_FLAG_ALLOW_REMOTE_DEBUGGING 'R'
+#define ASSIST_FLAG_ALLOW_UNSECURE_LS_LIBS 'L'
+#define ASSIST_FLAG_AGENT_RUNASWEBUSER 'u' /* signed "shadow" flag to verify value of unsigned DESIGN_FLAG_AGENT_RUNASWEBUSER*/
+#define ASSIST_FLAG_AGENT_RUNASSIGNER 's' /* signed "shadow" flag to verify value of unsigned DESIGN_FLAG_AGENT_RUNASWEBUSER*/
+#define ASSIST_FLAGS_ITEM "$AssistFlags" /* Misc flags */
+#define ASSIST_FLAGS_ITEM2 "$AssistFlags2" /* Unsigned Misc flags */
+#define ASSIST_ONBEHALFOF "$OnBehalfOf" /* used by agents to specify whose authority the agents
+ runs under (other than the signer) */
+#define ASSIST_RESTRICTED "$Restricted" /* agent designer can force the agent to have restricted
+ rights, even if the signer has unrestricted rights , or
+ raise their rights to be full admin + unrestricted */
+
+#define ASSIST_RESTRICTED_RESTRICTED 0x00000001 /* base value for restricted */
+#define ASSIST_RESTRICTED_UNRESTRICTED 0x00000000 /* base value for unrestricted */
+#define ASSIST_RESTRICTED_NOT_FORCED 0x00000000 /* used when the item is not used to force restrictions in the agent
+ agent can be unrestricted, if the signiture allows it */
+#define ASSIST_RESTRICTED_FORCED 0x00000001 /* used when the designer wants to force the agent to be only restricted
+ note: this flag has no effect when the agent signer is restricted or
+ has no rights to run the agents */
+#define ASSIST_RESTRICTED_FULLADMIN 0x00000002 /* unrestricted (low bit of zero, plus fulladmin */
+#define ASSIST_RESTRICTED_NOT_PRESENT 0x10000000 /* (in-memory) used when the item is not present in the agent */
+#define ASSIST_RESTRICTED_FORCED_USED 0x20000000 /* (in-memory) set when the flag was used to lower permissions */
+#define ASSIST_RESTRICTED_SCRIPT_LIBRARY 0x40000000 /* (in-memory) used when the agent rights are lowered because of the script library */
+
+
+#define ASSIST_MAIL_ITEM "$AssistMail" /* If this field exists in a mail note, it means that */
+ /* mail message was created by an agent. */
+
+#define ASSIST_TRIGGER_ITEM "$AssistTrigger" /* (Read-only) Assistant's trigger type */
+#define FORM_SCRIPT_OBJECT "$$FormScript_O" /* Script object code item */
+
+/* These were moved here from \edit\dmem.h */
+#define FORM_SCRIPT_ITEM_NAME "$$FormScript"
+#define DOC_SCRIPT_ITEM "$Script"
+#define DOC_SCRIPT_ITEM_OBJECT "$$Script_O"
+#define DOC_ACTION_ITEM "$$FormAction"
+#define DOC_SCRIPT_NAME "$$ScriptName"
+#define DOC_SCRIPT_BREAKPOINTS "$Breakpoints"
+
+/* View Script items */
+#define VIEW_SCRIPT_NAME "$ViewScript"
+#define VIEW_SCRIPT_OBJECT "$ViewScript_O"
+#define VIEW_GLOBAL_SCRIPT_NAME "$ViewGlobalScript"
+#define VIEW_GLOBAL_SCRIPT_OBJECT "$ViewGlobalScript_O"
+#define VIEW_ACTION_ITEM_NAME "$ViewAction" /* Formula for view script event */
+#define VIEW_ACTION_EVENT_COUNT 14 /* ie, $ViewAction0-$ViewAction10 - one per view script event that can contain formulas */
+
+/* Database Script items */
+#define DB_SCRIPT_DESIGN_NAME "Database Script"
+#define DB_SCRIPT_NAME "$DBScript"
+#define DB_SCRIPT_OBJECT "$DBScript_O"
+#define DB_ACTION_ITEM_NAME "$DBAction"
+
+/* Script Library items */
+#define SCRIPTLIB_ITEM_NAME "$ScriptLib"
+#define SCRIPTLIB_OBJECT "$ScriptLib_O"
+#define JAVASCRIPTLIBRARY_CODE "$JavaScriptLibrary"
+
+/* Servlet items */
+#define SERVLET_FLAGS_ITEM "$ServletFlags"
+#define SERVLET_FLAG_HASSOURCE 'S' /* has real source, not just included files */
+
+/* Web Service items */
+//#define WEBSERVICE_NAMESPACE "$WSNameSpace"
+#define WEBSERVICE_PORTTYPE "$WSPortType"
+#define WEBSERVICE_ELTNAME "$WSEltName"
+#define WEBSERVICE_PORTNAME "$WSPortName"
+#define WEBSERVICE_PORTCLASS "$WSPortClass"
+
+#define WEBSERVICE_FLAGS_ITEM "$WebServiceFlags"
+#define WEBSERVICE_FLAG_SOAPDEFAULT 'S'
+#define WEBSERVICE_FLAG_SOAPOPERATION 'O'
+#define WEBSERVICE_FLAG_DOCBIND 'D'
+#define WEBSERVICE_FLAG_WRAPBIND 'W'
+#define WEBSERVICE_FLAG_LITERALBIND 'L'
+#define WEBSERVICE_FLAG_XMLDATAMAP 'X'
+#define WEBSERVICE_FLAG_XMLDOCTYPE 'Y'
+#define WEBSERVICE_FLAG_ISVALID 'V'
+#define WEBSERVICE_FLAG_FROZEN 'F'
+#define WEBSERVICE_FLAG_VALIDATION 'N'
+#define WEBSERVICE_FLAG_BADCOMPILE 'C'
+
+/* Replication formula note item names */
+
+#define REPLFORMULA_SERVER_ITEM FIELD_TITLE
+#define REPLFORMULA_VERSION_ITEM "$ReplVersion"
+#define REPLFORMULA_SOURCE_SERVERS "$ReplSrcServers"
+#define REPLFORMULA_NOTECLASS_ITEM "$ReplClassMasks"
+#define REPLFORMULA_FORMULA_ITEM "$ReplFormula"
+#define REPLFORMULA_VIEW_ITEM "$ReplView" /* V4 feature; sel repl by view */
+#define REPLFORMULA_PRIVATE_FOLDER_ITEM "$ReplPrivateFolder" /* V4 feature; sel repl by private folder */
+#define REPLFORMULA_FIELDS_ITEM "$ReplFields" /* V4.5 feature; sel repl by fields */
+#define REPLFORMULA_LOCAL_FOLDER_ITEM "$ReplLocalFolder"
+
+#define REPL_LOCAL_FOLDER_DEFAULT "($KeepLocal)"
+
+#define REPLICATION_FORM "$Replication" /* Name of replication form */
+#define REPLFORMULA_FORM_ITEM "$ReplForm" /* V6 feature; sel repl by form */
+#define REPLFORMULA_FORM_NOTUSED "0"
+#define REPLFORMULA_FORM_USED "1"
+#define REPLFORMULA_FORM_FORMULA_ITEM "$ReplFormFormula"
+
+
+#define FIELD_NAME_DELIMITER ';'
+#define VIEW_NAME_DELIMITER ';'
+#define VIEW_NAME_DELIMETER VIEW_NAME_DELIMITER /* (misspelled!) */
+
+/* Special replication flags */
+
+#define REPLFLAGS_ITEM "$ReplFlags"
+#define REPL_FLAG_NOREPL 'n'
+
+/* Icon note item names */
+
+#define DESK_ICON_ITEM "IconBitmap"
+#define LSECFLAGS_ITEM "$LSECFlags"
+#define DEFAULT_NAVIGATOR_ITEM "$DefaultNavigator"
+#define DEFAULT_WEB_NAVIGATOR_ITEM "$DefaultWebNavigator"
+#define DEFAULT_WEBPAGE_ITEM "$DefaultWebPage"
+#define DEFAULT_OUTLINE_ITEM "$DefaultOutline"
+#define DEFAULT_FRAMESET_ITEM "$DefaultFrameset"
+#define DEFAULT_WEB_FRAMESET_ITEM "$DefaultWebFrameset"
+#define DEFAULT_WEB_PAGE_ITEM "$DefaultWebLaunchPage"
+#define ICON_TEMPLATEMODTIME_ITEM "$TemplateModTime"
+#define ICON_TEMPLATESERVERNAME_ITEM "$TemplateServerName"
+#define ICON_TEMPLATEFILENAME_ITEM "$TemplateFileName"
+#define ICON_UPDATEDBYLIMIT "$UpdatedByLimit"
+#define ICON_REVISIONSLIMIT "$RevisionsLimit"
+#define ICON_SOFTDELETE_EXPIRE_HOURS "$SoftDeleteExpireHours"
+#define LAUNCH_VIEWNAME_ITEM "$LaunchViewName"
+#define LAUNCH_WEB_VIEWNAME_ITEM "$LaunchWebViewName"
+#define LAUNCH_DOCLINK_ITEM "$LaunchDoclink"
+#define LAUNCH_WEB_DOCLINK_ITEM "$LaunchWebDoclink"
+#define LAUNCH_WEB_DOCLINK_ANCHOR_ITEM "$LaunchWebDoclinkAnchor"
+#define DEFAULT_LANGUAGE "$DefaultLanguage"
+#define DEFAULT_COLLATION "$DefaultCollation"
+#define COLLATION_TYPE "$CollationType"
+
+/* Character flags for replicated local security property ($LSECFlags field
+ in the icon note */
+
+#define CHFLAG_SET_LOCALSEC 's' /* should set local access control */
+#define CHFLAG_CLEAR_LOCALSEC 'c' /* should clear local access control */
+#define CHFLAG_COMPACT_LOCALSEC 'p' /* compact should set local access control */
+
+/* character flags for the "replicated file header" ($Flags field in the
+ icon note) */
+
+/* NOTE: These flags are not in alphabetical order. There are more of them than
+ you think. Keep looking until you see a comment saying the set is over. */
+
+/* ----< This is the beginning of the CHFLAGs >---- */
+
+#define ICON_FLAGS DESIGN_FLAGS
+
+/* icon flags */
+#define CHFLAG_LAUNCH_APP 'a'
+#define CHFLAG_MAILBOX_TYPE 'A'
+#define CHFLAG_ADDRESS_BOOK_TYPE 'b'
+#define CHFLAG_LIGHT_ADDRESS_BOOK_TYPE 'B'
+#define CHFLAG_SHOW_CHANGED_POLICY 'c'
+#define CHFLAG_LAUNCH_DOCLINK 'd'
+#define CHFLAG_LAUNCH_FRAMESET 'F'
+#define CHFLAG_RESTRICT_STORED_FORMS 'f'
+#define CHFLAG_LIBRARY_TYPE 'g'
+#define CHFLAG_DEFERRED_LOADED_IMAGES 'i'
+#define CHFLAG_PERSONALJOURNAL_TYPE 'j'
+#define CHFLAG_LAUNCH_NAVIGATOR 'l'
+#define CHFLAG_SEARCH_SCOPE_TYPE 'm'
+#define CHFLAG_NEVER_SHOW_POLICY 'n'
+#define CHFLAG_LAUNCH_OUTLINE 'o' /* Launch Outline as the navigator */
+#define CHFLAG_ALWAYS_SHOW_POLICY 'p'
+#define CHFLAG_MAILFILE_TYPE 'r'
+#define CHFLAG_SOLO_NAVIGATOR 's'
+#define CHFLAG_OBSOLETE_DONTUSE 't'
+#define CHFLAG_SITEDB_TYPE 'u'
+ /* 'refresh' flag from build 130-133 */
+ /* has been superceded by a flag in */
+ /* ICON_FLAGS_NOREFRESH, below. */
+ /* don't use this one anymore... */
+#define CHFLAG_NO_SHOW_VIEW 'v'
+
+#define CHFLAG_LAUNCH_WEBPAGE 'W' /* Launch navigator of type Web Page */
+#define CHFLAG_PANE_BIGFOLDER 'w' /* preview pane orientation; mutually exclusive with below */
+#define CHFLAG_PANE_SMALLVIEW 'x' /* preview pane orientation; mutually exclusive with above*/
+#define CHFLAG_PANE_MAXIMIZED 'y' /* preview pane size */
+
+/* web-specific launch flags */
+#define CHFLAG_WEB_LAUNCH_DOCLINK 'D'
+#define CHFLAG_WEB_LAUNCH_NAVIGATOR 'L'
+#define CHFLAG_WEB_ALWAYS_SHOW_POLICY 'P'
+#define CHFLAG_WEB_LAUNCH_THISDOCLINK 'T'
+#define CHFLAG_WEB_LAUNCH_VIEWNAME 'V'
+#define CHFLAG_WEB_USEJAVASCRIPT 'J'
+#define CHFLAG_WEB_USESSLCONN 'X'
+#define CHFLAG_WEB_LAUNCH_PAGE 'E'
+#define CHFLAG_WEB_LAUNCH_FRAMESET 'S'
+#define CHFLAG_RESTORE_VIEW 'K'
+
+#define CHFLAG_MULTILINGUAL_DB 'M'
+#define CHFLAG_ALLOW_DECS_CONNECTIONS 'C'
+
+#define CHFLAG_NOUNREAD_MARKS 'z'
+#define CHFLAG_DISABLE_RESPONSE_INFO '1'
+#define CHFLAG_FORM_BUCKET_OPT '2'
+#define CHFLAG_MAINTAIN_LAST_ACCESSED '3'
+#define CHFLAG_DELETES_ARE_SOFT '4'
+
+#define CHFLAG_IS_LOCK_DB '5'
+#define CHFLAG_IS_DESIGN_LOCK_DB '6'
+#define CHFLAG_LARGE_UNKTABLE '7'
+#define CHFLAG_HIDE_FROM_WEB '8'
+#define CHFLAG_IS_WEBAPPLICATION '9'
+
+#define CHFLAG_REFRESH_ON_ADMIN 'e'
+
+#define CHFLAG_COPY_PROFILES 'G' /* For templates - copy profile notes on creating database from this one
+ and when refreshing databases from it */
+#define CHFLAG_LZ1 'Z' /* LZ1 compression db option. */
+#define CHFLAG_REPL_UNREAD_CLUSTERED 'Q'
+#define CHFLAG_REPL_UNREAD_EVERYWHERE 'U' /* Icon flag for enabling replication of unread marks - on AND off cluster */
+#define CHFLAG_TRACK_REPLYFORWARD 'h' /* inherited track reply/forward flag */
+
+/* ----< This is the end of the CHFLAGs >---- */
+
+/* unlike the $Flags field, this field doesn't get
+ refreshed/replaced on a design refresh/replace
+ and they don't inherit from parent templates
+*/
+#define ICON_FLAGS_NOREFRESH "$FlagsNoRefresh"
+
+#define CHFLAG_NR_ADV_TEMPLATE 't'
+#define CHFLAG_NR_SINGLE_COPY_TEMPLATE 's'
+
+#define CHFLAG_NR_DONTTRACK_REPLYFORWARD 'r' /* need separate flags here because */
+#define CHFLAG_NR_DOTRACK_REPLYFORWARD 'f' /* we need to know if user turned off OR on to override template setting */
+#define CHFLAG_NR_REPLUNREAD_NEVER 'v'
+#define CHFLAG_NR_REPLUNREAD_CLUSTERED 'Q'
+#define CHFLAG_NR_REPLUNREAD_EVERYWHERE 'U'
+
+/* Special replication flags */
+
+#define REPLFLAGS_ITEM "$ReplFlags"
+#define REPL_FLAG_NOREPL 'n'
+
+/* Auto-merge replication conflicts */
+
+#define ITEM_CONFLICT_ACTION "$ConflictAction" /* enable auto-merge conflicts if 1 */
+#define CONFLICT_AUTOMERGE '1'
+#define CONFLICT_NONE '2'
+#define CONFLICT_BEST_MERGE '3'
+
+#define ITEM_CONFLICT_ITEMS "$ConflictItems"
+
+/* Form note item names */
+
+#define ITEM_NAME_TEMPLATE "$Body" /* form item to hold form CD */
+#define ITEM_NAME_DOCUMENT "$Info" /* document header info */
+#define ITEM_NAME_TEMPLATE_NAME FIELD_TITLE /* form title item */
+#define ITEM_NAME_FORMLINK "$FormLinks" /* form link table */
+#define ITEM_NAME_FIELDS "$Fields" /* field name table */
+#define ITEM_NAME_FORMPRIVS "$FormPrivs" /* form privileges */
+#define ITEM_NAME_FORMUSERS "$FormUsers" /* text list of users allowed to use the form */
+#define ITEM_NAME_FRAMESET "$FrameSet" /* form item to hold form Frameset definition */
+#define ITEM_NAME_FRAMEINFO "$FrameInfo" /* frameset used to open form */
+
+/* Special form flags */
+
+#define ITEM_NAME_KEEP_PRIVATE "$KeepPrivate"
+#define PRIVATE_FLAG_YES '1' /* $KeepPrivate = TRUE force disabling of printing, mail forwarding and edit copy */
+#define PRIVATE_FLAG_YES_RESEND '2' /* $KeepPrivate = TRUE same as PRIVATE_FLAG_YES except allow resend */
+
+#define ITEM_NAME_DATEPICKER_MONTH "$DatePickerMonth"
+#define ITEM_NAME_DATEPICKER_DAY "$DatePickerDay"
+#define ITEM_NAME_DATEPICKER_YEAR "$DatePickerYear"
+#define ITEM_NAME_HEADERAREA "$HeaderArea"
+#define ITEM_NAME_FOOTERAREA "$FooterArea"
+#define ITEM_NAME_REGIONFRAMESET "$RegionFrameset"
+#define ITEM_NAME_BACKGROUNDGRAPHIC "$Background"
+#define ITEM_NAME_BACKGROUNDGRAPHICR5 "$BackgroundR5"
+#define ITEM_NAME_BACKGROUNDGRAPHICBODY "$BackgroundBody"
+#define ITEM_NAME_PAPERCOLOR "$PaperColor"
+#define ITEM_NAME_PAPERCOLOREX "$PaperColorEx"
+#define ITEM_NAME_LAYER "$Layer"
+#define ITEM_NAME_LAYERTEXT "$LayerText"
+#define ITEM_NAME_RESTRICTBKOVERRIDE "$NoBackgroundOverride"
+#define RESTRICTBK_FLAG_NOOVERRIDE '1' /* $NoBackgroundOverride = TRUE Don't allow user to override document background */
+#define ITEM_NAME_HTMLCODE "$HTMLCode"
+#define ITEM_NAME_HTMLCODE_CLIENT "$HTMLCodeClient"
+#define ITEM_NAME_DAVNAME "$DAVName"
+
+#define ITEM_NAME_AUTO_EDIT_NOTE "$AutoEditMode"
+#define AUTO_EDIT_FLAG_YES '1' /* $AutoEditMode = TRUE force edit mode on open regardless of Form flag */
+
+#define ITEM_NAME_SHOW_NAVIGATIONBAR "$ShowNavigationBar" /* Display the URL navigation Bar */
+#define ITEM_NAME_HIDE_SCROLL_BARS "$HideScrollBars"
+#define WINDOW_SCROLL_BARS_NONE '1'
+#define WINDOW_SCROLL_BARS_HORZ '2'
+#define WINDOW_SCROLL_BARS_VERT '3'
+
+#define ITEM_NAME_BACKGROUNDGRAPHIC_REPEAT "$BackgroundRepeat"
+#define ITEM_NAME_BACKGROUNDGRAPHIC_REPEATBODY "$BackgroundRepeatBody"
+#define ITEM_NAME_USER_BACKGROUNDGRAPHIC_REPEAT "$UserBackgroundRepeat"
+#define ITEM_NAME_USER_BACKGROUNDGRAPHIC_REPEATBODY "$UserBackgroundRepeatBody"
+#define BACKGROUNDGRAPHIC_REPEAT_ONCE '1'
+#define BACKGROUNDGRAPHIC_REPEAT_VERT '2'
+#define BACKGROUNDGRAPHIC_REPEAT_HORIZ '3'
+#define BACKGROUNDGRAPHIC_REPEAT_BOTH '4'
+#define BACKGROUNDGRAPHIC_REPEAT_SIZE '5'
+#define BACKGROUNDGRAPHIC_REPEAT_CENTER '6'
+
+#define ITEM_NAME_HIDE_GRAPHIC_IN_EDIT_MODE "$HideGraphicInEditMode"
+
+
+#define ITEM_NAME_RFSAVEINFO "$RFSaveInfo"
+
+
+
+#define ITEM_NAME_VERSION_OPT "$VersionOpt" /* Over-ride the Form flags for versioning. */
+#define VERSION_FLAG_NONE '0' /* $Version = 0, None */
+#define VERSION_FLAG_MURESP '1' /* $Version = 1, Manual - Update becomes response */
+#define VERSION_FLAG_AURESP '2' /* $Version = 2, Auto - Update becomes response */
+#define VERSION_FLAG_MUPAR '3' /* $Version = 3, Manual - Update becomes parent */
+#define VERSION_FLAG_AUPAR '4' /* $Version = 4, Auto - Update becomes parent */
+#define VERSION_FLAG_MUSIB '5' /* $Version = 5, Manual - Update becomes sibling */
+#define VERSION_FLAG_AUSIB '6' /* $Version = 6, Auto - Update becomes sibling */
+
+
+/* Document note item names */
+
+#define ITEM_NAME_TEMPLATE_USED FIELD_FORM /* form name used to create note, user-visible */
+#define ITEM_NAME_NOTEREF FIELD_LINK /* optional reference to another note */
+#define ITEM_NAME_VERREF "$VERREF" /* optional reference to master version note */
+#define ITEM_NAME_LINK "$Links" /* note link table */
+#define ITEM_NAME_REVISIONS "$Revisions" /* Revision history */
+#define ITEM_NAME_CONFLICT VIEW_CONFLICT_ITEM /* Replication update conflict */
+#define ITEM_NAME_AUTHORS "$Authors" /* text list of users allowed to modify document below editor access */
+#define ITEM_NAME_WRITERS "$Writers" /* text list of users allowed to modify document */
+#define ITEM_NAME_PROVISIONAL_WRITERS "$PWriters" /* text list of users provisionally allowed to modify document */
+#define ITEM_NAME_TEMP_PROVISIONAL_WRITERS "$PTWriters" /* text list of users provisionally allowed to temporarily modify document */
+#define ITEM_NAME_WRITERSDATE "$WritersDate" /* timedate of when any form of $[X]Writers was taken out */
+
+/* Document and form note item names, all items are optional */
+
+#define ITEM_NAME_FONTS "$Fonts" /* font table */
+#define ITEM_NAME_HEADER "$Header" /* print page header */
+#define ITEM_NAME_FOOTER "$Footer" /* print page footer */
+#define ITEM_NAME_HFFLAGS "$HFFlags" /* header/footer flags */
+ #define HFFLAGS_NOPRINTONFIRSTPAGE '1' /* suppress printing header/footer on first page */
+ #define HFFLAGS_DIRECTION_RTL 'R' /* header/footer is RTL */
+#define ITEM_NAME_WINDOWTITLE "$WindowTitle"/* window title */
+#define ITEM_NAME_ATTACHMENT "$FILE" /* file attachment, MUST STAY UPPER-CASE BECAUSE IT'S SIGNED! */
+#define ITEM_NAME_HTMLHEADTAG "$HTMLHeadTag"/* Override for HTML head tag */
+#define ITEM_NAME_HTMLBODYTAG "$HTMLBodyTag"/* Override for HTML body tag */
+#define ITEM_NAME_WEBQUERYSAVE "$WEBQuerySave" /*WebQuerySave formula */
+#define ITEM_NAME_WEBQUERYOPEN "$WEBQueryOpen" /*WebQueryOpen formula */
+#define ITEM_NAME_APPHELPFORMULA "$AppHelpFormula" /* Help doc to load */
+#define ITEM_NAME_STYLESHEETLIST "$StyleSheetList"/* Style Sheet List */
+#define ITEM_NAME_DEFAULTDECSINFO "$DefaultDECSInfo" /* default DECS info for all form fields */
+#define ITEM_NAME_EXTERNAL_FIELDS "$ExternalFields" /* # of DECS fields in form */
+#define ITEM_NAME_CLIENTEVENTINFO "$ClientEventTag"
+#define ITEM_NAME_WEBEVENTINFO "$WebEventTag"
+
+#define ITEM_NAME_WEBFLAGS "$WebFlags" /* Web related flags for form or document */
+#define WEBFLAG_NOTE_USEAPPLET_INBROWSER 'B' /* use appropriate applet when serving to browser */
+#define WEBFLAG_NOTE_IS_HTML 'H' /* treat this document or form as plain HTML, do not convert styled text to HTML */
+#define WEBFLAG_NOTE_CONTAINS_VIEW 'V' /* optimization for web server: this note contains an embedded view */
+#define WEBFLAG_NOTE_HTML_ALL_FLDS 'F' /* gen'd HTML for all fields */
+#define WEBFLAG_NOTE_CONTAINS_JSBUTTON 'J' /* Generate <FORM> tag */
+#define WEBFLAG_NOTE_ALLOW_DOC_SELECTIONS 'S'
+
+/* THESE NEXT TWO FLAGS ARE OBSOLETE - SHOULD BE REMOVED ASAP */
+#define WEBFLAG_NOTE_FILE_DEPLOYABLE 'D' /* for web apps, this file is ready for primetime */
+#define WEBFLAG_NOTE_DONTREFRESH_ON_REDEPLOY 'R' /* for web apps, this file should not be replaced on redeploy */
+#define ITEM_NAME_WEBPUBLISHING "$WebPublishing"
+#define ITEM_NAME_TEXTPROPERTIES "$TextProperties" /* Text Properties table */
+#define ITEM_NAME_DAVPROPERTIES "$DavProps" /* WebDAV dead properties */
+#define ITEM_NAME_DAVNAMESPACES "$DavNamespaces" /* WebDAV namespaces for dead properties */
+
+
+
+/* Document note Sign/Seal item names */
+
+#define ITEM_NAME_NOTE_SIGNATURE "$Signature"
+#define ITEM_NAME_NOTE_SIG_PREFIX "$Sig_" /* Prefix for multiple signatures. */
+#define ITEM_NAME_NOTE_STOREDFORM_SIG "$SIG$Form" /* stored form signature */
+#define ITEM_NAME_NOTE_STOREDSUBFORM_SIG_PREFIX "$SIG$" /* stored subform signature prefix - followed by subform name*/
+#define ITEM_NAME_NOTE_STOREDFORM_SIG_PREFIX "$SIG" /* stored form and subform signature prefix - followed by either $FORM or the subform name*/
+#define ITEM_NAME_NOTE_SEAL "$Seal"
+#define ITEM_NAME_NOTE_SEALDATA "$SealData"
+#define ITEM_NAME_NOTE_SEALNAMES "SecretEncryptionKeys"
+#define ITEM_NAME_NOTE_SEALUSERS "PublicEncryptionKeys"
+#define ITEM_NAME_NOTE_FORCESIGN "Sign"
+#define ITEM_NAME_NOTE_FORCESEAL "Encrypt"
+#define ITEM_NAME_NOTE_FORCEMAIL "MailOptions"
+#define ITEM_NAME_NOTE_FORCESAVE "SaveOptions"
+#define ITEM_NAME_NOTE_FORCESEALSAVED "EncryptSaved"
+#define ITEM_NAME_NOTE_MAILSAVE "MailSaveOptions"
+#define ITEM_NAME_NOTE_FOLDERADD "FolderOptions"
+/* also see EncryptionStatus and SignatureStatus below */
+
+/* Item name suffixes for design note items that are add to data note when "store form with document" is used. */
+
+#define STOREDFORM_ITEM_SUFFIX "_StoredForm"
+#define STOREDSUBFORM_ITEM_SUFFIX "_StoredSubform" /* A number 1 - Number of subforms will also be append... _StoredSubform1 */
+#define ITEM_NAME_STOREDFORM_CRC "$StoredFormCRC" /* A CRC on the first $Body item of a stored form in doc document. Used to detect down stream client changes. */
+
+#define ITEM_NAME_STOREDFORM_REPID "$Form_RepId_SF" /* Replica id of a form's originating database. */
+
+/*
+ * This item name (which is '$Body_StoredForm') is the "new" way of storing a form with a document. This item
+ * and all items with the _StoredForm and/or _StoredSubformX suffix supercede the the original item names
+ * in documents that have stored forms unless a downstream client... pre 5.0.6... makes a change as detected
+ * with $StoredFormCRC as mentioned above.
+ */
+#define ITEM_NAME_TEMPLATE_STOREDFORM ITEM_NAME_TEMPLATE STOREDFORM_ITEM_SUFFIX
+
+/* Group expansion item and legal values */
+
+#define ITEM_NAME_NOTE_GROUPEXP "ExpandPersonalGroups" /* For backward compatibility */
+#define ITEM_NAME_NOTE_EXPANDGROUPS "$ExpandGroups"
+#define MAIL_DONT_EXPAND_GROUPS '0'
+#define MAIL_EXPAND_LOCAL_GROUPS '1'
+#define MAIL_EXPAND_PUBLIC_GROUPS '2'
+#define MAIL_EXPAND_LOCAL_AND_PUBLIC_GROUPS '3'
+
+/* Search term highlights item name prefix. An item name is
+ concatenated to this; e.g. $Highlights_Body. */
+
+#define ITEM_NAME_HIGHLIGHTS "$Highlights_"
+
+/* Import/Export document item names */
+
+#define IMPORT_BODY_ITEM_NAME "Body"
+#define IMPORT_FORM_ITEM_NAME FIELD_FORM
+#define NEW_FORM_ITEM_NAME FIELD_FORM
+
+/* Help index note item names */
+
+#define ITEM_OBJECT "$Section"
+#define HELP_VIEW_NAME "(All)"
+#define APP_HELP_DEFAULT_VIEW_NAME "(Help)"
+
+/* Help view names */
+
+#define HELP_VIEW_TOC "Top10" /* Table of contents view */
+#define HELP_VIEW_MSG "MSG" /* Messages view */
+#define HELP_VIEW_ATFUNC "REF" /* @Functions view */
+#define HELP_VIEW_INDEX "IDX" /* Index view */
+#define HELP_VIEW_NEWS "NEWS" /* Release Notes view */
+#define HELP_VIEW_V3CMD "CLASSIC" /* V3 Menu Command Equivalents */
+
+/* Help navigator names */
+
+#define HELP_NAV_HOW "Help Topics - How"
+#define HELP_NAV_INDEX "Help Topics - Index"
+#define HELP_NAV_MSG "Help Topics - Trouble"
+#define HELP_NAV_ATFUNC "Help Topics - Tell Me"
+#define HELP_NAV_KBD "Help Topics - Tell Me"
+
+/* Notes Help Template String */
+#define HELP_TEMPLATE_STRING "NotesHelp"
+
+/* Catalog form names */
+
+#define NOTEFILE_FORM_NAME "Notefile"
+#define CONNECTION_FORM_NAME "Connection"
+
+/* Catalog view names */
+#define CATALOG_VIEW_REPLICA_ID "Databases by _Replica ID"
+#define CATALOG_VIEW_CATEGORY "Databases by _Category"
+#define CATALOG_VIEW_MULTIDBBIT "($MultiDbIndex)"
+
+/* Catalog document note item names */
+
+#define CATALOG_ITEM_SERVER "Server"
+#define CATALOG_ITEM_REMOTE_SERVER "RemoteServer"
+#define CATALOG_ITEM_PATHNAME "Pathname"
+#define CATALOG_ITEM_TITLE "Title"
+#define CATALOG_ITEM_REPLICAID "ReplicaID"
+#define CATALOG_ITEM_POLICY_DATE "PolicyDate"
+#define CATALOG_ITEM_LICENSEID "LicenseID"
+#define CATALOG_ITEM_MANAGERS "Managers"
+#define CATALOG_ITEM_BODY "Body"
+#define CATALOG_ITEM_VIEW_INDEX "View"
+#define CATALOG_ITEM_CATEGORY1 "Category1"
+#define CATALOG_ITEM_CATEGORY2 "Category2"
+#define CATALOG_ITEM_CATEGORY3 "Category3"
+#define CATALOG_ITEM_CATEGORY4 "Category4"
+#define CATALOG_ITEM_CATEGORY5 "Category5"
+#define CATALOG_ITEM_CAT MAIL_CATEGORIES_ITEM
+#define CATALOG_ITEM_FULLNAME "FullName"
+#define CATALOG_ITEM_META_TITLE "Title"
+#define CATALOG_ITEM_META_CREATOR "Creator"
+#define CATALOG_ITEM_META_DESCRIPTION "Description"
+#define CATALOG_ITEM_META_TYPE "MetaType"
+#define CATALOG_ITEM_META_IDENTIFIER "URL"
+#define CATALOG_ITEM_META_CREATION_DATE "CreationDate"
+#define CATALOG_ITEM_META_CATEGORIES "Categories"
+#define CATALOG_ITEM_ADMIN_SERVER "DbAdminServer"
+#define CATALOG_ITEM_ADMIN_SERVER_NAMES "DbAdminServerNames"
+/* for agents */
+#define CATALOG_ITEM_AGENT_AGENTNAME "AgentName"
+#define CATALOG_ITEM_AGENT_DB "AgentDb"
+#define CATALOG_ITEM_AGENT_SIGNER "AgentSigner"
+#define CATALOG_ITEM_AGENT_ONBEHALF "AgentOnBehalf"
+#define CATALOG_ITEM_AGENT_INTERVALTYPE "AgentIntervalType"
+#define CATALOG_ITEM_AGENT_INTERVAL "AgentInterval"
+#define CATALOG_ITEM_AGENT_TIME1 "AgentTimeOne"
+#define CATALOG_ITEM_AGENT_TIME2 "AgentTimeTwo"
+#define CATALOG_ITEM_AGENT_STARTTIME "AgentStartTime"
+#define CATALOG_ITEM_AGENT_ENDTIME "AgentEndTime"
+#define CATALOG_ITEM_AGENT_NOWEEKEND "AgentNoWeekend"
+#define CATALOG_ITEM_AGENT_PERSONAL "AgentPersonal"
+#define CATALOG_ITEM_AGENT_COUNT "AgentCount"
+#define CATALOG_ITEM_AGENT_FIELDCOUNT "AgentFieldCount"
+#define CATALOG_ITEM_AGENT_TRIGGERTYPE "AgentTriggerType"
+#define CATALOG_ITEM_AGENT_SEARCHTYPE "AgentSearchType"
+#define CATALOG_ITEM_AGENT_SERVER "AgentServer"
+#define CATALOG_ITEM_AGENT_LASTRUN "AgentLastRunTime"
+#define CATALOG_ITEM_AGENT_DOCPROCESSED "AgentDocsProcessed"
+#define CATALOG_ITEM_AGENT_ENABLED "AgentEnabled"
+#define CATALOG_ITEM_AGENT_ACTIVATABLE "AgentActivatable"
+#define CATALOG_ITEM_AGENT_RUNASWEB "AgentRunAsWebUser"
+#define CATALOG_ITEM_AGENT_RESTRICTED "AgentRestricted"
+#define CATALOG_ITEM_AGENT_LANGUAGE "AgentLanguage"
+
+
+
+/* Multi DB searching document forms, item names, and item values */
+
+#define MULTIDB_FORM_CONFIG "ConfigurationForm"
+#define MULTIDB_FORM_ENTRY "Database"
+#define MULTIDB_ITEM_ACL "ACL"
+#define MULTIDB_ITEM_CATEGORIES "DatabaseCategories"
+#define MULTIDB_ITEM_CONFIGLINK "ConfigLink"
+#define MULTIDB_ITEM_DOMAIN "Domain"
+#define MULTIDB_ITEM_INDEXOPTIONS "IndexOptions"
+#define MULTIDB_ITEM_PATHNAME "Pathname"
+#define MULTIDB_ITEM_REPLICAID "ReplicaID"
+#define MULTIDB_ITEM_SCOPE "Scope"
+#define MULTIDB_ITEM_SERVER "Server"
+#define MULTIDB_ITEM_TITLE "Title"
+#define MULTIDB_ITEM_VIEWCHOICE "DbViews"
+#define MULTIDB_ITEM_VIEWLIST "DatabaseViews"
+#define MULTIDB_INDEX_NONE "0"
+#define MULTIDB_INDEX_SUMMARY "1"
+#define MULTIDB_INDEX_FULLNOTE "2"
+#define MULTIDB_INDEX_ATTACHMENT "3"
+#define MULTIDB_SCOPE_DATABASE "0"
+#define MULTIDB_SCOPE_DIRECTORY "1"
+#define MULTIDB_SCOPE_SERVER "2"
+#define MULTIDB_SCOPE_DOMAIN "3"
+#define MULTIDB_VIEW_REPLICAID "$ReplicaID"
+
+/* Library document note item names */
+
+#define LIBRARY_ITEM_AUTHOR "Author"
+#define LIBRARY_ITEM_SERVER "Server"
+#define LIBRARY_ITEM_PATHNAME "Pathname"
+#define LIBRARY_ITEM_TITLE "Title"
+#define LIBRARY_ITEM_REPLICAID "ReplicaID"
+#define LIBRARY_ITEM_ABSTRACT "Abstract"
+#define LIBRARY_PATHNAME "LibraryPathName"
+#define LIBRARY_TITLE "LibraryTitle"
+#define LIBRARY_SENDTO "SendTo"
+#define LIBRARY_LIBRARIAN "Librarian"
+
+/* Library Form Names */
+#define LIBRARIAN_FORM_NAME "Librarian"
+
+/* Library View Names */
+#define LIBRARY_REPID_VIEW "($RepID)"
+#define LIBRARY_LIBRARIAN_VIEW "($Librarians)"
+
+/* Disk directory search item names and values */
+
+#define DBDIR_PATH_ITEM "$Path" /* Path name */
+#define DBDIR_TYPE_ITEM "$Type" /* Type item */
+#define DBDIR_TYPE_ITEM_DIRECTORY "$DIR" /* Directory type name */
+#define DBDIR_TYPE_ITEM_NOTEFILE "$NOTEFILE" /* Notefile type name */
+#define DBDIR_TYPE_ITEM_OLDNOTEFILE "$OLDNOTEFILE"
+#define DBDIR_INFO_ITEM "$Info" /* Info item */
+#define DBDIR_LENGTH_ITEM "$Length"
+#define DBDIR_MODIFIED_ITEM "$Modified"
+#define DBDIR_PROPERTIES_ITEM "$Properties"
+#define DBDIR_LINK_ITEM "$LinkInfo"
+#define DBDIR_DIRECTORY_LINK "$DIRLINK" /* Directory Link */
+#define DBDIR_DATABASE_LINK "$DBLINK" /* Database Link */
+#define DBDIR_DBOPTIONS_ITEM "$DBOPTIONS" /* Database Options */
+#define DBDIR_DBVERSIONS_ITEM "$DBVERSIONS" /* Database Major and Minor versions */
+#define DBDIR_DBCREATED_ITEM "$DBCREATED" /* Database Created date */
+#define DBDIR_LASTFIXUP_ITEM "$LASTFIXUP" /* Last database fixup time */
+#define DBDIR_QUOTALIMIT_ITEM "$QUOTALIMIT" /* Database quota limit */
+#define DBDIR_QUOTAWARNING_ITEM "$QUOTAWARNING" /* Database quota warning */
+#define DBDIR_MAXDBSIZE_ITEM "$MAXDBSIZE" /* Database MAximum Size - 1Gb, 2GB, 3GB, 4GB */
+#define DBDIR_PHYSICALPATH_ITEM "$PHYSICALPATH" /* Physical file path (OS level path) */
+#define DBDIR_ISLOGGED_ITEM "$ISLOGGED" /* Is the db logged? */
+#define DBDIR_LENGTH2_ITEM "$Length2" /* File Size as NSFDISKPOS */
+#define DBDIR_DBOPTIONS2_ITEM "$DBOPTIONS2" /* Database Options[1] */
+#define DBDIR_DBOPTIONS3_ITEM "$DBOPTIONS3" /* Database Options[2] */
+#define DBDIR_DBOPTIONS4_ITEM "$DBOPTIONS4" /* Database Options[3] */
+#define DBDIR_DATAMODIFIED_ITEM "$DATAMOD" /* Data Modified time */
+#define DBDIR_NONDATAMODIFIED_ITEM "$NONDATAMOD" /* Non Data Modified time */
+#define DBDIR_CURRENTUSAGE_ITEM "$CURRENTUSAGE" /* CurrentSpace Utilization */
+#define DBDIR_STORAGEPATH_ITEM "$STORAGEPATH" /* Raw file path (all links translated) */
+#define DBDIR_REPLFLAGS_ITEM "$ReplFlags" /* Replica Flags */
+#define DBDIR_DB2_DATABASE_LINK "$DB2LINK" /* DB2 Database Link */
+
+/* Form names for log database. */
+
+#define LOG_EVENT_FORM "Events"
+#define LOG_REPLICA_FORM "Replication"
+#define LOG_MAIL_FORM "Mail Routing"
+#define LOG_SESSION_FORM "Session"
+#define LOG_USAGE_FORM "Activity"
+#define LOG_SIZE_FORM "Size"
+#define LOG_PHONE_FORM "Phone Call"
+#define LOG_PHONE_IN_FORM "Phone Call - Incoming"
+#define LOG_PHONE_OUT_FORM "Phone Call - Outgoing"
+#define LOG_PT_FORM "Passthru Connection"
+#define LOG_OBJSTORE_USAGE_FORM "ObjStoreUsageForm"
+/* This is the form name used by the log package "activity logging API" */
+#define LOG_ACTIVITY_FORM "ActivityData"
+
+/* View names for log database. */
+
+#define LOG_OBJSTORE_USAGE_VIEW "ObjStoreUsageView"
+#define LOG_MAIL_ROUTING_EVENTS_VIEW "MailRoutingEvents"
+#define LOG_ACTIVITY_DATA_VIEW "($ActivityData)"
+#define LOG_ACTIVITY_SCHEMA_VIEW "($ActivitySchema)"
+
+/* Item names used by the log facility itself or commonly used
+ by different packages that call the log facility. */
+
+#define LOG_ITEM_STARTTIME "StartTime"
+#define LOG_ITEM_STARTTIME_TEXT "StartTimeText"
+#define LOG_ITEM_ENDTIME "FinishTime"
+#define LOG_ITEM_BODY "Body"
+#define LOG_ITEM_SERVER "Server"
+#define LOG_ITEM_PORT "Port"
+#define LOG_ITEM_EVENTS "Events"
+#define LOG_ITEM_EVENT_LIST "EventList"
+#define LOG_ITEM_EVENT_STATUS "EventStatus"
+#define LOG_ITEM_EVENT_TYPE "EventType"
+#define LOG_ITEM_EVENT_SEV "EventSeverity"
+#define LOG_ITEM_EVENT_TIME "EventTime"
+#define LOG_ITEM_EVENT_TIME_SIZE "EventTimeSize"
+#define LOG_ITEM_EVENT_ADDERR "EventAdditionalErrorCode"
+#define LOG_ITEM_EVENT_ADDERR_TYPE "EventAdditionalErrorType"
+#define LOG_ITEM_EVENT_ADDERR_SEV "EventAdditionalErrorSeverity"
+#define LOG_ITEM_EVENT_ADDIN "EventAddinName"
+#define LOG_ITEM_EVENT_PARAMETERS "EventParameters"
+#define LOG_ITEM_PATHNAME "Pathname"
+#define LOG_ITEM_TITLE "Title"
+#define LOG_ITEM_CAT MAIL_CATEGORIES_ITEM
+#define LOG_ITEM_BYTESIN "BytesIn"
+#define LOG_ITEM_BYTESOUT "BytesOut"
+
+/* Item names for replicator notes in log file. */
+
+#define REPLICA_ITEM_SOURCE_SERVER "SourceServer"
+#define REPLICA_ITEM_INITIATED_BY "InitiatedBy"
+
+/* Item names for session notes in log file. */
+
+#define SESSION_ITEM_USERNAME "UserName"
+#define SESSION_ITEM_READS "Reads"
+#define SESSION_ITEM_WRITES "Writes"
+#define SESSION_ITEM_SENT_FROM "SentFromServer"
+#define SESSION_ITEM_SENT_TO "SentToServer"
+#define SESSION_ITEM_UNCOMPSENT_FROM "SentFromServerUncompressed"
+#define SESSION_ITEM_UNCOMP_SENT_TO "SentToServerUncompressed"
+#define SESSION_ITEM_COMPSENT_FROM "SentFromServerCompressed"
+#define SESSION_ITEM_COMP_SENT_TO "SentToServerCompressed"
+
+#define SESSION_ITEM_TRANSACTIONS "Transactions"
+
+/* Item names for escrow log */
+
+#define ESCROW_SENDTO "Escrow Agent"
+
+#define ESCROW_USER "User"
+#define ESCROW_SERVER "Server"
+#define ESCROW_CERTIFIER "Certifier"
+
+#define ESCROW_LOCATION_ITEM "Location"
+#define ESCROW_COMMENT_ITEM "Comment"
+
+/* Item names for database activity note in log file */
+
+#define ACTIVITY_ITEM_MANAGERS "Managers"
+#define ACTIVITY_ITEM_VIEWTITLES "ViewTitles" /* Obsolete in R6 */
+#define ACTIVITY_ITEM_VIEWSIZES "ViewSizes" /* Obsolete in R6 */
+#define ACTIVITY_ITEM_ALLVIEWINFO "AllViewInfo" /* New in R6 */
+#define ACTIVITY_ITEM_DISKSPACE "DiskSpace"
+#define ACTIVITY_ITEM_DISKUSAGE "DiskUsage"
+#define ACTIVITY_ITEM_PERIOD "Period"
+#define ACTIVITY_ITEM_PERIOD_USES "PeriodUses"
+#define ACTIVITY_ITEM_PERIOD_READS "PeriodReads"
+#define ACTIVITY_ITEM_PERIOD_WRITES "PeriodWrites"
+#define ACTIVITY_ITEM_DAY_USES "DayUses"
+#define ACTIVITY_ITEM_DAY_READS "DayReads"
+#define ACTIVITY_ITEM_DAY_WRITES "DayWrites"
+#define ACTIVITY_ITEM_WEEK_USES "WeekUses"
+#define ACTIVITY_ITEM_WEEK_READS "WeekReads"
+#define ACTIVITY_ITEM_WEEK_WRITES "WeekWrites"
+#define ACTIVITY_ITEM_MONTH_USES "MonthUses"
+#define ACTIVITY_ITEM_MONTH_READS "MonthReads"
+#define ACTIVITY_ITEM_MONTH_WRITES "MonthWrites"
+
+/* Items associated with server activity in the log */
+
+#define SRVACT_ITEM_ACTIVITY_NAME "ActivityName"
+#define SRVACT_ITEM_ACTIVITY_FIELDS "ActivityFields"
+#define SRVACT_ITEM_ACTIVITY_TYPES "ActivityTypes"
+#define SRVACT_ITEM_ACTIVITY_SCHEMA "ActivitySchema"
+
+
+/* Item names for unet notes in log file. */
+#define UNIXNET_ITEM_BODY "UnixBody"
+
+#if 0
+
+/* Address Book - "X400Server" form item names */
+
+#define MAIL_X400_SERVER_FORM "Server" /* Form and type name */
+#define MAIL_X400_SERVERNAME_ITEM "ServerName" /* X400 MTA name */
+#define MAIL_X400_GLOBAL_DOMAIN_ITEM "GlobalDomain" /* Global domain identifier */
+#define MAIL_X400_COUNTRY_ITEM "Country" /* Country name */
+#define MAIL_X400_ADMD_ITEM "ADMD" /* Administration Management Domain name*/
+#define MAIL_X400_PRMD_ITEM "Domain" /* Private Domain name */
+#define MAIL_X400_CREDENTIALS_ITEM "Credentials" /* MTA credentials */
+#define MAIL_X400_SUPP_APP_CONTEXTS_ITEM "SupportedApplicationsContext" /* Supported app. contexts */
+#define MAIL_X400_DEL_CONTENT_LENGTH_ITEM "DeliveryContentLength" /* Delivery content length */
+#define MAIL_X400_DEL_CONTENT_TYPE_ITEM "DeliveryContentTypes" /* Delivery content types */
+#define MAIL_X400_PSEL_ITEM "PSEL" /* Presentation selector */
+#define MAIL_X400_SSEL_ITEM "SSEL" /* Session selector */
+#define MAIL_X400_TSEL_ITEM "TSEL" /* Transport selector */
+#define MAIL_X400_NADDRESSES_ITEM "NAddresses" /* Network addresses */
+
+#endif
+
+
+
+/* Public Queue Names */
+
+#define TASK_QUEUE_PREFIX "MQ$" /* Prepended to "addin" task */
+ /* name to form task's queue name */
+
+#define SERVER_QUEUE_NAME "_SERVER" /* DB Server */
+#define REPL_QUEUE_NAME TASK_QUEUE_PREFIX"REPLICATOR" /* Replicator */
+#define ROUTER_QUEUE_NAME TASK_QUEUE_PREFIX"ROUTER" /* Mail Router */
+#define UPDATE_QUEUE_NAME TASK_QUEUE_PREFIX"INDEXER" /* Index views & full text process */
+#define LOGIN_QUEUE_NAME TASK_QUEUE_PREFIX"LOGIN" /* Login Process */
+#define EVENT_QUEUE_NAME TASK_QUEUE_PREFIX"EVENT" /* Event process */
+#define REPORT_QUEUE_NAME TASK_QUEUE_PREFIX"REPORTER" /* Report process */
+#define CLREPL_QUEUE_NAME TASK_QUEUE_PREFIX"CLREPL" /* Cluster Replicator */
+#define FIXUP_QUEUE_NAME TASK_QUEUE_PREFIX"FIXUP" /* Fixup */
+#define COLLECT_QUEUE_NAME TASK_QUEUE_PREFIX"COLLECTOR" /* Collector*/
+#define NOI_QUEUE_NAME TASK_QUEUE_PREFIX"DIIOP" /* NOI Process */
+#define ALARM_QUEUE_NAME TASK_QUEUE_PREFIX"ALARMS" /* Alarms Cache daemon */
+#define MONITOR_QUEUE_NAME TASK_QUEUE_PREFIX"MONITOR" /* Monitor */
+#define MONALARM_QUEUE_NAME TASK_QUEUE_PREFIX"MONITORALARM" /* Monitor */
+#define APDAEMON_REQ_QUEUE TASK_QUEUE_PREFIX"APDAEMONREQ" /* Admin Panel Daemon (Request Queue) */
+#define APDAEMON_FILERES_QUEUE TASK_QUEUE_PREFIX"APDAEMONFILERESPONSE" /* Admin Panel Daemon (File Response Queue) */
+#define APDAEMON_FILEREQ_QUEUE TASK_QUEUE_PREFIX"APDAEMONFILEREQUEST" /* Admin Panel Daemon (Server Response Queue) */
+#define BKTASKS_QUEUE_NAME TASK_QUEUE_PREFIX"BKTASKS" /* bktasks */
+#define RZINTER_QUEUE_NAME TASK_QUEUE_PREFIX"RZINTER" /* Red Zone Interface to Collector */
+#define RZEXTRA_QUEUE_NAME TASK_QUEUE_PREFIX"RZEXTRA" /* Red Zone Extra MQ */
+#define RZBG_QUEUE_NAME TASK_QUEUE_PREFIX"RZBG" /* Red Zone Background MQ */
+#define RZBGEXTRA_QUEUE_NAME TASK_QUEUE_PREFIX"RZBGEXTRA" /* Red Zone Background Extra MQ */
+#define REALTIME_STATS_QUEUE_NAME TASK_QUEUE_PREFIX"REALTIME" /* Monitor */
+#define RUNJAVA_QUEUE_NAME TASK_QUEUE_PREFIX"RUNJAVA" /* Runjava (used by ISpy) */
+#define STATS_QUEUE_NAME TASK_QUEUE_PREFIX"STATS" /* Runjava (used by ISpy) */
+#define LOG_SEARCH_QUEUE_NAME TASK_QUEUE_PREFIX"LOGSEARCH" /* Runjava (used by ISpy) */
+#define DAEMON_EVENT_QUEUE_NAME TASK_QUEUE_PREFIX"DAEMONEVENT" /* Event process */
+#define DAEMON_COLLECT_QUEUE_NAME TASK_QUEUE_PREFIX"DAEMONCOLLECTOR" /* Collector*/
+#define DIRCAT_QUEUE_NAME TASK_QUEUE_PREFIX"DIRCAT" /* Dircat */
+#define RMEVAL_QUEUE_NAME TASK_QUEUE_PREFIX"RMEVAL" /* RMEval */
+#define SCRREPL_QUEUE_NAME TASK_QUEUE_PREFIX"SCR" /* Streaming Cluster Replicator */
+
+
+
+/* Names for server access lists and other stuff from NOTES.INI */
+
+#define SERVER_TITLE_NAME "SERVER_TITLE"
+#define ALLOW_ACCESS_NAME "ALLOW_ACCESS"
+#define DENY_ACCESS_NAME "DENY_ACCESS"
+#define CREATE_FILE_ACCESS_NAME "CREATE_FILE_ACCESS"
+#define CREATE_REPLICA_ACCESS_NAME "CREATE_REPLICA_ACCESS"
+#define ADMIN_ACCESS_NAME "ADMIN_ACCESS"
+#define ALLOW_PASSTHRU_TARGET_NAME "ALLOW_PASSTHRU_TARGETS"
+#define ALLOW_PASSTHRU_CLIENT_NAME "ALLOW_PASSTHRU_CLIENTS"
+#define ALLOW_PASSTHRU_CALLER_NAME "ALLOW_PASSTHRU_CALLERS"
+#define ALLOW_PASSTHRU_ACCESS_NAME "ALLOW_PASSTHRU_ACCESS"
+#define ALLOW_RESTRICTED_LOTUSCRIPT_NAME "ALLOW_RESTRICTED_LOTUSSCRIPT"
+#define ALLOW_UNRESTRICTED_LOTUSCRIPT_NAME "ALLOW_UNRESTRICTED_LOTUSSCRIPT"
+#define ALLOW_MONITORS_NAME "ALLOW_MONITORS"
+#define DENY_MONITORS_NAME "DENY_MONITORS"
+
+/* Field Names for server access lists and other stuff from NAMES.NSF */
+
+#define ALLOW_ACCESS_ITEM "AllowAccess"
+#define DENY_ACCESS_ITEM "DenyAccess"
+#define CREATE_FILE_ACCESS_ITEM "CreateAccess"
+#define CREATE_REPLICA_ACCESS_ITEM "ReplicaAccess"
+#define CREATE_TEMPLATE_ACCESS_ITEM "TemplateAccess"
+#define ADMIN_ACCESS_ITEM "Administrator"
+#define ALLOW_PASSTHRU_TARGET_ITEM "PTTargets"
+#define ALLOW_PASSTHRU_CLIENT_ITEM "PTClients"
+#define ALLOW_PASSTHRU_CALLER_ITEM "PTCallers"
+#define ALLOW_PASSTHRU_ACCESS_ITEM "PTAccess"
+#define ALLOW_RESTRICTED_LOTUSCRIPT_ITEM "RestrictedList"
+#define ALLOW_UNRESTRICTED_LOTUSCRIPT_ITEM "UnrestrictedList"
+#define ALLOW_ON_BEHALF_ITEM "OnBehalfOfLst"
+#define ALLOW_ON_BEHALF_INVOKER_ITEM "OnBehalfOfInvokerLst"
+#define ALLOW_PERSONAL_ITEM "PrivateList"
+#define ALLOW_LIBRARIES_ITEM "LibsLst"
+#define ALLOW_REMOTE_HNAMES_ITEM "TrustedSrvrs"
+#define ALLOW_MONITORS_ITEM "AllowMonitors"
+#define DENY_MONITORS_ITEM "DenyMonitors"
+#define FULL_ADMIN_ACCESS_ITEM "FullAdmin"
+#define DB_ADMIN_ACCESS_ITEM "DBAdmin"
+#define REMOTE_ADMIN_ACCESS_ITEM "RemoteAdmin"
+#define VO_ADMIN_ACCESS_ITEM "VOAdmin"
+#define WEB_ADMIN_ACCESS_ITEM "BrowserAdminAccess"
+#define NNTP_ADMIN_ACCESS_ITEM "NNTP_Admin"
+#define SYS_ADMIN_ACCESS_ITEM "SysAdmin"
+#define SYS_ADMIN_RES_ACCESS_ITEM "ResSysAdmin"
+#define SYS_ADMIN_RES_COMMANDS_ITEM "ResSystemCmds"
+
+/* Names for folder pane. */
+
+#define CATEGORIES_AS_FOLDERS "CategoriesAsFolders"
+
+/* Location information */
+
+#define LOCATION_DEFAULT "Location"
+#define LOCATION_TYPE "LocationType"
+#define LOCATION_TRAVELPROMPT "TravelPrompt"
+#define LOCATION_FORMTYPE "Location"
+#define LOCATION_REPLICATIONFORM "$ReplicationSubform"
+#define LOCATION_VIEW "($Locations)"
+#define LOCATION_NAME "Name"
+#define LOCATION_SOURCE "Source"
+#define LOCATION_USERID "UserID"
+#define LOCATION_TIMEZONE "TimeZone"
+#define LOCATION_R5TIMEZONE "R5TimeZone"
+#define LOCATION_USEOSTZ "UseOSTZ"
+#define LOCATION_DST "DST"
+#define LOCATION_DOMAIN "Domain"
+#define LOCATION_MAILSERVER "MailServer"
+#define LOCATION_DIRSERVER "DirectoryServer"
+#define LOCATION_MAILFILE "MailFile"
+#define LOCATION_MAILFILE_LASTSEQ "$MailFileSeq"
+#define LOCATION_DEFPASSTHRU "DefaultPassthruServer"
+#define LOCATION_OUTSIDELINE "OutsideLine"
+#define LOCATION_CARDPREFIX "CallPre" /* Number to dial to get carriers dial tone (10ATT or 1800...) */
+#define LOCATION_CARDSUFFIX "Suffix" /* Number to identify user;s account (i.e. User's Home Phone + PIN) */
+#define LOCATION_INTERNATIONALPREFIX "InternationalPrefix"
+#define LOCATION_LONGDISTANCEPREFIX "LongDistancePrefix"
+#define LOCATION_COUNTRY "Country"
+#define LOCATION_AREACODE "AreaCode"
+#define LOCATION_MAILTYPE "MailType"
+#define LOCATION_MAILTHRESHOLD "MailThreshold"
+#define LOCATION_TCPNAMESERVER "TcpNameServer"
+#define LOCATION_TCPNAMESERVERHOST "TcpNameServerHost"
+
+#define LOCATION_REPLICATION_ENABLED "ReplicationEnabled"
+#define LOCATION_REPLICATE_IMMEDIATE "ReplicateImmediate"
+#define LOCATION_REPLICATE_AT_START "ReplicateAtStart"
+#define LOCATION_PROMPT_AT_START "PromptAtStart"
+#define LOCATION_REPLICATE_AT_END "ReplicateAtEnd"
+#define LOCATION_PROMPT_AT_END "PrmptAtEnd"
+#define LOCATION_OUTBOX_AT_END "ReplicateOutboxAtEnd"
+#define LOCATION_TOBESENT_AT_END "ReplicateToBeSentAtEnd"
+
+#define LOCATION_USESPRIORITYSCHEDULE "HiPriorityReplication"
+
+#define LOCATION_SCHEDULE "Enabled"
+#define LOCATION_PRIORITYSCHEDULE "Enabled_HI"
+#define LOCATION_SCHEDULE_DURATION "Schedule"
+#define LOCATION_SCHEDULE_DURATION_HI "Schedule_HI"
+#define LOCATION_INTERVAL "Interval"
+#define LOCATION_INTERVAL_HI "Interval_HI"
+#define LOCATION_WEEKDAYS_LIST "WeekDays"
+#define LOCATION_WEEKDAYS_LIST_HI "WeekDays_HI"
+
+#define LOCATION_NDSNAMESERVER "NDSNameServer"
+#define LOCATION_NDSNAMESERVERADDRESS "NDSNameServerAddress"
+#define LOCATION_NETBIOSNAMESERVER "NetBIOSNameServer"
+#define LOCATION_SOCKSPROXY "Proxy_SOCKs"
+#define LOCATION_SSLPROXY "Proxy_SSL"
+#define LOCATION_NOTESHTTPPROXY "Proxy_NotesHttp"
+#define LOCATION_PROXYUSERID "Proxy_LoginName"
+#define LOCATION_PROXYPASSWORD "Proxy_Password"
+#define LOCATION_PROXYAUTH_ENABLED "ProxyAuthenticationFlag"
+
+#define LOCATION_IMAGES "Images"
+#define LOCATION_USERNAME_FLAG "UserNameFlag" /* Primary/Alternate UserName Mode. 0 = Primary, 1 = Alternate */
+
+/* The following field is only meaningful if the user has workstation based
+ mail, if they do not, then it is assumed that server addressing (i.e.
+ resolution of the names, and allowing the use of server N&A books when
+ addressing mail, is always available). If the user is using a local
+ mail file, but has network connectivity, then they may want to allow
+ the use of server addressing. If the user has no connectivity, then'
+ this should be assumed to be off - regardless of its setting. DWC */
+
+#define LOCATION_SERVERADDRESSING "MailAddressing"
+
+ /* InterNotes/Web Location Items */
+
+#define LOCATION_INTERNOTES "InterNotes"
+#define LOCATION_WEBLOCALDB "WebDbName"
+#define LOCATION_WEBSERVERDB "WebDbName"
+#define LOCATION_WEBRETRIEVERLOCATION "WebLocation"
+#define LOCATION_WEBUPDATECACHE "WebUpdateCache"
+#define LOCATION_WEBRETRIEVERLOGGING "WebLogLevel"
+#define LOCATION_WEBRETRIEVER "WebRetriever"
+#define LOCATION_WEBRETRIEVERS "WebRetrievers"
+#define LOCATION_WEBRETRIEVERPATH "WebRetrieverPath"
+#define LOCATION_WEBHTTPPROXY "Proxy_HTTP"
+#define LOCATION_WEBFTPPROXY "Proxy_FTP"
+#define LOCATION_WEBGOPHERPROXY "Proxy_Gopher"
+#define LOCATION_WEBNOPROXY "No_Proxy"
+#define LOCATION_PROXYFLAG "ProxyFlag"
+
+#define LOCATION_SSLSITECERT "SSLSiteCerts"
+#define LOCATION_SSLEXPIREDCERTS "SSLExpiredCerts"
+#define LOCATION_SSLPROTOCOLVER "SSLProtocolVersion"
+#define LOCATION_SSLSENDCERTS "SSLSendCertificates"
+
+ /* Java Location Items */
+
+#define LOCATION_JAVASECUREDOMAINLIST "JavaSecureDomain"
+#define LOCATION_JAVAALLOWINSECURE "JavaAllowInSecureDomain"
+#define LOCATION_JAVAALLOWINOTHER "JavaAllowInOtherDomains"
+#define LOCATION_JAVATRUSTPROXY "JavaTrustHTTPProxy"
+
+ /* Internet Mail Location Items */
+
+#define LOCATION_IMAIL_PROTOCOL "MailServerProtocol"
+#define LOCATION_IMAIL_USER "ImailUsername"
+#define LOCATION_IMAIL_PASSWORD "ImailPassword"
+#define LOCATION_IMAIL_SERVERLIST "ImailServer"
+#define LOCATION_IMAIL_SMTP_SERVER "ImailSMTPServer"
+#define LOCATION_IMAIL_PORT "ImailPort"
+#define LOCATION_IMAIL_USE_SSL "ImailUseSSL"
+#define LOCATION_IMAIL_ADDRESS "ImailAddress"
+#define LOCATION_IMAIL_ADDRESS_UPDATED_BY "ImailAddressUpdatedBy"
+#define LOCATION_IMAIL_POP_DEL_MAIL "PopDeleteMail"
+#define LOCATION_IMAIL_SMTP_ROUTE "SMTPRoute"
+#define LOCATION_IMAIL_INTERNET_DOMAIN "InternetDomain"
+#define LOCATION_IMAIL_ATTACH_ENCODE "SMTPEncodingScheme"
+#define LOCATION_IMAIL_MAC_ATTACH_ENCODE "SMTPMacAttachConvertOption"
+#define LOCATION_IMAIL_MSGFORMAT "MessageFormat"
+ /* If this field is set, this location's internet mail can be changed for existing users
+ with information from the directory person record on the home server */
+#define LOCATION_IMAIL_ACCEPTUPDATES "ImailAcceptUpdates"
+
+
+ /* Admin Client Location Items */
+
+#define LOCATION_ADMIN_MONITOR_REMENABLE "EnableRemoteMonitor"
+#define LOCATION_ADMIN_MONITOR_REMSERVER "RemoteMonitorServer"
+#define LOCATION_ADMIN_MONITOR_COLLINTER "DataCollectionInterval"
+#define LOCATION_ADMIN_MONITOR_AUTOACTIVATE "AutoActivateMonitor"
+#define LOCATION_ADMIN_FAVORITE_SERVERS "AdminFavoriteServers"
+#define LOCATION_ADMIN_STAT_GEN_REPORTS "GenerateStatReports"
+#define LOCATION_ADMIN_STAT_REP_INTERVAL "ReportInterval"
+#define LOCATION_ADMIN_STAT_GEN_ALARMS "GenerateStatAlarms"
+#define LOCATION_ADMIN_STAT_ALARM_INTERVAL "AlarmInterval"
+#define LOCATION_ADMIN_CHART_SAMEAS_MON "ChartIntervalIsSameAsMonitor"
+#define LOCATION_ADMIN_CHART_INTERVAL "ChartInterval"
+
+
+/* Personal database names... */
+#define LOCATION_BOOKMARK_DB "BookmarkDb"
+#define LOCATION_SUBSCRIPTION_DB "HeadlineDb"
+
+
+/* Prior to build 125, in the location record, the ports that were listed
+ were those that were enabled. Beginning in build 125, the ports that
+ are listed (internally by a different item) are those that are disabled.
+ The location form will however present the enabled ports by selecting the
+ ports which are not specifed in the disabled item. When saved, it is
+ inverted back to mean the ports that are disabled. In this manner,
+ newly added ports will be enabled for all locations (by default). */
+
+#define LOCATION_AUTONETCONFIG "AutoNetConfig"
+#define LOCATION_PORTS "PortName" /* Prior to 125 */
+#define LOCATION_DISABLEDPORTS "DisabledPorts" /* 125 and later */
+#define LOCATION_NAMELOOKUPMODE "NameLookupMode"
+#define LOCATION_NAMELOOKUPPREF "NameLookupPref"
+#define LOCATION_EXHAUSTIVENAMELOOKUP "ExhaustiveNameLookup"
+#define LOCATION_MAIL_ADDR_FILE "MailAddressFile" /* Last N&A Book used at this location */
+#define LOCATION_VERSION "$LocationVersion"
+#define LOCATION_BCASELIST "$BCaseList"
+#define LOCATION_DIALING_SERVERS "$DialingServers"
+#define LOCATION_DIALING_RULES "$DialingRules"
+#define LOCATION_STACKFILENAMES "$StackFileNames" /* Filename of topmost
+ replica icon at this
+ location for this
+ 'stack', */
+/* The V5 list is a parallel list of a database and the last replica. It
+ is independent of the V4 list to avoid differnces that may be necessary
+ between the 2 lists. */
+
+#define LOCATION_LASTFILENAMES "$LastFileNames" /* Filename of topmost
+ replica icon at this
+ location for this
+ 'stack', */
+#define LOCATION_LASTREPLICAIDS "$LastReplicaIDs" /* Replica ID of topmost
+ replica icon at this
+ location for this
+ 'stack', */
+#define LOCATION_LASTACCESSED "$LastAccessedDB" /* Time/Date of last use
+ of this DB. */
+
+#define LOCATION_SAVED_SERVER "$SavedServers" /* Server name */
+#define LOCATION_SAVED_PORT "$SavedPorts" /* Port server reached on */
+#define LOCATION_SAVED_ADDRESS "$SavedAddresses" /* Server address on this port */
+#define LOCATION_SAVED_DATE "$SavedDate" /* Julian Date */
+#define LOCATION_SAVED_LAST_TRIED_DATE "$SavedTriedDate" /* Julian Date */
+#define LOCATION_RLAN_IDLE_TIMEOUT "RLANIdleTimeout" /* timeout for RLAN hangup */
+
+/* The following field was introduced in build 133 so that new icons added
+ to the desktop get bubbled to the top of the stack if appropriate. New
+ icons should be at the top of the stack if:
+
+ the DB icon is mew, is for a server DB, the location has a LAN port and
+ the current top of the stack is a local database.
+ the DB icon is mew, is for a local DB, the location has no LAN port and
+ the current top of the stack is a server database.
+*/
+#define LOCATION_STACKCHECKED "$StackChecked"
+
+/* If this field is set, this location can be changed for existing users
+ with information from the person record and setup profile records for this
+ user on their home server */
+
+#define LOCATION_ACCEPTUPDATES "AcceptUpdates"
+
+/* Sametime server */
+
+#define LOCATION_SAMETIMESERVER "SametimeServer"
+
+#define LOCATION_SAMETIME_PORT "SametimePort"
+#define LOCATION_SAMETIME_PROTOCOL "SametimeProtocol"
+#define LOCATION_SAMETIME_PROXY_TYPE "SametimeProxyType"
+#define LOCATION_SAMETIME_PROXY_SERVER "SametimeProxyServer"
+#define LOCATION_SAMETIME_PROXY_PORT "SametimeProxyPort"
+#define LOCATION_SAMETIME_PROXY_RESOLVE "SametimeServerNameResolve"
+#define LOCATION_SAMETIME_PROXY_USERNAME "SametimeProxyUsername"
+#define LOCATION_SAMETIME_PROXY_PASSWORD "SametimeProxyPassword"
+#define LOCATION_SAMETIME_LOGON_WHEN "SametimeLogonWhen"
+#define LOCATION_SAMETIME_PASSWORD "SametimePassword"
+#define LOCATION_SAMETIME_USERNAME "SametimeUsername"
+
+/* Cached mail file replica ID information. This information can only
+ be used if the last mailfile name agrees with the present one. That
+ would mean that the user has not changed the file name and or server
+ name since the time we squirreled the information away. */
+
+#define LOCATION_LAST_MAILFILE_NAME "$LastMailPath"
+#define LOCATION_LAST_MAILFILE_REPID "$LastMailRepID"
+
+
+
+/* Catalog server - used for Domain Search */
+
+#define CATALOG_FILE_V5 "catalog.nsf"
+#define LOCATION_CATALOGSERVER "CatalogServer"
+#define DOMAINQUERY_FORM_NAME "DomainQuery"
+#define LOCAL_DOMAIN_CATALOG_SERVERS "LocalDomainCatalogServers"
+#define DOMAIN_INDEXER_SCOPE "CatalogIndexerScope"
+#define DOMAIN_CATALOG_FIELD "CatalogType"
+#define DOMAIN_INDEXER_DIRECTORY "CatalogIndexerDirectory"
+#define DOMAIN_CATALOG_NAME "Domain Catalog"
+#define DOMAIN_CATALOG_SCOPE "CatalogDomainScope"
+#define CATALOG_SERVERLOOKUPITEMCOUNT 2
+#define CATALOG_SERVERLOOKUPITEMS "CatalogType\0Administrator\0"
+
+#define BOOKMARK_DBNAME "bookmark.nsf"
+#define BOOKMARK_TEMPLATENAME "bookmark.ntf"
+#define BOOKMARK_FINDDB_FORMNAME "DatabaseSearch"
+
+/* some bookmark views */
+#define BOOKMARK_LAYOUTS_VIEW "(Layouts)"
+#define BOOKMARK_URLS_VIEW "(URLs)"
+#define BOOKMARK_DOWNLOADS_VIEW "(Downloads)"
+
+/* This is a field on URL bookmark notes to give revision info */
+#define BOOKMARK_URL_MODIFIED "LotusModified"
+#define BOOKMARK_URL_502 "5.02"
+
+/* Fields used to store the list of folders into which a document is to be
+ saved. Note that @Command([ChooseFolders]) reads and writes these fields,
+ so you do not normally need to manipulate them in a document.
+
+ Note also that to a user, there are only two sets of folders: Shared and
+ Private, with the distinction that some Private folders are stored in the
+ databse, and some on the workstation in the desktop file (when the user
+ cannot store them in the database due to access restrictions). */
+
+#define FOLDERS_SHARED "$Folders" /* List of shared folders. */
+#define FOLDERS_PRIVATE "$PrivateFolders" /* List of private folders (in database). */
+#define FOLDERS_PRIVATE_LOCAL "$LocalPrivateFolders" /* List of private folders (in desktop). */
+
+/* Item names of fields in Mail template: */
+
+#define MAILREPORT_ITEM "$DeliveryReport" /* TBD */
+
+/* Item Name of view format note item */
+
+#define ITEM_NAME_VIEW_FORMATNOTE "$FormatNote" /* UNID of note views design was originally copied from */
+
+/* Profile note & field name items on view format note. The profile field
+ contains a user-definable formula for a column */
+
+#define VIEW_COLUMN_PROFILE_DOC "$ColumnProfileDoc"
+#define VIEW_COLUMN_FORMAT_ITEM "$ColumnFormatItem"
+
+/* Standard folder names. */
+
+#define FOLDER_INBOX "($Inbox)"
+#define FOLDER_DRAFTS "($Drafts)"
+#define FOLDER_SENT "($Sent)"
+#define FOLDER_ALL "($All)"
+#define FOLDER_CALENDAR "($Calendar)"
+#define FOLDER_TODO "($ToDo)"
+#define FOLDER_MEETINGS "($Meetings)"
+#define FOLDER_TRASH "($Trash)"
+#define FOLDER_PROFILE "($Profiles)"
+#define FOLDER_ALARMS "($Alarms)"
+#define FOLDER_SOFT_DELETE "($SoftDeletions)"
+#define FOLDER_CONTACTS "($Contacts)"
+#define FOLDER_RULES "(Rules)"
+#define FOLDER_GROUP_CALENDARS "(Group Calendars)"
+#define FOLDER_STATIONERY "(Stationery)"
+#define FOLDER_FOLLOW_UP "($FollowUp)"
+#define FOLDER_MEETINGS_BY_CATEGORY "($Meetings By Category)"
+#define FOLDER_MEETINGS_BY_MONTH "($Meetings By Month)"
+#define FOLDER_MEETINGS_ALL_BY_DATE "($Meetings All By Date)"
+#define FOLDER_MEETINGS_BY_ENTRY_TYPE "($Meetings By Entry Type)"
+#define FOLDER_MEETINGS_BY_STATUS "($Meetings By Status)"
+#define FOLDER_MEETINGS_ALL_BY_DATE2 "($MeetingsAllByDate2)"
+#define FOLDER_MEETINGS_ON_MY_CALENDAR "($MeetingsOnMyCalendar)"
+#define FOLDER_MINIVIEW_NOTICES "Miniview - Notices2"
+#define FOLDER_JUNKMAIL "($JunkMail)"
+#define VIEW_FOLLOW_UP "($Follow-Up)"
+
+#define COMMON_SCRIPT_LIBRARY_NAME "Common"
+
+#define FOLDER_INBOX_NAME "$Inbox"
+#define FOLDER_DRAFTS_NAME "$Drafts"
+#define FOLDER_SENT_NAME "$Sent"
+#define FOLDER_ALL_MAIL "$All"
+#define FOLDER_CALENDAR_NAME "$Calendar"
+#define FOLDER_TODO_NAME "$ToDo"
+#define FOLDER_MEETINGS_NAME "$Meetings"
+#define FOLDER_TRASH_NAME "$Trash"
+#define FOLDER_PROFILE_NAME "$Profiles"
+#define FOLDER_ALARMS_NAME "$Alarms"
+#define FOLDER_SOFT_DELETE_NAME "$SoftDeletions"
+#define FOLDER_CONTACTS_NAME "$Contacts"
+#define FOLDER_RULES_NAME "Rules"
+#define FOLDER_GROUP_CALENDARS_NAME "Group Calendars"
+#define FOLDER_STATIONERY_NAME "Stationery"
+#define FOLDER_FOLLOW_UP_NAME "$FollowUp"
+#define FOLDER_MEETINGS_BY_CATEGORY_NAME "$Meetings by Category"
+#define FOLDER_MEETINGS_BY_MONTH_NAME "$Meetings By Month"
+#define FOLDER_MEETINGS_ALL_BY_DATE_NAME "$Meetings All By Date"
+#define FOLDER_MEETINGS_BY_ENTRY_TYPE_NAME "$Meetings By Entry Type"
+#define FOLDER_MEETINGS_BY_STATUS_NAME "$Meetings By Status"
+#define FOLDER_MEETINGS_ALL_BY_DATE2_NAME "$MeetingsAllByDate2"
+#define FOLDER_MEETINGS_ON_MY_CALENDAR_NAME "$MeetingsOnMyCalendar"
+#define FOLDER_JUNKMAIL_NAME "$JunkMail"
+#define VIEW_FOLLOW_UP_NAME "$Follow-Up"
+#define VIEW_IMTRANSCRIPTS_NAME "$IMTranscripts"
+#define VIEW_MAILTHREADS_NAME "Mail Threads"
+
+#define FOLDER_INBOX_ALIAS "Inbox"
+#define FOLDER_DRAFTS_ALIAS "Drafts"
+#define FOLDER_SENT_ALIAS "Sent"
+#define FOLDER_ALL_MAIL_ALIAS "All"
+#define FOLDER_CALENDAR_ALIAS "Calendar"
+#define FOLDER_TODO_ALIAS "Tasks"
+#define FOLDER_MEETINGS_ALIAS "Meetings"
+#define FOLDER_TRASH_ALIAS "Trash"
+#define FOLDER_JUNKMAIL_ALIAS "JunkMail"
+#define FOLDER_PROFILE_ALIAS "Profiles"
+#define FOLDER_ALARMS_ALIAS "Alarms"
+#define FOLDER_SOFT_DELETE_ALIAS "SoftDeletions"
+#define FOLDER_CONTACTS_ALIAS "People"
+#define FOLDER_RULES_ALIAS "Rules"
+#define FOLDER_GROUP_CALENDARS_ALIAS "(GroupCalendarFolder)"
+#define FOLDER_STATIONERY_ALIAS "Stationery"
+#define FOLDER_MEETINGS_BY_CATEGORY_ALIAS "Meetings by Category"
+#define FOLDER_MEETINGS_BY_MONTH_ALIAS "Meetings by Month"
+#define FOLDER_MEETINGS_ALL_BY_DATE_ALIAS "MeetingsAllByDate"
+#define FOLDER_MEETINGS_BY_ENTRY_TYPE_ALIAS "MeetingsByEntryType"
+#define FOLDER_MEETINGS_BY_STATUS_ALIAS "MeetingsByStatus"
+
+/* Site database view name */
+
+#define SITE_DBLOOKUP_VIEW "($DbLookup)"
+
+/* Router Shared Mail Object Store names */
+
+#define SHARED_MAIL_NAME "SHARED_MAIL" /* config variable for shared mail */
+#define ROUTER_OBJECT_STORE_NAME "mailobj.nsf" /* object store link file used by the router */
+#define ROUTER_OBJECT_STORE_DBNAME "mailobj1.nsf" /* object store database created by the router */
+
+
+
+/* Cluster Name and Address Book lookup definitions */
+
+#define CLUSTERS_CLUSTER_VIEW_1 "1\\$Clusters"
+#define CLUSTERS_CLUSTER_VIEW "$Clusters"
+#define CLUSTERS_CLUSTER_ITEM_NAME "ClusterName"
+#define CLUSTERS_CLUSTER_COL_NAME "$4" /* Name of the ClusterName column in the $Clusters view */
+#define CLUSTERS_CLUSTER_ITEM 0
+
+#define CLUSTERS_SERVERS_VIEW_1 "1\\$Servers"
+#define CLUSTERS_SERVERS_VIEW "$Servers"
+#define CLUSTERS_SERVER_ITEM_NAME "ServerName"
+#define CLUSTERS_SERVER_COL_NAME "$0" /* Name of the ServerName column in the $Clusters view */
+#define CLUSTERS_SERVER_ITEM 0
+
+#define CLUSTERS_CLREPID_ITEM_NAME "ClRepID"
+#define CLUSTERS_CLREPID_ITEM 0
+
+/* Cluster Database Directory definitions */
+
+#define CLUSTERS_SERVER_VIEW "$Server"
+#define CLUSTERS_PATHNAME_VIEW "$Pathname"
+#define CLUSTERS_REPID_VIEW "$ReplicaID"
+#define CLUSTERS_DIRTITLE_VIEW "$DirectoryTitle"
+
+#define CLUSTERS_SERVER_FIELD "Server"
+#define CLUSTERS_REPID_FIELD "ReplicaID"
+#define CLUSTERS_PATHNAME_FIELD "PathName"
+#define CLUSTERS_TITLE_FIELD "Title"
+#define CLUSTERS_OUTOFSERVICE_FIELD "DatabaseOutOfService"
+#define CLUSTERS_REPL_FIELD "ClusterReplicate"
+#define CLUSTERS_FAILBYPATH_FIELD "OnlyFailoverbyPathname"
+#define CLUSTERS_DELETE_FIELD "MarkedForDelete"
+
+#define CLUSTERS_DBDIR_NAME "cldbdir.nsf"
+#define CLUSTERS_DBDIR_TEMPLATE_NAME "cldbdir4.ntf"
+
+/* Values for CLUSTERS_OUTOFSERVICE_FIELD */
+#define CLUSTERS_IN_SERVICE "0"
+#define CLUSTERS_OUT_OF_SERVICE "1"
+
+/* Values for CLUSTERS_CLREPL_FIELD */
+#define CLUSTERS_CLUSTER_REPLICATE_ON "1"
+#define CLUSTERS_CLUSTER_REPLICATE_OFF "0"
+
+
+/* User registration document and DUS (Domino Upgrade Service) field definitions */
+
+/* Fields related to the basics user registration dialog pane */
+#define USERREG_FULLNAME_ITEM "FullName"
+#define USERREG_FIRSTNAME_ITEM "FirstName"
+#define USERREG_LASTNAME_ITEM "LastName"
+#define USERREG_MIDDLEINITIAL_ITEM "MiddleInitial"
+#define USERREG_SHORTNAME_ITEM "ShortName"
+#define USERREG_PASSWORD_ITEM "UserPassword"
+#define USERREG_POLICY_ITEM "ExplicitPolicy"
+#define USERREG_ORG_POLICY_ITEM "OrgPolicy"
+
+/* Comment field in the 'Other' user registration dialog pane */
+#define USERREG_COMMENT_ITEM "Comment"
+
+/* DUS related fields */
+#define USERREG_DUSUSERID_ITEM "NUAUserID"
+#define USERREG_DUSNAME_ITEM "NUAName"
+#define USERREG_DUSALIASNAMES_ITEM "DUSFullNameAliases"
+#define USERREG_DUSMAILFILE_ITEM "NUAMailFile"
+#define USERREG_DUSGROUPID_ITEM "GroupID"
+#define USERREG_DUSPARENTGROUPS_ITEM "ParentGroups" /* for groups with parent groups */
+#define USERREG_PERSONNOTEHANDLE_ITEM "PersonNoteHandle" /* note handle to new person note in NAB created by user reg */
+
+/* Advance info item fields */
+#define USERREG_DUSADVANCEDINFO_ITEM "NUAAdvancedInfo" /* The DUS must set the DUS_ADVANCEDINFO_ITEM below to "1" if
+ any of the USERREG_XXX fields below are set by the DUS */
+#define USERREG_STORAGE_ITEM "MessageStorage" /* Specifies how user wants to store the mail. See USERREG_STORAGE_XXX below */
+#define USERREG_STORAGE_UNKNOWN 0xFF /* can't find storage type */
+#define USERREG_STORAGE_CDRECORDS 0 /* Store as cd records only */
+#define USERREG_STORAGE_CDRECORDS_AND_RFC822 1 /* Store as cd records & attachment of original message */
+#define USERREG_STORAGE_RFC822 2 /* Store original message as attachment (no cdrecords) */
+#define USERREG_STORAGE_NATIVE_MIME 3 /* Store headers & parts as separate items (without conversion) or CD */
+#define USERREG_STORAGE_NATIVE_MIME_ONLY 4 /* Store headers & parts as separate items (without conversion) only */
+
+#define USERREG_PERSONAL_TITLE "Title" /* keyword choices are Mr., Ms., Mrs., Miss, Dr. or Prof. */
+#define USERREG_GENERATION_QUALIFIER "Suffix" /* keyword choices are I, II, III, Jr., or Sr. */
+
+#define USERREG_HOME_STREETADDRESS "StreetAddress"
+#define USERREG_HOME_CITY "City"
+#define USERREG_HOME_STATE "State"
+#define USERREG_HOME_ZIP "Zip"
+#define USERREG_HOME_COUNTRY "Country"
+#define USERREG_PHONENUMBER_ITEM "PhoneNumber"
+#define USERREG_HOME_FAX "HomeFAXPhoneNumber"
+#define USERREG_SPOUSE "Spouse"
+#define USERREG_CHILDREN "Children"
+
+#define USERREG_COMPANYNAME_ITEM "CompanyName"
+#define USERREG_JOB_TITLE "JobTitle"
+#define USERREG_DEPARTMENT_ITEM "Department"
+#define USERREG_MANAGER "Manager"
+#define USERREG_OFFICEPHONE_ITEM "OfficePhoneNumber"
+#define USERREG_CELL_PHONE "CellPhoneNumber"
+#define USERREG_PAGER "PhoneNumber_6"
+#define USERREG_OFFICE_FAX "OfficeFAXPhoneNumber"
+#define USERREG_ASSISTANT "Assistant"
+#define USERREG_OFFICE_STREETADDRESS "OfficeStreetAddress"
+#define USERREG_OFFICE_CITY "OfficeCity"
+#define USERREG_OFFICE_STATE "OfficeState"
+#define USERREG_OFFICE_ZIP "OfficeZip"
+#define USERREG_OFFICE_COUNTRY "OfficeCountry"
+#define USERREG_OFFICE_NUMBER "OfficeNumber"
+#define USERREG_EMPLOYEEID_ITEM "EmployeeID"
+
+#define USERREG_ENCRYPT_INCOMING_MAIL "EncryptIncomingMail" /* keyword choices are "Yes" | "1" or "No" | "0" */
+#define USERREG_X400_ADDRESS "x400Address"
+#define USERREG_WEB_SITE "WebSite"
+#define USERREG_CALENDARDOMAIN_ITEM "CalendarDomain" /* User's calendar domain override */
+/* END of User registration document and DUS field definitions */
+
+
+/* Last specified path and username for alternate mail logon dialog. */
+
+#define ALT_MAIL_LAST_PATH "AltMailLastPath"
+#define ALT_MAIL_LAST_NAME "AltMailLastName"
+
+/* Convert Utility Constants. */
+
+#define ITEM_NAME_CONVERT_FORM FIELD_FORM
+#define ITEM_NAME_CONVERT_DATE "ConvertedDate"
+#define ITEM_NAME_HIDDEN_DOC "HiddenDocument"
+
+/* Names stored as UNKs if a note has rarely used item names. */
+
+#define RARELY_USED_NAME "$RarelyUsedName"
+#define RARELY_USED_TABLE "$RarelyUsedTable"
+#define RARELY_USED_V4_ONLY_ITEM "$RUsedR4Only"
+
+#define AGENT_HSCRIPT_ITEM "$AgentHScript"
+#define AGENT_HSCRIPTOBJ_ITEM "$AgentHScript_O"
+
+/* Local schedule retrieval defintions */
+
+#define LOCSCHED_FORM_NAME "LocalSchedSettings"
+#define LOCSCHED_PROFILE_NAME "LocalSchedSettings"
+
+/* Fields in local schedule database (busytime) for local
+ schedule synchronization via replicator page. */
+
+
+#define ITEM_LOCSCHED_LIST "LocalSchedList"
+#define ITEM_LOCSCHED_DAYSTOFETCH "LocalSchedDaysToFetch"
+#define ITEM_LOCSCHED_SUPPRESS "LocalSchedSuppressMinutes"
+
+/* OLE "special" Items used for ActiveDoc/RichText rendering */
+
+#define OLE_ITEM_OLEOBJFIELD "$OLEObjField"
+#define OLE_ITEM_OLEOBJPROGID "$OLEObjProgID"
+#define OLE_ITEM_OLEOBJRICHTEXTFIELD "$OLEObjRichTextField"
+
+/* Enables any OLE object to be in-place activated in preview pane mode. Used
+ to activate OLE controls like WEB Browser */
+#define OLE_PREVIEW_ACTIVATE "$OLEPreviewActivate"
+
+/*Site Database design and item names*/
+#define SITE_FORM_NAME "Database"
+#define SITE_REPLICAID_VIEW_NAME "($ReplicaID)"
+#define SITE_PROFILE_NAME "Site"
+
+#define SITE_TITLE_ITEM_NAME "Title"
+#define SITE_REALTITLE_ITEM_NAME "RealTitle"
+#define SITE_DBICON_ITEM_NAME "dbicon"
+#define SITE_SEQUENCE_ITEM_NAME "dbsequence"
+#define SITE_REPLICAID_ITEM_NAME "replicaid"
+#define SITE_SEQUENCE_ITEM_NAME "dbsequence"
+#define SITE_SERVERHINT_ITEM_NAME "$ServerHint"
+
+/* Web Browser control well known action name and form name */
+#define OLE_URLNAVIGATE_ACTION "$ControlURLNavigate"
+#define OLE_WEBBROWSER_FORM "WebBrowserForm" /* Used if IE 3 is installed */
+#define OLE_WEBBROWSER4_FORM "WebBrowser4Form" /* Used if IE 4 is installed */
+#define OLE_MOZILLABROWSER_FORM "MozillaForm" /* Used if NS 6 Mozilla control is installed */
+
+/* Distinguished Field Names */
+#define DN_COUNTRY "C"
+#define DN_ORGANIZATION "O"
+#define DN_ORGANIZATIONAL_UNIT "OU"
+#define DN_COMMON_NAME "CN"
+#define DN_SURNAME "S"
+#define DN_USER_ID "UID"
+#define DN_STREET_ADDRESS "STREET"
+#define DN_LOCALITY "L"
+#define DN_STATE "ST"
+#define DN_DOMAIN_COMPONENT "DC"
+
+
+
+/* Items used to store folder references. */
+
+#define ITEM_FOLDER_REF "$FolderRef"
+#define ITEM_FOLDER_REF_ID "$FolderRefID"
+#define ITEM_FOLDER_REF_FLAGS "$FolderRefFlags"
+
+/* Items used to store r6 imap folder references. */
+
+#define IMAP_ITEM_FOLDER_REF "$IMAPFolderRef"
+#define IMAP_ITEM_FOLDER_REF_ID "$IMAPFolderRefID"
+#define IMAP_ITEM_FOLDER_REF_FLAGS "$IMAPFolderRefFlags"
+
+/* DON'T CHANGE FOLLOWING VALUES. IMAP SERVER DEPENDS ON THESE VALUES. */
+/* Folder reference flag values. */
+
+#define FOLDER_REF_FLAG_SEEN 0x00000001
+#define FOLDER_REF_FLAG_ANSWERED 0x00000002
+#define FOLDER_REF_FLAG_FLAGGED 0x00000004
+#define FOLDER_REF_FLAG_DELETED 0x00000008
+#define FOLDER_REF_FLAG_DRAFT 0x00000010
+
+#define FOLDER_REF_FLAG_NOT_RECENT 0x00000020
+#define FOLDER_REF_FLAG_RECENT 0x00000040 /* Unique flag value that is not stored */
+
+#define FOLDER_REF_FLAG_MDNSENT 0x00000080
+#define FOLDER_REF_FLAG_KEYWORD 0x00000100
+
+/* Name of the folder reference information collection. */
+
+#define FOLDER_REF_INFO_COLLECTION "$FolderRefInfo"
+
+/* Collations in the folder reference information collection. */
+
+#define FOLDER_UNID_REF_ID_COLLATION_NUMBER 1
+#define FOLDER_UNID_REF_ID_COLLATION_LEVELS 2
+
+#define FOLDER_UNID_NNTP_DATE_COLLATION_NUMBER 2
+#define FOLDER_UNID_NNTP_DATE_COLLATION_LEVELS 2
+
+/* Summary item names used to store folder reference information. */
+
+#define FOLDER_REF_UNID_ITEM_NAME "$105"
+#define FOLDER_REF_REF_ID_ITEM_NAME "$FolderRefID"
+#define FOLDER_REF_FLAGS_ITEM_NAME "$FolderRefFlags"
+
+/* Summarty item names used to store NNTP folder reference information. */
+
+#define FOLDER_REF_NNTP_SUBJECT_ITEM_NAME "$110"
+#define FOLDER_REF_NNTP_FROM_ITEM_NAME "$109"
+#define FOLDER_REF_NNTP_DATE_ITEM_NAME "$113"
+#define FOLDER_REF_NNTP_MESSAGE_ID_ITEM_NAME "$uname"
+#define FOLDER_REF_NNTP_REFERENCES_ITEM_NAME "$114"
+#define FOLDER_REF_NNTP_SIZE_ITEM_NAME "NNTP_Size"
+#define FOLDER_REF_NNTP_LINES_ITEM_NAME "Lines"
+#define FOLDER_REF_NNTP_ISLMBCS_ITEM_NAME "$115"
+#define FOLDER_REF_NNTP_DISTRIBUTION_ITEM_NAME "Distribution"
+#define FOLDER_REF_NNTP_PATH_ITEM_NAME "Path"
+
+
+/* Folder flag values. */
+
+#define FOLDER_FLAG_NOINFERIORS 0x00000001
+#define FOLDER_FLAG_NOSELECT 0x00000002
+#define FOLDER_FLAG_MARKED 0x00000004
+#define FOLDER_FLAG_UNMARKED 0x00000008
+
+#define FOLDER_FLAG_SYSTEM 0x00000010 /* Set if folder name starts with '$' */
+#define FOLDER_FLAG_HIDDEN 0x00000020 /* Set if folder name starts with '(' */
+
+#define FOLDER_FLAG_NNTP_NEWSGROUP 0x00000040
+#define FOLDER_FLAG_HASCHILDREN 0x00000080 /* set if folder has children */
+
+/* A special, unique folder flag value, that is never stored, used to indicate
+ that any value of folder flags are to be considered a match. */
+
+#define FOLDER_FLAG_ANY 0x80000000
+
+/* A mask of bits that are used to qualify a folder name. */
+
+#define FOLDER_FLAG_MATCH_MASK (FOLDER_FLAG_SYSTEM | FOLDER_FLAG_HIDDEN)
+
+/* A bit that is used to indicate that any value of folder flags are to be
+ considered a match. */
+
+#define FOLDER_FLAG_MATCH_ANY (FOLDER_FLAG_ANY)
+
+
+/* Name of the folder information collection. */
+
+#define FOLDER_INFO_COLLECTION "$FolderInfo"
+
+/* Collations in the folder information collection. */
+
+#define FOLDER_NAME_COLLATION_NUMBER 1
+#define FOLDER_NAME_COLLATION_LEVELS 1
+
+#define FOLDER_UNID_COLLATION_NUMBER 2
+#define FOLDER_UNID_COLLATION_LEVELS 1
+
+/* Collations in the IMAIL resync information collection. */
+
+#define RESYNC_INFO_NOTEID_COLLATION_NUMBER 1
+#define RESYNC_INFO_NOTEID_COLLATION_LEVELS 1
+
+#define RESYNC_INFO_UID_COLLATION_NUMBER 2
+#define RESYNC_INFO_UID_COLLATION_LEVELS 1
+
+#define RESYNC_INFO_MID_COLLATION_NUMBER 3
+#define RESYNC_INFO_MID_COLLATION_LEVELS 1
+
+/* Summary item names used to store folder information. */
+
+#define FOLDER_NAME_ITEM_NAME "$106"
+#define FOLDER_UNID_ITEM_NAME "$103"
+#define FOLDER_FLAGS_ITEM_NAME "$107"
+
+/* Items used to store folder information. */
+
+#define ITEM_FOLDER_FLAGS "$FolderFlags"
+
+/* Length of the text representation of an UNID in hex format. */
+
+#define UNID_TEXT_LENGTH (2 * sizeof(UNID))
+
+/* IMAP subscription list */
+
+#define IMAP_PROFILE_SUBSCRIPTION "IMAPProfileSubscription"
+#define ITEM_IMAP_SUBSCRIPTION "$IMAPSubscription"
+
+/* IMAP NAMESPACE Configuration Items */
+
+#define IMAP_CFGREC_NS_SHAREDDBLINKS "IMAPNSShrdDbLinks"
+#define IMAP_CFGREC_NS_OTHERSUNREAD "IMAPNSOthersUnrd"
+#define IMAP_PROFILE_NS_OTHERUSERS "IMAPNSOtherUsers"
+
+/* IMAP Replication Items */
+
+#define IMAP_SEQNO_ITEM_NAME "$IMAPSeqNo"
+#define IMAP_LASTFOLDERUNID_ITEM_NAME "$IMAPLastFolderUNID"
+#define IMAP_UID_ITEM_NAME "$IMAPUID"
+#define IMAP_FLAGS_ITEM_NAME "$IMAPFlags"
+#define IMAP_DISCFLAGS_ITEM_NAME "$IMAPDiscFlags"
+#define IMAP_MSGID_ITEM_NAME "$IMAPMsgID"
+
+/* IMAP Replication $IMAPResyncInfo view column names */
+
+#define IMAP_SEQNO_COLUMN "IMAPSeqNo"
+#define IMAP_LASTFOLDERUNID_COLUMN "IMAPLastFolderUNID"
+#define IMAP_UID_COLUMN "IMAPUID"
+#define IMAP_FLAGS_COLUMN "IMAPFlags"
+#define IMAP_DISCFLAGS_COLUMN "IMAPDiscFlags"
+#define IMAP_MSGID_COLUMN "IMAPMsgID"
+
+/* NNTP Replication Items */
+
+#define NNTP_FOLDERUNID_ITEM_NAME "$NNTPFolderUNID"
+#define NNTP_UID_ITEM_NAME "$NNTPUID"
+#define NNTP_FLAGS_ITEM_NAME "$NNTPFlags"
+#define NNTP_MSGID_ITEM_NAME "$UName"
+#define FIELD_PARENT_UNAME "$ParentUName"
+
+/* NNTP Replication $NNTPResyncInfo view column names */
+
+#define NNTP_FOLDERUNID_COLUMN "NNTPFolderUNID"
+#define NNTP_UID_COLUMN "NNTPUID"
+#define NNTP_FLAGS_COLUMN "NNTPFlags"
+#define NNTP_MSGID_COLUMN "UName"
+
+/* Name of the IMAP Resync information collection. */
+
+#define IMAP_RESYNC_INFO_COLLECTION "$IMAPResyncInfo"
+
+/* Name of the NNTP Resync information collection. */
+
+#define NNTP_RESYNC_INFO_COLLECTION "$NNTPResyncInfo"
+
+/* components (java applets, etc. ) */
+
+#define COMPONENTS_LIST_ITEM "$Components"
+
+/* Setup */
+#define SETUP_SERVERLOOKUP_VIEW "($ServersLookup)"
+
+/* Admin Panel */
+
+#define NETWORKS_NAMESPACE "$Networks"
+#define INIT_NETWORKSLOOKUPITEMCOUNT 2
+#define INIT_NETWORKSLOOKUPITEMS "Network\0ServerName"
+#define INIT_NETWORKSITEM_NETWORK 0
+#define INIT_NETWORKSITEM_SERVER 1
+
+#define POLICIES_NAMESPACE "$Policies"
+#define POLICIES_NAMESPACE_ALT "($Policies)"
+#define POLICY_MASTER_POLICY_FORM "PolicyMaster"
+#define POLICY_ARCHIVE_SETTINGS_FORM "PolicyArchive"
+#define POLICY_SETUP_SETTINGS_FORM "PolicySetup"
+#define POLICY_REG_SETTINGS_FORM "PolicyRegistration"
+#define POLICY_DESKTOP_SETTINGS_FORM "PolicyDesktop"
+#define POLICY_SECURITY_SETTINGS_FORM "PolicySecurity"
+#define POLICY_SYNOPSIS_FORM "Synopsis"
+
+/* Domain Type */
+
+#define NOTES_DOMAIN_TYPE "NOTES"
+#define LDAP_DOMAIN_TYPE "LDAP"
+
+
+
+/* Headline Items */
+
+#define HEADLINE_DEFAULTVIEW_ITEM "($Headlines)" /* Default view to use to create headlines views */
+
+#define HEADLINE_VIEW_ITEM "$HLView" /* Headline marker item for headlines view */
+#define HEADLINE_SUMMARY_ITEM "$HLNoteSummary" /* Headline summary item */
+#define HEADLINE_MODIFIED_ITEM "$HLNoteModified" /* Headline last modified time (time) */
+#define HEADLINE_UNID_ITEM "$HLNoteUNID" /* Headline UNID (text) */
+#define HEADLINE_SEARCHMATCH_ITEM "$HLNoteSearchMatch" /* Headline search match item (text format below) */
+#define HEADLINE_REF_ITEM "$HLNoteREF" /* Headline saved reference (no main topic found) */
+
+/* Subscription Items */
+
+#define SUBSCRIPTION_VIEW "$Subscriptions" /* Alias of subscriptions view */
+#define SUBSCRIPTION_FORM "$Subscription" /* Name of subscription form */
+#define SUBSCRIPTION_HEADLINES_VIEW "$HeadlinesView" /* Designer specified view for headlines */
+#define FIELD_FORM_DBID "$FormDatabaseID"
+
+#define SUBSCRIPTION_VIEW_ITEM "$HLSubscription" /* Marker item for subscriptions */
+#define SUBSCRIPTION_TITLE "$HLTitle" /* Title of subscription */
+
+#define SUBSCRIPTION_DISABLED_ITEM "$HLDisabled" /* Disabled Flag, checked before enabled flag */
+#define SUBSCRIPTION_ENABLED_ITEM "$HLEnabled" /* Enabled Flag, only checked if disabled flag not found */
+#define SUBSCRIPTION_DISABLED '0' /* Enabled Flag - disabled */
+#define SUBSCRIPTION_ENABLED '1' /* Enabled Flag - enabled */
+
+#define SUBSCRIPTION_TYPE_ITEM "$HLType" /* Subscription Type */
+#define SUBSCRIPTION_TYPE_DB '1' /* Subscription Type - DB monitoring */
+#define SUBSCRIPTION_TYPE_VIEW '2' /* Subscription Type - view */
+#define SUBSCRIPTION_TYPE_URL '3' /* Subscription Type - URL */
+#define SUBSCRIPTION_KIND_DB 1 /* Subscription Kind - DB monitoring */
+#define SUBSCRIPTION_KIND_VIEW 2 /* Subscription Kind - view */
+#define SUBSCRIPTION_KIND_URL 3 /* Subscription Kind - URL */
+#define SUBSCRIPTION_UNID_ITEM "$HLUnid" /* Subscription UNID for resync */
+#define SUBSCRIPTION_MODIFIED_ITEM "$HLModifiedTime" /* Subscription Modified time for resync */
+
+
+#define SUBSCRIPTION_TARGETFRAME_ITEM "$HLTargetFrame" /* Frame to use for the subscription */
+#define SUBSCRIPTION_FRAME_DB "$HLMonitorFrame" /* Default frame to use for monitor subscriptions */
+#define SUBSCRIPTION_FRAME_VIEW "$HLViewFrame" /* Default frame to use for view subscriptions */
+#define SUBSCRIPTION_FRAME_URL "$HLURLFrame" /* Default frame to use for URL subscriptions */
+
+#define SUBSCRIPTION_URL_ITEM "$HLURL" /* URL for View and URL subscription types */
+
+#define SUBSCRIPTION_FORMULA_ITEM "$HLFormula" /* Monitor Formula */
+#define SUBSCRIPTION_FULLTEXT_ITEM "$HLFulltext" /* Monitor Full Text */
+
+#define SUBSCRIPTION_OPTIONS_ITEM "$HLOptions" /* Monitor Options Flag */
+#define SUBSCRIPTION_OPTIONS_NONE '0' /* Monitor Options Flag - none */
+#define SUBSCRIPTION_OPTIONS_SUMMARY '1' /* Monitor Options Flag - summary */
+#define SUBSCRIPTION_OPTIONS_LOCAL '2' /* Monitor Options Flag - local */
+#define SUBSCRIPTION_OPTIONS_ALL '3' /* Monitor Options Flag - summary&local */
+
+
+#define SUBSCRIPTION_MONITORTYPE_ITEM "$HLMonitorType" /* Monitor Type Flag */
+#define SUBSCRIPTION_MONITORTYPE_FORMULA '1' /* Monitor Type Flag - formula */
+#define SUBSCRIPTION_MONITORTYPE_FULLTEXT '2' /* Monitor Type Flag - full text */
+#define SUBSCRIPTION_DB_ITEM "$HLMonitorDB" /* Database to Monitor */
+#define SUBSCRIPTION_DB_VIEW_ITEM "$HLHeadlineView" /* User specified view for headlines */
+
+#define SUBSCRIPTION_CREATE "$HLCreateSubscription" /* Flag to indicate a partial subscription that */
+ /* needs more information to be created */
+#define SUBSCRIPTION_CREATE_MAIL "mail" /* Creating a special mail file subscription */
+
+#define SUBSCRIPTION_LASTCHECKED_ITEM "$HLMLastChecked" /* Last time the monitor DB was checked */
+#define SUBSCRIPTION_CLIENTID_ITEM "$HLMClientId" /* Last ClientId used */
+#define SUBSCRIPTION_SERVER_ITEM "$HLMServer" /* Original server to be monitored */
+#define SUBSCRIPTION_LASTSERVER_ITEM "$HLMLastServer" /* Last server monitored */
+#define SUBSCRIPTION_LASTPATH_ITEM "$HLMLastPath" /* Last path monitored */
+#define SUBSCRIPTION_MONITORID_ITEM "$HLMMonitorId" /* Last MonitorId used */
+#define SUBSCRIPTION_ERROR_ITEM "$HLMError" /* Last error encountered while initilaizing */
+#define SUBSCRIPTION_SERVER_INFO "$HLMServerInfo" /* Information about last servers monitored */
+
+#define SUBSCRIPTION_DBNAME "Headline.nsf"
+
+
+/* Framesets used in the client */
+#define CLIENT_FRAMESET_LAYOUT "ClientLayout"
+#define CLIENT_FRAMESET_MORE "ClientMore"
+#define CLIENT_FRAMESET_BMPAGE "BMPage"
+
+/* Frameset used in mail */
+#define MAIL_FRAMESET_MAIL "MailFS"
+/* And by calendar */
+#define MAIL_FRAMESET_CALENDAR "CalendarFS"
+/* And by ToDo */
+#define MAIL_FRAMESET_TODO "ToDoFS"
+
+#define Bookmark_IntroPageName "Intro" /* webpage name in bookmark to startup */
+#define Bookmark_StartupFramesetName "Home" /* frameset name in bookmark to startup */
+
+/* Special frame names used by the client */
+
+#define NAVIGATOR_PANE "NotesNavigator"
+#define VIEW_PANE "NotesView"
+#define PREVIEW_PANE "NotesPreview"
+#define EMBEDDED_PREVIEW_PANE "EmbeddedNotesPreview"
+#define USE_DEFAULT_FRAME_TARGETING "UseNotesDefaultFrameTargeting"
+#define CALENDAR_PANE "CalendarView"
+
+/* Names used for various client types which can exist */
+#define DESIGNER_CLIENT "Designer"
+#define ADMIN_CLIENT "Admin"
+#define NOTES_CLIENT "Notes"
+#define DGW_CLIENT "DGW"
+
+/* For use in search results template forms */
+#define SEARCH_QUERY "Query"
+#define SEARCH_START "Start"
+#define SEARCH_COUNT "Count"
+#define SEARCH_HITS "Hits"
+#define SEARCH_TOTAL_HITS "TotalHits"
+#define SEARCH_RESULT_LIMIT "SearchMax"
+#define SEARCH_WV "SearchWV"
+#define SEARCH_THESAURUS "SearchThesaurus"
+#define SEARCH_FUZZY "SearchFuzzy"
+#define SEARCH_ORDER "SearchOrder"
+#define SEARCH_SORT_OPTIONS "SortOptions"
+#define SEARCH_OTHER_OPTIONS "OtherOptions"
+#define SEARCH_BODY "Body"
+#define SEARCH_ENTRYFORM_NAME "SearchEntry"
+#define SEARCH_BODY_WEB ITEM_NAME_EMBEDDED_VIEW
+#define SEARCH_VIEW "SearchView"
+#define SEARCH_SCOPE "Scope"
+
+/* Dublin Core Meta Data */
+#define ITEM_META_TITLE "$$Title"
+#define ITEM_META_CREATOR "$$Creator"
+#define ITEM_META_DESCRIPTION "$$Description"
+#define ITEM_META_TYPE "$$Type"
+#define ITEM_META_CATEGORIES "$$Categories"
+
+/* Document Content view in the Domain Catalog */
+#define CATALOG_VIEW_CONTENT_CATEGORY "$DocumentContent"
+
+/* Shared Resources */
+
+#define ITEM_NAME_IMAGE_DATA "$ImageData"
+#define ITEM_NAME_IMAGE_NAMES "$ImageNames"
+#define ITEM_NAME_IMAGES_WIDE "$ImagesWide"
+#define ITEM_NAME_IMAGES_HIGH "$ImagesHigh"
+#define ITEM_NAME_IMAGES_COLORIZE "$ImagesColorize"
+#define ITEM_NAME_IMAGES_WEB_BROWSER_COMPATIBLE "$WebBrowserCompatible"
+
+#define ITEM_NAME_JAVA_FILES "$JavaFiles"
+
+#define ITEM_NAME_STYLE_SHEET_DATA "$StyleSheetData"
+#define ITEM_NAME_STYLE_SHEET_NAME "$StyleSheetName"
+
+#define ITEM_NAME_FILE_DATA "$FileData"
+#define ITEM_NAME_FILE_NAMES "$FileNames"
+#define ITEM_NAME_FILE_WEBPATH "$WebFilePath"
+#define ITEM_NAME_FILE_EDITFILE "$EditFilePath"
+#define ITEM_NAME_FILE_EDITOR "$FileEditor"
+
+#define ITEM_NAME_FILE_SIZE "$FileSize"
+#define ITEM_NAME_FILE_MIMETYPE "$MimeType"
+#define ITEM_NAME_FILE_MIMECHARSET "$MimeCharSet"
+#define ITEM_NAME_FILE_MODINFO "$FileModDT"
+
+/* defadmin.ntf definitions. */
+
+#define ITEM_TASK_LOAD_LOADCMD "$Task_LoadCmd"
+#define ITEM_TASK_TELLCMD "$Task_TellCmd"
+#define ITEM_TASK_LOAD_NAME "Task_name"
+#define ITEM_TASK_LOAD_FILENAME "Task_filename"
+#define ITEM_TASK_LOAD_DESCRIPTION "Task_description"
+#define ITEM_TASK_LOAD_HASUI "Task_hasLoadUI"
+#define ITEM_TASK_TELL_HASUI "Task_hasTellUI"
+#define ITEM_TASK_MONITOR_NAME "Task_MonitorName"
+#define ITEM_TASK_NO_START_ASP "DisableStartForASP"
+
+/* Special image resource name which will... */
+
+#define IMAGE_DBICON_NAME "$Icon" /* use Database's icon if the image does not exist. */
+#define IMAGE_OLEICON_NAME "$OLEIcon" /* use associated executable's icon if an image dosn't exist */
+
+/* For reading International MIME settings in NAB */
+#define MIMEI18N_FLD_CONFIG_ENABLED "MIMEOptionsEnabled"
+#define MIMEI18N_FLD_PRIMARY_GROUP "CVS_PrimaryGroup"
+#define MIMEI18N_FLD_SECONDARY_GROUPS "CVS_SecondaryGroups"
+#define MIMEI18N_FLD_INP_ALIAS_ALIAS "CVSI_CharsetAlias%d"
+#define MIMEI18N_FLD_INP_ALIAS_ACTUAL "CVSI_CharsetActual%d"
+#define MIMEI18N_FLD_EXP_ALIAS_ALIAS "CVSO_CharsetAlias%d"
+#define MIMEI18N_FLD_EXP_ALIAS_ACTUAL "CVSO_CharsetActual%d"
+#define MIMEI18N_FLD_CHARSET_DETECT "SMTPCharSetDetect"
+#define MIMEI18N_FLD_8BIT_FALLBACK "CVSI_NonMIMECharSet"
+#define MIMEI18N_FLD_INP_GROUP_FONT_PROP "CVSI_%s_F_P"
+#define MIMEI18N_FLD_INP_GROUP_FONT_MONO "CVSI_%s_F_M"
+#define MIMEI18N_FLD_INP_GROUP_FONT_PLAIN "CVSI_%s_F_T"
+#define MIMEI18N_FLD_INP_GROUP_FONT_PLAIN_SIZE "CVSI_%s_F_Size"
+#define MIMEI18N_FLD_INP_GROUP_FONT_HTML_SIZE "CVSI_%s_F_HSize"
+#define MIMEI18N_FLD_EXP_GROUP_CSET_HEAD "CVSO_%s_CS_H"
+#define MIMEI18N_FLD_EXP_GROUP_CSET_BODY "CVSO_%s_CS_B"
+#define MIMEI18N_FLD_EXP_GROUP_ENC_HEAD "CVSO_%s_ENC_H"
+#define MIMEI18N_FLD_EXP_GROUP_ENC_BODY "CVSO_%s_ENC_B"
+/* _FALLBACK_MODE is obsolete, now using _MULTILINGUAL_MODE */
+#define MIMEI18N_FLD_EXP_FALLBACK_MODE "CVS_MLMessageHandling"
+#define MIMEI18N_FLD_EXP_MULTILINGUAL_MODE "CVS_MultilingualMsgHandling"
+#define MIMEI18N_LOCATION_I18N_VIEW "($InternationalMIMESettings)"
+
+/* these are obsolete, now using _MULTILINGUAL_xxx */
+#define MIMEI18N_FALLBACK_UTF8 1
+#define MIMEI18N_FALLBACK_FALLBACK_CHAR 2
+#define MIMEI18N_FALLBACK_UNICODE_ENTITIES 3
+#define MIMEI18N_FALLBACK_REFUSE 4
+
+#define MIMEI18N_MULTILINGUAL_UNICODE 1
+#define MIMEI18N_MULTILINGUAL_BEST_MATCH 2
+
+/*
+ * some standard mime charset names used by the XmlReformatter
+ * and other xml code
+ */
+#define MIME_CHARSET_UTF8 "UTF-8"
+#define MIME_CHARSET_UTF16 "UTF-16"
+#define MIME_CHARSET_UTF16LE "UTF-16LE"
+#define MIME_CHARSET_UTF16BE "UTF-16BE"
+
+/* these are NOTES.INI variables used on the client only -- not server
+ * which has this stuff in a config note
+ */
+#define MIME_MULTILINGUAL_MODE_VAR "MIMEMultilingualMode"
+#define MIME_PROMPT_MULTILINGUAL_VAR "MIMEPromptMultilingual"
+
+/* NOTES.INI variables - show user preference about displaying
+ * some Plug-In related warnings
+ */
+#define PluginsWarningDialog 0
+#define PluginsWarningStatusBar 1
+#define PluginsWarningDoNotShow 2
+
+#define PluginsWarningOption "PluginsWarningOption"
+
+/* see net/resolver.c for use of these */
+#define HTTP_SERVER_LOOKUP_ITEMS "HTTP_HostName\0SMTPFullHostDomain\0HTTP_NormalMode\0HTTP_SSLMode\0HTTP_Port\0HTTP_SSLPort\0HTTP_RedirectUseHTTPS\0HTTP_RedirectServerName\0HTTP_RedirectPortNo\0HTTP_CompanionStack\0Enabled_0\0Protocol_0\0NetAddr_0\0Enabled_1\0Protocol_1\0NetAddr_1\0Enabled_2\0Protocol_2\0NetAddr_2\0Enabled_3\0Protocol_3\0NetAddr_3\0Enabled_4\0Protocol_4\0NetAddr_4\0Enabled_5\0Protocol_5\0NetAddr_5\0Enabled_6\0Protocol_6\0NetAddr_6\0Enabled_7\0Protocol_7\0NetAddr_7"
+#define HTTP_SERVER_LOOKUP_ITEM_COUNT 30
+#define HTTP_SERVER_LOOKUP_ITEM_HTTPHOSTNAME 0
+#define HTTP_SERVER_LOOKUP_ITEM_FULLHOSTNAME 1
+#define HTTP_SERVER_LOOKUP_ITEM_NORMALMODE 2
+#define HTTP_SERVER_LOOKUP_ITEM_SSLMODE 3
+#define HTTP_SERVER_LOOKUP_ITEM_PORT 4
+#define HTTP_SERVER_LOOKUP_ITEM_SSLPORT 5
+#define HTTP_SERVER_LOOKUP_ITEM_REDIRECTUSEHTTPS 6
+#define HTTP_SERVER_LOOKUP_ITEM_REDIRECTSERVERNAME 7
+#define HTTP_SERVER_LOOKUP_ITEM_REDIRECTPORTNO 8
+#define HTTP_SERVER_LOOKUP_ITEM_COMPANIONSTACK 9
+#define HTTP_SERVER_LOOKUP_ITEM_OFFS_START 10
+#define HTTP_SERVER_LOOKUP_ITEM_OFFS_ENABLED 0
+#define HTTP_SERVER_LOOKUP_ITEM_OFFS_PROTOCOL 1
+#define HTTP_SERVER_LOOKUP_ITEM_OFFS_NETADDR 2
+#define HTTP_SERVER_LOOKUP_ITEM_OFFS_MAX 3
+
+/* Fault Recovery Address Book items */
+#define FR_LOOKUP_ITEM_COUNT 7
+#define FR_LOOKUP_ITEMS \
+"FREnbld\0FltRcvryCrsh\0FltRcvryMin\0\
+FltRcvryMax\0FltRcvryNot\0FltRcvryScrpt\0NSDEnbld"
+
+#define FR_ENABLED_ITEM 0
+#define FR_MAX_CRASHES_ITEM 1
+#define FR_CRASH_TIME_LIMIT_ITEM 2
+#define FR_CLEANUPSCRIPT_TIME_LIMIT_ITEM 3
+#define FR_NOTIFY_ITEM 4
+#define FR_CLEANUPSCRIPT_ITEM 5
+#define NSD_ENABLED_ITEM 6
+
+#define FR_LOOKUP_ITEM_COUNT_ADC 2
+#define FR_LOOKUP_ITEMS_ADC "FltRcvryNot\0NSDEnbld"
+#define FR_NOTIFY_ITEM_ADC 0
+#define FR_NSD_ENABLED_ITEM_ADC 1
+
+#define FA_NUM_LOOKUP_ITEMS 2
+#define FA_LOOKUP_ITEMS "MailServer\0MailFile"
+#define FA_LOOKUP_SERVER 0
+#define FA_LOOKUP_FILE 1
+
+#define ADMINP_FR_ENABLED_ITEM "FREnbld"
+#define ADMINP_FR_MAX_CRASHES_ITEM "FltRcvryCrsh"
+#define ADMINP_FR_CRASH_TIME_LIMIT_ITEM "FltRcvryMin"
+#define ADMINP_FR_CLEANUPSCRIPT_TIME_LIMIT_ITEM "FltRcvryMax"
+#define ADMINP_FR_NOTIFY_ITEM "FltRcvryNot"
+#define ADMINP_FR_CLEANUPSCRIPT_ITEM "FltRcvryScrpt"
+#define ADMINP_NSD_ENABLED_ITEM "NSDEnbld"
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* STD_NAME_DEFS */
+
+#if defined(OS400) && (__OS400_TGTVRM__ >= 510)
+#pragma datamodel(pop)
+#endif
+
diff --git a/protocols/LotusNotify/src/debug.cpp b/protocols/LotusNotify/src/debug.cpp
new file mode 100644
index 0000000000..72816e4875
--- /dev/null
+++ b/protocols/LotusNotify/src/debug.cpp
@@ -0,0 +1,41 @@
+#include "stdafx.h"
+#include "debug.h"
+
+HNETLIBUSER netlibHandle;
+
+void logRegister(){
+ // Register netlib user for logging function
+ NETLIBUSER nlu = {};
+ nlu.flags = NUF_UNICODE | NUF_NOOPTIONS;
+ nlu.szSettingsModule = MODULENAME;
+ nlu.szDescriptiveName.w = mir_a2u(MODULENAME);
+ netlibHandle = Netlib_RegisterUser(&nlu);
+}
+
+void logUnregister(){
+ Netlib_CloseHandle(netlibHandle);
+ netlibHandle = nullptr;
+}
+
+void log(const wchar_t* szText){
+
+ if (netlibHandle) {
+ Netlib_LogW(netlibHandle, szText);
+ }
+
+ #ifdef _DEBUG
+ OutputDebugString(szText);
+ #endif //_DEBUG
+}
+
+void log_p(const wchar_t* szText, ...){
+ va_list args;
+ va_start(args, szText);
+ int len = _vscwprintf(szText, args ) + 1; // _vscprintf doesn't count terminating '\0' //!!!!!!!!!!!!!!!!
+ wchar_t* buffer = new wchar_t[len * sizeof(wchar_t)];
+ mir_vsnwprintf(buffer, len, szText, args);
+ va_end(args);
+ log(buffer);
+ delete[] buffer;
+}
+
diff --git a/protocols/LotusNotify/src/debug.h b/protocols/LotusNotify/src/debug.h
new file mode 100644
index 0000000000..838c922564
--- /dev/null
+++ b/protocols/LotusNotify/src/debug.h
@@ -0,0 +1,8 @@
+#pragma once
+
+extern char MODULENAME[];
+
+void logRegister(void);
+void logUnregister(void);
+void log(const wchar_t* szText);
+void log_p(const wchar_t* szText, ...);
diff --git a/protocols/LotusNotify/src/lotusnotes.cpp b/protocols/LotusNotify/src/lotusnotes.cpp
new file mode 100644
index 0000000000..adc60a7bdf
--- /dev/null
+++ b/protocols/LotusNotify/src/lotusnotes.cpp
@@ -0,0 +1,84 @@
+#include "stdafx.h"
+#include "lotusnotes.h"
+
+OSPATHNETCONSTRUCT OSPathNetConstruct1;
+NOTESINITEXTENDED NotesInitExtended1;
+NSFDBOPEN NSFDbOpen1;
+SECKFMGETUSERNAME SECKFMGetUserName1;
+NSFDBGETUNREADNOTETABLE NSFDbGetUnreadNoteTable1;
+NSFDBUPDATEUNREAD NSFDbUpdateUnread1;
+IDSCAN IDScan1;
+NSFNOTEOPEN NSFNoteOpen1;
+NSFDBGETNOTEINFO NSFDbGetNoteInfo1;
+NSFITEMGETTEXT NSFItemGetText1;
+NSFITEMGETTIME NSFItemGetTime1;
+CONVERTTIMEDATETOTEXT ConvertTIMEDATEToText1;
+OSTRANSLATE OSTranslate1;
+MAILGETMESSAGEATTACHMENTINFO MailGetMessageAttachmentInfo1;
+NSFNOTECLOSE NSFNoteClose1;
+IDDESTROYTABLE IDDestroyTable1;
+NSFDBCLOSE NSFDbClose1;
+OSLOADSTRING OSLoadString1;
+NOTESTERM NotesTerm1;
+OSGETENVIRONMENTSTRING OSGetEnvironmentString1;
+OSSETENVIRONMENTVARIABLE OSSetEnvironmentVariable1;
+NSGETSERVERLIST NSGetServerList1;
+OSLOCKOBJECT OSLockObject1;
+OSUNLOCKOBJECT OSUnlockObject1;
+OSMEMFREE OSMemFree1;
+EMREGISTER EMRegister1;
+EMDEREGISTER EMDeregister1;
+NOTESINITTHREAD NotesInitThread1;
+NOTESTERMTHREAD NotesTermThread1;
+
+BOOL HookLotusFunctions()
+{
+ return (
+ (OSPathNetConstruct1 = (OSPATHNETCONSTRUCT)GetProcAddress(hLotusDll, "OSPathNetConstruct"))
+ && (NotesInitExtended1 = (NOTESINITEXTENDED)GetProcAddress(hLotusDll, "NotesInitExtended"))
+ && (NSFDbOpen1 = (NSFDBOPEN)GetProcAddress(hLotusDll, "NSFDbOpen"))
+ && (SECKFMGetUserName1 = (SECKFMGETUSERNAME)GetProcAddress(hLotusDll, "SECKFMGetUserName"))
+ && (NSFDbGetUnreadNoteTable1 = (NSFDBGETUNREADNOTETABLE)GetProcAddress(hLotusDll, "NSFDbGetUnreadNoteTable"))
+ && (NSFDbUpdateUnread1 = (NSFDBUPDATEUNREAD)GetProcAddress(hLotusDll, "NSFDbUpdateUnread"))
+ && (IDScan1 = (IDSCAN)GetProcAddress(hLotusDll, "IDScan"))
+ && (NSFNoteOpen1 = (NSFNOTEOPEN)GetProcAddress(hLotusDll, "NSFNoteOpen"))
+ && (NSFDbGetNoteInfo1 = (NSFDBGETNOTEINFO)GetProcAddress(hLotusDll, "NSFDbGetNoteInfo"))
+ && (NSFItemGetText1 = (NSFITEMGETTEXT)GetProcAddress(hLotusDll, "NSFItemGetText"))
+ && (NSFItemGetTime1 = (NSFITEMGETTIME)GetProcAddress(hLotusDll, "NSFItemGetTime"))
+ && (ConvertTIMEDATEToText1 = (CONVERTTIMEDATETOTEXT)GetProcAddress(hLotusDll, "ConvertTIMEDATEToText"))
+ && (OSTranslate1 = (OSTRANSLATE)GetProcAddress(hLotusDll, "OSTranslate"))
+ && (MailGetMessageAttachmentInfo1 = (MAILGETMESSAGEATTACHMENTINFO)GetProcAddress(hLotusDll, "MailGetMessageAttachmentInfo"))
+ && (NSFNoteClose1 = (NSFNOTECLOSE)GetProcAddress(hLotusDll, "NSFNoteClose"))
+ && (IDDestroyTable1 = (IDDESTROYTABLE)GetProcAddress(hLotusDll, "IDDestroyTable"))
+ && (NSFDbClose1 = (NSFDBCLOSE)GetProcAddress(hLotusDll, "NSFDbClose"))
+ && (OSLoadString1 = (OSLOADSTRING)GetProcAddress(hLotusDll, "OSLoadString"))
+ && (NotesTerm1 = (NOTESTERM)GetProcAddress(hLotusDll, "NotesTerm"))
+ && (OSGetEnvironmentString1 = (OSGETENVIRONMENTSTRING)GetProcAddress(hLotusDll, "OSGetEnvironmentString"))
+ && (OSSetEnvironmentVariable1 = (OSSETENVIRONMENTVARIABLE)GetProcAddress(hLotusDll, "OSSetEnvironmentVariable"))
+ && (NSGetServerList1 = (NSGETSERVERLIST)GetProcAddress(hLotusDll, "NSGetServerList"))
+ && (OSLockObject1 = (OSLOCKOBJECT)GetProcAddress(hLotusDll, "OSLockObject"))
+ && (OSUnlockObject1 = (OSUNLOCKOBJECT)GetProcAddress(hLotusDll, "OSUnlockObject"))
+ && (OSMemFree1 = (OSMEMFREE)GetProcAddress(hLotusDll, "OSMemFree"))
+ && (EMRegister1 = (EMREGISTER)GetProcAddress(hLotusDll, "EMRegister"))
+ && (EMDeregister1 = (EMDEREGISTER)GetProcAddress(hLotusDll, "EMDeregister"))
+ && (NotesInitThread1 = (NOTESINITTHREAD)GetProcAddress(hLotusDll, "NotesInitThread"))
+ && (NotesTermThread1 = (NOTESTERMTHREAD)GetProcAddress(hLotusDll, "NotesTermThread"))
+ ) ? TRUE : FALSE;
+}
+
+void GetLotusPath(wchar_t *sTemp, DWORD size)
+{
+ DWORD rc;
+ HKEY dmKey;
+
+ rc = RegOpenKeyEx( HKEY_LOCAL_MACHINE , TEXT("Software\\Lotus\\Notes") ,0, KEY_QUERY_VALUE, &dmKey );
+
+ if (rc != ERROR_SUCCESS) {
+ return;
+ }
+
+ RegQueryValueEx( dmKey, TEXT("Path"), nullptr, nullptr, (BYTE*)sTemp, &size );
+ RegCloseKey(dmKey);
+ return;
+}
+
diff --git a/protocols/LotusNotify/src/lotusnotes.h b/protocols/LotusNotify/src/lotusnotes.h
new file mode 100644
index 0000000000..620aab2822
--- /dev/null
+++ b/protocols/LotusNotify/src/lotusnotes.h
@@ -0,0 +1,176 @@
+#pragma once
+
+
+extern HINSTANCE hLotusDll;
+
+typedef STATUS (CALLBACK *OSPATHNETCONSTRUCT)(
+ const char far *PortName,
+ const char far *ServerName,
+ const char far *FileName,
+ char far *retPathName);
+extern OSPATHNETCONSTRUCT OSPathNetConstruct1;
+
+typedef STATUS (CALLBACK LNPUBLIC *NOTESINITEXTENDED)(
+ int argc,
+ char far * far *argv);
+extern NOTESINITEXTENDED NotesInitExtended1;
+
+typedef STATUS (CALLBACK LNPUBLIC *NSFDBOPEN)(
+ const char far *PathName,
+ DBHANDLE far *rethDB);
+extern NSFDBOPEN NSFDbOpen1;
+
+typedef STATUS (CALLBACK LNPUBLIC *SECKFMGETUSERNAME)(
+ char far *retUserName);
+extern SECKFMGETUSERNAME SECKFMGetUserName1;
+
+typedef STATUS (CALLBACK LNPUBLIC *NSFDBGETUNREADNOTETABLE)(
+ DBHANDLE hDB,
+ char far *UserName,
+ WORD UserNameLength,
+ BOOL fCreateIfNotAvailable,
+ HANDLE far *rethUnreadList);
+extern NSFDBGETUNREADNOTETABLE NSFDbGetUnreadNoteTable1;
+
+typedef STATUS (CALLBACK LNPUBLIC *NSFDBUPDATEUNREAD)(
+ DBHANDLE hDataDB,
+ HANDLE hUnreadList);
+extern NSFDBUPDATEUNREAD NSFDbUpdateUnread1;
+
+typedef BOOL (CALLBACK LNPUBLIC *IDSCAN)(
+ HANDLE hTable,///DHANDLE
+ BOOL fFirst,
+ DWORD far *retID);
+extern IDSCAN IDScan1;
+
+typedef STATUS (CALLBACK LNPUBLIC *NSFNOTEOPEN)(
+ DBHANDLE db_handle,
+ NOTEID note_id,
+ WORD open_flags,
+ NOTEHANDLE far *note_handle);
+extern NSFNOTEOPEN NSFNoteOpen1;
+
+typedef STATUS (CALLBACK LNPUBLIC *NSFDBGETNOTEINFO)(
+ DBHANDLE hDb,
+ NOTEID NoteID,
+ OID far *retNoteOID,
+ TIMEDATE far *retModified,
+ WORD far *retNoteClass);
+extern NSFDBGETNOTEINFO NSFDbGetNoteInfo1;
+
+typedef WORD (CALLBACK LNPUBLIC *NSFITEMGETTEXT)(
+ NOTEHANDLE note_handle,
+ const char far *item_name,
+ char far *item_text,
+ WORD text_len);
+extern NSFITEMGETTEXT NSFItemGetText1;
+
+typedef BOOL (CALLBACK LNPUBLIC *NSFITEMGETTIME)(
+ NOTEHANDLE note_handle,
+ const char far *td_item_name,
+ TIMEDATE far *td_item_value);
+extern NSFITEMGETTIME NSFItemGetTime1;
+
+typedef STATUS (CALLBACK LNPUBLIC *CONVERTTIMEDATETOTEXT)(
+ const void far *IntlFormat,
+ const TFMT far *TextFormat,
+ const TIMEDATE far *InputTime,
+ char far *retTextBuffer,
+ WORD TextBufferLength,
+ WORD far *retTextLength);
+extern CONVERTTIMEDATETOTEXT ConvertTIMEDATEToText1;
+
+typedef WORD (CALLBACK LNPUBLIC *OSTRANSLATE)(
+ WORD TranslateMode,
+ const char far *In,
+ WORD InLength,
+ char far *Out,
+ WORD OutLength);
+extern OSTRANSLATE OSTranslate1;
+
+typedef BOOL (CALLBACK LNPUBLIC *MAILGETMESSAGEATTACHMENTINFO)(
+ HANDLE hMessage, ///DHANDLE
+ WORD Num,
+ BLOCKID far *bhItem,
+ char far *FileName,
+ DWORD far *FileSize,
+ WORD far *FileAttributes,
+ WORD far *FileHostType,
+ TIMEDATE *FileCreated,
+ TIMEDATE far *FileModified);
+extern MAILGETMESSAGEATTACHMENTINFO MailGetMessageAttachmentInfo1;
+
+typedef STATUS (CALLBACK LNPUBLIC *NSFNOTECLOSE)(
+ NOTEHANDLE note_handle);
+extern NSFNOTECLOSE NSFNoteClose1;
+
+typedef STATUS (CALLBACK LNPUBLIC *IDDESTROYTABLE)(
+ HANDLE hTable); ///DHANDLE
+extern IDDESTROYTABLE IDDestroyTable1;
+
+typedef STATUS (CALLBACK LNPUBLIC *NSFDBCLOSE)(
+ DBHANDLE hDB);
+extern NSFDBCLOSE NSFDbClose1;
+
+typedef WORD (CALLBACK LNPUBLIC *OSLOADSTRING)(
+ HMODULE hModule,
+ STATUS StringCode,
+ char far *retBuffer,
+ WORD BufferLength);
+extern OSLOADSTRING OSLoadString1;
+
+typedef void (CALLBACK LNPUBLIC *NOTESTERM)(void);
+extern NOTESTERM NotesTerm1;
+
+typedef BOOL (CALLBACK LNPUBLIC *OSGETENVIRONMENTSTRING)(
+ const char far *VariableName,
+ char far *retValueBuffer,
+ WORD BufferLength);
+extern OSGETENVIRONMENTSTRING OSGetEnvironmentString1;
+
+typedef void (CALLBACK LNPUBLIC *OSSETENVIRONMENTVARIABLE)(
+ const char far *VariableName,
+ const char far *Value);
+extern OSSETENVIRONMENTVARIABLE OSSetEnvironmentVariable1;
+
+typedef STATUS (CALLBACK LNPUBLIC *NSGETSERVERLIST)(
+ char far *pPortName,
+ HANDLE far *retServerTextList); ///DHANDLE
+extern NSGETSERVERLIST NSGetServerList1;
+
+typedef void far* (CALLBACK LNPUBLIC *OSLOCKOBJECT)(
+ HANDLE Handle); ///DHANDLE
+extern OSLOCKOBJECT OSLockObject1;
+
+typedef BOOL (CALLBACK LNPUBLIC *OSUNLOCKOBJECT)(
+ HANDLE Handle); ///DHANDLE
+extern OSUNLOCKOBJECT OSUnlockObject1;
+
+typedef STATUS (CALLBACK LNPUBLIC *OSMEMFREE)(
+ HANDLE Handle); ///DHANDLE
+extern OSMEMFREE OSMemFree1;
+
+typedef STATUS (CALLBACK LNPUBLIC *EMREGISTER)(
+ EID EmID,
+ DWORD Flags,
+ EMHANDLER Proc,
+ WORD RecursionID,
+ HEMREGISTRATION far *rethRegistration);
+extern EMREGISTER EMRegister1;
+
+typedef STATUS (CALLBACK LNPUBLIC *EMDEREGISTER)(
+ HANDLE Handle); ///HEMREGISTRATION
+extern EMDEREGISTER EMDeregister1;
+
+typedef STATUS (CALLBACK LNPUBLIC *NOTESINITTHREAD)(void);
+extern NOTESINITTHREAD NotesInitThread1;
+
+typedef void (CALLBACK LNPUBLIC *NOTESTERMTHREAD)(void);
+extern NOTESTERMTHREAD NotesTermThread1;
+
+
+
+
+BOOL HookLotusFunctions();
+void GetLotusPath(wchar_t *sTemp, DWORD size);
+
diff --git a/protocols/LotusNotify/src/resource.h b/protocols/LotusNotify/src/resource.h
new file mode 100644
index 0000000000..4c9b28d25c
--- /dev/null
+++ b/protocols/LotusNotify/src/resource.h
@@ -0,0 +1,52 @@
+//{{NO_DEPENDENCIES}}
+// Microsoft Visual C++ generated include file.
+// Used by LotusNotify.rc
+//
+#define IDI_ICON1 101
+#define IDD_OPT_LOTUS_MISC 102
+#define IDI_ICON2 103
+#define IDD_OPT_LOTUS_CONECTION 104
+#define IDD_OPT_LOTUS_POPUP 105
+#define IDC_SERVER 1001
+#define IDC_DATABASE 1002
+#define IDC_DATABASE2 1003
+#define IDC_INTERVAL 1003
+#define IDC_COMMAND 1004
+#define IDC_COMMAND2 1005
+#define IDC_PARAMETERS 1005
+#define IDC_ONCEONLY 1006
+#define IDC_SHOWERROR 1007
+#define IDC_SERVERSEC 1008
+#define IDC_SETCOLOURS 1009
+#define IDC_INTERVAL1 1010
+#define IDC_BGCOLOR 1011
+#define IDC_FGCOLOR 1012
+#define IDC_NONCLICKEDONLY 1013
+#define IDC_NEWEST 1014
+#define IDC_BUTTON_DETECT 1015
+#define IDC_STATUS 1016
+#define IDC_BUTTON_CLEAR 1019
+#define IDC_FILTER_SENDER 1020
+#define IDC_FILTER_SUBJECT 1021
+#define IDC_BUTTON_ADD_SENDER_FILTER 1022
+#define IDC_BUTTON_ADD_SUBJECT_FILTER 1023
+#define IDC_BUTTON_REMOVE_SENDER_FILTER 1024
+#define IDC_BUTTON_REMOVE_SUBJECT_FILTER 1025
+#define IDC_PASSWORD 1026
+#define IDC_BUTTON_CHECK 1027
+#define IDC_FILTER_TO 1028
+#define IDC_BUTTON_ADD_TO_FILTER 1029
+#define IDC_BUTTON_REMOVE_TO_FILTER 1030
+#define IDC_KEEP_CONNEXION_ON_ERROR 1031
+#define IDC_REMEMBEREVENNONCLICKED 1032
+
+// Next default values for new objects
+//
+#ifdef APSTUDIO_INVOKED
+#ifndef APSTUDIO_READONLY_SYMBOLS
+#define _APS_NEXT_RESOURCE_VALUE 106
+#define _APS_NEXT_COMMAND_VALUE 40001
+#define _APS_NEXT_CONTROL_VALUE 1033
+#define _APS_NEXT_SYMED_VALUE 101
+#endif
+#endif
diff --git a/protocols/LotusNotify/src/stdafx.cxx b/protocols/LotusNotify/src/stdafx.cxx
new file mode 100644
index 0000000000..1b563fc866
--- /dev/null
+++ b/protocols/LotusNotify/src/stdafx.cxx
@@ -0,0 +1,18 @@
+/*
+Copyright (C) 2012-19 Miranda NG team (https://miranda-ng.org)
+
+This program is free software; you can redistribute it and/or
+modify it under the terms of the GNU General Public License
+as published by the Free Software Foundation version 2
+of the License.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "stdafx.h" \ No newline at end of file
diff --git a/protocols/LotusNotify/src/stdafx.h b/protocols/LotusNotify/src/stdafx.h
new file mode 100644
index 0000000000..e4d7c40456
--- /dev/null
+++ b/protocols/LotusNotify/src/stdafx.h
@@ -0,0 +1,38 @@
+#pragma once
+
+
+// Windows headers
+#include <windows.h>
+#include <commctrl.h>
+#include <assert.h>
+
+// Miranda headers
+//LotusNotify.h
+
+#include <m_core.h>
+#include <win2k.h>
+#include <newpluginapi.h>
+#include <m_clistint.h>
+#include <m_skin.h>
+#include <m_langpack.h>
+#include <m_options.h>
+#include <m_popup.h>
+#include <m_utils.h>
+#include <m_protosvc.h>
+#include <m_system.h>
+#include <m_netlib.h>
+
+// Notesapi headers
+#define W32
+#if defined(_WIN64)
+#define _AMD64_
+#endif
+#include "cnotesapi/include/global.h"
+#include "cnotesapi/include/osmisc.h"
+#include "cnotesapi/include/nsfdb.h"
+#include "cnotesapi/include/nsfsearc.h"
+#include "cnotesapi/include/names.h"
+#include "cnotesapi/include/osenv.h"
+#include "cnotesapi/include/extmgr.h"
+#include "cnotesapi/include/bsafeerr.h"
+#include "cnotesapi/include/nsferr.h"
diff --git a/protocols/LotusNotify/src/version.h b/protocols/LotusNotify/src/version.h
new file mode 100644
index 0000000000..96d7cf4283
--- /dev/null
+++ b/protocols/LotusNotify/src/version.h
@@ -0,0 +1,15 @@
+#define __MAJOR_VERSION 0
+#define __MINOR_VERSION 1
+#define __RELEASE_NUM 23
+#define __BUILD_NUM 0
+
+#include <stdver.h>
+
+#define __PLUGIN_NAME "LotusNotify"
+#define __FILENAME "LotusNotify.dll"
+#define __DESCRIPTION "Notify about new mail in Lotus Database"
+#define __FILECOMMENTS "Miranda NG Plugin - Notify about new mail in Lotus Database"
+#define __AUTHOR "MaKaRSoFT - http://maciej.wycik.pl/miranda"
+#define __AUTHORWEB "https://miranda-ng.org/p/LotusNotify/"
+#define __COPYRIGHT "© 2006 MaKaRSoFT, 2013 wsx22, 2015 pepinlebref"
+#define __LEGALTRADEMARKS "Freeware"
diff --git a/protocols/NewsAggregator/NewsAggregator.vcxproj b/protocols/NewsAggregator/NewsAggregator.vcxproj
new file mode 100644
index 0000000000..3b427aec7d
--- /dev/null
+++ b/protocols/NewsAggregator/NewsAggregator.vcxproj
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project DefaultTargets="Build" ToolsVersion="15.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>
+ <ImportGroup Label="PropertySheets">
+ <Import Project="$(ProjectDir)..\..\build\vc.common\plugin.props" />
+ </ImportGroup>
+</Project> \ No newline at end of file
diff --git a/protocols/NewsAggregator/NewsAggregator.vcxproj.filters b/protocols/NewsAggregator/NewsAggregator.vcxproj.filters
new file mode 100644
index 0000000000..5ef6c526f1
--- /dev/null
+++ b/protocols/NewsAggregator/NewsAggregator.vcxproj.filters
@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <Import Project="$(ProjectDir)..\..\build\vc.common\common.filters" />
+</Project> \ No newline at end of file
diff --git a/protocols/NewsAggregator/Res/AddFeed.ico b/protocols/NewsAggregator/Res/AddFeed.ico
new file mode 100644
index 0000000000..6a7e9af31e
--- /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..9a720c2e07
--- /dev/null
+++ b/protocols/NewsAggregator/Res/CheckALL.ico
Binary files differ
diff --git a/protocols/NewsAggregator/Res/Disabled.ico b/protocols/NewsAggregator/Res/Disabled.ico
new file mode 100644
index 0000000000..1055879373
--- /dev/null
+++ b/protocols/NewsAggregator/Res/Disabled.ico
Binary files differ
diff --git a/protocols/NewsAggregator/Res/Enabled.ico b/protocols/NewsAggregator/Res/Enabled.ico
new file mode 100644
index 0000000000..b62ed83376
--- /dev/null
+++ b/protocols/NewsAggregator/Res/Enabled.ico
Binary files differ
diff --git a/protocols/NewsAggregator/Res/Export.ico b/protocols/NewsAggregator/Res/Export.ico
new file mode 100644
index 0000000000..945815b772
--- /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..bbe29ca82f
--- /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..75c9ff1aa3
--- /dev/null
+++ b/protocols/NewsAggregator/Res/Main.ico
Binary files differ
diff --git a/protocols/NewsAggregator/Res/Resource.rc b/protocols/NewsAggregator/Res/Resource.rc
new file mode 100644
index 0000000000..eb7688640f
--- /dev/null
+++ b/protocols/NewsAggregator/Res/Resource.rc
@@ -0,0 +1,184 @@
+// Microsoft Visual C++ generated resource script.
+//
+#include "..\src\resource.h"
+
+#define APSTUDIO_READONLY_SYMBOLS
+/////////////////////////////////////////////////////////////////////////////
+//
+// Generated from the TEXTINCLUDE 2 resource.
+//
+#include "afxres.h"
+
+/////////////////////////////////////////////////////////////////////////////
+#undef APSTUDIO_READONLY_SYMBOLS
+
+/////////////////////////////////////////////////////////////////////////////
+// Russian (Russia) 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 "Main.ico"
+IDI_CHECKALL ICON "CheckAll.ico"
+IDI_ADDFEED ICON "AddFeed.ico"
+IDI_IMPORTFEEDS ICON "Import.ico"
+IDI_EXPORTFEEDS ICON "Export.ico"
+IDI_ENABLED ICON "Enabled.ico"
+IDI_DISABLED ICON "Disabled.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_BORDER | 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_IMPORT,252,204,50,14
+ PUSHBUTTON "Export",IDC_EXPORT,252,219,50,14
+ CONTROL "Retrieve news at startup",IDC_STARTUPRETRIEVE,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,9,205,203,10
+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,160,16
+ PUSHBUTTON "Reset",IDC_RESET,192,184,45,14
+ PUSHBUTTON "?",IDC_TAGHELP,175,184,15,14
+ LTEXT "0 - check manually",IDC_STATIC,100,55,78,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
+
+IDD_AUTHENTICATION DIALOGEX 0, 0, 211, 106
+STYLE DS_SETFONT | DS_MODALFRAME | DS_3DLOOK | DS_FIXEDSYS | DS_CENTER | WS_POPUP | WS_VISIBLE | WS_CAPTION | WS_SYSMENU
+EXSTYLE WS_EX_CONTROLPARENT
+CAPTION "Authentication"
+FONT 8, "MS Shell Dlg", 0, 0, 0x1
+BEGIN
+ CTEXT "Feed name",IDC_FEEDNAME,7,5,196,8
+ LTEXT "This feed seems to need authentication. Please fill username and password fields:",IDC_STATIC,7,19,196,22
+ RTEXT "Username",IDC_STATIC,25,49,42,8
+ EDITTEXT IDC_FEEDUSERNAME,71,46,80,14,ES_AUTOHSCROLL
+ RTEXT "Password",IDC_STATIC,25,66,42,8
+ EDITTEXT IDC_FEEDPASSWORD,71,63,80,14,ES_PASSWORD | ES_AUTOHSCROLL
+ DEFPUSHBUTTON "OK",IDOK,98,87,50,14
+ PUSHBUTTON "Cancel",IDCANCEL,153,87,50,14
+END
+
+IDD_FEEDEXPORT DIALOGEX 0, 0, 275, 138
+STYLE DS_SETFONT | DS_MODALFRAME | DS_3DLOOK | DS_FIXEDSYS | DS_CENTER | WS_MAXIMIZEBOX | WS_POPUP | WS_VISIBLE | WS_CAPTION | WS_SYSMENU
+EXSTYLE WS_EX_ACCEPTFILES | WS_EX_CONTROLPARENT
+CAPTION "Export"
+FONT 8, "MS Shell Dlg", 0, 0, 0x1
+BEGIN
+ LTEXT "Available feeds:",IDC_STATIC,6,6,100,8
+ LTEXT "Feeds to be exported:",IDC_STATIC,150,6,98,8
+ LISTBOX IDC_FEEDSLIST,6,18,120,98,LBS_SORT | LBS_NOINTEGRALHEIGHT | LBS_EXTENDEDSEL | WS_VSCROLL | WS_HSCROLL | WS_TABSTOP
+ LISTBOX IDC_FEEDSEXPORTLIST,150,18,120,98,LBS_SORT | LBS_NOINTEGRALHEIGHT | LBS_EXTENDEDSEL | WS_VSCROLL | WS_HSCROLL | WS_TABSTOP
+ PUSHBUTTON "->",IDC_ADDFEED,129,24,17,14
+ PUSHBUTTON "<-",IDC_REMOVEFEED,129,40,17,14
+ PUSHBUTTON "&Export",IDOK,164,120,50,14
+ PUSHBUTTON "&Close",IDCANCEL,220,120,50,14
+ PUSHBUTTON "->>",IDC_ADDALLFEEDS,129,78,17,14
+ PUSHBUTTON "<<-",IDC_REMOVEALLFEEDS,129,95,17,14
+END
+
+IDD_FEEDIMPORT DIALOGEX 0, 0, 276, 161
+STYLE DS_SETFONT | DS_MODALFRAME | DS_3DLOOK | DS_FIXEDSYS | DS_CENTER | WS_MAXIMIZEBOX | WS_POPUP | WS_VISIBLE | WS_CAPTION | WS_SYSMENU
+EXSTYLE WS_EX_ACCEPTFILES | WS_EX_CONTROLPARENT
+CAPTION "Import"
+FONT 8, "MS Shell Dlg", 0, 0, 0x1
+BEGIN
+ LTEXT "Import from:",IDC_STATIC,6,7,47,8
+ EDITTEXT IDC_IMPORTFILEPATH,59,5,186,14,ES_AUTOHSCROLL | ES_READONLY
+ PUSHBUTTON "...",IDC_BROWSEIMPORTFILE,248,5,22,14
+ LTEXT "Available feeds:",IDC_STATIC,6,26,100,8
+ LTEXT "Feeds to be imported:",IDC_STATIC,150,26,101,8
+ LISTBOX IDC_FEEDSLIST,6,38,120,98,LBS_SORT | LBS_NOINTEGRALHEIGHT | LBS_EXTENDEDSEL | WS_VSCROLL | WS_HSCROLL | WS_TABSTOP
+ LISTBOX IDC_FEEDSIMPORTLIST,150,38,120,98,LBS_SORT | LBS_NOINTEGRALHEIGHT | LBS_EXTENDEDSEL | WS_VSCROLL | WS_HSCROLL | WS_TABSTOP
+ PUSHBUTTON "->",IDC_ADDFEED,129,47,17,14
+ PUSHBUTTON "<-",IDC_REMOVEFEED,129,63,17,14
+ PUSHBUTTON "&Import",IDOK,165,141,50,14
+ PUSHBUTTON "&Close",IDCANCEL,220,141,50,14
+ PUSHBUTTON "->>",IDC_ADDALLFEEDS,129,97,17,14
+ PUSHBUTTON "<<-",IDC_REMOVEALLFEEDS,129,113,17,14
+END
+
+
+#ifdef APSTUDIO_INVOKED
+/////////////////////////////////////////////////////////////////////////////
+//
+// TEXTINCLUDE
+//
+
+1 TEXTINCLUDE
+BEGIN
+ "..\\src\\resource.h\0"
+END
+
+2 TEXTINCLUDE
+BEGIN
+ "#include ""afxres.h""\r\n"
+ "\0"
+END
+
+3 TEXTINCLUDE
+BEGIN
+ "\r\n"
+ "\0"
+END
+
+#endif // APSTUDIO_INVOKED
+
+
+#endif // Russian (Russia) resources
+/////////////////////////////////////////////////////////////////////////////
+
+
+
+#ifndef APSTUDIO_INVOKED
+/////////////////////////////////////////////////////////////////////////////
+//
+// Generated from the TEXTINCLUDE 3 resource.
+//
+
+
+/////////////////////////////////////////////////////////////////////////////
+#endif // not APSTUDIO_INVOKED
+
diff --git a/protocols/NewsAggregator/Res/Version.rc b/protocols/NewsAggregator/Res/Version.rc
new file mode 100644
index 0000000000..5a5ddd63ed
--- /dev/null
+++ b/protocols/NewsAggregator/Res/Version.rc
@@ -0,0 +1,9 @@
+// Microsoft Visual C++ generated resource script.
+//
+#ifdef APSTUDIO_INVOKED
+#error this file is not editable by Microsoft Visual C++
+#endif //APSTUDIO_INVOKED
+
+#include "..\src\version.h"
+
+#include "..\..\build\Version.rc"
diff --git a/protocols/NewsAggregator/Src/Authentication.cpp b/protocols/NewsAggregator/Src/Authentication.cpp
new file mode 100644
index 0000000000..35c5cb36bd
--- /dev/null
+++ b/protocols/NewsAggregator/Src/Authentication.cpp
@@ -0,0 +1,101 @@
+/*
+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 "stdafx.h"
+
+void CreateAuthString(char *auth, MCONTACT hContact, CFeedEditor *pDlg)
+{
+ wchar_t *tlogin = nullptr, *tpass = nullptr;
+ if (hContact && g_plugin.getByte(hContact, "UseAuth")) {
+ tlogin = g_plugin.getWStringA(hContact, "Login");
+ tpass = g_plugin.getWStringA(hContact, "Password");
+ }
+ else if (pDlg && pDlg->m_useauth.IsChecked()) {
+ tlogin = pDlg->m_login.GetText();
+ tpass = pDlg->m_password.GetText();
+ }
+ char *user = mir_u2a(tlogin), *pass = mir_u2a(tpass);
+
+ char str[MAX_PATH];
+ int len = mir_snprintf(str, "%s:%s", user, pass);
+ mir_free(user);
+ mir_free(pass);
+ mir_free(tlogin);
+ mir_free(tpass);
+
+ mir_snprintf(auth, 250, "Basic %s", ptrA(mir_base64_encode(str, (size_t)len)));
+}
+
+CAuthRequest::CAuthRequest(CFeedEditor *pDlg, MCONTACT hContact) :
+ CSuper(g_plugin, IDD_AUTHENTICATION),
+ m_feedname(this, IDC_FEEDNAME), m_username(this, IDC_FEEDUSERNAME),
+ m_password(this, IDC_FEEDPASSWORD), m_ok(this, IDOK)
+{
+ m_pDlg = pDlg;
+ m_hContact = hContact;
+ m_ok.OnClick = Callback(this, &CAuthRequest::OnOk);
+}
+
+bool CAuthRequest::OnInitDialog()
+{
+ if (m_pDlg) {
+ ptrW strfeedtitle(m_pDlg->m_feedtitle.GetText());
+
+ if (strfeedtitle)
+ m_feedname.SetText(strfeedtitle);
+ else {
+ ptrW strfeedurl(m_pDlg->m_feedurl.GetText());
+ m_feedname.SetText(strfeedurl);
+ }
+ }
+ else if (m_hContact) {
+ ptrW ptszNick(g_plugin.getWStringA(m_hContact, "Nick"));
+ if (!ptszNick)
+ ptszNick = g_plugin.getWStringA(m_hContact, "URL");
+ if (ptszNick)
+ m_feedname.SetText(ptszNick);
+ }
+ return true;
+}
+
+void CAuthRequest::OnOk(CCtrlBase*)
+{
+ ptrW strfeedusername(m_username.GetText());
+ if (!strfeedusername || mir_wstrcmp(strfeedusername, L"") == 0) {
+ MessageBox(m_hwnd, TranslateT("Enter your username"), TranslateT("Error"), MB_OK | MB_ICONERROR);
+ return;
+ }
+ ptrA strfeedpassword(m_password.GetTextA());
+ if (!strfeedpassword || mir_strcmp(strfeedpassword, "") == 0) {
+ MessageBox(m_hwnd, TranslateT("Enter your password"), TranslateT("Error"), MB_OK | MB_ICONERROR);
+ return;
+ }
+ if (m_pDlg) {
+ m_pDlg->m_useauth.SetState(1);
+ m_pDlg->m_login.Enable(1);
+ m_pDlg->m_password.Enable(1);
+ m_pDlg->m_login.SetText(strfeedusername);
+ m_pDlg->m_password.SetTextA(strfeedpassword);
+ }
+ else if (m_hContact) {
+ g_plugin.setByte(m_hContact, "UseAuth", 1);
+ g_plugin.setWString(m_hContact, "Login", strfeedusername);
+ g_plugin.setString(m_hContact, "Password", strfeedpassword);
+ }
+}
diff --git a/protocols/NewsAggregator/Src/CheckFeed.cpp b/protocols/NewsAggregator/Src/CheckFeed.cpp
new file mode 100644
index 0000000000..87282451f4
--- /dev/null
+++ b/protocols/NewsAggregator/Src/CheckFeed.cpp
@@ -0,0 +1,473 @@
+/*
+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 "stdafx.h"
+
+static CMStringA DetectEncoding(const TiXmlDocument &doc)
+{
+ auto *pChild = doc.FirstChild();
+ if (pChild)
+ if (auto *pDecl = pChild->ToDeclaration())
+ if (auto *pVal = pDecl->Value())
+ if (!memcmp(pVal, "xml", 3)) {
+ const char *p1 = strstr(pVal, "encoding=\""), *p2 = 0;
+ if (p1) {
+ p1 += 10;
+ p2 = strchr(p1, '\"');
+ }
+ if (p1 && p2)
+ return CMStringA(p1, int(p2-p1));
+ }
+
+ return CMStringA();
+}
+
+static wchar_t* EncodeResult(const char *szString, const CMStringA &szEncoding)
+{
+ if (szEncoding == "koi8-r")
+ return mir_a2u_cp(szString, 20866);
+ if (szEncoding == "windows-1251")
+ return mir_a2u_cp(szString, 1251);
+
+ return mir_utf8decodeW(szString);
+}
+
+static void SetAvatar(MCONTACT hContact, const char *pszValue)
+{
+ Utf2T url(pszValue);
+ g_plugin.setWString(hContact, "ImageURL", url);
+
+ PROTO_AVATAR_INFORMATION ai = { 0 };
+ ai.hContact = hContact;
+
+ ptrW szNick(g_plugin.getWStringA(hContact, "Nick"));
+ if (szNick) {
+ wchar_t *ext = wcsrchr((wchar_t *)url, '.') + 1;
+ ai.format = ProtoGetAvatarFormat(ext);
+
+ wchar_t *filename = szNick;
+ mir_snwprintf(ai.filename, L"%s\\%s.%s", tszRoot, filename, ext);
+ if (DownloadFile(url, ai.filename)) {
+ g_plugin.setWString(hContact, "ImagePath", ai.filename);
+ ProtoBroadcastAck(MODULENAME, hContact, ACKTYPE_AVATAR, ACKRESULT_SUCCESS, (HANDLE)&ai, NULL);
+ }
+ else ProtoBroadcastAck(MODULENAME, hContact, ACKTYPE_AVATAR, ACKRESULT_FAILED, (HANDLE)&ai, NULL);
+ }
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// touches a feed to verify whether it exists
+
+LPCTSTR CheckFeed(wchar_t *tszURL, CFeedEditor *pEditDlg)
+{
+ Netlib_LogfW(hNetlibUser, L"Started validating feed %s.", tszURL);
+ char *szData = nullptr;
+ GetNewsData(tszURL, &szData, NULL, pEditDlg);
+ if (szData) {
+ TiXmlDocument doc;
+ int ret = doc.Parse(szData);
+ mir_free(szData);
+ if (ret == ERROR_SUCCESS) {
+ CMStringA codepage = DetectEncoding(doc);
+
+ for (auto *it : TiXmlEnum(&doc)) {
+ auto *szNodeName = it->Name();
+ const TiXmlElement *pNode;
+ if (!mir_strcmpi(szNodeName, "rss") || !mir_strcmpi(szNodeName, "rdf"))
+ pNode = it->FirstChildElement();
+ else if (!mir_strcmpi(szNodeName, "feed"))
+ pNode = it;
+ else continue;
+
+ for (auto *child : TiXmlFilter(pNode, "title")) {
+ wchar_t mes[MAX_PATH];
+ mir_snwprintf(mes, TranslateT("%s\nis a valid feed's address."), tszURL);
+ MessageBox(pEditDlg->GetHwnd(), mes, TranslateT("News Aggregator"), MB_OK | MB_ICONINFORMATION);
+ return EncodeResult(child->GetText(), codepage);
+ }
+ }
+ }
+ }
+
+ Netlib_LogfW(hNetlibUser, L"%s is not a valid feed's address.", tszURL);
+ wchar_t mes[MAX_PATH];
+ mir_snwprintf(mes, TranslateT("%s\nis not a valid feed's address."), tszURL);
+ MessageBox(pEditDlg->GetHwnd(), mes, TranslateT("News Aggregator"), MB_OK | MB_ICONERROR);
+ return nullptr;
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// loads a feed completely, with messages
+
+static void XmlToMsg(MCONTACT hContact, CMStringW &title, CMStringW &link, CMStringW &descr, CMStringW &author, CMStringW &comments, CMStringW &guid, CMStringW &category, time_t stamp)
+{
+ CMStringW message = g_plugin.getWStringA(hContact, "MsgFormat");
+ if (!message)
+ message = TAGSDEFAULT;
+
+ if (title.IsEmpty())
+ message.Replace(L"#<title>#", TranslateT("empty"));
+ else
+ message.Replace(L"#<title>#", title);
+
+ if (link.IsEmpty())
+ message.Replace(L"#<link>#", TranslateT("empty"));
+ else
+ message.Replace(L"#<link>#", link);
+
+ if (descr.IsEmpty())
+ message.Replace(L"#<description>#", TranslateT("empty"));
+ else
+ message.Replace(L"#<description>#", descr);
+
+ if (author.IsEmpty())
+ message.Replace(L"#<author>#", TranslateT("empty"));
+ else
+ message.Replace(L"#<author>#", author);
+
+ if (comments.IsEmpty())
+ message.Replace(L"#<comments>#", TranslateT("empty"));
+ else
+ message.Replace(L"#<comments>#", comments);
+
+ if (guid.IsEmpty())
+ message.Replace(L"#<guid>#", TranslateT("empty"));
+ else
+ message.Replace(L"#<guid>#", guid);
+
+ if (category.IsEmpty())
+ message.Replace(L"#<category>#", TranslateT("empty"));
+ else
+ message.Replace(L"#<category>#", category);
+
+ DBEVENTINFO olddbei = {};
+ bool MesExist = false;
+ T2Utf pszTemp(message);
+ DWORD cbMemoLen = 10000, cbOrigLen = (DWORD)mir_strlen(pszTemp);
+ BYTE *pbBuffer = (BYTE*)mir_alloc(cbMemoLen);
+ for (MEVENT hDbEvent = db_event_last(hContact); hDbEvent; hDbEvent = db_event_prev(hContact, hDbEvent)) {
+ olddbei.cbBlob = db_event_getBlobSize(hDbEvent);
+ if (olddbei.cbBlob > cbMemoLen)
+ pbBuffer = (PBYTE)mir_realloc(pbBuffer, (size_t)(cbMemoLen = olddbei.cbBlob));
+ olddbei.pBlob = pbBuffer;
+ db_event_get(hDbEvent, &olddbei);
+
+ // there's no need to look for the elder events
+ if (stamp > 0 && olddbei.timestamp < (DWORD)stamp)
+ break;
+
+ if ((DWORD)mir_strlen((char*)olddbei.pBlob) == cbOrigLen && !mir_strcmp((char*)olddbei.pBlob, pszTemp)) {
+ MesExist = true;
+ break;
+ }
+ }
+ mir_free(pbBuffer);
+
+ if (!MesExist) {
+ if (stamp == 0)
+ stamp = time(0);
+
+ T2Utf pszMessage(message);
+
+ PROTORECVEVENT recv = { 0 };
+ recv.timestamp = (DWORD)stamp;
+ recv.szMessage = pszMessage;
+ ProtoChainRecvMsg(hContact, &recv);
+ }
+}
+
+void CheckCurrentFeed(MCONTACT hContact)
+{
+ // Check is disabled by the user?
+ if (!g_plugin.getByte(hContact, "CheckState", 1) != 0)
+ return;
+
+ wchar_t *szURL = g_plugin.getWStringA(hContact, "URL");
+ if (szURL == nullptr)
+ return;
+
+ Netlib_LogfW(hNetlibUser, L"Started checking feed %s.", szURL);
+
+ char *szData = nullptr;
+ GetNewsData(szURL, &szData, hContact, nullptr);
+ mir_free(szURL);
+
+ if (szData == nullptr)
+ return;
+
+ TiXmlDocument doc;
+ int ret = doc.Parse(szData);
+ mir_free(szData);
+ if (ret != ERROR_SUCCESS)
+ return;
+
+ CMStringA codepage = DetectEncoding(doc);
+
+ CMStringW szValue;
+
+ for (auto *it : TiXmlEnum(&doc)) {
+ auto *szNodeName = it->Name();
+ bool isRSS = !mir_strcmpi(szNodeName, "rss"), isAtom = !mir_strcmpi(szNodeName, "rdf");
+ if (isRSS || isAtom) {
+ if (isRSS) {
+ if (auto *pVersion = it->Attribute("version")) {
+ char ver[MAX_PATH];
+ mir_snprintf(ver, "RSS %s", pVersion);
+ g_plugin.setString(hContact, "MirVer", ver);
+ }
+ }
+ else if (isAtom)
+ g_plugin.setWString(hContact, "MirVer", L"RSS 1.0");
+
+ for (auto *child : TiXmlEnum(it->FirstChildElement())) {
+ auto *childName = child->Name();
+ if (!mir_strcmpi(childName, "title")) {
+ ptrW szChildText(EncodeResult(child->GetText(), codepage));
+ if (szChildText)
+ g_plugin.setWString(hContact, "FirstName", ClearText(szValue, szChildText));
+ }
+ else if (!mir_strcmpi(childName, "link")) {
+ ptrW szChildText(EncodeResult(child->GetText(), codepage));
+ if (szChildText)
+ g_plugin.setWString(hContact, "Homepage", ClearText(szValue, szChildText));
+ }
+ else if (!mir_strcmpi(childName, "description")) {
+ ptrW szChildText(EncodeResult(child->GetText(), codepage));
+ if (szChildText) {
+ ClearText(szValue, szChildText);
+ g_plugin.setWString(hContact, "About", szValue);
+ db_set_ws(hContact, "CList", "StatusMsg", szValue);
+ }
+ }
+ else if (!mir_strcmpi(childName, "language")) {
+ ptrW szChildText(EncodeResult(child->GetText(), codepage));
+ if (szChildText)
+ g_plugin.setWString(hContact, "Language1", ClearText(szValue, szChildText));
+ }
+ else if (!mir_strcmpi(childName, "managingEditor")) {
+ ptrW szChildText(EncodeResult(child->GetText(), codepage));
+ if (szChildText)
+ g_plugin.setWString(hContact, "e-mail", ClearText(szValue, szChildText));
+ }
+ else if (!mir_strcmpi(childName, "category")) {
+ ptrW szChildText(EncodeResult(child->GetText(), codepage));
+ if (szChildText)
+ g_plugin.setWString(hContact, "Interest0Text", ClearText(szValue, szChildText));
+ }
+ else if (!mir_strcmpi(childName, "copyright")) {
+ ptrW szChildText(EncodeResult(child->GetText(), codepage));
+ if (szChildText)
+ db_set_s(hContact, "UserInfo", "MyNotes", _T2A(ClearText(szValue, szChildText)));
+ }
+ else if (!mir_strcmpi(childName, "image")) {
+ for (auto *xmlImage : TiXmlFilter(child, "url"))
+ SetAvatar(hContact, xmlImage->GetText());
+ }
+ else if (!mir_strcmpi(childName, "lastBuildDate")) {
+ time_t stamp = DateToUnixTime(child->GetText(), 0);
+ double deltaupd = difftime(time(0), stamp);
+ double deltacheck = difftime(time(0), (time_t)g_plugin.getDword(hContact, "LastCheck"));
+ if (deltaupd - deltacheck >= 0) {
+ g_plugin.setDword(hContact, "LastCheck", (DWORD)time(0));
+ return;
+ }
+ }
+ else if (!mir_strcmpi(childName, "item")) {
+ CMStringW title, link, descr, author, comments, guid, category;
+ time_t stamp = 0;
+ for (auto *itemval : TiXmlEnum(child)) {
+ auto *itemName = itemval->Name();
+ ptrW value(EncodeResult(itemval->GetText(), codepage));
+
+ // We only use the first tag for now and ignore the rest.
+ if (!mir_strcmpi(itemName, "title"))
+ ClearText(title, value);
+
+ else if (!mir_strcmpi(itemName, "link"))
+ ClearText(link, value);
+
+ else if (!mir_strcmpi(itemName, "pubDate") || !mir_strcmpi(itemName, "date")) {
+ if (stamp == 0)
+ stamp = DateToUnixTime(itemval->GetText(), 0);
+ }
+ else if (!mir_strcmpi(itemName, "description") || !mir_strcmpi(itemName, "encoded"))
+ ClearText(descr, value);
+
+ else if (!mir_strcmpi(itemName, "author") || !mir_strcmpi(itemName, "creator"))
+ ClearText(author, value);
+
+ else if (!mir_strcmpi(itemName, "comments"))
+ ClearText(comments, value);
+
+ else if (!mir_strcmpi(itemName, "guid"))
+ ClearText(guid, value);
+
+ else if (!mir_strcmpi(itemName, "category"))
+ ClearText(category, value);
+ }
+
+ XmlToMsg(hContact, title, link, descr, author, comments, guid, category, stamp);
+ }
+ }
+ }
+ else if (!mir_strcmpi(szNodeName, "feed")) {
+ g_plugin.setWString(hContact, "MirVer", L"Atom 3");
+ for (auto *child : TiXmlEnum(it)) {
+ auto *szChildName = child->Name();
+ if (!mir_strcmpi(szChildName, "title")) {
+ ptrW szChildText(EncodeResult(child->GetText(), codepage));
+ if (szChildText)
+ g_plugin.setWString(hContact, "FirstName", ClearText(szValue, szChildText));
+ }
+ else if (!mir_strcmpi(szChildName, "link")) {
+ if (!child->Attribute("rel", "self"))
+ if (auto *pHref = child->Attribute("href"))
+ g_plugin.setWString(hContact, "Homepage", Utf2T(pHref));
+ }
+ else if (!mir_strcmpi(szChildName, "subtitle")) {
+ ptrW szChildText(EncodeResult(child->GetText(), codepage));
+ if (szChildText) {
+ ClearText(szValue, szChildText);
+ g_plugin.setWString(hContact, "About", szValue);
+ db_set_ws(hContact, "CList", "StatusMsg", szValue);
+ }
+ }
+ else if (!mir_strcmpi(szChildName, "language")) {
+ ptrW szChildText(EncodeResult(child->GetText(), codepage));
+ if (szChildText)
+ g_plugin.setWString(hContact, "Language1", ClearText(szValue, szChildText));
+ }
+ else if (!mir_strcmpi(szChildName, "author")) {
+ for (auto *authorval : TiXmlFilter(child, "email")) {
+ g_plugin.setWString(hContact, "e-mail", ptrW(EncodeResult(authorval->GetText(), codepage)));
+ break;
+ }
+ }
+ else if (!mir_strcmpi(szChildName, "category")) {
+ ptrW szChildText(EncodeResult(child->GetText(), codepage));
+ if (szChildText)
+ g_plugin.setWString(hContact, "Interest0Text", ClearText(szValue, szChildText));
+ }
+ else if (!mir_strcmpi(szChildName, "icon")) {
+ for (auto *imageval : TiXmlFilter(child, "url"))
+ SetAvatar(hContact, imageval->GetText());
+ }
+ else if (!mir_strcmpi(szChildName, "updated")) {
+ time_t stamp = DateToUnixTime(child->GetText(), 1);
+ double deltaupd = difftime(time(0), stamp);
+ double deltacheck = difftime(time(0), (time_t)g_plugin.getDword(hContact, "LastCheck"));
+ if (deltaupd - deltacheck >= 0) {
+ g_plugin.setDword(hContact, "LastCheck", (DWORD)time(0));
+ return;
+ }
+ }
+ else if (!mir_strcmpi(szChildName, "entry")) {
+ CMStringW title, link, descr, author, comments, guid, category;
+ time_t stamp = 0;
+ for (auto *itemval : TiXmlEnum(child)) {
+ LPCSTR szItemName = itemval->Name();
+ if (!mir_strcmpi(szItemName, "title")) {
+ ptrW szItemText(EncodeResult(itemval->GetText(), codepage));
+ if (szItemText)
+ ClearText(title, szItemText);
+ }
+ else if (!mir_strcmpi(szItemName, "link")) {
+ if (auto *pszLink = itemval->Attribute("href"))
+ ClearText(link, ptrW(EncodeResult(pszLink, codepage)));
+ }
+ else if (!mir_strcmpi(szItemName, "updated")) {
+ if (stamp == 0)
+ stamp = DateToUnixTime(itemval->GetText(), 0);
+ }
+ else if (!mir_strcmpi(szItemName, "summary") || !mir_strcmpi(szItemName, "content")) {
+ ptrW szItemText(EncodeResult(itemval->GetText(), codepage));
+ if (szItemText)
+ ClearText(descr, szItemText);
+ }
+ else if (!mir_strcmpi(szItemName, "author")) {
+ for (auto *authorval : TiXmlFilter(itemval, "name")) {
+ ptrW szItemText(EncodeResult(authorval->GetText(), codepage));
+ if (szItemText)
+ ClearText(author, szItemText);
+ break;
+ }
+ }
+ else if (!mir_strcmpi(szItemName, "comments")) {
+ ptrW szItemText(EncodeResult(itemval->GetText(), codepage));
+ if (szItemText)
+ ClearText(comments, szItemText);
+ }
+ else if (!mir_strcmpi(szItemName, "id")) {
+ ptrW szItemText(EncodeResult(itemval->GetText(), codepage));
+ if (szItemText)
+ ClearText(guid, szItemText);
+ }
+ else if (!mir_strcmpi(szItemName, "category")) {
+ if (auto *p = itemval->Attribute("term"))
+ ClearText(link, ptrW(EncodeResult(p, codepage)));
+ }
+ }
+
+ XmlToMsg(hContact, title, link, descr, author, comments, guid, category, stamp);
+ }
+ }
+ }
+ }
+ g_plugin.setDword(hContact, "LastCheck", (DWORD)time(0));
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// downloads avatars from a given feed
+
+void CheckCurrentFeedAvatar(MCONTACT hContact)
+{
+ if (!g_plugin.getByte(hContact, "CheckState", 1))
+ return;
+
+ wchar_t *szURL = g_plugin.getWStringA(hContact, "URL");
+ if (szURL == nullptr)
+ return;
+
+ char *szData = nullptr;
+ GetNewsData(szURL, &szData, hContact, nullptr);
+ mir_free(szURL);
+
+ if (szData == nullptr)
+ return;
+
+ TiXmlDocument doc;
+ int ret = doc.Parse(szData);
+ mir_free(szData);
+ if (ret != ERROR_SUCCESS)
+ return;
+
+ for (auto *it : TiXmlEnum(&doc)) {
+ auto *szNodeName = it->Name();
+ if (!mir_strcmpi(szNodeName, "rss") || !mir_strcmpi(szNodeName, "rdf")) {
+ for (auto *child : TiXmlFilter(it->FirstChildElement(), "image"))
+ for (auto *xmlImage : TiXmlFilter(child, "url"))
+ SetAvatar(hContact, xmlImage->GetText());
+ }
+ else if (!mir_strcmpi(szNodeName, "feed")) {
+ for (auto *child : TiXmlFilter(it, "icon"))
+ for (auto *xmlImage : TiXmlFilter(child, "url"))
+ SetAvatar(hContact, xmlImage->GetText());
+ }
+ }
+}
diff --git a/protocols/NewsAggregator/Src/Icons.cpp b/protocols/NewsAggregator/Src/Icons.cpp
new file mode 100644
index 0000000000..b9cdeb6166
--- /dev/null
+++ b/protocols/NewsAggregator/Src/Icons.cpp
@@ -0,0 +1,53 @@
+/*
+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 "stdafx.h"
+
+static IconItem iconList[] =
+{
+ { LPGEN("Protocol icon"), "main", IDI_ICON},
+ { LPGEN("Check All Feeds"), "checkall", IDI_CHECKALL},
+ { LPGEN("Add Feed"), "addfeed", IDI_ADDFEED},
+ { LPGEN("Import Feeds"), "importfeeds", IDI_IMPORTFEEDS},
+ { LPGEN("Export Feeds"), "exportfeeds", IDI_EXPORTFEEDS},
+ { LPGEN("Check Feed"), "checkfeed", IDI_CHECKALL},
+ { LPGEN("Auto Update Enabled"), "enabled", IDI_ENABLED},
+ { LPGEN("Auto Update Disabled"), "disabled", IDI_DISABLED}
+};
+
+void InitIcons()
+{
+ g_plugin.registerIcon(LPGEN("News Aggregator"), iconList, MODULENAME);
+}
+
+HICON LoadIconEx(const char *name, bool big)
+{
+ char szSettingName[100];
+ mir_snprintf(szSettingName, "%s_%s", MODULENAME, name);
+ return IcoLib_GetIcon(szSettingName, big);
+}
+
+HANDLE GetIconHandle(const char *name)
+{
+ for (int i=0; i < _countof(iconList); i++)
+ if ( !mir_strcmp(iconList[i].szName, name))
+ return iconList[i].hIcolib;
+
+ return nullptr;
+}
diff --git a/protocols/NewsAggregator/Src/Menus.cpp b/protocols/NewsAggregator/Src/Menus.cpp
new file mode 100644
index 0000000000..7770e843eb
--- /dev/null
+++ b/protocols/NewsAggregator/Src/Menus.cpp
@@ -0,0 +1,83 @@
+/*
+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 "stdafx.h"
+
+HGENMENU hService2[7];
+
+void InitMenu()
+{
+ CMenuItem mi(&g_plugin);
+ mi.flags = CMIF_UNICODE | CMIF_NOTOFFLINE;
+ mi.root = g_plugin.addRootMenu(MO_MAIN, LPGENW("News Aggregator"), 500099000);
+ Menu_ConfigureItem(mi.root, MCI_OPT_UID, "D9733E4F-1946-4390-8EB3-591E8687222E");
+
+ SET_UID(mi, 0x3ec91864, 0xefa7, 0x4994, 0xb7, 0x75, 0x6c, 0x96, 0xcb, 0x29, 0x2f, 0x93);
+ mi.position = 10100001;
+ if (g_plugin.getByte("AutoUpdate", 1))
+ mi.name.w = LPGENW("Auto Update Enabled");
+ else
+ mi.name.w = LPGENW("Auto Update Disabled");
+ mi.hIcolibItem = GetIconHandle("main");
+ mi.pszService = MS_NEWSAGGREGATOR_ENABLED;
+ hService2[0] = Menu_AddMainMenuItem(&mi);
+
+ SET_UID(mi, 0x8076bb4d, 0x1e44, 0x43af, 0x97, 0x1e, 0x31, 0xd8, 0xa4, 0xe9, 0xb8, 0x37);
+ mi.position = 20100001;
+ mi.name.w = LPGENW("Check All Feeds");
+ mi.pszService = MS_NEWSAGGREGATOR_CHECKALLFEEDS;
+ hService2[1] = Menu_AddMainMenuItem(&mi);
+
+ SET_UID(mi, 0xb876484d, 0x28aa, 0x4e03, 0x9e, 0x98, 0xed, 0xbc, 0xd1, 0xcf, 0x31, 0x80);
+ mi.position = 20100002;
+ mi.hIcolibItem = GetIconHandle("addfeed");
+ mi.name.w = LPGENW("Add Feed");
+ mi.pszService = MS_NEWSAGGREGATOR_ADDFEED;
+ hService2[2] = Menu_AddMainMenuItem(&mi);
+
+ SET_UID(mi, 0x600bf2c2, 0xa974, 0x44d3, 0x98, 0xf9, 0xe6, 0x65, 0x7c, 0x1f, 0x63, 0x37);
+ mi.position = 20100003;
+ mi.hIcolibItem = GetIconHandle("importfeeds");
+ mi.name.w = LPGENW("Import Feeds");
+ mi.pszService = MS_NEWSAGGREGATOR_IMPORTFEEDS;
+ hService2[3] = Menu_AddMainMenuItem(&mi);
+
+ SET_UID(mi, 0xc09c8119, 0x64c2, 0x49bd, 0x81, 0xf, 0x54, 0x20, 0x69, 0xd7, 0x30, 0xcf);
+ mi.position = 20100004;
+ mi.hIcolibItem = GetIconHandle("exportfeeds");
+ mi.name.w = LPGENW("Export Feeds");
+ mi.pszService = MS_NEWSAGGREGATOR_EXPORTFEEDS;
+ hService2[4] = Menu_AddMainMenuItem(&mi);
+
+ // adding contact menu items
+ SET_UID(mi, 0x92be499c, 0x928c, 0x4789, 0x8f, 0x36, 0x28, 0xa2, 0x9f, 0xb7, 0x1a, 0x97);
+ mi.root = nullptr;
+ mi.position = -0x7FFFFFFA;
+ mi.hIcolibItem = GetIconHandle("checkfeed");
+ mi.name.w = LPGENW("Check feed");
+ mi.pszService = MS_NEWSAGGREGATOR_CHECKFEED;
+ hService2[5] = Menu_AddContactMenuItem(&mi, MODULENAME);
+
+ SET_UID(mi, 0x41a70fbc, 0x9241, 0x44c0, 0x90, 0x90, 0x87, 0xd2, 0xc5, 0x9f, 0xc9, 0xac);
+ mi.name.w = LPGENW("Change feed");
+ mi.pszService = MS_NEWSAGGREGATOR_CHANGEFEED;
+ hService2[6] = Menu_AddContactMenuItem(&mi, MODULENAME);
+
+ Menu_ModifyItem(hService2[0], nullptr, GetIconHandle(g_plugin.getByte("AutoUpdate", 1) ? "enabled" : "disabled"));
+}
diff --git a/protocols/NewsAggregator/Src/NewsAggregator.cpp b/protocols/NewsAggregator/Src/NewsAggregator.cpp
new file mode 100644
index 0000000000..8ee17dd97a
--- /dev/null
+++ b/protocols/NewsAggregator/Src/NewsAggregator.cpp
@@ -0,0 +1,106 @@
+/*
+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 "stdafx.h"
+
+HANDLE hPrebuildMenuHook = nullptr;
+CDlgBase *pAddFeedDialog = nullptr, *pImportDialog = nullptr, *pExportDialog = nullptr;
+wchar_t tszRoot[MAX_PATH] = {0};
+HANDLE hUpdateMutex;
+
+LIST<CFeedEditor> g_arFeeds(1, PtrKeySortT);
+
+CMPlugin g_plugin;
+
+/////////////////////////////////////////////////////////////////////////////////////////
+
+PLUGININFOEX pluginInfoEx = {
+ sizeof(PLUGININFOEX),
+ __PLUGIN_NAME,
+ PLUGIN_MAKE_VERSION(__MAJOR_VERSION, __MINOR_VERSION, __RELEASE_NUM, __BUILD_NUM),
+ __DESCRIPTION,
+ __AUTHOR,
+ __COPYRIGHT,
+ __AUTHORWEB,
+ UNICODE_AWARE,
+ // {56CC3F29-CCBF-4546-A8BA-9856248A412A}
+ {0x56cc3f29, 0xccbf, 0x4546, {0xa8, 0xba, 0x98, 0x56, 0x24, 0x8a, 0x41, 0x2a}}
+};
+
+CMPlugin::CMPlugin() :
+ PLUGIN<CMPlugin>(MODULENAME, pluginInfoEx)
+{
+ RegisterProtocol(PROTOTYPE_VIRTUAL);
+ SetUniqueId("URL");
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+
+extern "C" __declspec(dllexport) const MUUID MirandaInterfaces[] = { MIID_PROTOCOL, MIID_LAST };
+
+/////////////////////////////////////////////////////////////////////////////////////////
+
+int CMPlugin::Load()
+{
+ // Add options hook
+ HookEvent(ME_OPT_INITIALISE, OptInit);
+ HookEvent(ME_SYSTEM_MODULESLOADED, NewsAggrInit);
+ HookEvent(ME_SYSTEM_PRESHUTDOWN, NewsAggrPreShutdown);
+
+ hUpdateMutex = CreateMutex(nullptr, FALSE, nullptr);
+
+ CreateProtoServiceFunction(MODULENAME, PS_GETNAME, NewsAggrGetName);
+ CreateProtoServiceFunction(MODULENAME, PS_GETCAPS, NewsAggrGetCaps);
+ CreateProtoServiceFunction(MODULENAME, PS_SETSTATUS, NewsAggrSetStatus);
+ CreateProtoServiceFunction(MODULENAME, PS_GETSTATUS, NewsAggrGetStatus);
+ CreateProtoServiceFunction(MODULENAME, PS_LOADICON, NewsAggrLoadIcon);
+ CreateProtoServiceFunction(MODULENAME, PSS_GETINFO, NewsAggrGetInfo);
+ CreateProtoServiceFunction(MODULENAME, PS_GETAVATARINFO, NewsAggrGetAvatarInfo);
+ CreateProtoServiceFunction(MODULENAME, PSR_MESSAGE, NewsAggrRecvMessage);
+
+ CreateServiceFunction(MS_NEWSAGGREGATOR_CHECKALLFEEDS, CheckAllFeeds);
+ CreateServiceFunction(MS_NEWSAGGREGATOR_ADDFEED, AddFeed);
+ CreateServiceFunction(MS_NEWSAGGREGATOR_IMPORTFEEDS, ImportFeeds);
+ CreateServiceFunction(MS_NEWSAGGREGATOR_EXPORTFEEDS, ExportFeeds);
+ CreateServiceFunction(MS_NEWSAGGREGATOR_CHECKFEED, CheckFeed);
+ CreateServiceFunction(MS_NEWSAGGREGATOR_CHANGEFEED, ChangeFeed);
+ CreateServiceFunction(MS_NEWSAGGREGATOR_ENABLED, EnableDisable);
+
+ HOTKEYDESC hkd = {};
+ hkd.dwFlags = HKD_UNICODE;
+ hkd.pszName = "NewsAggregator/CheckAllFeeds";
+ hkd.szDescription.w = LPGENW("Check All Feeds");
+ hkd.szSection.w = LPGENW("News Aggregator");
+ hkd.pszService = MS_NEWSAGGREGATOR_CHECKALLFEEDS;
+ hkd.DefHotKey = HOTKEYCODE(HOTKEYF_CONTROL+HKCOMB_A, 'O') | HKF_MIRANDA_LOCAL;
+ g_plugin.addHotkey(&hkd);
+
+ InitIcons();
+
+ return 0;
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+
+int CMPlugin::Unload()
+{
+ DestroyUpdateList();
+ CloseHandle(hUpdateMutex);
+ return 0;
+}
diff --git a/protocols/NewsAggregator/Src/Options.cpp b/protocols/NewsAggregator/Src/Options.cpp
new file mode 100644
index 0000000000..6239ce15c1
--- /dev/null
+++ b/protocols/NewsAggregator/Src/Options.cpp
@@ -0,0 +1,1016 @@
+/*
+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 "stdafx.h"
+
+CExportFeed::CExportFeed()
+ : CSuper(g_plugin, IDD_FEEDEXPORT),
+ m_feedslist(this, IDC_FEEDSLIST), m_feedsexportlist(this, IDC_FEEDSEXPORTLIST),
+ m_addfeed(this, IDC_ADDFEED), m_removefeed(this, IDC_REMOVEFEED),
+ m_addallfeeds(this, IDC_ADDALLFEEDS), m_removeallfeeds(this, IDC_REMOVEALLFEEDS),
+ m_ok(this, IDOK)
+{
+ m_addfeed.OnClick = Callback(this, &CExportFeed::OnAddFeed);
+ m_removefeed.OnClick = Callback(this, &CExportFeed::OnRemoveFeed);
+ m_addallfeeds.OnClick = Callback(this, &CExportFeed::OnAddAllFeeds);
+ m_removeallfeeds.OnClick = Callback(this, &CExportFeed::OnRemoveAllFeeds);
+ m_ok.OnClick = Callback(this, &CExportFeed::OnOk);
+
+ m_feedslist.OnDblClick = Callback(this, &CExportFeed::OnFeedsList);
+ m_feedsexportlist.OnDblClick = Callback(this, &CExportFeed::OnFeedsExportList);
+}
+
+bool CExportFeed::OnInitDialog()
+{
+ Utils_RestoreWindowPositionNoSize(m_hwnd, NULL, MODULENAME, "ExportDlg");
+ for (auto &hContact : Contacts(MODULENAME)) {
+ ptrW message(g_plugin.getWStringA(hContact, "Nick"));
+ if (message != nullptr)
+ m_feedslist.AddString(message);
+ }
+ m_removefeed.Disable();
+ m_removeallfeeds.Disable();
+ m_ok.Disable();
+ if (!m_feedslist.GetCount()) {
+ m_addfeed.Disable();
+ m_addallfeeds.Disable();
+ }
+ return true;
+}
+
+void CExportFeed::OnAddFeed(CCtrlBase*)
+{
+ if (!m_removefeed.Enabled())
+ m_removefeed.Enable();
+ if (!m_removeallfeeds.Enabled())
+ m_removeallfeeds.Enable();
+ if (!m_ok.Enabled())
+ m_ok.Enable();
+ int cursel = m_feedslist.GetCurSel();
+ wchar_t item[MAX_PATH];
+ m_feedslist.GetItemText(cursel, item, _countof(item));
+ m_feedsexportlist.AddString(item);
+ m_feedslist.DeleteString(cursel);
+ if (!m_feedslist.GetCount()) {
+ m_addfeed.Disable();
+ m_addallfeeds.Disable();
+ }
+}
+
+void CExportFeed::OnRemoveFeed(CCtrlBase*)
+{
+ if (!m_addfeed.Enabled())
+ m_addfeed.Enable();
+ if (!m_addallfeeds.Enabled())
+ m_addallfeeds.Enable();
+ int cursel = m_feedsexportlist.GetCurSel();
+ wchar_t item[MAX_PATH];
+ m_feedsexportlist.GetItemText(cursel, item, _countof(item));
+ m_feedslist.AddString(item);
+ m_feedsexportlist.DeleteString(cursel);
+ if (!m_feedsexportlist.GetCount()) {
+ m_removefeed.Disable();
+ m_removeallfeeds.Disable();
+ m_ok.Disable();
+ }
+}
+
+void CExportFeed::OnAddAllFeeds(CCtrlBase*)
+{
+ if (!m_removefeed.Enabled())
+ m_removefeed.Enable();
+ if (!m_removeallfeeds.Enabled())
+ m_removeallfeeds.Enable();
+ if (!m_ok.Enabled())
+ m_ok.Enable();
+ int count = m_feedslist.GetCount();
+ for (int i = 0; i < count; i++) {
+ wchar_t item[MAX_PATH];
+ m_feedslist.GetItemText(i, item, _countof(item));
+ m_feedsexportlist.AddString(item);
+ }
+ for (int i = count - 1; i > -1; i--)
+ m_feedslist.DeleteString(i);
+ m_addfeed.Disable();
+ m_addallfeeds.Disable();
+}
+
+void CExportFeed::OnRemoveAllFeeds(CCtrlBase*)
+{
+ if (!m_addfeed.Enabled())
+ m_addfeed.Enable();
+ if (!m_addallfeeds.Enabled())
+ m_addallfeeds.Enable();
+ int count = m_feedsexportlist.GetCount();
+ for (int i = 0; i < count; i++) {
+ wchar_t item[MAX_PATH];
+ m_feedsexportlist.GetItemText(i, item, _countof(item));
+ m_feedslist.AddString(item);
+ }
+ for (int i = count - 1; i > -1; i--)
+ m_feedsexportlist.DeleteString(i);
+ m_removefeed.Disable();
+ m_removeallfeeds.Disable();
+ m_ok.Disable();
+}
+
+void CExportFeed::OnFeedsList(CCtrlBase*)
+{
+ if (!m_removefeed.Enabled())
+ m_removefeed.Enable();
+ if (!m_removeallfeeds.Enabled())
+ m_removeallfeeds.Enable();
+ if (!m_ok.Enabled())
+ m_ok.Enable();
+ int cursel = m_feedslist.GetCurSel();
+ wchar_t item[MAX_PATH];
+ m_feedslist.GetItemText(cursel, item, _countof(item));
+ m_feedsexportlist.AddString(item);
+ m_feedslist.DeleteString(cursel);
+ if (!m_feedslist.GetCount()) {
+ m_addfeed.Disable();
+ m_addallfeeds.Disable();
+ }
+}
+
+void CExportFeed::OnFeedsExportList(CCtrlBase*)
+{
+ if (!m_addfeed.Enabled())
+ m_addfeed.Enable();
+ if (!m_addallfeeds.Enabled())
+ m_addallfeeds.Enable();
+ int cursel = m_feedsexportlist.GetCurSel();
+ wchar_t item[MAX_PATH];
+ m_feedsexportlist.GetItemText(cursel, item, _countof(item));
+ m_feedslist.AddString(item);
+ m_feedsexportlist.DeleteString(cursel);
+ if (!m_feedsexportlist.GetCount()) {
+ m_removefeed.Disable();
+ m_removeallfeeds.Disable();
+ m_ok.Disable();
+ }
+}
+
+static const TiXmlElement* AdviceNode(const TiXmlElement *node)
+{
+ auto *tmpnode = node;
+
+ // try to rest on the same level first
+ node = node->NextSiblingElement();
+ if (node)
+ return node;
+
+ do {
+ // go up one level
+ node = tmpnode->Parent()->ToElement();
+ tmpnode = node;
+ node = node->NextSiblingElement();
+ if (node)
+ return node;
+ }
+ while (mir_strcmpi(tmpnode->Name(), "body"));
+
+ // nothing found or we reached body
+ return nullptr;
+}
+
+void CExportFeed::OnOk(CCtrlBase*)
+{
+ wchar_t FileName[MAX_PATH];
+ VARSW tszMirDir(L"%miranda_path%");
+
+ OPENFILENAME ofn = { 0 };
+ ofn.lStructSize = sizeof(ofn);
+ wchar_t tmp[MAX_PATH];
+ mir_snwprintf(tmp, L"%s (*.opml)%c*.opml%c%c", TranslateT("OPML files"), 0, 0, 0);
+ ofn.lpstrFilter = tmp;
+ ofn.hwndOwner = nullptr;
+ ofn.lpstrFile = FileName;
+ ofn.nMaxFile = MAX_PATH;
+ ofn.nMaxFileTitle = MAX_PATH;
+ ofn.Flags = OFN_HIDEREADONLY | OFN_SHAREAWARE | OFN_PATHMUSTEXIST | OFN_OVERWRITEPROMPT;
+ ofn.lpstrInitialDir = tszMirDir;
+ *FileName = '\0';
+ ofn.lpstrDefExt = L"";
+ if (!GetSaveFileName(&ofn))
+ return;
+
+ TiXmlDocument doc;
+ auto *hXml = doc.NewElement("opml"); doc.InsertEndChild(hXml);
+ hXml->SetAttribute("version", "1.0");
+
+ auto *xmlHeader = doc.NewElement("head"); hXml->InsertEndChild(xmlHeader);
+ auto *xmlTitle = doc.NewElement("title"); xmlTitle->SetText("Miranda NG NewsAggregator plugin export"); xmlHeader->InsertEndChild(xmlTitle);
+
+ auto *xmlBody = doc.NewElement("body"); hXml->InsertEndChild(xmlBody);
+
+ int count = m_feedsexportlist.GetCount();
+ for (int i = 0; i < count; i++) {
+ wchar_t item[MAX_PATH];
+ m_feedsexportlist.GetItemText(i, item, _countof(item));
+ MCONTACT hContact = GetContactByNick(item);
+ wchar_t
+ *title = g_plugin.getWStringA(hContact, "Nick"),
+ *url = g_plugin.getWStringA(hContact, "URL"),
+ *siteurl = g_plugin.getWStringA(hContact, "Homepage"),
+ *group = db_get_wsa(hContact, "CList", "Group");
+
+ TiXmlElement *elem = xmlBody;
+ if (group) {
+ wchar_t *section = wcstok(group, L"\\");
+ while (section != nullptr) {
+ TiXmlElement *existgroup = 0;
+ for (auto *it : TiXmlFilter(elem, "outline")) {
+ if (it->Attribute("title", T2Utf(section))) {
+ existgroup = (TiXmlElement*)it;
+ break;
+ }
+ }
+
+ if (!existgroup) {
+ auto *pNew = doc.NewElement("outline");
+ pNew->SetAttribute("title", section); pNew->SetAttribute("text", section);
+ elem->InsertEndChild(pNew);
+ elem = pNew;
+ }
+ else elem = existgroup;
+
+ section = wcstok(nullptr, L"\\");
+ }
+ }
+
+ auto *pNew = doc.NewElement("outline"); elem->InsertEndChild(pNew);
+ pNew->SetAttribute("text", title);
+ pNew->SetAttribute("title", title);
+ pNew->SetAttribute("type", "rss");
+ pNew->SetAttribute("xmlUrl", url);
+ pNew->SetAttribute("htmlUrl", siteurl);
+
+ mir_free(title);
+ mir_free(url);
+ mir_free(siteurl);
+ mir_free(group);
+ }
+
+ FILE *out = _wfopen(FileName, L"wb");
+ if (out) {
+ tinyxml2::XMLPrinter printer(out);
+ doc.Print(&printer);
+ fclose(out);
+ }
+}
+
+bool CExportFeed::OnClose()
+{
+ Utils_SaveWindowPosition(m_hwnd, NULL, MODULENAME, "ExportDlg");
+ if (pExportDialog)
+ pExportDialog = nullptr;
+ return true;
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+
+CImportFeed::CImportFeed(CCtrlListView *m_feeds)
+ : CSuper(g_plugin, IDD_FEEDIMPORT),
+ m_importfile(this, IDC_IMPORTFILEPATH), m_browsefile(this, IDC_BROWSEIMPORTFILE),
+ m_feedslist(this, IDC_FEEDSLIST), m_feedsimportlist(this, IDC_FEEDSIMPORTLIST),
+ m_addfeed(this, IDC_ADDFEED), m_removefeed(this, IDC_REMOVEFEED),
+ m_addallfeeds(this, IDC_ADDALLFEEDS), m_removeallfeeds(this, IDC_REMOVEALLFEEDS),
+ m_ok(this, IDOK)
+{
+ m_list = m_feeds;
+ m_browsefile.OnClick = Callback(this, &CImportFeed::OnBrowseFile);
+ m_addfeed.OnClick = Callback(this, &CImportFeed::OnAddFeed);
+ m_removefeed.OnClick = Callback(this, &CImportFeed::OnRemoveFeed);
+ m_addallfeeds.OnClick = Callback(this, &CImportFeed::OnAddAllFeeds);
+ m_removeallfeeds.OnClick = Callback(this, &CImportFeed::OnRemoveAllFeeds);
+ m_ok.OnClick = Callback(this, &CImportFeed::OnOk);
+
+ m_feedslist.OnDblClick = Callback(this, &CImportFeed::OnFeedsList);
+ m_feedsimportlist.OnDblClick = Callback(this, &CImportFeed::OnFeedsImportList);
+}
+
+bool CImportFeed::OnInitDialog()
+{
+ Utils_RestoreWindowPositionNoSize(m_hwnd, NULL, MODULENAME, "ImportDlg");
+ m_removefeed.Disable();
+ m_removeallfeeds.Disable();
+ m_ok.Disable();
+ m_addfeed.Disable();
+ m_addallfeeds.Disable();
+ return true;
+}
+
+void CImportFeed::OnBrowseFile(CCtrlBase*)
+{
+ wchar_t FileName[MAX_PATH];
+ VARSW tszMirDir(L"%miranda_path%");
+
+ OPENFILENAME ofn = { 0 };
+ ofn.lStructSize = sizeof(ofn);
+ wchar_t tmp[MAX_PATH];
+ mir_snwprintf(tmp, L"%s (*.opml, *.xml)%c*.opml;*.xml%c%c", TranslateT("OPML files"), 0, 0, 0);
+ ofn.lpstrFilter = tmp;
+ ofn.hwndOwner = nullptr;
+ ofn.lpstrFile = FileName;
+ ofn.nMaxFile = MAX_PATH;
+ ofn.nMaxFileTitle = MAX_PATH;
+ ofn.Flags = OFN_HIDEREADONLY;
+ ofn.lpstrInitialDir = tszMirDir;
+ *FileName = '\0';
+ ofn.lpstrDefExt = L"";
+ if (!GetOpenFileName(&ofn))
+ return;
+
+ FILE *in = _wfopen(FileName, L"rb");
+ if (in == nullptr)
+ return;
+
+ TiXmlDocument doc;
+ int res = doc.LoadFile(in);
+ fclose(in);
+ if (res != 0) {
+ MessageBox(m_hwnd, TranslateT("Not valid import file."), TranslateT("Error"), MB_OK | MB_ICONERROR);
+ return;
+ }
+
+ m_importfile.SetText(FileName);
+
+ auto *node = TiXmlConst(&doc)["opml"]["body"]["outline"].ToElement();
+ if (!node)
+ node = TiXmlConst(&doc)["body"]["outline"].ToElement();
+ if (node == nullptr) {
+ MessageBox(m_hwnd, TranslateT("Not valid import file."), TranslateT("Error"), MB_OK | MB_ICONERROR);
+ return;
+ }
+
+ while (node) {
+ auto *pszUrl = node->Attribute("xmlUrl");
+ if (!pszUrl && node->NoChildren())
+ node = AdviceNode(node);
+ else if (!pszUrl && !node->NoChildren())
+ node = node->FirstChildElement();
+ else if (pszUrl) {
+ if (auto *pszText = node->Attribute("text")) {
+ Utf2T text(pszText);
+ m_feedslist.AddString(text);
+ m_addfeed.Enable();
+ m_addallfeeds.Enable();
+ }
+
+ node = AdviceNode(node);
+ }
+ }
+}
+
+void CImportFeed::OnAddFeed(CCtrlBase*)
+{
+ if (!m_removefeed.Enabled())
+ m_removefeed.Enable();
+ if (!m_removeallfeeds.Enabled())
+ m_removeallfeeds.Enable();
+ if (!m_ok.Enabled())
+ m_ok.Enable();
+ int cursel = m_feedslist.GetCurSel();
+ wchar_t item[MAX_PATH];
+ m_feedslist.GetItemText(cursel, item, _countof(item));
+ m_feedsimportlist.AddString(item);
+ m_feedslist.DeleteString(cursel);
+ if (!m_feedslist.GetCount()) {
+ m_addfeed.Disable();
+ m_addallfeeds.Disable();
+ }
+}
+
+void CImportFeed::OnRemoveFeed(CCtrlBase*)
+{
+ if (!m_addfeed.Enabled())
+ m_addfeed.Enable();
+ if (!m_addallfeeds.Enabled())
+ m_addallfeeds.Enable();
+ int cursel = m_feedsimportlist.GetCurSel();
+ wchar_t item[MAX_PATH];
+ m_feedsimportlist.GetItemText(cursel, item, _countof(item));
+ m_feedslist.AddString(item);
+ m_feedsimportlist.DeleteString(cursel);
+ if (!m_feedsimportlist.GetCount()) {
+ m_removefeed.Disable();
+ m_removeallfeeds.Disable();
+ m_ok.Disable();
+ }
+}
+
+void CImportFeed::OnAddAllFeeds(CCtrlBase*)
+{
+ if (!m_removefeed.Enabled())
+ m_removefeed.Enable();
+ if (!m_removeallfeeds.Enabled())
+ m_removeallfeeds.Enable();
+ if (!m_ok.Enabled())
+ m_ok.Enable();
+ int count = m_feedslist.GetCount();
+ for (int i = 0; i < count; i++) {
+ wchar_t item[MAX_PATH];
+ m_feedslist.GetItemText(i, item, _countof(item));
+ m_feedsimportlist.AddString(item);
+ }
+ for (int i = count - 1; i > -1; i--)
+ m_feedslist.DeleteString(i);
+ m_addfeed.Disable();
+ m_addallfeeds.Disable();
+}
+
+void CImportFeed::OnRemoveAllFeeds(CCtrlBase*)
+{
+ if (!m_addfeed.Enabled())
+ m_addfeed.Enable();
+ if (!m_addallfeeds.Enabled())
+ m_addallfeeds.Enable();
+ int count = m_feedsimportlist.GetCount();
+ for (int i = 0; i < count; i++) {
+ wchar_t item[MAX_PATH];
+ m_feedsimportlist.GetItemText(i, item, _countof(item));
+ m_feedslist.AddString(item);
+ }
+ for (int i = count - 1; i > -1; i--)
+ m_feedsimportlist.DeleteString(i);
+ m_removefeed.Disable();
+ m_removeallfeeds.Disable();
+ m_ok.Disable();
+}
+
+void CImportFeed::OnFeedsList(CCtrlBase*)
+{
+ if (!m_removefeed.Enabled())
+ m_removefeed.Enable();
+ if (!m_removeallfeeds.Enabled())
+ m_removeallfeeds.Enable();
+ if (!m_ok.Enabled())
+ m_ok.Enable();
+ int cursel = m_feedslist.GetCurSel();
+ wchar_t item[MAX_PATH];
+ m_feedslist.GetItemText(cursel, item, _countof(item));
+ m_feedsimportlist.AddString(item);
+ m_feedslist.DeleteString(cursel);
+ if (!m_feedslist.GetCount()) {
+ m_addfeed.Disable();
+ m_addallfeeds.Disable();
+ }
+}
+
+void CImportFeed::OnFeedsImportList(CCtrlBase*)
+{
+ if (!m_addfeed.Enabled())
+ m_addfeed.Enable();
+ if (!m_addallfeeds.Enabled())
+ m_addallfeeds.Enable();
+ int cursel = m_feedsimportlist.GetCurSel();
+ wchar_t item[MAX_PATH];
+ m_feedsimportlist.GetItemText(cursel, item, _countof(item));
+ m_feedslist.AddString(item);
+ m_feedsimportlist.DeleteString(cursel);
+ if (!m_feedsimportlist.GetCount()) {
+ m_removefeed.Disable();
+ m_removeallfeeds.Disable();
+ m_ok.Disable();
+ }
+}
+
+void CImportFeed::OnOk(CCtrlBase*)
+{
+ wchar_t FileName[MAX_PATH];
+ m_importfile.GetText(FileName, _countof(FileName));
+
+ FILE *in = _wfopen(FileName, L"rb");
+ if (in == nullptr)
+ return;
+
+ TiXmlDocument doc;
+ int res = doc.LoadFile(in);
+ fclose(in);
+ if (res != 0)
+ return;
+
+ auto *node = TiXmlConst(&doc)["opml"]["body"]["outline"].ToElement();
+ if (!node)
+ node = TiXmlConst(&doc)["body"]["outline"].ToElement();
+ if (node == nullptr)
+ return;
+
+ int count = m_feedsimportlist.GetCount();
+ int DUPES = 0;
+
+ while (node) {
+ auto *pszUrl = node->Attribute("xmlUrl");
+ if (!pszUrl && node->NoChildren())
+ node = AdviceNode(node);
+ else if (!pszUrl && !node->NoChildren())
+ node = node->FirstChildElement();
+ else if (pszUrl) {
+ wchar_t *text = nullptr, *url = nullptr, *siteurl = nullptr;
+ bool bNeedToImport = false;
+
+ if (auto *pszText = node->Attribute("text")) {
+ text = mir_utf8decodeW(pszText);
+
+ for (int j = 0; j < count; j++) {
+ wchar_t item[MAX_PATH];
+ m_feedsimportlist.GetItemText(j, item, _countof(item));
+ if (!mir_wstrcmpi(item, text)) {
+ bNeedToImport = true;
+ break;
+ }
+ }
+ }
+
+ if (auto *pszText = node->Attribute("xmlUrl")) {
+ url = mir_utf8decodeW(pszText);
+ if (GetContactByURL(url) && bNeedToImport) {
+ bNeedToImport = false;
+ DUPES++;
+ }
+ }
+
+ if (auto *pszText = node->Attribute("htmlUrl"))
+ siteurl = mir_utf8decodeW(pszText);
+
+ if (bNeedToImport && text && url && siteurl) {
+ CMStringW wszGroup;
+ auto *parent = node->Parent()->ToElement();
+ while (mir_strcmpi(parent->Name(), "body")) {
+ if (auto *pszText = parent->Attribute("text")) {
+ if (!wszGroup.IsEmpty())
+ wszGroup.Insert(0, L"\\");
+ wszGroup.Insert(0, Utf2T(pszText));
+ }
+ parent = parent->Parent()->ToElement();
+ }
+
+ MCONTACT hContact = db_add_contact();
+ Proto_AddToContact(hContact, MODULENAME);
+ g_plugin.setWString(hContact, "Nick", text);
+ g_plugin.setWString(hContact, "URL", url);
+ g_plugin.setWString(hContact, "Homepage", siteurl);
+ g_plugin.setByte(hContact, "CheckState", 1);
+ g_plugin.setDword(hContact, "UpdateTime", DEFAULT_UPDATE_TIME);
+ g_plugin.setWString(hContact, "MsgFormat", TAGSDEFAULT);
+ g_plugin.setWord(hContact, "Status", Proto_GetStatus(MODULENAME));
+
+ if (m_list != nullptr) {
+ int iItem = m_list->AddItem(text, -1);
+ m_list->SetItem(iItem, 1, url);
+ m_list->SetCheckState(iItem, 1);
+ }
+
+ if (!wszGroup.IsEmpty()) {
+ db_set_ws(hContact, "CList", "Group", wszGroup);
+ Clist_GroupCreate(0, wszGroup);
+ }
+ }
+ mir_free(text);
+ mir_free(url);
+ mir_free(siteurl);
+
+ node = AdviceNode(node);
+ }
+ }
+
+ wchar_t mes[MAX_PATH];
+ if (DUPES)
+ mir_snwprintf(mes, TranslateT("Imported %d feed(s)\r\nNot imported %d duplicate(s)."), count - DUPES, DUPES);
+ else
+ mir_snwprintf(mes, TranslateT("Imported %d feed(s)."), count);
+ MessageBox(m_hwnd, mes, TranslateT("News Aggregator"), MB_OK | MB_ICONINFORMATION);
+}
+
+bool CImportFeed::OnClose()
+{
+ Utils_SaveWindowPosition(m_hwnd, NULL, MODULENAME, "ImportDlg");
+ if (pImportDialog)
+ pImportDialog = nullptr;
+ return true;
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+
+CFeedEditor::CFeedEditor(int iItem, CCtrlListView *m_feeds, MCONTACT Contact)
+ : CSuper(g_plugin, IDD_ADDFEED),
+ m_feedtitle(this, IDC_FEEDTITLE), m_feedurl(this, IDC_FEEDURL),
+ m_checktime(this, IDC_CHECKTIME), m_checktimespin(this, IDC_TIMEOUT_VALUE_SPIN, 999),
+ m_checkfeed(this, IDC_DISCOVERY), m_useauth(this, IDC_USEAUTH),
+ m_login(this, IDC_LOGIN), m_password(this, IDC_PASSWORD),
+ m_tagedit(this, IDC_TAGSEDIT), m_reset(this, IDC_RESET),
+ m_help(this, IDC_TAGHELP), m_ok(this, IDOK), m_iItem(iItem)
+{
+ m_list = m_feeds;
+ m_hContact = Contact;
+ m_checkfeed.OnClick = Callback(this, &CFeedEditor::OnCheckFeed);
+ m_useauth.OnChange = Callback(this, &CFeedEditor::OnUseAuth);
+ m_reset.OnClick = Callback(this, &CFeedEditor::OnReset);
+ m_help.OnClick = Callback(this, &CFeedEditor::OnHelp);
+ m_ok.OnClick = Callback(this, &CFeedEditor::OnOk);
+}
+
+bool CFeedEditor::OnInitDialog()
+{
+ if (m_iItem == -1 && m_hContact == NULL)
+ SetWindowText(m_hwnd, TranslateT("Add Feed"));
+ else
+ SetWindowText(m_hwnd, TranslateT("Change Feed"));
+ m_checktime.SetMaxLength(3);
+
+ if (m_iItem > -1 && m_hContact == 0) {
+ wchar_t SelNick[MAX_PATH], SelUrl[MAX_PACKAGE_NAME];
+ m_list->GetItemText(m_iItem, 0, SelNick, _countof(SelNick));
+ m_list->GetItemText(m_iItem, 1, SelUrl, _countof(SelNick));
+
+ for (auto &hContact : Contacts(MODULENAME)) {
+ ptrW dbNick(g_plugin.getWStringA(hContact, "Nick"));
+ if ((dbNick == NULL) || (mir_wstrcmp(dbNick, SelNick) != 0))
+ continue;
+
+ ptrW dbURL(g_plugin.getWStringA(hContact, "URL"));
+ if ((dbURL == NULL) || (mir_wstrcmp(dbURL, SelUrl) != 0))
+ continue;
+
+ m_hContact = hContact;
+ m_feedtitle.SetText(SelNick);
+ m_feedurl.SetText(SelUrl);
+ m_checktime.SetInt(g_plugin.getDword(hContact, "UpdateTime", DEFAULT_UPDATE_TIME));
+
+ ptrW szMsgFormat(g_plugin.getWStringA(hContact, "MsgFormat"));
+ if (szMsgFormat)
+ m_tagedit.SetText(szMsgFormat);
+
+ if (g_plugin.getByte(hContact, "UseAuth", 0)) {
+ m_useauth.SetState(1);
+ m_login.Enable();
+ m_password.Enable();
+
+ ptrW szLogin(g_plugin.getWStringA(hContact, "Login"));
+ if (szLogin)
+ m_login.SetText(szLogin);
+
+ pass_ptrA pwd(g_plugin.getStringA(hContact, "Password"));
+ m_password.SetTextA(pwd);
+ }
+ g_arFeeds.insert(this);
+ Utils_RestoreWindowPositionNoSize(m_hwnd, hContact, MODULENAME, "ChangeDlg");
+ break;
+ }
+ }
+ else if (m_iItem == -1 && m_hContact == NULL) {
+ m_feedurl.SetText(L"http://");
+ m_tagedit.SetText(TAGSDEFAULT);
+ m_checktime.SetInt(DEFAULT_UPDATE_TIME);
+ Utils_RestoreWindowPositionNoSize(m_hwnd, NULL, MODULENAME, "AddDlg");
+ }
+ else if (m_hContact != NULL) {
+ ptrW dbNick(g_plugin.getWStringA(m_hContact, "Nick"));
+ ptrW dbURL(g_plugin.getWStringA(m_hContact, "URL"));
+
+ m_feedtitle.SetText(dbNick);
+ m_feedurl.SetText(dbURL);
+ m_checktime.SetInt(g_plugin.getDword(m_hContact, "UpdateTime", DEFAULT_UPDATE_TIME));
+
+ ptrW szMsgFormat(g_plugin.getWStringA(m_hContact, "MsgFormat"));
+ if (szMsgFormat)
+ m_tagedit.SetText(szMsgFormat);
+
+ if (g_plugin.getByte(m_hContact, "UseAuth")) {
+ m_useauth.SetState(1);
+ m_login.Enable();
+ m_password.Enable();
+
+ ptrW szLogin(g_plugin.getWStringA(m_hContact, "Login"));
+ if (szLogin)
+ m_login.SetText(szLogin);
+
+ pass_ptrA pwd(g_plugin.getStringA(m_hContact, "Password"));
+ m_password.SetTextA(pwd);
+ }
+ g_arFeeds.insert(this);
+ Utils_RestoreWindowPositionNoSize(m_hwnd, m_hContact, MODULENAME, "ChangeDlg");
+ }
+ return true;
+}
+
+void CFeedEditor::OnCheckFeed(CCtrlBase*)
+{
+ m_checkfeed.Disable();
+ m_checkfeed.SetText(TranslateT("Wait..."));
+ wchar_t *tszTitle = nullptr;
+ ptrW strfeedurl(m_feedurl.GetText());
+ if (strfeedurl || mir_wstrcmp(strfeedurl, L"http://") != 0 || mir_wstrcmp(strfeedurl, L"") != 0)
+ tszTitle = (wchar_t*)CheckFeed(strfeedurl, this);
+ else
+ MessageBox(m_hwnd, TranslateT("Enter Feed URL"), TranslateT("Error"), MB_OK);
+ m_feedtitle.SetText(tszTitle);
+ mir_free(tszTitle);
+ m_checkfeed.Enable();
+ m_checkfeed.SetText(TranslateT("Check Feed"));
+}
+
+void CFeedEditor::OnReset(CCtrlBase*)
+{
+ if (MessageBox(m_hwnd, TranslateT("Are you sure?"), TranslateT("Tags Mask Reset"), MB_YESNO | MB_ICONWARNING) == IDYES)
+ m_tagedit.SetText(TAGSDEFAULT);
+}
+
+void CFeedEditor::OnHelp(CCtrlBase*)
+{
+ CMStringW wszTagHelp;
+ wszTagHelp.Format(L"%s - %s\n%s - %s\n%s - %s\n%s - %s\n%s - %s\n%s - %s\n%s - %s",
+ L"#<title>#", TranslateT("The title of the item."),
+ L"#<description>#", TranslateT("The item synopsis."),
+ L"#<link>#", TranslateT("The URL of the item."),
+ L"#<author>#", TranslateT("Email address of the author of the item."),
+ L"#<comments>#", TranslateT("URL of a page for comments relating to the item."),
+ L"#<guid>#", TranslateT("A string that uniquely identifies the item."),
+ L"#<category>#", TranslateT("Specify one or more categories that the item belongs to."));
+ MessageBox(m_hwnd, wszTagHelp, TranslateT("Feed Tag Help"), MB_OK);
+}
+
+void CFeedEditor::OnOk(CCtrlBase*)
+{
+ ptrW strfeedtitle(m_feedtitle.GetText());
+ if (!strfeedtitle || mir_wstrcmp(strfeedtitle, L"") == 0) {
+ MessageBox(m_hwnd, TranslateT("Enter Feed name"), TranslateT("Error"), MB_OK);
+ return;
+ }
+
+ ptrW strfeedurl(m_feedurl.GetText());
+ if (!strfeedurl || mir_wstrcmp(strfeedurl, L"http://") == 0 || mir_wstrcmp(strfeedurl, L"") == 0) {
+ MessageBox(m_hwnd, TranslateT("Enter Feed URL"), TranslateT("Error"), MB_OK);
+ return;
+ }
+
+ ptrW strtagedit(m_tagedit.GetText());
+ if (!strtagedit || mir_wstrcmp(strtagedit, L"") == 0) {
+ MessageBox(m_hwnd, TranslateT("Enter message format"), TranslateT("Error"), MB_OK);
+ return;
+ }
+
+ MCONTACT hContact;
+ if (m_iItem == -1 && m_hContact == NULL) {
+ hContact = db_add_contact();
+ Proto_AddToContact(hContact, MODULENAME);
+ g_plugin.setByte(hContact, "CheckState", 1);
+ }
+ else hContact = m_hContact;
+
+ g_plugin.setWString(hContact, "Nick", strfeedtitle);
+ g_plugin.setWString(hContact, "URL", strfeedurl);
+ g_plugin.setDword(hContact, "UpdateTime", m_checktime.GetInt());
+ g_plugin.setWString(hContact, "MsgFormat", strtagedit);
+ g_plugin.setWord(hContact, "Status", Proto_GetStatus(MODULENAME));
+ if (m_useauth.IsChecked()) {
+ g_plugin.setByte(hContact, "UseAuth", 1);
+ g_plugin.setWString(hContact, "Login", m_login.GetText());
+ g_plugin.setString(hContact, "Password", m_password.GetTextA());
+ }
+ else {
+ g_plugin.delSetting(hContact, "UseAuth");
+ g_plugin.delSetting(hContact, "Login");
+ g_plugin.delSetting(hContact, "Password");
+ }
+
+ if (m_iItem == -1 && m_list != nullptr && m_hContact == NULL) {
+ int iItem = m_list->AddItem(strfeedtitle, -1);
+ m_list->SetItem(iItem, 1, strfeedurl);
+ m_list->SetCheckState(iItem, 1);
+ }
+ else if (m_iItem > -1) {
+ m_list->SetItem(m_iItem, 0, strfeedtitle);
+ m_list->SetItem(m_iItem, 1, strfeedurl);
+ }
+}
+
+bool CFeedEditor::OnClose()
+{
+ g_arFeeds.remove(this);
+ Utils_SaveWindowPosition(m_hwnd, NULL, MODULENAME, m_iItem == -1 ? "AddDlg" : "ChangeDlg");
+ if (pAddFeedDialog == this)
+ pAddFeedDialog = nullptr;
+ return true;
+}
+
+void CFeedEditor::OnUseAuth(CCtrlBase*)
+{
+ m_login.Enable(m_useauth.GetState());
+ m_password.Enable(m_useauth.GetState());
+}
+
+void COptionsMain::UpdateList()
+{
+ for (auto &hContact : Contacts(MODULENAME)) {
+ UpdateListFlag = TRUE;
+ ptrW ptszNick(g_plugin.getWStringA(hContact, "Nick"));
+ if (ptszNick) {
+ int iItem = m_feeds.AddItem(ptszNick, -1);
+
+ ptrW ptszURL(g_plugin.getWStringA(hContact, "URL"));
+ if (ptszURL) {
+ m_feeds.SetItem(iItem, 1, ptszURL);
+ m_feeds.SetCheckState(iItem, g_plugin.getByte(hContact, "CheckState", 1));
+ }
+ }
+ }
+ UpdateListFlag = FALSE;
+}
+
+COptionsMain::COptionsMain() :
+ CDlgBase(g_plugin, IDD_OPTIONS),
+ m_feeds(this, IDC_FEEDLIST),
+ m_add(this, IDC_ADD),
+ m_change(this, IDC_CHANGE),
+ m_delete(this, IDC_REMOVE),
+ m_import(this, IDC_IMPORT),
+ m_export(this, IDC_EXPORT),
+ m_checkonstartup(this, IDC_STARTUPRETRIEVE)
+{
+ CreateLink(m_checkonstartup, "StartupRetrieve", DBVT_BYTE, 1);
+
+ m_add.OnClick = Callback(this, &COptionsMain::OnAddButtonClick);
+ m_change.OnClick = Callback(this, &COptionsMain::OnChangeButtonClick);
+ m_delete.OnClick = Callback(this, &COptionsMain::OnDeleteButtonClick);
+ m_import.OnClick = Callback(this, &COptionsMain::OnImportButtonClick);
+ m_export.OnClick = Callback(this, &COptionsMain::OnExportButtonClick);
+
+ m_feeds.OnItemChanged = Callback(this, &COptionsMain::OnFeedListItemChanged);
+ m_feeds.OnDoubleClick = Callback(this, &COptionsMain::OnFeedListDoubleClick);
+
+}
+
+bool COptionsMain::OnInitDialog()
+{
+ CDlgBase::OnInitDialog();
+ m_change.Disable();
+ m_delete.Disable();
+ m_feeds.SetExtendedListViewStyle(LVS_EX_FULLROWSELECT | LVS_EX_CHECKBOXES);
+ m_feeds.AddColumn(0, TranslateT("Feed"), 160);
+ m_feeds.AddColumn(1, TranslateT("URL"), 276);
+ UpdateList();
+ return true;
+}
+
+bool COptionsMain::OnApply()
+{
+ for (auto &hContact : Contacts(MODULENAME)) {
+ ptrW dbNick(g_plugin.getWStringA(hContact, "Nick"));
+ for (int i = 0; i < m_feeds.GetItemCount(); i++) {
+ wchar_t nick[MAX_PATH];
+ m_feeds.GetItemText(i, 0, nick, _countof(nick));
+ if (mir_wstrcmp(dbNick, nick) == 0) {
+ g_plugin.setByte(hContact, "CheckState", m_feeds.GetCheckState(i));
+ if (!m_feeds.GetCheckState(i))
+ db_set_b(hContact, "CList", "Hidden", 1);
+ else
+ db_unset(hContact, "CList", "Hidden");
+ }
+ }
+ }
+ return true;
+}
+
+void COptionsMain::OnAddButtonClick(CCtrlBase*)
+{
+ if (pAddFeedDialog == nullptr) {
+ pAddFeedDialog = new CFeedEditor(-1, &m_feeds, NULL);
+ pAddFeedDialog->SetParent(m_hwnd);
+ pAddFeedDialog->Show();
+ }
+ else {
+ SetForegroundWindow(pAddFeedDialog->GetHwnd());
+ SetFocus(pAddFeedDialog->GetHwnd());
+ }
+}
+
+void COptionsMain::OnChangeButtonClick(CCtrlBase*)
+{
+ int isel = m_feeds.GetSelectionMark();
+ CFeedEditor *pDlg = nullptr;
+ for (auto &it : g_arFeeds) {
+ wchar_t nick[MAX_PATH], url[MAX_PATH];
+ m_feeds.GetItemText(isel, 0, nick, _countof(nick));
+ m_feeds.GetItemText(isel, 1, url, _countof(url));
+
+ ptrW dbNick(g_plugin.getWStringA(it->getContact(), "Nick"));
+ if ((dbNick == NULL) || (mir_wstrcmp(dbNick, nick) != 0))
+ continue;
+
+ ptrW dbURL(g_plugin.getWStringA(it->getContact(), "URL"));
+ if ((dbURL == NULL) || (mir_wstrcmp(dbURL, url) != 0))
+ continue;
+
+ pDlg = it;
+ }
+
+ if (pDlg == nullptr) {
+ pDlg = new CFeedEditor(isel, &m_feeds, NULL);
+ pDlg->SetParent(m_hwnd);
+ pDlg->Show();
+ }
+ else {
+ SetForegroundWindow(pDlg->GetHwnd());
+ SetFocus(pDlg->GetHwnd());
+ }
+}
+
+void COptionsMain::OnDeleteButtonClick(CCtrlBase*)
+{
+ if (MessageBox(m_hwnd, TranslateT("Are you sure?"), TranslateT("Contact deleting"), MB_YESNO | MB_ICONWARNING) == IDYES) {
+ wchar_t nick[MAX_PATH], url[MAX_PATH];
+ int isel = m_feeds.GetSelectionMark();
+ m_feeds.GetItemText(isel, 0, nick, _countof(nick));
+ m_feeds.GetItemText(isel, 1, url, _countof(url));
+
+ for (auto &hContact : Contacts(MODULENAME)) {
+ ptrW dbNick(g_plugin.getWStringA(hContact, "Nick"));
+ if (dbNick == NULL)
+ break;
+ if (mir_wstrcmp(dbNick, nick))
+ continue;
+
+ ptrW dbURL(g_plugin.getWStringA(hContact, "URL"));
+ if (dbURL == NULL)
+ break;
+ if (mir_wstrcmp(dbURL, url))
+ continue;
+
+ db_delete_contact(hContact);
+ m_feeds.DeleteItem(isel);
+ break;
+ }
+ }
+}
+
+void COptionsMain::OnImportButtonClick(CCtrlBase*)
+{
+ if (pImportDialog == nullptr) {
+ pImportDialog = new CImportFeed(&m_feeds);
+ pImportDialog->Show();
+ pImportDialog->SetParent(m_hwnd);
+ }
+}
+
+void COptionsMain::OnExportButtonClick(CCtrlBase*)
+{
+ if (pExportDialog == nullptr) {
+ pExportDialog = new CExportFeed();
+ pExportDialog->Show();
+ pExportDialog->SetParent(m_hwnd);
+ }
+}
+
+void COptionsMain::OnFeedListItemChanged(CCtrlListView::TEventInfo *evt)
+{
+ int isel = m_feeds.GetSelectionMark();
+ if (isel == -1) {
+ m_change.Disable();
+ m_delete.Disable();
+ }
+ else {
+ m_change.Enable();
+ m_delete.Enable();
+ }
+ if (((evt->nmlv->uNewState ^ evt->nmlv->uOldState) & LVIS_STATEIMAGEMASK) && !UpdateListFlag)
+ NotifyChange();
+}
+
+void COptionsMain::OnFeedListDoubleClick(CCtrlBase*)
+{
+ int isel = m_feeds.GetHotItem();
+ if (isel != -1) {
+ CFeedEditor *pDlg = new CFeedEditor(isel, &m_feeds, 0);
+ pDlg->SetParent(m_hwnd);
+ pDlg->Show();
+ }
+}
+
+int OptInit(WPARAM wParam, LPARAM)
+{
+ OPTIONSDIALOGPAGE odp = {};
+ odp.flags = ODPF_BOLDGROUPS | ODPF_UNICODE;
+ odp.szGroup.w = LPGENW("Network");
+ odp.szTitle.w = LPGENW("News Aggregator");
+ odp.pDialog = new COptionsMain();
+ g_plugin.addOptions(wParam, &odp);
+ return 0;
+}
diff --git a/protocols/NewsAggregator/Src/Options.h b/protocols/NewsAggregator/Src/Options.h
new file mode 100644
index 0000000000..2389eb9bb9
--- /dev/null
+++ b/protocols/NewsAggregator/Src/Options.h
@@ -0,0 +1,162 @@
+#ifndef _OPTIONS_H_
+#define _OPTIONS_H_
+
+class COptionsMain : public CDlgBase
+{
+private:
+ CCtrlListView m_feeds;
+ CCtrlButton m_add;
+ CCtrlButton m_change;
+ CCtrlButton m_delete;
+ CCtrlButton m_import;
+ CCtrlButton m_export;
+ CCtrlCheck m_checkonstartup;
+
+protected:
+ bool OnInitDialog() override;
+ bool OnApply() override;
+
+ void OnAddButtonClick(CCtrlBase*);
+ void OnChangeButtonClick(CCtrlBase*);
+ void OnDeleteButtonClick(CCtrlBase*);
+ void OnImportButtonClick(CCtrlBase*);
+ void OnExportButtonClick(CCtrlBase*);
+
+ void OnFeedListItemChanged(CCtrlListView::TEventInfo *evt);
+ void OnFeedListDoubleClick(CCtrlBase*);
+
+ void UpdateList();
+
+public:
+ COptionsMain();
+};
+
+class CFeedEditor : public CDlgBase
+{
+ friend class CAuthRequest;
+
+private:
+ typedef CDlgBase CSuper;
+
+ int m_iItem;
+ CCtrlListView *m_list;
+ MCONTACT m_hContact;
+
+ CCtrlEdit m_feedtitle;
+ CCtrlEdit m_feedurl;
+ CCtrlEdit m_checktime;
+ CCtrlSpin m_checktimespin;
+ CCtrlButton m_checkfeed;
+ CCtrlEdit m_tagedit;
+ CCtrlButton m_reset;
+ CCtrlButton m_help;
+ CCtrlButton m_ok;
+
+protected:
+ bool OnInitDialog() override;
+ bool OnClose() override;
+
+ void OnCheckFeed(CCtrlBase*);
+ void OnReset(CCtrlBase*);
+ void OnHelp(CCtrlBase*);
+ void OnOk(CCtrlBase*);
+ void OnUseAuth(CCtrlBase*);
+
+public:
+ CCtrlCheck m_useauth;
+ CCtrlEdit m_login;
+ CCtrlEdit m_password;
+
+ CFeedEditor(int iItem, CCtrlListView *m_list, MCONTACT Contact);
+
+ __inline MCONTACT getContact() const { return m_hContact; }
+};
+
+class CImportFeed : public CDlgBase
+{
+private:
+ typedef CDlgBase CSuper;
+
+ CCtrlListView *m_list;
+
+ CCtrlEdit m_importfile;
+ CCtrlButton m_browsefile;
+ CCtrlListBox m_feedslist;
+ CCtrlListBox m_feedsimportlist;
+ CCtrlButton m_addfeed;
+ CCtrlButton m_removefeed;
+ CCtrlButton m_addallfeeds;
+ CCtrlButton m_removeallfeeds;
+ CCtrlButton m_ok;
+
+protected:
+ bool OnInitDialog() override;
+ bool OnClose() override;
+
+ void OnBrowseFile(CCtrlBase*);
+ void OnAddFeed(CCtrlBase*);
+ void OnRemoveFeed(CCtrlBase*);
+ void OnAddAllFeeds(CCtrlBase*);
+ void OnRemoveAllFeeds(CCtrlBase*);
+ void OnOk(CCtrlBase*);
+
+ void OnFeedsList(CCtrlBase*);
+ void OnFeedsImportList(CCtrlBase*);
+
+public:
+ CImportFeed(CCtrlListView *m_list);
+};
+
+class CExportFeed : public CDlgBase
+{
+private:
+ typedef CDlgBase CSuper;
+
+ CCtrlListBox m_feedslist;
+ CCtrlListBox m_feedsexportlist;
+ CCtrlButton m_addfeed;
+ CCtrlButton m_removefeed;
+ CCtrlButton m_addallfeeds;
+ CCtrlButton m_removeallfeeds;
+ CCtrlButton m_ok;
+
+protected:
+ bool OnInitDialog() override;
+ bool OnClose() override;
+
+ void OnAddFeed(CCtrlBase*);
+ void OnRemoveFeed(CCtrlBase*);
+ void OnAddAllFeeds(CCtrlBase*);
+ void OnRemoveAllFeeds(CCtrlBase*);
+ void OnOk(CCtrlBase*);
+
+ void OnFeedsList(CCtrlBase*);
+ void OnFeedsExportList(CCtrlBase*);
+
+public:
+ CExportFeed();
+};
+
+class CAuthRequest : public CDlgBase
+{
+private:
+ typedef CDlgBase CSuper;
+
+ CFeedEditor *m_pDlg;
+ MCONTACT m_hContact;
+
+ CCtrlBase m_feedname;
+ CCtrlEdit m_username;
+ CCtrlEdit m_password;
+ CCtrlButton m_ok;
+
+protected:
+ bool OnInitDialog() override;
+
+ void OnOk(CCtrlBase*);
+
+public:
+ CAuthRequest(CFeedEditor *pDlg, MCONTACT hContact);
+};
+
+#endif //_OPTIONS_H_ \ 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..b5b8c9f028
--- /dev/null
+++ b/protocols/NewsAggregator/Src/Services.cpp
@@ -0,0 +1,261 @@
+/*
+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 "stdafx.h"
+
+int g_nStatus = ID_STATUS_ONLINE;
+UINT_PTR timerId = 0;
+HANDLE hTBButton = nullptr, hNewsAggregatorFolder = nullptr;
+
+int OnFoldersChanged(WPARAM, LPARAM)
+{
+ FoldersGetCustomPathT(hNewsAggregatorFolder, tszRoot, MAX_PATH, L"");
+ return 0;
+}
+
+int NewsAggrInit(WPARAM, LPARAM)
+{
+ if (hNewsAggregatorFolder = FoldersRegisterCustomPathT(LPGEN("Avatars"), LPGEN("News Aggregator"), MIRANDA_USERDATAT L"\\Avatars\\" _A2W(DEFAULT_AVATARS_FOLDER)))
+ FoldersGetCustomPathT(hNewsAggregatorFolder, tszRoot, MAX_PATH, L"");
+ else
+ mir_wstrncpy(tszRoot, VARSW(L"%miranda_userdata%\\Avatars\\" _A2W(DEFAULT_AVATARS_FOLDER)), _countof(tszRoot));
+
+ for (auto &hContact : Contacts(MODULENAME)) {
+ if (!g_plugin.getByte("StartupRetrieve", 1))
+ g_plugin.setDword(hContact, "LastCheck", (DWORD)time(0));
+ g_plugin.setWord(hContact, "Status", ID_STATUS_ONLINE);
+ }
+
+ NetlibInit();
+ InitMenu();
+
+ HookEvent(ME_TTB_MODULELOADED, OnToolbarLoaded);
+ HookEvent(ME_FOLDERS_PATH_CHANGED, OnFoldersChanged);
+
+ // timer for the first update
+ timerId = SetTimer(nullptr, 0, 10000, timerProc2); // first update is 10 sec after load
+
+ return 0;
+}
+
+int NewsAggrPreShutdown(WPARAM, LPARAM)
+{
+ KillTimer(nullptr, timerId);
+ NetlibUnInit();
+ return 0;
+}
+
+INT_PTR NewsAggrGetName(WPARAM wParam, LPARAM lParam)
+{
+ if(lParam) {
+ mir_strncpy((char *)lParam, MODULENAME, wParam);
+ return 0;
+ }
+
+ return 1;
+}
+
+INT_PTR NewsAggrGetCaps(WPARAM wp, LPARAM)
+{
+ 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";
+ default:
+ return 0;
+ }
+}
+
+INT_PTR NewsAggrSetStatus(WPARAM wp, LPARAM)
+{
+ int nStatus = (int)wp;
+ if ((ID_STATUS_ONLINE == nStatus) || (ID_STATUS_OFFLINE == nStatus)) {
+ int nOldStatus = g_nStatus;
+ if(nStatus != g_nStatus) {
+ g_nStatus = nStatus;
+
+ for (auto &hContact : Contacts(MODULENAME))
+ g_plugin.setWord(hContact, "Status", nStatus);
+
+ ProtoBroadcastAck(MODULENAME, NULL, ACKTYPE_STATUS, ACKRESULT_SUCCESS, (HANDLE)nOldStatus, (LPARAM)g_nStatus);
+ }
+ }
+
+ return 0;
+}
+
+INT_PTR NewsAggrGetStatus(WPARAM, LPARAM)
+{
+ return g_nStatus;
+}
+
+INT_PTR NewsAggrLoadIcon(WPARAM wParam, LPARAM)
+{
+ return (LOWORD(wParam) == PLI_PROTOCOL) ? (INT_PTR)CopyIcon(LoadIconEx("main", FALSE)) : 0;
+}
+
+static void __cdecl AckThreadProc(void *param)
+{
+ Sleep(100);
+ ProtoBroadcastAck(MODULENAME, (MCONTACT)param, ACKTYPE_GETINFO, ACKRESULT_SUCCESS, (HANDLE)1);
+}
+
+INT_PTR NewsAggrGetInfo(WPARAM, LPARAM lParam)
+{
+ CCSDATA *ccs = (CCSDATA *)lParam;
+ mir_forkthread(AckThreadProc, (void*)ccs->hContact);
+ return 0;
+}
+
+INT_PTR CheckAllFeeds(WPARAM, LPARAM lParam)
+{
+ for (auto &hContact : Contacts(MODULENAME)) {
+ if (lParam && g_plugin.getDword(hContact, "UpdateTime", DEFAULT_UPDATE_TIME))
+ UpdateListAdd(hContact);
+ else if (!lParam)
+ UpdateListAdd(hContact);
+ }
+ if (!ThreadRunning)
+ mir_forkthread(UpdateThreadProc);
+
+ return 0;
+}
+
+INT_PTR AddFeed(WPARAM, LPARAM)
+{
+ if (pAddFeedDialog == nullptr) {
+ pAddFeedDialog = new CFeedEditor(-1, nullptr, NULL);
+ pAddFeedDialog->Show();
+ }
+ else {
+ SetForegroundWindow(pAddFeedDialog->GetHwnd());
+ SetFocus(pAddFeedDialog->GetHwnd());
+ }
+ return 0;
+}
+
+INT_PTR ChangeFeed(WPARAM hContact, LPARAM)
+{
+ CFeedEditor *pDlg = nullptr;
+ for (auto &it : g_arFeeds)
+ if (it->getContact() == hContact)
+ pDlg = it;
+
+ if (pDlg == nullptr) {
+ pDlg = new CFeedEditor(-1, nullptr, (MCONTACT)hContact);
+ pDlg->Show();
+ }
+ else {
+ SetForegroundWindow(pDlg->GetHwnd());
+ SetFocus(pDlg->GetHwnd());
+ }
+ return 0;
+}
+
+INT_PTR ImportFeeds(WPARAM, LPARAM)
+{
+ if (pImportDialog == nullptr)
+ pImportDialog = new CImportFeed(nullptr);
+ pImportDialog->Show();
+ return 0;
+}
+
+INT_PTR ExportFeeds(WPARAM, LPARAM)
+{
+ if (pExportDialog == nullptr)
+ pExportDialog = new CExportFeed();
+ pExportDialog->Show();
+ return 0;
+}
+
+INT_PTR CheckFeed(WPARAM hContact, LPARAM)
+{
+ if(IsMyContact((MCONTACT)hContact))
+ UpdateListAdd((MCONTACT)hContact);
+ if ( !ThreadRunning)
+ mir_forkthread(UpdateThreadProc);
+ 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) && g_plugin.getDword(pai->hContact, "UpdateTime", DEFAULT_UPDATE_TIME))
+ UpdateListAdd(pai->hContact);
+ if (g_plugin.getByte("AutoUpdate", 1) != 0 && !ThreadRunning)
+ mir_forkthread(UpdateThreadProc, (void *)TRUE);
+
+ ptrW ptszImageURL(g_plugin.getWStringA(pai->hContact, "ImageURL"));
+ return (ptszImageURL == nullptr) ? GAIR_NOAVATAR : GAIR_WAITFOR;
+}
+
+INT_PTR NewsAggrRecvMessage(WPARAM, LPARAM lParam)
+{
+ PROTOACCOUNT *pa = Proto_GetAccount(MODULENAME);
+ if (pa && pa->ppro) {
+ CCSDATA *ccs = (CCSDATA*)lParam;
+ pa->ppro->PROTO_INTERFACE::RecvMsg(ccs->hContact, (PROTORECVEVENT*)ccs->lParam);
+ }
+
+ return 0;
+}
+
+void UpdateMenu(bool State)
+{
+ if (!State) // to enable auto-update
+ Menu_ModifyItem(hService2[0], LPGENW("Auto Update Enabled"), GetIconHandle("enabled"));
+ else // to disable auto-update
+ Menu_ModifyItem(hService2[0], LPGENW("Auto Update Disabled"), GetIconHandle("disabled"));
+
+ CallService(MS_TTB_SETBUTTONSTATE, (WPARAM)hTBButton, State ? TTBST_PUSHED : 0);
+ g_plugin.setByte("AutoUpdate", !State);
+}
+
+// update the newsaggregator auto-update menu item when click on it
+INT_PTR EnableDisable(WPARAM, LPARAM)
+{
+ UpdateMenu(g_plugin.getByte("AutoUpdate", 1) != 0);
+ NewsAggrSetStatus(g_plugin.getByte("AutoUpdate", 1) ? ID_STATUS_ONLINE : ID_STATUS_OFFLINE, 0);
+ return 0;
+}
+
+int OnToolbarLoaded(WPARAM, LPARAM)
+{
+ TTBButton ttb = {};
+ ttb.name = LPGEN("Enable/disable auto update");
+ ttb.pszService = MS_NEWSAGGREGATOR_ENABLED;
+ ttb.pszTooltipUp = LPGEN("Auto Update Enabled");
+ ttb.pszTooltipDn = LPGEN("Auto Update Disabled");
+ ttb.hIconHandleUp = GetIconHandle("enabled");
+ ttb.hIconHandleDn = GetIconHandle("disabled");
+ ttb.dwFlags = (g_plugin.getByte("AutoUpdate", 1) ? 0 : TTBBF_PUSHED) | TTBBF_ASPUSHBUTTON | TTBBF_VISIBLE;
+ hTBButton = g_plugin.addTTB(&ttb);
+ return 0;
+}
diff --git a/protocols/NewsAggregator/Src/Update.cpp b/protocols/NewsAggregator/Src/Update.cpp
new file mode 100644
index 0000000000..96990dbcd2
--- /dev/null
+++ b/protocols/NewsAggregator/Src/Update.cpp
@@ -0,0 +1,139 @@
+/*
+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 "stdafx.h"
+
+// check if Feed is currently updating
+bool ThreadRunning;
+UPDATELIST *UpdateListHead = nullptr;
+UPDATELIST *UpdateListTail = nullptr;
+
+// main auto-update timer
+void CALLBACK timerProc(HWND, UINT, UINT_PTR, DWORD)
+{
+ // only run if it is not current updating and the auto update option is enabled
+ if (!ThreadRunning && !Miranda_IsTerminated()) {
+ bool HaveUpdates = FALSE;
+ for (auto &hContact : Contacts(MODULENAME)) {
+ if (g_plugin.getDword(hContact, "UpdateTime", DEFAULT_UPDATE_TIME)) {
+ double diff = difftime(time(0), (time_t)g_plugin.getDword(hContact, "LastCheck", 0));
+ if (g_plugin.getByte("AutoUpdate", 1) != 0 && diff >= g_plugin.getDword(hContact, "UpdateTime", DEFAULT_UPDATE_TIME) * 60) {
+ UpdateListAdd(hContact);
+ HaveUpdates = TRUE;
+ }
+ }
+ }
+ if (!ThreadRunning && HaveUpdates)
+ mir_forkthread(UpdateThreadProc);
+ }
+}
+
+// temporary timer for first run
+// when this is run, it kill the old startup timer and create the permenant one above
+void CALLBACK timerProc2(HWND, UINT, UINT_PTR, DWORD)
+{
+ KillTimer(nullptr, timerId);
+ ThreadRunning = FALSE;
+
+ if (g_plugin.getByte("AutoUpdate", 1) && !Miranda_IsTerminated()) {
+ if (g_plugin.getByte("StartupRetrieve", 1))
+ CheckAllFeeds(0, 1);
+ timerId = SetTimer(nullptr, 0, 30000, (TIMERPROC)timerProc);
+ }
+}
+
+void UpdateListAdd(MCONTACT hContact)
+{
+ UPDATELIST *newItem = (UPDATELIST*)mir_alloc(sizeof(UPDATELIST));
+ newItem->hContact = hContact;
+ newItem->next = nullptr;
+
+ WaitForSingleObject(hUpdateMutex, INFINITE);
+
+ if (UpdateListTail == nullptr)
+ UpdateListHead = newItem;
+ else UpdateListTail->next = newItem;
+ UpdateListTail = newItem;
+
+ ReleaseMutex(hUpdateMutex);
+}
+
+MCONTACT UpdateGetFirst()
+{
+ MCONTACT hContact = NULL;
+
+ WaitForSingleObject(hUpdateMutex, INFINITE);
+
+ if (UpdateListHead != nullptr) {
+ UPDATELIST* Item = UpdateListHead;
+ hContact = Item->hContact;
+ UpdateListHead = Item->next;
+ mir_free(Item);
+
+ if (UpdateListHead == nullptr)
+ UpdateListTail = nullptr;
+ }
+
+ ReleaseMutex(hUpdateMutex);
+
+ return hContact;
+}
+
+void DestroyUpdateList(void)
+{
+ WaitForSingleObject(hUpdateMutex, INFINITE);
+
+ // free the list one by one
+ UPDATELIST *temp = UpdateListHead;
+ while (temp != nullptr) {
+ UpdateListHead = temp->next;
+ mir_free(temp);
+ temp = UpdateListHead;
+ }
+ // make sure the entire list is clear
+ UpdateListTail = nullptr;
+
+ ReleaseMutex(hUpdateMutex);
+}
+
+void UpdateThreadProc(void *AvatarCheck)
+{
+ WaitForSingleObject(hUpdateMutex, INFINITE);
+ if (ThreadRunning) {
+ ReleaseMutex(hUpdateMutex);
+ return;
+ }
+ ThreadRunning = TRUE; // prevent 2 instance of this thread running
+ ReleaseMutex(hUpdateMutex);
+
+ CoInitializeEx(nullptr, COINIT_APARTMENTTHREADED);
+
+ // update news by getting the first station from the queue until the queue is empty
+ while (UpdateListHead != nullptr && !Miranda_IsTerminated()) {
+ if (AvatarCheck != nullptr)
+ CheckCurrentFeedAvatar(UpdateGetFirst());
+ else
+ CheckCurrentFeed(UpdateGetFirst());
+ }
+
+ // exit the update thread
+ ThreadRunning = FALSE;
+
+ CoUninitialize();
+}
diff --git a/protocols/NewsAggregator/Src/Utils.cpp b/protocols/NewsAggregator/Src/Utils.cpp
new file mode 100644
index 0000000000..80248ba48f
--- /dev/null
+++ b/protocols/NewsAggregator/Src/Utils.cpp
@@ -0,0 +1,445 @@
+/*
+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 "stdafx.h"
+
+HNETLIBUSER hNetlibUser = nullptr;
+HNETLIBCONN hNetlibHttp;
+bool UpdateListFlag = FALSE;
+
+bool IsMyContact(MCONTACT hContact)
+{
+ const char *szProto = GetContactProto(hContact);
+ return szProto != nullptr && mir_strcmp(MODULENAME, szProto) == 0;
+}
+
+void NetlibInit()
+{
+ NETLIBUSER nlu = {};
+ nlu.flags = NUF_OUTGOING | NUF_INCOMING | NUF_HTTPCONNS | NUF_UNICODE;
+ nlu.szDescriptiveName.w = TranslateT("NewsAggregator HTTP connections");
+ nlu.szSettingsModule = MODULENAME;
+ hNetlibUser = Netlib_RegisterUser(&nlu);
+}
+
+void NetlibUnInit()
+{
+ Netlib_CloseHandle(hNetlibUser);
+ hNetlibUser = nullptr;
+}
+
+void GetNewsData(wchar_t *tszUrl, char **szData, MCONTACT hContact, CFeedEditor *pEditDlg)
+{
+ Netlib_LogfW(hNetlibUser, L"Getting feed data %s.", tszUrl);
+ NETLIBHTTPREQUEST nlhr = { 0 };
+
+ // initialize the netlib request
+ nlhr.cbSize = sizeof(nlhr);
+ nlhr.requestType = REQUEST_GET;
+ nlhr.flags = NLHRF_DUMPASTEXT | NLHRF_HTTP11 | NLHRF_REDIRECT;
+ if (wcsstr(tszUrl, L"https://") != nullptr)
+ nlhr.flags |= NLHRF_SSL;
+ char *szUrl = mir_u2a(tszUrl);
+ nlhr.szUrl = szUrl;
+ nlhr.nlc = hNetlibHttp;
+
+ // change the header so the plugin is pretended to be IE 6 + WinXP
+ NETLIBHTTPHEADER headers[5];
+ nlhr.headersCount = 4;
+ nlhr.headers = headers;
+ nlhr.headers[0].szName = "User-Agent";
+ nlhr.headers[0].szValue = NETLIB_USER_AGENT;
+ 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";
+ char auth[256];
+ if (g_plugin.getByte(hContact, "UseAuth", 0) || (pEditDlg && pEditDlg->m_useauth.IsChecked()) /*IsDlgButtonChecked(hwndDlg, IDC_USEAUTH)*/) {
+ nlhr.headersCount++;
+ nlhr.headers[4].szName = "Authorization";
+
+ CreateAuthString(auth, hContact, pEditDlg);
+ nlhr.headers[4].szValue = auth;
+ }
+
+ // download the page
+ NETLIBHTTPREQUEST *nlhrReply = Netlib_HttpTransaction(hNetlibUser, &nlhr);
+ if (nlhrReply) {
+ // if the recieved code is 200 OK
+ if (nlhrReply->resultCode == 200 && nlhrReply->dataLength > 0) {
+ Netlib_LogfW(hNetlibUser, L"Code 200: Succeeded getting feed data %s.", tszUrl);
+ // allocate memory and save the retrieved data
+ *szData = (char *)mir_alloc((size_t)(nlhrReply->dataLength + 2));
+ memcpy(*szData, nlhrReply->pData, (size_t)nlhrReply->dataLength);
+ (*szData)[nlhrReply->dataLength] = 0;
+ }
+ else if (nlhrReply->resultCode == 401) {
+ Netlib_LogfW(hNetlibUser, L"Code 401: feed %s needs auth data.", tszUrl);
+
+ if (CAuthRequest(pEditDlg, hContact).DoModal() == IDOK)
+ GetNewsData(tszUrl, szData, hContact, pEditDlg);
+ }
+ else Netlib_LogfW(hNetlibUser, L"Code %d: Failed getting feed data %s.", nlhrReply->resultCode, tszUrl);
+
+ Netlib_FreeHttpRequest(nlhrReply);
+ }
+ else Netlib_LogfW(hNetlibUser, L"Failed getting feed data %s, no response.", tszUrl);
+
+ mir_free(szUrl);
+}
+
+time_t DateToUnixTime(const char *stamp, bool FeedType)
+{
+ struct tm timestamp;
+ char date[9];
+ int i, y;
+ time_t t;
+
+ if (stamp == nullptr)
+ return 0;
+
+ char *p = NEWSTR_ALLOCA(stamp);
+
+ if (FeedType) {
+ // skip '-' chars
+ int si = 0, sj = 0;
+ while (true) {
+ if (p[si] == '-')
+ si++;
+ else if (!(p[sj++] = p[si++]))
+ break;
+ }
+ }
+ else {
+ char monthstr[4], timezonesign[2];
+ int day, month = 0, year, hour, min, sec, timezoneh, timezonem;
+ if (strchr(p, ',')) {
+ strtok(p, ",");
+ p = strtok(nullptr, ",");
+ sscanf(p + 1, "%d %3s %d %d:%d:%d %1s%02d%02d", &day, &monthstr, &year, &hour, &min, &sec, &timezonesign, &timezoneh, &timezonem);
+ if (!mir_strcmpi(monthstr, "Jan"))
+ month = 1;
+ if (!mir_strcmpi(monthstr, "Feb"))
+ month = 2;
+ if (!mir_strcmpi(monthstr, "Mar"))
+ month = 3;
+ if (!mir_strcmpi(monthstr, "Apr"))
+ month = 4;
+ if (!mir_strcmpi(monthstr, "May"))
+ month = 5;
+ if (!mir_strcmpi(monthstr, "Jun"))
+ month = 6;
+ if (!mir_strcmpi(monthstr, "Jul"))
+ month = 7;
+ if (!mir_strcmpi(monthstr, "Aug"))
+ month = 8;
+ if (!mir_strcmpi(monthstr, "Sep"))
+ month = 9;
+ if (!mir_strcmpi(monthstr, "Oct"))
+ month = 10;
+ if (!mir_strcmpi(monthstr, "Nov"))
+ month = 11;
+ if (!mir_strcmpi(monthstr, "Dec"))
+ month = 12;
+ if (year < 2000)
+ year += 2000;
+ if (!mir_strcmp(timezonesign, "+"))
+ mir_snprintf(p, 4 + 2 + 2 + 1 + 2 + 1 + 2 + 1 + 2 + 1, "%04d%02d%02dT%02d:%02d:%02d", year, month, day, hour - timezoneh, min - timezonem, sec);
+ else if (!mir_strcmp(timezonesign, "-"))
+ mir_snprintf(p, 4 + 2 + 2 + 1 + 2 + 1 + 2 + 1 + 2 + 1, "%04d%02d%02dT%02d:%02d:%02d", year, month, day, hour + timezoneh, min + timezonem, sec);
+ else
+ mir_snprintf(p, 4 + 2 + 2 + 1 + 2 + 1 + 2 + 1 + 2 + 1, "%04d%02d%02dT%02d:%02d:%02d", year, month, day, hour, min, sec);
+ }
+ else if (strchr(p, 'T')) {
+ sscanf(p, "%d-%d-%dT%d:%d:%d", &year, &month, &day, &hour, &min, &sec);
+ mir_snprintf(p, 4 + 2 + 2 + 1 + 2 + 1 + 2 + 1 + 2 + 1, "%04d%02d%02dT%02d:%02d:%02d", year, month, day, hour, min, sec);
+ }
+ else {
+ sscanf(p, "%d-%d-%d %d:%d:%d %1s%02d%02d", &year, &month, &day, &hour, &min, &sec, &timezonesign, &timezoneh, &timezonem);
+ if (!mir_strcmp(timezonesign, "+"))
+ mir_snprintf(p, 4 + 2 + 2 + 1 + 2 + 1 + 2 + 1 + 2 + 1, "%04d%02d%02dT%02d:%02d:%02d", year, month, day, hour - timezoneh, min - timezonem, sec);
+ else if (!mir_strcmp(timezonesign, "-"))
+ mir_snprintf(p, 4 + 2 + 2 + 1 + 2 + 1 + 2 + 1 + 2 + 1, "%04d%02d%02dT%02d:%02d:%02d", year, month, day, hour + timezoneh, min + timezonem, sec);
+ else
+ mir_snprintf(p, 4 + 2 + 2 + 1 + 2 + 1 + 2 + 1 + 2 + 1, "%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 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 (sscanf(p, "%d:%d:%d", &timestamp.tm_hour, &timestamp.tm_min, &timestamp.tm_sec) != 3)
+ return 0;
+
+ timestamp.tm_isdst = 0; // DST is already present in _timezone below
+ t = mktime(&timestamp);
+
+ _tzset();
+ t -= (time_t)_timezone;
+ return (t >= 0) ? t : 0;
+}
+
+bool DownloadFile(LPCTSTR tszURL, LPCTSTR tszLocal)
+{
+ NETLIBHTTPREQUEST nlhr = { 0 };
+ nlhr.cbSize = sizeof(nlhr);
+ nlhr.requestType = REQUEST_GET;
+ nlhr.flags = NLHRF_DUMPASTEXT | NLHRF_HTTP11;
+ char *szUrl = mir_u2a(tszURL);
+ nlhr.szUrl = szUrl;
+ NETLIBHTTPHEADER headers[4];
+ nlhr.headersCount = 4;
+ nlhr.headers = headers;
+ nlhr.headers[0].szName = "User-Agent";
+ nlhr.headers[0].szValue = NETLIB_USER_AGENT;
+ 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 = Netlib_HttpTransaction(hNetlibUser, &nlhr);
+ if (pReply) {
+ if ((200 == pReply->resultCode) && (pReply->dataLength > 0)) {
+ char *date = nullptr, *size = nullptr;
+ for (int i = 0; i < pReply->headersCount; i++) {
+ if (!mir_strcmpi(pReply->headers[i].szName, "Last-Modified")) {
+ date = pReply->headers[i].szValue;
+ continue;
+ }
+ else if (!mir_strcmpi(pReply->headers[i].szName, "Content-Length")) {
+ size = pReply->headers[i].szValue;
+ continue;
+ }
+ }
+ if (date != nullptr && size != nullptr) {
+ wchar_t *tsize = mir_a2u(size);
+ struct _stat buf;
+
+ int fh = _wopen(tszLocal, _O_RDONLY);
+ if (fh != -1) {
+ _fstat(fh, &buf);
+ time_t modtime = DateToUnixTime(date, 0);
+ time_t filemodtime = mktime(localtime(&buf.st_atime));
+ if (modtime > filemodtime && buf.st_size != _wtoi(tsize)) {
+ DWORD dwBytes;
+ HANDLE hFile = CreateFile(tszLocal, GENERIC_READ | GENERIC_WRITE, NULL, nullptr, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, nullptr);
+ WriteFile(hFile, pReply->pData, (DWORD)pReply->dataLength, &dwBytes, nullptr);
+ ret = true;
+ if (hFile)
+ CloseHandle(hFile);
+ }
+ _close(fh);
+ }
+ else {
+ DWORD dwBytes;
+ HANDLE hFile = CreateFile(tszLocal, GENERIC_READ | GENERIC_WRITE, NULL, nullptr, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, nullptr);
+ WriteFile(hFile, pReply->pData, (DWORD)pReply->dataLength, &dwBytes, nullptr);
+ ret = true;
+ if (hFile)
+ CloseHandle(hFile);
+ }
+ mir_free(tsize);
+ }
+ else {
+ DWORD dwBytes;
+ HANDLE hFile = CreateFile(tszLocal, GENERIC_READ | GENERIC_WRITE, NULL, nullptr, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, nullptr);
+ WriteFile(hFile, pReply->pData, (DWORD)pReply->dataLength, &dwBytes, nullptr);
+ ret = true;
+ if (hFile)
+ CloseHandle(hFile);
+ }
+ }
+ Netlib_FreeHttpRequest(pReply);
+ }
+
+ mir_free(szUrl);
+
+ return ret;
+}
+
+typedef HRESULT(MarkupCallback)(IHTMLDocument3 *, BSTR &message);
+
+HRESULT TestMarkupServices(BSTR bstrHtml, MarkupCallback *pCallback, BSTR &message)
+{
+ IHTMLDocument3 *pHtmlDocRoot = nullptr;
+
+ // Create the root document -- a "workspace" for parsing.
+ HRESULT hr = CoCreateInstance(CLSID_HTMLDocument, nullptr, CLSCTX_INPROC_SERVER, IID_PPV_ARGS(&pHtmlDocRoot));
+ if (SUCCEEDED(hr) && pHtmlDocRoot) {
+ IPersistStreamInit *pPersistStreamInit = nullptr;
+
+ hr = pHtmlDocRoot->QueryInterface(IID_PPV_ARGS(&pPersistStreamInit));
+ if (SUCCEEDED(hr)) {
+ // Initialize the root document to a default state -- ready for parsing.
+ pPersistStreamInit->InitNew();
+
+ IMarkupServices *pMarkupServices = nullptr;
+ hr = pHtmlDocRoot->QueryInterface(IID_PPV_ARGS(&pMarkupServices));
+ if (SUCCEEDED(hr)) {
+ IMarkupPointer *pMarkupBegin = nullptr;
+ IMarkupPointer *pMarkupEnd = nullptr;
+
+ // These markup pointers indicate the insertion point.
+ hr = pMarkupServices->CreateMarkupPointer(&pMarkupBegin);
+ if (SUCCEEDED(hr))
+ hr = pMarkupServices->CreateMarkupPointer(&pMarkupEnd);
+
+ if (SUCCEEDED(hr) && pMarkupBegin && pMarkupEnd) {
+ IMarkupContainer *pMarkupContainer = nullptr;
+
+ // Parse the string -- the markup container contains the parsed HTML.
+ // Markup pointers are updated to point to begining and end of new container.
+ hr = pMarkupServices->ParseString(bstrHtml, 0, &pMarkupContainer, pMarkupBegin, pMarkupEnd);
+ if (SUCCEEDED(hr) && pMarkupContainer) {
+ IHTMLDocument3 *pHtmlDoc = nullptr;
+
+ // Retrieve the document interface to the markup container.
+ hr = pMarkupContainer->QueryInterface(IID_PPV_ARGS(&pHtmlDoc));
+ if (SUCCEEDED(hr) && pHtmlDoc) {
+ // Invoke the user-defined action for this new fragment.
+ hr = pCallback(pHtmlDoc, message);
+
+ // Clean up.
+ pHtmlDoc->Release();
+ }
+ pMarkupContainer->Release();
+ }
+ pMarkupEnd->Release();
+ }
+ if (pMarkupBegin)
+ pMarkupBegin->Release();
+ pMarkupServices->Release();
+ }
+ pPersistStreamInit->Release();
+ }
+ pHtmlDocRoot->Release();
+ }
+ return hr;
+}
+
+HRESULT TestDocumentText(IHTMLDocument3 *pHtmlDoc, BSTR &message)
+{
+ IHTMLDocument2 *pDoc = nullptr;
+ IHTMLElement *pElem = nullptr;
+ BSTR bstrId = SysAllocString(L"test");
+
+ HRESULT hr = pHtmlDoc->QueryInterface(IID_PPV_ARGS(&pDoc));
+ if (SUCCEEDED(hr) && pDoc) {
+ hr = pDoc->get_body(&pElem);
+ if (SUCCEEDED(hr) && pElem) {
+ BSTR bstrText = nullptr;
+ pElem->get_innerText(&bstrText);
+ message = SysAllocString(bstrText);
+ SysFreeString(bstrText);
+ pElem->Release();
+ }
+
+ pDoc->Release();
+ }
+
+ SysFreeString(bstrId);
+ return hr;
+}
+
+LPCTSTR ClearText(CMStringW &result, const wchar_t *message)
+{
+ BSTR bstrHtml = SysAllocString(message), bstrRes = SysAllocString(L"");
+ HRESULT hr = TestMarkupServices(bstrHtml, &TestDocumentText, bstrRes);
+ if (SUCCEEDED(hr))
+ result = bstrRes;
+ else
+ result = message;
+ SysFreeString(bstrHtml);
+ SysFreeString(bstrRes);
+
+ result.Replace(L"&#163;", L"£"); //pound
+ result.Replace(L"&#178;", L"²"); //sup2
+ result.Replace(L"&#228;", L"ä"); //auml
+ result.Replace(L"&#233;", L"é"); //latin small letter e with acute
+ result.Replace(L"&#235;", L"ë"); //euml
+ result.Replace(L"&#246;", L"ö"); //ouml
+ result.Replace(L"&#382;", L"ž"); //Latin Small Letter Z With Caron
+ result.Replace(L"&#665;", L"ʙ"); //latin letter small capital b
+ result.Replace(L"&#774;", L"˘"); //Combining Breve
+ result.Replace(L"&#769;", L"´"); //Combining Acute Accent острое ударение
+ result.Replace(L"&#959;", L"ό"); // greek small letter omicron with tonos
+ result.Replace(L"&#1123;", L"ѣ"); //Cyrillic Small Letter Yat
+ result.Replace(L"&#1180;", L"Ҝ"); //cyrillic capital letter ka with vertical stroke
+ result.Replace(L"&#8203;", L"");
+ result.Replace(L"&#8206;", L""); //lrm
+ result.Replace(L"&#8207;", L""); //rlm
+ result.Replace(L"&#8209;", L"‑"); //Non-Breaking Hyphen
+ result.Replace(L"&#8227;", L"‣"); //Triangular Bullet
+ result.Replace(L"&#8722;", L"−"); //minus
+ result.Replace(L"&#9786;", L"☺"); //White Smiling Face
+ result.Replace(L"&#65279;", L"");
+
+ result.Trim();
+
+ return result;
+}
+
+MCONTACT GetContactByNick(const wchar_t *nick)
+{
+ for (auto &hContact : Contacts(MODULENAME)) {
+ ptrW contactNick(g_plugin.getWStringA(hContact, "Nick"));
+ if (!mir_wstrcmpi(contactNick, nick))
+ return hContact;
+ }
+ return 0;
+}
+
+MCONTACT GetContactByURL(const wchar_t *url)
+{
+ for (auto &hContact : Contacts(MODULENAME)) {
+ ptrW contactURL(g_plugin.getWStringA(hContact, "URL"));
+ if (!mir_wstrcmpi(contactURL, url))
+ return hContact;
+ }
+ return 0;
+}
diff --git a/protocols/NewsAggregator/Src/resource.h b/protocols/NewsAggregator/Src/resource.h
new file mode 100644
index 0000000000..131a0844ba
--- /dev/null
+++ b/protocols/NewsAggregator/Src/resource.h
@@ -0,0 +1,57 @@
+//{{NO_DEPENDENCIES}}
+// Microsoft Visual C++ generated include file.
+// Used by c:\Temp\Miranda NG\plugins\NewsAggregator\res\Resource.rc
+//
+#define IDD_OPTIONS 101
+#define IDD_AUTHENTICATION 102
+#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 IDI_ENABLED 115
+#define IDI_DISABLED 116
+#define IDD_FEEDEXPORT 140
+#define IDD_FEEDIMPORT 141
+#define IDC_TIMEOUT_VALUE_SPIN 1035
+#define IDC_FEEDLIST 1036
+#define IDC_ADD 1037
+#define IDC_CHANGE 1038
+#define IDC_REMOVE 1039
+#define IDC_IMPORT 1040
+#define IDC_EXPORT 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
+#define IDC_STARTUPRETRIEVE 1052
+#define IDC_FEEDUSERNAME 1105
+#define IDC_FEEDPASSWORD 1106
+#define IDC_FEEDSLIST 1108
+#define IDC_FEEDSEXPORTLIST 1109
+#define IDC_ADDFEED 1110
+#define IDC_REMOVEFEED 1111
+#define IDC_ADDALLFEEDS 1112
+#define IDC_REMOVEALLFEEDS 1113
+#define IDC_IMPORTFILEPATH 1114
+#define IDC_BROWSEIMPORTFILE 1115
+#define IDC_FEEDSIMPORTLIST 1117
+#define IDC_FEEDNAME 1124
+
+// Next default values for new objects
+//
+#ifdef APSTUDIO_INVOKED
+#ifndef APSTUDIO_READONLY_SYMBOLS
+#define _APS_NEXT_RESOURCE_VALUE 117
+#define _APS_NEXT_COMMAND_VALUE 40075
+#define _APS_NEXT_CONTROL_VALUE 1053
+#define _APS_NEXT_SYMED_VALUE 101
+#endif
+#endif
diff --git a/protocols/NewsAggregator/Src/stdafx.cxx b/protocols/NewsAggregator/Src/stdafx.cxx
new file mode 100644
index 0000000000..1b563fc866
--- /dev/null
+++ b/protocols/NewsAggregator/Src/stdafx.cxx
@@ -0,0 +1,18 @@
+/*
+Copyright (C) 2012-19 Miranda NG team (https://miranda-ng.org)
+
+This program is free software; you can redistribute it and/or
+modify it under the terms of the GNU General Public License
+as published by the Free Software Foundation version 2
+of the License.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "stdafx.h" \ No newline at end of file
diff --git a/protocols/NewsAggregator/Src/stdafx.h b/protocols/NewsAggregator/Src/stdafx.h
new file mode 100644
index 0000000000..819e96d69f
--- /dev/null
+++ b/protocols/NewsAggregator/Src/stdafx.h
@@ -0,0 +1,167 @@
+/*
+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.
+*/
+
+#pragma once
+
+// Windows Header Files:
+#include <windows.h>
+#include <commctrl.h>
+#include <time.h>
+#include <malloc.h>
+#include <fcntl.h>
+#include <io.h>
+#include <sys/stat.h>
+#include <mshtml.h>
+
+// Miranda header files
+#include <newpluginapi.h>
+#include <m_clist.h>
+#include <m_langpack.h>
+#include <m_options.h>
+#include <m_protosvc.h>
+#include <m_protoint.h>
+#include <m_database.h>
+#include <m_netlib.h>
+#include <m_icolib.h>
+#include <m_message.h>
+#include <win2k.h>
+#include <m_xml.h>
+#include <m_avatars.h>
+#include <m_hotkeys.h>
+#include <m_gui.h>
+
+#include <m_folders.h>
+#include <m_toptoolbar.h>
+
+#include "Options.h"
+#include "version.h"
+#include "resource.h"
+
+#define MODULENAME "NewsAggregator"
+#define TAGSDEFAULT L"#<title>#\r\n#<link>#\r\n#<description>#"
+#define DEFAULT_AVATARS_FOLDER "NewsAggregator"
+#define DEFAULT_UPDATE_TIME 60
+
+extern CDlgBase *pAddFeedDialog, *pImportDialog, *pExportDialog;
+extern HNETLIBUSER hNetlibUser;
+extern UINT_PTR timerId;
+extern LIST<CFeedEditor> g_arFeeds;
+// check if Feeds is currently updating
+extern bool ThreadRunning;
+extern bool UpdateListFlag;
+extern wchar_t tszRoot[MAX_PATH];
+
+struct CMPlugin : public PLUGIN<CMPlugin>
+{
+ CMPlugin();
+
+ int Load() override;
+ int Unload() override;
+};
+
+//============ STRUCT USED TO MAKE AN UPDATE LIST ============
+
+struct NEWSCONTACTLIST {
+ MCONTACT hContact;
+ struct NEWSCONTACTLIST *next;
+};
+
+typedef struct NEWSCONTACTLIST UPDATELIST;
+
+extern UPDATELIST *UpdateListHead;
+extern UPDATELIST *UpdateListTail;
+
+void UpdateListAdd(MCONTACT hContact);
+void UpdateThreadProc(void*);
+void DestroyUpdateList(void);
+
+extern HANDLE hUpdateMutex;
+extern HGENMENU hService2[7];
+
+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 NewsAggrRecvMessage(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 EnableDisable(WPARAM wParam, LPARAM lParam);
+int OnToolbarLoaded(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(MCONTACT hContact);
+void GetNewsData(wchar_t *szUrl, char **szData, MCONTACT hContact, CFeedEditor *pEditDlg);
+time_t DateToUnixTime(const char *stamp, bool FeedType);
+void CheckCurrentFeed(MCONTACT hContact);
+void CheckCurrentFeedAvatar(MCONTACT hContact);
+LPCTSTR CheckFeed(wchar_t* tszURL, CFeedEditor *pEditDlg);
+void UpdateMenu(bool State);
+LPCTSTR ClearText(CMStringW &value, const wchar_t *message);
+bool DownloadFile(LPCTSTR tszURL, LPCTSTR tszLocal);
+void CreateAuthString(char *auth, MCONTACT hContact, CFeedEditor *pDlg);
+MCONTACT GetContactByNick(const wchar_t *nick);
+MCONTACT GetContactByURL(const wchar_t *url);
+
+// =============== NewsAggregator SERVICES ================
+// Check all Feeds info
+// WPARAM = LPARAM = NULL
+#define MS_NEWSAGGREGATOR_CHECKALLFEEDS "NewsAggregator/CheckAllFeeds"
+
+// Add new Feed channel
+// WPARAM = LPARAM = NULL
+#define MS_NEWSAGGREGATOR_ADDFEED "NewsAggregator/AddNewsFeed"
+
+// Change Feed channel
+// WPARAM = LPARAM = NULL
+#define MS_NEWSAGGREGATOR_CHANGEFEED "NewsAggregator/ChangeNewsFeed"
+
+// Import Feed channels from file
+// WPARAM = LPARAM = NULL
+#define MS_NEWSAGGREGATOR_IMPORTFEEDS "NewsAggregator/ImportFeeds"
+
+// Export Feed channels to file
+// WPARAM = LPARAM = NULL
+#define MS_NEWSAGGREGATOR_EXPORTFEEDS "NewsAggregator/ExportFeeds"
+
+// Check Feed info
+// WPARAM = LPARAM = NULL
+#define MS_NEWSAGGREGATOR_CHECKFEED "NewsAggregator/CheckFeed"
+
+// Enable/disable getting feed info
+// WPARAM = LPARAM = NULL
+#define MS_NEWSAGGREGATOR_ENABLED "NewsAggregator/Enabled"
diff --git a/protocols/NewsAggregator/Src/version.h b/protocols/NewsAggregator/Src/version.h
new file mode 100644
index 0000000000..a7d2126e30
--- /dev/null
+++ b/protocols/NewsAggregator/Src/version.h
@@ -0,0 +1,13 @@
+#define __MAJOR_VERSION 0
+#define __MINOR_VERSION 1
+#define __RELEASE_NUM 0
+#define __BUILD_NUM 5
+
+#include <stdver.h>
+
+#define __PLUGIN_NAME "News aggregator"
+#define __FILENAME "NewsAggregator.dll"
+#define __DESCRIPTION "RSS/Atom news aggregator."
+#define __AUTHOR "Mataes, FREAK_THEMIGHTY"
+#define __AUTHORWEB "https://miranda-ng.org/p/NewsAggregator/"
+#define __COPYRIGHT "© 2012-19 Mataes, FREAK_THEMIGHTY"
diff --git a/protocols/NewsAggregator/docs/AtomText.txt b/protocols/NewsAggregator/docs/AtomText.txt
new file mode 100644
index 0000000000..f6d2723822
--- /dev/null
+++ b/protocols/NewsAggregator/docs/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/docs/RssText.txt b/protocols/NewsAggregator/docs/RssText.txt
new file mode 100644
index 0000000000..b3334ea219
--- /dev/null
+++ b/protocols/NewsAggregator/docs/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/docs/ToDo.txt b/protocols/NewsAggregator/docs/ToDo.txt
new file mode 100644
index 0000000000..09484b7932
--- /dev/null
+++ b/protocols/NewsAggregator/docs/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/docs/subscriptions_test.xml b/protocols/NewsAggregator/docs/subscriptions_test.xml
new file mode 100644
index 0000000000..bae46438dd
--- /dev/null
+++ b/protocols/NewsAggregator/docs/subscriptions_test.xml
@@ -0,0 +1,169 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<opml version="1.0">
+ <head>
+ <title>BasiL: подписки в Google Reader</title>
+ </head>
+ <body>
+ <outline text="ithappens" title="ithappens" type="rss"
+ xmlUrl="http://ithappens.ru/rss" htmlUrl="http://ithappens.ru/"/>
+ <outline title="Computerra" text="Computerra">
+ <outline title="My_Test" text="My_Test">
+ <outline text="bash" title="bash" type="rss"
+ xmlUrl="http://bash.im/rss" htmlUrl="http://bash.im/"/>
+ </outline>
+ <outline text="inside" title="inside" type="rss"
+ xmlUrl="http://www.ctinside.com/feeds/posts/default" htmlUrl="http://www.ctinside.com/"/>
+ <outline text="Компьюлента" title="Компьюлента" type="rss"
+ xmlUrl="http://www.compulenta.ru/rss.xml" htmlUrl="http://www.compulenta.ru"/>
+ <outline text="Статьи Компьютерры"
+ title="Статьи Компьютерры" type="rss"
+ xmlUrl="http://www.computerra.ru/rss.xml" htmlUrl="http://www.computerra.ru"/>
+ </outline>
+ <outline title="Soft" text="Soft">
+ <outline
+ text="Downloads for project cm9-wildfire-s on Google Code"
+ title="Downloads for project cm9-wildfire-s on Google Code"
+ type="rss"
+ xmlUrl="https://code.google.com/feeds/p/cm9-wildfire-s/downloads/basic" htmlUrl="http://code.google.com/p/cm9-wildfire-s/downloads/list"/>
+ <outline text="Downloads for project uawks on Google Code"
+ title="Downloads for project uawks on Google Code"
+ type="rss"
+ xmlUrl="http://code.google.com/feeds/p/uawks/downloads/basic" htmlUrl="http://code.google.com/p/uawks/downloads/list"/>
+ <outline
+ text="Issue updates for project uawks on Google Code"
+ title="Issue updates for project uawks on Google Code"
+ type="rss"
+ xmlUrl="http://code.google.com/feeds/p/uawks/issueupdates/basic" htmlUrl="http://code.google.com/p/uawks/issues/list"/>
+ <outline
+ text="Mercurial commits to project uawks on Google Code"
+ title="Mercurial commits to project uawks on Google Code"
+ type="rss"
+ xmlUrl="http://code.google.com/feeds/p/uawks/hgchanges/basic" htmlUrl="http://code.google.com/p/uawks/source/list"/>
+ <outline text="Punk" title="Punk" type="rss"
+ xmlUrl="http://www.punksoftware.com/rss" htmlUrl="http://punklabs.com/rss"/>
+ <outline text="Tomato by Shibby" title="Tomato by Shibby"
+ type="rss" xmlUrl="http://tomato.groov.pl/?feed=rss2" htmlUrl="http://tomato.groov.pl"/>
+ <outline text="TOR" title="TOR" type="rss"
+ xmlUrl="http://rss.gmane.org/gmane.network.onion-routing.announce" htmlUrl="http://permalink.gmane.org/gmane.network.onion-routing.announce"/>
+ <outline text="VideoLAN" title="VideoLAN" type="rss"
+ xmlUrl="http://www.videolan.org/videolan-news.rss" htmlUrl="http://www.videolan.org/"/>
+ </outline>
+ <outline title="Miranda" text="Miranda">
+ <outline text="Dev Blog" title="Dev Blog" type="rss"
+ xmlUrl="http://feeds.miranda-im.org/mirandadevjournal" htmlUrl="http://www.miranda-im.org"/>
+ <outline text="FLNew" title="FLNew" type="rss"
+ xmlUrl="http://feeds.miranda-im.org/mirandalast10add" htmlUrl="http://addons.miranda-im.org"/>
+ <outline text="FLupd" title="FLupd" type="rss"
+ xmlUrl="http://feeds.miranda-im.org/mirandalast10upd" htmlUrl="http://addons.miranda-im.org"/>
+ <outline text="mir-rl project updates - Google Code"
+ title="mir-rl project updates - Google Code" type="rss"
+ xmlUrl="http://code.google.com/feeds/p/mir-rl/updates/basic" htmlUrl="http://code.google.com/p/mir-rl/updates/list"/>
+ <outline text="Miranda IM" title="Miranda IM" type="rss"
+ xmlUrl="http://feeds.feedburner.com/mirandaannouncements" htmlUrl="http://www.miranda-im.org"/>
+ <outline text="Miranda IM Community"
+ title="Miranda IM Community" type="rss"
+ xmlUrl="http://community.livejournal.com/ru_mirandaim/data/rss" htmlUrl="http://ru-mirandaim.livejournal.com/"/>
+ <outline
+ text="Miranda-Planet - ваша планета Miranda IM ( билды, сборки, скины, плагины, русификация, WiKi, Форум )"
+ title="Miranda-Planet - ваша планета Miranda IM ( билды, сборки, скины, плагины, русификация, WiKi, Форум )"
+ type="rss" xmlUrl="http://miranda-planet.com/rss.xml" htmlUrl="http://miranda-planet.com/"/>
+ <outline text="ruCommunity" title="ruCommunity" type="rss"
+ xmlUrl="http://forum.miranda.im/external.php?type=RSS2" htmlUrl="http://forum.miranda.im"/>
+ </outline>
+ <outline title="Habr" text="Habr">
+ <outline text="Android" title="Android" type="rss"
+ xmlUrl="http://habrahabr.ru/rss/blogs/android/" htmlUrl="http://habrahabr.ru/rss/hub/android/"/>
+ <outline text="Design" title="Design" type="rss"
+ xmlUrl="http://habrahabr.ru/rss/blogs/design/" htmlUrl="http://habrahabr.ru/rss/hub/design/"/>
+ <outline text="DSLR" title="DSLR" type="rss"
+ xmlUrl="http://habrahabr.ru/rss/blogs/dslr/" htmlUrl="http://habrahabr.ru/rss/blog/dslr/"/>
+ <outline text="Future" title="Future" type="rss"
+ xmlUrl="http://habrahabr.ru/rss/blogs/the_future_is_here/" htmlUrl="http://habrahabr.ru/rss/hub/the_future_is_here/"/>
+ <outline text="Google" title="Google" type="rss"
+ xmlUrl="http://habrahabr.ru/rss/blogs/google/" htmlUrl="http://habrahabr.ru/rss/hub/google/"/>
+ <outline text="Hardware" title="Hardware" type="rss"
+ xmlUrl="http://habrahabr.ru/rss/blogs/hardware/" htmlUrl="http://habrahabr.ru/rss/hub/hardware/"/>
+ <outline text="IM" title="IM" type="rss"
+ xmlUrl="http://habrahabr.ru/rss/blogs/im/" htmlUrl="http://habrahabr.ru/rss/hub/im/"/>
+ <outline text="Jabber" title="Jabber" type="rss"
+ xmlUrl="http://habrahabr.ru/rss/blogs/jabber/" htmlUrl="http://habrahabr.ru/rss/blogs/jabber/"/>
+ <outline text="Miranda" title="Miranda" type="rss"
+ xmlUrl="http://habrahabr.ru/rss/blogs/miranda/" htmlUrl="http://habrahabr.ru/rss/blogs/miranda/"/>
+ <outline text="Netbook" title="Netbook" type="rss"
+ xmlUrl="http://habrahabr.ru/rss/blogs/netbook/" htmlUrl="http://habrahabr.ru/rss/hub/netbook/"/>
+ <outline text="OldThings" title="OldThings" type="rss"
+ xmlUrl="http://habrahabr.ru/rss/blogs/retro/" htmlUrl="http://habrahabr.ru/rss/blogs/retro/"/>
+ <outline text="Robots" title="Robots" type="rss"
+ xmlUrl="http://habrahabr.ru/rss/blogs/robot/" htmlUrl="http://habrahabr.ru/rss/hub/robot/"/>
+ <outline text="sciense" title="sciense" type="rss"
+ xmlUrl="http://habrahabr.ru/rss/blogs/popular_science/" htmlUrl="http://habrahabr.ru/rss/hub/popular_science/"/>
+ <outline text="TC" title="TC" type="rss"
+ xmlUrl="http://habrahabr.ru/rss/blogs/totalcmd/" htmlUrl="http://habrahabr.ru/rss/blogs/totalcmd/"/>
+ <outline text="Telecom" title="Telecom" type="rss"
+ xmlUrl="http://habrahabr.ru/rss/blogs/telecom/" htmlUrl="http://habrahabr.ru/rss/hub/telecom/"/>
+ <outline text="Win7" title="Win7" type="rss"
+ xmlUrl="http://habrahabr.ru/rss/blogs/windows7/" htmlUrl="http://habrahabr.ru/rss/blogs/windows7/"/>
+ <outline text="Хабрахабр / Биотехнологии / Захабренные"
+ title="Хабрахабр / Биотехнологии / Захабренные"
+ type="rss"
+ xmlUrl="http://habrahabr.ru/rss/blogs/biotech/" htmlUrl="http://habrahabr.ru/rss/hub/biotech/"/>
+ <outline text="Хабрахабр: Метки / wzor.net"
+ title="Хабрахабр: Метки / wzor.net" type="rss"
+ xmlUrl="http://habrahabr.ru/rss/tag/wzor.net/" htmlUrl="http://habrahabr.ru/rss/tag/wzor.net/"/>
+ </outline>
+ <outline title="News" text="News">
+ <outline text="2КОМ (новости)" title="2КОМ (новости)"
+ type="rss"
+ xmlUrl="http://www.2kom.ru/home/news/-rss.xml" htmlUrl="http://www.2kom.ru/home/news.html"/>
+ <outline text="4PDA" title="4PDA" type="rss"
+ xmlUrl="http://4pda.ru/feed/" htmlUrl="http://4pda.ru/"/>
+ <outline text="FotoTips.ru" title="FotoTips.ru" type="rss"
+ xmlUrl="http://feeds.feedburner.com/fototipsru" htmlUrl="http://fototips.ru"/>
+ <outline text="LifeHack.ru" title="LifeHack.ru" type="rss"
+ xmlUrl="http://www.lifehack.ru/rss/" htmlUrl="http://lifehack.ru"/>
+ <outline text="MForum.ru" title="MForum.ru" type="rss"
+ xmlUrl="http://www.mforum.ru/rss/news.xml" htmlUrl="http://www.mforum.ru/"/>
+ <outline text="Overclockers.ru" title="Overclockers.ru"
+ type="rss"
+ xmlUrl="http://www.overclockers.ru/rss/all.rss" htmlUrl="http://www.overclockers.ru"/>
+ <outline text="revolver.ru" title="revolver.ru" type="rss"
+ xmlUrl="http://revolver.ru/rss" htmlUrl="http://revolver.ru/"/>
+ <outline text="Самый сок!" title="Самый сок!" type="rss"
+ xmlUrl="http://ibigdan.livejournal.com/data/rss" htmlUrl="http://ibigdan.livejournal.com/"/>
+ <outline text="Танки Онлайн" title="Танки Онлайн" type="rss"
+ xmlUrl="http://blog.tankionline.com/feed/" htmlUrl="http://news.tankionline.com"/>
+ <outline text="Фергана.Ру" title="Фергана.Ру" type="rss"
+ xmlUrl="http://news.ferghana.ru/news.xml" htmlUrl="http://www.fergananews.com"/>
+ </outline>
+ <outline title="TC" text="TC">
+ <outline text="en.totalcmd.pl" title="en.totalcmd.pl"
+ type="rss" xmlUrl="http://en.totalcmd.pl/rss" htmlUrl="http://en.totalcmd.pl"/>
+ <outline text="tc" title="tc" type="rss"
+ xmlUrl="http://wincmd.ru/rss.xml" htmlUrl="http://wincmd.ru"/>
+ </outline>
+ <outline title="Science" text="Science">
+ <outline text="Astronet" title="Astronet" type="rss"
+ xmlUrl="http://www.astronet.ru/db/rss.xml" htmlUrl="http://www.astronet.ru/"/>
+ <outline text="COPAH.info - Наука. Сибирь. Общество"
+ title="COPAH.info - Наука. Сибирь. Общество" type="rss"
+ xmlUrl="http://www.copah.info/rss" htmlUrl="http://www.copah.info/rss"/>
+ <outline text="LHC" title="LHC" type="rss"
+ xmlUrl="http://fulltextrssfeed.com/elementy.ru/rss/news/LHC" htmlUrl="http://elementy.ru/LHC/news"/>
+ <outline text="Membrana.ru" title="Membrana.ru" type="rss"
+ xmlUrl="http://ftr.fivefilters.org/makefulltextfeed.php?url=http%3A%2F%2Fwww.membrana.ru%2Fexport%2Frss.xml&amp;max=1" htmlUrl="http://www.membrana.ru"/>
+ <outline text="Иванов" title="Иванов" type="rss"
+ xmlUrl="http://igorivanov.blogspot.com/feeds/posts/default" htmlUrl="http://igorivanov.blogspot.com/"/>
+ <outline text="НаукаИжизнь" title="НаукаИжизнь" type="rss"
+ xmlUrl="http://fulltextrssfeed.com/www.nkj.ru/rss/iblock_rss_31.xml" htmlUrl="http://www.nkj.ru"/>
+ <outline text="Элементы" title="Элементы" type="rss"
+ xmlUrl="http://fulltextrssfeed.com/elementy.ru/rss/news" htmlUrl="http://elementy.ru/"/>
+ </outline>
+ <outline title="Moviez" text="Moviez">
+ <outline text="Twitter / kuraj_bambey"
+ title="Twitter / kuraj_bambey" type="rss"
+ xmlUrl="http://twitter.com/statuses/user_timeline/44353505.rss" htmlUrl="http://twitter.com/kuraj_bambey"/>
+ <outline text="Мосенька" title="Мосенька" type="rss"
+ xmlUrl="http://feed.rutracker.org/atom/u/0/26/3796626.atom" htmlUrl="http://rutracker.org/forum/profile.php?mode=viewprofile&amp;u=3796626"/>
+ </outline>
+ </body>
+</opml>
diff --git a/protocols/NewsAggregator/proto_newsaggregator/Proto_NewsAggregator.vcxproj b/protocols/NewsAggregator/proto_newsaggregator/Proto_NewsAggregator.vcxproj
new file mode 100644
index 0000000000..1183249dd0
--- /dev/null
+++ b/protocols/NewsAggregator/proto_newsaggregator/Proto_NewsAggregator.vcxproj
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <ItemGroup Label="ProjectConfigurations">
+ <ProjectConfiguration Include="Debug|Win32">
+ <Configuration>Debug</Configuration>
+ <Platform>Win32</Platform>
+ </ProjectConfiguration>
+ <ProjectConfiguration Include="Debug|x64">
+ <Configuration>Debug</Configuration>
+ <Platform>x64</Platform>
+ </ProjectConfiguration>
+ <ProjectConfiguration Include="Release|Win32">
+ <Configuration>Release</Configuration>
+ <Platform>Win32</Platform>
+ </ProjectConfiguration>
+ <ProjectConfiguration Include="Release|x64">
+ <Configuration>Release</Configuration>
+ <Platform>x64</Platform>
+ </ProjectConfiguration>
+ </ItemGroup>
+ <PropertyGroup Label="Globals">
+ <ProjectName>Proto_NewsAggregator</ProjectName>
+ <ProjectGuid>{B97882DC-7462-41DB-A390-BDFCE5295265}</ProjectGuid>
+ </PropertyGroup>
+ <ImportGroup Label="PropertySheets">
+ <Import Project="$(ProjectDir)..\..\..\build\vc.common\icons.props" />
+ </ImportGroup>
+</Project> \ No newline at end of file
diff --git a/protocols/NewsAggregator/proto_newsaggregator/Proto_NewsAggregator.vcxproj.filters b/protocols/NewsAggregator/proto_newsaggregator/Proto_NewsAggregator.vcxproj.filters
new file mode 100644
index 0000000000..28f81e7f1b
--- /dev/null
+++ b/protocols/NewsAggregator/proto_newsaggregator/Proto_NewsAggregator.vcxproj.filters
@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <Import Project="$(ProjectDir)..\..\..\build\vc.common\common.filters" />
+</Project> \ No newline at end of file
diff --git a/protocols/NewsAggregator/proto_newsaggregator/res/Offline.ico b/protocols/NewsAggregator/proto_newsaggregator/res/Offline.ico
new file mode 100644
index 0000000000..b4fba290e7
--- /dev/null
+++ b/protocols/NewsAggregator/proto_newsaggregator/res/Offline.ico
Binary files differ
diff --git a/protocols/NewsAggregator/proto_newsaggregator/res/Online.ico b/protocols/NewsAggregator/proto_newsaggregator/res/Online.ico
new file mode 100644
index 0000000000..75c9ff1aa3
--- /dev/null
+++ b/protocols/NewsAggregator/proto_newsaggregator/res/Online.ico
Binary files differ
diff --git a/protocols/NewsAggregator/proto_newsaggregator/res/Proto_NewsAggregator.rc b/protocols/NewsAggregator/proto_newsaggregator/res/Proto_NewsAggregator.rc
new file mode 100644
index 0000000000..814c9e4f26
--- /dev/null
+++ b/protocols/NewsAggregator/proto_newsaggregator/res/Proto_NewsAggregator.rc
@@ -0,0 +1,70 @@
+// Microsoft Visual C++ generated resource script.
+//
+#include "..\src\resource.h"
+
+#define APSTUDIO_READONLY_SYMBOLS
+/////////////////////////////////////////////////////////////////////////////
+//
+// Generated from the TEXTINCLUDE 2 resource.
+//
+#include "afxres.h"
+
+/////////////////////////////////////////////////////////////////////////////
+#undef APSTUDIO_READONLY_SYMBOLS
+
+/////////////////////////////////////////////////////////////////////////////
+// Russian (Russia) resources
+
+#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_RUS)
+LANGUAGE LANG_RUSSIAN, SUBLANG_DEFAULT
+
+#ifdef APSTUDIO_INVOKED
+/////////////////////////////////////////////////////////////////////////////
+//
+// TEXTINCLUDE
+//
+
+1 TEXTINCLUDE
+BEGIN
+ "..\\src\\resource.h\0"
+END
+
+2 TEXTINCLUDE
+BEGIN
+ "#include ""afxres.h""\r\n"
+ "\0"
+END
+
+3 TEXTINCLUDE
+BEGIN
+ "\r\n"
+ "\0"
+END
+
+#endif // APSTUDIO_INVOKED
+
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Icon
+//
+
+// Icon with lowest ID value placed first to ensure application icon
+// remains consistent on all systems.
+IDI_ICON1 ICON "Offline.ico"
+IDI_ICON2 ICON "Online.ico"
+#endif // Russian (Russia) resources
+/////////////////////////////////////////////////////////////////////////////
+
+
+
+#ifndef APSTUDIO_INVOKED
+/////////////////////////////////////////////////////////////////////////////
+//
+// Generated from the TEXTINCLUDE 3 resource.
+//
+
+
+/////////////////////////////////////////////////////////////////////////////
+#endif // not APSTUDIO_INVOKED
+
diff --git a/protocols/NewsAggregator/proto_newsaggregator/src/resource.h b/protocols/NewsAggregator/proto_newsaggregator/src/resource.h
new file mode 100644
index 0000000000..38085445db
--- /dev/null
+++ b/protocols/NewsAggregator/proto_newsaggregator/src/resource.h
@@ -0,0 +1,17 @@
+//{{NO_DEPENDENCIES}}
+// Microsoft Visual C++ generated include file.
+// Used by Proto_NewsAggr.rc
+//
+#define IDI_ICON1 105
+#define IDI_ICON2 104
+
+// Next default values for new objects
+//
+#ifdef APSTUDIO_INVOKED
+#ifndef APSTUDIO_READONLY_SYMBOLS
+#define _APS_NEXT_RESOURCE_VALUE 103
+#define _APS_NEXT_COMMAND_VALUE 40001
+#define _APS_NEXT_CONTROL_VALUE 1001
+#define _APS_NEXT_SYMED_VALUE 101
+#endif
+#endif
diff --git a/protocols/Non-IM Contact/nimcontact.vcxproj b/protocols/Non-IM Contact/nimcontact.vcxproj
new file mode 100644
index 0000000000..be914aac44
--- /dev/null
+++ b/protocols/Non-IM Contact/nimcontact.vcxproj
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <ItemGroup Label="ProjectConfigurations">
+ <ProjectConfiguration Include="Debug|Win32">
+ <Configuration>Debug</Configuration>
+ <Platform>Win32</Platform>
+ </ProjectConfiguration>
+ <ProjectConfiguration Include="Debug|x64">
+ <Configuration>Debug</Configuration>
+ <Platform>x64</Platform>
+ </ProjectConfiguration>
+ <ProjectConfiguration Include="Release|Win32">
+ <Configuration>Release</Configuration>
+ <Platform>Win32</Platform>
+ </ProjectConfiguration>
+ <ProjectConfiguration Include="Release|x64">
+ <Configuration>Release</Configuration>
+ <Platform>x64</Platform>
+ </ProjectConfiguration>
+ </ItemGroup>
+ <PropertyGroup Label="Globals">
+ <ProjectName>NimContact</ProjectName>
+ <ProjectGuid>{A556E0B5-73A1-4676-BA1F-133820DE7D5A}</ProjectGuid>
+ </PropertyGroup>
+ <ImportGroup Label="PropertySheets">
+ <Import Project="$(ProjectDir)..\..\build\vc.common\plugin.props" />
+ </ImportGroup>
+</Project> \ No newline at end of file
diff --git a/protocols/Non-IM Contact/nimcontact.vcxproj.filters b/protocols/Non-IM Contact/nimcontact.vcxproj.filters
new file mode 100644
index 0000000000..fcae13a9d8
--- /dev/null
+++ b/protocols/Non-IM Contact/nimcontact.vcxproj.filters
@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <Import Project="$(ProjectDir)..\..\build\vc.common\common.filters" />
+</Project> \ No newline at end of file
diff --git a/protocols/Non-IM Contact/res/Version.rc b/protocols/Non-IM Contact/res/Version.rc
new file mode 100644
index 0000000000..5a5ddd63ed
--- /dev/null
+++ b/protocols/Non-IM Contact/res/Version.rc
@@ -0,0 +1,9 @@
+// Microsoft Visual C++ generated resource script.
+//
+#ifdef APSTUDIO_INVOKED
+#error this file is not editable by Microsoft Visual C++
+#endif //APSTUDIO_INVOKED
+
+#include "..\src\version.h"
+
+#include "..\..\build\Version.rc"
diff --git a/protocols/Non-IM Contact/res/resource.rc b/protocols/Non-IM Contact/res/resource.rc
new file mode 100644
index 0000000000..14d3f4624b
--- /dev/null
+++ b/protocols/Non-IM Contact/res/resource.rc
@@ -0,0 +1,321 @@
+// Microsoft Visual C++ generated resource script.
+//
+#include "../src/resource.h"
+
+#define APSTUDIO_READONLY_SYMBOLS
+/////////////////////////////////////////////////////////////////////////////
+//
+// Generated from the TEXTINCLUDE 2 resource.
+//
+#include "afxres.h"
+
+/////////////////////////////////////////////////////////////////////////////
+#undef APSTUDIO_READONLY_SYMBOLS
+
+/////////////////////////////////////////////////////////////////////////////
+// English (United States) resources
+
+#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU)
+LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
+#pragma code_page(1252)
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Dialog
+//
+
+IDD_ADD_FILE DIALOG 0, 0, 283, 190
+STYLE DS_SETFONT | DS_MODALFRAME | DS_CENTER | WS_POPUP | WS_VISIBLE | WS_CAPTION | WS_SYSMENU
+CAPTION "View/Edit Files"
+FONT 8, "MS Sans Serif"
+BEGIN
+ COMBOBOX IDC_FILE_LIST,54,4,222,99,CBS_DROPDOWNLIST | CBS_AUTOHSCROLL | WS_VSCROLL | WS_TABSTOP
+ EDITTEXT IDC_URL,54,20,222,12,ES_AUTOHSCROLL
+ EDITTEXT IDC_WWW_TIMER,82,37,30,12,ES_NUMBER
+ PUSHBUTTON "Add File",IDC_ADD_FILE,202,37,34,12
+ PUSHBUTTON "Add URL",IDC_ADD_URL,238,37,38,12
+ PUSHBUTTON "Remove Selected File",IDC_DEL_FILE,202,52,73,12
+ LISTBOX IDC_FILE_CONTENTS,4,70,272,113,LBS_NOINTEGRALHEIGHT | LBS_DISABLENOSCROLL | WS_VSCROLL | WS_HSCROLL | WS_TABSTOP
+ LTEXT "file(#)",IDC_STATIC,4,6,28,8
+ EDITTEXT IDC_FN,33,4,16,12,ES_READONLY | ES_NUMBER
+ LTEXT "URL",IDC_STATIC,4,22,41,8
+ LTEXT "Update URL every",IDC_STATIC,4,39,75,8
+ LTEXT "Intervals",IDC_STATIC,117,39,33,8
+ LTEXT "If the protocol timer is disabled, web pages won't be updated",IDC_STATIC,4,52,188,8
+END
+
+IDD_CONTACT_INFO DIALOG 0, 0, 283, 190
+STYLE DS_SETFONT | DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU
+CAPTION "contact display info"
+FONT 8, "MS Sans Serif"
+BEGIN
+ EDITTEXT IDC_DISPLAY_NAME,88,6,188,12,ES_AUTOHSCROLL
+ EDITTEXT IDC_TOOLTIP,7,40,269,143,ES_MULTILINE | ES_AUTOVSCROLL | ES_AUTOHSCROLL | ES_WANTRETURN | WS_VSCROLL | WS_HSCROLL
+ LTEXT "Contacts display name",IDC_STATIC,7,8,72,8
+ LTEXT "Contacts Tooltip",IDC_STATIC,7,26,52,8
+END
+
+IDD_OTHER_STUFF DIALOGEX 0, 0, 283, 190
+STYLE DS_SETFONT | DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU
+CAPTION "other settings"
+FONT 8, "MS Sans Serif", 0, 0, 0x0
+BEGIN
+ LTEXT "Link",IDC_STATIC,12,18,27,8
+ EDITTEXT IDC_LINK,42,16,230,12,ES_AUTOHSCROLL
+ LTEXT "Program parameters:",IDC_STATIC,12,33,83,8
+ EDITTEXT IDC_PARAMS,97,31,175,12,ES_AUTOHSCROLL
+ PUSHBUTTON "O&pen File",IDC_OPEN_FILE,149,47,56,14
+ PUSHBUTTON "O&pen Folder",IDC_OPEN_FOLDER,216,47,56,14
+ GROUPBOX "Link Settings",IDC_STATIC,7,4,269,60
+ GROUPBOX "Contact list settings",IDC_STATIC,7,68,269,64
+ COMBOBOX IDC_GROUP,43,79,158,74,CBS_DROPDOWN | CBS_AUTOHSCROLL | CBS_SORT | WS_VSCROLL | WS_TABSTOP
+ CONTROL "",CHK_ONLINE,"Button",BS_AUTORADIOBUTTON | BS_PUSHLIKE | WS_TABSTOP,71,95,16,16
+ CONTROL "",CHK_AWAY,"Button",BS_AUTORADIOBUTTON | BS_ICON | BS_PUSHLIKE | WS_TABSTOP,90,95,16,16
+ CONTROL "",CHK_NA,"Button",BS_AUTORADIOBUTTON | BS_ICON | BS_PUSHLIKE | WS_TABSTOP,109,95,16,16
+ CONTROL "",CHK_OCC,"Button",BS_AUTORADIOBUTTON | BS_ICON | BS_PUSHLIKE | WS_TABSTOP,128,95,16,16
+ CONTROL "",CHK_DND,"Button",BS_AUTORADIOBUTTON | BS_ICON | BS_PUSHLIKE | WS_TABSTOP,147,95,16,16
+ CONTROL "",CHK_FFC,"Button",BS_AUTORADIOBUTTON | BS_ICON | BS_PUSHLIKE | WS_TABSTOP,166,95,16,16
+ CONTROL "",CHK_INVISIBLE,"Button",BS_AUTORADIOBUTTON | BS_ICON | BS_PUSHLIKE | WS_TABSTOP,185,95,16,16
+ CONTROL "",CHK_PHONE,"Button",BS_AUTORADIOBUTTON | BS_ICON | BS_PUSHLIKE | WS_TABSTOP,204,95,16,16
+ CONTROL "",CHK_LUNCH,"Button",BS_AUTORADIOBUTTON | BS_ICON | BS_PUSHLIKE | WS_TABSTOP,223,95,16,16
+ LTEXT "Group:",IDC_STATIC,12,81,29,8
+ LTEXT "Status Icon",IDC_STATIC,12,99,54,8
+ LTEXT "Group\\Sub-Group",IDC_STATIC,205,81,67,8
+ GROUPBOX "Timer Settings",IDC_STATIC,7,139,269,44
+ CONTROL "Use Timer",CHK_USE_TIMER,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,12,148,108,10
+ EDITTEXT IDC_TIMER,22,162,35,12,ES_NUMBER | WS_DISABLED
+ CONTROL "Contact is always visible",IDC_ALWAYS_VISIBLE,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,12,115,92,10
+ CONTROL "Unless Non-IM Contacts protocol is OFFLINE",IDC_VISIBLE_UNLESS_OFFLINE,
+ "Button",BS_AUTOCHECKBOX | WS_DISABLED | WS_TABSTOP,112,115,158,10
+ LTEXT "Timer Intervals. ",IDC_TIMER_INTERVAL_MSG,61,166,211,8
+END
+
+IDD_OPTIONS DIALOGEX 0, 0, 291, 180
+STYLE DS_SETFONT | DS_FIXEDSYS | WS_CHILD
+EXSTYLE WS_EX_CONTROLPARENT
+FONT 8, "MS Shell Dlg", 0, 0, 0x1
+BEGIN
+ CONTROL "Away as another status",IDC_AWAYISNOTONLINE,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,7,42,169,10
+ CONTROL "Disable timer",IDC_DISABLETIMER,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,13,99,106,10
+ LTEXT "Timer interval (in seconds)",IDC_TIMER_TEXT,13,111,83,8
+ EDITTEXT IDC_TIMER_INT,102,109,20,12,ES_NUMBER
+ LTEXT "This will take affect after Non-IM Contacts' status is changed",IDC_TIMER_MSG,13,123,215,8
+ GROUPBOX "Timer Options",IDC_STATIC,7,87,277,49
+END
+
+IDD_TEST_LINE DIALOG 0, 0, 435, 119
+STYLE DS_SETFONT | DS_MODALFRAME | DS_CENTER | DS_CENTERMOUSE | WS_POPUP | WS_VISIBLE | WS_CAPTION | WS_SYSMENU
+CAPTION "String Maker"
+FONT 8, "MS Sans Serif"
+BEGIN
+ EDITTEXT IDC_STRING,15,17,409,14,ES_AUTOHSCROLL
+ DEFPUSHBUTTON "&Test String",IDOK,385,56,43,14
+ PUSHBUTTON "&Exit",IDCANCEL,385,92,43,14
+ GROUPBOX "String to test",IDC_STATIC,7,7,421,41
+ GROUPBOX "Returns....",IDC_STATIC,7,51,371,61
+ EDITTEXT IDC_ANSWER,15,62,353,43,ES_MULTILINE | ES_AUTOHSCROLL | ES_WANTRETURN | WS_VSCROLL | WS_HSCROLL
+ LTEXT "line()",IDC_LINE,73,36,16,8,WS_DISABLED
+ LTEXT "start()",IDC_START,32,36,18,8,WS_DISABLED
+ LTEXT "end()",IDC_END,53,36,17,8,WS_DISABLED
+ LTEXT "wholeline()",IDC_WHOLELINE,111,36,34,8,WS_DISABLED
+ LTEXT "csv()",IDC_CSV,92,36,16,8,WS_DISABLED
+ LTEXT "file()",IDC_FILE,15,36,14,8,WS_DISABLED
+ LTEXT "filename()",IDC_FILENAME,148,36,31,8,WS_DISABLED
+ PUSHBUTTON "Help",IDC_HELPMSG,385,73,43,14
+END
+
+IDD_HELP DIALOGEX 0, 0, 267, 218
+STYLE DS_SETFONT | DS_MODALFRAME | DS_SETFOREGROUND | DS_CENTER | DS_CENTERMOUSE | WS_POPUP | WS_VISIBLE | WS_CAPTION
+CAPTION "Help"
+FONT 9, "MS Sans Serif", 0, 0, 0x0
+BEGIN
+ DEFPUSHBUTTON "OK",IDOK,210,197,50,14
+ EDITTEXT IDC_HELPTEXT,7,7,253,187,ES_MULTILINE | ES_READONLY | WS_VSCROLL
+END
+
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// DESIGNINFO
+//
+
+#ifdef APSTUDIO_INVOKED
+GUIDELINES DESIGNINFO
+BEGIN
+ IDD_ADD_FILE, DIALOG
+ BEGIN
+ LEFTMARGIN, 4
+ RIGHTMARGIN, 276
+ VERTGUIDE, 26
+ TOPMARGIN, 4
+ BOTTOMMARGIN, 183
+ HORZGUIDE, 4
+ HORZGUIDE, 26
+ HORZGUIDE, 37
+ HORZGUIDE, 43
+ HORZGUIDE, 52
+ END
+
+ IDD_CONTACT_INFO, DIALOG
+ BEGIN
+ LEFTMARGIN, 7
+ RIGHTMARGIN, 276
+ TOPMARGIN, 4
+ BOTTOMMARGIN, 183
+ HORZGUIDE, 12
+ HORZGUIDE, 34
+ END
+
+ IDD_OTHER_STUFF, DIALOG
+ BEGIN
+ LEFTMARGIN, 7
+ RIGHTMARGIN, 276
+ VERTGUIDE, 12
+ VERTGUIDE, 39
+ VERTGUIDE, 272
+ TOPMARGIN, 4
+ BOTTOMMARGIN, 183
+ HORZGUIDE, 22
+ HORZGUIDE, 37
+ HORZGUIDE, 47
+ HORZGUIDE, 85
+ HORZGUIDE, 103
+ HORZGUIDE, 120
+ HORZGUIDE, 149
+ HORZGUIDE, 174
+ END
+
+ IDD_OPTIONS, DIALOG
+ BEGIN
+ LEFTMARGIN, 7
+ RIGHTMARGIN, 284
+ VERTGUIDE, 13
+ TOPMARGIN, 7
+ BOTTOMMARGIN, 173
+ HORZGUIDE, 99
+ HORZGUIDE, 115
+ END
+
+ IDD_TEST_LINE, DIALOG
+ BEGIN
+ LEFTMARGIN, 7
+ RIGHTMARGIN, 428
+ VERTGUIDE, 15
+ VERTGUIDE, 385
+ VERTGUIDE, 424
+ TOPMARGIN, 7
+ BOTTOMMARGIN, 112
+ HORZGUIDE, 36
+ END
+
+ IDD_HELP, DIALOG
+ BEGIN
+ LEFTMARGIN, 7
+ TOPMARGIN, 7
+ BOTTOMMARGIN, 154
+ END
+END
+#endif // APSTUDIO_INVOKED
+
+
+#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
+
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Icon
+//
+
+// Icon with lowest ID value placed first to ensure application icon
+// remains consistent on all systems.
+IDI_MAIN ICON "star8.ico"
+#endif // English (United States) resources
+/////////////////////////////////////////////////////////////////////////////
+
+
+/////////////////////////////////////////////////////////////////////////////
+// English (Australia) resources
+
+#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENA)
+LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_AUS
+#pragma code_page(1252)
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Dialog
+//
+
+IDD_CONTACT_COPYEXPORT DIALOGEX 0, 0, 283, 190
+STYLE DS_SETFONT | DS_MODALFRAME | WS_CHILD | WS_CAPTION | WS_SYSMENU
+CAPTION "Copy / Export contact"
+FONT 8, "MS Sans Serif", 0, 0, 0x0
+BEGIN
+ EDITTEXT IDC_STRING_REPLACE,13,43,254,108,ES_MULTILINE | ES_AUTOHSCROLL | ES_WANTRETURN | WS_VSCROLL
+ PUSHBUTTON "&Export Non-IM Contact",IDC_EXPORT,13,159,94,14
+ PUSHBUTTON "Co&py Non-IM Contact",IDC_DOIT,173,159,94,14
+ GROUPBOX "",IDC_STATIC,7,7,269,176
+ CONTROL "Type one replace string per line in the format ""original text,new text""",IDC_STATIC,
+ "Static",SS_LEFTNOWORDWRAP | WS_GROUP,13,18,254,10
+ LTEXT "EXAMPLE: %fn1,%fn2",IDC_STATIC,13,31,254,8
+END
+
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// DESIGNINFO
+//
+
+#ifdef APSTUDIO_INVOKED
+GUIDELINES DESIGNINFO
+BEGIN
+ IDD_CONTACT_COPYEXPORT, DIALOG
+ BEGIN
+ LEFTMARGIN, 7
+ RIGHTMARGIN, 276
+ VERTGUIDE, 13
+ VERTGUIDE, 267
+ TOPMARGIN, 7
+ BOTTOMMARGIN, 183
+ HORZGUIDE, 159
+ END
+END
+#endif // APSTUDIO_INVOKED
+
+#endif // English (Australia) resources
+/////////////////////////////////////////////////////////////////////////////
+
+
+
+#ifndef APSTUDIO_INVOKED
+/////////////////////////////////////////////////////////////////////////////
+//
+// Generated from the TEXTINCLUDE 3 resource.
+//
+
+
+/////////////////////////////////////////////////////////////////////////////
+#endif // not APSTUDIO_INVOKED
+
diff --git a/protocols/Non-IM Contact/res/star8.ico b/protocols/Non-IM Contact/res/star8.ico
new file mode 100644
index 0000000000..a4953cd753
--- /dev/null
+++ b/protocols/Non-IM Contact/res/star8.ico
Binary files differ
diff --git a/protocols/Non-IM Contact/src/contactinfo.cpp b/protocols/Non-IM Contact/src/contactinfo.cpp
new file mode 100644
index 0000000000..3bf022857e
--- /dev/null
+++ b/protocols/Non-IM Contact/src/contactinfo.cpp
@@ -0,0 +1,675 @@
+#include "stdafx.h"
+
+INT_PTR CALLBACK DlgProcContactInfo(HWND hwnd, UINT msg, WPARAM, LPARAM lParam)
+{
+ switch (msg) {
+ case WM_INITDIALOG:
+ TranslateDialogDefault(hwnd);
+ {
+ MCONTACT hContact = (MCONTACT)((PROPSHEETPAGE*)lParam)->lParam;
+ char name[2048];
+ SetWindowLongPtr(hwnd, GWLP_USERDATA, (LONG_PTR)hContact);
+
+ if (db_get_static(hContact, MODNAME, "Name", name, _countof(name)))
+ break;
+ SetDlgItemTextA(hwnd, IDC_DISPLAY_NAME, name);
+ if (db_get_static(hContact, MODNAME, "ToolTip", name, _countof(name)))
+ break;
+ SetDlgItemTextA(hwnd, IDC_TOOLTIP, name);
+ }
+ return TRUE;
+
+ case WM_COMMAND:
+ SendMessage(GetParent(hwnd), PSM_CHANGED, 0, 0);
+ return TRUE;
+
+ case WM_NOTIFY:
+ switch (((LPNMHDR)lParam)->idFrom) {
+ case 0:
+ switch (((LPNMHDR)lParam)->code) {
+ case PSN_APPLY:
+ MCONTACT hContact = (MCONTACT)GetWindowLongPtr(hwnd, GWLP_USERDATA);
+ if (GetWindowTextLength(GetDlgItem(hwnd, IDC_DISPLAY_NAME))) {
+ char text[512];
+ GetDlgItemTextA(hwnd, IDC_DISPLAY_NAME, text, _countof(text));
+ g_plugin.setString(hContact, "Name", text);
+ WriteSetting(hContact, MODNAME, "Name", MODNAME, "Nick");
+ }
+ else {
+ g_plugin.delSetting(hContact, "Name");
+ g_plugin.delSetting(hContact, "Nick");
+ }
+
+ if (GetWindowTextLength(GetDlgItem(hwnd, IDC_TOOLTIP))) {
+ char text[2048];
+ GetDlgItemTextA(hwnd, IDC_TOOLTIP, text, _countof(text));
+ g_plugin.setString(hContact, "ToolTip", text);
+ WriteSetting(hContact, MODNAME, "ToolTip", "UserInfo", "MyNotes");
+ }
+ else {
+ g_plugin.delSetting(hContact, "ToolTip");
+ db_unset(hContact, "UserInfo", "MyNotes");
+ }
+ }
+ return TRUE;
+ }
+ break;
+ }
+ return FALSE;
+}
+
+static WNDPROC g_PrevBtnWndProc = nullptr;
+
+LRESULT CALLBACK ButtWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
+{
+ LRESULT res = CallWindowProc(g_PrevBtnWndProc, hWnd, message, wParam, lParam);
+ if (WM_PAINT == message) {
+ RECT rc;
+ HDC dc = GetDC(hWnd);
+ BOOL isPressed = BST_CHECKED == SendMessage(hWnd, BM_GETCHECK, 0, 0);
+
+ GetClientRect(hWnd, &rc);
+ rc.left += (rc.right - rc.left - 16) / 2;
+ rc.top += (rc.bottom - rc.top - 16) / 2;
+ if (isPressed)
+ OffsetRect(&rc, 1, 1);
+ DrawIconEx(dc, rc.left, rc.top, (HICON)GetWindowLongPtr(hWnd, GWLP_USERDATA), 16, 16, 0, nullptr, DI_NORMAL);
+ ReleaseDC(hWnd, dc);
+ }
+
+ return res;
+}
+
+int BrowseForFolder(HWND hwnd, char *szPath)
+{
+ int result = 0;
+ LPMALLOC pMalloc;
+
+ if (SUCCEEDED(CoGetMalloc(1, &pMalloc))) {
+ ptrW tszPath(mir_a2u(szPath));
+ BROWSEINFO bi = {};
+ bi.hwndOwner = hwnd;
+ bi.pszDisplayName = tszPath;
+ bi.lpszTitle = TranslateT("Select Folder");
+ bi.ulFlags = BIF_EDITBOX | BIF_RETURNONLYFSDIRS; // Use this combo instead of BIF_USENEWUI
+ bi.lParam = (LPARAM)szPath;
+
+ ITEMIDLIST *pidlResult = SHBrowseForFolder(&bi);
+ if (pidlResult) {
+ SHGetPathFromIDListA(pidlResult, szPath);
+ mir_strcat(szPath, "\\");
+ result = 1;
+ }
+ pMalloc->Free(pidlResult);
+ pMalloc->Release();
+ }
+
+ return result;
+}
+
+INT_PTR CALLBACK DlgProcOtherStuff(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
+{
+ switch (msg) {
+ case WM_INITDIALOG:
+ TranslateDialogDefault(hwnd);
+ {
+ MCONTACT hContact = (MCONTACT)((PROPSHEETPAGE*)lParam)->lParam;
+ SetWindowLongPtr(hwnd, GWLP_USERDATA, (LONG_PTR)hContact);
+ if (!hContact)
+ break;
+
+ /* link*/
+ DBVARIANT dbv;
+ if (!g_plugin.getWString(hContact, "ProgramString", &dbv)) {
+ SetDlgItemText(hwnd, IDC_LINK, dbv.pwszVal);
+ db_free(&dbv);
+ }
+
+ if (!g_plugin.getWString(hContact, "ProgramParamsString", &dbv)) {
+ SetDlgItemText(hwnd, IDC_PARAMS, dbv.pwszVal);
+ db_free(&dbv);
+ }
+
+ /* group*/
+ wchar_t *szGroup;
+ for (int i = 1; (szGroup = Clist_GroupGetName(i, nullptr)) != nullptr; i++)
+ SendDlgItemMessage(hwnd, IDC_GROUP, CB_INSERTSTRING, 0, LPARAM(szGroup));
+
+ if (!db_get_ws(hContact, "CList", "Group", &dbv)) {
+ SetDlgItemText(hwnd, IDC_GROUP, dbv.pwszVal);
+ db_free(&dbv);
+ }
+
+ /* icons */
+ CheckRadioButton(hwnd, 40072, 40080, g_plugin.getWord(hContact, "Icon", ID_STATUS_ONLINE));
+ SetWindowLongPtr(GetDlgItem(hwnd, CHK_ONLINE), GWLP_USERDATA, (LONG_PTR)Skin_LoadProtoIcon(MODNAME, ID_STATUS_ONLINE));
+ g_PrevBtnWndProc = (WNDPROC)SetWindowLongPtr(GetDlgItem(hwnd, CHK_ONLINE), GWLP_WNDPROC, (LONG_PTR)ButtWndProc);
+ for (int i = ID_STATUS_ONLINE; i <= ID_STATUS_OUTTOLUNCH; i++) {
+ SetWindowLongPtr(GetDlgItem(hwnd, i), GWLP_USERDATA, (LONG_PTR)Skin_LoadProtoIcon(MODNAME, i));
+ SetWindowLongPtr(GetDlgItem(hwnd, i), GWLP_WNDPROC, (LONG_PTR)ButtWndProc);
+ }
+ db_free(&dbv);
+ /* timer */
+ CheckDlgButton(hwnd, CHK_USE_TIMER, g_plugin.getByte(hContact, "UseTimer", 0) ? BST_CHECKED : BST_UNCHECKED);
+ if (g_plugin.getWord(hContact, "Timer", 15)) {
+ CheckDlgButton(hwnd, CHK_USE_TIMER, BST_CHECKED);
+ EnableWindow(GetDlgItem(hwnd, IDC_TIMER), 1);
+ wchar_t string[512];
+ SetDlgItemText(hwnd, IDC_TIMER, _itow(g_plugin.getWord(hContact, "Timer", 15), string, 10));
+ if (!g_plugin.getWord("Timer", 1))
+ SetDlgItemText(hwnd, IDC_TIMER_INTERVAL_MSG, TranslateT("Non-IM Contact protocol timer is Disabled"));
+ else {
+ mir_snwprintf(string, TranslateT("Timer intervals... Non-IM Contact Protocol timer is %d seconds"), g_plugin.getWord("Timer", 1));
+ SetDlgItemText(hwnd, IDC_TIMER_INTERVAL_MSG, string);
+ }
+ }
+ /* always visible */
+ if (g_plugin.getByte(hContact, "AlwaysVisible", 0)) {
+ CheckDlgButton(hwnd, IDC_ALWAYS_VISIBLE, BST_CHECKED);
+ EnableWindow(GetDlgItem(hwnd, IDC_VISIBLE_UNLESS_OFFLINE), 1);
+ CheckDlgButton(hwnd, IDC_VISIBLE_UNLESS_OFFLINE, g_plugin.getByte(hContact, "VisibleUnlessOffline", 1) ? BST_CHECKED : BST_UNCHECKED);
+ }
+ }
+ return TRUE;
+
+ case WM_COMMAND:
+ SendMessage(GetParent(hwnd), PSM_CHANGED, 0, 0);
+ switch (LOWORD(wParam)) {
+ case IDC_ALWAYS_VISIBLE:
+ if (IsDlgButtonChecked(hwnd, IDC_ALWAYS_VISIBLE)) {
+ MCONTACT hContact = (MCONTACT)GetWindowLongPtr(hwnd, GWLP_USERDATA);
+ EnableWindow(GetDlgItem(hwnd, IDC_VISIBLE_UNLESS_OFFLINE), 1);
+ CheckDlgButton(hwnd, IDC_VISIBLE_UNLESS_OFFLINE, g_plugin.getByte(hContact, "VisibleUnlessOffline", 1) ? BST_CHECKED : BST_UNCHECKED);
+ }
+ else EnableWindow(GetDlgItem(hwnd, IDC_VISIBLE_UNLESS_OFFLINE), 0);
+ break;
+
+ case CHK_USE_TIMER:
+ if (IsDlgButtonChecked(hwnd, CHK_USE_TIMER)) {
+ MCONTACT hContact = (MCONTACT)GetWindowLongPtr(hwnd, GWLP_USERDATA);
+ char string[4];
+ EnableWindow(GetDlgItem(hwnd, IDC_TIMER), 1);
+ SetDlgItemTextA(hwnd, IDC_TIMER, _itoa(g_plugin.getWord(hContact, "Timer", 15), string, 10));
+ }
+ else EnableWindow(GetDlgItem(hwnd, IDC_TIMER), 0);
+ break;
+
+ case IDC_OPEN_FILE:
+ char szFileName[512];
+ if (Openfile(szFileName, 1))
+ SetDlgItemTextA(hwnd, IDC_LINK, szFileName);
+ break;
+
+ case IDC_OPEN_FOLDER:
+ if (BrowseForFolder(hwnd, szFileName)) {
+ mir_snprintf(szFileName, "%s ,/e", szFileName);
+ SetDlgItemTextA(hwnd, IDC_LINK, "explorer.exe");
+ SetDlgItemTextA(hwnd, IDC_PARAMS, szFileName);
+ }
+ }
+ break;
+
+ case WM_NOTIFY:
+ switch (((LPNMHDR)lParam)->idFrom) {
+ case 0:
+ switch (((LPNMHDR)lParam)->code) {
+ case PSN_APPLY:
+ int status = GetLCStatus(0, 0);
+ MCONTACT hContact = (MCONTACT)GetWindowLongPtr(hwnd, GWLP_USERDATA);
+
+ if (GetWindowTextLength(GetDlgItem(hwnd, IDC_LINK))) {
+ char text[512];
+ GetDlgItemTextA(hwnd, IDC_LINK, text, _countof(text));
+ g_plugin.setString(hContact, "ProgramString", text);
+ WriteSetting(hContact, MODNAME, "ProgramString", MODNAME, "Program");
+ }
+ else g_plugin.delSetting(hContact, "ProgramString");
+
+ if (GetWindowTextLength(GetDlgItem(hwnd, IDC_PARAMS))) {
+ char text[512];
+ GetDlgItemTextA(hwnd, IDC_PARAMS, text, _countof(text));
+ g_plugin.setString(hContact, "ProgramParamsString", text);
+ WriteSetting(hContact, MODNAME, "ProgramParamsString", MODNAME, "ProgramParams");
+ }
+ else g_plugin.delSetting(hContact, "ProgramParamsString");
+
+ if (GetWindowTextLength(GetDlgItem(hwnd, IDC_GROUP))) {
+ wchar_t text[512];
+ GetDlgItemText(hwnd, IDC_GROUP, text, _countof(text));
+ Clist_GroupCreate(NULL, text);
+ db_set_ws(hContact, "CList", "Group", text);
+ }
+ else db_unset(hContact, "CList", "Group");
+
+ for (int i = ID_STATUS_ONLINE; i <= ID_STATUS_OUTTOLUNCH; i++)
+ if (IsDlgButtonChecked(hwnd, i))
+ g_plugin.setWord(hContact, "Icon", (WORD)i);
+
+ /* set correct status */
+ if (status == ID_STATUS_ONLINE || status == ID_STATUS_AWAY || (status == g_plugin.getWord(hContact, "Icon", ID_STATUS_ONLINE)))
+ g_plugin.setWord(hContact, "Status", (WORD)g_plugin.getWord(hContact, "Icon", ID_STATUS_ONLINE));
+ else
+ g_plugin.setWord(hContact, "Status", ID_STATUS_OFFLINE);
+
+ if (IsDlgButtonChecked(hwnd, CHK_USE_TIMER)) {
+ if (GetWindowTextLength(GetDlgItem(hwnd, IDC_TIMER))) {
+ wchar_t text[512];
+ GetDlgItemText(hwnd, IDC_TIMER, text, _countof(text));
+ g_plugin.setWord(hContact, "Timer", (WORD)_wtoi(text));
+ }
+ else g_plugin.setWord(hContact, "Timer", 15);
+ }
+ else g_plugin.setWord(hContact, "Timer", 0);
+
+ // always visible
+ g_plugin.setByte(hContact, "AlwaysVisible", (BYTE)IsDlgButtonChecked(hwnd, IDC_ALWAYS_VISIBLE));
+ g_plugin.setByte(hContact, "VisibleUnlessOffline", (BYTE)IsDlgButtonChecked(hwnd, IDC_VISIBLE_UNLESS_OFFLINE));
+ }
+ return TRUE;
+ }
+ break;
+ }
+ return FALSE;
+}
+
+char* copyReplaceString(char* oldStr, char* newStr, char* findStr, char* replaceWithStr)
+{
+ int i = 0;
+ while (oldStr[i] != '\0') {
+ // msg(&oldStr[i],"");
+ if (!strncmp(&oldStr[i], findStr, mir_strlen(findStr))) {
+ mir_strcat(newStr, replaceWithStr);
+ i += (int)mir_strlen(findStr);
+ }
+ else {
+ strncat(newStr, &oldStr[i], 1);
+ i++;
+ }
+ }
+ return newStr;
+}
+
+#define MAX_REPLACES 15
+
+INT_PTR CALLBACK DlgProcCopy(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
+{
+ switch (msg) {
+ case WM_INITDIALOG:
+ TranslateDialogDefault(hwnd);
+ SetWindowLongPtr(hwnd, GWLP_USERDATA, ((PROPSHEETPAGE*)lParam)->lParam);
+ return TRUE;
+
+ case WM_COMMAND:
+ SendMessage(GetParent(hwnd), PSM_CHANGED, 0, 0);
+ switch (LOWORD(wParam)) {
+ case IDC_EXPORT:
+ ExportContact((MCONTACT)GetWindowLongPtr(hwnd, GWLP_USERDATA));
+ break;
+
+ case IDC_DOIT:
+ if (GetWindowTextLength(GetDlgItem(hwnd, IDC_STRING_REPLACE))) {
+ char newString[MAX_REPLACES][512], oldString[MAX_REPLACES][512];
+ char dbVar1[2000], dbVar2[2000];
+ int i = 0, j = 0, k = 0;
+ char *string = oldString[k];
+ MCONTACT hContact1 = (MCONTACT)GetWindowLongPtr(hwnd, GWLP_USERDATA);
+ if (!db_get_static(hContact1, MODNAME, "Name", dbVar1, _countof(dbVar1))) {
+ char *replace = (char*)malloc(GetWindowTextLength(GetDlgItem(hwnd, IDC_STRING_REPLACE)) + 1);
+ GetDlgItemTextA(hwnd, IDC_STRING_REPLACE, replace, GetWindowTextLength(GetDlgItem(hwnd, IDC_STRING_REPLACE)) + 1);
+ // get the list of replace strings
+ while (replace[i] != '\0') {
+ if (replace[i] == ',') {
+ string = newString[k];
+ j = 0;
+ }
+ else if (!strncmp(replace + i, "\r\n", 2)) {
+ if (string == newString[k])
+ k--;
+ if (k == MAX_REPLACES)
+ break;
+ string = oldString[++k];
+ i += 2;
+ continue;
+ }
+ else {
+ string[j] = replace[i];
+ string[++j] = '\0';
+ }
+ i++;
+ }
+ free(replace);
+ MCONTACT hContact2 = db_add_contact();
+ Proto_AddToContact(hContact2, MODNAME);
+ CallService(MS_IGNORE_IGNORE, (WPARAM)hContact2, IGNOREEVENT_USERONLINE);
+ g_plugin.setString(hContact2, "Nick", Translate("New Non-IM Contact"));
+ // blank dbVar2 so the replaceing doesnt crash..
+ mir_strcpy(dbVar2, "");
+ // copy the name (dbVar1 is the name)
+ for (i = 0; i < k; i++)
+ copyReplaceString(dbVar1, dbVar2, oldString[i], newString[i]);
+
+ g_plugin.setString(hContact2, "Name", dbVar2);
+ // copy the ProgramString
+ if (!db_get_static(hContact1, MODNAME, "ProgramString", dbVar1, _countof(dbVar1))) {
+ mir_strcpy(dbVar2, "");
+ for (i = 0; i <= k; i++)
+ copyReplaceString(dbVar1, dbVar2, oldString[i], newString[i]);
+
+ g_plugin.setString(hContact2, "ProgramString", dbVar2);
+ }
+ // copy the ProgramParamString
+ if (!db_get_static(hContact1, MODNAME, "ProgramParamString", dbVar1, _countof(dbVar1))) {
+ mir_strcpy(dbVar2, "");
+ for (i = 0; i <= k; i++)
+ copyReplaceString(dbVar1, dbVar2, oldString[i], newString[i]);
+
+ g_plugin.setString(hContact2, "ProgramParamString", dbVar2);
+ }
+ // copy the group
+ if (!db_get_static(hContact1, "CList", "Group", dbVar1, _countof(dbVar1))) {
+ mir_strcpy(dbVar2, "");
+ for (i = 0; i <= k; i++)
+ copyReplaceString(dbVar1, dbVar2, oldString[i], newString[i]);
+
+ db_set_s(hContact2, "CList", "Group", dbVar2);
+ }
+ // copy the ToolTip
+ if (!db_get_static(hContact1, MODNAME, "ToolTip", dbVar1, _countof(dbVar1))) {
+ mir_strcpy(dbVar2, "");
+ for (i = 0; i <= k; i++)
+ copyReplaceString(dbVar1, dbVar2, oldString[i], newString[i]);
+
+ g_plugin.setString(hContact2, "ToolTip", dbVar2);
+ }
+ // timer
+ g_plugin.setByte(hContact2, "UseTimer", g_plugin.getByte(hContact1, "UseTimer"));
+ g_plugin.setByte(hContact2, "Minutes", g_plugin.getByte(hContact1, "Minutes"));
+ g_plugin.setWord(hContact2, "Timer", g_plugin.getWord(hContact1, "Timer"));
+ //icon
+ g_plugin.setWord(hContact2, "Icon", g_plugin.getWord(hContact1, "Icon", 40072));
+ replaceAllStrings(hContact2);
+ }
+ }
+ else {
+ char dbVar1[2000];
+ MCONTACT hContact1 = (MCONTACT)GetWindowLongPtr(hwnd, GWLP_USERDATA);
+ if (!db_get_static(hContact1, MODNAME, "Name", dbVar1, _countof(dbVar1))) {
+ MCONTACT hContact2 = db_add_contact();
+ if (!hContact2) {
+ msg("contact did not get created", "");
+ return 0;
+ }
+ Proto_AddToContact(hContact2, MODNAME);
+ CallService(MS_IGNORE_IGNORE, (WPARAM)hContact2, IGNOREEVENT_USERONLINE);
+ g_plugin.setString(hContact2, "Nick", Translate("New Non-IM Contact"));
+ g_plugin.setString(hContact2, "Name", dbVar1);
+ if (!db_get_static(hContact1, MODNAME, "ProgramString", dbVar1, _countof(dbVar1)))
+ g_plugin.setString(hContact2, "ProgramString", dbVar1);
+
+ // copy the ProgramParamString
+ if (!db_get_static(hContact1, MODNAME, "ProgramParamString", dbVar1, _countof(dbVar1)))
+ g_plugin.setString(hContact2, "ProgramParamString", dbVar1);
+
+ // copy the group
+ if (!db_get_static(hContact1, "CList", "Group", dbVar1, _countof(dbVar1)))
+ db_set_s(hContact2, "CList", "Group", dbVar1);
+
+ // copy the ToolTip
+ if (!db_get_static(hContact1, MODNAME, "ToolTip", dbVar1, _countof(dbVar1)))
+ g_plugin.setString(hContact2, "ToolTip", dbVar1);
+
+ // timer
+ g_plugin.setByte(hContact2, "UseTimer", g_plugin.getByte(hContact1, "UseTimer"));
+ g_plugin.setByte(hContact2, "Minutes", g_plugin.getByte(hContact1, "Minutes"));
+ g_plugin.setWord(hContact2, "Timer", g_plugin.getWord(hContact1, "Timer"));
+
+ //icon
+ g_plugin.setWord(hContact2, "Icon", g_plugin.getWord(hContact1, "Icon", 40072));
+ replaceAllStrings(hContact2);
+ }
+ }
+ }
+ break;
+
+ case WM_NOTIFY:
+ switch (((LPNMHDR)lParam)->idFrom) {
+ case 0:
+ switch (((LPNMHDR)lParam)->code) {
+ case PSN_APPLY:
+ return TRUE;
+ }
+ }
+ break;
+ }
+ return FALSE;
+}
+
+void ExportContact(MCONTACT hContact)
+{
+ char szFileName[MAX_PATH];
+ char DBVar[1024];
+ int tmp;
+
+ if (Openfile(szFileName, 0)) {
+ // if (tmp = MessageBox(0, "Do you want to overwrite the contents of the file?\r\n\r\nPressing No will append this contact to the end of the file.",modFullname, MB_YESNO) == IDYES)
+ // file = fopen(szFileName, "w");
+ // else
+ FILE *file = fopen(szFileName, "a");
+ if (file) {
+ if (!db_get_static(hContact, MODNAME, "Name", DBVar, _countof(DBVar))) {
+ fprintf(file, "\r\n[Non-IM Contact]\r\nName=%s\r\n", DBVar);
+ if (!db_get_static(hContact, MODNAME, "ProgramString", DBVar, _countof(DBVar)))
+ fprintf(file, "ProgramString=%s\r\n", DBVar);
+ if (!db_get_static(hContact, MODNAME, "ProgramParamString", DBVar, _countof(DBVar)))
+ fprintf(file, "ProgramParamString=%s\r\n", DBVar);
+ if (!db_get_static(hContact, MODNAME, "ToolTip", DBVar, _countof(DBVar)))
+ fprintf(file, "ToolTip=%s</tooltip>\r\n", DBVar);
+ if (!db_get_static(hContact, "CList", "Group", DBVar, _countof(DBVar)))
+ fprintf(file, "Group=%s\r\n", DBVar);
+ if (tmp = g_plugin.getWord(hContact, "Icon", 40072))
+ fprintf(file, "Icon=%d\r\n", tmp);
+ if (tmp = g_plugin.getByte(hContact, "UseTimer", 0))
+ fprintf(file, "UseTimer=%d\r\n", tmp);
+ if (tmp = g_plugin.getByte(hContact, "Minutes", 1))
+ fprintf(file, "Minutes=%d\r\n", tmp);
+ if (tmp = g_plugin.getWord(hContact, "Timer", 0))
+ fprintf(file, "Timer=%d\r\n", tmp);
+ fprintf(file, "[/Non-IM Contact]\r\n");
+ }
+ else ("Contact is invalid", modFullname);
+ fclose(file);
+ }
+ }
+}
+
+INT_PTR ImportContacts(WPARAM, LPARAM)
+{
+ MCONTACT hContact;
+ char name[256] = "", program[256] = "", programparam[256] = "", group[256] = "", line[2001] = "";
+ int icon = 40072, usetimer = 0, minutes = 1, timer = 0;
+ char fn[MAX_PATH];
+ int i, j, contactDone = 0;
+ if (!Openfile(fn, 1))
+ return 1;
+
+ FILE *file = fopen(fn, "r");
+ if (!file)
+ return 1;
+
+ CMStringA tooltip;
+
+ while (fgets(line, 2000, file)) {
+ if (!mir_strcmp(line, "\r\n\0"))
+ continue;
+ if (!mir_strcmp(line, "[Non-IM Contact]\r\n"))
+ contactDone = 0;
+ else if (!strncmp(line, "Name=", mir_strlen("Name="))) {
+ i = (int)mir_strlen("Name="); j = 0;
+ while (line[i] != '\r' && line[i] != '\n' && line[i] != '\0') {
+ name[j] = line[i++];
+ name[++j] = '\0';
+ }
+ contactDone = 1;
+ }
+ else if (!strncmp(line, "ProgramString=", mir_strlen("ProgramString="))) {
+ i = (int)mir_strlen("ProgramString="); j = 0;
+ while (line[i] != '\r' && line[i] != '\n' && line[i] != '\0') {
+ program[j] = line[i++];
+ program[++j] = '\0';
+ }
+ }
+ else if (!strncmp(line, "ProgramParamString=", mir_strlen("ProgramParamString="))) {
+ i = (int)mir_strlen("ProgramParamString="); j = 0;
+ while (line[i] != '\r' && line[i] != '\n' && line[i] != '\0') {
+ programparam[j] = line[i++];
+ programparam[++j] = '\0';
+ }
+ }
+ else if (!strncmp(line, "Group=", mir_strlen("Group="))) {
+ i = (int)mir_strlen("Group="); j = 0;
+ while (line[i] != '\r' && line[i] != '\n' && line[i] != '\0') {
+ group[j] = line[i++];
+ group[++j] = '\0';
+ }
+ }
+ else if (!strncmp(line, "ToolTip=", mir_strlen("ToolTip="))) {
+ i = (int)mir_strlen("ToolTip=");
+ tooltip = &line[i];
+ fgets(line, 2000, file);
+ while (!strstr(line, "</tooltip>\r\n")) {
+ tooltip.Append(line);
+ fgets(line, 2000, file);
+ }
+ // the line that has the </tooltip>
+ tooltip.Append(line);
+ }
+ else if (!strncmp(line, "Icon=", mir_strlen("Icon="))) {
+ i = (int)mir_strlen("Icon=");
+ sscanf(&line[i], "%d", &icon);
+ }
+ else if (!strncmp(line, "UseTimer=", mir_strlen("UseTimer="))) {
+ i = (int)mir_strlen("UseTimer=");
+ sscanf(&line[i], "%d", &usetimer);
+ }
+ else if (!strncmp(line, "Timer=", mir_strlen("Timer="))) {
+ i = (int)mir_strlen("Timer=");
+ sscanf(&line[i], "%d", &timer);
+ }
+ else if (!strncmp(line, "Minutes=", mir_strlen("Minutes="))) {
+ i = (int)mir_strlen("Minutes=");
+ sscanf(&line[i], "%d", &minutes);
+ }
+ else if (contactDone && !mir_strcmp(line, "[/Non-IM Contact]\r\n")) {
+ if (!name) continue;
+ size_t size = mir_strlen(name) + mir_strlen("Do you want to import this Non-IM Contact?\r\n\r\nName: \r\n") + 1;
+ char *msg = (char*)malloc(size);
+ mir_snprintf(msg, size, "Do you want to import this Non-IM Contact?\r\n\r\nName: %s\r\n", name);
+ if (program[0] != '\0') {
+ msg = (char*)realloc(msg, mir_strlen(msg) + mir_strlen(program) + mir_strlen("Program: \r\n") + 1);
+ mir_strcat(msg, "Program: ");
+ mir_strcat(msg, program);
+ mir_strcat(msg, "\r\n");
+ }
+ if (programparam[0] != '\0') {
+ msg = (char*)realloc(msg, mir_strlen(msg) + mir_strlen(programparam) + mir_strlen("Program Parameters: \r\n") + 1);
+ mir_strcat(msg, "Program Parameters: ");
+ mir_strcat(msg, programparam);
+ mir_strcat(msg, "\r\n");
+ }
+ if (tooltip) {
+ msg = (char*)realloc(msg, mir_strlen(msg) + mir_strlen(tooltip) + mir_strlen("ToolTip: \r\n") + 1);
+ mir_strcat(msg, "ToolTip: ");
+ mir_strcat(msg, tooltip);
+ mir_strcat(msg, "\r\n");
+ }
+ if (group[0] != '\0') {
+ msg = (char*)realloc(msg, mir_strlen(msg) + mir_strlen(group) + mir_strlen("Group: \r\n") + 1);
+ mir_strcat(msg, "Group: ");
+ mir_strcat(msg, group);
+ mir_strcat(msg, "\r\n");
+ }
+ if (icon) {
+ char tmp[64];
+ if (icon == ID_STATUS_ONLINE)
+ mir_snprintf(tmp, "Icon: Online\r\n");
+ else if (icon == ID_STATUS_AWAY)
+ mir_snprintf(tmp, "Icon: Away\r\n");
+ else if (icon == ID_STATUS_NA)
+ mir_snprintf(tmp, "Icon: N/A\r\n");
+ else if (icon == ID_STATUS_DND)
+ mir_snprintf(tmp, "Icon: DND\r\n");
+ else if (icon == ID_STATUS_OCCUPIED)
+ mir_snprintf(tmp, "Icon: Occupied\r\n");
+ else if (icon == ID_STATUS_FREECHAT)
+ mir_snprintf(tmp, "Icon: Free for chat\r\n");
+ else if (icon == ID_STATUS_INVISIBLE)
+ mir_snprintf(tmp, "Icon: Invisible\r\n");
+ else if (icon == ID_STATUS_ONTHEPHONE)
+ mir_snprintf(tmp, "Icon: On the phone\r\n");
+ else if (icon == ID_STATUS_OUTTOLUNCH)
+ mir_snprintf(tmp, "Icon: Out to lunch\r\n");
+ else {
+ free(msg);
+ continue;
+ }
+ char *msgtemp = (char*)realloc(msg, mir_strlen(msg) + mir_strlen(tmp) + 1);
+ if (msgtemp) {
+ msg = msgtemp;
+ mir_strcat(msg, tmp);
+ }
+ }
+ if (usetimer && timer) {
+ char tmp[64], tmp2[8];
+ if (minutes)
+ mir_strcpy(tmp2, "Minutes");
+ else mir_strcpy(tmp2, "Seconds");
+ mir_snprintf(tmp, "UseTimer: Yes\r\nTimer: %d %s", timer, tmp2);
+ char *msgtemp = (char*)realloc(msg, mir_strlen(msg) + mir_strlen(tmp) + 1);
+ if (msgtemp) {
+ msg = msgtemp;
+ mir_strcat(msg, tmp);
+ }
+ }
+
+ if (MessageBoxA(nullptr, msg, modFullname, MB_YESNO) == IDYES) {
+ if (!(hContact = db_add_contact())) {
+ msg("contact did get created", "");
+ continue;
+ }
+ Proto_AddToContact(hContact, MODNAME);
+ CallService(MS_IGNORE_IGNORE, hContact, IGNOREEVENT_USERONLINE);
+ g_plugin.setString(hContact, "Nick", Translate("New Non-IM Contact"));
+ g_plugin.setString(hContact, "Name", name);
+ g_plugin.setString(hContact, "ProgramString", program);
+ // copy the ProgramParamString
+ g_plugin.setString(hContact, "ProgramParamString", programparam);
+ // copy the group
+ db_set_s(hContact, "CList", "Group", group);
+ // copy the ToolTip
+ g_plugin.setString(hContact, "ToolTip", tooltip);
+ // timer
+ g_plugin.setByte(hContact, "UseTimer", (BYTE)usetimer);
+ g_plugin.setByte(hContact, "Minutes", (BYTE)minutes);
+ g_plugin.setWord(hContact, "Timer", (WORD)timer);
+ //icon
+ g_plugin.setWord(hContact, "Icon", (WORD)icon);
+ replaceAllStrings(hContact);
+ }
+ free(msg);
+ contactDone = 0;
+ name[0] = '\0';
+ program[0] = '\0';
+ programparam[0] = '\0';
+ group[0] = '\0';
+ line[0] = '\0';
+ tooltip.Empty();
+ icon = 40072;
+ usetimer = 0;
+ minutes = 1;
+ timer = 0;
+ }
+ }
+ fclose(file);
+
+ return 1;
+}
diff --git a/protocols/Non-IM Contact/src/dialog.cpp b/protocols/Non-IM Contact/src/dialog.cpp
new file mode 100644
index 0000000000..989f2fdb81
--- /dev/null
+++ b/protocols/Non-IM Contact/src/dialog.cpp
@@ -0,0 +1,332 @@
+#include "stdafx.h"
+
+#define NIM_HELP_TEXT TranslateT("String replacing variables...\r\nThe following are all the valid variables that can be used. Refer to the wiki.miranda-ng.org for a proper explanation.\r\n\r\n\
+file(X)\t\t<- specifies the file to read from. MUST be followed by either start() or end() or wholeline()\r\n\
+filename(X)\t<- copies the filename of file X.\r\n\
+start(...)\t\t<- specifies where to start copying from.\r\n\
+end(...)\t\t<- specifies where to stop copying.\r\n\
+wholeline(line(...))\t<- specifies a whole line to copy\r\n\r\n\
+start() and end() explained\r\n.........................\r\n\
+MUST start with line() followed by a number or a string inside \" marks, OR csv(separatorX) variable. The number specifies which character in the line to start/end copying. The string specifies a string in the line to start/end copying.\r\n\r\n\
+csv(seperatorX) explained...\r\nSeperator is either \"tab\" or \"space\" or any SINGLE character. X is the Xth separator to pass before copying, (or to stop before).\r\n\r\n\
+Lastly the line(...) variable...\r\n\
+Inside the brackets must be either a number (to specify the line number), or a string inside \" marks (to use the line with that string), or lastline(X). The X in lastline is the Xth line above the last line, i.e., lastline(1) will use the 2nd last line of the file. If searching for a line with \"some words\" you may put a + or - X after the closing ), i.e., line(\"some words\")+3 to go 3 lines after the line with \"some words\".\r\n\r\n\
+Some examples...\r\n\
+filename(0) <- will display the filename of the 0th file\r\nfile(0)wholeline(line(0))) <- will display the whole first line of the 0th file\r\nfile(0)wholeline(line(\"hello\")-1))) <- the wholeline above the first occurrence of \"hello\" in the file\r\nfile(0)start(line(lastline(1))csv(tab2))end(line(lastline())csv(tab4))) <- starts at the 2nd last line of the file, from the 2nd tab variable, until the 4th tab variable in the last line (in the 0th file)\r\nfile(0)start(line(\"hello\")+1\"zzzz\")end(line(6)17)) <- starts from the first occurrence of zzzz in the line after the first occurrence of hello, until the 17th character in the 6th line (starting from line 0) of the 0th file.\r\n")
+
+
+INT_PTR CALLBACK DlgProcNimcOpts(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
+{
+ wchar_t tmp[5];
+
+ switch (msg) {
+ case WM_INITDIALOG:
+ TranslateDialogDefault(hwnd);
+ CheckDlgButton(hwnd, IDC_AWAYISNOTONLINE, g_plugin.getByte("AwayAsStatus") ? BST_CHECKED : BST_UNCHECKED);
+ if (g_plugin.getWord("Timer", 1)) {
+ EnableWindow(GetDlgItem(hwnd, IDC_TIMER_INT), 1);
+ SetDlgItemText(hwnd, IDC_TIMER_INT, _itow(g_plugin.getWord("Timer", 1), tmp, 10));
+ EnableWindow(GetDlgItem(hwnd, IDC_TIMER_TEXT), 1);
+ }
+ else {
+ CheckDlgButton(hwnd, IDC_DISABLETIMER, BST_CHECKED);
+ EnableWindow(GetDlgItem(hwnd, IDC_TIMER_INT), 0);
+ EnableWindow(GetDlgItem(hwnd, IDC_TIMER_TEXT), 0);
+ }
+ return TRUE;
+
+ case WM_COMMAND:
+ SendMessage(GetParent(hwnd), PSM_CHANGED, 0, 0);
+ switch (LOWORD(wParam)) {
+ case IDC_DISABLETIMER:
+ if (IsDlgButtonChecked(hwnd, IDC_DISABLETIMER)) {
+ EnableWindow(GetDlgItem(hwnd, IDC_TIMER_INT), 0);
+ EnableWindow(GetDlgItem(hwnd, IDC_TIMER_TEXT), 0);
+ }
+ else {
+ EnableWindow(GetDlgItem(hwnd, IDC_TIMER_TEXT), 1);
+ EnableWindow(GetDlgItem(hwnd, IDC_TIMER_INT), 1);
+ if (!GetWindowTextLength(GetDlgItem(hwnd, IDC_TIMER_INT)))
+ SetDlgItemText(hwnd, IDC_TIMER_INT, L"1");
+ }
+ break;
+ }
+ break;
+
+ case WM_NOTIFY:
+ switch (((LPNMHDR)lParam)->idFrom) {
+ case 0:
+ switch (((LPNMHDR)lParam)->code) {
+ case PSN_APPLY:
+ g_plugin.setByte("AwayAsStatus", (BYTE)IsDlgButtonChecked(hwnd, IDC_AWAYISNOTONLINE));
+ if (BST_UNCHECKED == IsDlgButtonChecked(hwnd, IDC_DISABLETIMER) && GetWindowTextLength(GetDlgItem(hwnd, IDC_TIMER_INT))) {
+ GetDlgItemText(hwnd, IDC_TIMER_INT, tmp, _countof(tmp));
+ g_plugin.setWord("Timer", (WORD)_wtoi(tmp));
+ }
+ else g_plugin.setWord("Timer", 0);
+ return TRUE;
+ }
+ }
+ break;
+ }
+ return FALSE;
+}
+
+// string replace test window thingamijig....
+
+// struct to keep track of ()'s in the test sring window
+#define MAX_BRACES 32
+#define VARS 7
+struct braces
+{
+ char var[64];
+ int idCtrl;
+}
+braceList[VARS] =
+{
+ { "file(", IDC_FILE },
+ { "start(", IDC_START },
+ { "end(", IDC_END },
+ { "csv(", IDC_CSV },
+ { "wholeline(", IDC_WHOLELINE },
+ { "filename(", IDC_FILENAME },
+ { "line(", IDC_LINE }
+};
+int braceOrder[MAX_BRACES] = { 0 };
+
+INT_PTR CALLBACK HelpWindowDlgProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM)
+{
+ switch (msg) {
+ case WM_INITDIALOG:
+ SetDlgItemText(hwnd, IDC_HELPTEXT, NIM_HELP_TEXT);
+ TranslateDialogDefault(hwnd);
+ return TRUE;
+
+ case WM_COMMAND:
+ switch (LOWORD(wParam)) {
+ case IDOK:
+ DestroyWindow(hwnd);
+ break;
+ }
+ return TRUE;
+ }
+ return FALSE;
+}
+
+INT_PTR CALLBACK TestWindowDlgProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM)
+{
+ switch (msg) {
+ case WM_INITDIALOG:
+ TranslateDialogDefault(hwnd);
+ return TRUE;
+
+ case WM_COMMAND:
+ switch (LOWORD(wParam)) {
+ case IDC_HELPMSG:
+ CreateDialog(g_plugin.getInst(), MAKEINTRESOURCE(IDD_HELP), nullptr, HelpWindowDlgProc);
+ break;
+
+ case IDCANCEL:
+ DestroyWindow(hwnd);
+ break;
+
+ case IDC_STRING:
+ if (HIWORD(wParam) == EN_CHANGE) {
+ char tmp[MAX_STRING_LENGTH];
+ int i = 0, j;
+ if (GetWindowTextLength(GetDlgItem(hwnd, IDC_STRING))) {
+ GetDlgItemTextA(hwnd, IDC_STRING, tmp, _countof(tmp));
+ if (tmp[mir_strlen(tmp) - 1] == '(') {
+ for (i = 0; i < VARS; i++) {
+ if (!mir_strcmp(braceList[i].var, &tmp[mir_strlen(tmp) - mir_strlen(braceList[i].var)])) {
+ for (j = 0; j < MAX_BRACES; j++) {
+ if (!braceOrder[j]) {
+ braceOrder[j] = i;
+ EnableWindow(GetDlgItem(hwnd, braceList[i].idCtrl), 1);
+ if (j)
+ EnableWindow(GetDlgItem(hwnd, braceList[braceOrder[j - 1]].idCtrl), 0);
+ break;
+ }
+ }
+ break;
+ }
+ }
+ }
+ else if (tmp[mir_strlen(tmp) - 1] == ')') {
+ for (j = 0; j < MAX_BRACES; j++) {
+ if (!braceOrder[j]) {
+ EnableWindow(GetDlgItem(hwnd, braceList[braceOrder[j - 1]].idCtrl), 0);
+ if (j > 1)
+ EnableWindow(GetDlgItem(hwnd, braceList[braceOrder[j - 2]].idCtrl), 1);
+ braceOrder[j - 1] = 0;
+ break;
+ }
+ }
+ }
+ }
+ else {
+ for (j = 0; j < MAX_BRACES; j++) {
+ if (!braceOrder[j]) break;
+ EnableWindow(GetDlgItem(hwnd, braceList[braceOrder[j]].idCtrl), 0);
+ }
+ }
+ }
+ break;
+
+ case IDOK:
+ CMStringA replacedString;
+ char str2replace[MAX_STRING_LENGTH];
+ int error;
+ if (GetWindowTextLength(GetDlgItem(hwnd, IDC_STRING))) {
+ GetDlgItemTextA(hwnd, IDC_STRING, str2replace, _countof(str2replace));
+ switch (stringReplacer(str2replace, replacedString, NULL)) {
+ case ERROR_NO_LINE_AFTER_VAR_F:
+ replacedString.Format("ERROR: no %s", "%line or %wholeline or %lastline after %fn");
+ error = 1;
+ break;
+ case ERROR_LINE_NOT_READ:
+ replacedString.Format("ERROR: file couldnt be opened ");
+ error = 1;
+ break;
+ case ERROR_NO_FILE:
+ replacedString.Format("ERROR: no file specified in settings");
+ error = 1;
+ break;
+ default:
+ error = 0;
+ }
+ SetDlgItemTextA(hwnd, IDC_ANSWER, replacedString);
+ }
+ }
+ break;
+ }
+ return FALSE;
+}
+
+INT_PTR testStringReplacer(WPARAM, LPARAM)
+{
+ CreateDialog(g_plugin.getInst(), MAKEINTRESOURCE(IDD_TEST_LINE), nullptr, TestWindowDlgProc);
+ return 0;
+}
+
+INT_PTR LoadFilesDlg(WPARAM, LPARAM)
+{
+ CreateDialog(g_plugin.getInst(), MAKEINTRESOURCE(IDD_ADD_FILE), nullptr, DlgProcFiles);
+ return 0;
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+
+static int CALLBACK PropSheetProc(HWND, UINT uMsg, LPARAM lParam)
+{
+ if (uMsg == PSCB_PRECREATE) {
+ // Remove the DS_CONTEXTHELP style from the
+ // dialog box template
+ if (((DLGTEMPLATEEX*)lParam)->signature == 0xFFFF)
+ ((DLGTEMPLATEEX*)lParam)->style &= ~DS_CONTEXTHELP;
+ else
+ ((LPDLGTEMPLATE)lParam)->style &= ~DS_CONTEXTHELP;
+
+ return TRUE;
+ }
+
+ return 0;
+}
+
+void DoPropertySheet(MCONTACT hContact)
+{
+ char nick[256];
+ PROPSHEETPAGEA psp[4] = { 0 };
+
+ /* contact info */
+ psp[0].dwSize = sizeof(PROPSHEETPAGE);
+ psp[0].dwFlags = PSP_USEICONID | PSP_USETITLE;
+ psp[0].hInstance = g_plugin.getInst();
+ psp[0].pszTemplate = MAKEINTRESOURCEA(IDD_CONTACT_INFO);
+ psp[0].pszIcon = nullptr;
+ psp[0].pfnDlgProc = DlgProcContactInfo;
+ psp[0].pszTitle = Translate("Contacts Display Info");
+ psp[0].lParam = hContact;
+ psp[0].pfnCallback = nullptr;
+
+ /* other settings */
+ psp[1].dwSize = sizeof(PROPSHEETPAGE);
+ psp[1].dwFlags = PSP_USEICONID | PSP_USETITLE;
+ psp[1].hInstance = g_plugin.getInst();
+ psp[1].pszTemplate = MAKEINTRESOURCEA(IDD_OTHER_STUFF);
+ psp[1].pszIcon = nullptr;
+ psp[1].pfnDlgProc = DlgProcOtherStuff;
+ psp[1].pszTitle = Translate("Link and Contact list Settings");
+ psp[1].lParam = hContact;
+ psp[1].pfnCallback = nullptr;
+
+ /* copy contact */
+ psp[2].dwSize = sizeof(PROPSHEETPAGE);
+ psp[2].dwFlags = PSP_USEICONID | PSP_USETITLE;
+ psp[2].hInstance = g_plugin.getInst();
+ psp[2].pszTemplate = MAKEINTRESOURCEA(IDD_CONTACT_COPYEXPORT);
+ psp[2].pszIcon = nullptr;
+ psp[2].pfnDlgProc = DlgProcCopy;
+ psp[2].pszTitle = Translate("Copy Contact");
+ psp[2].lParam = hContact;
+ psp[2].pfnCallback = nullptr;
+
+ /* files */
+ psp[3].dwSize = sizeof(PROPSHEETPAGE);
+ psp[3].dwFlags = PSP_USEICONID | PSP_USETITLE;
+ psp[3].hInstance = g_plugin.getInst();
+ psp[3].pszTemplate = MAKEINTRESOURCEA(IDD_ADD_FILE);
+ psp[3].pszIcon = nullptr;
+ psp[3].pfnDlgProc = DlgProcFiles;
+ psp[3].pszTitle = Translate("Files");
+ psp[3].lParam = 0;
+ psp[3].pfnCallback = nullptr;
+
+ /* propery sheet header.. dont touch !!!! */
+ PROPSHEETHEADERA psh = { sizeof(psh) };
+ psh.dwFlags = PSH_USEICONID | PSH_PROPSHEETPAGE | PSH_USECALLBACK;
+ psh.hInstance = g_plugin.getInst();
+ psh.pszIcon = MAKEINTRESOURCEA(IDI_MAIN);
+ if (!db_get_static(hContact, MODNAME, "Nick", nick, _countof(nick))) {
+ char title[256];
+ mir_snprintf(title, Translate("Edit Non-IM Contact \"%s\""), nick);
+ psh.pszCaption = title;
+ }
+ psh.nPages = _countof(psp);
+ psh.ppsp = (LPCPROPSHEETPAGEA)&psp;
+ psh.pfnCallback = PropSheetProc;
+
+ // Now do it and return
+ PropertySheetA(&psh);
+}
+
+INT_PTR addContact(WPARAM, LPARAM)
+{
+ char tmp[256];
+ MCONTACT hContact = db_add_contact();
+ Proto_AddToContact(hContact, MODNAME);
+ CallService(MS_IGNORE_IGNORE, hContact, IGNOREEVENT_USERONLINE);
+ g_plugin.setWString(hContact, "Nick", TranslateT("New Non-IM Contact"));
+ DoPropertySheet(hContact);
+ if (db_get_static(hContact, MODNAME, "Name", tmp, _countof(tmp)))
+ db_delete_contact(hContact);
+ replaceAllStrings(hContact);
+ return 0;
+}
+
+INT_PTR editContact(WPARAM wParam, LPARAM)
+{
+ MCONTACT hContact = wParam;
+ char tmp[256];
+ if (!hContact) {
+ hContact = db_add_contact();
+ Proto_AddToContact(hContact, MODNAME);
+ CallService(MS_IGNORE_IGNORE, hContact, IGNOREEVENT_USERONLINE);
+ g_plugin.setString(hContact, "Nick", Translate("New Non-IM Contact"));
+ }
+ DoPropertySheet(hContact);
+ if (db_get_static(hContact, MODNAME, "Name", tmp, _countof(tmp)))
+ db_delete_contact(hContact);
+ replaceAllStrings(hContact);
+ return 0;
+}
diff --git a/protocols/Non-IM Contact/src/files.cpp b/protocols/Non-IM Contact/src/files.cpp
new file mode 100644
index 0000000000..17a11edd3c
--- /dev/null
+++ b/protocols/Non-IM Contact/src/files.cpp
@@ -0,0 +1,328 @@
+#include "stdafx.h"
+
+INT_PTR exportContacts(WPARAM, LPARAM)
+{
+ char fn[MAX_PATH];
+ if (!Openfile(fn, 0))
+ return 0;
+
+ FILE* file;
+ if (MessageBox(nullptr, TranslateT("Do you want to overwrite the contents of the file?\r\n\r\nPressing No will append these contacts to the end of the file."), _A2W(modFullname), MB_YESNO) == IDYES)
+ file = fopen(fn, "w");
+ else
+ file = fopen(fn, "a");
+ if (!file)
+ return 0;
+
+ for (auto &hContact : Contacts(MODNAME)) {
+ int tmp;
+ char DBVar[1024];
+ if (!db_get_static(hContact, MODNAME, "Name", DBVar, _countof(DBVar))) {
+ fprintf(file, "\r\n[Non-IM Contact]\r\nName=%s\r\n", DBVar);
+ if (!db_get_static(hContact, MODNAME, "ProgramString", DBVar, _countof(DBVar)))
+ fprintf(file, "ProgramString=%s\r\n", DBVar);
+ if (!db_get_static(hContact, MODNAME, "ProgramParamString", DBVar, _countof(DBVar)))
+ fprintf(file, "ProgramParamString=%s\r\n", DBVar);
+ if (!db_get_static(hContact, MODNAME, "ToolTip", DBVar, _countof(DBVar)))
+ fprintf(file, "ToolTip=%s</tooltip>\r\n", DBVar);
+ if (!db_get_static(hContact, "CList", "Group", DBVar, _countof(DBVar)))
+ fprintf(file, "Group=%s\r\n", DBVar);
+ if (tmp = g_plugin.getWord(hContact, "Icon", 40072))
+ fprintf(file, "Icon=%d\r\n", tmp);
+ if (tmp = g_plugin.getByte(hContact, "UseTimer", 0))
+ fprintf(file, "UseTimer=%d\r\n", tmp);
+ if (tmp = g_plugin.getByte(hContact, "Minutes", 1))
+ fprintf(file, "Minutes=%d\r\n", tmp);
+ if (tmp = g_plugin.getWord(hContact, "Timer", 0))
+ fprintf(file, "Timer=%d\r\n", tmp);
+ fprintf(file, "[/Non-IM Contact]\r\n");
+ }
+ }
+ fclose(file);
+ return 0;
+}
+
+int Openfile(char *outputFile, int saveOpen) //0=save, 1=open
+{
+ char filename[MAX_PATH] = "";
+ char *filter = "All Files\0*.*\0";
+ int r;
+ char title[16];
+ if (saveOpen)
+ mir_strcpy(title, "Open file");
+ else mir_strcpy(title, "Save to file");
+
+ OPENFILENAMEA ofn = { sizeof(ofn) };
+ ofn.lpstrFile = filename;
+ ofn.lpstrFilter = filter;
+ ofn.Flags = saveOpen ? OFN_HIDEREADONLY | OFN_FILEMUSTEXIST | OFN_SHAREAWARE | OFN_PATHMUSTEXIST : OFN_HIDEREADONLY | OFN_SHAREAWARE | OFN_PATHMUSTEXIST;
+ ofn.lpstrTitle = title;
+ ofn.nMaxFile = MAX_PATH;
+
+ if (saveOpen)
+ r = GetOpenFileNameA(&ofn);
+ else
+ r = GetSaveFileNameA(&ofn);
+ if (!r)
+ return 0;
+ mir_strcpy(outputFile, filename);
+ return 1;
+}
+
+void reloadFiles(HWND fileList)
+{
+ SendMessage(fileList, CB_RESETCONTENT, 0, 0);
+ for (int i = 0;; i++) {
+ char file[MAX_PATH], fn[6];
+ mir_snprintf(fn, "fn%d", i);
+ if (db_get_static(NULL, MODNAME, fn, file, _countof(file)))
+ return;
+
+ /* add the file contents to the edit box */
+ int index = SendMessageA(fileList, CB_ADDSTRING, 0, (LPARAM)file);
+ SendMessage(fileList, CB_SETITEMDATA, index, (LPARAM)i);
+ SendMessage(fileList, CB_SETCURSEL, index, 0);
+ SetDlgItemTextA(GetParent(fileList), IDC_FN, _itoa(i, fn, 10));
+ }
+}
+
+int savehtml(char* outFile)
+{
+ FILE* file = fopen(outFile, "w");
+ if (!file) {
+ return 0;
+ }
+ fprintf(file, "%s", szInfo);
+ fclose(file);
+ return 1;
+}
+
+void readFile(HWND hwnd)
+{
+ int lineNumber, fileLength = 0;
+ char temp[MAX_STRING_LENGTH], szFileName[512], temp1[MAX_STRING_LENGTH];
+ int fileNumber = SendDlgItemMessage(hwnd, IDC_FILE_LIST, CB_GETCURSEL, 0, 0);
+ {
+ char fn[10];
+ mir_snprintf(fn, "fn%d", fileNumber);
+ if (db_get_static(NULL, MODNAME, fn, szFileName, _countof(szFileName))) {
+ msg(Translate("File couldn't be opened"), fn);
+ return;
+ }
+ }
+
+ if (!strncmp("http://", szFileName, mir_strlen("http://")) || !strncmp("https://", szFileName, mir_strlen("https://")))
+ mir_snprintf(szFileName, "%s\\plugins\\fn%d.html", getMimDir(temp), fileNumber);
+
+ FILE *filen = fopen(szFileName, "r");
+ if (!filen) {
+ MessageBox(nullptr, TranslateT("File couldn't be opened,2"), _A2W(modFullname), MB_OK);
+ return;
+ }
+ lineNumber = 0;
+ SendDlgItemMessage(hwnd, IDC_FILE_CONTENTS, LB_RESETCONTENT, 0, 0);
+ while (lineNumber < (MAXLINES) && (fgets(temp, MAX_STRING_LENGTH, filen))) {
+ if (temp[0] == '\t') temp[0] = ' ';
+ if (temp[mir_strlen(temp) - 1] == '\n' && temp[mir_strlen(temp) - 2] == '\r')
+ temp[mir_strlen(temp) - 2] = '\0';
+ else if (temp[mir_strlen(temp) - 1] == '\n')
+ temp[mir_strlen(temp) - 1] = '\0';
+ else temp[mir_strlen(temp)] = '\0';
+ mir_snprintf(temp1, Translate("line(%-3d) = | %s"), lineNumber, temp);
+ SendDlgItemMessageA(hwnd, IDC_FILE_CONTENTS, LB_ADDSTRING, 0, (LPARAM)temp1);
+ lineNumber++;
+ fileLength++;
+ if ((unsigned int)SendDlgItemMessage(hwnd, IDC_FILE_CONTENTS, LB_GETHORIZONTALEXTENT, 0, 0) <= (mir_strlen(temp1)*g_plugin.getByte("WidthMultiplier", 5)))
+ SendDlgItemMessage(hwnd, IDC_FILE_CONTENTS, LB_SETHORIZONTALEXTENT, (mir_strlen(temp1)*g_plugin.getByte("WidthMultiplier", 5)), 0);
+ }
+ fclose(filen);
+}
+
+#define WM_RELOADWINDOW (WM_USER+11)
+
+INT_PTR CALLBACK DlgProcFiles(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
+{
+ char tmp[MAX_PATH], fn[MAX_PATH];
+
+ switch (msg) {
+ case WM_RELOADWINDOW:
+ {
+ char string[MAX_STRING_LENGTH];
+ reloadFiles(GetDlgItem(hwnd, IDC_FILE_LIST));
+
+ int i = SendDlgItemMessage(hwnd, IDC_FILE_LIST, CB_GETCURSEL, 0, 0);
+ mir_snprintf(fn, "fn%d", i);
+ SendDlgItemMessage(hwnd, IDC_FILE_CONTENTS, LB_RESETCONTENT, 0, 0);
+ if (!db_get_static(NULL, MODNAME, fn, string, _countof(string))) {
+ if ((!strncmp("http://", string, mir_strlen("http://"))) || (!strncmp("https://", string, mir_strlen("https://")))) {
+ SetDlgItemTextA(hwnd, IDC_URL, string);
+ mir_snprintf(fn, "fn%d_timer", i);
+ SetDlgItemTextA(hwnd, IDC_WWW_TIMER, _itoa(g_plugin.getWord(fn, 60), tmp, 10));
+ }
+ readFile(hwnd);
+ }
+ }
+ break;
+
+ case WM_INITDIALOG:
+ SendMessage(hwnd, WM_RELOADWINDOW, 0, 0);
+ TranslateDialogDefault(hwnd);
+ return TRUE;
+
+ case WM_COMMAND:
+ SendMessage(GetParent(hwnd), PSM_CHANGED, 0, 0);
+ switch (LOWORD(wParam)) {
+ case IDC_ADD_URL:
+ if (GetWindowTextLength(GetDlgItem(hwnd, IDC_URL))) {
+ char text[512], url[512], szFileName[MAX_PATH], temp[512];
+ GetDlgItemTextA(hwnd, IDC_URL, text, _countof(text));
+ mir_strcpy(url, text);
+ if (!InternetDownloadFile(text)) {
+ for (int i = 0;; i++) {
+ mir_snprintf(fn, "fn%d", i);
+ if (db_get_static(NULL, MODNAME, fn, text, _countof(text))) {
+ mir_snprintf(szFileName, "%s\\plugins\\%s.html", getMimDir(temp), fn);
+ if (savehtml(szFileName)) {
+ mir_snprintf(fn, "fn%d", i);
+ g_plugin.setString(fn, url);
+ int timer;
+ if (!GetWindowTextLength(GetDlgItem(hwnd, IDC_WWW_TIMER)))
+ timer = 60;
+ else {
+ GetDlgItemTextA(hwnd, IDC_WWW_TIMER, text, _countof(text));
+ timer = atoi(text);
+ }
+ mir_snprintf(fn, "fn%d_timer", i);
+ g_plugin.setWord(fn, (WORD)timer);
+ SendMessage(hwnd, WM_RELOADWINDOW, 0, 0);
+ }
+ break;
+ }
+ }
+ }
+ }
+ break;
+
+ case IDC_WWW_TIMER:
+ if (HIWORD(wParam) == EN_CHANGE)
+ SendMessage(GetParent(hwnd), PSM_CHANGED, 0, 0);
+ break;
+
+ case IDC_ADD_FILE:
+ for (int i = 0;; i++) {
+ char file[MAX_PATH];
+ mir_snprintf(fn, "fn%d", i);
+ if (db_get_static(NULL, MODNAME, fn, file, _countof(file))) {
+ if (Openfile(file, 1)) {
+ g_plugin.setString(fn, file);
+ int index = SendDlgItemMessageA(hwnd, IDC_FILE_LIST, CB_ADDSTRING, 0, (LPARAM)file);
+ SendDlgItemMessage(hwnd, IDC_FILE_LIST, CB_SETITEMDATA, index, (LPARAM)i);
+ SendDlgItemMessage(hwnd, IDC_FILE_LIST, CB_SETCURSEL, index, 0);
+ SetDlgItemTextA(hwnd, IDC_FN, _itoa(i, fn, 10));
+ mir_snprintf(fn, "fn%d", index);
+ readFile(hwnd);
+ }
+ break;
+ }
+ }
+ break;
+
+ case IDC_DEL_FILE:
+ {
+ int index = SendDlgItemMessage(hwnd, IDC_FILE_LIST, CB_GETCURSEL, 0, 0), i = (int)SendDlgItemMessage(hwnd, IDC_FILE_LIST, CB_GETITEMDATA, index, 0);
+ int count = SendDlgItemMessage(hwnd, IDC_FILE_LIST, CB_GETCOUNT, 0, 0) - 1;
+ if (index == count) {
+ mir_snprintf(fn, "fn%d", index);
+ g_plugin.delSetting(fn);
+ SendDlgItemMessage(hwnd, IDC_FILE_LIST, CB_DELETESTRING, index, 0);
+ SendMessage(hwnd, WM_RELOADWINDOW, 0, 0);
+ if (!index) {
+ SetDlgItemText(hwnd, IDC_FN, L"");
+ SetDlgItemText(hwnd, IDC_FILE_CONTENTS, L"");
+ }
+
+ }
+ else {
+ mir_snprintf(fn, "fn%d", i);
+ while (!db_get_static(NULL, MODNAME, fn, tmp, _countof(tmp))) {
+ char fn1[4];
+ mir_snprintf(fn1, "fn%d", i - 1);
+ g_plugin.setString(fn1, tmp);
+ mir_snprintf(fn, "fn%d", ++i);
+ }
+ mir_snprintf(fn, "fn%d", --i);
+ g_plugin.delSetting(fn);
+ SendDlgItemMessage(hwnd, IDC_FILE_LIST, CB_DELETESTRING, index, 0);
+ SendMessage(hwnd, WM_RELOADWINDOW, 0, 0);
+ }
+ }
+ break;
+
+ case IDC_FILE_LIST:
+ if (HIWORD(wParam) == CBN_SELCHANGE) {
+ int index = SendDlgItemMessage(hwnd, IDC_FILE_LIST, CB_GETCURSEL, 0, 0);
+ SetDlgItemTextA(hwnd, IDC_FN, _itoa(index, fn, 10));
+ mir_snprintf(fn, "fn%d", index);
+ if (!db_get_static(NULL, MODNAME, fn, tmp, _countof(tmp))) {
+ if (!strncmp("http://", tmp, mir_strlen("http://")) || !strncmp("https://", tmp, mir_strlen("https://"))) {
+ SetDlgItemTextA(hwnd, IDC_URL, tmp);
+ mir_snprintf(fn, "fn%d_timer", index);
+ SetDlgItemTextA(hwnd, IDC_WWW_TIMER, _itoa(g_plugin.getWord(fn, 60), tmp, 10));
+ }
+ else {
+ SetDlgItemText(hwnd, IDC_URL, L"");
+ SetDlgItemText(hwnd, IDC_WWW_TIMER, L"");
+ }
+ readFile(hwnd);
+ }
+ }
+ break;
+ case IDCANCEL:
+ DestroyWindow(hwnd);
+ break;
+ }
+ break;
+
+ case WM_NOTIFY:
+ switch (((LPNMHDR)lParam)->idFrom) {
+ case 0:
+ switch (((LPNMHDR)lParam)->code) {
+ case PSN_APPLY:
+ int i = SendDlgItemMessage(hwnd, IDC_FILE_LIST, CB_GETCURSEL, 0, 0);
+ int timer;
+ char string[1000];
+ mir_snprintf(fn, "fn%d", i);
+ if (GetWindowTextLength(GetDlgItem(hwnd, IDC_WWW_TIMER))) {
+ wchar_t text[5];
+ GetDlgItemText(hwnd, IDC_WWW_TIMER, text, _countof(text));
+ timer = _wtoi(text);
+ }
+ else timer = 60;
+
+ if (!db_get_static(NULL, MODNAME, fn, string, _countof(string)))
+ if (!strncmp("http://", string, mir_strlen("http://")) || !strncmp("https://", string, mir_strlen("https://"))) {
+ mir_snprintf(fn, "fn%d_timer", i);
+ g_plugin.setWord(fn, (WORD)timer);
+ }
+
+ return TRUE;
+ }
+ }
+ break;
+ }
+ return FALSE;
+}
+
+char* getMimDir(char* file)
+{
+ GetModuleFileNameA(nullptr, file, MAX_PATH);
+
+ char *p1 = strrchr(file, '\\');
+ if (p1)
+ *p1 = '\0';
+
+ if (file[0] == '\\')
+ file[mir_strlen(file) - 1] = '\0';
+
+ return file;
+}
diff --git a/protocols/Non-IM Contact/src/http.cpp b/protocols/Non-IM Contact/src/http.cpp
new file mode 100644
index 0000000000..a7eaca69cb
--- /dev/null
+++ b/protocols/Non-IM Contact/src/http.cpp
@@ -0,0 +1,100 @@
+/*
+Weather Protocol plugin for Miranda IM
+Copyright (C) 2002-2004 Calvin Che
+
+This program is free software; you can redistribute it and/or
+modify it under the terms of the GNU General Public License
+as published by the Free Software Foundation; 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.
+*/
+
+/* This file contain the source related to downloading weather info
+ from the web using netlib
+*/
+
+#include "stdafx.h"
+
+char *szInfo;
+char *szData;
+HNETLIBUSER hNetlibUser;
+
+// function to download webpage from the internet
+// szUrl = URL of the webpage to be retrieved
+// return value = 0 for success, 1 or HTTP error code for failure
+// global var used: szData, szInfo = containing the retrieved data
+//
+int InternetDownloadFile(char *szUrl)
+{
+ NETLIBHTTPREQUEST nlhr = { 0 };
+
+ // initialize the netlib request
+ nlhr.cbSize = sizeof(nlhr);
+ nlhr.requestType = REQUEST_GET;
+ nlhr.flags = NLHRF_DUMPASTEXT;
+ nlhr.szUrl = szUrl;
+ // change the header so the plugin is pretended to be IE 6 + WinXP
+ nlhr.headersCount++;
+ nlhr.headers = (NETLIBHTTPHEADER*)malloc(sizeof(NETLIBHTTPHEADER)*nlhr.headersCount);
+ nlhr.headers[nlhr.headersCount - 1].szName = "User-Agent";
+ nlhr.headers[nlhr.headersCount - 1].szValue = NETLIB_USER_AGENT;
+
+ // download the page
+ NETLIBHTTPREQUEST *nlhrReply = Netlib_HttpTransaction(hNetlibUser, &nlhr);
+ if (nlhrReply) {
+ // return error code if the recieved code is neither 200 OK or 302 Moved
+ if (nlhrReply->resultCode != 200 && nlhrReply->resultCode != 302)
+ return nlhrReply->resultCode;
+ // if the recieved code is 200 OK
+ else if (nlhrReply->resultCode == 200) {
+ // allocate memory and save the retrieved data
+ szData = (char *)malloc(mir_strlen(nlhrReply->pData) + 2);
+ mir_strncpy(szData, nlhrReply->pData, mir_strlen(nlhrReply->pData));
+ }
+ // if the recieved code is 302 Moved, Found, etc
+ else if (nlhrReply->resultCode == 302) { // page moved
+ int i;
+ // get the url for the new location and save it to szInfo
+ // look for the reply header "Location"
+ for (i = 0; i < nlhrReply->headersCount; i++) {
+ if (!mir_strcmp(nlhrReply->headers[i].szName, "Location")) {
+ szData = (char *)malloc(512);
+ // add "Moved/Location:" in front of the new URL for identification
+ mir_snprintf(szData, 512, "Moved/Location: %s\n", nlhrReply->headers[i].szValue);
+ break;
+ }
+ }
+ // log the new url into netlib log
+ Netlib_Log(hNetlibUser, szData);
+ }
+ }
+ // if the data does not downloaded successfully (ie. disconnected), then return 1 as error code
+ else return 1;
+
+ // make a copy of the retrieved data, then free the memory of the http reply
+ szInfo = szData;
+ Netlib_FreeHttpRequest(nlhrReply);
+
+ // the recieved data is empty, data was not recieved, so return an error code of 1
+ if (!mir_strcmp(szInfo, "")) return 1;
+ return 0;
+}
+
+//============ NETLIB INITIALIZATION ============
+
+void NetlibInit()
+{
+ NETLIBUSER nlu = {};
+ nlu.flags = NUF_OUTGOING | NUF_HTTPCONNS | NUF_NOHTTPSOPTION | NUF_UNICODE;
+ nlu.szSettingsModule = MODNAME;
+ nlu.szDescriptiveName.w = TranslateT("Non-IM Contacts");
+ hNetlibUser = Netlib_RegisterUser(&nlu);
+}
diff --git a/protocols/Non-IM Contact/src/main.cpp b/protocols/Non-IM Contact/src/main.cpp
new file mode 100644
index 0000000000..d554ddc249
--- /dev/null
+++ b/protocols/Non-IM Contact/src/main.cpp
@@ -0,0 +1,194 @@
+//=====================================================
+// Includes
+//=====================================================
+
+#include "stdafx.h"
+
+#include "Version.h"
+
+CMPlugin g_plugin;
+
+INT_PTR doubleClick(WPARAM wParam, LPARAM)
+{
+ char program[MAX_PATH], params[MAX_PATH];
+ INT_PTR shellEXEerror = 0;
+ char* proto = GetContactProto(wParam);
+ if (proto && !mir_strcmp(proto, MODNAME)) {
+ if (GetKeyState(VK_CONTROL) & 0x8000) // ctrl is pressed
+ editContact(wParam, 0); // for later when i add a second double click setting
+ else if (!db_get_static(wParam, MODNAME, "Program", program, _countof(program)) && mir_strcmp(program, "")) {
+ if (db_get_static(wParam, MODNAME, "ProgramParams", params, _countof(params)))
+ mir_strcpy(params, "");
+ if (strstr(program, "http://") || strstr(program, "https://"))
+ Utils_OpenUrl(program);
+ else
+ shellEXEerror = (INT_PTR)ShellExecuteA(nullptr, nullptr, program, params, nullptr, SW_SHOW); //ignore the warning, its M$'s backwards compatabilty screwup :)
+ if (shellEXEerror == ERROR_FILE_NOT_FOUND || shellEXEerror == ERROR_PATH_NOT_FOUND)
+ Utils_OpenUrl(program);
+ }
+ else editContact(wParam, 0);
+ return 1;
+ }
+ return 0;
+}
+
+//=====================================================
+// Definitions
+//=====================================================
+int LCStatus = ID_STATUS_OFFLINE;
+//=====================================================
+
+//=====================================================
+// Name : MainInit
+// Parameters: wparam , lparam
+// Returns : int
+// Description : Called at very beginning of plugin
+//=====================================================
+//
+int NimcOptInit(WPARAM wParam, LPARAM)
+{
+ OPTIONSDIALOGPAGE odp = {};
+ odp.pszTemplate = MAKEINTRESOURCEA(IDD_OPTIONS);
+ odp.szGroup.a = LPGEN("Plugins");
+ odp.szTitle.a = LPGEN("Non-IM Contacts");
+ odp.pfnDlgProc = DlgProcNimcOpts;
+ g_plugin.addOptions(wParam, &odp);
+ return 0;
+}
+//=====================================================
+// Name : __declspec(dllexport) PLUGININFO* MirandaPluginInfo
+// Parameters: (DWORD mirandaVersion)
+// Returns :
+// Description : Sets plugin info
+//=====================================================
+
+PLUGININFOEX pluginInfoEx = {
+ sizeof(pluginInfoEx),
+ __PLUGIN_NAME,
+ PLUGIN_MAKE_VERSION(__MAJOR_VERSION, __MINOR_VERSION, __RELEASE_NUM, __BUILD_NUM),
+ __DESCRIPTION,
+ __AUTHOR,
+ __COPYRIGHT,
+ __AUTHORWEB,
+ UNICODE_AWARE,
+ //2e0d2ae3-e123-4607-8539-d4448d675ddb
+ { 0x2e0d2ae3, 0xe123, 0x4607, {0x85, 0x39, 0xd4, 0x44, 0x8d, 0x67, 0x5d, 0xdb} }
+};
+
+CMPlugin::CMPlugin() :
+ PLUGIN<CMPlugin>(MODNAME, pluginInfoEx)
+{
+ RegisterProtocol(PROTOTYPE_VIRTUAL);
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+
+extern "C" __declspec(dllexport) const MUUID MirandaInterfaces[] = { MIID_PROTOCOL, MIID_LAST };
+
+//=====================================================
+// Name : WINAPI DllMain
+// Parameters: HINSTANCE hinst,DWORD fdwReason,LPVOID lpvReserved
+// Returns : BOOL
+// Description :
+//=====================================================
+
+int ModulesLoaded(WPARAM, LPARAM)
+{
+ NetlibInit();
+ return 0;
+}
+
+//=====================================================
+// Name : Load
+// Parameters: PLUGINLINK *link
+// Returns : int
+// Description : Called when plugin is loaded into Miranda
+//=====================================================
+
+IconItem iconList[] =
+{
+ { LPGEN("Main Icon"), MODNAME, IDI_MAIN },
+};
+
+int CMPlugin::Load()
+{
+ g_plugin.registerIcon(LPGEN("Non-IM Contact"), iconList);
+
+ HookEvent(ME_CLIST_DOUBLECLICKED, (MIRANDAHOOK)doubleClick);
+ HookEvent(ME_OPT_INITIALISE, NimcOptInit);
+ HookEvent(ME_CLIST_STATUSMODECHANGE, SetLCStatus);
+
+ // load services (the first 5 are the basic ones needed to make a new protocol)
+ CreateProtoServiceFunction(MODNAME, PS_GETCAPS, GetLCCaps);
+ CreateProtoServiceFunction(MODNAME, PS_GETNAME, GetLCName);
+ CreateProtoServiceFunction(MODNAME, PS_LOADICON, LoadLCIcon);
+ CreateProtoServiceFunction(MODNAME, PS_GETSTATUS, GetLCStatus);
+
+ CreateServiceFunction("AddLCcontact", addContact);
+ CreateServiceFunction("EditLCcontact", editContact);
+ CreateServiceFunction("LoadFilesDlg", LoadFilesDlg);
+ CreateServiceFunction("ExportLCcontacts", exportContacts);
+ CreateServiceFunction("ImportLCcontacts", ImportContacts);
+ CreateServiceFunction("TestStringReplaceLine", testStringReplacer);
+ CreateServiceFunction("NIM_Contact/DoubleClick", doubleClick);
+
+ CMenuItem mi(&g_plugin);
+ mi.root = g_plugin.addRootMenu(MO_MAIN, LPGENW("&Non-IM Contact"), 600090000);
+ Menu_ConfigureItem(mi.root, MCI_OPT_UID, "D7CE61C5-1178-41BA-B2ED-5A711BB21AE9");
+
+ SET_UID(mi, 0x73c11266, 0x153c, 0x4da4, 0x9b, 0x82, 0x5c, 0xce, 0xca, 0x86, 0xd, 0x41);
+ mi.position = 600090000;
+ mi.name.a = LPGEN("&Add Non-IM Contact");
+ mi.pszService = "AddLCcontact";
+ mi.hIcolibItem = iconList[0].hIcolib;
+ Menu_AddMainMenuItem(&mi);
+
+ SET_UID(mi, 0xa511c5e, 0x26d2, 0x41b1, 0xbd, 0xb7, 0x3e, 0x62, 0xc8, 0x44, 0x37, 0xc9);
+ mi.position = 600090001;
+ mi.name.a = LPGEN("&View/Edit Files");
+ mi.pszService = "LoadFilesDlg";
+ Menu_AddMainMenuItem(&mi);
+
+ if (g_plugin.getByte("Beta", 0)) {
+ SET_UID(mi, 0x23051356, 0xad45, 0x4101, 0x8e, 0x11, 0xf6, 0x3a, 0xe8, 0xa3, 0xa5, 0x25);
+ mi.position = 600090002;
+ mi.name.a = LPGEN("&Export all Non-IM Contacts");
+ mi.pszService = "ExportLCcontacts";
+ Menu_AddMainMenuItem(&mi);
+
+ SET_UID(mi, 0xf3c4ebed, 0x789c, 0x4293, 0xaa, 0xcb, 0x22, 0xdc, 0xd4, 0xe0, 0x3c, 0x41);
+ mi.position = 600090003;
+ mi.name.a = LPGEN("&Import Non-IM Contacts");
+ mi.pszService = "ImportLCcontacts";
+ Menu_AddMainMenuItem(&mi);
+ }
+
+ SET_UID(mi, 0xb653d5e0, 0xb1e6, 0x46fc, 0xa7, 0x82, 0x35, 0x95, 0x74, 0xb1, 0xc, 0xdd);
+ mi.position = 600090000;
+ mi.name.a = LPGEN("&String Maker");
+ mi.pszService = "TestStringReplaceLine";
+ Menu_AddMainMenuItem(&mi);
+
+ SET_UID(mi, 0x1033e16d, 0x8a7c, 0x43db, 0xa9, 0x83, 0x56, 0x2f, 0x8a, 0x16, 0x7c, 0xe9);
+ mi.root = nullptr;
+ mi.position = -2000080000;
+ mi.name.a = LPGEN("E&dit Contact Settings");
+ mi.pszService = "EditLCcontact";
+ Menu_AddContactMenuItem(&mi, MODNAME);
+
+ HookEvent(ME_SYSTEM_MODULESLOADED, ModulesLoaded);
+ return 0;
+}
+
+//=====================================================
+// Name : Unload
+// Parameters: void
+// Returns :
+// Description : Unloads plugin
+//=====================================================
+
+int CMPlugin::Unload()
+{
+ killTimer();
+ return 0;
+}
diff --git a/protocols/Non-IM Contact/src/namereplacing.cpp b/protocols/Non-IM Contact/src/namereplacing.cpp
new file mode 100644
index 0000000000..d2b43eead9
--- /dev/null
+++ b/protocols/Non-IM Contact/src/namereplacing.cpp
@@ -0,0 +1,633 @@
+#include "stdafx.h"
+
+int readFileIntoArray(int fileNumber, char *FileContents[])
+{
+ char dbSetting[20], temp[MAX_STRING_LENGTH];
+ mir_snprintf(dbSetting, "fn%d", fileNumber);
+
+ char *szVar = db_get_sa(0, MODNAME, dbSetting);
+ if (szVar == nullptr)
+ return 0;
+
+ char tszFileName[MAX_PATH];
+ if (!strncmp("http://", szVar, 7) || !strncmp("https://", szVar, 7))
+ mir_snprintf(tszFileName, "%s\\plugins\\fn%d.html", getMimDir(temp), fileNumber);
+ else
+ mir_strncpy(tszFileName, szVar, _countof(tszFileName));
+ mir_free(szVar);
+
+ FILE* file = fopen(tszFileName, "r");
+ if (file == nullptr)
+ return 0;
+
+ // read the file into the FileContents array
+ // free this array before stringReplacer() returns
+ int i;
+ for (i = 0; fgets(temp, MAX_STRING_LENGTH - 1, file); i++) {
+ if (temp[mir_strlen(temp) - 1] == '\n')
+ temp[mir_strlen(temp) - 1] = '\0';
+ else temp[mir_strlen(temp)] = '\0';
+
+ FileContents[i] = (char*)malloc(mir_strlen(temp) + 1);
+ if (FileContents[i] == nullptr) break;
+ mir_strcpy(FileContents[i], temp);
+ }
+ fclose(file);
+ return i;
+}
+
+int getNumber(const char* line)
+{
+ int i;
+ return sscanf(line, "%d", &i) == 1 ? i : -1;
+}
+
+int findWordInString(const char* line, const char* string, int* lengthOfWord, int flag) /* flag = 0 %from, flag = 1 %until */
+{
+ unsigned int i, j = 0;
+ char word[64] = "", OpenDivider[8], CloseDivider[8];
+ strncpy(OpenDivider, "(\"", sizeof(OpenDivider));
+ strncpy(CloseDivider, "\")", sizeof(CloseDivider));
+ /* get the word we r looking for */
+ if (!strncmp(string, OpenDivider, mir_strlen(OpenDivider))) {
+ for (i = 2; strncmp(&string[i], CloseDivider, mir_strlen(CloseDivider)); i++) {
+ word[j] = string[i];
+ word[++j] = '\0';
+ }
+ }
+ i = 0;
+ *lengthOfWord = (int)(mir_strlen(word) + mir_strlen(CloseDivider) + mir_strlen(OpenDivider));
+ /* find the word in the line */
+ while (i < (mir_strlen(line) - mir_strlen(word))) {
+ if (!strncmp(&line[i], word, mir_strlen(word))) {
+ if (!flag) return i + (int)mir_strlen(word); /* the next char after the word */
+ else return i; /* the char before the word */
+ }
+ i++;
+ }
+ return -1;
+}
+
+int findLine(char* FileContents[], const char* string, int linesInFile, int startLine, int *positionInOldString)
+{
+ char tmp[5];
+ int i = getNumber(&string[*positionInOldString]);
+
+ // check if blank
+ if (string[*positionInOldString] == ')')
+ return startLine;
+
+ // check if its a number
+ if (i != -1) {
+ *positionInOldString += (int)mir_strlen(_itoa(i, tmp, 10)) - 1;
+ return i;
+ }
+
+ // lastline
+ if (!strncmp(&string[*positionInOldString], "lastline(", mir_strlen("lastline("))) {
+ *positionInOldString += (int)mir_strlen("lastline(");
+ i = getNumber(&string[*positionInOldString]);
+ if (i != -1) {
+ *positionInOldString += (int)mir_strlen(_itoa(i, tmp, 10));
+ return linesInFile - (i + 1);
+ }
+
+ (*positionInOldString)++;
+ return (linesInFile - 1);
+ }
+
+ // string
+ if (string[*positionInOldString] == '\"') {
+ char string2Find[256];
+ int j = 0;
+ // get the word to find
+ for (i = (*positionInOldString + 1); strncmp(&string[i], "\")", 2); i++) {
+ string2Find[j] = string[i];
+ string2Find[++j] = '\0';
+ }
+
+ // find the word
+ for (j = startLine; j < linesInFile; j++) {
+ if (strstr(FileContents[j], string2Find)) {
+ i = j;
+ break;
+ }
+ i = -1;
+ }
+ *positionInOldString += (int)(mir_strlen(string2Find) + mir_strlen("\"\")"));
+ if (i == -1) return i;
+ // allow for a +- after the word to go up or down lines
+ if (string[*positionInOldString] == '+') {
+ *positionInOldString += 1;
+ j = getNumber(&string[*positionInOldString]);
+ if (j != -1) {
+ *positionInOldString += (int)mir_strlen(_itoa(j, tmp, 10)) - 2;
+ return i + j;
+ }
+ }
+ else if (string[*positionInOldString] == '-') {
+ *positionInOldString += 1;
+ j = getNumber(&string[*positionInOldString]);
+ if (j != -1) {
+ *positionInOldString += (int)mir_strlen(_itoa(j, tmp, 10)) - 2;
+ return i - j;
+ }
+ }
+ else {
+ *positionInOldString -= 2;
+ return i;
+ }
+ }
+ return -1;
+}
+
+int findChar(char* FileContents[], const char* string, int startLine, int *positionInOldString, int startChar, int startEnd) // 0=start, 1=end for startEnd
+{
+ char tmp[5];
+ int i = getNumber(&string[*positionInOldString]);
+ // check if its a number
+ if (i != -1) {
+ *positionInOldString += (int)mir_strlen(_itoa(i, tmp, 10)) - 1;
+ return i;
+ }
+
+ // string
+ if (string[*positionInOldString] == '\"') {
+ char string2Find[256];
+ unsigned int j = 0;
+ // get the word to find
+ for (i = (*positionInOldString + 1); strncmp(&string[i], "\")", 2); i++) {
+ string2Find[j] = string[i];
+ string2Find[++j] = '\0';
+ }
+ // find the word
+ for (j = 0; j < mir_strlen(FileContents[startLine]); j++)
+ if (!strncmp(&FileContents[startLine][j], string2Find, mir_strlen(string2Find)))
+ break;
+
+ if (j == mir_strlen(FileContents[startLine]))
+ return -1;
+
+ *positionInOldString += (int)mir_strlen(string2Find) + 1;
+ return (startEnd) ? j : j + (int)mir_strlen(string2Find);
+ }
+
+ // csv(
+ if (!strncmp(&string[*positionInOldString], "csv(", mir_strlen("csv("))) {
+ char seperator;
+ int j = 0, k = startChar;
+ *positionInOldString += (int)mir_strlen("csv(");
+ if (!strncmp(&string[*positionInOldString], "tab", 3)) {
+ *positionInOldString += 3;
+ seperator = '\t';
+ }
+ else if (!strncmp(&string[*positionInOldString], "space", 5)) {
+ *positionInOldString += 5;
+ seperator = ' ';
+ }
+ else {
+ seperator = string[*positionInOldString];
+ *positionInOldString += 1;
+ }
+ i = getNumber(&string[*positionInOldString]);
+ if (i == -1) return -1;
+ *positionInOldString += (int)mir_strlen(_itoa(i, tmp, 10));
+ while (j < i) {
+ if (FileContents[startLine][k] == '\0') break;
+ if (FileContents[startLine][k] == seperator)
+ j++;
+ k++;
+ }
+ return k;
+ }
+ return -1;
+}
+
+// do the compare("A","B","X","Y")
+void checkStringForcompare(CMStringA &str)
+{
+ if (!strstr(str, "compare(\"")) return;
+ char *A, *B, *X, *Y, *copyOfStr = NEWSTR_ALLOCA(str.c_str());
+ CMStringA tmp;
+ unsigned int i, j = 0, s = str.GetLength();
+ for (i = 0; i < s; i++) {
+ if (!strncmp(str.c_str()+i, "compare(\"", mir_strlen("compare(\""))) {
+ i += (int)mir_strlen("compare(\"");
+ A = strtok(&copyOfStr[i], "\",\"");
+ B = strtok(nullptr, "\",\"");
+ X = strtok(nullptr, "\",\"");
+ Y = strtok(nullptr, ",\")");
+ j = Y - &copyOfStr[i] + (int)mir_strlen(Y) + 1;
+ if (A && B && X && Y) {
+ if (!mir_strcmp(A, B))
+ tmp.Append(X);
+ else
+ tmp.Append(Y);
+ }
+ else tmp.Append(str.c_str()+i, j);
+ i += j;
+ }
+ else tmp.AppendChar(copyOfStr[i]);
+ }
+ str = tmp;
+}
+
+// do save("A","B") A is DBVar name, B is value
+void checkStringForSave(MCONTACT hContact, CMStringA &str)
+{
+ if (!strstr(str, "save(\"")) return;
+ char *A, *B, *copyOfStr = NEWSTR_ALLOCA(str.c_str());
+ unsigned int i, j = 0, s = str.GetLength();
+ CMStringA tmp;
+ for (i = 0; i < s; i++) {
+ if (!strncmp(str.c_str()+i, "save(\"", mir_strlen("save(\""))) {
+ i += (int)mir_strlen("save(\"");
+ A = strtok(&copyOfStr[i], "\",\"");
+ B = strtok(nullptr, ",\")");
+ j = B - &copyOfStr[i] + (int)mir_strlen(B) + 1;
+ if (A && B)
+ g_plugin.setString(hContact, A, B);
+
+ else tmp.Append(str.c_str()+i, j);
+ i += j;
+ }
+ else tmp.AppendChar(copyOfStr[i]);
+ }
+ str = tmp;
+}
+
+// do load("A") A is DBVar name
+void checkStringForLoad(MCONTACT hContact, CMStringA &str)
+{
+ if (!strstr(str, "load(\"")) return;
+ char *A, *copyOfStr = NEWSTR_ALLOCA(str.c_str());
+ unsigned int i, j = 0, s = str.GetLength();
+ CMStringA tmp;
+ for (i = 0; i < s; i++) {
+ if (!strncmp(str.c_str()+i, "load(\"", mir_strlen("load(\""))) {
+ i += (int)mir_strlen("load(\"");
+ A = strtok(&copyOfStr[i], "\")");
+ j = A - &copyOfStr[i] + (int)mir_strlen(A) + 1;
+ if (A) {
+ DBVARIANT dbv;
+ if (!db_get_s(hContact, MODNAME, A, &dbv)) {
+ tmp.Append(dbv.pszVal);
+ db_free(&dbv);
+ }
+ }
+ else tmp.Append(str.c_str()+i, j);
+ i += j;
+ }
+ else tmp.AppendChar(copyOfStr[i]);
+ }
+ str = tmp;
+}
+
+// do saveN("A","B","C","D") A is module, B is setting, c is value, D is type 0/b 1/w 2/d 3/s
+void checkStringForSaveN(CMStringA &str)
+{
+ if (!strstr(str, "saveN(\"")) return;
+ char *A, *B, *C, *D, *copyOfStr = NEWSTR_ALLOCA(str.c_str());
+ unsigned int i, j = 0, s = str.GetLength();
+ CMStringA tmp;
+ for (i = 0; i < s; i++) {
+ if (!strncmp(str.c_str()+i, "saveN(\"", mir_strlen("saveN(\""))) {
+ i += (int)mir_strlen("saveN(\"");
+ A = strtok(&copyOfStr[i], "\",\"");
+ B = strtok(nullptr, ",\"");
+ C = strtok(nullptr, ",\"");
+ D = strtok(nullptr, ",\")");
+ j = D - &copyOfStr[i] + (int)mir_strlen(D) + 1;
+ if (A && B && C && D) {
+ switch (D[0]) {
+ case '0':
+ case 'b':
+ db_set_b(0, A, B, (BYTE)atoi(C));
+ break;
+ case '1':
+ case 'w':
+ db_set_w(0, A, B, (WORD)atoi(C));
+ break;
+ case '2':
+ case 'd':
+ db_set_dw(0, A, B, (DWORD)atoi(C));
+ break;
+ case '3':
+ case 's':
+ db_set_s(0, A, B, C);
+ break;
+ }
+ }
+ else tmp.Append(str.c_str()+i, j);
+ i += j;
+ }
+ else tmp.AppendChar(copyOfStr[i]);
+ }
+ str = tmp;
+}
+
+// do loadN("A","B") A is module, B is setting
+void checkStringForLoadN(CMStringA &str)
+{
+ if (!strstr(str, "loadN(\"")) return;
+ char *copyOfStr = NEWSTR_ALLOCA(str.c_str()), temp[32];
+ unsigned int i, j = 0, s = str.GetLength();
+ CMStringA tmp;
+ for (i = 0; i < s; i++) {
+ if (!strncmp(str.c_str()+i, "loadN(\"", mir_strlen("loadN(\""))) {
+ i += (int)mir_strlen("loadN(\"");
+ char *A = strtok(&copyOfStr[i], "\",\"");
+ char *B = strtok(nullptr, ",\")");
+ if (A && B) {
+ j = B - &copyOfStr[i] + (int)mir_strlen(B) + 1;
+ DBVARIANT dbv;
+ if (!db_get(NULL, A, B, &dbv)) {
+ switch (dbv.type) {
+ case DBVT_BYTE:
+ tmp.Append(_itoa(dbv.bVal, temp, 10));
+ break;
+ case DBVT_WORD:
+ tmp.Append(_itoa(dbv.wVal, temp, 10));
+ break;
+ case DBVT_DWORD:
+ tmp.Append(_itoa(dbv.dVal, temp, 10));
+ break;
+ case DBVT_ASCIIZ:
+ tmp.Append(dbv.pszVal);
+ break;
+ }
+ db_free(&dbv);
+ }
+ }
+ else tmp.Append(str.c_str()+i, i);
+ i += j;
+ }
+ else tmp.AppendChar(copyOfStr[i]);
+ }
+ str = tmp;
+}
+
+BOOL GetLastWriteTime(HANDLE hFile, LPSTR lpszString)
+{
+ FILETIME ftCreate, ftAccess, ftWrite;
+ SYSTEMTIME stUTC, stLocal;
+
+ // Retrieve the file times for the file.
+ if (!GetFileTime(hFile, &ftCreate, &ftAccess, &ftWrite))
+ return FALSE;
+
+ // Convert the last-write time to local time.
+ FileTimeToSystemTime(&ftWrite, &stUTC);
+ SystemTimeToTzSpecificLocalTime(nullptr, &stUTC, &stLocal);
+
+ // Build a string showing the date and time.
+ wsprintfA(lpszString, "%02d/%02d/%d %02d:%02d",
+ stLocal.wDay, stLocal.wMonth, stLocal.wYear,
+ stLocal.wHour, stLocal.wMinute); //!!!!!!!!!!!!!!!
+
+ return TRUE;
+}
+
+// do lastchecked(file(X)) returns amount of chars to add to str pointer
+int lastChecked(CMStringA &szNewStr, const char *str)
+{
+ char *szPattern = "lastchecked(file(";
+ size_t cbPattern = mir_strlen(szPattern);
+
+ if (!strncmp(str, szPattern, cbPattern)) {
+ int file;
+ char tszFileName[MAX_PATH], temp[MAX_PATH], szSetting[20];
+ sscanf(&str[cbPattern], "%d", &file);
+ mir_snprintf(szSetting, "fn%d", file);
+
+ char *szVar = db_get_sa(0, MODNAME, szSetting);
+ if (szVar == nullptr)
+ return 0;
+
+ if (!strncmp("http://", szVar, 7) || !strncmp("https://", szVar, 8))
+ mir_snprintf(tszFileName, "%s\\plugins\\fn%d.html", getMimDir(temp), file);
+ else
+ mir_strncpy(tszFileName, szVar, _countof(tszFileName));
+ mir_free(szVar);
+
+ HANDLE hFile = CreateFileA(tszFileName, 0, FILE_SHARE_READ, nullptr, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, nullptr);
+ if (hFile == INVALID_HANDLE_VALUE)
+ return 0;
+
+ if (GetLastWriteTime(hFile, tszFileName)) {
+ CloseHandle(hFile);
+ szNewStr.Append(tszFileName);
+ mir_snprintf(tszFileName, "%s%d))", szPattern, file);
+ return (int)mir_strlen(tszFileName);
+ }
+ CloseHandle(hFile);
+ }
+ return 0;
+}
+
+
+// do icon(x) 0=offline, 1=online, 10=lunch
+void checkIcon(MCONTACT hContact, char* string)
+{
+ char* str = strstr(string, "icon(");
+ if (str) {
+ int icon = getNumber(str + 5);
+ if (icon >= 0)
+ g_plugin.setWord(hContact, "Status", (WORD)(ID_STATUS_OFFLINE + icon));
+ }
+}
+
+int stringReplacer(const char *oldString, CMStringA &szNewString, MCONTACT hContact)
+{
+ char var_file[8];
+ int tempInt;
+ int startLine = 0, endLine = 0, startChar = 0, endChar = 0, wholeLine = -1, linesInFile;
+ int positionInOldString = 0;
+ char *fileContents[MAXLINES] = {}, tempString[MAX_STRING_LENGTH];
+
+ // setup the variable names
+ szNewString.Empty();
+ strncpy(var_file, "file(", sizeof(var_file));
+
+ while ((positionInOldString < (int)mir_strlen(oldString)) && (oldString[positionInOldString] != '\0')) {
+ // load the file... must be first
+ if (!strncmp(&oldString[positionInOldString], var_file, mir_strlen(var_file))) {
+ positionInOldString += (int)mir_strlen(var_file);
+ // check if its a number
+ tempInt = getNumber(&oldString[positionInOldString]);
+ if (tempInt == -1) {
+ // not a number so check vars..
+ // there are none yet
+ return ERROR_NO_FILE;
+ }
+ // read the file
+ linesInFile = readFileIntoArray(tempInt, fileContents);
+ if (linesInFile == 0)
+ return ERROR_NO_FILE;
+ positionInOldString += (int)mir_strlen(_itoa(tempInt, tempString, 10)) + 1; // +1 for the closing )
+
+ // wholeline()
+ if (!strncmp(&oldString[positionInOldString], "wholeline(line(", mir_strlen("wholeline(line("))) {
+ positionInOldString += (int)mir_strlen("wholeline(line(");
+ tempInt = findLine(fileContents, oldString, linesInFile, startLine, &positionInOldString);
+ if (tempInt == -1 || !fileContents[tempInt])
+ return ERROR_NO_LINE_AFTER_VAR_F;
+ wholeLine = tempInt;
+ positionInOldString += 3; // add 2 for the )) for wholeline(line())
+ }
+
+ if (!strncmp(&oldString[positionInOldString], "start(", mir_strlen("start("))) {
+ positionInOldString += (int)mir_strlen("start(line(");
+ tempInt = findLine(fileContents, oldString, linesInFile, startLine, &positionInOldString);
+ if (tempInt == -1 || !fileContents[tempInt])
+ return ERROR_NO_LINE_AFTER_VAR_F;
+ else {
+ positionInOldString += 2;
+ startLine = tempInt;
+ if (!endChar)
+ endChar = (int)mir_strlen(fileContents[startLine]);
+ tempInt = findChar(fileContents, oldString, startLine, &positionInOldString, startChar, 0);
+ if (tempInt == -1)
+ return ERROR_NO_LINE_AFTER_VAR_F;
+ startChar = tempInt;
+ }
+ positionInOldString += 2; // add 2 for the )) for start(line())
+ }
+
+ if (!strncmp(&oldString[positionInOldString], "end(", mir_strlen("end("))) {
+ positionInOldString += (int)mir_strlen("end(line(");
+ tempInt = findLine(fileContents, oldString, linesInFile, startLine, &positionInOldString);
+ if (tempInt == -1 || !fileContents[tempInt])
+ return ERROR_NO_LINE_AFTER_VAR_F;
+
+ positionInOldString += 2;
+ endLine = tempInt;
+ tempInt = findChar(fileContents, oldString, startLine, &positionInOldString, startChar, 1);
+ if (tempInt == -1)
+ return ERROR_NO_LINE_AFTER_VAR_F;
+ endChar = tempInt;
+ positionInOldString += 2; // add 2 for the )) for end(line())
+ }
+ // check for both start() and end() otherwise, only copying 1 line
+ if (!strstr(oldString, "start(")) startLine = endLine;
+ if (!strstr(oldString, "end(")) endLine = startLine;
+
+ // after all the options copy the line across and add 2 to positionInOldString for the file(print(....))
+ if (wholeLine >= 0)
+ szNewString.Append(fileContents[wholeLine]);
+ else {
+ // only copying from 1 line
+ if (startLine == endLine)
+ szNewString.Append(&fileContents[startLine][startChar], endChar - startChar);
+ else {
+ // copy the whole first line from startChar
+ szNewString.Append(&fileContents[startLine][startChar]);
+
+ // copy the middle lines across
+ for (int i = (startLine + 1); i < endLine; i++)
+ szNewString.Append(fileContents[i]);
+
+ // copy the last line untill endChar
+ szNewString.Append(fileContents[endLine], endChar);
+ }
+ }
+ }
+ // filename()
+ else if (!strncmp(&oldString[positionInOldString], "filename(", mir_strlen("filename("))) {
+ positionInOldString += (int)mir_strlen("filename(");
+ tempInt = getNumber(&oldString[positionInOldString]);
+ if (tempInt == -1)
+ return ERROR_NO_FILE;
+
+ mir_snprintf(tempString, "fn%d", tempInt);
+ if (db_get_static(NULL, MODNAME, tempString, tempString, _countof(tempString)))
+ return ERROR_NO_FILE;
+
+ szNewString.Append(tempString);
+ positionInOldString += (int)mir_strlen(_itoa(tempInt, tempString, 10)) + 1;
+ }
+ // lastchecked(file(X))
+ else if (!strncmp(&oldString[positionInOldString], "lastchecked(file(", mir_strlen("lastchecked(file("))) {
+ positionInOldString += lastChecked(szNewString, &oldString[positionInOldString]);
+ }
+ else {
+ szNewString.Append(&oldString[positionInOldString], 1);
+ positionInOldString++;
+ }
+ }
+ // free the file strings
+ for (tempInt = 0; (tempInt < MAXLINES) && (fileContents[tempInt] != nullptr); tempInt++)
+ free(fileContents[tempInt]);
+
+ // check for load("A","B")
+ checkStringForLoad(hContact, szNewString);
+ // and loadN(...)
+ checkStringForLoadN(szNewString);
+ // check for compare("A","B","X","Y")
+ checkStringForcompare(szNewString);
+ // check for save("A","B")
+ checkStringForSave(hContact, szNewString);
+ // and saveN(...)
+ checkStringForSaveN(szNewString);
+ return 1;
+}
+
+void WriteSetting(MCONTACT hContact, char* module1, char* setting1, char* module2, char* setting2)
+{
+ CMStringA newString;
+ char text[MAX_STRING_LENGTH];
+ int error = 0, status = GetLCStatus(0, 0);
+ if (!db_get_static(hContact, module1, setting1, text, _countof(text))) {
+ switch (stringReplacer(text, newString, hContact)) {
+ case ERROR_NO_LINE_AFTER_VAR_F:
+ newString.Format(Translate("%s - ERROR: no line specified or line not found (in %s)"), text, setting1);
+ error = 1;
+ break;
+ case ERROR_LINE_NOT_READ:
+ newString.Format(Translate("%s - ERROR: file couldn't be opened (in %s)"), text, setting1);
+ error = 1;
+ break;
+ case ERROR_NO_FILE:
+ newString.Format(Translate("%s - ERROR: no file specified in settings (in %s)"), text, setting1);
+ error = 1;
+ break;
+ default:
+ error = 0;
+ break;
+ }
+ // strip the tab and new lines from all except the tooltip
+ if (!error && mir_strcmp(setting1, "ToolTip"))
+ newString.TrimRight();
+ db_set_s(hContact, module2, setting2, newString);
+ }
+ else db_set_s(hContact, module2, setting2, "");
+
+ if (!error) {
+ if ((status == ID_STATUS_ONLINE) || (status == ID_STATUS_AWAY) ||
+ (status == g_plugin.getWord(hContact, "Icon", ID_STATUS_ONLINE)) ||
+ g_plugin.getByte(hContact, "AlwaysVisible", 0))
+ g_plugin.setWord(hContact, "Status", (WORD)g_plugin.getWord(hContact, "Icon", ID_STATUS_ONLINE));
+ else
+ g_plugin.setWord(hContact, "Status", ID_STATUS_OFFLINE);
+ }
+ else g_plugin.setWord(hContact, "Status", ID_STATUS_OFFLINE);
+}
+
+void replaceAllStrings(MCONTACT hContact)
+{
+ WriteSetting(hContact, MODNAME, "Name", MODNAME, "Nick");
+ WriteSetting(hContact, MODNAME, "ProgramString", MODNAME, "Program");
+ WriteSetting(hContact, MODNAME, "ProgramParamsString", MODNAME, "ProgramParams");
+ /* tooltips*/
+ WriteSetting(hContact, MODNAME, "ToolTip", "UserInfo", "MyNotes");
+
+ char tmp1[256], tmp2[256], tmp3[256];
+ if (db_get_static(hContact, MODNAME, "Program", tmp1, _countof(tmp1)))
+ db_set_s(hContact, "UserInfo", "FirstName", "");
+ else if (db_get_static(hContact, MODNAME, "ProgramParams", tmp2, _countof(tmp2)))
+ db_set_s(hContact, "UserInfo", "FirstName", tmp1);
+ else {
+ mir_snprintf(tmp3, "%s %s", tmp1, tmp2);
+ db_set_s(hContact, "UserInfo", "FirstName", tmp3);
+ }
+}
diff --git a/protocols/Non-IM Contact/src/resource.h b/protocols/Non-IM Contact/src/resource.h
new file mode 100644
index 0000000000..8ce9860106
--- /dev/null
+++ b/protocols/Non-IM Contact/src/resource.h
@@ -0,0 +1,76 @@
+//{{NO_DEPENDENCIES}}
+// Microsoft Developer Studio generated include file.
+// Used by resource.rc
+//
+#define IDD_ADD_FILE 101
+#define IDI_MAIN 103
+#define IDD_CONTACT_INFO 104
+#define IDD_OTHER_STUFF 105
+#define IDI_ICON1 106
+#define IDD_CONTACT_COPYEXPORT 108
+#define IDD_OPTIONS 109
+#define IDD_TEST_LINE 110
+#define IDD_HELP 111
+#define IDC_FN 1000
+#define IDC_FILE_LIST 1001
+#define IDC_ADD_FILE 1002
+#define IDC_ADD_FILE2 1003
+#define IDC_DEL_FILE 1004
+#define IDC_FILE_CONTENTS 1005
+#define IDC_URL 1006
+#define IDC_ADD_URL 1007
+#define IDC_DISPLAY_NAME 1007
+#define IDC_TOOLTIP 1008
+#define IDC_GROUP 1008
+#define IDC_HELPMSG 1009
+#define IDC_LINK 1010
+#define IDC_PARAMS 1011
+#define IDC_OPEN_FILE 1012
+#define IDC_OPEN_FOLDER 1013
+#define CHK_USE_TIMER 1016
+#define IDC_TIMER 1017
+#define IDC_MINUTES 1018
+#define IDC_SECONDS 1019
+#define CHK_CTRL 1020
+#define IDC_WWW_TIMER 1022
+#define IDC_STRING_REPLACE 1025
+#define IDC_DOIT 1026
+#define IDC_EXPORT 1027
+#define IDC_ALWAYS_VISIBLE 1028
+#define IDC_VISIBLE_UNLESS_OFFLINE 1029
+#define IDC_DISABLETIMER 1031
+#define IDC_TIMER_INT 1036
+#define IDC_AWAYISNOTONLINE 1037
+#define IDC_TIMER_TEXT 1039
+#define IDC_TIMER_MSG 1040
+#define IDC_STRING 1041
+#define IDC_ANSWER 1042
+#define IDC_LINE 1043
+#define IDC_START 1045
+#define IDC_END 1046
+#define IDC_WHOLELINE 1047
+#define IDC_CSV 1048
+#define IDC_FILE 1049
+#define IDC_FILENAME 1050
+#define IDC_TIMER_INTERVAL_MSG 1053
+#define IDC_HELPTEXT 1055
+#define CHK_ONLINE 40072
+#define CHK_AWAY 40073
+#define CHK_DND 40074
+#define CHK_NA 40075
+#define CHK_OCC 40076
+#define CHK_FFC 40077
+#define CHK_INVISIBLE 40078
+#define CHK_PHONE 40079
+#define CHK_LUNCH 40080
+
+// Next default values for new objects
+//
+#ifdef APSTUDIO_INVOKED
+#ifndef APSTUDIO_READONLY_SYMBOLS
+#define _APS_NEXT_RESOURCE_VALUE 112
+#define _APS_NEXT_COMMAND_VALUE 40001
+#define _APS_NEXT_CONTROL_VALUE 1057
+#define _APS_NEXT_SYMED_VALUE 101
+#endif
+#endif
diff --git a/protocols/Non-IM Contact/src/services.cpp b/protocols/Non-IM Contact/src/services.cpp
new file mode 100644
index 0000000000..e1b3278b84
--- /dev/null
+++ b/protocols/Non-IM Contact/src/services.cpp
@@ -0,0 +1,112 @@
+#include "stdafx.h"
+
+//=======================================================
+// GetCaps
+//=======================================================
+//
+INT_PTR GetLCCaps(WPARAM wParam, LPARAM)
+{
+ if (wParam == PFLAGNUM_1)
+ return 0;
+ if (wParam == PFLAGNUM_2)
+ return PF2_ONLINE | PF2_LONGAWAY | PF2_SHORTAWAY | PF2_LIGHTDND | PF2_HEAVYDND | PF2_FREECHAT | PF2_INVISIBLE | PF2_OUTTOLUNCH | PF2_ONTHEPHONE; // add the possible statuses here.
+ if (wParam == PFLAGNUM_3)
+ return 0;
+ return 0;
+}
+
+//=======================================================
+// GetName
+//=======================================================
+//
+INT_PTR GetLCName(WPARAM wParam, LPARAM lParam)
+{
+ mir_strncpy((char*)lParam, MODNAME, wParam);
+ return 0;
+}
+
+//=======================================================
+// BPLoadIcon
+//=======================================================
+//
+INT_PTR LoadLCIcon(WPARAM wParam, LPARAM)
+{
+ if (LOWORD(wParam) == PLI_PROTOCOL) {
+ if (wParam & PLIF_ICOLIBHANDLE)
+ return (INT_PTR)iconList[0].hIcolib;
+
+ HICON hIcon = IcoLib_GetIconByHandle(iconList[0].hIcolib, (wParam & PLIF_SMALL) == 0);
+ if (wParam & PLIF_ICOLIB)
+ return (INT_PTR)hIcon;
+
+ HICON hIcon2 = CopyIcon(hIcon);
+ IcoLib_ReleaseIcon(hIcon);
+ return (INT_PTR)hIcon2;
+ }
+
+ return NULL;
+}
+
+//=======================================================
+// SetFStatus
+//=======================================================
+//
+int SetLCStatus(WPARAM wParam, LPARAM)
+{
+ int oldStatus = LCStatus;
+ LCStatus = wParam;
+ g_plugin.setWord("Status", (WORD)wParam);
+ g_plugin.setWord("timerCount", 0);
+ if (LCStatus == ID_STATUS_OFFLINE || (LCStatus == ID_STATUS_AWAY && !g_plugin.getByte("AwayAsStatus", 0)) || !g_plugin.getWord("Timer", 1))
+ killTimer();
+ else if (g_plugin.getWord("Timer", 1))
+ startTimer(TIMER);
+
+ for (auto &hContact : Contacts(MODNAME)) {
+ if (LCStatus != ID_STATUS_OFFLINE)
+ replaceAllStrings(hContact);
+
+ switch (LCStatus) {
+ case ID_STATUS_OFFLINE:
+ if (g_plugin.getByte(hContact, "AlwaysVisible", 0) && !g_plugin.getByte(hContact, "VisibleUnlessOffline", 1))
+ g_plugin.setWord(hContact, "Status", (WORD)g_plugin.getWord(hContact, "Icon", ID_STATUS_ONLINE));
+ else
+ g_plugin.setWord(hContact, "Status", ID_STATUS_OFFLINE);
+ break;
+
+ case ID_STATUS_ONLINE:
+ g_plugin.setWord(hContact, "Status", (WORD)g_plugin.getWord(hContact, "Icon", ID_STATUS_ONLINE));
+ break;
+
+ case ID_STATUS_AWAY:
+ if (g_plugin.getByte("AwayAsStatus", 0) && (g_plugin.getByte(hContact, "AlwaysVisible", 0) || (g_plugin.getWord(hContact, "Icon", ID_STATUS_ONLINE) == ID_STATUS_AWAY)))
+ g_plugin.setWord(hContact, "Status", (WORD)g_plugin.getWord(hContact, "Icon", ID_STATUS_ONLINE));
+ else if (!g_plugin.getByte("AwayAsStatus", 0))
+ g_plugin.setWord(hContact, "Status", (WORD)g_plugin.getWord(hContact, "Icon", ID_STATUS_ONLINE));
+ else
+ g_plugin.setWord(hContact, "Status", ID_STATUS_OFFLINE);
+ break;
+
+ default:
+ if (g_plugin.getByte(hContact, "AlwaysVisible", 0) || LCStatus == g_plugin.getWord(hContact, "Icon", ID_STATUS_ONLINE))
+ g_plugin.setWord(hContact, "Status", (WORD)g_plugin.getWord(hContact, "Icon", ID_STATUS_ONLINE));
+ break;
+ }
+ }
+
+ ProtoBroadcastAck(MODNAME, NULL, ACKTYPE_STATUS, ACKRESULT_SUCCESS, (HANDLE)oldStatus, wParam);
+ return 0;
+}
+
+//=======================================================
+// GetStatus
+//=======================================================
+//
+INT_PTR GetLCStatus(WPARAM, LPARAM)
+{
+ if ((LCStatus >= ID_STATUS_ONLINE) && (LCStatus <= ID_STATUS_OUTTOLUNCH))
+ return LCStatus;
+ else
+ return ID_STATUS_OFFLINE;
+}
+
diff --git a/protocols/Non-IM Contact/src/stdafx.cxx b/protocols/Non-IM Contact/src/stdafx.cxx
new file mode 100644
index 0000000000..1b563fc866
--- /dev/null
+++ b/protocols/Non-IM Contact/src/stdafx.cxx
@@ -0,0 +1,18 @@
+/*
+Copyright (C) 2012-19 Miranda NG team (https://miranda-ng.org)
+
+This program is free software; you can redistribute it and/or
+modify it under the terms of the GNU General Public License
+as published by the Free Software Foundation version 2
+of the License.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "stdafx.h" \ No newline at end of file
diff --git a/protocols/Non-IM Contact/src/stdafx.h b/protocols/Non-IM Contact/src/stdafx.h
new file mode 100644
index 0000000000..e0d30707fe
--- /dev/null
+++ b/protocols/Non-IM Contact/src/stdafx.h
@@ -0,0 +1,130 @@
+//=====================================================
+// Includes (yea why not include lots of stuff :p )
+//=====================================================
+#ifndef COMMONHEADERS
+#define COMMONHEADERS
+
+#include <windows.h>
+#include <commctrl.h>
+#include <winsock.h>
+#include <shlobj.h>
+
+#include <malloc.h>
+#include <stdio.h>
+#include <time.h>
+#include <stddef.h>
+#include <process.h>
+#include <string.h>
+
+struct DLGTEMPLATEEX
+{
+ WORD dlgVer;
+ WORD signature;
+ DWORD helpID;
+ DWORD exStyle;
+ DWORD style;
+ WORD cDlgItems;
+ short x;
+ short y;
+ short cx;
+ short cy;
+};
+
+#include <newpluginapi.h>
+#include <m_clistint.h>
+#include <m_skin.h>
+#include <m_langpack.h>
+#include <m_database.h>
+#include <m_system.h>
+#include <m_icolib.h>
+#include <m_protocols.h>
+#include <m_userinfo.h>
+#include <m_options.h>
+#include <m_protosvc.h>
+#include <m_utils.h>
+#include <m_ignore.h>
+#include <m_netlib.h>
+#include <win2k.h>
+
+#include "resource.h"
+
+//=======================================================
+// Definitions
+//=======================================================
+#define MODNAME "NIM_Contact"
+#define modFullname "Non-IM Contact"
+#define MAXLINES 10000
+#define MAX_STRING_LENGTH 10000
+#define LINE_LENGTH 10000
+#define msg(a,b) MessageBoxA(0,a,b,MB_OK);
+#define TIMER (g_plugin.getWord("Timer", 1) * 1000)
+
+/* ERROR VALUES */
+#define ERROR_NO_LINE_AFTER_VAR_F -1
+#define ERROR_LINE_NOT_READ -2
+#define ERROR_NO_FILE -3
+
+//=======================================================
+// Defines
+//=======================================================
+// General
+
+extern int LCStatus;
+extern IconItem iconList[];
+
+// Services.c
+INT_PTR GetLCCaps(WPARAM wParam,LPARAM lParam);
+INT_PTR GetLCName(WPARAM wParam,LPARAM lParam);
+INT_PTR LoadLCIcon(WPARAM wParam,LPARAM lParam);
+int SetLCStatus(WPARAM wParam,LPARAM lParam);
+INT_PTR GetLCStatus(WPARAM wParam,LPARAM lParam);
+
+// dialog.c
+INT_PTR addContact(WPARAM wParam,LPARAM lParam) ;
+INT_PTR editContact(WPARAM wParam,LPARAM lParam);
+INT_PTR CALLBACK DlgProcNimcOpts(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam);
+INT_PTR testStringReplacer(WPARAM wParam, LPARAM lParam);
+INT_PTR LoadFilesDlg(WPARAM wParam, LPARAM lParam);
+
+
+// files.c
+int Openfile(char* outputFile, int saveOpen);
+INT_PTR CALLBACK DlgProcFiles(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam);
+int savehtml(char* outFile);
+char* getMimDir(char* file);
+INT_PTR exportContacts(WPARAM wParam,LPARAM lParam) ;
+
+// contactinfo.c
+INT_PTR CALLBACK DlgProcContactInfo(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam);
+INT_PTR CALLBACK DlgProcOtherStuff(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam);
+INT_PTR CALLBACK DlgProcCopy(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam);
+void ExportContact(MCONTACT hContact);
+INT_PTR ImportContacts(WPARAM wParam, LPARAM lParam);
+
+// stringreplacer.c
+int stringReplacer(const char *oldString, CMStringA &szNewString, MCONTACT hContact);
+void replaceAllStrings(MCONTACT hContact);
+void WriteSetting(MCONTACT hContact, char* module1, char* setting1 , char* module12, char* setting2);
+
+//timer.c
+int startTimer(int interval);
+int killTimer();
+
+// http.c
+void NetlibInit();
+int InternetDownloadFile (char *szUrl);
+extern char *szInfo;
+extern char *szData;
+extern HNETLIBUSER hNetlibUser;
+
+struct CMPlugin : public PLUGIN<CMPlugin>
+{
+ CMPlugin();
+
+ int Load() override;
+ int Unload() override;
+};
+
+#endif
+
+#pragma comment(lib,"comctl32.lib")
diff --git a/protocols/Non-IM Contact/src/timer.cpp b/protocols/Non-IM Contact/src/timer.cpp
new file mode 100644
index 0000000000..c0c292dcc9
--- /dev/null
+++ b/protocols/Non-IM Contact/src/timer.cpp
@@ -0,0 +1,85 @@
+#include "stdafx.h"
+
+static UINT_PTR timerId = 0;
+
+//=====================================================
+// Name : timerProc
+// Parameters: none
+// Returns : void
+// Description : called when the timer interval occurs
+//=====================================================
+//
+void timerFunc(void*)
+{
+ char text[512], fn[16], szFileName[MAX_PATH], temp[MAX_PATH];
+
+ int timerCount = g_plugin.getWord("timerCount", 1) + 1;
+
+ if (LCStatus == ID_STATUS_OFFLINE) {
+ killTimer();
+ return;
+ }
+ g_plugin.setWord("timerCount", (WORD)timerCount);
+
+ /* update the web pages*/
+ for (int i = 0;; i++) {
+ mir_snprintf(fn, "fn%d", i);
+ if (db_get_static(NULL, MODNAME, fn, text, _countof(text)))
+ break;
+
+ if (!strncmp("http://", text, mir_strlen("http://")) || !strncmp("https://", text, mir_strlen("https://"))) {
+ mir_snprintf(fn, "fn%d_timer", i);
+ int timer = g_plugin.getWord(fn, 60);
+ if (timer && !(timerCount % timer)) {
+ if (!InternetDownloadFile(text)) {
+ mir_snprintf(szFileName, "%s\\plugins\\fn%d.html", getMimDir(temp), i);
+ savehtml(szFileName);
+ }
+ }
+ }
+ }
+
+ /* update all the contacts */
+ for (auto &hContact : Contacts(MODNAME)) {
+ int timer = g_plugin.getWord(hContact, "Timer", 15);
+ if (timer && !(timerCount % timer))
+ if (!db_get_static(hContact, MODNAME, "Name", text, _countof(text)))
+ replaceAllStrings(hContact);
+ }
+}
+
+void CALLBACK timerProc(HWND, UINT, UINT_PTR, DWORD)
+{
+ // new thread for the timer...
+ mir_forkthread(timerFunc);
+}
+
+//=====================================================
+// Name : startTimer
+// Parameters: int interval
+// Returns : int
+// Description : starts the timer
+//=====================================================
+//
+int startTimer(int interval)
+{
+ timerId = SetTimer(nullptr, 0, interval, timerProc);
+ return 0;
+}
+
+//=====================================================
+// Name : killTimer
+// Parameters: none
+// Returns : int
+// Description : stops the timer
+//=====================================================
+//
+int killTimer()
+{
+ if (timerId != 0) {
+ g_plugin.setWord("timerCount", 0);
+ KillTimer(nullptr, timerId);
+ timerId = 0;
+ }
+ return 0;
+}
diff --git a/protocols/Non-IM Contact/src/version.h b/protocols/Non-IM Contact/src/version.h
new file mode 100644
index 0000000000..d8bf664b36
--- /dev/null
+++ b/protocols/Non-IM Contact/src/version.h
@@ -0,0 +1,13 @@
+#define __MAJOR_VERSION 0
+#define __MINOR_VERSION 6
+#define __RELEASE_NUM 0
+#define __BUILD_NUM 3
+
+#include <stdver.h>
+
+#define __PLUGIN_NAME "Non-IM Contact"
+#define __FILENAME "NimContact.dll"
+#define __DESCRIPTION "Non-IM Contact allows you to add 'contacts' that can act as shortcuts to other programs, or links to web pages.\r\nThe contacts name can be read from a text file (includes any ASCII file).\r\nThis plugin is a combination of Favorites and Text Reader plugins both made by me)"
+#define __AUTHOR "Jonathan Gordon"
+#define __AUTHORWEB "https://miranda-ng.org/p/NimContact/"
+#define __COPYRIGHT "© 2003-2004 Jonathan Gordon, jdgordy@gmail.com"
diff --git a/protocols/Weather/docs/history.txt b/protocols/Weather/docs/history.txt
new file mode 100644
index 0000000000..bf3351da1d
--- /dev/null
+++ b/protocols/Weather/docs/history.txt
@@ -0,0 +1,930 @@
+Weather Protocol - Version History
+==================================
+Version 0.3.8.19 2011/09/03
+ - Fixed Brief window update on weather station update
+ - Fixed No ini window no show
+
+Version 0.3.8.18 2010/08/20
+ - Specialized translations for all weather conditions
+ - Fixed possible crashes
+
+Version 0.3.8.17 2010/05/29
+ - Added possibility to add specialized translations for weather conditions
+ format: #condition Weather
+ - Added 32x32 icon support
+ - 32x32 icon is used in a frame in a frame if no avatar present
+ - Added support for Miranda 0.9 persistent http trasactions
+ - Changed Breif dialog appearence
+ - Fixed translation issues
+ - Fixed keyborad navigation in UserInfo dialog
+ - Requires Miranda 0.8 or higher
+
+Version 0.3.8.16 2009/08/09
+ - Increased allowed size of station id
+ - Removed built-in support for HTTP compression (compression not supported with pre 0.8 Miranda any longer)
+ - Fixed crash with no ini files
+ - x64 port
+
+Version 0.3.8.15 2009/03/22
+ - Added support for gif avatars
+ - Added support for 4 urls per ini
+ - Added supoort for html metadata (utf8)
+ - Fixed rounding with fractional reading display
+ - Added more http redirection support
+ - Allow to draw forced avatar in frame
+
+Version 0.3.8.14 2009/01/10
+ - Fixed Set Data failures
+ - Fixed crashes with http
+ - Fixed http errors processing
+ - Added support for temperature in format -<space><number>
+
+Version 0.3.8.13 2008/12/25
+ - Changed search UI to have more descriptive labels
+ - Documentation updates
+
+Version 0.3.8.12 2008/12/22
+ - Added support for cookies (cakes and ice cream)
+
+Version 0.3.8.10 2008/12/07
+ - Fixed temperature display
+
+Version 0.3.8.9 2008/12/06
+ - Added support for deflate compressed http streams
+ - Fixes for weather crashes
+ - Added option to round all values to nearest integer
+
+Version 0.3.8.8 2008/11/22
+ - Improved formatting for numerical values
+ - Fixed crashes due to compressed http stream
+ - Added support for gzip encoded http stream
+
+Version 0.3.8.7 2008/08/02
+ - Fixed crash for people measuring speed in km/h
+
+Version 0.3.8.6 2008/08/01
+ - Added display fraction of temperature and wind speed when available
+ - Added handling of UTF8 pages (needed for GisMeteo)
+
+Version 0.3.8.5 2008/07/27
+ - Fixed option dialog layout
+ - Fixed ini version display
+ - Fixed memory leak with multiurl ini
+ - Fixed plugin version number
+
+Version 0.3.8.3 2008/07/24
+ - Fixed url tag
+ - Added headers to variable view
+ - Fixed options dialog layout
+
+Version 0.3.8.2 2008/06/08
+ - Fixed ini version display in User Info
+ - Fixes for wind in Weather Underground ini to work correctly
+
+Version 0.3.8.1 2008/05/25
+ - Added ability to parse upto 3 URL per ini file for weather data
+ - Fixed break data and parameters with units
+ - Added ability to skin weather frame with clist_modern ("Main,ID=WeatherFrame")
+ - Added display "nickname" in the first line of the frame
+ - Added avatar display in the weather frame
+
+Version 0.3.7.2 2008/01/19
+ - Fixed updates in normal mode
+ - Fixed option dialog layout
+
+Version 0.3.7.1 2007/12/22
+ - Partial workaround for core HTTP problem
+ - Tabbed option dialog
+
+Version 0.3.7.0 2007/12/21
+ - Added icolib support
+ - Added frames support
+ - New icons by Angeli-Ka
+ - Compatible with Miranda 0.7 and later
+
+Version 0.3.6.5 2007/08/17
+ - Workaround for tray icon
+
+Version 0.3.6.4 2007/07/27
+ - Fixed caching problems
+
+Version 0.3.6.3 2007/07/08
+ - Fixed error message at stratup (with updater)
+ - Increased possible weather variable size
+ - More generic couldy definition
+
+Version 0.3.6.2 2007/06/02
+ - More sensible autoupdate Enable/Disable operation
+
+Version 0.3.6.1 2007/06/01
+ - Fixed popup click action
+ - Fixed translation
+
+Version 0.3.6.0 2007/05/18
+ - New icons by Angeli-Ka
+ - Protocol icons split into separate dll
+ - Option dialog and menus redesign
+ - Instant avatar update
+ - Ini file display name now used as client ID (MirVer)
+ - Moved ini file list into View/Change My Details
+ - Support for new plugin interface
+ - Fixed few parsing issues
+
+Version 0.3.5.19 2007/01/27
+ - Fixed translation
+
+Version 0.3.5.18 2007/01/26
+ - Fixed translation
+ - Fixed resource leaks
+ - Fixed crash
+ - Partial unicode support
+
+Version 0.3.5.17 2007/01/20
+ - Reduced GDI resource utilization
+ - Fixed memory leak with old ini files
+ - Fixed search function for stations with special characters
+
+Version 0.3.5.16 2006/11/27
+ - Fixed units conversion
+ - Fixed memory corruption
+ - Added ability to show clickable links in Brief window
+
+Version 0.3.5.15 2006/11/16
+ - Fixed web page parsing (Wind Speed in Yahoo)
+ - Fixed "No wind" condition handling
+ - Performance improvments for HTTP transfers
+ - Fixed memory corruption
+
+Version 0.3.5.14 2006/10/31
+ - Fixed status message operation
+
+Version 0.3.5.13 2006/10/29
+ - Fixed non english alphabets operation
+ - Fixed Weather condition update issues
+ - Added option to keep station status from reflecting weather condition
+ (should resolve avatar overlay problems with clist modern)
+ - Moved Weather main menu entry into the protocol group
+ - Improvements for forecast window sizing
+
+Version 0.3.5.12 2006/07/23
+ - Fixed non english alphabets operation
+
+Version 0.3.5.11 2006/07/22
+ - Fixed text corruption
+ - Added ability to display avatars for each weather condition
+ - Fixed Win95 operation
+
+Version 0.3.5.10 2006/07/16
+ - Changed Current Date/Time display (%d) according to locale
+ - Changed handling of HTTP redirect requests
+
+Version 0.3.5.9 2006/04/08
+ - Fixed misplaced buttons on forecast view window
+ - Fixed weather history incorrect source
+ - Fixed incorrect PopUp notification text in the menu
+
+Version 0.3.5.8 2005/09/20
+ - Fixed automatic set of deafult station logic failure and as a result crash at power-up
+ - Fixed INI info dialog layout and ini version information
+ - Fixed rare crash on exit
+ - Fixed resource leak
+ - Fixed few memory leaks
+ - Fixed crash at power-up with corrupted ini file
+ - A lot of code robustness updates
+
+Version 0.3.5.7 2005/09/18
+ - Fixed few resource leaks
+ - Fixed gloabal status
+ - Fixed weather alert format
+ - Fixed very rare crash on exit
+
+Version 0.3.5.6 2005/09/14
+ - Fixed few crashes on exit and
+ - A lot of code robustness updates
+ - Updater compatibility
+ - Fixed resource leaks
+
+Version 0.3.5.5 2005/09/11
+ - Fixed crash on exit
+ - Support for custom "Status Messages"
+
+Version 0.3.5.4 2005/09/08
+ - Fixed crash in my User details
+ - Fixed endless "updating user info ..."
+ - Fixed search function regression
+
+Version 0.3.5.3 2005/09/07
+ - Fixed crash at Powerup
+ - Fixed crash on Miranda exit
+ - Fixed numerous other crashes
+ - Fixed numerous memory leaks
+ - Fixed memory corruption
+ - Fixed resource leak
+
+Version 0.3.5.2 2005/09/07
+ - Fixed crash on Miranda exit
+ - Fixed numerous other crashes
+ - Fixed numerous memory leaks
+ - Fixed memory corruption
+ - Fixed resource leak
+
+Version 0.3.5.0 2005/03/21
+ - New Option: Disable update on startup
+ - New Option: Enable/Disable popups by type: update, alert, error
+ - INI Option: Support breaking string
+ - INI Option: Support hidden fields
+ - INI Option: Support icon assignment from ini
+ - Updated sample_ini.ini and translation
+ - Some other minor changes that I can't remember
+
+Version 0.3.4.4 2004/12/28
+ - Load window list correctly, fix problem with brief info and edit dlg not showing
+ - Some internal changes with new service functions
+
+Version 0.3.4.3 2004/12/26
+ - Minor change in INI loading
+
+Version 0.3.4.2 Beta 2004/12/16
+ - Bug fix: Miranda cannot quit after forkthread is used
+ - Bug fix: The unit % does not work anymore
+ - Bug fix: No longer crash when the link settings is not set
+ - Update the weather ini download link to the new location
+
+Version 0.3.4.1 Beta 2004/12/09
+ - ESC now works in weather dialogs
+ - More changes to forkthread
+ - Document updated: weather-translation, sample_ini
+
+Version 0.3.4.0 Beta 2004/11/21
+ - Change the threading to forkthread
+ - New option: Custom status when condition is unavailable
+ - New option: Convert day/month string into 2 char or 3 char format
+ - Some internal changes
+ - Minor change in ini format
+
+Version 0.3.3.17 2004/11/19
+ - Condition translated correctly when writing into database
+ - Correctly restore the windows position for edit setting dialog
+
+Version 0.3.3.16 2004/11/10
+
+Version 0.3.3.15 2004/10/21
+ - Remember the window position for edit settings dialog
+ - Minor change in dialog (I still can't get the close on ESC to work...)
+
+Version 0.3.3.14 Beta 2004/10/20
+ - Fix the crash in option page bug (hopefully)
+ - Fix the support for \n in text input
+ - Minor change in dialog
+
+Version 0.3.3.13 2004/10/16
+ - Another fix for default station
+ - Some changes to reduce database read/write for default station changes
+ - Now the plugin is correctly registered in known module list for DBEditor++
+ - Save the setting for popup and update enable/disable directly after menu click
+ - Some update in readme, more changes in translation (thanks smyle again)
+
+Version 0.3.3.12 2004/10/16
+ - Fix 2 possible crashes regarding default station
+
+Version 0.3.3.11 2004/10/15
+ - Fix a bug with global status
+ - Updated translation list (thanks smyle)
+
+Version 0.3.3.10 2004/10/14
+ - Changes in default station handling, hopefully will fix a crash in option page
+ - Add new sound event: Weather alert
+ - Add new menu item: Add new weather station (call up the find/add dialog)
+ - Document updated: weather_translation.txt
+
+Version 0.3.3.9 2004/09/26
+ - Some changes in code.
+
+Version 0.3.3.8 2004/09/24
+ - Now uses default system text for brief info and setup dialog.
+
+Version 0.3.3.7 (Beta)
+ - Test releases for crash in option page
+
+Version 0.3.3.6 2004/09/24
+ - Add a sound event when weather condition is updated
+ - Use the default system color for brief info and setup dialog
+ - Minor change in unit conversion
+ - Fix in brief info when there is no data for current conditions
+ - Add entry to Database Editor++ known module
+
+Version 0.3.3.5 2004/08/14
+ - Fix apply button in option pages
+ - Fix "Humidity" in default settings
+ - Ignore the sample ini file if it is placed in plugin\weather dir
+ - Minor changes in update timer and option dialog
+
+Version 0.3.3.4 (Beta) 2004/07/23
+ - Fix some bug in text option
+ - Take proto_weather.dll icon into account when auto-assigning icon
+ - Option to disable automatic icon assignment
+ - Few minor changes
+ - Document updated: weather_translation.txt
+
+Version 0.3.3.3 2004/07/21
+ - Automatically set to default weather icon if no custom one is set
+ - Add a ini setup information dialog to help setup weather protocol
+ - Update in brief info now retrieve new data from the internet
+ - Few minor changes
+ - Document updated: weather_translation.txt
+
+Version 0.3.3.2 (Beta) 2004/07/14
+ - Show error detail on update errors
+ - Includes simple set of 16-colors weather icons in the dll file
+ - Option to disable italic display for station with alert issued
+ - Option to disable warning dialog if ini is not found at startup
+ - Attempt to fix the black bar bug in brief info
+ - Fix the bug that shows connecting as weather status
+ - Document updated: weather_translation.txt
+
+Version 0.3.3.1 2004/06/19
+ - Minor change in the brief info dialog
+ - More info items are now translatable
+ - Case conversion in condition to make them translatable (use unit: Cond)
+ - Save window size for the brief info dialog
+ - Fix crash when invalid ID or ini file for the station is not found
+ - Few minor changes
+ - Document updated: sample_ini
+
+Version 0.3.3.0 (Beta) 2004/06/12
+ - A new feature that erase old data while updating for new data
+ - A change in the brief information dialog (thanks micron-x for last seen plugin)
+ - Double click a contact shows brief info dialog (thanks Matrix and JdGordon)
+ - Add brief info title setting
+ - Change in the weather, text, and popup options dialogs
+ - Add reset to default and preview for all display text field
+ - Change the way the plugin handles protocol status
+ - Enable/disable auto-update from the main menu
+ - Reconizes dust conditions and assign a fog icon (thanks Klenje)
+ - Support the units "%" and "Deg"
+ - Fix a crash if miranda32.exe is renamed
+ - Fix crashes in between updating of 2 stations (thanks Targaff)
+ - Update links in the readme and DLL to the new weather category (thanks lynlimz)
+ - Other bug fixes and minor changes
+ - Document updated: weather-translation, langpack_defweather, sample_ini
+
+Version 0.3.2.16 2004/05/27
+ - Reconizes condition in lower case
+ - Few changes.
+
+Version 0.3.2.15 2004/05/24
+ - Now reconizes the condition string "T-storm"
+ - No longer skip hidden weather contact while updating
+ - Bug fix when previewing weather popups
+ - Bug fix in parsing the HTML content (in cases where "&" exists)
+ - Few other minor fixes and changes.
+
+Version 0.3.2.14 2004/05/12
+ - Popup preview include a preview of popup text settings (use default station)
+ - Fix memory leaks in various places.
+
+Version 0.3.2.13 2004/05/08
+ - Changed some linker options to prevent plugin not loading
+
+Version 0.3.2.12 2004/05/08
+ - Assign fog icon to the sand conditions
+
+Version 0.3.2.11 2004/05/07
+ - Really ignore the "Ignore" item in the ini file
+ - Fix crash when unloading ini's (at reload or shutdown)
+ - Change in weather alert popup
+ - Few minor changes
+
+Version 0.3.2.10 2004/05/02
+ - Rebuild using Visual C++
+
+Version 0.3.2.9 2004/04/29
+ - Attempt to fix crash when searching for cities by name
+ - Display a list of custom variables
+ - Fix memory leak when reloading strings from ini files
+ - Changes in the code for parsing weather info and loading ini files
+ - Other minor changes
+
+Version 0.3.2.8 2004/04/28
+ - Fix on loading ini strings, support for v1.1a again
+ - Fix in weather station search
+ - Fix crash when not connected to the internet
+ - Add a new debug function (need DB Editor)
+ - A few other minor fixes and changes
+
+Version 0.3.2.7 2004/04/19
+ - Fixing the crash on startup bug one more time :(
+
+Version 0.3.2.6 2004/04/19
+ - Attempt to fix an crash on startup bug again.
+ - Temporary remove support for v1.1a of the INI file. :(
+
+Version 0.3.2.5 2004/04/19
+ - Attempt to fix an crash on startup bug.
+
+Version 0.3.2.4 2004/04/19
+ - Fix some error while loading weather ini file.
+ - Obtain station name from the net in edit dialog.
+ - Display N/A when temperature is unavail. and the string retrieved is not "N/A"
+ - Some minor changes.
+
+Version 0.3.2.3 2004/04/18
+ - Automatically suppress online notification for all weather contact when upgrade.
+ - Fixed crash when adding new contact.
+ - Fixed crash when importing contact using mContacts.
+ - Some minor changes.
+
+Version 0.3.2.2 2004/04/18
+ - Change the way weather handles status, now properly display NA for def stn.
+ - Protocol status can be changed freely if "Do not display weather conditions
+ as protocol status" is enabled.
+ - More memory leak fixes and crash fixes.
+
+Version 0.3.2.1 2004/04/17
+ - Reduce memory use by more than 60% and fixed some memory leaks
+ - Support a revision of v1.1 ini file (the length string now can be unlimited)
+ - Incrase the maximun text length to 4k (but try keep it as short as possible)
+ - A few minor fixes and changes
+ - Updated readme file.
+
+Version 0.3.2.0 2004/04/12
+ - Support new variable %% (same as \%) and %[..] (see readme)
+ - Now with the complete support of weather INI v1.1
+ - Very basic support of weather alert notifications (if the INI supports it)
+ - Add browse, view webpage, and reset to default buttons edit settings dialog
+ - Interface changes and fixed tab order for all dialogs
+ - Display information for the weather INI files
+ - Some other monor changes and fixes
+ - Updates Read Me, and now it is in HTML format.
+
+Version 0.3.1.8 2004/04/09
+ - "My Notes" text are copied to "Current\WeatherInfo" (might be useful for some plugins)
+ - Increase the length of display texts from 512b to 4k
+ - Bug Fix: when temperature is N/A, display N/A
+ - Bug Fix: rounding in unit conversion, err...
+ - Bug Fix: crash with new ini setting "Set Data="
+
+Version 0.3.1.7 2004/04/08
+ - Now correctly support the new ini files.
+
+Version 0.3.1.6 2004/04/04
+ - Support escape characters "\%" for displaying %
+ - Changes in warning popups
+
+Version 0.3.1.5 2004/04/02
+ - New option: Consider weather info updated only when cond and temp are changed
+ - Support v1.1 of weather ini files - only support loading, but not the new features ;)
+ - Rounding is used when converting units
+ - Attempt to fix the crash on exit and reload weather data bug
+ - The default update time is changed to 20 min
+ - Other minor fixes and changes that I don't remember
+
+Version 0.3.1.1 2004/03/27
+ - Fix the crash when opening brief info dialog
+ - The default for "Support online notification" is on when adding new station
+
+Version 0.3.1.0 2004/03/25
+ - Change the way popup is handled, no longer need to enable the threading option
+ - Manually add station without searching by entering "#" in the ID field
+ - Always provide a search result if the weather service has no ID search available.
+ - Some error handling and popups to prevent crashes.
+ - New hookable event: ME_WEATHER_UPDATED
+ - Bug fix: Translation of retrieved data
+ - Bug fix: Search don't work for city that has more than 1 word
+ - Bug fix: Speed conversion is wrong
+ - Bug fix: weatherch.ini: Crash if adding/updating a station in US Eastern timezone
+ - Updated: weatherch.ini, Read Me, Translation, Sample INI, m_weather.h
+
+Version 0.3.0.1 (Beta) 2004/03/23
+ - Do not update contacts that are hidden from list (see it as "disabled" contacts)
+ - Give error message box when selecting more info and weather map before setting the URL
+ - Bug fix: Find and search contacts (no result found + crashes)
+ - Bug fix: Issue with StartupStatus, now weather will update at least once on startup
+ regardless of what's the setting there.
+ - Bug fix: Visibility unit conversion
+ - Bug fix: Weather contacts appear offline if langpack is installed
+ - Bug fix: Some spelling error
+ - Bug fix: Feel-like temperature can't be displayed by mToolTip
+ - Bug fix: WU: Find and search for station that doesn't have current condition
+ - Updated: All 4 INI files, Read Me, Translation
+
+Version 0.3.0.0 (Beta) 2004/03/22
+ - Combine the weather dll's into one
+ - Using external file for getting update (in plugins\weather directory)
+ - Added user detail page for weather contacts
+ - New and improved option pages
+ - Proxy support (now uses netlib)
+ - Unit conversion for pressure, visibility, and wind
+ - Optimization in the edit setting dialog - Allow multiple window
+ - Changes in brief info dialog - able to open multiple brief info
+ - Reduce the number of DB access for getting settings
+ - Add more variables such as feel-like temperature, pressure
+ - Add menu item for enable/disable popup
+ - Support weather icon determination for site in other languages using langpack
+ - Support for plugin uninstaller
+ - Optimization in weather update - now update using a queue and minimize DB access
+ - Optimizaiton in add/search - now don't do unnecessary searches
+ - Other code optimization and reduce file size
+ - Reload weather update data file from the main menu
+ - Some other major and minor UI change
+ - Remove some useless features
+ - Bug fix: temperature conversion (thanks to sirius)
+ - Bug fix: crash on adding new station
+ - Some minor changes and fixes in webpage downloading.
+ - Includes documentation for INI update data file and icon selection translation.
+ - Major changes in translation strings.
+ - Some update in the readme documentation.
+ - Included in this version:
+ Weather Channel, Weather Underground (both US and International), Yahoo Weather.
+
+Version 0.2.5.2
+
+Version 0.2.5.1 2003/07/19
+ - Minor bug fixes
+
+Version 0.2.5.0 2003/06/09
+ - New feature: short weather information as status message and/or note.
+ - New option: display weather options inside plugin options.
+ - Create a seperate page for text and display options.
+ - Other minor changes and bug fixes
+
+Version 0.2.4.5 2003/06/12
+ - Bug fix: Backup/restore protocol icon (including rebuild icon) if status is hidden.
+ - Bug fix: Popup only condition changes.
+
+Version 0.2.4.4 2003/06/08
+ - Fixed typo in option
+ - Weather underground: Retrieve data for high/low temperature even if
+ current info is unavailable
+ - Minor code change.
+
+Version 0.2.4.3 2003/06/07
+ - Fix weather underground searching station
+
+Version 0.2.4.2 2003/06/06
+ - Fixed weather underground station name display problem.
+ - Changes to make compatible with earlier version in case of downgrading
+ - Reorganize language pack strings.
+
+Version 0.2.4.1 (Beta) 2003/05/28
+ - New preview using the selected timeout value.
+ - Modified timeout warning message box.
+
+Version 0.2.4.0 (Beta) 2003/05/28
+ - Added advanced option page
+ - New option: Popup timeout
+ - Restore the hide icons in status / task bar option
+ - Use old weather information if new data is unavailable
+ - Add the debug setting in advanced option page
+ - Major internal / weather update / DB settings change
+
+Version 0.2.3.13 2003/05/30
+ - Fixed searching weather underground station
+ - Few minor changes
+
+Version 0.2.3.12 2003/05/28
+
+Version 0.2.3.11 (Beta) 2003/05/27
+ - Fixed Weather Channel for the FOURTH time
+
+Version 0.2.3.10 2003/05/27
+ - Third fix for Weather Channel.
+ - Note: If v0.2.3.9 works, there is no need to upgrade
+
+Version 0.2.3.9 2003/05/26
+ - Fixed download from Weather Channel
+ - Few minor changes and updates
+
+Version 0.2.3.8 2003/05/25
+ - Removed some unnecessary popup that causes crash and/or confusion
+ - Minor code change in weather update.
+
+Version 0.2.3.7 (Beta) 2003/05/08
+ - Now compile using latest Miranda source code
+
+Version 0.2.3.6 (Beta) 2003/04/15
+
+Version 0.2.3.5 2003/03/16
+ - Fix in "Do not display weather condition as protocol status" option
+ - Fix in maximun temperature for weather channel plugin.
+
+Version 0.2.3.4 2003/03/16
+
+Version 0.2.3.3 (Beta) 2003/03/10
+ - Remove features that are incompatiable with latest version of Miranda
+ - Bug fix on retrieving weather (again!)
+
+Version 0.2.3.2 (Beta) 2003/02/28
+ - Few minor bug fixes
+
+Version 0.2.3.1 (Beta) 2003/02/17
+ - Bug fix in retrieving high and low temperature.
+ - Other minor fixes.
+
+Version 0.2.3.0 2003/02/05
+ - New option: Do not display default condition as protocol status
+ - Support Miranda Installer
+ - Other minor code changes.
+
+Version 0.2.2.11 2003/01/31
+ - Fixed some weather info parsing problems
+
+Version 0.2.2.10 2003/01/26
+ - Fix some minor errors in weather update
+
+Version 0.2.2.9 2003/01/25
+ - Add some warning messages.
+
+Version 0.2.2.8 (Beta) 2003/01/25
+ - Fixed on popup display.
+ - More infinite loop prevention.
+
+Version 0.2.2.7 2003/01/24
+ - Forget to update version number in last release
+
+Version 0.2.2.6 2003/01/24
+ - Popup only when condition changes now work properly.
+ - Minor bug fix in logging
+ - Smaller file size.
+ - Other minor changes.
+
+Version 0.2.2.5 (Beta) 2003/01/23
+ - Fixed weatherch.dll for new website format.
+
+Version 0.2.2.4 (Beta) 2003/01/18
+ - Minor code change
+
+Version 0.2.2.3 2003/01/16
+
+Version 0.2.2.2 2003/01/15
+ - Show popup action selection when menu is opened.
+ - Bug fix: Modified weather station now can update normally.
+
+Version 0.2.2.1 (Beta) 2003/01/12
+ - Bug fix: Opening menu when click on PopUp.
+ - Added link in main menu to the homepage of weathe source.
+ - New protocol icon.
+
+Version 0.2.2.0 (Beta) 2003/01/11
+ - Move pop-up related options to popup option page.
+ - New option: Set popup title
+ - New option: Specify command for popups when mouse is clicked.
+ - Added variable information popup.
+ - Some UI changes.
+ - Added version info.
+ - Some translation string added / changed.
+
+Version 0.2.1.6 (Beta) 2003/01/09
+ - Shorten code in some functions.
+
+Version 0.2.1.5 2003/01/08
+ - Updated weatherch.dll for data retrieval.
+ - Bug fix: Searching new weather station.
+ - Bug fix: Loading default settings.
+ - Few other minor changes.
+
+Version 0.2.1.3 (Beta) 2003/01/07
+ - Minor bug fix.
+
+Version 0.2.1.2 2003/01/04
+ - New option: Overwrite File upon Update.
+ - Update in translation doc.
+
+Version 0.2.1.1 2003/01/03
+ - Better support for multiline popups.
+ - Minor change in codes and readme document.
+
+Version 0.2.1.0 2002/12/31
+ - New option: Override default URL settings for each contact
+ - Display text are no longer case sensitive.
+ - Prevent opening two dialogs at the same time.
+
+Version 0.2.0.5 2002/12/18
+ - Few minor changes and bug fixes
+
+Version 0.2.0.4 (Beta) 2002/12/15
+ - Bug fix: changing status and popups.
+ - Minor change in weather update.
+
+Version 0.2.0.3 (Beta) 2002/12/14
+ - Bug fix: disable popup st startup.
+ - Other minor changes.
+
+Version 0.2.0.2 (Beta) 2002/12/12
+ - Try to make string compatible between each weather source (not tested)
+ - Bug fix: crash when not connected (not tested)
+ - New weather condition in translation string.
+ - Various other minor bug fixes and changes.
+
+Version 0.2.0.1 (Beta) 2002/12/11
+ - Fix in updating weather information in wunderground.dll
+ - Various other minor bug fixes and changes.
+
+Version 0.2.0.0 (Beta) 2002/12/10
+ - Completed wunderground.dll
+ - Bug fix: Update all weather.
+ - Bug fix: Weather update in weatherch.dll
+ - Various other bug fixes and improvements.
+
+Version 0.1.9.5 (Preview) 2002/12/10
+ - Completed weatherch.dll
+ - Weather Underground (wunderground.dll) included - not complete yet.
+ - Bug fix: Default weather station and weather status.
+ - Bug fix: Crash when edit weather station.
+ - Bug fix: Crash when adding new weather station.
+ - Bug fix: Searching for weather station when no contact found.
+ - Various other changes and bug fixes.
+
+Version 0.1.9.0 (Preview) 2002/12/09
+ - Split code into different files for easier modification.
+ - Support for multiple weather protocols (required minimal change + new build)
+ - Minor changes and bug fixes
+
+Version 0.1.5.2 2002/12/09
+ - Bug fix: crash when "Show multiple icons only when statuses differ" enabled
+ - Bug fix: some options not saved properly.
+ - Bug fix: bug fix when adding the first station.
+
+Version 0.1.5.1 2002/12/07
+ - Bug fix in showing notifying messages.
+
+Version 0.1.5.0 2002/12/06
+ - Error detections.
+ - New option: Show errors on popups.
+ - Display default station weather condition as status icon.
+ - Enable / Disable weather update through status.
+ - New weather conditions.
+ - Slight change in adding new weather station.
+ - Fixed tab orders.
+
+Version 0.1.4.9 2002/12/06
+
+Version 0.1.2.0 2002/11/29
+ - Add links to weather maps.
+ - Add option to change Popup text, Log text, and URL links.
+ - New variables: %d, %s, %S
+ - New option: open webpage in new window.
+ - Internal code changes and bug fixes.
+
+Version 0.1.1.1 2002/11/25
+ - Bug fix: Translations
+ - Minor code change and translation updates.
+
+Version 0.1.1.0 2002/11/24
+ - Brief Information template now translable.
+ - Add set to default button for Brief Information display.
+ - UI change in Brief Information dialog.
+ - Add some control over looping.
+ - Set default weather station (currently has no use, but it maybe useful later or by
+ other plugins)
+ - Bug fix: Searching for station using city names.
+ - Bug fix: Assigning icon to weather conditions.
+ - Fixed tab order.
+ - Other minor UI and code changes (hope this will fix some bugs).
+
+Version 0.1.0.0 2002/11/23
+ - Now add weather station via Find/Add Contact dialog.
+ - Able to search for station using city name.
+ - Customize string for showing brief information.
+ - New option: Log weather station in history.
+ - New option: Disable popup for specific weather station.
+ - Bug fix: Update after editing weather station.
+ - Bug fix: Now correctly update using the new webpage format.
+ - Updated translation string (both dll and weather condition).
+ - Updated debug output method.
+ - Smaller file size.
+ - Re-organized readme and language files.
+ - Various other minor bug fixes and improvement.
+
+Version 0.0.8.5 2002/11/22
+ - Bug fix: Hiding icon in task bar.
+ - New weather condition added (both dll and langpack).
+
+Version 0.0.8.4 2002/11/22
+ - Bug fix: Update issues.
+ - Updated translation string.
+
+Version 0.0.8.3 2002/11/21
+ - Interface change in option screen.
+ - Prevent displaying invalid data.
+ - Minor code change for update weather condition.
+ - Added missing translation string.
+
+Version 0.0.8.2 2002/11/20
+ - Bug fix: Translation of weather condition on contact list
+ - Bug fix: Temperature conversion.
+ - Minor change in option screens and edit setting screen.
+
+Version 0.0.8.1 2002/11/19
+ - Bug fix: Fixed temperature display.
+ - Fixed tab orders.
+
+Version 0.0.8.0 (Beta) 2002/11/19
+ - Retrieve high and low temperature forecast for the current day.
+ - Search and display temperature from alternative source when it is unknown.
+ (For the people who have N/A display beside their city, this ver should work now)
+ - More customizable contact list name display.
+ - Bug fix: C and F conversion when temperature < 0 degree C.
+ - Bug fix: Some update problems.
+ - Language pack updated: more weather conditions.
+
+Version 0.0.7.5 (Beta) 2002/11/18
+ - Right click -> Update Weather will no longer freeze Miranda.
+ - New option: Disable popup if condition doesn't change.
+ - Bug fix: prevent manual update when auto-update is in progress.
+ - Added missing translation string.
+
+Version 0.0.7.0 (Beta) 2002/11/17
+ - Updating weather will no longer freeze up miranda.
+ - Add option to disable popup.
+ - Bug fix: Now saves the degree sign in option.
+ - Bug fix: Logging weather condition and view log command.
+ - Bug fix: Update weather condition after modifying weather station.
+ - Added missing translation string.
+ - Various other improvements.
+
+Version 0.0.6.1 (Beta) 2002/11/16
+ - Bug fix: Update after modifying weather station.
+ - Bug fix: No cache (slower but more accurate info).
+
+Version 0.0.6.0 (Beta) 2002/11/16
+ - The plugin has it's own popup (not using NewStatusNotify's anymore)
+ - Add option to hide icon in status bar and status menu (expreimental release).
+ - Various minor changes.
+
+Version 0.0.5.1 (Alpha) 2002/11/16
+
+Version 0.0.5.0 (Alpha) 2002/11/15
+
+Version 0.0.4.3 (Beta) 2002/11/15
+ - Added option to disable main menu item.
+ - Various minor improvements.
+
+Version 0.0.4.2 (Beta) 2002/11/15
+ - Bug fix: translation strings.
+ - Bug fix: no longer open miranda directory when no log is found.
+
+Version 0.0.4.1 (Beta) 2002/11/15
+ - Bug fix on retrieving weather information.
+ - Removed debug string that was accidentally built in the last release. (see above)
+
+Version 0.0.4.0 (Beta) 2002/11/14
+ - Retrieve weather information no longer require temp files.
+ - Able to modify weather station settings.
+ - Add link to log file in contact menu.
+ - Add an option for degree sign (I can't think of a better way to do this).
+ - Relocate main menu item.
+ - Bug fix: DB: Attempt to get wrong type of value, word.
+ - Various other minor bug fixes.
+
+Version 0.0.3.7 (Beta) 2002/11/14
+ - Bug fix: degree signs (sorry for the copy-and-paste error).
+ - Move the temporary file to miranda directory.
+
+Version 0.0.3.6 (Beta) 2002/11/14
+ - Bug fix: degree signs (changable using language pack)
+ - Bug fix: DB: Attempt to get wrong type of value, word.
+ - More weather condition are now able to display with correct icon.
+
+Version 0.0.3.5 (Beta) 2002/11/13
+ - Initial public beta release.
+
+Version 0.0.3.1 (Beta) 2002/11/13
+
+Version 0.0.3.0 (Beta) 2002/11/12
+ - Disable auto update option.
+ - Logging weather condition.
+ - New option for displaying weather conditions on contact list.
+ - Bug fix: some tarnslation strings.
+ - Bug fix: switching between English and metric units.
+ - Bug fix: time of update.
+
+Version 0.0.2.1 (Preview) 2002/11/12
+ - Bug fix: F to C conversion.
+ - Bug fix: Display complete forcast page in correct unit system.
+
+Version 0.0.2.0 (Preview) 2002/11/12
+ - Display temperature on contact list.
+ - Translable strings.
+ - Display brief weather information as message box.
+ - Faster information download.
+ - Various other fixes.
+
+Version 0.0.1.2 (Pre-Alpha) 2002/11/12
+
+Version 0.0.1.1 (Pre-Alpha) 2002/11/11
+ - Faster and more reliable download.
+ - Various bug fixes.
+
+Version 0.0.1.0 (Pre-Alpha) 2002/11/11
+ - Retrieve temperature and update time.
+
+Version 0.0.0.3 (Pre-Alpha) 2002/11/11
+ - Bug fix in weather condition and icons.
+ - Various other bug fixes.
+
+Version 0.0.0.2 (Pre-Alpha) 2002/11/11
+ - Set the name for city, retrieve weather condition.
+
+Version 0.0.0.1 (Pre-Alpha) 2002/11/10
+ - Initial build
diff --git a/protocols/Weather/docs/license.txt b/protocols/Weather/docs/license.txt
new file mode 100644
index 0000000000..5b6e7c66c2
--- /dev/null
+++ b/protocols/Weather/docs/license.txt
@@ -0,0 +1,340 @@
+ GNU GENERAL PUBLIC LICENSE
+ Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.
+ 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+ Preamble
+
+ The licenses for most software are designed to take away your
+freedom to share and change it. By contrast, the GNU General Public
+License is intended to guarantee your freedom to share and change free
+software--to make sure the software is free for all its users. This
+General Public License applies to most of the Free Software
+Foundation's software and to any other program whose authors commit to
+using it. (Some other Free Software Foundation software is covered by
+the GNU Library General Public License instead.) You can apply it to
+your programs, too.
+
+ When we speak of free software, we are referring to freedom, not
+price. Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+ To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if you
+distribute copies of the software, or if you modify it.
+
+ For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must give the recipients all the rights that
+you have. You must make sure that they, too, receive or can get the
+source code. And you must show them these terms so they know their
+rights.
+
+ We protect your rights with two steps: (1) copyright the software, and
+(2) offer you this license which gives you legal permission to copy,
+distribute and/or modify the software.
+
+ Also, for each author's protection and ours, we want to make certain
+that everyone understands that there is no warranty for this free
+software. If the software is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original, so
+that any problems introduced by others will not reflect on the original
+authors' reputations.
+
+ Finally, any free program is threatened constantly by software
+patents. We wish to avoid the danger that redistributors of a free
+program will individually obtain patent licenses, in effect making the
+program proprietary. To prevent this, we have made it clear that any
+patent must be licensed for everyone's free use or not licensed at all.
+
+ The precise terms and conditions for copying, distribution and
+modification follow.
+
+ GNU GENERAL PUBLIC LICENSE
+ TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+ 0. This License applies to any program or other work which contains
+a notice placed by the copyright holder saying it may be distributed
+under the terms of this General Public License. The "Program", below,
+refers to any such program or work, and a "work based on the Program"
+means either the Program or any derivative work under copyright law:
+that is to say, a work containing the Program or a portion of it,
+either verbatim or with modifications and/or translated into another
+language. (Hereinafter, translation is included without limitation in
+the term "modification".) Each licensee is addressed as "you".
+
+Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope. The act of
+running the Program is not restricted, and the output from the Program
+is covered only if its contents constitute a work based on the
+Program (independent of having been made by running the Program).
+Whether that is true depends on what the Program does.
+
+ 1. You may copy and distribute verbatim copies of the Program's
+source code as you receive it, in any medium, provided that you
+conspicuously and appropriately publish on each copy an appropriate
+copyright notice and disclaimer of warranty; keep intact all the
+notices that refer to this License and to the absence of any warranty;
+and give any other recipients of the Program a copy of this License
+along with the Program.
+
+You may charge a fee for the physical act of transferring a copy, and
+you may at your option offer warranty protection in exchange for a fee.
+
+ 2. You may modify your copy or copies of the Program or any portion
+of it, thus forming a work based on the Program, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+ a) You must cause the modified files to carry prominent notices
+ stating that you changed the files and the date of any change.
+
+ b) You must cause any work that you distribute or publish, that in
+ whole or in part contains or is derived from the Program or any
+ part thereof, to be licensed as a whole at no charge to all third
+ parties under the terms of this License.
+
+ c) If the modified program normally reads commands interactively
+ when run, you must cause it, when started running for such
+ interactive use in the most ordinary way, to print or display an
+ announcement including an appropriate copyright notice and a
+ notice that there is no warranty (or else, saying that you provide
+ a warranty) and that users may redistribute the program under
+ these conditions, and telling the user how to view a copy of this
+ License. (Exception: if the Program itself is interactive but
+ does not normally print such an announcement, your work based on
+ the Program is not required to print an announcement.)
+
+These requirements apply to the modified work as a whole. If
+identifiable sections of that work are not derived from the Program,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works. But when you
+distribute the same sections as part of a whole which is a work based
+on the Program, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Program.
+
+In addition, mere aggregation of another work not based on the Program
+with the Program (or with a work based on the Program) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+ 3. You may copy and distribute the Program (or a work based on it,
+under Section 2) in object code or executable form under the terms of
+Sections 1 and 2 above provided that you also do one of the following:
+
+ a) Accompany it with the complete corresponding machine-readable
+ source code, which must be distributed under the terms of Sections
+ 1 and 2 above on a medium customarily used for software interchange; or,
+
+ b) Accompany it with a written offer, valid for at least three
+ years, to give any third party, for a charge no more than your
+ cost of physically performing source distribution, a complete
+ machine-readable copy of the corresponding source code, to be
+ distributed under the terms of Sections 1 and 2 above on a medium
+ customarily used for software interchange; or,
+
+ c) Accompany it with the information you received as to the offer
+ to distribute corresponding source code. (This alternative is
+ allowed only for noncommercial distribution and only if you
+ received the program in object code or executable form with such
+ an offer, in accord with Subsection b above.)
+
+The source code for a work means the preferred form of the work for
+making modifications to it. For an executable work, complete source
+code means all the source code for all modules it contains, plus any
+associated interface definition files, plus the scripts used to
+control compilation and installation of the executable. However, as a
+special exception, the source code distributed need not include
+anything that is normally distributed (in either source or binary
+form) with the major components (compiler, kernel, and so on) of the
+operating system on which the executable runs, unless that component
+itself accompanies the executable.
+
+If distribution of executable or object code is made by offering
+access to copy from a designated place, then offering equivalent
+access to copy the source code from the same place counts as
+distribution of the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+ 4. You may not copy, modify, sublicense, or distribute the Program
+except as expressly provided under this License. Any attempt
+otherwise to copy, modify, sublicense or distribute the Program is
+void, and will automatically terminate your rights under this License.
+However, parties who have received copies, or rights, from you under
+this License will not have their licenses terminated so long as such
+parties remain in full compliance.
+
+ 5. You are not required to accept this License, since you have not
+signed it. However, nothing else grants you permission to modify or
+distribute the Program or its derivative works. These actions are
+prohibited by law if you do not accept this License. Therefore, by
+modifying or distributing the Program (or any work based on the
+Program), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Program or works based on it.
+
+ 6. Each time you redistribute the Program (or any work based on the
+Program), the recipient automatically receives a license from the
+original licensor to copy, distribute or modify the Program subject to
+these terms and conditions. You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+
+ 7. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License. If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Program at all. For example, if a patent
+license would not permit royalty-free redistribution of the Program by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Program.
+
+If any portion of this section is held invalid or unenforceable under
+any particular circumstance, the balance of the section is intended to
+apply and the section as a whole is intended to apply in other
+circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system, which is
+implemented by public license practices. Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+ 8. If the distribution and/or use of the Program is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Program under this License
+may add an explicit geographical distribution limitation excluding
+those countries, so that distribution is permitted only in or among
+countries not thus excluded. In such case, this License incorporates
+the limitation as if written in the body of this License.
+
+ 9. The Free Software Foundation may publish revised and/or new versions
+of the General Public License from time to time. Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+Each version is given a distinguishing version number. If the Program
+specifies a version number of this License which applies to it and "any
+later version", you have the option of following the terms and conditions
+either of that version or of any later version published by the Free
+Software Foundation. If the Program does not specify a version number of
+this License, you may choose any version ever published by the Free Software
+Foundation.
+
+ 10. If you wish to incorporate parts of the Program into other free
+programs whose distribution conditions are different, write to the author
+to ask for permission. For software which is copyrighted by the Free
+Software Foundation, write to the Free Software Foundation; we sometimes
+make exceptions for this. Our decision will be guided by the two goals
+of preserving the free status of all derivatives of our free software and
+of promoting the sharing and reuse of software generally.
+
+ NO WARRANTY
+
+ 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
+PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
+REPAIR OR CORRECTION.
+
+ 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGES.
+
+ END OF TERMS AND CONDITIONS
+
+ How to Apply These Terms to Your New Programs
+
+ If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+ To do so, attach the following notices to the program. It is safest
+to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+ <one line to give the program's name and a brief idea of what it does.>
+ Copyright (C) <year> <name of author>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+
+Also add information on how to contact you by electronic and paper mail.
+
+If the program is interactive, make it output a short notice like this
+when it starts in an interactive mode:
+
+ Gnomovision version 69, Copyright (C) year name of author
+ Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+ This is free software, and you are welcome to redistribute it
+ under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License. Of course, the commands you use may
+be called something other than `show w' and `show c'; they could even be
+mouse-clicks or menu items--whatever suits your program.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the program, if
+necessary. Here is a sample; alter the names:
+
+ Yoyodyne, Inc., hereby disclaims all copyright interest in the program
+ `Gnomovision' (which makes passes at compilers) written by James Hacker.
+
+ <signature of Ty Coon>, 1 April 1989
+ Ty Coon, President of Vice
+
+This General Public License does not permit incorporating your program into
+proprietary programs. If your program is a subroutine library, you may
+consider it more useful to permit linking proprietary applications with the
+library. If this is what you want to do, use the GNU Library General
+Public License instead of this License.
diff --git a/protocols/Weather/docs/readme.html b/protocols/Weather/docs/readme.html
new file mode 100644
index 0000000000..0f3e8d80c8
--- /dev/null
+++ b/protocols/Weather/docs/readme.html
@@ -0,0 +1,230 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
+<html>
+ <head>
+ <title>Read Me for Weather Protocol</title>
+ <script language="javascript" type="text/javascript">
+function link(num){document.location="http://addons.miranda-im.org/details.php?action=viewfile&id="+num;}
+ </script>
+ </head>
+ <body>
+ <h2>Read Me for Weather Protocol</h2>
+ <hr/>
+ <pre>
+<a name="top"><font color="red">
+<b>*** IMPORTANT NOTICE ***</b>
+Be cautious when choosing the "special status" selection for selecting the status
+assign to contact whose current condition is unavailable. This feature is not
+officially support by Miranda and may cause a lot of plugins to crash. Be sure to
+backup your profile before you try this feature.</font>
+
+</a>
+</pre>
+<hr/>
+<pre>
+
+<b><u>File Content</u></b>
+
+<a href="#fea">Features</a>
+<a href="#fi">Files Included</a>
+<a href="#sr">System Requirement</a>
+<a href="#ins">Installation</a>
+<a href="#faq">Frequently Asked Questions</a>
+<a href="#lic">License</a>
+
+</pre>
+<hr/>
+<pre>
+
+<a name="fea"><b><u>Features</u></b>
+
+ - Retrieve weather information and display them on your Miranda contact list.
+ - Provide a contact information page for viewing the current weather conditions.
+ - Display PopUp when information is retrieved.
+ - Log weather conditions to a file or in history.
+ - Quick links for viewing complete forecast and weather maps.
+
+
+</a><a name="fi"><b><u>Files Included</u></b>
+
+ - plugins\weather.dll
+ The core to the weather plugin. Required component
+ - </a><a href="langpack_defweather.txt">langpack_defweather.txt</a> (stored in the documentation folder by default)
+ Langpack for weather icon assignment, containing documentation for how to use
+ - <a href="weather-readme.html">plugins\weather-doc\weather-readme.html</a>
+ Documentation and FAQ for Weather Protocol (this file).
+ - <a href="sample_ini.ini">plugins\weather-doc\sample_ini.ini</a>
+ Documentation of the format of the weather INI file.
+ - <a href="weather-translation.txt">plugins\weather-doc\weather-translation.txt</a>
+ A file that contains a translation of hopefully all string used in Weather Protocol.
+
+
+<a name="sr"><b><u>System Requirement</u></b>
+
+ - </a><a href=
+"http://www.miranda-im.org">Miranda IM</a> (v0.7.3.0 or later)
+ - <a href="http://addons.miranda-im.org/index.php?action=display&amp;id=78">Weather INI file</a>
+ - Weather icons (Optional)
+ Numerous choices available in <a href=
+"http://addons.miranda-im.org/index.php?action=display&amp;id=35">icon downloads</a>.
+ - <a href=
+"javascript:link(2759)">YAPP plugin</a> by sje or <a href=
+"javascript:link(3400)">PopUp Plus plugin</a> by nullbie (Optional)
+
+
+<a name="ins"><b><u>Installation</u></b>
+ For installation of weather protocol, it is recommended for installing it using Miranda
+ Installer. For manual installation, please following these steps:
+
+ 1. Copy weather.dll into plugins directory.
+ 2. Get the ini's from file listing and place them into plugin\weather directory.
+ 3. If you want external file for status icon selection, copy the content of
+ langpack_defweather.txt into your language pack and (optionally) enable
+ "Disable internal icon selection" from the option page.
+ 4. In icon option, customize the weather icon or use the default one in the dll
+
+ IMPORTANT UPGRADE NOTICE
+ Due to the changes made in this version, Weather 0.3.x is not compatible with older
+ releases (v0.2.x). Therefore, you should delete your weather contacts before
+ upgrading to this new version.
+
+
+</a><a name="faq"><b><u>Frequently Asked Question</u></b>
+
+<i><u>Setting Up Weather Protocol</u></i>
+For installation, follow the steps describe in the </a><a href=
+"#ins">installation</a> section of the readme.
+
+<b>Q1-1. Weather Protocol does not do anything after I installed it, and it
+ cannot go online.</b>
+A. You need to add a new station before you can go online.
+
+<b>Q1-2. How do I add new stations?</b>
+A. Use the find/add dialog box. You can either search for station ID (see the readme
+ for the ini file to see how it can be obtained) or search by city name by entering
+ the name in either one of the Nickname, Firstname, or Lastname field.
+
+<b>Q1-3. I can't find my station! Any help?</b>
+A. Make sure you have installed the plugin and ini file correctly. At least one INI
+ file must exist in the plugins\weather directory in order for the plugin to funciton
+ properly. For more information, click <a href=
+"#ins">here</a>.
+
+<b>Q1-4. I have installed the plugin properly, and it still doesn't work. I have
+ noticed that there is no traffic generated by the plugin.</b>
+A. Check you proxy setting, some proxy does not work properly under Miranda IM 0.3.3.0.
+ If your proxy is having problem connecting, you need to upgrade to Miranda IM 0.3.3.1
+ or try the <a href="http://www.miranda-im.org/development/">nightly builds</a>
+ (Note: They are experimental builds!)
+ Also, if you are using <a href="javascript:link(844)">traffic counter</a> plugin,
+ please make sure that you are using the latest version. The old version stops Weather
+ and some other plugin from working.
+
+<i><u>INI and Development Related Questions</u></i>
+
+<b>Q2-1. What are those INI files for?</b>
+A. The INI files contain information for downloading and parsing weather information
+ from a particular weather site. At least one INI file must exist in order for the
+ plugin to work. For a list of available INI's, click <a href="#top">here</a>.
+
+<b>Q2-2. Can I install or modify the INI files without restarting Miranda?</b>
+A. Yes, choose: M (main menu) -&gt; Weather -&gt; Reload Weather Data
+
+<b>Q2-3. I want to retrieve weather information from a different source than those
+ that are currently available. How can this be done?</b>
+A. You can write your own INI file. For more information, click <a href="sample_ini.ini">here</a>.
+
+<b>Q2-4. I wrote/downloaded an ini file that retrieve weather condition in a
+ language that weather protocol doesn't seems to reconize and always
+ display N/A. What should I do?</b>
+A. You can use translation string for assigning icons. For more information, click <a href="langpack_defweather.txt">here</a>.
+
+<b>Q2-5. How does weather assign status icons for each status?</b>
+A. Online = Sunny
+ Away = Partly Cloudy
+ NA = Cloudy
+ Occupied = Rain
+ DND = Rain Shower
+ Free for Chat = Snow / Wintery Conditions
+ Invisible = Lightning / Thunderstorm
+ On the Phone = Snow Shower
+ Out to Lunch = Fog / Haze
+ Offline = No Data Available
+
+<u><i>Obtaining Weather Data</i></u>
+
+<b>Q3-1. Does weather protocol retreve weather forecasts?</b>
+A. Support of this feature depend on the ini file you use. If it is supported, the most
+ likely variable you use for it is %[Forecast Day #] or %[FD#] where # is the day you
+ want the forecast for. See the readme supplied in the INI file package for more
+ information.
+
+<b>Q3-2. How long should the time between update be?</b>
+A. This depend on the update interval on the website. Generally, this field should set
+ to a value between 10 to 30 minutes. If the value is too small, a lot of traffics
+ will be generated by the protocol.
+
+<b>Q3-3. How can I temporary disable weather procotol?</b>
+A. Switch the weather status to OFFLINE, but this will not work if you have "Do not
+ display weather condition as protocol status" option enabled. To enable the
+ protocol again, switch it to a status other than OFFLINE. Automatic update of
+ weather condition can be disabled through menu and option page.
+
+<b>Q3-4. Why are the name of some weather contacts italic on my contact?</b>
+A. There are weather alerts issued for those cities. To see the alert title, use the
+ %[Alert] variable. You can disable this function in option page.
+
+<b>Q3-5. There are some status that the weather plugin doesn't seems to
+ reconize and always shows as N/A on the contact list. What can I do?</b>
+A. If the source of weather info is in a language other than English, please check the
+ INI package for instruction of how to install language pack. If the source is in
+ English, notify me.
+
+<u><i>Customizing the Weather Protocol</i></u>
+
+<b>Q4-1. Can I hide Weather from status bar and protocol menu?</b>
+A. Go to Options-&gt;Plugins-&gt;Weather, enable "Hide Weather in status bar and status menu".
+
+<b>Q4-2. I can't find Weather in the icon option drop-down list. How can I change
+ weather icons?</b>
+A. Weather icon cannot be changed if "Hide Weather in status bar and status menu" is
+ enabled. To change icons, disable the option (see Q4-1), make your change, then re-
+ enable it.
+
+<b>Q4-3. I can't find the options for changing display text.</b>
+A. Go to Options-&gt;Plugins-&gt;Weather, then click on the icon beside "Change display texts"
+
+<b>Q4-4. How can I change the display name of my city?</b>
+A. Right-click on the city and select "Edit Settings". Change the field "City name"
+ to the new display name.
+
+<b>Q4-5. How can I change the default station?</b>
+A. Use the Edit Settings dialog (See A4-4). Note that only 1 station can be default.
+
+<b>Q4-6. What is the %[..] variable for?</b>
+A. They are the custom variables. Replace the ".." with a setting name that can be
+ found in \Weather in the database. For more information about the availability of
+ the settings, use <a href=
+"javascript:link(2957)">Database Editor</a> or refer to the readme of the ini file.
+
+<b>Q4-7. What are the "Extra Text" for?</b>
+A. The field has no use internally. However, it can be useful for some other plugin
+ to obtain a weather information string that is already parsed.
+
+<b>Q4-8. I want weather protocol to have the same status as the other protocols.
+ Is such option available?</b>
+A.
+Disable the option "Use weather condition as protocol status", then you will be
+ able to change the status freely.
+
+<b>Q4-9. How do I create avatars for each weather condition?</b>
+A. Put the following files into the Miranda\Plugins\Weather folder:
+ Light.png, Fog.png, SShower.png, Snow.png, RShower.png, Rain.png
+ PCloudy.png, Cloudy.png, Sunny.png, NA.png
+
+
+<a name="lic">License
+
+This plugin is released under </a><a href="http://www.gnu.org/licenses/gpl.txt">GPL</a>.
+</pre>
+ </body>
+</html>
diff --git a/protocols/Weather/docs/sample_ini.ini b/protocols/Weather/docs/sample_ini.ini
new file mode 100644
index 0000000000..9a045e1a3c
--- /dev/null
+++ b/protocols/Weather/docs/sample_ini.ini
@@ -0,0 +1,428 @@
+[Weather 0.3.x Update Data 1.5]
+
+; This file contains the information required for the weather protocol to obtain update.
+; For the plugin to function properly, at least one of these file must be present.
+; The proper location of these files is: plugins\weather
+
+; Note that for the entire file, DO NOT put spaces before or after the "=". The groups
+; and setting names (for example, [Header] and Name) are not case sensitive; however,
+; the values set for each settings ARE case sensitive.
+
+; Also note that the first line of this file must be either one of the following:
+; [Weather 0.3.x Update Data] (min. req. v0.3.0.0)
+; [Weather 0.3.x Update Data 1.1] (min. req. v0.3.1.8)
+; [Weather 0.3.x Update Data 1.1a] (min. req. v0.3.2.8)
+; [Weather 0.3.x Update Data 1.2] (min. req. v0.3.5.0)
+; [Weather 0.3.x Update Data 1.3] (min. req. v0.3.8.0)
+; [Weather 0.3.x Update Data 1.4] (min. req. v0.3.8.12)
+; [Weather 0.3.x Update Data 1.5] (min. req. v0.4.0.2)
+
+; Minimun version for not crashing Miranda (Set to this version to prevent the ini from
+; loading in an old version of weather plugin and crash Miranda)
+; 1.1a String longer than 256 characters.
+; 1.1 More than 16 data items in the ini
+; Not using [/...] footer at the end of the list
+; 1.0 All other features
+
+; Minimun version for using the new features (Set to this version to prevent invalid data
+; for user with old version of weather plugin. However, the other features still works)
+; 1.5 Using "UserAgent="
+; 1.4 Using "Cookie="
+; 1.3 Using "Update Url2=" & "Update Url3="
+; 1.2 Using the operation "Break Data="
+; Using the setting "Hidden=" for each data item
+; Assign weather icons from ini
+; 1.1a Support for the units: Day, Month, %, Deg, Cond
+; 1.1 Using the operation "Set Data="
+; 1.0 All other features
+
+; Revision history:
+; 1.5 (Updated in v0.4.0.2)
+; New "UserAgent="
+; 1.4 (Updated in v0.3.8.12)
+; New "Cookie="
+; 1.3 (Updated in v0.3.8.0)
+; New "Update Url2=" & "Update Url3="
+; 1.2 (Updated in v0.3.5.0; minimun req. v0.3.5.0)
+; New operation "Break Data="
+; New setting "Hidden=" that hide the data item from the mor data list
+; Weather icon assignment from the ini
+; 1.1a (Updated in v0.3.4.0; minimun req. v0.3.2.8)
+; Support for Day, Month units
+; 1.1a (Updated in v0.3.3.0; minimun req. v0.3.2.8)
+; Support the %, Deg, Cond units
+; 1.1a (For v0.3.2.8; minimun req. v0.3.2.8)
+; Now the string can be unlimited long (at least when it's within 4096 characters)
+; 1.1 (For v0.3.2.0; minimun req. v0.3.1.8)
+; No more need to use [/...] headers (now it just like a normal INI file)
+; Support more weather data, and the number of data is no longer limited to 16
+; New operation "Set Data=" that assign data items without download the info
+; 1.0 (For v0.3.0.0; minimun req. v0.3.0.0)
+; Initial version.
+
+; ======================================================================================
+
+; INI Headers
+
+[Header]
+; The name field contains the string that will appear to the user. Please be unique.
+; (for example, "Yahoo Weather")
+Name=
+
+; The internal name is the string that will be used to set the weather ID, and are used
+; internally to obtain the weather update information. This string should be short and
+; unique.
+; (for example, "yw" for "Yahoo Weather")
+Internal Name=
+
+; The following 3 fields are used in the plugin for INI information only, but it also
+; gives user some information about the file.
+Description=
+Author=
+Version=
+
+; For the following three default fields, %s is used for station ID (the one with the
+; internal name taken away, for example, CAXX0001)
+[Default]
+; The default URL for getting more weather information from contact menu or brief info
+; dialog. This setting is the default one assigned to the weather contact when it is
+; added, but can be changed by user in the Edit Settings dialog.
+Default URL=
+
+; The default URL for getting weather map from contact menu. Same as above.
+Default Map=
+
+; The URL for retrieving weather updates.
+Update URL=
+Update URL2=
+Update URL3=
+Update URL4=
+
+; Set cookie(s) when retrieving weather updates.
+Cookie=
+
+; Set user agent for http requests.
+UserAgent=
+
+; ======================================================================================
+
+; Weather Data Fields
+
+; The following section list the data fields that are used to assign the data to be stored
+; in the database. These fields should be placed in the order of appearance in the
+; download information. For each item searched, the string before the item are discarded
+; so if the order is wrong, no information can be obtained from the latter item.
+
+; Format (not all settings are necessary):
+; [Field Name]
+; Start=
+; End=
+; Set Data=
+; Break Data=
+; Source=
+; Unit=
+; Hidden=
+
+; Default Fields:
+; [Condition] Current condition, to assign condition icon
+; [Update] For display of the update time of the weather data
+; [Temperature] Current temperature
+; [Feel] Feel-like temperature
+; [High] Today's high
+; [Low] Today's low
+; [Sunrise] Sun rise time
+; [Sunset] Sun set time
+; [Wind Direction] Wind direction (not including speed)
+; Be careful to consider the no wind situation (ie. calm)
+; [Wind Speed] The speed of the wind
+; [Pressure] Barometer pressure
+; [Visibility] Visibility, if the value is 0 or non-numerical value, then unit conversion
+; for this will not run and original string is retained
+; [Humidity] Humidity, without a % sign.
+
+; Special Fields:
+; [Alert]
+; Special item for weather alert.
+; If the data retrieved for this field is non-empty, then a special alert popup will
+; display and the city on the contact list will be in a special state (using the
+; setting for "Contact to whom you have a different visibility".
+; This will be reset to normal once the alert field becomes empty.
+; [Ignore]
+; Special item for the plugin to ignore what the value it gets and all errors when
+; getting it. The value obtained for this field will not be written into the
+; database, and no popup and notification will be raised. This is useful to skip
+; some specific text or end the download script. Multiple placement of this field
+; is allowed.
+; Note: For prevent the popup of error message, v0.3.2.11 is required
+
+; Custom Fields:
+; [%name%]
+; Where %name% can be any string you want.
+
+
+; Settings:
+; Settings for obtaining data: "Start=", "End=", "Set Data=", "Break Data=", "Source="
+
+; There are 3 ways for the plugin to obtain the information string:
+; 1. Parse directly from the webpage by specifying start and end strings. Note that these
+; strings are case sensitive.
+
+; When parsing the information, the following items are removed:
+; HTML tags example: <b> </b>
+; symbols example: &nbsp;
+; linefeed and tabs
+; multiple spaces, spaces at the beginning and at the end of the string
+; Also, if the start field is blank, that means the information starts immediately
+; after the string from the last "End=" field. If the end field is blank, that means
+; the information ends at the first space the plugin encounters (even if it is inside
+; a HTML tag).
+
+; An example, for parsing
+; "<sth before>Partly <!-- something in middle -->&nbsp; Cloudy<sth after>
+; The code to give "Partly Cloudy" (without quotation):
+; [Condition]
+; Start=<sth before>
+; End=<sth after>
+
+; 2. Concatenate strings, using "Set Data=", can merge various string together by placing
+; them around the operator " & " (without the quotation mark but with the 2 spaces).
+; For the variable strings (ie. the data item retrieved previously), use []
+; For constant strings, use ""
+
+; For example, merging two condition strings "Condition 1" and "Condition 2":
+; [Condition]
+; Set Data=[Condition 1] & " and " & [Condition 2]
+
+; Another example, copy the content of "Condition
+; [Copy of Condition]
+; Set Data=[Condition]
+
+; 3. Break a string into 2, using "Break Data=", by specifying the string in between the
+; two substrings. The first half will store into the name specify by the header, and
+; the second half will be specified by "End="
+
+; An example, to reverse what we did in Example 2 (the two condition strings):
+; [Condition 1]
+; Break Data= and
+; Source=Condition
+; End=Condition 2
+
+; Other Settings:
+; Unit=
+; Specify the unit for the data, for use in unit conversion. The conversion to use
+; depends on the value assigned.
+; For temperature conversion: C, F, K
+; For speed conversion: km/h, m/s, mph, knots
+; For pressure conversion: hPa, kPa, mb, torr, mm, in
+; For distance conversion: km, miles
+; For adding a percent sign at the end: %
+; For adding a degree sign at the end: Deg
+; Convert condition str to proper case: Cond
+; For weekday string length: Day
+; For month string length: Month
+
+; Hidden=
+; Acceptable values: true, false
+; Using this on any field will prevent it from being displayed in the "More Info"
+; list, but its value will still be stored in the database.
+
+; Url=
+; Acceptable values: 1, 2, 3
+; Specifies the url on where to look for data item
+; If parameter is not specified item is searched on all urls, the last found will be used
+
+; Here's an example:
+[Condition]
+Start=
+End=
+Unit=Cond
+
+[Temperature]
+Start=
+End=
+Unit=C
+
+[Humidity TEMP]
+Start=
+End=
+Hidden=true
+
+[Humidity]
+Set Data=[Humidity TEMP] & "%"
+
+; - or -
+
+[Humidity]
+Start=
+End=
+Unit=%
+
+
+; ======================================================================================
+
+; The setting for find and add contacts.
+
+; ID search is used when the user type in the ID in the "Station ID" field and pressed
+; "Search"
+[ID Search]
+
+; This can be "true" or "false" (without quotation, not case sensitive)
+; If this is set to "false", all the following strings are ignored and the ID are NOT
+; going to search for this weather service.
+; If this field is set to FALSE, no matter what the user type for station ID, the
+; plugin will always return a result with station name empty and ID the same as what
+; the user has typed.
+Available=
+
+; The URL for ID search. Note that %s is used for placing the ID.
+Search URL=
+
+; The string appeared in the downloaded information when there is no match
+; (ie. "Document not found")
+; If this string is found while searching, the search process quit and return no result.
+Not Found Str=
+
+; Similar to weather information retrival above. This is the string preceeding the
+; station name obtained from searching. Note that the parsing is the same as above, and
+; spaces can be used.
+Name Start=
+
+; This is what's after the station name.
+Name End=
+
+; END ID SEARCH
+
+; Name search is used when the user type in any of the name field (Nick, First, Last) and
+; click on the "search" button.
+[Name Search]
+
+; This can be "true" or "false" (without quotation, not case sensitive)
+; If this is set to "false", then the plugin igmore the information stated in the Single
+; fields (ie. from "Single Name Start" to "Single ID End")
+Single Result=
+
+; This can be "true" or "false" (without quotation, not case sensitive)
+; If this is set to "false", then the plugin igmore the information stated in the Multiple
+; fields (ie. from Multiple Name Start" to Multiple ID End")
+; Note that if both single and multiple are disabled, the Name search are disabled for
+; this weather service.
+Multiple Result=
+
+; The URL for doing the name search. %s will be replaced by the station name input from
+; the user.
+Search URL=
+
+; The string appeared in the downloaded information when there is no match
+; (ie. "Document not found")
+; If this string is found while searching, the search process quit and return no result.
+Not Found Str=
+
+; This field determines whether the search will return a single result or multiple result
+; If the string stated in this field is found and Single Result is enabled from above, the
+; settings for single result will be used. Otherwise, the settings in multiple result
+; will be used.
+Single Result Str=
+
+; These fields are for the single result
+
+; Determine which item is the first to appear in the download search result file
+; This field can be ID or Name (not case sensitive).
+; For example, if ID is used here, it means that station ID appears before the station
+; name in the downloaded document.
+Single First=
+
+; The start and end string for station name. Parsing using the same way as discribed
+; above for weather information.
+; Note that if both fields are empty, then whatever the user type into the search field
+; will be used for the station name.
+Single Name Start=
+Single Name End=
+
+; The start and end string for station name. Parsing using the same way as discribed
+; above for weather information.
+Single ID Start=
+Single ID End=
+
+; The multiple result is similar to the single result as described above.
+; For this search, the plugin will loop until no more Name's and ID's can be founded
+; in the downloaded file.
+Mult First=
+Mult Name Start=
+Mult Name End=
+Mult ID Start=
+Mult ID End=
+
+; END NAME SEARCH
+
+; For a workaround of URL forwarding issue:
+; If the page retrieved contains URL forward (ie. the 302 code), the download content
+; will appears as:
+; Moved/Location: <forwarded URL>
+; This might be useful for writing the start/end string settings for the single result
+; Name Search.
+; A typical use of this is:
+; Single Result Str=Moved/Location:
+; Single First=ID (this isn't really matter)
+; Single Name Start=
+; Single Name End= (this will use whatever user type in as stn name)
+; Single ID Start=/newpages/ (what's before the station ID in the URL)
+; Single ID End=.html (what's after the station ID)
+
+; ======================================================================================
+
+; INI Defined Icon Assignments (new in v1.2)
+
+; These assignment will take the highest priority (before the internal and the langpack
+; defined assignment) when matching the condition (icon) to the current condition.
+; These settings are INI specific, which means that the setting in one INI will not affect
+; the stations that are associated to another INI.
+
+; Format:
+; {icon name}={string to search}
+
+; The "icon name" is the icon to assigned with the condition string containing the string
+; specified in "string to search" is found.
+
+; Available icon names are (in order of assigning priority):
+; Lightning, Fog, Snow Shower, Snow, Rain Shower, Rain, Partly Cloudy, Cloudy, Sunny, N/A
+
+; For examples, mimicking what internal icon selection and langpack_defweather do (of
+; course, putting these in an actual INI is not needed and is waste of space and memory).
+
+[Icons]
+Sunny=Sunny
+Sunny=Clear
+Sunny=Fair
+
+Partly Cloudy=Mainly Sunny
+Partly Cloudy=Mainly Clear
+Partly Cloudy=Partly
+Partly Cloudy=Mostly
+Partly Cloudy=Clouds
+
+Cloudy=Cloudy
+Cloudy=Overcast
+
+Rain=Drizzle
+Rain=Rain
+
+Rain Shower=Rain Shower
+Rain Shower=Shower
+
+Snow=Snow
+Snow=Ice
+Snow=Freezing
+Snow=Wintery
+
+Snow Shower=Snow Shower
+Snow Shower=Flurries
+
+Ligntning=Thunder
+Ligntning=T-storm
+
+Fog=Fog
+Fog=Mist
+Fog=Smoke
+Fog=Haze
+Fog=Sand
+Fog=Dust
diff --git a/protocols/Weather/docs/weather/gismeteo.ini b/protocols/Weather/docs/weather/gismeteo.ini
new file mode 100644
index 0000000000..eb1d38231d
--- /dev/null
+++ b/protocols/Weather/docs/weather/gismeteo.ini
@@ -0,0 +1,906 @@
+[Weather 0.3.x Update Data 1.4]
+
+;*********************************************************
+;
+; 3 gismeteo.com(ua/ru).
+;
+; !
+; __ ID , .
+;
+;
+; .
+; ( ) " " .
+;
+;
+; ->->-> "" ( )
+; :
+
+
+; %[CityName] %u
+; ----------------------------------------------------------------
+; : %c
+; : %t
+; : %p
+; : %m
+; : %i %w
+; : %[TW]
+; : %r, : %y, : %[Day Length], : %[Moon Phase]
+;
+; (, [], , , , )
+; -------------------------------------------------------------------------------------------------------
+; %[Forecast Day 1]
+; %[Forecast Day 2]
+; %[Forecast Day 3]
+; %[Forecast Day 4]
+; %[Forecast Day 5]
+; %[Forecast Day 6]
+; %[Forecast Day 7]
+; %[Forecast Day 8]
+; %[Forecast Day 9]
+; %[Forecast Day 10]
+; %[Forecast Day 11]
+; %[Forecast Day 12]
+
+
+;
+; ~~~~~~~~~~~~~~~
+; http://www.gismeteo.xxx
+; xxx - "com" , .. "ru", "ua" .,
+;
+;*********************************************************
+
+[Header]
+Name=GisMeteo
+Internal Name=gm
+Description=Weather information from Gismeteo
+Author=Eugene
+Version=2012.05.03
+[/Header]
+
+
+[Default]
+Default URL=http://www.gismeteo.ua/city/daily/%s/
+Default Map=
+Update URL=http://www.gismeteo.ua/city/daily/%s/
+[/Default]
+
+
+;------, ,
+;------TODO ...
+;[nodata]
+;Start=<div class="nodata">
+;End=</div>
+;[/nodata]
+;-----------------------------------------------------
+
+[CityName]
+Start=
+End=
+[/CityName]
+
+[Condition]
+Start=<dd>
+End=</dd>
+[/Condition]
+
+[Temperature]
+Start=<dd class='value m_temp c'>
+End=<
+Unit=C
+[/Temperature]
+
+;[Visibility]
+;Set Data=[Condition]
+;[/Visibility]
+
+[Wind Direction]
+Start=<dl title="
+End="
+[/Wind Direction]
+
+[Wind Speed]
+Start=<dd class='value m_wind ms' style='display:inline'>
+End=<span class="unit">
+Unit=m/s
+[/Wind Speed]
+
+
+[Pressure]
+Start=<dd class='value m_press torr'>
+End=<span class="unit">
+Unit=mm
+[/Pressure]
+
+[Humidity]
+Start=<div class="wicon hum" title="">
+End=<span class="unit">
+Unit=%
+[/Humidity]
+
+[Update]
+Start=data-obs-time="
+End="
+[/Update]
+
+;[Cloudy]
+;Start=
+;End=</b>
+;[/Cloudy]
+
+; DATE: T - time, D - day, M - month, W - weekday
+[FD1DW]
+Start=<div class="wtab swtab" id="tab_wdaily1">
+End=</dt>
+Hidden=true
+
+[FD1DDM]
+Start=<dd>
+End=</dd>
+Hidden=true
+
+;-------------
+[Low]
+Start=<div class="temp">
+End=</span>
+Unit=C
+[/Low]
+
+[High]
+Start=..
+End=</span>
+Unit=C
+[/High]
+;-------------
+
+[FD2DW]
+Start=<dt>
+End=</dt>
+Hidden=true
+
+[FD2DDM]
+Start=<dd>
+End=</dd>
+Hidden=true
+
+[FD3DW]
+Start=<dt>
+End=</dt>
+Hidden=true
+
+[FD3DDM]
+Start=<dd>
+End=</dd>
+Hidden=true
+
+
+
+;---------------//////////////////////////
+;------1--------//////////////////////////
+;---------------//////////////////////////
+;---------1-234--------------
+
+[FD1DT]
+Start=<tbody id="wdaily1">
+End=</th>
+
+[FD1D]
+Set Data=[FD1DW] & " " & [FD1DDM] & " " & [FD1DT]
+
+
+; CONDITION
+[FD1C]
+Start=<td class="cltext">
+End=</td>
+
+;temperature
+[FD1T]
+Start=<td class="temp">
+End=</span>
+
+; PRESSURE
+[FD1P]
+Start=<td>
+End=</span>
+
+; WIND: H - Hidden data D - direction, S - Speed
+[FD1WD]
+Start=<dl class="wind">
+End=</dt>
+Hidden=true
+[FD1WS]
+Start=<dd>
+End=</span>
+Hidden=true
+[FD1W]
+Set Data=[FD1WD] & " " & [FD1WS] & "m/s"
+
+; Humidity
+[FD1H]
+Start=<td>
+End=</td>
+Hidden=true
+
+; Feel Like Temperature
+[FD1F]
+Start=<td>
+End=</span>
+Hidden=true
+
+;================================================
+
+;---------1-2-34--------------
+
+[FD2DT]
+Start=</tr>
+End=</th>
+[FD2D]
+Set Data=[FD1DW] & " " & [FD1DDM] & " " & [FD2DT]
+; CONDITION
+[FD2C]
+Start=<td class="cltext">
+End=</td>
+;temperature
+[FD2T]
+Start=<td class="temp">
+End=</span>
+; PRESSURE
+[FD2P]
+Start=<td>
+End=</span>
+; WIND: H - Hidden data D - direction, S - Speed
+[FD2WD]
+Start=<dl class="wind">
+End=</dt>
+Hidden=true
+[FD2WS]
+Start=<dd>
+End=</span>
+Hidden=true
+[FD2W]
+Set Data=[FD2WD] & " " & [FD2WS] & "m/s"
+; Humidity
+[FD2H]
+Start=<td>
+End=</td>
+Hidden=true
+; Feel Like Temperature
+[FD2F]
+Start=<td>
+End=</span>
+Hidden=true
+
+;================================================
+;---------12-3-4--------------
+
+[FD3DT]
+Start=</tr>
+End=</th>
+[FD3D]
+Set Data=[FD1DW] & " " & [FD1DDM] & " " & [FD3DT]
+; CONDITION
+[FD3C]
+Start=<td class="cltext">
+End=</td>
+;temperature
+[FD3T]
+Start=<td class="temp">
+End=</span>
+; PRESSURE
+[FD3P]
+Start=<td>
+End=</span>
+; WIND: H - Hidden data D - direction, S - Speed
+[FD3WD]
+Start=<dl class="wind">
+End=</dt>
+Hidden=true
+[FD3WS]
+Start=<dd>
+End=</span>
+Hidden=true
+[FD3W]
+Set Data=[FD3WD] & " " & [FD3WS] & "m/s"
+; Humidity
+[FD3H]
+Start=<td>
+End=</td>
+Hidden=true
+; Feel Like Temperature
+[FD3F]
+Start=<td>
+End=</span>
+Hidden=true
+
+;================================================
+;---------123-4--------------
+
+[FD4DT]
+Start=</tr>
+End=</th>
+
+[FD4D]
+Set Data=[FD1DW] & " " & [FD1DDM] & " " & [FD4DT]
+
+
+; CONDITION
+[FD4C]
+Start=<td class="cltext">
+End=</td>
+
+;temperature
+[FD4T]
+Start=<td class="temp">
+End=</span>
+
+; PRESSURE
+[FD4P]
+Start=<td>
+End=</span>
+
+; WIND: H - Hidden data D - direction, S - Speed
+[FD4WD]
+Start=<dl class="wind">
+End=</dt>
+Hidden=true
+[FD4WS]
+Start=<dd>
+End=</span>
+Hidden=true
+[FD4W]
+Set Data=[FD4WD] & " " & [FD4WS] & "m/s"
+
+; Humidity
+[FD4H]
+Start=<td>
+End=</td>
+Hidden=true
+
+; Feel Like Temperature
+[FD4F]
+Start=<td>
+End=</span>
+Hidden=true
+
+;================================================
+;====================1===========================
+;================================================
+
+
+;---------------//////////////////////////
+;------2--------//////////////////////////
+;---------------//////////////////////////
+;---------1-234--------------
+
+[FD5DT]
+Start=</tbody>
+End=</th>
+
+[FD5D]
+Set Data=[FD2DW] & " " & [FD2DDM] & " " & [FD5DT]
+
+
+; CONDITION
+[FD5C]
+Start=<td class="cltext">
+End=</td>
+
+;temperature
+[FD5T]
+Start=<td class="temp">
+End=</span>
+
+; PRESSURE
+[FD5P]
+Start=<td>
+End=</span>
+
+; WIND: H - Hidden data D - direction, S - Speed
+[FD5WD]
+Start=<dl class="wind">
+End=</dt>
+Hidden=true
+[FD5WS]
+Start=<dd>
+End=</span>
+Hidden=true
+[FD5W]
+Set Data=[FD5WD] & " " & [FD5WS] & "m/s"
+
+; Humidity
+[FD5H]
+Start=<td>
+End=</td>
+Hidden=true
+
+; Feel Like Temperature
+[FD5F]
+Start=<td>
+End=</span>
+Hidden=true
+
+;================================================
+
+;---------1-2-34--------------
+
+[FD6DT]
+Start=</tr>
+End=</th>
+
+[FD6D]
+Set Data=[FD2DW] & " " & [FD2DDM] & " " & [FD6DT]
+
+
+; CONDITION
+[FD6C]
+Start=<td class="cltext">
+End=</td>
+
+;temperature
+[FD6T]
+Start=<td class="temp">
+End=</span>
+
+; PRESSURE
+[FD6P]
+Start=<td>
+End=</span>
+
+; WIND: H - Hidden data D - direction, S - Speed
+[FD6WD]
+Start=<dl class="wind">
+End=</dt>
+Hidden=true
+[FD6WS]
+Start=<dd>
+End=</span>
+Hidden=true
+[FD6W]
+Set Data=[FD6WD] & " " & [FD6WS] & "m/s"
+
+; Humidity
+[FD6H]
+Start=<td>
+End=</td>
+Hidden=true
+
+; Feel Like Temperature
+[FD6F]
+Start=<td>
+End=</span>
+Hidden=true
+
+;================================================
+
+;---------12-3-4--------------
+
+[FD7DT]
+Start=</tr>
+End=</th>
+
+[FD7D]
+Set Data=[FD2DW] & " " & [FD2DDM] & " " & [FD7DT]
+
+
+; CONDITION
+[FD7C]
+Start=<td class="cltext">
+End=</td>
+
+;temperature
+[FD7T]
+Start=<td class="temp">
+End=</span>
+
+; PRESSURE
+[FD7P]
+Start=<td>
+End=</span>
+
+; WIND: H - Hidden data D - direction, S - Speed
+[FD7WD]
+Start=<dl class="wind">
+End=</dt>
+Hidden=true
+[FD7WS]
+Start=<dd>
+End=</span>
+Hidden=true
+[FD7W]
+Set Data=[FD7WD] & " " & [FD7WS] & "m/s"
+
+; Humidity
+[FD7H]
+Start=<td>
+End=</td>
+Hidden=true
+
+; Feel Like Temperature
+[FD7F]
+Start=<td>
+End=</span>
+Hidden=true
+
+
+;================================================
+;---------123-4--------------
+
+[FD8DT]
+Start=</tr>
+End=</th>
+
+[FD8D]
+Set Data=[FD2DW] & " " & [FD2DDM] & " " & [FD8DT]
+
+
+; CONDITION
+[FD8C]
+Start=<td class="cltext">
+End=</td>
+
+;temperature
+[FD8T]
+Start=<td class="temp">
+End=</span>
+
+; PRESSURE
+[FD8P]
+Start=<td>
+End=</span>
+
+; WIND: H - Hidden data D - direction, S - Speed
+[FD8WD]
+Start=<dl class="wind">
+End=</dt>
+Hidden=true
+[FD8WS]
+Start=<dd>
+End=</span>
+Hidden=true
+[FD8W]
+Set Data=[FD8WD] & " " & [FD8WS] & "m/s"
+
+; Humidity
+[FD8H]
+Start=<td>
+End=</td>
+Hidden=true
+
+; Feel Like Temperature
+[FD8F]
+Start=<td>
+End=</span>
+Hidden=true
+
+;================================================
+;====================2===========================
+;================================================
+
+;---------------//////////////////////////
+;------3--------//////////////////////////
+;---------------//////////////////////////
+;---------1-234--------------
+
+[FD9DT]
+Start=</tbody>
+End=</th>
+
+[FD9D]
+Set Data=[FD3DW] & " " & [FD3DDM] & " " & [FD9DT]
+
+
+; CONDITION
+[FD9C]
+Start=<td class="cltext">
+End=</td>
+
+;temperature
+[FD9T]
+Start=<td class="temp">
+End=</span>
+
+; PRESSURE
+[FD9P]
+Start=<td>
+End=</span>
+
+; WIND: H - Hidden data D - direction, S - Speed
+[FD9WD]
+Start=<dl class="wind">
+End=</dt>
+Hidden=true
+[FD9WS]
+Start=<dd>
+End=</span>
+Hidden=true
+[FD9W]
+Set Data=[FD9WD] & " " & [FD9WS] & "m/s"
+
+; Humidity
+[FD9H]
+Start=<td>
+End=</td>
+Hidden=true
+
+; Feel Like Temperature
+[FD9F]
+Start=<td>
+End=</span>
+Hidden=true
+
+;================================================
+
+;---------1-2-34--------------
+
+[FD10DT]
+Start=</tr>
+End=</th>
+
+[FD10D]
+Set Data=[FD3DW] & " " & [FD3DDM] & " " & [FD10DT]
+
+
+; CONDITION
+[FD10C]
+Start=<td class="cltext">
+End=</td>
+
+;temperature
+[FD10T]
+Start=<td class="temp">
+End=</span>
+
+; PRESSURE
+[FD10P]
+Start=<td>
+End=</span>
+
+; WIND: H - Hidden data D - direction, S - Speed
+[FD10WD]
+Start=<dl class="wind">
+End=</dt>
+Hidden=true
+[FD10WS]
+Start=<dd>
+End=</span>
+Hidden=true
+[FD10W]
+Set Data=[FD10WD] & " " & [FD10WS] & "m/s"
+
+; Humidity
+[FD10H]
+Start=<td>
+End=</td>
+Hidden=true
+
+; Feel Like Temperature
+[FD10F]
+Start=<td>
+End=</span>
+Hidden=true
+
+;================================================
+
+;---------12-3-4--------------
+
+[FD11DT]
+Start=</tr>
+End=</th>
+
+[FD11D]
+Set Data=[FD3DW] & " " & [FD3DDM] & " " & [FD11DT]
+
+
+; CONDITION
+[FD11C]
+Start=<td class="cltext">
+End=</td>
+
+;temperature
+[FD11T]
+Start=<td class="temp">
+End=</span>
+
+; PRESSURE
+[FD11P]
+Start=<td>
+End=</span>
+
+; WIND: H - Hidden data D - direction, S - Speed
+[FD11WD]
+Start=<dl class="wind">
+End=</dt>
+Hidden=true
+[FD11WS]
+Start=<dd>
+End=</span>
+Hidden=true
+[FD11W]
+Set Data=[FD11WD] & " " & [FD11WS] & "m/s"
+
+; Humidity
+[FD11H]
+Start=<td>
+End=</td>
+Hidden=true
+
+; Feel Like Temperature
+[FD11F]
+Start=<td>
+End=</span>
+Hidden=true
+
+;================================================
+;---------123-4--------------
+
+[FD12DT]
+Start=</tr>
+End=</th>
+
+[FD12D]
+Set Data=[FD3DW] & " " & [FD3DDM] & " " & [FD12DT]
+
+
+; CONDITION
+[FD12C]
+Start=<td class="cltext">
+End=</td>
+
+;temperature
+[FD12T]
+Start=<td class="temp">
+End=</span>
+
+; PRESSURE
+[FD12P]
+Start=<td>
+End=</span>
+
+; WIND: H - Hidden data D - direction, S - Speed
+[FD12WD]
+Start=<dl class="wind">
+End=</dt>
+Hidden=true
+[FD12WS]
+Start=<dd>
+End=</span>
+Hidden=true
+[FD12W]
+Set Data=[FD12WD] & " " & [FD12WS] & "m/s"
+
+; Humidity
+[FD12H]
+Start=<td>
+End=</td>
+Hidden=true
+
+; Feel Like Temperature
+[FD12F]
+Start=<td>
+End=</span>
+Hidden=true
+
+;================================================
+;====================3===========================
+;================================================
+
+
+
+[Forecast Day 1]
+Set Data=[FD1D] & " : " & [FD1T] & "C [" & [FD1F] & "C]" & ", " & [FD1C] & ", " & [FD1W] & ", " & [FD1P] & " mm, " & [FD1H] & "%"
+[Forecast Day 2]
+Set Data=[FD2D] & " : " & [FD2T] & "C [" & [FD2F] & "C]" & ", " & [FD2C] & ", " & [FD2W] & ", " & [FD2P] & " mm, " & [FD2H] & "%"
+[Forecast Day 3]
+Set Data=[FD3D] & " : " & [FD3T] & "C [" & [FD3F] & "C]" & ", " & [FD3C] & ", " & [FD3W] & ", " & [FD3P] & " mm, " & [FD3H] & "%"
+[Forecast Day 4]
+Set Data=[FD4D] & " : " & [FD4T] & "C [" & [FD4F] & "C]" & ", " & [FD4C] & ", " & [FD4W] & ", " & [FD4P] & " mm, " & [FD4H] & "%"
+
+[Forecast Day 5]
+Set Data=[FD5D] & " : " & [FD5T] & "C [" & [FD5F] & "C]" & ", " & [FD5C] & ", " & [FD5W] & ", " & [FD5P] & " mm, " & [FD5H] & "%"
+[Forecast Day 6]
+Set Data=[FD6D] & " : " & [FD6T] & "C [" & [FD6F] & "C]" & ", " & [FD6C] & ", " & [FD6W] & ", " & [FD6P] & " mm, " & [FD6H] & "%"
+[Forecast Day 7]
+Set Data=[FD7D] & " : " & [FD7T] & "C [" & [FD7F] & "C]" & ", " & [FD7C] & ", " & [FD7W] & ", " & [FD7P] & " mm, " & [FD7H] & "%"
+[Forecast Day 8]
+Set Data=[FD8D] & " : " & [FD8T] & "C [" & [FD8F] & "C]" & ", " & [FD8C] & ", " & [FD8W] & ", " & [FD8P] & " mm, " & [FD8H] & "%"
+
+[Forecast Day 9]
+Set Data=[FD9D] & " : " & [FD9T] & "C [" & [FD9F] & "C]" & ", " & [FD9C] & ", " & [FD9W] & ", " & [FD9P] & " mm, " & [FD9H] & "%"
+[Forecast Day 10]
+Set Data=[FD10D] & " : " & [FD10T] & "C [" & [FD10F] & "C]" & ", " & [FD10C] & ", " & [FD10W] & ", " & [FD10P] & " mm, " & [FD10H] & "%"
+[Forecast Day 11]
+Set Data=[FD11D] & " : " & [FD11T] & "C [" & [FD11F] & "C]" & ", " & [FD11C] & ", " & [FD11W] & ", " & [FD11P] & " mm, " & [FD11H] & "%"
+[Forecast Day 12]
+Set Data=[FD12D] & " : " & [FD12T] & "C [" & [FD12F] & "C]" & ", " & [FD12C] & ", " & [FD12W] & ", " & [FD12P] & " mm, " & [FD12H] & "%"
+
+
+
+;--------------------------------------------
+[TW]
+Start= :
+End=&deg
+Unit=C
+[/TW]
+
+
+[Feel]
+Start=<p class="temp">
+End=&deg
+Unit=C
+[/Feel]
+
+[Sunrise]
+Start=</strong>
+End=</li>
+[/Sunrise]
+
+[Sunset]
+Start=</strong>
+End=</li>
+[/Sunset]
+
+[Day Length]
+Start=</strong>
+End=</li>
+[/Day Length]
+
+[MP1]
+Start=</strong>
+End=</li>
+Hidden=true
+
+[MP2]
+Start=<strong>
+End=</strong>
+Hidden=true
+
+[Moon Phase]
+Set Data=[MP1] & ", " & [MP2]
+[/Moon Phase]
+
+;[Update]
+;Start=<span class="icon date_bottom">
+;End=</span>
+;[/Update]
+
+
+;[Feel]
+;Set Data=[FD1FH]
+
+
+[Icons]
+Sunny=
+Sunny=
+Partly Cloudy=
+Cloudy=
+Cloudy=
+Rain=
+Rain Shower=
+Rain Shower=
+Snow=
+Snow=
+Snow Shower=
+Snow Shower=
+Snow Shower=
+Ligntning=
+Fog=
+
+
+[ID Search]
+Available=TRUE
+Search URL=http://www.gismeteo.ua/city/daily/%s/
+Not Found Str=Not Found
+Name Start= .
+Name End=.">
+[/ID Search]
+
+[Name Search]
+Single Result=false
+Multiple Result=true
+Search URL=http://www.gismeteo.ua/city/?gis=%s
+Not Found Str=Not found
+
+Mult First=ID
+Mult ID Start=<li><a href="/city/daily/
+Mult ID End=/">
+Mult Name Start=/"><span><b>
+Mult Name End=</b></span></a> \ No newline at end of file
diff --git a/protocols/Weather/docs/weather/msn.ini b/protocols/Weather/docs/weather/msn.ini
new file mode 100644
index 0000000000..6a2929b4b6
--- /dev/null
+++ b/protocols/Weather/docs/weather/msn.ini
@@ -0,0 +1,1063 @@
+[Weather 0.3.x Update Data 1.5]
+[Header]
+Name=MSN Weather (New Layout)
+Internal Name=msn2014
+Description=Get Weather from www.msn.com/en-us/weather
+Author=HostedDinner
+Version=2014-11-08
+
+;Id of the station is lat,long as for example New York: "40.78,-73.83"
+
+[Default]
+Default URL=http://www.msn.com/en-us/weather/today/x/we-city-%s
+Default Map=http://www.msn.com/en-us/weather/maps/x/we-city-%s
+Update URL=http://www.msn.com/en-us/weather/today/x/we-city-%s?weadegreetype=C
+UserAgent=Mozilla/5.0 (Windows NT 6.3; WOW64; rv:33.0) Gecko/20100101 Firefox/33.0
+
+
+;current Weather
+[Ignore]
+Start=<div class="current-info">
+End=">
+
+[Temperature]
+Start=
+End=</span>
+Unit=C
+Url=1
+
+[Condition]
+Start=<span>
+End=</span>
+Url=1
+Unit=Cond
+
+[Feel]
+Start=Feels Like</span>
+End=&#176;
+Unit=C
+Url=1
+
+[Wind Direction]
+Start=title="
+End="
+Url=1
+
+[Wind Speed]
+Start=</div>
+End=kmph
+Url=1
+Unit=km/h
+
+[Pressure]
+Start=<span>Barometer</span>
+End=</li>
+Url=1
+Unit=mb
+
+[Visibility]
+Start=<span>Visibility</span>
+End=km
+Url=1
+Unit=km
+
+[Humidity]
+Start=<span>Humidity</span>
+End=%
+Url=1
+Unit=%
+
+[Dewpoint]
+Start=<span>Dew Point</span>
+End=&#176;
+Url=1
+unit=C
+
+
+;First entry is still today
+[Sunrise]
+Start=&quot;sunrise&quot;:&quot;
+End=&quot;
+Url=1
+
+[Sunset]
+Start=&quot;sunset&quot;:&quot;
+End=&quot;
+Url=1
+
+[Moonrise]
+Start=&quot;moonrise&quot;:&quot;
+End=&quot;
+Url=1
+
+[Moonset]
+Start=&quot;moonset&quot;:&quot;
+End=&quot;
+Url=1
+
+[Moonphase]
+Start=&quot;moon&quot;:&quot;
+End=&quot;
+Url=1
+
+[UV Index]
+Start=&quot;uvindex&quot;:&quot;
+End=&quot;
+Url=1
+
+[Ignore]
+Start=class="precipicn
+End=>
+Url=1
+
+[Precipitation]
+Start=>
+End=%</span>
+Url=1
+Unit=%
+
+[High]
+Start=<p>
+End=&#176;
+Url=1
+Unit=C
+
+[Low]
+Start=<p class="transparent">
+End=&#176;
+Url=1
+Unit=C
+
+
+
+;Forecast
+
+;[Forecast Day 1 Sunrise]
+;Start=&quot;sunrise&quot;:&quot;
+;End=&quot;
+;Url=1
+;Hidden=true
+
+;[Forecast Day 1 Sunset]
+;Start=&quot;sunset&quot;:&quot;
+;End=&quot;
+;Url=1
+;Hidden=true
+
+;[Forecast Day 1 Moonrise]
+;Start=&quot;moonrise&quot;:&quot;
+;End=&quot;
+;Url=1
+;Hidden=true
+
+;[Forecast Day 1 Moonset]
+;Start=&quot;moonset&quot;:&quot;
+;End=&quot;
+;Url=1
+;Hidden=true
+
+;[Forecast Day 1 Moonphase]
+;Start=&quot;moon&quot;:&quot;
+;End=&quot;
+;Url=1
+;Hidden=true
+
+[Forecast Day 1 Humidity]
+Start=&quot;humidity&quot;:&quot;
+End=%&quot;
+Url=1
+Unit=%
+Hidden=true
+
+[Forecast Day 1 UV Index]
+Start=&quot;uvindex&quot;:&quot;
+End=&quot;
+Url=1
+Hidden=true
+
+;[Ignore]
+;Start=class="dt"
+;End=>
+;Url=1
+
+[Forecast Day 1 WeekDay]
+Start=<span>
+End=</span>
+Url=1
+Unit=Day
+Hidden=true
+
+[Forecast Day 1 Day]
+Start=<span>
+End=</span>
+Url=1
+Hidden=true
+
+[Forecast Day 1 Condition]
+Start=title="
+End="
+Url=1
+Unit=Cond
+Hidden=true
+
+[Ignore]
+Start=class="precipicn
+End=>
+Url=1
+
+[Forecast Day 1 Precipitation]
+Start=>
+End=%</span>
+Url=1
+Unit=%
+Hidden=true
+
+[Forecast Day 1 High]
+Start=<p>
+End=&#176;
+Url=1
+Unit=C
+Hidden=true
+
+[Forecast Day 1 Low]
+Start=<p class="transparent">
+End=&#176;
+Url=1
+Unit=C
+Hidden=true
+
+;[Forecast Day 2 Sunrise]
+;Start=&quot;sunrise&quot;:&quot;
+;End=&quot;
+;Url=1
+;Hidden=true
+
+;[Forecast Day 2 Sunset]
+;Start=&quot;sunset&quot;:&quot;
+;End=&quot;
+;Url=1
+;Hidden=true
+
+;[Forecast Day 2 Moonrise]
+;Start=&quot;moonrise&quot;:&quot;
+;End=&quot;
+;Url=1
+;Hidden=true
+
+;[Forecast Day 2 Moonset]
+;Start=&quot;moonset&quot;:&quot;
+;End=&quot;
+;Url=1
+;Hidden=true
+
+;[Forecast Day 2 Moonphase]
+;Start=&quot;moon&quot;:&quot;
+;End=&quot;
+;Url=1
+;Hidden=true
+
+[Forecast Day 2 Humidity]
+Start=&quot;humidity&quot;:&quot;
+End=%&quot;
+Url=1
+Unit=%
+Hidden=true
+
+[Forecast Day 2 UV Index]
+Start=&quot;uvindex&quot;:&quot;
+End=&quot;
+Url=1
+Hidden=true
+
+;[Ignore]
+;Start=class="dt"
+;End=>
+;Url=1
+
+[Forecast Day 2 WeekDay]
+Start=<span>
+End=</span>
+Url=1
+Unit=Day
+Hidden=true
+
+[Forecast Day 2 Day]
+Start=<span>
+End=</span>
+Url=1
+Hidden=true
+
+[Forecast Day 2 Condition]
+Start=title="
+End="
+Url=1
+Unit=Cond
+Hidden=true
+
+[Ignore]
+Start=class="precipicn
+End=>
+Url=1
+
+[Forecast Day 2 Precipitation]
+Start=>
+End=%</span>
+Url=1
+Unit=%
+Hidden=true
+
+[Forecast Day 2 High]
+Start=<p>
+End=&#176;
+Url=1
+Unit=C
+Hidden=true
+
+[Forecast Day 2 Low]
+Start=<p class="transparent">
+End=&#176;
+Url=1
+Unit=C
+Hidden=true
+
+;[Forecast Day 3 Sunrise]
+;Start=&quot;sunrise&quot;:&quot;
+;End=&quot;
+;Url=1
+;Hidden=true
+
+;[Forecast Day 3 Sunset]
+;Start=&quot;sunset&quot;:&quot;
+;End=&quot;
+;Url=1
+;Hidden=true
+
+;[Forecast Day 3 Moonrise]
+;Start=&quot;moonrise&quot;:&quot;
+;End=&quot;
+;Url=1
+;Hidden=true
+
+;[Forecast Day 3 Moonset]
+;Start=&quot;moonset&quot;:&quot;
+;End=&quot;
+;Url=1
+;Hidden=true
+
+;[Forecast Day 3 Moonphase]
+;Start=&quot;moon&quot;:&quot;
+;End=&quot;
+;Url=1
+;Hidden=true
+
+[Forecast Day 3 Humidity]
+Start=&quot;humidity&quot;:&quot;
+End=%&quot;
+Url=1
+Unit=%
+Hidden=true
+
+[Forecast Day 3 UV Index]
+Start=&quot;uvindex&quot;:&quot;
+End=&quot;
+Url=1
+Hidden=true
+
+;[Ignore]
+;Start=class="dt"
+;End=>
+;Url=1
+
+[Forecast Day 3 WeekDay]
+Start=<span>
+End=</span>
+Url=1
+Unit=Day
+Hidden=true
+
+[Forecast Day 3 Day]
+Start=<span>
+End=</span>
+Url=1
+Hidden=true
+
+[Forecast Day 3 Condition]
+Start=title="
+End="
+Url=1
+Unit=Cond
+Hidden=true
+
+[Ignore]
+Start=class="precipicn
+End=>
+Url=1
+
+[Forecast Day 3 Precipitation]
+Start=>
+End=%</span>
+Url=1
+Unit=%
+Hidden=true
+
+[Forecast Day 3 High]
+Start=<p>
+End=&#176;
+Url=1
+Unit=C
+Hidden=true
+
+[Forecast Day 3 Low]
+Start=<p class="transparent">
+End=&#176;
+Url=1
+Unit=C
+Hidden=true
+
+;[Forecast Day 4 Sunrise]
+;Start=&quot;sunrise&quot;:&quot;
+;End=&quot;
+;Url=1
+;Hidden=true
+
+;[Forecast Day 4 Sunset]
+;Start=&quot;sunset&quot;:&quot;
+;End=&quot;
+;Url=1
+;Hidden=true
+
+;[Forecast Day 4 Moonrise]
+;Start=&quot;moonrise&quot;:&quot;
+;End=&quot;
+;Url=1
+;Hidden=true
+
+;[Forecast Day 4 Moonset]
+;Start=&quot;moonset&quot;:&quot;
+;End=&quot;
+;Url=1
+;Hidden=true
+
+;[Forecast Day 4 Moonphase]
+;Start=&quot;moon&quot;:&quot;
+;End=&quot;
+;Url=1
+;Hidden=true
+
+[Forecast Day 4 Humidity]
+Start=&quot;humidity&quot;:&quot;
+End=%&quot;
+Url=1
+Unit=%
+Hidden=true
+
+[Forecast Day 4 UV Index]
+Start=&quot;uvindex&quot;:&quot;
+End=&quot;
+Url=1
+Hidden=true
+
+;[Ignore]
+;Start=class="dt"
+;End=>
+;Url=1
+
+[Forecast Day 4 WeekDay]
+Start=<span>
+End=</span>
+Url=1
+Unit=Day
+Hidden=true
+
+[Forecast Day 4 Day]
+Start=<span>
+End=</span>
+Url=1
+Hidden=true
+
+[Forecast Day 4 Condition]
+Start=title="
+End="
+Url=1
+Unit=Cond
+Hidden=true
+
+[Ignore]
+Start=class="precipicn
+End=>
+Url=1
+
+[Forecast Day 4 Precipitation]
+Start=>
+End=%</span>
+Url=1
+Unit=%
+Hidden=true
+
+[Forecast Day 4 High]
+Start=<p>
+End=&#176;
+Url=1
+Unit=C
+Hidden=true
+
+[Forecast Day 4 Low]
+Start=<p class="transparent">
+End=&#176;
+Url=1
+Unit=C
+Hidden=true
+
+;[Forecast Day 5 Sunrise]
+;Start=&quot;sunrise&quot;:&quot;
+;End=&quot;
+;Url=1
+;Hidden=true
+
+;[Forecast Day 5 Sunset]
+;Start=&quot;sunset&quot;:&quot;
+;End=&quot;
+;Url=1
+;Hidden=true
+
+;[Forecast Day 5 Moonrise]
+;Start=&quot;moonrise&quot;:&quot;
+;End=&quot;
+;Url=1
+;Hidden=true
+
+;[Forecast Day 5 Moonset]
+;Start=&quot;moonset&quot;:&quot;
+;End=&quot;
+;Url=1
+;Hidden=true
+
+;[Forecast Day 5 Moonphase]
+;Start=&quot;moon&quot;:&quot;
+;End=&quot;
+;Url=1
+;Hidden=true
+
+[Forecast Day 5 Humidity]
+Start=&quot;humidity&quot;:&quot;
+End=%&quot;
+Url=1
+Unit=%
+Hidden=true
+
+[Forecast Day 5 UV Index]
+Start=&quot;uvindex&quot;:&quot;
+End=&quot;
+Url=1
+Hidden=true
+
+;[Ignore]
+;Start=class="dt"
+;End=>
+;Url=1
+
+[Forecast Day 5 WeekDay]
+Start=<span>
+End=</span>
+Url=1
+Unit=Day
+Hidden=true
+
+[Forecast Day 5 Day]
+Start=<span>
+End=</span>
+Url=1
+Hidden=true
+
+[Forecast Day 5 Condition]
+Start=title="
+End="
+Url=1
+Unit=Cond
+Hidden=true
+
+[Ignore]
+Start=class="precipicn
+End=>
+Url=1
+
+[Forecast Day 5 Precipitation]
+Start=>
+End=%</span>
+Url=1
+Unit=%
+Hidden=true
+
+[Forecast Day 5 High]
+Start=<p>
+End=&#176;
+Url=1
+Unit=C
+Hidden=true
+
+[Forecast Day 5 Low]
+Start=<p class="transparent">
+End=&#176;
+Url=1
+Unit=C
+Hidden=true
+
+;[Forecast Day 6 Sunrise]
+;Start=&quot;sunrise&quot;:&quot;
+;End=&quot;
+;Url=1
+;Hidden=true
+
+;[Forecast Day 6 Sunset]
+;Start=&quot;sunset&quot;:&quot;
+;End=&quot;
+;Url=1
+;Hidden=true
+
+;[Forecast Day 6 Moonrise]
+;Start=&quot;moonrise&quot;:&quot;
+;End=&quot;
+;Url=1
+;Hidden=true
+
+;[Forecast Day 6 Moonset]
+;Start=&quot;moonset&quot;:&quot;
+;End=&quot;
+;Url=1
+;Hidden=true
+
+;[Forecast Day 6 Moonphase]
+;Start=&quot;moon&quot;:&quot;
+;End=&quot;
+;Url=1
+;Hidden=true
+
+[Forecast Day 6 Humidity]
+Start=&quot;humidity&quot;:&quot;
+End=%&quot;
+Url=1
+Unit=%
+Hidden=true
+
+[Forecast Day 6 UV Index]
+Start=&quot;uvindex&quot;:&quot;
+End=&quot;
+Url=1
+Hidden=true
+
+;[Ignore]
+;Start=class="dt"
+;End=>
+;Url=1
+
+[Forecast Day 6 WeekDay]
+Start=<span>
+End=</span>
+Url=1
+Unit=Day
+Hidden=true
+
+[Forecast Day 6 Day]
+Start=<span>
+End=</span>
+Url=1
+Hidden=true
+
+[Forecast Day 6 Condition]
+Start=title="
+End="
+Url=1
+Unit=Cond
+Hidden=true
+
+[Ignore]
+Start=class="precipicn
+End=>
+Url=1
+
+[Forecast Day 6 Precipitation]
+Start=>
+End=%</span>
+Url=1
+Unit=%
+Hidden=true
+
+[Forecast Day 6 High]
+Start=<p>
+End=&#176;
+Url=1
+Unit=C
+Hidden=true
+
+[Forecast Day 6 Low]
+Start=<p class="transparent">
+End=&#176;
+Url=1
+Unit=C
+Hidden=true
+
+;[Forecast Day 7 Sunrise]
+;Start=&quot;sunrise&quot;:&quot;
+;End=&quot;
+;Url=1
+;Hidden=true
+
+;[Forecast Day 7 Sunset]
+;Start=&quot;sunset&quot;:&quot;
+;End=&quot;
+;Url=1
+;Hidden=true
+
+;[Forecast Day 7 Moonrise]
+;Start=&quot;moonrise&quot;:&quot;
+;End=&quot;
+;Url=1
+;Hidden=true
+
+;[Forecast Day 7 Moonset]
+;Start=&quot;moonset&quot;:&quot;
+;End=&quot;
+;Url=1
+;Hidden=true
+
+;[Forecast Day 7 Moonphase]
+;Start=&quot;moon&quot;:&quot;
+;End=&quot;
+;Url=1
+;Hidden=true
+
+[Forecast Day 7 Humidity]
+Start=&quot;humidity&quot;:&quot;
+End=%&quot;
+Url=1
+Unit=%
+Hidden=true
+
+[Forecast Day 7 UV Index]
+Start=&quot;uvindex&quot;:&quot;
+End=&quot;
+Url=1
+Hidden=true
+
+;[Ignore]
+;Start=class="dt"
+;End=>
+;Url=1
+
+[Forecast Day 7 WeekDay]
+Start=<span>
+End=</span>
+Url=1
+Unit=Day
+Hidden=true
+
+[Forecast Day 7 Day]
+Start=<span>
+End=</span>
+Url=1
+Hidden=true
+
+[Forecast Day 7 Condition]
+Start=title="
+End="
+Url=1
+Unit=Cond
+Hidden=true
+
+[Ignore]
+Start=class="precipicn
+End=>
+Url=1
+
+[Forecast Day 7 Precipitation]
+Start=>
+End=%</span>
+Url=1
+Unit=%
+Hidden=true
+
+[Forecast Day 7 High]
+Start=<p>
+End=&#176;
+Url=1
+Unit=C
+Hidden=true
+
+[Forecast Day 7 Low]
+Start=<p class="transparent">
+End=&#176;
+Url=1
+Unit=C
+Hidden=true
+
+;[Forecast Day 8 Sunrise]
+;Start=&quot;sunrise&quot;:&quot;
+;End=&quot;
+;Url=1
+;Hidden=true
+
+;[Forecast Day 8 Sunset]
+;Start=&quot;sunset&quot;:&quot;
+;End=&quot;
+;Url=1
+;Hidden=true
+
+;[Forecast Day 8 Moonrise]
+;Start=&quot;moonrise&quot;:&quot;
+;End=&quot;
+;Url=1
+;Hidden=true
+
+;[Forecast Day 8 Moonset]
+;Start=&quot;moonset&quot;:&quot;
+;End=&quot;
+;Url=1
+;Hidden=true
+
+;[Forecast Day 8 Moonphase]
+;Start=&quot;moon&quot;:&quot;
+;End=&quot;
+;Url=1
+;Hidden=true
+
+[Forecast Day 8 Humidity]
+Start=&quot;humidity&quot;:&quot;
+End=%&quot;
+Url=1
+Unit=%
+Hidden=true
+
+[Forecast Day 8 UV Index]
+Start=&quot;uvindex&quot;:&quot;
+End=&quot;
+Url=1
+Hidden=true
+
+;[Ignore]
+;Start=class="dt"
+;End=>
+;Url=1
+
+[Forecast Day 8 WeekDay]
+Start=<span>
+End=</span>
+Url=1
+Unit=Day
+Hidden=true
+
+[Forecast Day 8 Day]
+Start=<span>
+End=</span>
+Url=1
+Hidden=true
+
+[Forecast Day 8 Condition]
+Start=title="
+End="
+Url=1
+Unit=Cond
+Hidden=true
+
+[Ignore]
+Start=class="precipicn
+End=>
+Url=1
+
+[Forecast Day 8 Precipitation]
+Start=>
+End=%</span>
+Url=1
+Unit=%
+Hidden=true
+
+[Forecast Day 8 High]
+Start=<p>
+End=&#176;
+Url=1
+Unit=C
+Hidden=true
+
+[Forecast Day 8 Low]
+Start=<p class="transparent">
+End=&#176;
+Url=1
+Unit=C
+Hidden=true
+
+;[Forecast Day 9 Sunrise]
+;Start=&quot;sunrise&quot;:&quot;
+;End=&quot;
+;Url=1
+;Hidden=true
+
+;[Forecast Day 9 Sunset]
+;Start=&quot;sunset&quot;:&quot;
+;End=&quot;
+;Url=1
+;Hidden=true
+
+;[Forecast Day 9 Moonrise]
+;Start=&quot;moonrise&quot;:&quot;
+;End=&quot;
+;Url=1
+;Hidden=true
+
+;[Forecast Day 9 Moonset]
+;Start=&quot;moonset&quot;:&quot;
+;End=&quot;
+;Url=1
+;Hidden=true
+
+;[Forecast Day 9 Moonphase]
+;Start=&quot;moon&quot;:&quot;
+;End=&quot;
+;Url=1
+;Hidden=true
+
+[Forecast Day 9 Humidity]
+Start=&quot;humidity&quot;:&quot;
+End=%&quot;
+Url=1
+Unit=%
+Hidden=true
+
+[Forecast Day 9 UV Index]
+Start=&quot;uvindex&quot;:&quot;
+End=&quot;
+Url=1
+Hidden=true
+
+;[Ignore]
+;Start=class="dt"
+;End=>
+;Url=1
+
+[Forecast Day 9 WeekDay]
+Start=<span>
+End=</span>
+Url=1
+Unit=Day
+Hidden=true
+
+[Forecast Day 9 Day]
+Start=<span>
+End=</span>
+Url=1
+Hidden=true
+
+[Forecast Day 9 Condition]
+Start=title="
+End="
+Url=1
+Unit=Cond
+Hidden=true
+
+[Ignore]
+Start=class="precipicn
+End=>
+Url=1
+
+[Forecast Day 9 Precipitation]
+Start=>
+End=%</span>
+Url=1
+Unit=%
+Hidden=true
+
+[Forecast Day 9 High]
+Start=<p>
+End=&#176;
+Url=1
+Unit=C
+Hidden=true
+
+[Forecast Day 9 Low]
+Start=<p class="transparent">
+End=&#176;
+Url=1
+Unit=C
+Hidden=true
+
+
+
+
+
+[Update]
+Start=data-obstime="
+End="
+Url=1
+
+
+[Forecast Day 1]
+Set Data=[Forecast Day 1 WeekDay] & ", " & [Forecast Day 1 Day] & ": " & [Forecast Day 1 Condition] & " (" & [Forecast Day 1 Low] & "/" & [Forecast Day 1 High] & "), " & [Forecast Day 1 Precipitation] & " Rain, UV: " & [Forecast Day 1 UV Index] & ", Humidity: " & [Forecast Day 1 Humidity]
+
+[Forecast Day 2]
+Set Data=[Forecast Day 2 WeekDay] & ", " & [Forecast Day 2 Day] & ": " & [Forecast Day 2 Condition] & " (" & [Forecast Day 2 Low] & "/" & [Forecast Day 2 High] & "), " & [Forecast Day 2 Precipitation] & " Rain, UV: " & [Forecast Day 2 UV Index] & ", Humidity: " & [Forecast Day 2 Humidity]
+
+[Forecast Day 3]
+Set Data=[Forecast Day 3 WeekDay] & ", " & [Forecast Day 3 Day] & ": " & [Forecast Day 3 Condition] & " (" & [Forecast Day 3 Low] & "/" & [Forecast Day 3 High] & "), " & [Forecast Day 3 Precipitation] & " Rain, UV: " & [Forecast Day 3 UV Index] & ", Humidity: " & [Forecast Day 3 Humidity]
+
+[Forecast Day 4]
+Set Data=[Forecast Day 4 WeekDay] & ", " & [Forecast Day 4 Day] & ": " & [Forecast Day 4 Condition] & " (" & [Forecast Day 4 Low] & "/" & [Forecast Day 4 High] & "), " & [Forecast Day 4 Precipitation] & " Rain, UV: " & [Forecast Day 4 UV Index] & ", Humidity: " & [Forecast Day 4 Humidity]
+
+[Forecast Day 5]
+Set Data=[Forecast Day 5 WeekDay] & ", " & [Forecast Day 5 Day] & ": " & [Forecast Day 5 Condition] & " (" & [Forecast Day 5 Low] & "/" & [Forecast Day 5 High] & "), " & [Forecast Day 5 Precipitation] & " Rain, UV: " & [Forecast Day 5 UV Index] & ", Humidity: " & [Forecast Day 5 Humidity]
+
+[Forecast Day 6]
+Set Data=[Forecast Day 6 WeekDay] & ", " & [Forecast Day 6 Day] & ": " & [Forecast Day 6 Condition] & " (" & [Forecast Day 6 Low] & "/" & [Forecast Day 6 High] & "), " & [Forecast Day 6 Precipitation] & " Rain, UV: " & [Forecast Day 6 UV Index] & ", Humidity: " & [Forecast Day 6 Humidity]
+
+[Forecast Day 7]
+Set Data=[Forecast Day 7 WeekDay] & ", " & [Forecast Day 7 Day] & ": " & [Forecast Day 7 Condition] & " (" & [Forecast Day 7 Low] & "/" & [Forecast Day 7 High] & "), " & [Forecast Day 7 Precipitation] & " Rain, UV: " & [Forecast Day 7 UV Index] & ", Humidity: " & [Forecast Day 7 Humidity]
+
+[Forecast Day 8]
+Set Data=[Forecast Day 8 WeekDay] & ", " & [Forecast Day 8 Day] & ": " & [Forecast Day 8 Condition] & " (" & [Forecast Day 8 Low] & "/" & [Forecast Day 8 High] & "), " & [Forecast Day 8 Precipitation] & " Rain, UV: " & [Forecast Day 8 UV Index] & ", Humidity: " & [Forecast Day 8 Humidity]
+
+[Forecast Day 9]
+Set Data=[Forecast Day 9 WeekDay] & ", " & [Forecast Day 9 Day] & ": " & [Forecast Day 9 Condition] & " (" & [Forecast Day 9 Low] & "/" & [Forecast Day 9 High] & "), " & [Forecast Day 9 Precipitation] & " Rain, UV: " & [Forecast Day 9 UV Index] & ", Humidity: " & [Forecast Day 9 Humidity]
+
+
+
+[ID Search]
+Available=false
+
+[Name Search]
+Single Result=false
+Multiple Result=false
+
+;It's impossible to parse that...
+;the id is the lat/long of the town seperated with comma...
+;Search URL=http://api.bing.com/qsonhs.aspx?ds=w8weather&mkt=en-us&q=%s
+
+
+
+[Icons]
+;Sunny=Sunny
+Sunny=Clear
+Sunny=Fair
+Sunny=Sunny (Clear)
+
+;Partly Cloudy=Partly Cloudy
+Partly Cloudy=Mostly Cloudy
+
+;Cloudy=Cloudy
+
+;Rain=Rain
+Rain=Showers
+
+
+;Rain Shower=Rain Shower
+Rain Shower=Sprinkles
+;To fix this one:
+Rain Shower=Sleet
+
+;Snow=Snow
+
+;Snow Shower=Snow Shower
+
+;Ligntning=Ligntning
+Ligntning=T-storms
+Ligntning=Scattered Thunderstorms
+Ligntning=Isolated Thunderstorms
+
+;Fog=Fog
+
diff --git a/protocols/Weather/docs/weather/weatherxml.ini b/protocols/Weather/docs/weather/weatherxml.ini
new file mode 100644
index 0000000000..ad42d4f27e
--- /dev/null
+++ b/protocols/Weather/docs/weather/weatherxml.ini
@@ -0,0 +1,911 @@
+[Weather 0.3.x Update Data 1.2]
+[Header]
+Name=WeatherXML
+Internal Name=wxml
+Author=CNSK (Fix by BloodySword)
+Version=0.0.5.3 2009-07-16
+[Default]
+Default URL=http://www.weather.com/outlook/travel/businesstraveler/local/%s
+Default Map=http://www.weather.com/outlook/travel/map/%s
+Update URL=http://xml.weather.com/weather/local/%s?cc=*&dayf=10&unit=s
+
+[Station]
+Start=<dnam>
+End=<
+[Local Time]
+Start=<tm>
+End=<
+[Latitude]
+Start=<lat>
+End=<
+[Longitude]
+Start=<lon>
+End=<
+[Sunrise]
+Start=<sunr>
+End=<
+[Sunset]
+Start=<suns>
+End=<
+[UTC]
+Start=<zone>
+End=<
+[Update VAR]
+Start=<lsup>
+End=M
+[Update]
+Set Data=[Update VAR] & "M"
+[Observatory]
+Start=<obst>
+End=<
+[Temperature]
+Start=<tmp>
+End=<
+Unit=F
+[Feel]
+Start=<flik>
+End=<
+Unit=F
+[Condition]
+Start=<t>
+End=<
+unit=cond
+[Pressure]
+Start=<r>
+End=<
+Unit=in
+[Pressure Tendency]
+Start=<d>
+End=<
+[Wind Speed]
+Start=<s>
+End=<
+Unit=mph
+[Wind Gusts]
+Start=<gust>
+End=<
+Unit=mph
+[Wind Direction DEG]
+Start=<d>
+End=<
+[WindDir]
+Start=<t>
+End=<
+[Wind Direction]
+Set Data=[Wind Direction DEG] & " [" & [WindDir] & "]"
+[Humidity]
+Start=<hmid>
+End=<
+Unit=%
+[Visibility]
+Start=<vis>
+End=<
+Unit=miles
+[UVI]
+Start=<i>
+End=<
+[UV]
+Start=<t>
+End=<
+[UV Index]
+Set Data=[UVI] & " " & [UV]
+[Dewpoint]
+Start=<dewp>
+End=<
+Unit=F
+[Moon]
+Start=<t>
+End=</t>
+[Forecast Update VAR]
+Start=<lsup>
+End=M
+[Forecast Update]
+Set Data=[Forecast Update VAR] & "M"
+[W1]
+Start=<day d="0" t="
+End="
+Unit=Day
+[D1]
+Start=dt="
+End="
+[H1]
+Start=<hi>
+End=<
+Unit=F
+[L1]
+Start=<low>
+End=<
+Unit=F
+[R1]
+Start=<sunr>
+End=<
+[S1]
+Start=<suns>
+End=<
+[C1D]
+Start=<t>
+End=<
+Unit=Cond
+[WS1D]
+Start=<s>
+End=<
+Unit=mph
+[WG1D]
+Start=<gust>
+End=</gust>
+Unit=mph
+[WD1D]
+Start=<d>
+End=<
+Unit=Deg
+[WT1D]
+Start=<t>
+End=<
+[P1D]
+Start=<ppcp>
+End=<
+Unit=%
+[H1D]
+Start=<hmid>
+End=<
+Unit=%
+[C1N]
+Start=<t>
+End=<
+Unit=Cond
+[WS1N]
+Start=<s>
+End=<
+Unit=mph
+[WG1N]
+Start=<gust>
+End=</gust>
+Unit=mph
+[WD1N]
+Start=<d>
+End=<
+Unit=Deg
+[WT1N]
+Start=<t>
+End=<
+[P1N]
+Start=<ppcp>
+End=<
+Unit=%
+[H1N]
+Start=<hmid>
+End=<
+Unit=%
+[W2]
+Start=<day d="1" t="
+End="
+Unit=Day
+[D2]
+Start=dt="
+End=">
+[H2]
+Start=<hi>
+End=</hi>
+Unit=F
+[L2]
+Start=<low>
+End=</low>
+Unit=F
+[R2]
+Start=<sunr>
+End=</sunr>
+[S2]
+Start=<suns>
+End=</suns>
+[C2D]
+Start=<t>
+End=</t>
+unit=cond
+[WS2D]
+Start=<s>
+End=</s>
+Unit=mph
+[WG2D]
+Start=<gust>
+End=</gust>
+Unit=mph
+[WD2D]
+Start=<d>
+End=</d>
+Unit=Deg
+[WT2D]
+Start=<t>
+End=</t>
+[P2D]
+Start=<ppcp>
+End=</ppcp>
+Unit=%
+[H2D]
+Start=<hmid>
+End=</hmid>
+Unit=%
+[C2N]
+Start=<t>
+End=</t>
+unit=cond
+[WS2N]
+Start=<s>
+End=</s>
+Unit=mph
+[WG2N]
+Start=<gust>
+End=</gust>
+Unit=mph
+[WD2N]
+Start=<d>
+End=</d>
+Unit=Deg
+[WT2N]
+Start=<t>
+End=</t>
+[P2N]
+Start=<ppcp>
+End=</ppcp>
+Unit=%
+[H2N]
+Start=<hmid>
+End=</hmid>
+Unit=%
+[W3]
+Start=<day d="2" t="
+End="
+Unit=Day
+[D3]
+Start=dt="
+End=">
+[H3]
+Start=<hi>
+End=</hi>
+Unit=F
+[L3]
+Start=<low>
+End=</low>
+Unit=F
+[R3]
+Start=<sunr>
+End=</sunr>
+[S3]
+Start=<suns>
+End=</suns>
+[C3D]
+Start=<t>
+End=</t>
+unit=cond
+[WS3D]
+Start=<s>
+End=</s>
+Unit=mph
+[WG3D]
+Start=<gust>
+End=</gust>
+Unit=mph
+[WD3D]
+Start=<d>
+End=</d>
+Unit=Deg
+[WT3D]
+Start=<t>
+End=</t>
+[P3D]
+Start=<ppcp>
+End=</ppcp>
+Unit=%
+[H3D]
+Start=<hmid>
+End=</hmid>
+Unit=%
+[C3N]
+Start=<t>
+End=</t>
+unit=cond
+[WS3N]
+Start=<s>
+End=</s>
+Unit=mph
+[WG3N]
+Start=<gust>
+End=</gust>
+Unit=mph
+[WD3N]
+Start=<d>
+End=</d>
+Unit=Deg
+[WT3N]
+Start=<t>
+End=</t>
+[P3N]
+Start=<ppcp>
+End=</ppcp>
+Unit=%
+[H3N]
+Start=<hmid>
+End=</hmid>
+Unit=%
+[W4]
+Start=<day d="3" t="
+End="
+Unit=Day
+[D4]
+Start=dt="
+End=">
+[H4]
+Start=<hi>
+End=</hi>
+Unit=F
+[L4]
+Start=<low>
+End=</low>
+Unit=F
+[R4]
+Start=<sunr>
+End=</sunr>
+[S4]
+Start=<suns>
+End=</suns>
+[C4D]
+Start=<t>
+End=</t>
+unit=cond
+[WS4D]
+Start=<s>
+End=</s>
+Unit=mph
+[WG4D]
+Start=<gust>
+End=</gust>
+Unit=mph
+[WD4D]
+Start=<d>
+End=</d>
+Unit=Deg
+[WT4D]
+Start=<t>
+End=</t>
+[P4D]
+Start=<ppcp>
+End=</ppcp>
+Unit=%
+[H4D]
+Start=<hmid>
+End=</hmid>
+Unit=%
+[C4N]
+Start=<t>
+End=</t>
+unit=cond
+[WS4N]
+Start=<s>
+End=</s>
+Unit=mph
+[WG4N]
+Start=<gust>
+End=</gust>
+Unit=mph
+[WD4N]
+Start=<d>
+End=</d>
+Unit=Deg
+[WT4N]
+Start=<t>
+End=</t>
+[P4N]
+Start=<ppcp>
+End=</ppcp>
+Unit=%
+[H4N]
+Start=<hmid>
+End=</hmid>
+Unit=%
+[W5]
+Start=<day d="4" t="
+End="
+Unit=Day
+[D5]
+Start=dt="
+End=">
+[H5]
+Start=<hi>
+End=</hi>
+Unit=F
+[L5]
+Start=<low>
+End=</low>
+Unit=F
+[R5]
+Start=<sunr>
+End=</sunr>
+[S5]
+Start=<suns>
+End=</suns>
+[C5D]
+Start=<t>
+End=</t>
+unit=cond
+[WS5D]
+Start=<s>
+End=</s>
+Unit=mph
+[WG5D]
+Start=<gust>
+End=</gust>
+Unit=mph
+[WD5D]
+Start=<d>
+End=</d>
+Unit=Deg
+[WT5D]
+Start=<t>
+End=</t>
+[P5D]
+Start=<ppcp>
+End=</ppcp>
+Unit=%
+[H5D]
+Start=<hmid>
+End=</hmid>
+Unit=%
+[C5N]
+Start=<t>
+End=</t>
+unit=cond
+[WS5N]
+Start=<s>
+End=</s>
+Unit=mph
+[WG5N]
+Start=<gust>
+End=</gust>
+Unit=mph
+[WD5N]
+Start=<d>
+End=</d>
+Unit=Deg
+[WT5N]
+Start=<t>
+End=</t>
+[P5N]
+Start=<ppcp>
+End=</ppcp>
+Unit=%
+[H5N]
+Start=<hmid>
+End=</hmid>
+Unit=%
+[W6]
+Start=<day d="5" t="
+End="
+Unit=Day
+[D6]
+Start=dt="
+End=">
+[H6]
+Start=<hi>
+End=</hi>
+Unit=F
+[L6]
+Start=<low>
+End=</low>
+Unit=F
+[R6]
+Start=<sunr>
+End=</sunr>
+[S6]
+Start=<suns>
+End=</suns>
+[C6D]
+Start=<t>
+End=</t>
+unit=cond
+[WS6D]
+Start=<s>
+End=</s>
+Unit=mph
+[WG6D]
+Start=<gust>
+End=</gust>
+Unit=mph
+[WD6D]
+Start=<d>
+End=</d>
+Unit=Deg
+[WT6D]
+Start=<t>
+End=</t>
+[P6D]
+Start=<ppcp>
+End=</ppcp>
+Unit=%
+[H6D]
+Start=<hmid>
+End=</hmid>
+Unit=%
+[C6N]
+Start=<t>
+End=</t>
+unit=cond
+[WS6N]
+Start=<s>
+End=</s>
+Unit=mph
+[WG6N]
+Start=<gust>
+End=</gust>
+Unit=mph
+[WD6N]
+Start=<d>
+End=</d>
+Unit=Deg
+[WT6N]
+Start=<t>
+End=</t>
+[P6N]
+Start=<ppcp>
+End=</ppcp>
+Unit=%
+[H6N]
+Start=<hmid>
+End=</hmid>
+Unit=%
+[W7]
+Start=<day d="6" t="
+End="
+Unit=Day
+[D7]
+Start=dt="
+End=">
+[H7]
+Start=<hi>
+End=</hi>
+Unit=F
+[L7]
+Start=<low>
+End=</low>
+Unit=F
+[R7]
+Start=<sunr>
+End=</sunr>
+[S7]
+Start=<suns>
+End=</suns>
+[C7D]
+Start=<t>
+End=</t>
+unit=cond
+[WS7D]
+Start=<s>
+End=</s>
+Unit=mph
+[WG7D]
+Start=<gust>
+End=</gust>
+Unit=mph
+[WD7D]
+Start=<d>
+End=</d>
+Unit=Deg
+[WT7D]
+Start=<t>
+End=</t>
+[P7D]
+Start=<ppcp>
+End=</ppcp>
+Unit=%
+[H7D]
+Start=<hmid>
+End=</hmid>
+Unit=%
+[C7N]
+Start=<t>
+End=</t>
+unit=cond
+[WS7N]
+Start=<s>
+End=</s>
+Unit=mph
+[WG7N]
+Start=<gust>
+End=</gust>
+Unit=mph
+[WD7N]
+Start=<d>
+End=</d>
+Unit=Deg
+[WT7N]
+Start=<t>
+End=</t>
+[P7N]
+Start=<ppcp>
+End=</ppcp>
+Unit=%
+[H7N]
+Start=<hmid>
+End=</hmid>
+Unit=%
+[W8]
+Start=<day d="7" t="
+End="
+Unit=Day
+[D8]
+Start=dt="
+End=">
+[H8]
+Start=<hi>
+End=</hi>
+Unit=F
+[L8]
+Start=<low>
+End=</low>
+Unit=F
+[R8]
+Start=<sunr>
+End=</sunr>
+[S8]
+Start=<suns>
+End=</suns>
+[C8D]
+Start=<t>
+End=</t>
+unit=cond
+[WS8D]
+Start=<s>
+End=</s>
+Unit=mph
+[WG8D]
+Start=<gust>
+End=</gust>
+Unit=mph
+[WD8D]
+Start=<d>
+End=</d>
+Unit=Deg
+[WT8D]
+Start=<t>
+End=</t>
+[P8D]
+Start=<ppcp>
+End=</ppcp>
+Unit=%
+[H8D]
+Start=<hmid>
+End=</hmid>
+Unit=%
+[C8N]
+Start=<t>
+End=</t>
+unit=cond
+[WS8N]
+Start=<s>
+End=</s>
+Unit=mph
+[WG8N]
+Start=<gust>
+End=</gust>
+Unit=mph
+[WD8N]
+Start=<d>
+End=</d>
+Unit=Deg
+[WT8N]
+Start=<t>
+End=</t>
+[P8N]
+Start=<ppcp>
+End=</ppcp>
+Unit=%
+[H8N]
+Start=<hmid>
+End=</hmid>
+Unit=%
+[W9]
+Start=<day d="8" t="
+End="
+Unit=Day
+[D9]
+Start=dt="
+End=">
+[H9]
+Start=<hi>
+End=</hi>
+Unit=F
+[L9]
+Start=<low>
+End=</low>
+Unit=F
+[R9]
+Start=<sunr>
+End=</sunr>
+[S9]
+Start=<suns>
+End=</suns>
+[C9D]
+Start=<t>
+End=</t>
+unit=cond
+[WS9D]
+Start=<s>
+End=</s>
+Unit=mph
+[WG9D]
+Start=<gust>
+End=</gust>
+Unit=mph
+[WD9D]
+Start=<d>
+End=</d>
+Unit=Deg
+[WT9D]
+Start=<t>
+End=</t>
+[P9D]
+Start=<ppcp>
+End=</ppcp>
+Unit=%
+[H9D]
+Start=<hmid>
+End=</hmid>
+Unit=%
+[C9N]
+Start=<t>
+End=</t>
+unit=cond
+[WS9N]
+Start=<s>
+End=</s>
+Unit=mph
+[WG9N]
+Start=<gust>
+End=</gust>
+Unit=mph
+[WD9N]
+Start=<d>
+End=</d>
+Unit=Deg
+[WT9N]
+Start=<t>
+End=</t>
+[P9N]
+Start=<ppcp>
+End=</ppcp>
+Unit=%
+[H9N]
+Start=<hmid>
+End=</hmid>
+Unit=%
+[W0]
+Start=<day d="9" t="
+End="
+Unit=Day
+[D0]
+Start=dt="
+End=">
+[H0]
+Start=<hi>
+End=</hi>
+Unit=F
+[L0]
+Start=<low>
+End=</low>
+Unit=F
+[R0]
+Start=<sunr>
+End=</sunr>
+[S0]
+Start=<suns>
+End=</suns>
+[C0D]
+Start=<t>
+End=</t>
+unit=cond
+[WS0D]
+Start=<s>
+End=</s>
+Unit=mph
+[WG0D]
+Start=<gust>
+End=</gust>
+Unit=mph
+[WD0D]
+Start=<d>
+End=</d>
+Unit=Deg
+[WT0D]
+Start=<t>
+End=</t>
+[P0D]
+Start=<ppcp>
+End=</ppcp>
+Unit=%
+[H0D]
+Start=<hmid>
+End=</hmid>
+Unit=%
+[C0N]
+Start=<t>
+End=</t>
+unit=cond
+[WS0N]
+Start=<s>
+End=</s>
+Unit=mph
+[WG0N]
+Start=<gust>
+End=</gust>
+Unit=mph
+[WD0N]
+Start=<d>
+End=</d>
+Unit=Deg
+[WT0N]
+Start=<t>
+End=</t>
+[P0N]
+Start=<ppcp>
+End=</ppcp>
+Unit=%
+[H0N]
+Start=<hmid>
+End=</hmid>
+Unit=%
+[Low]
+set Data=[L1]
+[High]
+set Data=[H1]
+
+[Forecast Day 1]
+Set Data=[D1] & ": " & [H1] & "/" & [L1] & "; " & "Day" & ": " & [C1D] & ", " & "Wind" & " " & [WT1D] & ", " & [WS1D] & "; " & "Night" & ": " & [C1N] & ", " & "Wind" & " " & [WT1N] & ", " & [WS1N]
+
+[Forecast Day 2]
+Set Data=[D2] & ": " & [H2] & "/" & [L2] & "; " & "Day" & ": " & [C2D] & ", " & "Wind" & " " & [WT2D] & ", " & [WS2D] & "; " & "Night" & ": " & [C2N] & ", " & "Wind" & " " & [WT2N] & ", " & [WS2N]
+
+[Forecast Day 3]
+Set Data=[D3] & ": " & [H3] & "/" & [L3] & "; " & "Day" & ": " & [C3D] & ", " & "Wind" & " " & [WT3D] & ", " & [WS3D] & "; " & "Night" & ": " & [C3N] & ", " & "Wind" & " " & [WT3N] & ", " & [WS3N]
+
+[Forecast Day 4]
+Set Data=[D4] & ": " & [H4] & "/" & [L4] & "; " & "Day" & ": " & [C4D] & ", " & "Wind" & " " & [WT4D] & ", " & [WS4D] & "; " & "Night" & ": " & [C4N] & ", " & "Wind" & " " & [WT4N] & ", " & [WS4N]
+
+[Forecast Day 5]
+Set Data=[D5] & ": " & [H5] & "/" & [L5] & "; " & "Day" & ": " & [C5D] & ", " & "Wind" & " " & [WT5D] & ", " & [WS5D] & "; " & "Night" & ": " & [C5N] & ", " & "Wind" & " " & [WT5N] & ", " & [WS5N]
+
+[Forecast Day 6]
+Set Data=[D6] & ": " & [H6] & "/" & [L6] & "; " & "Day" & ": " & [C6D] & ", " & "Wind" & " " & [WT6D] & ", " & [WS6D] & "; " & "Night" & ": " & [C6N] & ", " & "Wind" & " " & [WT6N] & ", " & [WS6N]
+
+[Forecast Day 7]
+Set Data=[D7] & ": " & [H7] & "/" & [L7] & "; " & "Day" & ": " & [C7D] & ", " & "Wind" & " " & [WT7D] & ", " & [WS7D] & "; " & "Night" & ": " & [C7N] & ", " & "Wind" & " " & [WT7N] & ", " & [WS7N]
+
+[Forecast Day 8]
+Set Data=[D8] & ": " & [H8] & "/" & [L8] & "; " & "Day" & ": " & [C8D] & ", " & "Wind" & " " & [WT8D] & ", " & [WS8D] & "; " & "Night" & ": " & [C8N] & ", " & "Wind" & " " & [WT8N] & ", " & [WS8N]
+
+[Forecast Day 9]
+Set Data=[D9] & ": " & [H9] & "/" & [L9] & "; " & "Day" & ": " & [C9D] & ", " & "Wind" & " " & [WT9D] & ", " & [WS9D] & "; " & "Night" & ": " & [C9N] & ", " & "Wind" & " " & [WT9N] & ", " & [WS9N]
+
+[Forecast Day 0]
+Set Data=[D0] & ": " & [H0] & "/" & [L0] & "; " & "Day" & ": " & [C0D] & ", " & "Wind" & " " & [WT0D] & ", " & [WS0D] & "; " & "Night" & ": " & [C0N] & ", " & "Wind" & " " & [WT0N] & ", " & [WS0N]
+
+
+[ID Search]
+Available=TRUE
+Search URL=http://xml.weather.com/weather/local/%s
+Not Found Str=Invalid location provided
+Name Start=<dnam>
+Name End=</dnam>
+[Name Search]
+Single Result=TRUE
+Multiple Result=TRUE
+Search URL=http://xml.weather.com/search/search?where=%s
+Not Found Str=<search ver="2.0" />
+Single Result Str=Moved/Location:
+Single First=ID
+Single Name Start=type="1">
+Single Name End=</loc>
+Single ID Start=<loc id="
+Single ID End="
+Mult First=ID
+Mult Name Start=type="1">
+Mult Name End=</loc>
+Mult ID Start=<loc id="
+Mult ID End=" \ No newline at end of file
diff --git a/protocols/Weather/docs/weather/wundergrnd_intl.ini b/protocols/Weather/docs/weather/wundergrnd_intl.ini
new file mode 100644
index 0000000000..f0a9dd3954
--- /dev/null
+++ b/protocols/Weather/docs/weather/wundergrnd_intl.ini
@@ -0,0 +1,348 @@
+[Weather 0.3.x Update Data 1.4]
+
+; Short history:
+; 2004/03/22 Initial release
+; 2004/03/23 Some fixes in visibility
+; 2004/04/08 Update to v1.1, some new variables
+; 2004/04/09 Some changes in format
+; 2004/04/28 Fix in station search, no wind
+; 2004/04/29 Fix wind, add some variables, Retrieve text forecast
+; 2004/05/05 New WU webpage format update
+; 2004/06/19 Fixes in forecast, new UV variable
+; 2005/09/29 Updated for new website
+; 2006/03/02 Updated for new website
+; 2006/03/03 Updated for new website
+; 2006/07/16 Updated for new website / Fixed search
+; 2006/07/18 Updated for new website
+; 2006/11/19 Added Feels-Like temperature
+; 2006/12/01 Fixed pressure change indication
+; 2008/02/04 Updated for new website
+; 2008/02/19 Many fixes
+; 2008/04/24 Fixed search and wind speed
+; 2008/04/25 Fixed Visibility
+; 2008/04/26 Fixed Feels-Like temperature
+; 2008/06/07 Fixed wind display
+; 2008/07/11 Updated for new website
+; 2008/12/06 Updated for new website
+; 2008/12/20 Updated for new website
+; 2008/12/22 Updated for new website
+; 2008/12/25 Fixed wind speed
+; 2010/05/09 Fixed weather display when Feel-Like temeprature does not exist
+; 2011/02/13 Updated for new website
+
+[Header]
+Name=Weather Underground Int'l
+Internal Name=wu_intl
+Description=Download weather information for non-US cities from www.weatherunderground.com
+Author=borkra mod by Mataes
+Version=2011/02/13
+
+[Default]
+Default URL=http://www.wunderground.com/global/stations/%s.html
+Default Map=
+Update URL=http://classic.wunderground.com/global/stations/%s.html
+Cookie=Units=english
+
+[Local Time]
+Start=Local Time:
+End=</span>
+
+[Latitude]
+Start=<a href="http://maps.google.com/maps?q=
+End=,
+
+[Longitude]
+End="
+
+[Alert]
+Start=Active Advisory:
+End=</a></nobr>
+
+[Update]
+Start=Updated:
+End=</span>
+
+[Temperature]
+Start=<div style="font-size: 17px;">
+End=&nbsp;&deg;F
+Unit=F
+
+[Condition]
+Start=<div class="b" style="font-size: 14px;">
+End=</div>
+Unit=Cond
+
+[Feel]
+Set Data=[Temperature]
+
+[Feel]
+Start=<td>Windchill:
+End=&nbsp;&deg;F
+Unit=F
+
+[Humidity]
+Start=Humidity:
+End=</nobr>
+
+[Dewpoint]
+Start=Dew Point:
+End=&nbsp;
+Unit=F
+
+[Wind Speed]
+Set Data="0"
+Unit=mph
+
+; default is set to variable wind
+[Wind Direction]
+Set Data="Calm"
+
+[WindTmp]
+Start=<td>Wind:</td>
+End=window.wind_animate['CONDBOXWIND']=
+Hidden=True
+
+[Wind Speed]
+Source=WindTmp
+Break Data=mph
+Unit=mph
+
+[Wind Gust]
+Start=Wind Gust:
+End=</span>
+Unit=mph
+
+[Pressure]
+Start=Pressure:
+End=&nbsp;in
+Unit=in
+
+[Pressure Change]
+Set Data="Stable"
+
+[Pressure Change]
+Start=</span>\n\t\t(
+End=)\n\t\t</td>
+
+[Heat Index]
+Start=<td>Heat Index:
+End=&nbsp;&deg;F
+Unit=F
+
+[Visibility]
+Start=Visibility:
+End=&nbsp;miles
+Unit=miles
+
+[UV Index]
+Start=UV:
+End=<span
+
+[Elevation]
+Start=Elevation:
+End=</span>
+Unit=ft
+
+[Wind Direction DEG]
+Start=Wind Dir:
+End=&deg;</span
+Unit=Deg
+
+[Wind Direction]
+Start=> (
+End=)</td>
+
+[Sunrise]
+Start=Actual Time</td>
+End=</td>
+
+[Sunset]
+Start=<td>
+End=</td>
+
+[Moonrise]
+Start=Moon</td>
+End=</td>
+
+[Moonset]
+Start=<td>
+End=</td>
+
+[Visible Light Length]
+Start=Length Of Visible Light:</td>
+End=</td>
+
+[Day Length]
+Start=Length of Day</td>
+End=</div>
+
+[Day Length Diff Time]
+Start=<span class="b">
+End=s
+Hidden=True
+
+[Day Length Diff Word]
+End=</span>
+Hidden=True
+
+[Day Length Diff]
+Set Data=[Day Length Diff Time] & "s " & [Day Length Diff Word]
+
+[Moon Phase]
+Start=<div class="b">
+End=,
+Hidden=True
+
+[Moon Percent]
+Start=
+End=%
+Unit=%
+Hidden=True
+
+[Moon Visible]
+Start=
+End=</div>
+Hidden=True
+
+[Moon]
+Set Data=[Moon Phase] & ", " & [Moon Percent] & " " & [Moon Visible]
+
+[Forecast Day 1 Day]
+Start=<td class="taC" style="width: 20%;">
+End=</td>
+
+[Forecast Day 2 Day]
+Start=<td class="taC" style="width: 20%;">
+End=</td>
+
+[Forecast Day 3 Day]
+Start=<td class="taC" style="width: 20%;">
+End=</td>
+
+[Forecast Day 4 Day]
+Start=<td class="taC" style="width: 20%;">
+End=</td>
+
+[Forecast Day 5 Day]
+Start=<td class="taC" style="width: 20%;">
+End=</td>
+
+[Forecast Day 1 High]
+Start=<div class="b nobr">\n\t\t<span style="color: #900;">
+End=&deg;
+Unit=F
+
+[Forecast Day 1 Low]
+Start=<span style="color: #009;">
+End=&deg; F</span>
+Unit=F
+
+[Forecast Day 2 High]
+Start=<div class="b nobr">\n\t\t<span style="color: #900;">
+End=&deg; F</span>
+Unit=F
+
+[Forecast Day 2 Low]
+Start=<span style="color: #009;">
+End=&deg; F</span>
+Unit=F
+
+[Forecast Day 3 High]
+Start=<div class="b nobr">\n\t\t<span style="color: #900;">
+End=&deg;
+Unit=F
+
+[Forecast Day 3 Low]
+Start=<span style="color: #009;">
+End=&deg;
+Unit=F
+
+[Forecast Day 4 High]
+Start=<div class="b nobr">\n\t\t<span style="color: #900;">
+End=&deg;
+Unit=F
+
+[Forecast Day 4 Low]
+Start=<span style="color: #009;">
+End=&deg;
+Unit=F
+
+[Forecast Day 5 High]
+Start=<div class="b nobr">\n\t\t<span style="color: #900;">
+End=&deg;
+Unit=F
+
+[Forecast Day 5 Low]
+Start=<span style="color: #009;">
+End=&deg;
+Unit=F
+
+[Forecast Day 1 Condition]
+Start=<td class="taC" >
+End=</td>
+Unit=Cond
+
+[Forecast Day 2 Condition]
+Start=<td class="taC" >
+End=</td>
+Unit=Cond
+
+[Forecast Day 3 Condition]
+Start=<td class="taC" >
+End=</td>
+Unit=Cond
+
+[Forecast Day 4 Condition]
+Start=<td class="taC" >
+End=</td>
+Unit=Cond
+
+[Forecast Day 5 Condition]
+Start=<td class="taC" >
+End=</td>
+Unit=Cond
+
+[Max]
+Set Data=[Forecast Day 1 High]
+
+[Min]
+Set Data=[Forecast Day 1 Low]
+
+[Forecast Day 1]
+Set Data=[Forecast Day 1 Day] & ": " & [Forecast Day 1 Condition] & ", " & [Forecast Day 1 High] & "/" & [Forecast Day 1 Low]
+
+[Forecast Day 2]
+Set Data=[Forecast Day 2 Day] & ": " & [Forecast Day 2 Condition] & ", " & [Forecast Day 2 High] & "/" & [Forecast Day 2 Low]
+
+[Forecast Day 3]
+Set Data=[Forecast Day 3 Day] & ": " & [Forecast Day 3 Condition] & ", " & [Forecast Day 3 High] & "/" & [Forecast Day 3 Low]
+
+[Forecast Day 4]
+Set Data=[Forecast Day 4 Day] & ": " & [Forecast Day 4 Condition] & ", " & [Forecast Day 4 High] & "/" & [Forecast Day 4 Low]
+
+[Forecast Day 5]
+Set Data=[Forecast Day 5 Day] & ": " & [Forecast Day 5 Condition] & ", " & [Forecast Day 5 High] & "/" & [Forecast Day 5 Low]
+
+[ID Search]
+Available=TRUE
+Search URL=http://english.wunderground.com/global/stations/%s.html
+Not Found Str=City Not Found
+Name Start=type="application/rss+xml" title="
+Name End= RSS"
+
+[Name Search]
+Single Result=TRUE
+Multiple Result=TRUE
+Search URL=http://classic.wunderground.com/cgi-bin/findweather/getForecast?query=%s
+Not Found Str=City Not Found
+Single Result Str=type="application/rss+xml" title="
+Single First=Name
+Single Name Start=type="application/rss+xml" title="
+Single Name End= RSS"
+Single ID Start=global/stations/
+Single ID End=.xml
+Mult First=ID
+Mult Name Start=
+Mult Name End=</a></td>
+Mult ID Start=<td><a href="/global/stations/
+Mult ID End=.html">
diff --git a/protocols/Weather/docs/weather/wundergrnd_xml.ini b/protocols/Weather/docs/weather/wundergrnd_xml.ini
new file mode 100644
index 0000000000..0ffbd376c1
--- /dev/null
+++ b/protocols/Weather/docs/weather/wundergrnd_xml.ini
@@ -0,0 +1,325 @@
+[Weather 0.3.x Update Data 1.3]
+
+; Short history:
+; 2008/05/19 Initial release
+; 2008/06/07 More data
+; 2008/06/08 More data
+; 2011/02/13 Fixed feel temperature
+
+[Header]
+Name=Weather Underground XML
+Internal Name=wuxml
+Description=Download weather information from www.weatherunderground.com
+Author=borkra
+Version=2011/02/13
+
+[Default]
+Default URL=http://www.wunderground.com/%s.html
+Default Map=
+
+Update URL=http://api.wunderground.com/auto/wui/geo/ForecastXML/%s.html
+Update URL2=http://api.wunderground.com/auto/wui/geo/WXCurrentObXML/%s.html
+Update URL3=http://api.wunderground.com/auto/wui/geo/AlertsXML/%s.html
+
+[Alert]
+Start=<description>
+End=</description>
+
+[Latitude]
+Start=<latitude>
+End=</latitude>
+
+[Longitude]
+Start=<longitude>
+End=</longitude>
+
+[Observatory]
+Start=<station_id>
+End=</station_id>
+
+[Update]
+Start=<observation_time>Last Updated on
+End=</observation_time>
+
+[Condition]
+Start=<weather>
+End=</weather>
+Unit=Cond
+
+[Temperature]
+Start=<temp_f>
+End=</temp_f>
+Unit=F
+
+[Humidity]
+Start=<relative_humidity>
+End=</relative_humidity>
+
+[Wind Direction]
+Start=<wind_dir>
+End=</wind_dir>
+
+[Wind Direction DEG]
+Start=<wind_degrees>
+End=</wind_degrees>
+Unit=Deg
+
+[Wind Speed]
+Start=<wind_mph>
+End=</wind_mph>
+Unit=mph
+
+[Wind Gust]
+Start=<wind_gust_mph>
+End=</wind_gust_mph>
+Unit=mph
+
+[Pressure]
+Start=<pressure_in>
+End=</pressure_in>
+Unit=in
+
+[Pressure Tendency]
+Set Data="Unknown"
+
+[Dewpoint]
+Start=<dewpoint_f>
+End=</dewpoint_f>
+Unit=F
+
+[Feel]
+Set Data=[Temperature]
+Url=1
+
+[Feel]
+Start=<heat_index_f>
+End=</heat_index_f>
+Unit=F
+
+[Feel]
+Start=<windchill_f>
+End=</windchill_f>
+Unit=F
+
+[Visibility]
+Start=<visibility_mi>
+End=</visibility_mi>
+Unit=miles
+
+[Forecast Day 1 Text]
+Start=<fcttext>
+End=</fcttext>
+
+[Forecast Day 2 Text]
+Start=<fcttext>
+End=</fcttext>
+
+[Forecast Day 1 Day]
+Start=<weekday>
+End=</weekday>
+
+[Timezone]
+Start=<tz_short>
+End=</tz_short>
+
+[Forecast Day 1 High]
+Start=<fahrenheit>
+End=</fahrenheit>
+Unit=F
+
+[Forecast Day 1 Low]
+Start=<fahrenheit>
+End=</fahrenheit>
+Unit=F
+
+[Forecast Day 1 Condition]
+Start=<conditions>
+End=</conditions>
+Unit=Cond
+
+[Forecast Day 2 Day]
+Start=<weekday>
+End=</weekday>
+
+[Forecast Day 2 High]
+Start=<fahrenheit>
+End=</fahrenheit>
+Unit=F
+
+[Forecast Day 2 Low]
+Start=<fahrenheit>
+End=</fahrenheit>
+Unit=F
+
+[Forecast Day 2 Condition]
+Start=<conditions>
+End=</conditions>
+Unit=Cond
+
+[Forecast Day 3 Day]
+Start=<weekday>
+End=</weekday>
+
+[Forecast Day 3 High]
+Start=<fahrenheit>
+End=</fahrenheit>
+Unit=F
+
+[Forecast Day 3 Low]
+Start=<fahrenheit>
+End=</fahrenheit>
+Unit=F
+
+[Forecast Day 3 Condition]
+Start=<conditions>
+End=</conditions>
+Unit=Cond
+
+[Forecast Day 4 Day]
+Start=<weekday>
+End=</weekday>
+
+[Forecast Day 4 High]
+Start=<fahrenheit>
+End=</fahrenheit>
+Unit=F
+
+[Forecast Day 4 Low]
+Start=<fahrenheit>
+End=</fahrenheit>
+Unit=F
+
+[Forecast Day 4 Condition]
+Start=<conditions>
+End=</conditions>
+Unit=Cond
+
+[Forecast Day 5 Day]
+Start=<weekday>
+End=</weekday>
+
+[Forecast Day 5 High]
+Start=<fahrenheit>
+End=</fahrenheit>
+Unit=F
+
+[Forecast Day 5 Low]
+Start=<fahrenheit>
+End=</fahrenheit>
+Unit=F
+
+[Forecast Day 5 Condition]
+Start=<conditions>
+End=</conditions>
+Unit=Cond
+
+[Forecast Day 6 Day]
+Start=<weekday>
+End=</weekday>
+
+[Forecast Day 6 High]
+Start=<fahrenheit>
+End=</fahrenheit>
+Unit=F
+
+[Forecast Day 6 Low]
+Start=<fahrenheit>
+End=</fahrenheit>
+Unit=F
+
+[Forecast Day 6 Condition]
+Start=<conditions>
+End=</conditions>
+Unit=Cond
+
+[High]
+Set Data=[Forecast Day 1 High]
+
+[Low]
+Set Data=[Forecast Day 1 Low]
+
+[Forecast Day 1]
+Set Data=[Forecast Day 1 Day] & ": " & [Forecast Day 1 Condition] & ", " & [Forecast Day 1 High] & "/" & [Forecast Day 1 Low]
+
+[Forecast Day 2]
+Set Data=[Forecast Day 2 Day] & ": " & [Forecast Day 2 Condition] & ", " & [Forecast Day 2 High] & "/" & [Forecast Day 2 Low]
+
+[Forecast Day 3]
+Set Data=[Forecast Day 3 Day] & ": " & [Forecast Day 3 Condition] & ", " & [Forecast Day 3 High] & "/" & [Forecast Day 3 Low]
+
+[Forecast Day 4]
+Set Data=[Forecast Day 4 Day] & ": " & [Forecast Day 4 Condition] & ", " & [Forecast Day 4 High] & "/" & [Forecast Day 4 Low]
+
+[Forecast Day 5]
+Set Data=[Forecast Day 5 Day] & ": " & [Forecast Day 5 Condition] & ", " & [Forecast Day 5 High] & "/" & [Forecast Day 5 Low]
+
+[Forecast Day 6]
+Set Data=[Forecast Day 6 Day] & ": " & [Forecast Day 6 Condition] & ", " & [Forecast Day 6 High] & "/" & [Forecast Day 6 Low]
+
+[Moon]
+Start=<percentIlluminated>
+End=</percentIlluminated>
+Unit=%
+
+[LTH]
+Start=<hour>
+End=</hour>
+Hidden=True
+
+[LTM]
+Start=<minute>
+End=</minute>
+Hidden=True
+
+[Local Time]
+Set Data=[LTH] & ":" & [LTM] & " " & [Timezone]
+
+[SSTH]
+Start=<hour>
+End=</hour>
+Hidden=True
+
+[SSTM]
+Start=<minute>
+End=</minute>
+Hidden=True
+
+[Sunset]
+Set Data=[SSTH] & ":" & [SSTM] & " " & [Timezone]
+
+[SRTH]
+Start=<hour>
+End=</hour>
+Hidden=True
+
+[SRTM]
+Start=<minute>
+End=</minute>
+Hidden=True
+
+[Sunrise]
+Set Data=[SRTH] & ":" & [SRTM] & " " & [Timezone]
+
+[ID Search]
+Available=TRUE
+Search URL=http://api.wunderground.com/auto/wui/geo/WXCurrentObXML/%s.html
+Not Found Str=Search not found
+Name Start=type=<full>
+Name End=</full>
+
+[Name Search]
+Single Result=TRUE
+Multiple Result=TRUE
+Search URL=http://api.wunderground.com/auto/wui/geo/GeoLookupXML/index.xml?query=%s
+Not Found Str=Search not found
+Single Result Str=<requesturl>
+Single First=Name
+Single Name Start=<city>
+Single Name End=</city>
+Single ID Start=<requesturl>/
+Single ID End=.html
+Mult First=Name
+Mult Name Start=<name>
+Mult Name End=</name>
+Mult ID Start=<link>/
+Mult ID End=.html
diff --git a/protocols/Weather/proto_weather/proto_weather.vcxproj b/protocols/Weather/proto_weather/proto_weather.vcxproj
new file mode 100644
index 0000000000..abd20e124a
--- /dev/null
+++ b/protocols/Weather/proto_weather/proto_weather.vcxproj
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <ItemGroup Label="ProjectConfigurations">
+ <ProjectConfiguration Include="Debug|Win32">
+ <Configuration>Debug</Configuration>
+ <Platform>Win32</Platform>
+ </ProjectConfiguration>
+ <ProjectConfiguration Include="Debug|x64">
+ <Configuration>Debug</Configuration>
+ <Platform>x64</Platform>
+ </ProjectConfiguration>
+ <ProjectConfiguration Include="Release|Win32">
+ <Configuration>Release</Configuration>
+ <Platform>Win32</Platform>
+ </ProjectConfiguration>
+ <ProjectConfiguration Include="Release|x64">
+ <Configuration>Release</Configuration>
+ <Platform>x64</Platform>
+ </ProjectConfiguration>
+ </ItemGroup>
+ <PropertyGroup Label="Globals">
+ <ProjectName>Proto_Weather</ProjectName>
+ <ProjectGuid>{B2F4BA6C-1BD6-4A50-A706-DCBC6A5D439B}</ProjectGuid>
+ </PropertyGroup>
+ <ImportGroup Label="PropertySheets">
+ <Import Project="$(ProjectDir)..\..\..\build\vc.common\icons.props" />
+ </ImportGroup>
+</Project> \ No newline at end of file
diff --git a/protocols/Weather/proto_weather/proto_weather.vcxproj.filters b/protocols/Weather/proto_weather/proto_weather.vcxproj.filters
new file mode 100644
index 0000000000..28f81e7f1b
--- /dev/null
+++ b/protocols/Weather/proto_weather/proto_weather.vcxproj.filters
@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <Import Project="$(ProjectDir)..\..\..\build\vc.common\common.filters" />
+</Project> \ No newline at end of file
diff --git a/protocols/Weather/proto_weather/res/Cloud.ico b/protocols/Weather/proto_weather/res/Cloud.ico
new file mode 100644
index 0000000000..52b8842c76
--- /dev/null
+++ b/protocols/Weather/proto_weather/res/Cloud.ico
Binary files differ
diff --git a/protocols/Weather/proto_weather/res/FOG.ico b/protocols/Weather/proto_weather/res/FOG.ico
new file mode 100644
index 0000000000..598889503e
--- /dev/null
+++ b/protocols/Weather/proto_weather/res/FOG.ico
Binary files differ
diff --git a/protocols/Weather/proto_weather/res/LIGHT.ico b/protocols/Weather/proto_weather/res/LIGHT.ico
new file mode 100644
index 0000000000..bff56d15d2
--- /dev/null
+++ b/protocols/Weather/proto_weather/res/LIGHT.ico
Binary files differ
diff --git a/protocols/Weather/proto_weather/res/NA.ico b/protocols/Weather/proto_weather/res/NA.ico
new file mode 100644
index 0000000000..47840dafbb
--- /dev/null
+++ b/protocols/Weather/proto_weather/res/NA.ico
Binary files differ
diff --git a/protocols/Weather/proto_weather/res/PCLOUDY.ico b/protocols/Weather/proto_weather/res/PCLOUDY.ico
new file mode 100644
index 0000000000..eef4eccb59
--- /dev/null
+++ b/protocols/Weather/proto_weather/res/PCLOUDY.ico
Binary files differ
diff --git a/protocols/Weather/proto_weather/res/RAIN.ico b/protocols/Weather/proto_weather/res/RAIN.ico
new file mode 100644
index 0000000000..4a43c4c62b
--- /dev/null
+++ b/protocols/Weather/proto_weather/res/RAIN.ico
Binary files differ
diff --git a/protocols/Weather/proto_weather/res/RSHOWER.ico b/protocols/Weather/proto_weather/res/RSHOWER.ico
new file mode 100644
index 0000000000..dcb98b80a1
--- /dev/null
+++ b/protocols/Weather/proto_weather/res/RSHOWER.ico
Binary files differ
diff --git a/protocols/Weather/proto_weather/res/SNOW.ico b/protocols/Weather/proto_weather/res/SNOW.ico
new file mode 100644
index 0000000000..3cc60a0817
--- /dev/null
+++ b/protocols/Weather/proto_weather/res/SNOW.ico
Binary files differ
diff --git a/protocols/Weather/proto_weather/res/SSHOWER.ico b/protocols/Weather/proto_weather/res/SSHOWER.ico
new file mode 100644
index 0000000000..f2e2e45a02
--- /dev/null
+++ b/protocols/Weather/proto_weather/res/SSHOWER.ico
Binary files differ
diff --git a/protocols/Weather/proto_weather/res/SUN.ico b/protocols/Weather/proto_weather/res/SUN.ico
new file mode 100644
index 0000000000..c5a1206468
--- /dev/null
+++ b/protocols/Weather/proto_weather/res/SUN.ico
Binary files differ
diff --git a/protocols/Weather/proto_weather/res/resource.rc b/protocols/Weather/proto_weather/res/resource.rc
new file mode 100644
index 0000000000..5341c6dbf8
--- /dev/null
+++ b/protocols/Weather/proto_weather/res/resource.rc
@@ -0,0 +1,41 @@
+//Microsoft Developer Studio generated resource script.
+//
+
+#define APSTUDIO_READONLY_SYMBOLS
+/////////////////////////////////////////////////////////////////////////////
+//
+// Generated from the TEXTINCLUDE 2 resource.
+//
+#include "winres.h"
+/////////////////////////////////////////////////////////////////////////////
+#undef APSTUDIO_READONLY_SYMBOLS
+
+/////////////////////////////////////////////////////////////////////////////
+// English (U.S.) resources
+
+#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU)
+#ifdef _WIN32
+LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
+#pragma code_page(1252)
+#endif //_WIN32
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Icon
+//
+
+// Icon with lowest ID value placed first to ensure application icon
+// remains consistent on all systems.
+104 ICON "SUN.ico"
+105 ICON "NA.ico"
+128 ICON "PCLOUDY.ico"
+129 ICON "RSHOWER.ico"
+130 ICON "LIGHT.ico"
+131 ICON "RAIN.ico"
+158 ICON "SNOW.ico"
+159 ICON "CLOUD.ico"
+1002 ICON "SSHOWER.ico"
+1003 ICON "FOG.ico"
+
+#endif // English (U.S.) resources
+///////////////////////////////////////////////////////////////////////////// \ No newline at end of file
diff --git a/protocols/Weather/res/Version.rc b/protocols/Weather/res/Version.rc
new file mode 100644
index 0000000000..5a5ddd63ed
--- /dev/null
+++ b/protocols/Weather/res/Version.rc
@@ -0,0 +1,9 @@
+// Microsoft Visual C++ generated resource script.
+//
+#ifdef APSTUDIO_INVOKED
+#error this file is not editable by Microsoft Visual C++
+#endif //APSTUDIO_INVOKED
+
+#include "..\src\version.h"
+
+#include "..\..\build\Version.rc"
diff --git a/protocols/Weather/res/brief.ico b/protocols/Weather/res/brief.ico
new file mode 100644
index 0000000000..20b5fa1dd1
--- /dev/null
+++ b/protocols/Weather/res/brief.ico
Binary files differ
diff --git a/protocols/Weather/res/disabled.ico b/protocols/Weather/res/disabled.ico
new file mode 100644
index 0000000000..9993103efc
--- /dev/null
+++ b/protocols/Weather/res/disabled.ico
Binary files differ
diff --git a/protocols/Weather/res/edit.ico b/protocols/Weather/res/edit.ico
new file mode 100644
index 0000000000..7c6b07c71a
--- /dev/null
+++ b/protocols/Weather/res/edit.ico
Binary files differ
diff --git a/protocols/Weather/res/icon.ico b/protocols/Weather/res/icon.ico
new file mode 100644
index 0000000000..eef4eccb59
--- /dev/null
+++ b/protocols/Weather/res/icon.ico
Binary files differ
diff --git a/protocols/Weather/res/log.ico b/protocols/Weather/res/log.ico
new file mode 100644
index 0000000000..fc4bf7251b
--- /dev/null
+++ b/protocols/Weather/res/log.ico
Binary files differ
diff --git a/protocols/Weather/res/map.ico b/protocols/Weather/res/map.ico
new file mode 100644
index 0000000000..16b359b132
--- /dev/null
+++ b/protocols/Weather/res/map.ico
Binary files differ
diff --git a/protocols/Weather/res/more.ico b/protocols/Weather/res/more.ico
new file mode 100644
index 0000000000..bfd03e8bac
--- /dev/null
+++ b/protocols/Weather/res/more.ico
Binary files differ
diff --git a/protocols/Weather/res/popup.ico b/protocols/Weather/res/popup.ico
new file mode 100644
index 0000000000..5b3fe4e65b
--- /dev/null
+++ b/protocols/Weather/res/popup.ico
Binary files differ
diff --git a/protocols/Weather/res/popup_no.ico b/protocols/Weather/res/popup_no.ico
new file mode 100644
index 0000000000..2b298a96ea
--- /dev/null
+++ b/protocols/Weather/res/popup_no.ico
Binary files differ
diff --git a/protocols/Weather/res/resource.rc b/protocols/Weather/res/resource.rc
new file mode 100644
index 0000000000..9841527018
--- /dev/null
+++ b/protocols/Weather/res/resource.rc
@@ -0,0 +1,427 @@
+// Microsoft Visual C++ generated resource script.
+//
+#include "..\src\resource.h"
+
+#define APSTUDIO_READONLY_SYMBOLS
+/////////////////////////////////////////////////////////////////////////////
+//
+// Generated from the TEXTINCLUDE 2 resource.
+//
+#include <winres.h>
+
+/////////////////////////////////////////////////////////////////////////////
+#undef APSTUDIO_READONLY_SYMBOLS
+
+/////////////////////////////////////////////////////////////////////////////
+// Немецкий (Германия) resources
+
+#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_DEU)
+LANGUAGE LANG_GERMAN, SUBLANG_GERMAN
+#pragma code_page(1252)
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Dialog
+//
+
+IDD_BRIEF DIALOGEX 0, 0, 245, 231
+STYLE DS_SETFONT | DS_SETFOREGROUND | DS_3DLOOK | DS_FIXEDSYS | DS_CENTER | WS_MINIMIZEBOX | WS_MAXIMIZEBOX | WS_POPUP | WS_VISIBLE | WS_CAPTION | WS_SYSMENU | WS_THICKFRAME
+EXSTYLE WS_EX_WINDOWEDGE | WS_EX_CONTROLPARENT
+FONT 8, "MS Shell Dlg", 0, 0, 0x1
+BEGIN
+ CONTROL "",IDC_HEADERBAR,"MHeaderbarCtrl",0x0,0,0,245,25
+ CONTROL "",IDC_MTEXT,"RichEdit50W",NOT WS_VISIBLE | WS_VSCROLL | WS_TABSTOP | 0x804,0,25,244,180,WS_EX_STATICEDGE
+ CONTROL "List1",IDC_DATALIST,"SysListView32",LVS_REPORT | LVS_SINGLESEL | LVS_SORTASCENDING | WS_TABSTOP,0,25,244,180,WS_EX_STATICEDGE
+ PUSHBUTTON "Update",IDC_MUPDATE,10,213,48,13
+ PUSHBUTTON "Brief Info",IDC_MTOGGLE,79,213,48,13
+ PUSHBUTTON "Webpage",IDC_MWEBPAGE,132,213,48,13
+ DEFPUSHBUTTON "Close",IDCANCEL,184,213,48,13
+END
+
+IDD_OPTIONS DIALOGEX 0, 0, 306, 222
+STYLE DS_SETFONT | DS_FIXEDSYS | WS_CHILD
+EXSTYLE WS_EX_CONTROLPARENT
+FONT 8, "MS Shell Dlg", 0, 0, 0x1
+BEGIN
+ GROUPBOX "Options",IDC_STATIC,3,0,299,70,WS_GROUP
+ CONTROL "Update weather information on startup",IDC_STARTUPUPD,
+ "Button",BS_AUTOCHECKBOX | WS_TABSTOP,8,12,286,8
+ CONTROL "Update weather information every",IDC_UPDATE,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,8,23,206,8
+ EDITTEXT IDC_UPDATETIME,223,21,33,12,ES_AUTOHSCROLL | ES_NUMBER | NOT WS_BORDER,WS_EX_CLIENTEDGE | WS_EX_STATICEDGE
+ LTEXT "minutes",IDC_STATIC,260,23,39,8
+ CONTROL "Consider weather info updated only when condition and temperature are changed",IDC_UPDCONDCHG,
+ "Button",BS_AUTOCHECKBOX | WS_TABSTOP,8,34,286,8
+ CONTROL "Remove old data when updating",IDC_REMOVEOLD,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,8,45,286,8
+ CONTROL "Make the contact italic when weather alert is issued",IDC_MAKEI,
+ "Button",BS_AUTOCHECKBOX | WS_TABSTOP,8,56,286,8
+ GROUPBOX "Modes",IDC_STATIC,3,70,300,37
+ CONTROL "Use weather condition as protocol status",IDC_PROTOCOND,
+ "Button",BS_AUTOCHECKBOX | WS_TABSTOP,8,81,278,8
+ CONTROL "Avatar only mode",IDC_DISCONDICON,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,8,91,278,8
+ GROUPBOX "Units",IDC_STATIC,3,107,299,80,WS_GROUP
+ LTEXT "Temperature",IDC_STATIC,8,116,53,8
+ CONTROL "Celsius",IDC_T1,"Button",BS_AUTORADIOBUTTON,65,116,40,8
+ CONTROL "Fahrenheit",IDC_T2,"Button",BS_AUTORADIOBUTTON,120,116,47,8
+ LTEXT "Degree sign:",IDC_STATIC,227,116,55,8
+ EDITTEXT IDC_DEGREE,283,116,13,12,ES_AUTOHSCROLL | NOT WS_BORDER,WS_EX_CLIENTEDGE | WS_EX_STATICEDGE
+ LTEXT "Wind",IDC_STATIC,8,125,53,8
+ CONTROL "km/h",IDC_W1,"Button",BS_AUTORADIOBUTTON,65,125,34,8
+ CONTROL "m/s",IDC_W2,"Button",BS_AUTORADIOBUTTON,120,125,34,8
+ CONTROL "mph",IDC_W3,"Button",BS_AUTORADIOBUTTON,176,125,34,8
+ CONTROL "knots",IDC_W4,"Button",BS_AUTORADIOBUTTON,232,125,49,8
+ LTEXT "Visibility",IDC_STATIC,8,134,53,8
+ CONTROL "km",IDC_V1,"Button",BS_AUTORADIOBUTTON,65,134,34,8
+ CONTROL "miles",IDC_V2,"Button",BS_AUTORADIOBUTTON,120,134,34,8
+ LTEXT "Pressure",IDC_STATIC,8,143,53,8
+ CONTROL "kPa",IDC_P1,"Button",BS_AUTORADIOBUTTON,65,143,38,8
+ CONTROL "mb (hPa)",IDC_P2,"Button",BS_AUTORADIOBUTTON,120,143,56,8
+ CONTROL "inches",IDC_P3,"Button",BS_AUTORADIOBUTTON,176,143,38,8
+ CONTROL "mm Hg (torr)",IDC_P4,"Button",BS_AUTORADIOBUTTON,232,143,62,8
+ LTEXT "Day/Month",IDC_STATIC,8,153,53,8
+ CONTROL "No change",IDC_D1,"Button",BS_AUTORADIOBUTTON,65,153,52,8
+ CONTROL "2 chars",IDC_D2,"Button",BS_AUTORADIOBUTTON,120,153,56,8
+ CONTROL "3 chars",IDC_D3,"Button",BS_AUTORADIOBUTTON,176,153,56,8
+ LTEXT "Elevation",IDC_STATIC,8,163,53,8
+ CONTROL "ft",IDC_E1,"Button",BS_AUTORADIOBUTTON,65,163,34,8
+ CONTROL "m",IDC_E2,"Button",BS_AUTORADIOBUTTON,120,163,34,8
+ CONTROL "Do not append units to values",IDC_DONOTAPPUNITS,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,8,174,144,8
+ CONTROL "Do not display fractional values",IDC_NOFRAC,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,155,174,139,8
+ GROUPBOX "Frame",IDC_STATIC,3,187,300,29
+ EDITTEXT IDC_AVATARSIZE,8,196,36,14,ES_AUTOHSCROLL | ES_NUMBER | NOT WS_BORDER,WS_EX_CLIENTEDGE | WS_EX_STATICEDGE
+ CONTROL "",IDC_AVATARSPIN,"msctls_updown32",UDS_SETBUDDYINT | UDS_ALIGNRIGHT | UDS_AUTOBUDDY | UDS_ARROWKEYS | UDS_NOTHOUSANDS,43,196,11,14
+ LTEXT "Avatar size",IDC_STATIC,60,200,95,9
+END
+
+IDD_EDIT DIALOGEX 0, 0, 241, 226
+STYLE DS_SETFONT | DS_MODALFRAME | DS_SETFOREGROUND | DS_3DLOOK | DS_FIXEDSYS | DS_CENTER | WS_POPUP | WS_VISIBLE | WS_CAPTION | WS_SYSMENU
+EXSTYLE WS_EX_CONTROLPARENT
+CAPTION "Edit Weather Station"
+FONT 8, "MS Shell Dlg", 0, 0, 0x1
+BEGIN
+ GROUPBOX "Weather Station",IDC_STATIC,5,7,231,46
+ LTEXT "City name",IDC_STATIC,12,21,57,8,SS_CENTERIMAGE
+ EDITTEXT IDC_NAME,69,19,146,12,ES_AUTOHSCROLL
+ LTEXT "ID",IDC_STATIC,12,37,57,8,SS_CENTERIMAGE
+ EDITTEXT IDC_ID,69,35,146,12,ES_AUTOHSCROLL
+ GROUPBOX "Log Information",IDC_STATIC,5,55,231,53
+ CONTROL "Use internal history",IDC_Internal,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,12,68,218,8
+ CONTROL "Use external file",IDC_External,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,12,80,98,8
+ CONTROL "Overwrite file upon update",IDC_Overwrite,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,119,80,111,8
+ LTEXT "Path:",IDC_STATIC,25,93,37,8,SS_CENTERIMAGE
+ EDITTEXT IDC_LOG,69,91,146,12,ES_AUTOHSCROLL | ES_READONLY
+ CONTROL "6",IDC_BROWSE,"MButtonClass",WS_TABSTOP,217,91,13,12,WS_EX_NOACTIVATE | 0x10000000L
+ GROUPBOX "Link Settings",IDC_STATIC,5,110,231,44
+ LTEXT "More Info URL",IDC_STATIC,12,123,57,8
+ EDITTEXT IDC_IURL,69,121,131,12,ES_AUTOHSCROLL
+ CONTROL "6",IDC_VIEW1,"MButtonClass",WS_TABSTOP,202,121,13,12,WS_EX_NOACTIVATE | 0x10000000L
+ CONTROL "6",IDC_RESET1,"MButtonClass",WS_TABSTOP,217,121,13,12,WS_EX_NOACTIVATE | 0x10000000L
+ LTEXT "Weather Map",IDC_STATIC,12,138,57,8
+ EDITTEXT IDC_MURL,69,137,131,12,ES_AUTOHSCROLL
+ CONTROL "6",IDC_VIEW2,"MButtonClass",WS_TABSTOP,202,137,13,12,WS_EX_NOACTIVATE | 0x10000000L
+ CONTROL "6",IDC_RESET2,"MButtonClass",WS_TABSTOP,217,137,13,12,WS_EX_NOACTIVATE | 0x10000000L
+ GROUPBOX "Other Options",IDC_STATIC,5,157,231,46
+ CONTROL "Set as default station",IDC_DEFA,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,12,168,218,8
+ CONTROL "Disable automatic update for this station",IDC_DAutoUpdate,
+ "Button",BS_AUTOCHECKBOX | WS_TABSTOP,12,179,218,8
+ CONTROL "Disable Popup for this station",IDC_DPop,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,12,190,218,8
+ PUSHBUTTON "Change",IDC_CHANGE,57,207,46,14
+ DEFPUSHBUTTON "Cancel",IDCANCEL,136,207,46,14
+ CONTROL "",IDC_SVCINFO,"MButtonClass",WS_TABSTOP,217,35,13,12,WS_EX_NOACTIVATE | 0x10000000L
+ CONTROL "",IDC_GETNAME,"MButtonClass",WS_TABSTOP,217,19,13,12,WS_EX_NOACTIVATE | 0x10000000L
+END
+
+IDD_POPUP DIALOGEX 0, 0, 312, 236
+STYLE DS_SETFONT | DS_FIXEDSYS | WS_CHILD
+EXSTYLE WS_EX_CONTROLPARENT
+FONT 8, "MS Shell Dlg", 0, 0, 0x1
+BEGIN
+ GROUPBOX "Popup Options",IDC_STATIC,4,5,158,54
+ CONTROL "Enable popups",IDC_E,"Button",BS_AUTOCHECKBOX | BS_NOTIFY | WS_TABSTOP,15,15,143,9
+ CONTROL "Popup only when condition changes",IDC_CH,"Button",BS_AUTOCHECKBOX | BS_NOTIFY | WS_TABSTOP,15,44,140,10
+ GROUPBOX "Colors",IDC_STATIC,168,5,139,54
+ CONTROL "",IDC_BGCOLOUR,"ColourPicker",WS_TABSTOP,177,16,39,11
+ LTEXT "Background color",IDC_STATIC,223,18,78,8,SS_CENTERIMAGE
+ CONTROL "",IDC_TEXTCOLOUR,"ColourPicker",WS_TABSTOP,177,30,39,11
+ LTEXT "Text color",IDC_STATIC,223,31,80,8,SS_CENTERIMAGE
+ CONTROL "Use Windows colors",IDC_USEWINCOLORS,"Button",BS_AUTOCHECKBOX | BS_NOTIFY | WS_TABSTOP,177,43,125,13
+ GROUPBOX "Popup Actions",IDC_STATIC,4,63,157,46
+ LTEXT "Left Click",IDC_STATIC,13,77,42,8
+ CONTROL "",IDC_LeftClick,"MButtonClass",WS_TABSTOP,59,76,95,9,WS_EX_NOACTIVATE | 0x10000000L
+ LTEXT "Right Click",IDC_STATIC,13,93,42,8
+ CONTROL "",IDC_RightClick,"MButtonClass",WS_TABSTOP,59,92,95,9,WS_EX_NOACTIVATE | 0x10000000L
+ GROUPBOX "Popup Delay",IDC_STATIC,167,63,141,46
+ CONTROL "Delay",IDC_PD3,"Button",BS_AUTORADIOBUTTON,177,74,53,8
+ EDITTEXT IDC_DELAY,233,73,36,12,ES_RIGHT | ES_AUTOHSCROLL | ES_NUMBER | NOT WS_BORDER,WS_EX_STATICEDGE
+ LTEXT "seconds",IDC_STATIC,272,73,34,10
+ CONTROL "From popup plugin",IDC_PD1,"Button",BS_AUTORADIOBUTTON,177,85,110,8
+ CONTROL "Permanent",IDC_PD2,"Button",BS_AUTORADIOBUTTON,177,96,110,8
+ GROUPBOX "Popup Text",IDC_STATIC,3,112,305,121
+ LTEXT "Popup Title",IDC_STATIC,15,124,56,9
+ EDITTEXT IDC_PTitle,72,121,231,12,ES_AUTOHSCROLL
+ LTEXT "Popup Text",IDC_STATIC,15,138,55,9
+ EDITTEXT IDC_PText,72,136,231,92,ES_MULTILINE | ES_AUTOVSCROLL | ES_WANTRETURN | WS_VSCROLL
+ CONTROL "Variables",IDC_VAR3,"MButtonClass",WS_TABSTOP,7,153,62,12,WS_EX_NOACTIVATE | 0x10000000L
+ CONTROL "Default",IDC_PDEF,"MButtonClass",WS_TABSTOP,7,175,62,12,WS_EX_NOACTIVATE | 0x10000000L
+ CONTROL "Preview",IDC_PREVIEW,"MButtonClass",WS_TABSTOP,7,197,61,12,WS_EX_NOACTIVATE | 0x10000000L
+ CONTROL "Updates",IDC_POP1,"Button",BS_AUTOCHECKBOX | BS_NOTIFY | WS_TABSTOP,29,24,64,9
+ CONTROL "Alerts",IDC_POP2,"Button",BS_AUTOCHECKBOX | BS_NOTIFY | WS_TABSTOP,29,34,64,9
+ CONTROL "Errors",IDC_W,"Button",BS_AUTOCHECKBOX | BS_NOTIFY | WS_TABSTOP,97,24,54,9
+END
+
+IDD_TEXTOPT DIALOGEX 0, 0, 309, 233
+STYLE DS_SETFONT | DS_FIXEDSYS | WS_CHILD
+EXSTYLE WS_EX_CONTROLPARENT
+FONT 8, "MS Shell Dlg", 0, 0, 0x1
+BEGIN
+ CONTROL "Contact List",IDC_TM1,"MButtonClass",WS_TABSTOP | 0x100,2,16,77,9,WS_EX_WINDOWEDGE | WS_EX_NOACTIVATE | 0x10000000L
+ EDITTEXT IDC_CTEXT,80,15,125,12,ES_AUTOHSCROLL
+ CONTROL "Brief Info Title",IDC_TM2,"MButtonClass",WS_TABSTOP,2,3,77,9,WS_EX_WINDOWEDGE | WS_EX_NOACTIVATE | 0x10000000L
+ EDITTEXT IDC_BTITLE,80,1,226,12,ES_AUTOHSCROLL
+ CONTROL "Brief Info",IDC_TM3,"MButtonClass",WS_TABSTOP,57,41,77,9,WS_EX_WINDOWEDGE | WS_EX_NOACTIVATE | 0x10000000L
+ EDITTEXT IDC_BTEXT,1,51,203,41,ES_MULTILINE | ES_WANTRETURN | WS_VSCROLL
+ CONTROL "Note Text",IDC_TM4,"MButtonClass",WS_TABSTOP,57,94,77,9,WS_EX_WINDOWEDGE | WS_EX_NOACTIVATE | 0x10000000L
+ EDITTEXT IDC_NTEXT,1,104,203,44,ES_MULTILINE | ES_WANTRETURN | WS_VSCROLL
+ CONTROL "Extra Text",IDC_TM5,"MButtonClass",WS_TABSTOP,57,150,77,9,WS_EX_WINDOWEDGE | WS_EX_NOACTIVATE | 0x10000000L
+ EDITTEXT IDC_XTEXT,2,160,202,45,ES_MULTILINE | ES_WANTRETURN | WS_VSCROLL
+ CONTROL "External Log",IDC_TM6,"MButtonClass",WS_TABSTOP,2,208,77,9,WS_EX_WINDOWEDGE | WS_EX_NOACTIVATE | 0x10000000L
+ EDITTEXT IDC_ETEXT,80,206,183,12,ES_AUTOHSCROLL
+ CONTROL "History Log",IDC_TM7,"MButtonClass",WS_TABSTOP,2,221,77,9,WS_EX_WINDOWEDGE | WS_EX_NOACTIVATE | 0x10000000L
+ EDITTEXT IDC_HTEXT,80,219,183,12,ES_AUTOHSCROLL
+ GROUPBOX "Variable List",IDC_STATIC,207,14,99,191
+ LTEXT "",IDC_VARLIST,213,25,86,157
+ CONTROL "More Variables",IDC_MORE,"MButtonClass",WS_TABSTOP,216,187,81,15,WS_EX_WINDOWEDGE | WS_EX_NOACTIVATE | 0x10000000L
+ CONTROL "Reset",IDC_RESET,"MButtonClass",WS_TABSTOP,266,208,40,21,WS_EX_WINDOWEDGE | WS_EX_NOACTIVATE | 0x10000000L
+ EDITTEXT IDC_BTITLE2,80,28,125,12,ES_AUTOHSCROLL
+ CONTROL "Status Message",IDC_TM8,"MButtonClass",WS_TABSTOP | 0x100,2,29,77,9,WS_EX_WINDOWEDGE | WS_EX_NOACTIVATE | 0x10000000L
+END
+
+IDD_USERINFO DIALOGEX 0, 0, 222, 132
+STYLE DS_SETFONT | DS_FIXEDSYS | DS_CONTROL | WS_CHILD
+EXSTYLE WS_EX_CONTROLPARENT
+FONT 8, "MS Shell Dlg", 0, 0, 0x1
+BEGIN
+ ICON "",IDC_INFOICON,16,15,20,20,SS_CENTERIMAGE
+ LTEXT "",IDC_INFO1,12,8,193,10
+ LTEXT "Sunset",IDC_STATIC,112,58,54,8
+ LTEXT "Feel-like",IDC_STATIC,12,46,39,8
+ LTEXT "Today's Low",IDC_STATIC,112,82,54,8
+ LTEXT "Wind",IDC_STATIC,12,70,39,8
+ LTEXT "Today's High",IDC_STATIC,112,70,54,8
+ LTEXT "Sunrise",IDC_STATIC,112,46,54,8
+ LTEXT "",IDC_INFO11,12,121,195,9
+ LTEXT "Dew point",IDC_STATIC,12,94,39,8
+ LTEXT "Pressure",IDC_STATIC,12,58,39,8
+ GROUPBOX "",IDC_STATIC,4,36,211,84
+ GROUPBOX "",IDC_STATIC,4,1,211,35
+ EDITTEXT IDC_INFO2,42,20,165,12,ES_AUTOHSCROLL | ES_READONLY | NOT WS_BORDER
+ EDITTEXT IDC_INFO3,51,46,57,12,ES_AUTOHSCROLL | ES_READONLY | NOT WS_BORDER
+ EDITTEXT IDC_INFO4,51,58,57,12,ES_AUTOHSCROLL | ES_READONLY | NOT WS_BORDER
+ EDITTEXT IDC_INFO5,51,70,56,12,ES_AUTOHSCROLL | ES_READONLY | NOT WS_BORDER
+ EDITTEXT IDC_INFO6,51,94,56,12,ES_AUTOHSCROLL | ES_READONLY | NOT WS_BORDER
+ EDITTEXT IDC_INFO7,166,46,41,12,ES_AUTOHSCROLL | ES_READONLY | NOT WS_BORDER
+ EDITTEXT IDC_INFO8,166,58,41,12,ES_AUTOHSCROLL | ES_READONLY | NOT WS_BORDER
+ EDITTEXT IDC_INFO9,166,70,41,12,ES_AUTOHSCROLL | ES_READONLY | NOT WS_BORDER
+ EDITTEXT IDC_INFO10,166,82,41,12,ES_AUTOHSCROLL | ES_READONLY | NOT WS_BORDER
+ LTEXT "Humidity",IDC_STATIC,12,82,39,8
+ EDITTEXT IDC_INFO12,51,82,56,12,ES_AUTOHSCROLL | ES_READONLY | NOT WS_BORDER
+ LTEXT "Visibility",IDC_STATIC,12,106,39,8
+ EDITTEXT IDC_INFO13,51,106,56,12,ES_AUTOHSCROLL | ES_READONLY | NOT WS_BORDER
+ CONTROL "More...",IDC_MOREDETAIL,"MButtonClass",WS_TABSTOP,129,104,61,12,WS_EX_WINDOWEDGE | WS_EX_NOACTIVATE | 0x10000000L
+END
+
+IDD_SETUP DIALOGEX 0, 0, 259, 142
+STYLE DS_SETFONT | DS_SETFOREGROUND | DS_3DLOOK | DS_FIXEDSYS | DS_CENTER | WS_MINIMIZEBOX | WS_POPUP | WS_VISIBLE | WS_CAPTION | WS_SYSMENU
+EXSTYLE WS_EX_CONTROLPARENT
+CAPTION "Weather Protocol INI Setup"
+FONT 8, "MS Shell Dlg", 0, 0, 0x1
+BEGIN
+ CONTROL "Install and load your weather ini file here",IDC_HEADERBAR,
+ "MHeaderbarCtrl",0x0,0,0,259,28
+ CTEXT "Weather Protocol cannot find any weather INI file stored in your computer. To setup weather INI and add weather stations, please follow the steps:",IDC_STATIC,11,32,222,26
+ CONTROL "Click here to download a weather ini file from Miranda file listing",IDC_STEP1,
+ "MButtonClass",WS_TABSTOP,5,62,249,12,WS_EX_WINDOWEDGE | 0x800000L
+ CONTROL "Extract the weather ini file from archive to this directory",IDC_STEP2,
+ "MButtonClass",WS_TABSTOP,5,74,249,12,WS_EX_WINDOWEDGE | 0x800000L
+ CONTROL "Click here to load the data from the new ini file into memory",IDC_STEP3,
+ "MButtonClass",WS_TABSTOP,5,86,249,13,WS_EX_WINDOWEDGE | 0x800000L
+ CONTROL "Add new weather station and close this dialog",IDC_STEP4,
+ "MButtonClass",WS_TABSTOP,5,99,249,12,WS_EX_WINDOWEDGE | 0x800000L
+ PUSHBUTTON "Close",IDCANCEL,107,122,48,13
+ CONTROL "",IDC_MFRAME,"Static",SS_ETCHEDHORZ,0,117,259,1
+END
+
+IDD_INFO DIALOGEX 0, 0, 225, 155
+STYLE DS_SETFONT | DS_FIXEDSYS | DS_CONTROL | WS_CHILD | WS_SYSMENU
+EXSTYLE WS_EX_CONTROLPARENT
+FONT 8, "MS Shell Dlg", 400, 0, 0x1
+BEGIN
+ CONTROL "",IDC_INFOLIST,"SysListView32",LVS_REPORT | LVS_SINGLESEL | LVS_ALIGNLEFT | WS_BORDER | WS_TABSTOP,7,7,210,115
+ LTEXT "Total INI files",IDC_STATIC,7,125,95,8
+ LTEXT "Total memory used",IDC_STATIC,7,138,92,8
+ LTEXT "",IDC_INICOUNT,104,125,30,10,SS_SUNKEN
+ LTEXT "",IDC_MEMUSED,104,138,29,10,SS_SUNKEN
+ PUSHBUTTON "Reload INI",IDC_RELOADINI,145,128,64,18
+END
+
+IDD_SEARCHCITY DIALOGEX 0, 0, 114, 55
+STYLE DS_SETFONT | DS_FIXEDSYS | DS_CONTROL | WS_CHILD | WS_SYSMENU
+EXSTYLE WS_EX_TRANSPARENT | WS_EX_CONTROLPARENT
+FONT 8, "MS Shell Dlg", 400, 0, 0x1
+BEGIN
+ EDITTEXT IDC_SEARCHCITY,3,18,103,12,0,WS_EX_CLIENTEDGE
+ LTEXT "City:",IDC_STATIC,6,7,99,8
+END
+
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// DESIGNINFO
+//
+
+#ifdef APSTUDIO_INVOKED
+GUIDELINES DESIGNINFO
+BEGIN
+ IDD_BRIEF, DIALOG
+ BEGIN
+ RIGHTMARGIN, 241
+ BOTTOMMARGIN, 226
+ END
+
+ IDD_OPTIONS, DIALOG
+ BEGIN
+ VERTGUIDE, 8
+ VERTGUIDE, 294
+ BOTTOMMARGIN, 209
+ END
+
+ IDD_POPUP, DIALOG
+ BEGIN
+ RIGHTMARGIN, 306
+ BOTTOMMARGIN, 233
+ END
+
+ IDD_TEXTOPT, DIALOG
+ BEGIN
+ BOTTOMMARGIN, 232
+ END
+
+ IDD_SETUP, DIALOG
+ BEGIN
+ BOTTOMMARGIN, 136
+ END
+
+ IDD_INFO, DIALOG
+ BEGIN
+ LEFTMARGIN, 7
+ RIGHTMARGIN, 217
+ TOPMARGIN, 7
+ BOTTOMMARGIN, 148
+ END
+
+ IDD_SEARCHCITY, DIALOG
+ BEGIN
+ RIGHTMARGIN, 113
+ BOTTOMMARGIN, 54
+ END
+END
+#endif // APSTUDIO_INVOKED
+
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Menu
+//
+
+IDR_PMENU MENU
+BEGIN
+ POPUP "Menu"
+ BEGIN
+ MENUITEM "Dismiss Popup", IDM_M1
+ MENUITEM "Open brief information", IDM_M2
+ MENUITEM "Open complete forecast", IDM_M3
+ MENUITEM "Open weather map", IDM_M4
+ MENUITEM "View history", IDM_M5
+ MENUITEM "Open log file", IDM_M6
+ MENUITEM "Show user menu", IDM_M7
+ MENUITEM "Show user detail", IDM_M8
+ END
+END
+
+IDR_TMENU MENU
+BEGIN
+ POPUP "Menu"
+ BEGIN
+ MENUITEM "To old setting", ID_T1
+ MENUITEM "To default", ID_T2
+ END
+END
+
+IDR_TMMENU MENU
+BEGIN
+ POPUP "Menu"
+ BEGIN
+ MENUITEM "Preview", ID_MPREVIEW
+ MENUITEM "Reset", ID_MRESET
+ END
+END
+
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Icon
+//
+
+// Icon with lowest ID value placed first to ensure application icon
+// remains consistent on all systems.
+IDI_ICON ICON "icon.ico"
+IDI_UPDATE ICON "update.ico"
+IDI_READ ICON "more.ico"
+IDI_S ICON "brief.ico"
+IDI_LOG ICON "log.ico"
+IDI_EDIT ICON "edit.ico"
+IDI_MAP ICON "map.ico"
+IDI_POPUP ICON "popup.ico"
+IDI_NOPOPUP ICON "popup_no.ico"
+IDI_UPDATE2 ICON "update2.ico"
+IDI_DISABLED ICON "disabled.ico"
+
+#ifdef APSTUDIO_INVOKED
+/////////////////////////////////////////////////////////////////////////////
+//
+// TEXTINCLUDE
+//
+
+1 TEXTINCLUDE
+BEGIN
+ "..\\src\\resource.h\0"
+END
+
+2 TEXTINCLUDE
+BEGIN
+ "#include <winres.h>\r\n"
+ "\0"
+END
+
+3 TEXTINCLUDE
+BEGIN
+ "\r\n"
+ "\0"
+END
+
+#endif // APSTUDIO_INVOKED
+
+#endif // Немецкий (Германия) resources
+/////////////////////////////////////////////////////////////////////////////
+
+
+
+#ifndef APSTUDIO_INVOKED
+/////////////////////////////////////////////////////////////////////////////
+//
+// Generated from the TEXTINCLUDE 3 resource.
+//
+
+
+/////////////////////////////////////////////////////////////////////////////
+#endif // not APSTUDIO_INVOKED
+
diff --git a/protocols/Weather/res/update.ico b/protocols/Weather/res/update.ico
new file mode 100644
index 0000000000..0e4fd3171a
--- /dev/null
+++ b/protocols/Weather/res/update.ico
Binary files differ
diff --git a/protocols/Weather/res/update2.ico b/protocols/Weather/res/update2.ico
new file mode 100644
index 0000000000..d702dfc8bd
--- /dev/null
+++ b/protocols/Weather/res/update2.ico
Binary files differ
diff --git a/protocols/Weather/src/resource.h b/protocols/Weather/src/resource.h
new file mode 100644
index 0000000000..eecba58268
--- /dev/null
+++ b/protocols/Weather/src/resource.h
@@ -0,0 +1,175 @@
+//{{NO_DEPENDENCIES}}
+// Microsoft Visual C++ generated include file.
+// Used by ..\res\resource.rc
+//
+#define IDI_ICON 101
+#define IDD_USERINFO 201
+#define IDD_EDIT 202
+#define IDI_DISABLED 203
+#define IDD_POPUP 204
+#define IDD_OPTIONS 205
+#define IDI_LOG 206
+#define IDI_UPDATE2 208
+#define IDI_READ 209
+#define IDI_UPDATE 210
+#define IDI_S 211
+#define IDI_MAP 212
+#define IDR_PMENU 213
+#define IDI_POPUP 214
+#define IDI_NOPOPUP 215
+#define IDD_TEXTOPT 216
+#define IDD_BRIEF 217
+#define IDD_SETUP 218
+#define IDR_TMENU 219
+#define IDR_TMMENU 220
+#define IDI_EDIT 222
+#define IDD_INFO 224
+#define IDD_SEARCHCITY 225
+#define IDC_NAME 2000
+#define IDC_ID 2001
+#define IDC_LOG 2003
+#define IDC_UPDATETIME 2005
+#define IDC_CTEXT 2006
+#define IDC_AVATARSIZE 2006
+#define IDC_UPDATE 2007
+#define IDC_BTITLE 2008
+#define IDC_STARTUPUPD 2008
+#define IDC_CHANGE 2009
+#define IDC_BTITLE2 2009
+#define IDC_USEWINCOLORS 2010
+#define IDC_BTEXT 2011
+#define IDC_CH 2013
+#define IDC_NTEXT 2015
+#define IDC_DEGREE 2016
+#define IDC_E 2017
+#define IDC_W 2018
+#define IDC_POP1 2019
+#define IDC_XTEXT 2020
+#define IDC_POP2 2020
+#define IDC_PText 2021
+#define IDC_PTitle 2023
+#define IDC_Internal 2024
+#define IDC_ETEXT 2025
+#define IDC_DISCONDICON 2025
+#define IDC_External 2026
+#define IDC_DONOTAPPUNITS 2026
+#define IDC_DEFA 2027
+#define IDC_NOFRAC 2027
+#define IDC_HTEXT 2028
+#define IDC_DPop 2029
+#define IDC_DAutoUpdate 2030
+#define IDC_IURL 2032
+#define IDC_MURL 2033
+#define IDC_PROTOCOND 2034
+#define IDC_Overwrite 2035
+#define IDC_UPDCONDCHG 2036
+#define IDC_REMOVEOLD 2037
+#define IDC_MAKEI 2039
+#define IDC_BGCOLOUR 2040
+#define IDC_TEXTCOLOUR 2041
+#define IDC_LeftClick 2042
+#define IDC_PREVIEW 2043
+#define IDC_VAR3 2044
+#define IDC_RightClick 2045
+#define IDC_DELAY 2046
+#define IDC_PDEF 2047
+#define IDC_T1 2048
+#define IDC_T2 2049
+#define IDC_W1 2050
+#define IDC_W2 2051
+#define IDC_W3 2052
+#define IDC_W4 2053
+#define IDC_BROWSE 2054
+#define IDC_VIEW1 2055
+#define IDC_RESET1 2056
+#define IDC_VIEW2 2057
+#define IDC_V1 2058
+#define IDC_V2 2059
+#define IDC_RESET2 2060
+#define IDC_SVCINFO 2061
+#define IDC_GETNAME 2062
+#define IDC_P1 2063
+#define IDC_P2 2064
+#define IDC_P3 2065
+#define IDC_P4 2066
+#define IDC_RESET 2067
+#define IDC_D1 2067
+#define IDC_D2 2068
+#define IDC_D3 2069
+#define IDC_INFO1 2069
+#define IDC_INFOICON 2070
+#define IDC_INFO11 2071
+#define IDC_INFO2 2072
+#define IDC_INFO3 2073
+#define IDC_VARLIST 2074
+#define IDC_INFO4 2075
+#define IDC_INFO5 2076
+#define IDC_PD1 2077
+#define IDC_PD2 2078
+#define IDC_PD3 2079
+#define IDC_INFO6 2079
+#define IDC_TM1 2080
+#define IDC_TM2 2081
+#define IDC_TM3 2082
+#define IDC_TM4 2083
+#define IDC_TM5 2084
+#define IDC_TM6 2085
+#define IDC_TM7 2086
+#define IDC_TM8 2087
+#define IDC_INFO7 2087
+#define IDC_TM9 2088
+#define IDC_INFO8 2089
+#define IDC_INFO9 2090
+#define IDC_INFO10 2091
+#define IDC_INFO12 2092
+#define IDC_INFO13 2093
+#define IDC_MORE 2094
+#define IDC_MOREDETAIL 2095
+#define IDC_DATALIST 2096
+#define IDC_MUPDATE 2097
+#define IDC_MFRAME 2099
+#define IDC_MTOGGLE 2101
+#define IDC_MWEBPAGE 2102
+#define IDC_MTEXT 2103
+#define IDC_STEP1 2107
+#define IDC_STEP2 2108
+#define IDC_STEP3 2109
+#define IDC_STEP4 2110
+#define IDC_INFOLIST 2117
+#define IDC_RELOADINI 2118
+#define IDC_MEMUSED 2119
+#define IDC_INICOUNT 2120
+#define IDC_AVATARSPIN 2124
+#define IDC_SEARCHCITY 2125
+#define IDC_HEADERBAR 2126
+#define IDC_E1 2128
+#define IDC_E2 2129
+#define OIC_HAND 32513
+#define OIC_QUES 32514
+#define OIC_BANG 32515
+#define OIC_NOTE 32516
+#define IDM_M1 40002
+#define IDM_M2 40003
+#define IDM_M3 40004
+#define IDM_M4 40005
+#define IDM_M5 40006
+#define IDM_M6 40007
+#define IDM_M7 40008
+#define IDM_M8 40009
+#define ID_T1 40010
+#define ID_T2 40011
+#define ID_MPREVIEW 40020
+#define ID_MRESET 40021
+#define IDC_STATIC -1
+
+// Next default values for new objects
+//
+#ifdef APSTUDIO_INVOKED
+#ifndef APSTUDIO_READONLY_SYMBOLS
+#define _APS_NO_MFC 1
+#define _APS_NEXT_RESOURCE_VALUE 226
+#define _APS_NEXT_COMMAND_VALUE 40030
+#define _APS_NEXT_CONTROL_VALUE 2128
+#define _APS_NEXT_SYMED_VALUE 101
+#endif
+#endif
diff --git a/protocols/Weather/src/stdafx.cxx b/protocols/Weather/src/stdafx.cxx
new file mode 100644
index 0000000000..1b563fc866
--- /dev/null
+++ b/protocols/Weather/src/stdafx.cxx
@@ -0,0 +1,18 @@
+/*
+Copyright (C) 2012-19 Miranda NG team (https://miranda-ng.org)
+
+This program is free software; you can redistribute it and/or
+modify it under the terms of the GNU General Public License
+as published by the Free Software Foundation version 2
+of the License.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "stdafx.h" \ No newline at end of file
diff --git a/protocols/Weather/src/stdafx.h b/protocols/Weather/src/stdafx.h
new file mode 100644
index 0000000000..eee562a9ed
--- /dev/null
+++ b/protocols/Weather/src/stdafx.h
@@ -0,0 +1,547 @@
+/*
+Weather Protocol plugin for Miranda NG
+Copyright (C) 2012-19 Miranda NG team
+Copyright (c) 2005-2011 Boris Krasnovskiy All Rights Reserved
+Copyright (c) 2002-2005 Calvin Che
+
+This program is free software; you can redistribute it and/or
+modify it under the terms of the GNU General Public License
+as published by the Free Software Foundation; version 2
+of the License.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+/* This file contains the includes, weather constants/declarations,
+ the structs, and the primitives for some of the functions.
+*/
+
+#pragma once
+
+//============ THE INCLUDES ===========
+
+#include <share.h>
+#include <time.h>
+#include <windows.h>
+#include <commctrl.h>
+#include <richedit.h>
+#include <malloc.h>
+
+#include <newpluginapi.h>
+#include <m_icolib.h>
+#include <m_options.h>
+#include <m_langpack.h>
+#include <m_skin.h>
+#include <m_database.h>
+#include <m_history.h>
+#include <m_protosvc.h>
+#include <m_userinfo.h>
+#include <m_netlib.h>
+#include <m_ignore.h>
+#include <m_findadd.h>
+#include <m_button.h>
+#include <m_avatars.h>
+#include <m_clc.h>
+#include <m_fontservice.h>
+#include <m_skin_eng.h>
+#include <m_cluiframes.h>
+#include <m_popup.h>
+#include <win2k.h>
+#include <m_acc.h>
+
+#include <m_weather.h>
+#include <m_toptoolbar.h>
+
+#include "resource.h"
+#include "version.h"
+
+//============ CONSTANTS ============
+
+// name
+#define MODULENAME "Weather"
+#define WEATHERPROTOTEXT "Weather"
+#define DEFCURRENTWEATHER "WeatherCondition"
+#define WEATHERCONDITION "Current"
+
+// weather conditions
+#define SUNNY ID_STATUS_ONLINE
+#define NA ID_STATUS_OFFLINE
+#define PCLOUDY ID_STATUS_AWAY
+#define CLOUDY ID_STATUS_NA
+#define RAIN ID_STATUS_OCCUPIED
+#define RSHOWER ID_STATUS_DND
+#define SNOW ID_STATUS_FREECHAT
+#define LIGHT ID_STATUS_INVISIBLE
+#define THUNDER ID_STATUS_INVISIBLE
+#define SSHOWER ID_STATUS_ONTHEPHONE
+#define FOG ID_STATUS_OUTTOLUNCH
+#define UNAVAIL 40081
+
+// status
+#define NOSTATUSDATA 1
+
+// limits
+#define MAX_TEXT_SIZE 4096
+#define MAX_DATA_LEN 1024
+
+// db info mangement mode
+#define WDBM_REMOVE 1
+#define WDBM_DETAILDISPLAY 2
+
+// more info list column width
+#define LIST_COLUMN 150
+
+// others
+#define NODATA TranslateT("N/A")
+#define UM_SETCONTACT 40000
+
+// weather update error codes
+#define INVALID_ID_FORMAT 10
+#define INVALID_SVC 11
+#define INVALID_ID 12
+#define SVC_NOT_FOUND 20
+#define NETLIB_ERROR 30
+#define DATA_EMPTY 40
+#define DOC_NOT_FOUND 42
+#define DOC_TOO_SHORT 43
+#define UNKNOWN_ERROR 99
+
+// weather update error text
+#define E10 TranslateT("Invalid ID format, missing \"/\" (10)")
+#define E11 TranslateT("Invalid service (11)")
+#define E12 TranslateT("Invalid station (12)")
+#define E20 TranslateT("Weather service ini for this station is not found (20)")
+#define E30 TranslateT("Netlib error - check your internet connection (30)")
+#define E40 TranslateT("Empty data is retrieved (40)")
+#define E42 TranslateT("Document not found (42)")
+#define E43 TranslateT("Document too short to contain any weather data (43)")
+#define E99 TranslateT("Unknown error (99)")
+
+// HTTP error... not all translated
+// 100 Continue
+// 101 Switching Protocols
+// 200 OK
+// 201 Created
+// 202 Accepted
+// 203 Non-Authoritative Information
+#define E204 TranslateT("HTTP Error: No content (204)")
+// 205 Reset Content
+// 206 Partial Content
+// 300 Multiple Choices
+#define E301 TranslateT("HTTP Error: Data moved (301)")
+// 302 Found
+// 303 See Other
+// 304 Not Modified
+#define E305 TranslateT("HTTP Error: Use proxy (305)")
+// 306 (Unused)
+#define E307 TranslateT("HTTP Error: Temporary redirect (307)")
+#define E400 TranslateT("HTTP Error: Bad request (400)")
+#define E401 TranslateT("HTTP Error: Unauthorized (401)")
+#define E402 TranslateT("HTTP Error: Payment required (402)")
+#define E403 TranslateT("HTTP Error: Forbidden (403)")
+#define E404 TranslateT("HTTP Error: Not found (404)")
+#define E405 TranslateT("HTTP Error: Method not allowed (405)")
+// 406 Not Acceptable
+#define E407 TranslateT("HTTP Error: Proxy authentication required (407)")
+// 408 Request Timeout
+// 409 Conflict
+#define E410 TranslateT("HTTP Error: Gone (410)")
+// 411 Length Required
+// 412 Precondition Failed
+// 413 Request Entity Too Large
+// 414 Request-URI Too Long
+// 415 Unsupported Media Type
+// 416 Requested Range Not Satisfiable
+// 417 Expectation Failed
+#define E500 TranslateT("HTTP Error: Internal server error (500)")
+// 501 Not Implemented
+#define E502 TranslateT("HTTP Error: Bad gateway (502)")
+#define E503 TranslateT("HTTP Error: Service unavailable (503)")
+#define E504 TranslateT("HTTP Error: Gateway timeout (504)")
+// 505 HTTP Version Not Supported
+
+// defaults constants
+#define C_DEFAULT L"%n [%t, %c]"
+#define N_DEFAULT TranslateT("%c\\nTemperature: %t\\nFeel-Like: %f\\nPressure: %p\\nWind: %i %w\\nHumidity: %m\\nDew Point: %e\\nVisibility: %v\\n\\nSun Rise: %r\\nSun Set: %y\\n\\n5 Days Forecast:\\n%[Forecast Day 1]\\n%[Forecast Day 2]\\n%[Forecast Day 3]\\n%[Forecast Day 4]\\n%[Forecast Day 5]")
+#define B_DEFAULT TranslateT("Feel-Like: %f\\nPressure: %p\\nWind: %i %w\\nHumidity: %m\\nDew Point: %e\\nVisibility: %v\\n\\nSun Rise: %r\\nSun Set: %y\\n\\n5 Days Forecast:\\n%[Forecast Day 1]\\n%[Forecast Day 2]\\n%[Forecast Day 3]\\n%[Forecast Day 4]\\n%[Forecast Day 5]")
+#define b_DEFAULT TranslateT("Weather Condition for %n as of %u")
+#define X_DEFAULT N_DEFAULT
+#define H_DEFAULT TranslateT("%c, %t (feel-like %f) Wind: %i %w Humidity: %m")
+#define E_DEFAULT TranslateT("%n at %u: %c, %t (feel-like %f) Wind: %i %w Humidity: %m")
+#define P_DEFAULT TranslateT("%n (%u)")
+#define p_DEFAULT TranslateT("%c, %t\\nToday: High %h, Low %l")
+#define s_DEFAULT TranslateT("Temperature: %[Temperature]")
+#define VAR_LIST_POPUP TranslateT("%c\tcurrent condition\n%d\tcurrent date\n%e\tdewpoint\n%f\tfeel-like temperature\n%h\ttoday's high\n%i\twind direction\n%l\ttoday's low\n%m\thumidity\n%n\tstation name\n%p\tpressure\n%r\tsunrise time\n%s\tstation ID\n%t\ttemperature\n%u\tupdate time\n%v\tvisibility\n%w\twind speed\n%y\tsun set")
+#define VAR_LIST_OPT TranslateT("%c\tcurrent condition\n%d\tcurrent date\n%e\tdewpoint\n%f\tfeel-like temp\n%h\ttoday's high\n%i\twind direction\n%l\ttoday's low\n%m\thumidity\n%n\tstation name\n%p\tpressure\n%r\tsunrise time\n%s\tstation ID\n%t\ttemperature\n%u\tupdate time\n%v\tvisibility\n%w\twind speed\n%y\tsun set\n----------\n\\n\tnew line")
+#define WEATHER_NO_INFO TranslateT("No information available.\r\nPlease update weather condition first.")
+#define CUSTOM_VARS TranslateT("%[..]\tcustom variables")
+#define VARS_LIST TranslateT("Here is a list of custom variables that are currently available")
+#define NO_FORECAST_URL TranslateT("The URL for complete forecast has not been set. You can set it from the Edit Settings dialog.")
+#define NO_MAP_URL TranslateT("The URL for weather map has not been set. You can set it from the Edit Settings dialog.")
+
+//============ OPTION STRUCT ============
+
+// option struct
+struct MYOPTIONS
+{
+ // main options
+ BYTE AutoUpdate;
+ BYTE CAutoUpdate;
+ BYTE StartupUpdate;
+ BYTE NoProtoCondition;
+ BYTE UpdateOnlyConditionChanged;
+ BYTE RemoveOldData;
+ BYTE MakeItalic;
+
+ WORD UpdateTime;
+ WORD AvatarSize;
+
+ // units
+ WORD tUnit;
+ WORD wUnit;
+ WORD vUnit;
+ WORD pUnit;
+ WORD dUnit;
+ WORD eUnit;
+ wchar_t DegreeSign[4];
+ BYTE DoNotAppendUnit;
+ BYTE NoFrac;
+
+ // texts
+ wchar_t *cText;
+ wchar_t *bTitle;
+ wchar_t *bText;
+ wchar_t *nText;
+ wchar_t *eText;
+ wchar_t *hText;
+ wchar_t *xText;
+ wchar_t *sText;
+
+ // advanced
+ BYTE DisCondIcon;
+
+ // popup options
+ BYTE UsePopup;
+ BYTE UpdatePopup;
+ BYTE AlertPopup;
+ BYTE PopupOnChange;
+ BYTE ShowWarnings;
+
+ // popup colors
+ BYTE UseWinColors;
+ COLORREF BGColour;
+ COLORREF TextColour;
+
+ // popup actions
+ DWORD LeftClickAction;
+ DWORD RightClickAction;
+
+ // popup delay
+ DWORD pDelay;
+
+ // popup texts
+ wchar_t *pTitle;
+ wchar_t *pText;
+
+ // other misc stuff
+ wchar_t Default[64];
+ MCONTACT DefStn;
+};
+
+void DestroyOptions(void);
+
+//============ STRUCT USED TO MAKE AN UPDATE LIST ============
+struct WCONTACTLIST {
+ MCONTACT hContact;
+ struct WCONTACTLIST *next;
+};
+
+typedef struct WCONTACTLIST UPDATELIST;
+
+extern UPDATELIST *UpdateListHead, *UpdateListTail;
+
+void DestroyUpdateList(void);
+
+//============ DATA FORMAT STRUCT ============
+
+#define WID_NORMAL 0
+#define WID_SET 1
+#define WID_BREAK 2
+
+typedef struct {
+ wchar_t *Name;
+ wchar_t *Start;
+ wchar_t *End;
+ wchar_t *Unit;
+ char *Url;
+ wchar_t *Break;
+ int Type;
+} WIDATAITEM;
+
+struct WITEMLIST {
+ WIDATAITEM Item;
+ struct WITEMLIST *Next;
+};
+
+typedef struct WITEMLIST WIDATAITEMLIST;
+
+typedef struct {
+ BOOL Available;
+ char *SearchURL;
+ wchar_t *NotFoundStr;
+ WIDATAITEM Name;
+} WIIDSEARCH;
+
+typedef struct {
+ BOOL Available;
+ wchar_t *First;
+ WIDATAITEM Name;
+ WIDATAITEM ID;
+} WINAMESEARCHTYPE;
+
+typedef struct {
+ char *SearchURL;
+ wchar_t *NotFoundStr;
+ wchar_t *SingleStr;
+ WINAMESEARCHTYPE Single;
+ WINAMESEARCHTYPE Multiple;
+} WINAMESEARCH;
+
+struct STRLIST {
+ wchar_t *Item;
+ struct STRLIST *Next;
+};
+
+typedef struct STRLIST WICONDITEM;
+
+typedef struct {
+ WICONDITEM *Head;
+ WICONDITEM *Tail;
+} WICONDLIST;
+
+typedef struct {
+ wchar_t *FileName;
+ wchar_t *ShortFileName;
+ BOOL Enabled;
+
+ // header
+ wchar_t *DisplayName;
+ wchar_t *InternalName;
+ wchar_t *Description;
+ wchar_t *Author;
+ wchar_t *Version;
+ int InternalVer;
+ size_t MemUsed;
+
+ // default
+ char *DefaultURL;
+ wchar_t *DefaultMap;
+ char *UpdateURL;
+ char *UpdateURL2;
+ char *UpdateURL3;
+ char *UpdateURL4;
+ char *Cookie;
+ char *UserAgent;
+// items
+ int UpdateDataCount;
+ WIDATAITEMLIST *UpdateData;
+ WIDATAITEMLIST *UpdateDataTail;
+ WIIDSEARCH IDSearch;
+ WINAMESEARCH NameSearch;
+ WICONDLIST CondList[10];
+} WIDATA;
+
+//============ DATA LIST (LINKED LIST) ============
+
+struct DATALIST {
+ WIDATA Data;
+ struct DATALIST *next;
+};
+
+typedef struct DATALIST WIDATALIST;
+
+//============ GLOBAL VARIABLES ============
+
+extern WIDATALIST *WIHead, *WITail;
+
+extern HWND hPopupWindow, hWndSetup;
+
+extern MYOPTIONS opt;
+
+extern unsigned status, old_status;
+
+extern MWindowList hDataWindowList, hWindowList;
+
+extern HNETLIBUSER hNetlibUser;
+extern HANDLE hHookWeatherUpdated, hHookWeatherError, hTBButton, hUpdateMutex;
+extern UINT_PTR timerId;
+
+extern HGENMENU hMwinMenu;
+
+// check if weather is currently updating
+extern BOOL ThreadRunning;
+
+//============ FUNCTION PRIMITIVES ============
+
+// functions in weather_addstn.c
+INT_PTR WeatherAddToList(WPARAM wParam,LPARAM lParam);
+BOOL CheckSearch();
+
+int IDSearch(wchar_t *id, const int searchId);
+int NameSearch(wchar_t *name, const int searchId);
+
+INT_PTR WeatherBasicSearch(WPARAM wParam,LPARAM lParam);
+INT_PTR WeatherCreateAdvancedSearchUI(WPARAM wParam, LPARAM lParam);
+INT_PTR WeatherAdvancedSearch(WPARAM wParam, LPARAM lParam);
+
+int WeatherAdd(WPARAM wParam, LPARAM lParam);
+
+// functions used in weather_contacts.c
+INT_PTR ViewLog(WPARAM wParam,LPARAM lParam);
+INT_PTR LoadForecast(WPARAM wParam,LPARAM lParam);
+INT_PTR WeatherMap(WPARAM wParam,LPARAM lParam);
+INT_PTR EditSettings(WPARAM wParam,LPARAM lParam);
+
+int ContactDeleted(WPARAM wParam,LPARAM lParam);
+
+BOOL IsMyContact(MCONTACT hContact);
+
+// functions in weather_conv.c
+void GetTemp(wchar_t *tempchar, wchar_t *unit, wchar_t *str);
+void GetSpeed(wchar_t *tempchar, wchar_t *unit, wchar_t *str);
+void GetPressure(wchar_t *tempchar, wchar_t *unit, wchar_t *str);
+void GetDist(wchar_t *tempchar, wchar_t *unit, wchar_t *str);
+void GetElev(wchar_t *tempchar, wchar_t *unit, wchar_t *str);
+
+WORD GetIcon(const wchar_t* cond, WIDATA *Data);
+void CaseConv(wchar_t *str);
+void TrimString(char *str);
+void TrimString(WCHAR *str);
+void ConvertBackslashes(char *str);
+char *GetSearchStr(char *dis);
+
+wchar_t *GetDisplay(WEATHERINFO *w, const wchar_t *dis, wchar_t* str);
+INT_PTR GetDisplaySvcFunc(WPARAM wParam, LPARAM lParam);
+
+void GetSvc(wchar_t *pszID);
+void GetID(wchar_t *pszID);
+
+wchar_t *GetError(int code);
+
+// functions in weather_data.c
+void GetStationID(MCONTACT hContact, wchar_t* id, int idlen);
+WEATHERINFO LoadWeatherInfo(MCONTACT Change);
+int DBGetData(MCONTACT hContact, char *setting, DBVARIANT *dbv);
+
+void EraseAllInfo(void);
+
+void GetDataValue(WIDATAITEM *UpdateData, wchar_t *Data, wchar_t** szInfo);
+void ConvertDataValue(WIDATAITEM *UpdateData, wchar_t *Data);
+void wSetData(char **Data, const char *Value);
+void wSetData(WCHAR **Data, const char *Value);
+void wSetData(WCHAR **Data, const WCHAR *Value);
+void wfree(char **Data);
+void wfree(WCHAR **Data);
+
+void DBDataManage(MCONTACT hContact, WORD Mode, WPARAM wParam, LPARAM lParam);
+
+// functions in weather_http.c
+int InternetDownloadFile (char *szUrl, char *cookie, char *userAgent, wchar_t** szData);
+void NetlibInit();
+
+// functions in weather_ini.c
+WIDATA* GetWIData(wchar_t *pszServ);
+
+bool IsContainedInCondList(const wchar_t *pszStr, WICONDLIST *List);
+
+void DestroyWIList();
+bool LoadWIData(bool dial);
+
+INT_PTR CALLBACK DlgPopupOpts(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam);
+
+// functions in weather_info.c
+void GetINIInfo(wchar_t *pszSvc);
+
+void MoreVarList();
+
+// functions in weather_opt.c
+void SetTextDefault(const char* in);
+void LoadOptions();
+void SaveOptions();
+
+int OptInit(WPARAM wParam,LPARAM lParam);
+
+
+// functions in weather_popup.c
+int WeatherPopup(WPARAM wParam, LPARAM lParam);
+int WeatherError(WPARAM wParam, LPARAM lParam);
+int WPShowMessage(wchar_t* lpzText, WORD kind);
+
+LRESULT CALLBACK PopupWndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
+
+// functions in weather_svcs.c
+void InitServices(void);
+
+INT_PTR WeatherSetStatus(WPARAM new_status, LPARAM lParam);
+INT_PTR WeatherGetCaps(WPARAM wParam, LPARAM lParam);
+INT_PTR WeatherGetName(WPARAM wParam, LPARAM lParam);
+INT_PTR WeatherGetStatus(WPARAM wParam, LPARAM lParam);
+INT_PTR WeatherLoadIcon(WPARAM wParam, LPARAM lParam);
+
+void UpdateMenu(BOOL State);
+void UpdatePopupMenu(BOOL State);
+void AddMenuItems();
+void AvatarDownloaded(MCONTACT hContact);
+
+// functions in weather_update.c
+int UpdateWeather(MCONTACT hContact);
+
+void UpdateAll(BOOL AutoUpdate, BOOL RemoveOld);
+INT_PTR UpdateSingleStation(WPARAM wParam,LPARAM lParam);
+INT_PTR UpdateAllInfo(WPARAM wParam,LPARAM lParam);
+INT_PTR UpdateSingleRemove(WPARAM wParam,LPARAM lParam);
+INT_PTR UpdateAllRemove(WPARAM wParam,LPARAM lParam);
+
+int GetWeatherData(MCONTACT hContact);
+
+void CALLBACK timerProc(HWND hwnd, UINT uMsg, UINT_PTR idEvent, DWORD dwTime);
+void CALLBACK timerProc2(HWND hwnd, UINT uMsg, UINT_PTR idEvent, DWORD dwTime);
+
+// function from multiwin module
+void InitMwin(void);
+void DestroyMwin(void);
+INT_PTR Mwin_MenuClicked(WPARAM wParam, LPARAM lParam);
+int BuildContactMenu(WPARAM wparam, LPARAM lparam);
+void UpdateMwinData(MCONTACT hContact);
+void removeWindow(MCONTACT hContact);
+
+// functions in weather_userinfo.c
+int UserInfoInit(WPARAM wParam, LPARAM lParam);
+INT_PTR CALLBACK DlgProcINIPage(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam);
+
+#define WM_UPDATEDATA WM_USER + 2687
+
+int BriefInfo(WPARAM wParam, LPARAM lParam);
+INT_PTR BriefInfoSvc(WPARAM wParam, LPARAM lParam);
+
+void InitIcons(void);
+HICON LoadIconEx(const char* name, bool big);
+HANDLE GetIconHandle(const char* name);
+void ReleaseIconEx(HICON hIcon);
+
+//============ Plugin Class ============
+
+struct CMPlugin : public PLUGIN<CMPlugin>
+{
+ CMPlugin();
+
+ int Load() override;
+ int Unload() override;
+};
+
diff --git a/protocols/Weather/src/version.h b/protocols/Weather/src/version.h
new file mode 100644
index 0000000000..d777fe40f9
--- /dev/null
+++ b/protocols/Weather/src/version.h
@@ -0,0 +1,13 @@
+#define __MAJOR_VERSION 0
+#define __MINOR_VERSION 4
+#define __RELEASE_NUM 0
+#define __BUILD_NUM 4
+
+#include <stdver.h>
+
+#define __PLUGIN_NAME "Weather"
+#define __FILENAME "Weather.dll"
+#define __DESCRIPTION "Retrieves weather information and displays it in your contact list."
+#define __AUTHOR "Miranda NG team"
+#define __AUTHORWEB "https://miranda-ng.org/p/Weather/"
+#define __COPYRIGHT "© 2002-2005 NoName, 2005-2010 Boris Krasnovskiy, 2012-19 Miranda NG team"
diff --git a/protocols/Weather/src/weather.cpp b/protocols/Weather/src/weather.cpp
new file mode 100644
index 0000000000..742f860967
--- /dev/null
+++ b/protocols/Weather/src/weather.cpp
@@ -0,0 +1,231 @@
+/*
+Weather Protocol plugin for Miranda IM
+Copyright (c) 2012 Miranda NG team
+Copyright (c) 2005-2011 Boris Krasnovskiy All Rights Reserved
+Copyright (c) 2002-2005 Calvin Che
+
+This program is free software; you can redistribute it and/or
+modify it under the terms of the GNU General Public License
+as published by the Free Software Foundation; version 2
+of the License.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+/*
+Main file for the Weather Protocol, includes loading, unloading,
+upgrading, support for plugin uninsaller, and anything that doesn't
+belong to any other file.
+*/
+
+#include "stdafx.h"
+
+//============ GLOBAL VARIABLES ============
+
+WIDATALIST *WIHead;
+WIDATALIST *WITail;
+
+HWND hPopupWindow;
+
+HANDLE hHookWeatherUpdated;
+HANDLE hHookWeatherError;
+
+MWindowList hDataWindowList, hWindowList;
+
+HANDLE hUpdateMutex;
+
+unsigned status;
+unsigned old_status;
+
+UINT_PTR timerId;
+
+CMPlugin g_plugin;
+
+MYOPTIONS opt;
+
+// check if weather is currently updating
+BOOL ThreadRunning;
+
+// variable to determine if module loaded
+BOOL ModuleLoaded;
+
+HANDLE hTBButton = nullptr;
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// plugin info
+
+static const PLUGININFOEX pluginInfoEx =
+{
+ sizeof(PLUGININFOEX),
+ __PLUGIN_NAME,
+ PLUGIN_MAKE_VERSION(__MAJOR_VERSION, __MINOR_VERSION, __RELEASE_NUM, __BUILD_NUM),
+ __DESCRIPTION,
+ __AUTHOR,
+ __COPYRIGHT,
+ __AUTHORWEB,
+ UNICODE_AWARE,
+ // {6B612A34-DCF2-4E32-85CF-B6FD006B745E}
+ {0x6b612a34, 0xdcf2, 0x4e32, {0x85, 0xcf, 0xb6, 0xfd, 0x0, 0x6b, 0x74, 0x5e}}
+};
+
+CMPlugin::CMPlugin() :
+ PLUGIN<CMPlugin>(MODULENAME, pluginInfoEx)
+{
+ opt.NoProtoCondition = g_plugin.getByte("NoStatus", true);
+ RegisterProtocol((opt.NoProtoCondition) ? PROTOTYPE_VIRTUAL : PROTOTYPE_PROTOCOL);
+ SetUniqueId("ID");
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+
+extern "C" __declspec(dllexport) const MUUID MirandaInterfaces[] = { MIID_PROTOCOL, MIID_LAST };
+
+/////////////////////////////////////////////////////////////////////////////////////////
+
+int WeatherShutdown(WPARAM, LPARAM)
+{
+ KillTimer(nullptr, timerId); // kill update timer
+
+ SaveOptions(); // save options once more
+ status = ID_STATUS_OFFLINE; // set status to offline
+
+ WindowList_Broadcast(hWindowList, WM_CLOSE, 0, 0);
+ WindowList_Broadcast(hDataWindowList, WM_CLOSE, 0, 0);
+ SendMessage(hWndSetup, WM_CLOSE, 0, 0);
+
+ return 0;
+}
+
+int OnToolbarLoaded(WPARAM, LPARAM)
+{
+ TTBButton ttb = {};
+ ttb.name = LPGEN("Enable/disable auto update");
+ ttb.pszService = MS_WEATHER_ENABLED;
+ ttb.pszTooltipUp = LPGEN("Auto Update Enabled");
+ ttb.pszTooltipDn = LPGEN("Auto Update Disabled");
+ ttb.hIconHandleUp = GetIconHandle("main");
+ ttb.hIconHandleDn = GetIconHandle("disabled");
+ ttb.dwFlags = (g_plugin.getByte("AutoUpdate", 1) ? 0 : TTBBF_PUSHED) | TTBBF_ASPUSHBUTTON | TTBBF_VISIBLE;
+ hTBButton = g_plugin.addTTB(&ttb);
+ return 0;
+}
+
+// weather protocol initialization function
+// run after the event ME_SYSTEM_MODULESLOADED occurs
+int WeatherInit(WPARAM, LPARAM)
+{
+ // initialize netlib
+ NetlibInit();
+
+ InitMwin();
+
+ // load weather menu items
+ AddMenuItems();
+
+ // timer for the first update
+ timerId = SetTimer(nullptr, 0, 5000, timerProc2); // first update is 5 sec after load
+
+ // weather user detail
+ HookEvent(ME_USERINFO_INITIALISE, UserInfoInit);
+ HookEvent(ME_TTB_MODULELOADED, OnToolbarLoaded);
+ return 0;
+}
+
+//============ MISC FUNCTIONS ============
+
+// initialize the global variables at startup
+void InitVar()
+{
+ // setup the linklist for weather update list
+ UpdateListTail = nullptr;
+ UpdateListHead = nullptr;
+
+ // other settings
+ timerId = 0;
+ opt.DefStn = NULL;
+ ModuleLoaded = FALSE;
+}
+
+int CMPlugin::Load()
+{
+ // initialize global variables
+ InitVar();
+
+ // load options and set defaults
+ LoadOptions();
+
+ InitIcons();
+
+ // reset the weather data at startup for individual contacts
+ EraseAllInfo();
+
+ // load weather update data
+ LoadWIData(true);
+
+ // set status to online if "Do not display weather condition as protocol status" is enabled
+ old_status = status = ID_STATUS_OFFLINE;
+
+ // add an event on weather update and error
+ hHookWeatherUpdated = CreateHookableEvent(ME_WEATHER_UPDATED);
+ hHookWeatherError = CreateHookableEvent(ME_WEATHER_ERROR);
+
+ // initialize options and network
+ HookEvent(ME_OPT_INITIALISE, OptInit);
+ HookEvent(ME_SYSTEM_MODULESLOADED, WeatherInit);
+ HookEvent(ME_DB_CONTACT_DELETED, ContactDeleted);
+ HookEvent(ME_CLIST_DOUBLECLICKED, BriefInfo);
+ HookEvent(ME_WEATHER_UPDATED, WeatherPopup);
+ HookEvent(ME_WEATHER_ERROR, WeatherError);
+ HookEvent(ME_SYSTEM_PRESHUTDOWN, WeatherShutdown);
+ HookEvent(ME_CLIST_PREBUILDCONTACTMENU, BuildContactMenu);
+
+ hDataWindowList = WindowList_Create();
+ hWindowList = WindowList_Create();
+
+ hUpdateMutex = CreateMutex(nullptr, FALSE, nullptr);
+
+ // initialize weather protocol services
+ InitServices();
+
+ // add sound event
+ g_plugin.addSound("weatherupdated", _A2W(MODULENAME), LPGENW("Condition Changed"));
+ g_plugin.addSound("weatheralert", _A2W(MODULENAME), LPGENW("Alert Issued"));
+
+ // window needed for popup commands
+ wchar_t SvcFunc[100];
+ mir_snwprintf(SvcFunc, L"%s__PopupWindow", _A2W(MODULENAME));
+ hPopupWindow = CreateWindowEx(WS_EX_TOOLWINDOW, L"static", SvcFunc, 0, CW_USEDEFAULT, CW_USEDEFAULT,
+ CW_USEDEFAULT, CW_USEDEFAULT, HWND_DESKTOP, nullptr, g_plugin.getInst(), nullptr);
+ SetWindowLongPtr(hPopupWindow, GWLP_WNDPROC, (LONG_PTR)PopupWndProc);
+ return 0;
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// unload function
+
+int CMPlugin::Unload()
+{
+ DestroyMwin();
+ DestroyWindow(hPopupWindow);
+
+ DestroyHookableEvent(hHookWeatherUpdated);
+ DestroyHookableEvent(hHookWeatherError);
+
+ Netlib_CloseHandle(hNetlibUser);
+
+ DestroyUpdateList();
+ DestroyOptions();
+ DestroyWIList(); // unload all ini data from memory
+
+ WindowList_Destroy(hDataWindowList);
+ WindowList_Destroy(hWindowList);
+
+ CloseHandle(hUpdateMutex);
+ return 0;
+}
diff --git a/protocols/Weather/src/weather_addstn.cpp b/protocols/Weather/src/weather_addstn.cpp
new file mode 100644
index 0000000000..ca7a8ae6e3
--- /dev/null
+++ b/protocols/Weather/src/weather_addstn.cpp
@@ -0,0 +1,432 @@
+/*
+Weather Protocol plugin for Miranda IM
+Copyright (c) 2012 Miranda NG team
+Copyright (c) 2005-2011 Boris Krasnovskiy All Rights Reserved
+Copyright (c) 2002-2005 Calvin Che
+
+This program is free software; you can redistribute it and/or
+modify it under the terms of the GNU General Public License
+as published by the Free Software Foundation; version 2
+of the License.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+/* This file contain the source related to search and add a weather station
+to the contact list. Contain code for both name and ID search.
+*/
+
+#include "stdafx.h"
+
+// variables used for weather_addstn.c
+static int sttSearchId = -1;
+static wchar_t name1[256];
+
+// ============ ADDING NEW STATION ============
+
+// protocol service function for adding a new contact onto contact list
+// lParam = PROTOSEARCHRESULT
+INT_PTR WeatherAddToList(WPARAM, LPARAM lParam)
+{
+ PROTOSEARCHRESULT *psr = (PROTOSEARCHRESULT*)lParam;
+ if (!psr || !psr->email.w)
+ return 0;
+
+ // search for existing contact
+ for (auto &hContact : Contacts()) {
+ // check if it is a weather contact
+ if (IsMyContact(hContact)) {
+ DBVARIANT dbv;
+ // check ID to see if the contact already exist in the database
+ if (!g_plugin.getWString(hContact, "ID", &dbv)) {
+ if (!mir_wstrcmpi(psr->email.w, dbv.pwszVal)) {
+ // remove the flag for not on list and hidden, thus make the contact visible
+ // and add them on the list
+ if (db_get_b(hContact, "CList", "NotOnList", 1)) {
+ db_unset(hContact, "CList", "NotOnList");
+ db_unset(hContact, "CList", "Hidden");
+ }
+ db_free(&dbv);
+ // contact is added, function quitting
+ return (INT_PTR)hContact;
+ }
+ db_free(&dbv);
+ }
+ }
+ }
+
+ // if contact with the same ID was not found, add it
+ if (psr->cbSize < sizeof(PROTOSEARCHRESULT)) return 0;
+ MCONTACT hContact = db_add_contact();
+ Proto_AddToContact(hContact, MODULENAME);
+ // suppress online notification for the new contact
+ CallService(MS_IGNORE_IGNORE, hContact, IGNOREEVENT_USERONLINE);
+
+ // set contact info and settings
+ wchar_t svc[256];
+ wcsncpy(svc, psr->email.w, _countof(svc)); svc[_countof(svc) - 1] = 0;
+ GetSvc(svc);
+ // set settings by obtaining the default for the service
+ if (psr->lastName.w[0] != 0) {
+ WIDATA *sData = GetWIData(svc);
+ g_plugin.setWString(hContact, "MapURL", sData->DefaultMap);
+ g_plugin.setString(hContact, "InfoURL", sData->DefaultURL);
+ }
+ else { // if no valid service is found, create empty strings for MapURL and InfoURL
+ g_plugin.setString(hContact, "MapURL", "");
+ g_plugin.setString(hContact, "InfoURL", "");
+ }
+ // write the other info and settings to the database
+ g_plugin.setWString(hContact, "ID", psr->email.w);
+ g_plugin.setWString(hContact, "Nick", psr->nick.w);
+ g_plugin.setWord(hContact, "Status", ID_STATUS_OFFLINE);
+
+ AvatarDownloaded(hContact);
+
+ wchar_t str[256];
+ mir_snwprintf(str, TranslateT("Current weather information for %s."), psr->nick.w);
+ g_plugin.setWString(hContact, "About", str);
+
+ // make the last update tags to something invalid
+ g_plugin.setString(hContact, "LastLog", "never");
+ g_plugin.setString(hContact, "LastCondition", "None");
+ g_plugin.setString(hContact, "LastTemperature", "None");
+
+ // ignore status change
+ db_set_dw(hContact, "Ignore", "Mask", 8);
+
+ // if no default station is found, set the new contact as default station
+ if (opt.Default[0] == 0) {
+ DBVARIANT dbv;
+ GetStationID(hContact, opt.Default, _countof(opt.Default));
+
+ opt.DefStn = hContact;
+ if (!g_plugin.getWString(hContact, "Nick", &dbv)) {
+ // notification message box
+ mir_snwprintf(str, TranslateT("%s is now the default weather station"), dbv.pwszVal);
+ db_free(&dbv);
+ MessageBox(nullptr, str, TranslateT("Weather Protocol"), MB_OK | MB_ICONINFORMATION);
+ }
+ g_plugin.setWString("Default", opt.Default);
+ }
+ // display the Edit Settings dialog box
+ EditSettings(hContact, 0);
+ return (INT_PTR)hContact;
+}
+
+// ============ WARNING DIALOG ============
+
+// show a message box and cancel search if update is in process
+BOOL CheckSearch()
+{
+ if (UpdateListHead != nullptr) {
+ MessageBox(nullptr, TranslateT("Please try again after weather update is completed."), TranslateT("Weather Protocol"), MB_OK | MB_ICONERROR);
+ return FALSE;
+ }
+ return TRUE;
+}
+
+// ============ BASIC ID SEARCH ============
+
+static wchar_t sttSID[32];
+
+// A timer process for the ID search (threaded)
+static void __cdecl BasicSearchTimerProc(LPVOID)
+{
+ int result;
+ // search only when it's not current updating weather.
+ if (CheckSearch())
+ result = IDSearch(sttSID, sttSearchId);
+
+ // broadcast the search result
+ ProtoBroadcastAck(MODULENAME, NULL, ACKTYPE_SEARCH, ACKRESULT_SUCCESS, (HANDLE)sttSearchId);
+
+ // exit the search
+ sttSearchId = -1;
+}
+
+// the service function for ID search
+// lParam = ID search string
+INT_PTR WeatherBasicSearch(WPARAM, LPARAM lParam)
+{
+ if (sttSearchId != -1) return 0; //only one search at a time
+ wcsncpy(sttSID, (wchar_t*)lParam, _countof(sttSID));
+ sttSID[_countof(sttSID) - 1] = 0;
+ sttSearchId = 1;
+ // create a thread for the ID search
+ mir_forkthread(BasicSearchTimerProc);
+ return sttSearchId;
+}
+
+// ============ NAME SEARCH ============
+//
+// name search timer process (threaded)
+static void __cdecl NameSearchTimerProc(LPVOID)
+{
+ // search only when it's not current updating weather.
+ if (CheckSearch())
+ if (name1[0] != 0)
+ NameSearch(name1, sttSearchId); // search nickname field
+
+ // broadcast the result
+ ProtoBroadcastAck(MODULENAME, NULL, ACKTYPE_SEARCH, ACKRESULT_SUCCESS, (HANDLE)sttSearchId);
+
+ // exit the search
+ sttSearchId = -1;
+}
+
+static INT_PTR CALLBACK WeatherSearchAdvancedDlgProc(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM)
+{
+ switch (msg) {
+ case WM_INITDIALOG:
+ TranslateDialogDefault(hwndDlg);
+ SetFocus(GetDlgItem(hwndDlg, IDC_SEARCHCITY));
+ return TRUE;
+
+ case WM_COMMAND:
+ if (HIWORD(wParam) == EN_SETFOCUS)
+ PostMessage(GetParent(hwndDlg), WM_COMMAND, MAKEWPARAM(0, EN_SETFOCUS), (LPARAM)hwndDlg);
+ }
+ return FALSE;
+}
+
+INT_PTR WeatherCreateAdvancedSearchUI(WPARAM, LPARAM lParam)
+{
+ HWND parent = (HWND)lParam;
+ if (parent)
+ return (INT_PTR)CreateDialogParam(g_plugin.getInst(), MAKEINTRESOURCE(IDD_SEARCHCITY), parent, WeatherSearchAdvancedDlgProc, 0);
+
+ return 0;
+}
+
+// service function for name search
+INT_PTR WeatherAdvancedSearch(WPARAM, LPARAM lParam)
+{
+ if (sttSearchId != -1) return 0; //only one search at a time
+
+ sttSearchId = 1;
+ GetDlgItemText((HWND)lParam, IDC_SEARCHCITY, name1, _countof(name1));
+
+ // search for the weather station using a thread
+ mir_forkthread(NameSearchTimerProc);
+ return sttSearchId;
+}
+
+// ============ SEARCH FOR A WEATHER STATION USING ID ============
+
+// Seaching station ID from a single weather service (Threaded)
+// sID = search string for the station ID
+// searchId = -1
+// sData = the ID search data for that particular weather service
+// svcname = the name of the weather service that is currently searching (ie. Yahoo Weather)
+int IDSearchProc(wchar_t *sID, const int searchId, WIIDSEARCH *sData, wchar_t *svc, wchar_t *svcname)
+{
+ wchar_t str[MAX_DATA_LEN], newID[MAX_DATA_LEN];
+
+ if (sData->Available) {
+ char loc[255];
+ wchar_t *szData = nullptr;
+
+ // load the page
+ mir_snprintf(loc, sData->SearchURL, sID);
+ BOOL bFound = (InternetDownloadFile(loc, nullptr, nullptr, &szData) == 0);
+ if (bFound) {
+ wchar_t* szInfo = szData;
+
+ // not found
+ if (wcsstr(szInfo, sData->NotFoundStr) == nullptr)
+ GetDataValue(&sData->Name, str, &szInfo);
+ }
+
+ mir_free(szData);
+ // Station not found exit
+ if (!bFound) return 1;
+ }
+
+ // give no station name but only ID if the search is unavailable
+ else wcsncpy(str, TranslateT("<Enter station name here>"), MAX_DATA_LEN - 1);
+ mir_snwprintf(newID, L"%s/%s", svc, sID);
+
+ // set the search result and broadcast it
+ PROTOSEARCHRESULT psr = { sizeof(psr) };
+ psr.flags = PSR_UNICODE;
+ psr.nick.w = str;
+ psr.firstName.w = L" ";
+ psr.lastName.w = svcname;
+ psr.email.w = newID;
+ ProtoBroadcastAck(MODULENAME, NULL, ACKTYPE_SEARCH, ACKRESULT_DATA, (HANDLE)searchId, (LPARAM)&psr);
+
+ return 0;
+}
+
+// ID search (Threaded)
+// sID: the ID to search for
+// searchId: don't change
+// return 0 if no error
+int IDSearch(wchar_t *sID, const int searchId)
+{
+ // for a normal ID search (ID != #)
+ if (mir_wstrcmp(sID, L"#")) {
+ WIDATALIST *Item = WIHead;
+
+ // search every weather service using the search station ID
+ while (Item != nullptr) {
+ IDSearchProc(sID, searchId, &Item->Data.IDSearch, Item->Data.InternalName, Item->Data.DisplayName);
+ Item = Item->next;
+ }
+ }
+ // if the station ID is #, return a dummy result and quit the funciton
+ else {
+ // return an empty contact on "#"
+ PROTOSEARCHRESULT psr = { sizeof(psr) };
+ psr.flags = PSR_UNICODE;
+ psr.nick.w = TranslateT("<Enter station name here>"); // to be entered
+ psr.firstName.w = L" ";
+ psr.lastName.w = L"";
+ psr.email.w = TranslateT("<Enter station ID here>"); // to be entered
+ ProtoBroadcastAck(MODULENAME, NULL, ACKTYPE_SEARCH, ACKRESULT_DATA, (HANDLE)searchId, (LPARAM)&psr);
+ }
+
+ return 0;
+}
+
+// ============ SEARCH FOR A WEATHER STATION BY NAME ============
+
+// Seaching station name from a single weather service (Threaded)
+// name = the name of the weather station to be searched
+// searchId = -1
+// sData = the name search data for that particular weather service
+// svcname = the name of the weather service that is currently searching (ie. Yahoo Weather)
+int NameSearchProc(wchar_t *name, const int searchId, WINAMESEARCH *sData, wchar_t *svc, wchar_t *svcname)
+{
+ wchar_t Name[MAX_DATA_LEN], str[MAX_DATA_LEN], sID[MAX_DATA_LEN], *szData = nullptr, *search;
+
+ // replace spaces with %20
+ char loc[256];
+ T2Utf szSearchName(name);
+ mir_snprintf(loc, sData->SearchURL, mir_urlEncode(szSearchName).c_str());
+ if (InternetDownloadFile(loc, nullptr, nullptr, &szData) == 0) {
+ wchar_t* szInfo = szData;
+ search = wcsstr(szInfo, sData->NotFoundStr); // determine if data is available
+ if (search == nullptr) { // if data is found
+ // test if it is single result
+ if (sData->Single.Available && sData->Multiple.Available)
+ search = wcsstr(szInfo, sData->SingleStr);
+ // for single result
+ if (sData->Single.Available && (search != nullptr || !sData->Multiple.Available)) { // single result
+ // if station ID appears first in the downloaded data
+ if (!mir_wstrcmpi(sData->Single.First, L"ID")) {
+ GetDataValue(&sData->Single.ID, str, &szInfo);
+ mir_snwprintf(sID, L"%s/%s", svc, str);
+ GetDataValue(&sData->Single.Name, Name, &szInfo);
+ }
+ // if station name appears first in the downloaded data
+ else if (!mir_wstrcmpi(sData->Single.First, L"NAME")) {
+ GetDataValue(&sData->Single.Name, Name, &szInfo);
+ GetDataValue(&sData->Single.ID, str, &szInfo);
+ mir_snwprintf(sID, L"%s/%s", svc, str);
+ }
+ else
+ str[0] = 0;
+
+ // if no station ID is obtained, quit the search
+ if (str[0] == 0) {
+ mir_free(szData);
+ return 1;
+ }
+
+ // if can't get the name, use the search string as name
+ if (Name[0] == 0)
+ wcsncpy(Name, name, _countof(Name));
+
+ // set the data and broadcast it
+ PROTOSEARCHRESULT psr = { sizeof(psr) };
+ psr.flags = PSR_UNICODE;
+ psr.nick.w = Name;
+ psr.firstName.w = L" ";
+ psr.lastName.w = svcname;
+ psr.email.w = sID;
+ psr.id.w = sID;
+ ProtoBroadcastAck(MODULENAME, NULL, ACKTYPE_SEARCH, ACKRESULT_DATA, (HANDLE)searchId, (LPARAM)&psr);
+ mir_free(szData);
+ return 0;
+ }
+ // for multiple result
+ else if (sData->Multiple.Available) { // multiple results
+ // search for the next occurrence of the string
+ while (true) {
+ // if station ID appears first in the downloaded data
+ if (!mir_wstrcmpi(sData->Multiple.First, L"ID")) {
+ GetDataValue(&sData->Multiple.ID, str, &szInfo);
+ mir_snwprintf(sID, L"%s/%s", svc, str);
+ GetDataValue(&sData->Multiple.Name, Name, &szInfo);
+ }
+ // if station name appears first in the downloaded data
+ else if (!mir_wstrcmpi(sData->Multiple.First, L"NAME")) {
+ GetDataValue(&sData->Multiple.Name, Name, &szInfo);
+ GetDataValue(&sData->Multiple.ID, str, &szInfo);
+ mir_snwprintf(sID, L"%s/%s", svc, str);
+ }
+ else
+ break;
+
+ // if no station ID is obtained, search completed and quit the search
+ if (str[0] == 0)
+ break;
+
+ // if can't get the name, use the search string as name
+ if (Name[0] == 0)
+ wcsncpy(Name, name, _countof(Name));
+
+ PROTOSEARCHRESULT psr = { sizeof(psr) };
+ psr.flags = PSR_UNICODE;
+ psr.nick.w = Name;
+ psr.firstName.w = L"";
+ psr.lastName.w = svcname;
+ psr.email.w = sID;
+ psr.id.w = sID;
+ ProtoBroadcastAck(MODULENAME, NULL, ACKTYPE_SEARCH, ACKRESULT_DATA, (HANDLE)searchId, (LPARAM)&psr);
+ }
+ }
+ }
+
+ mir_free(szData);
+ return 0;
+ }
+
+ mir_free(szData);
+ return 1;
+}
+
+// name search (Threaded)
+// name: the station name to search for
+// searchId: don't change
+// return 0 if no error
+int NameSearch(wchar_t *name, const int searchId)
+{
+ // search every weather service using the search station name
+ WIDATALIST *Item = WIHead;
+ while (Item != nullptr) {
+ if (Item->Data.NameSearch.Single.Available || Item->Data.NameSearch.Multiple.Available)
+ NameSearchProc(name, searchId, &Item->Data.NameSearch, Item->Data.InternalName, Item->Data.DisplayName);
+ Item = Item->next;
+ }
+
+ return 0;
+}
+
+// ======================MENU ITEM FUNCTION ============
+
+// add a new weather station via find/add dialog
+int WeatherAdd(WPARAM, LPARAM)
+{
+ db_set_s(0, "FindAdd", "LastSearched", "Weather");
+ CallService(MS_FINDADD_FINDADD, 0, 0);
+ return 0;
+}
diff --git a/protocols/Weather/src/weather_contacts.cpp b/protocols/Weather/src/weather_contacts.cpp
new file mode 100644
index 0000000000..f572b29564
--- /dev/null
+++ b/protocols/Weather/src/weather_contacts.cpp
@@ -0,0 +1,480 @@
+/*
+Weather Protocol plugin for Miranda IM
+Copyright (c) 2012 Miranda NG team
+Copyright (c) 2005-2011 Boris Krasnovskiy All Rights Reserved
+Copyright (c) 2002-2005 Calvin Che
+
+This program is free software; you can redistribute it and/or
+modify it under the terms of the GNU General Public License
+as published by the Free Software Foundation; version 2
+of the License.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+/* This file contain the source that is related to weather contacts,
+include the links, edit settings, and loading weather information for
+the contact.
+*/
+
+#include "stdafx.h"
+
+static void OpenUrl(wchar_t* format, wchar_t* id)
+{
+ wchar_t loc[512];
+ GetID(id);
+ mir_snwprintf(loc, format, id);
+ Utils_OpenUrlW(loc);
+}
+
+//============ BASIC CONTACTS FUNCTIONS AND LINKS ============
+
+// view weather log for the contact
+// wParam = current contact
+INT_PTR ViewLog(WPARAM wParam, LPARAM lParam)
+{
+ // see if the log path is set
+ DBVARIANT dbv;
+ if (!g_plugin.getWString(wParam, "Log", &dbv)) {
+ if (dbv.pszVal[0] != 0)
+ ShellExecute((HWND)lParam, L"open", dbv.pwszVal, L"", L"", SW_SHOW);
+ db_free(&dbv);
+ }
+ else // display warning dialog if no path is specified
+ MessageBox(nullptr, TranslateT("Weather condition was not logged."),
+ TranslateT("Weather Protocol"), MB_OK | MB_ICONINFORMATION);
+ return 0;
+}
+
+// read complete forecast
+// wParam = current contact
+INT_PTR LoadForecast(WPARAM wParam, LPARAM)
+{
+ wchar_t id[256], loc2[256];
+ GetStationID(wParam, id, _countof(id));
+ if (id[0] != 0) {
+ // check if the complte forecast URL is set. If it is not, display warning and quit
+ if (db_get_wstatic(wParam, MODULENAME, "InfoURL", loc2, _countof(loc2)) || loc2[0] == 0) {
+ MessageBox(nullptr, NO_FORECAST_URL, TranslateT("Weather Protocol"), MB_ICONINFORMATION);
+ return 1;
+ }
+ // set the url and open the webpage
+ OpenUrl(loc2, id);
+ }
+ return 0;
+}
+
+// load weather map
+// wParam = current contact
+INT_PTR WeatherMap(WPARAM wParam, LPARAM)
+{
+ wchar_t id[256], loc2[256];
+ GetStationID(wParam, id, _countof(id));
+ if (id[0] != 0) {
+ // check if the weather map URL is set. If it is not, display warning and quit
+ if (db_get_wstatic(wParam, MODULENAME, "MapURL", loc2, _countof(loc2)) || loc2[0] == 0) {
+ MessageBox(nullptr, NO_MAP_URL, TranslateT("Weather Protocol"), MB_ICONINFORMATION);
+ return 1;
+ }
+
+ // set the url and open the webpage
+ OpenUrl(loc2, id);
+ }
+
+ return 0;
+}
+
+//============ EDIT SETTINGS ============
+
+typedef struct
+{
+ MCONTACT hContact;
+ HICON hRename;
+ HICON hUserDetail;
+ HICON hFile;
+ HICON hSrchAll;
+} CntSetWndDataType;
+
+// edit weather settings
+// lParam = current contact
+static INT_PTR CALLBACK DlgProcChange(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam)
+{
+ DBVARIANT dbv;
+ wchar_t str[MAX_DATA_LEN], str2[256], city[256], filter[256], *pfilter, *chop;
+ char loc[512];
+ OPENFILENAME ofn; // common dialog box structure
+ MCONTACT hContact;
+ WIDATA *sData;
+ CntSetWndDataType *wndData = nullptr;
+
+ switch (msg) {
+ case WM_INITDIALOG:
+ TranslateDialogDefault(hwndDlg);
+
+ wndData = (CntSetWndDataType*)mir_alloc(sizeof(CntSetWndDataType));
+ wndData->hContact = hContact = lParam;
+ wndData->hRename = Skin_LoadIcon(SKINICON_OTHER_RENAME);
+ wndData->hUserDetail = Skin_LoadIcon(SKINICON_OTHER_USERDETAILS);
+ wndData->hFile = Skin_LoadIcon(SKINICON_EVENT_FILE);
+ wndData->hSrchAll = Skin_LoadIcon(SKINICON_OTHER_SEARCHALL);
+
+ SetWindowLongPtr(hwndDlg, GWLP_USERDATA, (LONG_PTR)wndData);
+
+ // set button images
+ SendDlgItemMessage(hwndDlg, IDC_GETNAME, BM_SETIMAGE, IMAGE_ICON, (LPARAM)wndData->hRename);
+ SendDlgItemMessage(hwndDlg, IDC_SVCINFO, BM_SETIMAGE, IMAGE_ICON, (LPARAM)wndData->hUserDetail);
+ SendDlgItemMessage(hwndDlg, IDC_BROWSE, BM_SETIMAGE, IMAGE_ICON, (LPARAM)wndData->hFile);
+ SendDlgItemMessage(hwndDlg, IDC_VIEW1, BM_SETIMAGE, IMAGE_ICON, (LPARAM)wndData->hSrchAll);
+ SendDlgItemMessage(hwndDlg, IDC_RESET1, BM_SETIMAGE, IMAGE_ICON, (LPARAM)wndData->hRename);
+ SendDlgItemMessage(hwndDlg, IDC_VIEW2, BM_SETIMAGE, IMAGE_ICON, (LPARAM)wndData->hSrchAll);
+ SendDlgItemMessage(hwndDlg, IDC_RESET2, BM_SETIMAGE, IMAGE_ICON, (LPARAM)wndData->hRename);
+
+ // make all buttons flat
+ SendDlgItemMessage(hwndDlg, IDC_GETNAME, BUTTONSETASFLATBTN, TRUE, 0);
+ SendDlgItemMessage(hwndDlg, IDC_SVCINFO, BUTTONSETASFLATBTN, TRUE, 0);
+ SendDlgItemMessage(hwndDlg, IDC_BROWSE, BUTTONSETASFLATBTN, TRUE, 0);
+ SendDlgItemMessage(hwndDlg, IDC_VIEW1, BUTTONSETASFLATBTN, TRUE, 0);
+ SendDlgItemMessage(hwndDlg, IDC_RESET1, BUTTONSETASFLATBTN, TRUE, 0);
+ SendDlgItemMessage(hwndDlg, IDC_VIEW2, BUTTONSETASFLATBTN, TRUE, 0);
+ SendDlgItemMessage(hwndDlg, IDC_RESET2, BUTTONSETASFLATBTN, TRUE, 0);
+
+ // set tooltip for the buttons
+ SendDlgItemMessage(hwndDlg, IDC_GETNAME, BUTTONADDTOOLTIP, (WPARAM)LPGENW("Get city name from ID"), BATF_UNICODE);
+ SendDlgItemMessage(hwndDlg, IDC_SVCINFO, BUTTONADDTOOLTIP, (WPARAM)LPGENW("Weather INI information"), BATF_UNICODE);
+ SendDlgItemMessage(hwndDlg, IDC_BROWSE, BUTTONADDTOOLTIP, (WPARAM)LPGENW("Browse"), BATF_UNICODE);
+ SendDlgItemMessage(hwndDlg, IDC_VIEW1, BUTTONADDTOOLTIP, (WPARAM)LPGENW("View webpage"), BATF_UNICODE);
+ SendDlgItemMessage(hwndDlg, IDC_RESET1, BUTTONADDTOOLTIP, (WPARAM)LPGENW("Reset to default"), BATF_UNICODE);
+ SendDlgItemMessage(hwndDlg, IDC_VIEW2, BUTTONADDTOOLTIP, (WPARAM)LPGENW("View webpage"), BATF_UNICODE);
+ SendDlgItemMessage(hwndDlg, IDC_RESET2, BUTTONADDTOOLTIP, (WPARAM)LPGENW("Reset to default"), BATF_UNICODE);
+
+ // save the handle for the contact
+ WindowList_Add(hWindowList, hwndDlg, hContact);
+
+ // start to get the settings
+ // if the setting not exist, leave the dialog box blank
+ if (!g_plugin.getWString(hContact, "ID", &dbv)) {
+ SetDlgItemText(hwndDlg, IDC_ID, dbv.pwszVal);
+ // check if the station is a default station
+ CheckDlgButton(hwndDlg, IDC_DEFA, mir_wstrcmp(dbv.pwszVal, opt.Default) != 0 ? BST_CHECKED : BST_UNCHECKED);
+ db_free(&dbv);
+ }
+ if (!g_plugin.getWString(hContact, "Nick", &dbv)) {
+ SetDlgItemText(hwndDlg, IDC_NAME, dbv.pwszVal);
+ db_free(&dbv);
+ }
+ if (!g_plugin.getWString(hContact, "Log", &dbv)) {
+ SetDlgItemText(hwndDlg, IDC_LOG, dbv.pwszVal);
+ // if the log path is not empty, check the checkbox for external log
+ if (dbv.pwszVal[0]) CheckDlgButton(hwndDlg, IDC_External, BST_CHECKED);
+ db_free(&dbv);
+ }
+ // enable/disable the browse button depending on the value of external log checkbox
+ EnableWindow(GetDlgItem(hwndDlg, IDC_BROWSE), (BYTE)IsDlgButtonChecked(hwndDlg, IDC_External));
+
+ // other checkbox options
+ CheckDlgButton(hwndDlg, IDC_DPop, g_plugin.getByte(hContact, "DPopUp", FALSE) ? BST_CHECKED : BST_UNCHECKED);
+ CheckDlgButton(hwndDlg, IDC_DAutoUpdate, g_plugin.getByte(hContact, "DAutoUpdate", FALSE) ? BST_CHECKED : BST_UNCHECKED);
+ CheckDlgButton(hwndDlg, IDC_Internal, g_plugin.getByte(hContact, "History", 0) ? BST_CHECKED : BST_UNCHECKED);
+
+ if (!g_plugin.getWString(hContact, "InfoURL", &dbv)) {
+ SetDlgItemText(hwndDlg, IDC_IURL, dbv.pwszVal);
+ db_free(&dbv);
+ }
+ if (!g_plugin.getWString(hContact, "MapURL", &dbv)) {
+ SetDlgItemText(hwndDlg, IDC_MURL, dbv.pwszVal);
+ db_free(&dbv);
+ }
+
+ // display the dialog box and free memory
+ Utils_RestoreWindowPositionNoMove(hwndDlg, NULL, MODULENAME, "EditSetting_");
+ ShowWindow(hwndDlg, SW_SHOW);
+ break;
+
+ case WM_COMMAND:
+ wndData = (CntSetWndDataType*)GetWindowLongPtr(hwndDlg, GWLP_USERDATA);
+ hContact = wndData ? wndData->hContact : NULL;
+
+ switch (LOWORD(wParam)) {
+ case IDC_ID:
+ // check if there are 2 parts in the ID (svc/id) seperated by "/"
+ // if not, don't let user change the setting
+ GetDlgItemText(hwndDlg, IDC_ID, str, _countof(str));
+ chop = wcsstr(str, L"/");
+ if (chop == nullptr)
+ EnableWindow(GetDlgItem(hwndDlg, IDC_CHANGE), FALSE);
+ else
+ EnableWindow(GetDlgItem(hwndDlg, IDC_CHANGE), TRUE);
+ break;
+
+ case IDC_NAME:
+ // check if station name is entered
+ // if not, don't let user change the setting
+ GetDlgItemText(hwndDlg, IDC_NAME, str, _countof(str));
+ EnableWindow(GetDlgItem(hwndDlg, IDC_CHANGE), str[0] != 0);
+ break;
+
+ case IDC_GETNAME:
+ // the button for getting station name from the internet
+ // this function uses the ID search for add/find weather station
+ if (!CheckSearch())
+ return TRUE; // don't download if update is in progress
+
+ // get the weather update data using the string in the ID field
+ GetDlgItemText(hwndDlg, IDC_ID, str, _countof(str));
+ GetSvc(str);
+ sData = GetWIData(str);
+ GetDlgItemText(hwndDlg, IDC_ID, str, _countof(str));
+ GetID(str);
+ // if ID search is available, do it
+ if (sData->IDSearch.Available) {
+ // load the page
+ mir_snprintf(loc, sData->IDSearch.SearchURL, str);
+ str[0] = 0;
+ wchar_t *pData = nullptr;
+ if (InternetDownloadFile(loc, nullptr, sData->UserAgent, &pData) == 0) {
+ wchar_t *szInfo = pData;
+ wchar_t* search = wcsstr(szInfo, sData->IDSearch.NotFoundStr);
+
+ // if the page is found (ie. valid ID), get the name of the city
+ if (search == nullptr)
+ GetDataValue(&sData->IDSearch.Name, str, &szInfo);
+ }
+ // free memory
+ mir_free(pData);
+ }
+
+ // give no station name but only ID if the search is unavailable
+ if (str[0] != 0)
+ SetDlgItemText(hwndDlg, IDC_NAME, str);
+ break;
+
+ case IDC_External:
+ // enable/disable the borwse button depending if the external log is enabled
+ EnableWindow(GetDlgItem(hwndDlg, IDC_BROWSE), (BYTE)IsDlgButtonChecked(hwndDlg, IDC_External));
+ if (!(BYTE)IsDlgButtonChecked(hwndDlg, IDC_External))
+ return TRUE;
+ __fallthrough;
+
+ case IDC_BROWSE:
+ // browse for the external log file
+ GetDlgItemText(hwndDlg, IDC_LOG, str, _countof(str));
+ // Initialize OPENFILENAME
+ memset(&ofn, 0, sizeof(OPENFILENAME));
+ ofn.lStructSize = sizeof(OPENFILENAME);
+ ofn.hwndOwner = hwndDlg;
+ ofn.lpstrFile = str;
+ ofn.nMaxFile = _countof(str);
+ // set filters
+ wcsncpy(filter, TranslateT("Text Files"), _countof(filter) - 1);
+ mir_wstrncat(filter, L" (*.txt)", _countof(filter) - mir_wstrlen(filter));
+ pfilter = filter + mir_wstrlen(filter) + 1;
+ wcsncpy(pfilter, L"*.txt", _countof(filter) - 1);
+ pfilter = pfilter + mir_wstrlen(pfilter) + 1;
+ wcsncpy(pfilter, TranslateT("All Files"), _countof(filter) - 1);
+ mir_wstrncat(pfilter, L" (*.*)", _countof(filter) - mir_wstrlen(filter));
+ pfilter = pfilter + mir_wstrlen(pfilter) + 1;
+ wcsncpy(pfilter, L"*.*", _countof(filter) - 1);
+ pfilter = pfilter + mir_wstrlen(pfilter) + 1;
+ *pfilter = '\0';
+ ofn.lpstrFilter = filter;
+ ofn.nFilterIndex = 1;
+ ofn.lpstrFileTitle = nullptr;
+ ofn.nMaxFileTitle = 0;
+ ofn.lpstrInitialDir = nullptr;
+ ofn.Flags = OFN_PATHMUSTEXIST;
+
+ // Display a Open dialog box and put the file name on the dialog
+ if (GetOpenFileName(&ofn))
+ SetDlgItemText(hwndDlg, IDC_LOG, ofn.lpstrFile);
+ // if there is no log file specified, disable external logging
+ EnableWindow(GetDlgItem(hwndDlg, IDC_CHANGE), ofn.lpstrFile[0] != 0);
+ break;
+
+ case IDC_VIEW1:
+ // view the page for more info
+ GetDlgItemText(hwndDlg, IDC_IURL, str, _countof(str));
+ if (str[0] == 0)
+ return TRUE;
+ GetDlgItemText(hwndDlg, IDC_ID, str2, _countof(str2));
+ OpenUrl(str, str2);
+ break;
+
+ case IDC_VIEW2:
+ // view the page for weather map
+ GetDlgItemText(hwndDlg, IDC_MURL, str, _countof(str));
+ if (str[0] == 0)
+ return TRUE;
+ GetDlgItemText(hwndDlg, IDC_ID, str2, _countof(str2));
+ OpenUrl(str, str2);
+ break;
+
+ case IDC_RESET1:
+ // reset the more info url to service default
+ GetDlgItemText(hwndDlg, IDC_ID, str, _countof(str));
+ GetSvc(str);
+ sData = GetWIData(str);
+ SetDlgItemTextA(hwndDlg, IDC_IURL, sData->DefaultURL);
+ break;
+
+ case IDC_RESET2:
+ // reset the weathe map url to service default
+ GetDlgItemText(hwndDlg, IDC_ID, str, _countof(str));
+ GetSvc(str);
+ sData = GetWIData(str);
+ SetDlgItemText(hwndDlg, IDC_MURL, sData->DefaultMap);
+ break;
+
+ case IDC_SVCINFO:
+ // display the information of the ini file used by the weather station
+ GetDlgItemText(hwndDlg, IDC_ID, str, _countof(str));
+ GetSvc(str);
+ GetINIInfo(str);
+ break;
+
+ case IDC_CHANGE:
+ // temporary disable the protocol while applying the change
+ // start writing the new settings to database
+ GetDlgItemText(hwndDlg, IDC_ID, str, _countof(str));
+ g_plugin.setWString(hContact, "ID", str);
+ if ((BYTE)IsDlgButtonChecked(hwndDlg, IDC_DEFA)) { // if default station is set
+ mir_wstrcpy(opt.Default, str);
+ opt.DefStn = hContact;
+ g_plugin.setWString("Default", opt.Default);
+ }
+ GetDlgItemText(hwndDlg, IDC_NAME, city, _countof(city));
+ g_plugin.setWString(hContact, "Nick", city);
+ mir_snwprintf(str2, TranslateT("Current weather information for %s."), city);
+ if ((BYTE)IsDlgButtonChecked(hwndDlg, IDC_External)) {
+ GetDlgItemText(hwndDlg, IDC_LOG, str, _countof(str));
+ g_plugin.setWString(hContact, "Log", str);
+ }
+ else g_plugin.delSetting(hContact, "Log");
+
+ GetDlgItemText(hwndDlg, IDC_IURL, str, _countof(str));
+ g_plugin.setWString(hContact, "InfoURL", str);
+
+ GetDlgItemText(hwndDlg, IDC_MURL, str, _countof(str));
+ g_plugin.setWString(hContact, "MapURL", str);
+ g_plugin.setWord(hContact, "Status", ID_STATUS_OFFLINE);
+ g_plugin.setWord(hContact, "StatusIcon", ID_STATUS_OFFLINE);
+ AvatarDownloaded(hContact);
+ g_plugin.setWString(hContact, "About", str2);
+ g_plugin.setByte(hContact, "History", (BYTE)IsDlgButtonChecked(hwndDlg, IDC_Internal));
+ g_plugin.setByte(hContact, "Overwrite", (BYTE)IsDlgButtonChecked(hwndDlg, IDC_Overwrite));
+ g_plugin.setByte(hContact, "File", (BYTE)IsDlgButtonChecked(hwndDlg, IDC_External));
+ g_plugin.setByte(hContact, "DPopUp", (BYTE)IsDlgButtonChecked(hwndDlg, IDC_DPop));
+ g_plugin.setByte(hContact, "DAutoUpdate", (BYTE)IsDlgButtonChecked(hwndDlg, IDC_DAutoUpdate));
+
+ // re-enable the protocol and update the data for the station
+ g_plugin.setString(hContact, "LastCondition", "None");
+ UpdateSingleStation(hContact, 0);
+ __fallthrough;
+
+ case IDCANCEL:
+ // remove the dialog from window list and close it
+ DestroyWindow(hwndDlg);
+ break;
+ }
+ break;
+
+ case WM_CLOSE:
+ // remove the dialog from window list and close it
+ DestroyWindow(hwndDlg);
+ break;
+
+ case WM_DESTROY:
+ wndData = (CntSetWndDataType*)GetWindowLongPtr(hwndDlg, GWLP_USERDATA);
+ IcoLib_ReleaseIcon(wndData->hFile);
+ IcoLib_ReleaseIcon(wndData->hRename);
+ IcoLib_ReleaseIcon(wndData->hSrchAll);
+ IcoLib_ReleaseIcon(wndData->hUserDetail);
+ mir_free(wndData);
+ SetWindowLongPtr(hwndDlg, GWLP_USERDATA, 0);
+
+ WindowList_Remove(hWindowList, hwndDlg);
+ Utils_SaveWindowPosition(hwndDlg, NULL, MODULENAME, "EditSetting_");
+ break;
+ }
+ return FALSE;
+}
+
+// show edit settings dialog
+// wParam = current contact
+INT_PTR EditSettings(WPARAM wParam, LPARAM)
+{
+ HWND hEditDlg = WindowList_Find(hWindowList, wParam);
+
+ // search the dialog list to prevent multiple instance of dialog for the same contact
+ if (hEditDlg != nullptr) {
+ // if the dialog box already opened, bring it to the front
+ SetForegroundWindow(hEditDlg);
+ SetFocus(hEditDlg);
+ }
+ else {
+ // if the dialog box is not opened, open a new one
+ if (IsMyContact(wParam))
+ CreateDialogParam(g_plugin.getInst(), MAKEINTRESOURCE(IDD_EDIT), nullptr, DlgProcChange, (LPARAM)wParam);
+ }
+
+ return 0;
+}
+
+//============ CONTACT DELETION ============
+//
+// when a contact is deleted, make sure some other contact take over the default station
+// wParam = deleted contact
+int ContactDeleted(WPARAM wParam, LPARAM)
+{
+ if (!IsMyContact(wParam))
+ return 0;
+
+ removeWindow(wParam);
+
+ // exit this function if it is not default station
+ ptrW tszID(g_plugin.getWStringA(wParam, "ID"));
+ if (tszID != NULL)
+ if (mir_wstrcmp(tszID, opt.Default))
+ return 0;
+
+ // now the default station is deleted, try to get a new one
+
+ // start looking for other weather stations
+ for (auto &hContact : Contacts(MODULENAME)) {
+ tszID = g_plugin.getWStringA(hContact, "ID");
+ if (tszID == NULL)
+ continue;
+
+ // if the station is not a default station, set it as the new default station
+ // this is the first weather station encountered from the search
+ if (mir_wstrcmp(opt.Default, tszID)) {
+ wcsncpy_s(opt.Default, tszID, _TRUNCATE);
+ opt.DefStn = hContact;
+ ptrW tszNick(g_plugin.getWStringA(hContact, "Nick"));
+ if (tszNick != NULL) {
+ wchar_t str[255];
+ mir_snwprintf(str, TranslateT("%s is now the default weather station"), (wchar_t*)tszNick);
+ MessageBox(nullptr, str, TranslateT("Weather Protocol"), MB_OK | MB_ICONINFORMATION);
+ }
+ g_plugin.setWString("Default", opt.Default);
+ return 0; // exit this function quickly
+ }
+ }
+
+ // got here if no more weather station left
+ opt.Default[0] = 0; // no default station
+ opt.DefStn = NULL;
+ g_plugin.setWString("Default", opt.Default);
+ return 0;
+}
+
+BOOL IsMyContact(MCONTACT hContact)
+{
+ const char *szProto = GetContactProto(hContact);
+ return szProto != nullptr && mir_strcmp(MODULENAME, szProto) == 0;
+}
diff --git a/protocols/Weather/src/weather_conv.cpp b/protocols/Weather/src/weather_conv.cpp
new file mode 100644
index 0000000000..c46b079531
--- /dev/null
+++ b/protocols/Weather/src/weather_conv.cpp
@@ -0,0 +1,637 @@
+/*
+Weather Protocol plugin for Miranda IM
+Copyright (c) 2012 Miranda NG team
+Copyright (c) 2005-2011 Boris Krasnovskiy All Rights Reserved
+Copyright (c) 2002-2005 Calvin Che
+
+This program is free software; you can redistribute it and/or
+modify it under the terms of the GNU General Public License
+as published by the Free Software Foundation; version 2
+of the License.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+/*
+This file contain the source related unit conversion, icon assignment,
+string conversions, display text parsing, etc
+*/
+
+#include "stdafx.h"
+
+//============ SOME HELPER FUNCTIONS ============
+
+// see if a string is a number
+// s = the string to be determined
+// return value = true if the string is a number, false if it isn't
+BOOL is_number(wchar_t *s)
+{
+ BOOL tag = FALSE;
+ // looking character by character
+ // for a number: numerous spaces in front, then optional +/-, then the number
+ // don't care anything that comes after it
+ while (*s != '\0') {
+ if (*s >= '0' && *s <= '9') return TRUE;
+ else if (*s == ' ');
+ else if (*s != '+' && *s != '-') return FALSE;
+ else if ((*s == '+' || *s == '-') && !tag) tag = TRUE;
+ else return FALSE;
+ s++;
+ }
+ return FALSE;
+}
+
+static void numToStr(double num, wchar_t *str, size_t strSize)
+{
+ int i = (int)(num * (opt.NoFrac ? 10 : 100));
+ int u = abs(i);
+
+ int r = u % 10;
+ int w = u / 10 + (r >= 5);
+
+ if (opt.NoFrac)
+ r = 0;
+ else {
+ r = w % 10;
+ w /= 10;
+ }
+
+ if (i < 0 && (w || r)) w = -w;
+ if (r)
+ mir_snwprintf(str, strSize, L"%i.%i", w, r);
+ else
+ mir_snwprintf(str, strSize, L"%i", w);
+}
+
+//============ UNIT CONVERSIONS ============
+
+// temperature conversion
+// tempchar = the string containing the temperature value
+// unit = the unit for temperature
+// return value = the converted temperature with degree sign and unit; if fails, return N/A
+void GetTemp(wchar_t *tempchar, wchar_t *unit, wchar_t* str)
+{
+ // unit can be C, F
+ double temp;
+ wchar_t tstr[20];
+
+ TrimString(tempchar);
+ if (tempchar[0] == '-' && tempchar[1] == ' ')
+ memmove(&tempchar[1], &tempchar[2], sizeof(wchar_t)*(mir_wstrlen(&tempchar[2]) + 1));
+
+ // quit if the value obtained is N/A or not a number
+ if (!mir_wstrcmp(tempchar, NODATA) || !mir_wstrcmp(tempchar, L"N/A")) {
+ mir_wstrcpy(str, tempchar);
+ return;
+ }
+ if (!is_number(tempchar)) {
+ mir_wstrcpy(str, NODATA);
+ return;
+ }
+
+ // convert the string to an integer
+ temp = _wtof(tempchar);
+
+ // convert all to F first
+ if (!mir_wstrcmpi(unit, L"C")) temp = (temp * 9 / 5) + 32;
+ else if (!mir_wstrcmpi(unit, L"K")) temp = ((temp - 273.15) * 9 / 5) + 32;
+
+ // convert to apporiate unit
+ switch (opt.tUnit) {
+ case 1:
+ // rounding
+ numToStr((temp - 32) / 9 * 5, tstr, _countof(tstr));
+ if (opt.DoNotAppendUnit)
+ wcsncpy_s(str, MAX_DATA_LEN, tstr, _TRUNCATE);
+ else
+ mir_snwprintf(str, MAX_DATA_LEN, L"%s%sC", tstr, opt.DegreeSign);
+ break;
+
+ case 2:
+ numToStr(temp, tstr, _countof(tstr));
+ if (opt.DoNotAppendUnit)
+ wcsncpy_s(str, MAX_DATA_LEN, tstr, _TRUNCATE);
+ else
+ mir_snwprintf(str, MAX_DATA_LEN, L"%s%sF", tstr, opt.DegreeSign);
+ break;
+ }
+}
+
+// temperature conversion
+// tempchar = the string containing the pressure value
+// unit = the unit for pressure
+// return value = the converted pressure with unit; if fail, return the original string
+void GetPressure(wchar_t *tempchar, wchar_t *unit, wchar_t* str)
+{
+ // unit can be kPa, hPa, mb, in, mm, torr
+ double tempunit = 0, output;
+ int intunit;
+
+ // convert the string to a floating point number (always positive)
+ // if it end up with 0, then it's not a number, return the original string and quit
+ output = _wtof(tempchar);
+ if (output == 0) {
+ mir_wstrcpy(str, tempchar);
+ return;
+ }
+
+ // convert all to mb first
+ if (!mir_wstrcmpi(unit, L"KPA"))
+ tempunit = (double)output * 10;
+ else if (!mir_wstrcmpi(unit, L"HPA"))
+ tempunit = (double)output;
+ else if (!mir_wstrcmpi(unit, L"MB"))
+ tempunit = (double)output;
+ else if (!mir_wstrcmpi(unit, L"IN"))
+ tempunit = (double)output * 33.86388;
+ else if (!mir_wstrcmpi(unit, L"MM"))
+ tempunit = (double)output * 1.33322;
+ else if (!mir_wstrcmpi(unit, L"TORR"))
+ tempunit = (double)output * 1.33322;
+
+ // convert to apporiate unit
+ switch (opt.pUnit) {
+ case 1:
+ intunit = (int)(tempunit + 0.5);
+ mir_snwprintf(str, MAX_DATA_LEN, L"%i.%i %s", intunit / 10, intunit % 10, opt.DoNotAppendUnit ? L"" : TranslateT("kPa"));
+ break;
+ case 2:
+ intunit = (int)(tempunit + 0.5);
+ mir_snwprintf(str, MAX_DATA_LEN, L"%i %s", intunit, opt.DoNotAppendUnit ? L"" : TranslateT("mb"));
+ break;
+ case 3:
+ intunit = (int)((tempunit * 10 / 33.86388) + 0.5);
+ mir_snwprintf(str, MAX_DATA_LEN, L"%i.%i %s", intunit / 10, intunit % 10, opt.DoNotAppendUnit ? L"" : TranslateT("in"));
+ break;
+ case 4:
+ intunit = (int)((tempunit * 10 / 1.33322) + 0.5);
+ mir_snwprintf(str, MAX_DATA_LEN, L"%i.%i %s", intunit / 10, intunit % 10, opt.DoNotAppendUnit ? L"" : TranslateT("mm"));
+ break;
+ default:
+ mir_wstrcpy(str, tempchar);
+ break;
+
+ }
+}
+
+// speed conversion
+// tempchar = the string containing the speed value
+// unit = the unit for speed
+// return value = the converted speed with unit; if fail, return _T(""
+void GetSpeed(wchar_t *tempchar, wchar_t *unit, wchar_t *str)
+{
+ // unit can be km/h, mph, m/s, knots
+ double tempunit;
+ wchar_t tstr[20];
+
+ str[0] = 0;
+
+ // convert the string into an integer (always positive)
+ // if the result is 0, then the string is not a number, return _T(""
+ tempunit = _wtof(tempchar);
+ if (tempunit == 0 && tempchar[0] != '0')
+ return;
+
+ // convert all to m/s first
+ if (!mir_wstrcmpi(unit, L"KM/H"))
+ tempunit /= 3.6;
+ // else if ( !mir_wstrcmpi(unit, L"M/S")
+ // tempunit = tempunit;
+ else if (!mir_wstrcmpi(unit, L"MPH"))
+ tempunit *= 0.44704;
+ else if (!mir_wstrcmpi(unit, L"KNOTS"))
+ tempunit *= 0.514444;
+
+ // convert to apporiate unit
+ switch (opt.wUnit) {
+ case 1:
+ numToStr(tempunit * 3.6, tstr, _countof(tstr));
+ mir_snwprintf(str, MAX_DATA_LEN, L"%s %s", tstr, opt.DoNotAppendUnit ? L"" : TranslateT("km/h"));
+ break;
+ case 2:
+ numToStr(tempunit, tstr, _countof(tstr));
+ mir_snwprintf(str, MAX_DATA_LEN, L"%s %s", tstr, opt.DoNotAppendUnit ? L"" : TranslateT("m/s"));
+ break;
+ case 3:
+ numToStr(tempunit / 0.44704, tstr, _countof(tstr));
+ mir_snwprintf(str, MAX_DATA_LEN, L"%s %s", tstr, opt.DoNotAppendUnit ? L"" : TranslateT("mph"));
+ break;
+ case 4:
+ numToStr(tempunit / 0.514444, tstr, _countof(tstr));
+ mir_snwprintf(str, MAX_DATA_LEN, L"%s %s", tstr, opt.DoNotAppendUnit ? L"" : TranslateT("knots"));
+ break;
+ }
+}
+
+// distance conversion
+// tempchar = the string containing the distance value
+// unit = the unit for distance
+// return value = the converted distance with unit; if fail, return original string
+void GetDist(wchar_t *tempchar, wchar_t *unit, wchar_t *str)
+{
+ // unit can be km, miles
+ double tempunit = 0, output;
+ int intunit;
+
+ // convert the string to a floating point number (always positive)
+ // if it end up with 0, then it's not a number, return the original string and quit
+ output = _wtof(tempchar);
+ if (output == 0) {
+ mir_wstrcpy(str, tempchar);
+ return;
+ }
+
+ // convert all to km first
+ if (!mir_wstrcmpi(unit, L"KM"))
+ tempunit = (double)output;
+ else if (!mir_wstrcmpi(unit, L"MILES"))
+ tempunit = (double)output * 1.609;
+
+ // convert to apporiate unit
+ switch (opt.vUnit) {
+ case 1:
+ intunit = (int)((tempunit * 10) + 0.5);
+ mir_snwprintf(str, MAX_DATA_LEN, L"%i.%i %s", intunit / 10, intunit % 10, opt.DoNotAppendUnit ? L"" : TranslateT("km"));
+ break;
+ case 2:
+ intunit = (int)((tempunit * 10 / 1.609) + 0.5);
+ mir_snwprintf(str, MAX_DATA_LEN, L"%i.%i %s", intunit / 10, intunit % 10, opt.DoNotAppendUnit ? L"" : TranslateT("miles"));
+ break;
+ default:
+ mir_wstrcpy(str, tempchar);
+ break;
+ }
+}
+
+// elevation conversion
+// tempchar = the string containing the elevation value
+// unit = the unit for elevation
+// return value = the converted elevation with unit; if fail, return original string
+void GetElev(wchar_t *tempchar, wchar_t *unit, wchar_t *str)
+{
+ // unit can be ft, m
+ double tempunit = 0, output;
+ int intunit;
+
+ // convert the string to a floating point number (always positive)
+ // if it end up with 0, then it's not a number, return the original string and quit
+ output = _wtof(tempchar);
+ if (output == 0) {
+ mir_wstrcpy(str, tempchar);
+ return;
+ }
+
+ // convert all to m first
+ if (!mir_wstrcmpi(unit, L"M"))
+ tempunit = (double)output;
+ else if (!mir_wstrcmpi(unit, L"FT"))
+ tempunit = (double)output / 3.28;
+
+ // convert to apporiate unit
+ switch (opt.eUnit) {
+ case 1:
+ intunit = (int)((tempunit * 10 * 3.28) + 0.5);
+ mir_snwprintf(str, MAX_DATA_LEN, L"%i.%i %s", intunit / 10, intunit % 10, opt.DoNotAppendUnit ? L"" : TranslateT("ft"));
+ break;
+ case 2:
+ intunit = (int)((tempunit * 10) + 0.5);
+ mir_snwprintf(str, MAX_DATA_LEN, L"%i.%i %s", intunit / 10, intunit % 10, opt.DoNotAppendUnit ? L"" : TranslateT("m"));
+ break;
+ default:
+ mir_wstrcpy(str, tempchar);
+ break;
+ }
+}
+
+//============ CONDITION ICON ASSIGNMENT ============
+
+// assign the contact icon (status) from the condition string
+// the description may be different between different sources
+// cond = the string for weather condition
+// return value = status for the icon (ONLINE, OFFLINE, etc)
+
+static const wchar_t *statusStr[10] = { L"Lightning", L"Fog", L"Snow Shower", L"Snow", L"Rain Shower", L"Rain", L"Partly Cloudy", L"Cloudy", L"Sunny", L"N/A" };
+static const WORD statusValue[10] = { LIGHT, FOG, SSHOWER, SNOW, RSHOWER, RAIN, PCLOUDY, CLOUDY, SUNNY, NA };
+
+WORD GetIcon(const wchar_t* cond, WIDATA *Data)
+{
+ // set the icon using ini
+ for (int i = 0; i < 10; i++)
+ if (IsContainedInCondList(cond, &Data->CondList[i]))
+ return statusValue[i];
+
+ // internal detection
+ if (
+ wcsstr(cond, L"mainy sunny") != nullptr ||
+ wcsstr(cond, L"mainy clear") != nullptr ||
+ wcsstr(cond, L"partly cloudy") != nullptr ||
+ wcsstr(cond, L"mostly") != nullptr ||
+ wcsstr(cond, L"clouds") != nullptr) {
+ return PCLOUDY;
+ }
+ else if (
+ wcsstr(cond, L"sunny") != nullptr ||
+ wcsstr(cond, L"clear") != nullptr ||
+ wcsstr(cond, L"fair") != nullptr) {
+ return SUNNY;
+ }
+ else if (
+ wcsstr(cond, L"thunder") != nullptr ||
+ wcsstr(cond, L"t-storm") != nullptr) {
+ return LIGHT;
+ }
+ else if (
+ wcsstr(cond, L"cloud") != nullptr ||
+ wcsstr(cond, L"overcast") != nullptr) {
+ return CLOUDY;
+ }
+ else if (
+ wcsstr(cond, L"fog") != nullptr ||
+ wcsstr(cond, L"mist") != nullptr ||
+ wcsstr(cond, L"smoke") != nullptr ||
+ wcsstr(cond, L"sand") != nullptr ||
+ wcsstr(cond, L"dust") != nullptr ||
+ wcsstr(cond, L"haze") != nullptr) {
+ return FOG;
+ }
+ else if (
+ (wcsstr(cond, L"shower") != nullptr && wcsstr(cond, L"snow") != nullptr) ||
+ wcsstr(cond, L"flurries") != nullptr) {
+ return SSHOWER;
+ }
+ else if (
+ wcsstr(cond, L"rain shower") != nullptr ||
+ wcsstr(cond, L"shower") != nullptr) {
+ return RSHOWER;
+ }
+ else if (
+ wcsstr(cond, L"snow") != nullptr ||
+ wcsstr(cond, L"ice") != nullptr ||
+ wcsstr(cond, L"freezing") != nullptr ||
+ wcsstr(cond, L"wintry") != nullptr) {
+ return SNOW;
+ }
+ else if (
+ wcsstr(cond, L"drizzle") != nullptr ||
+ wcsstr(cond, L"rain") != nullptr) {
+ return RAIN;
+ }
+
+ // set the icon using langpack
+ for (int i = 0; i < 9; i++) {
+ wchar_t LangPackStr[64], LangPackStr1[128];
+ int j = 0;
+ do {
+ j++;
+ // using the format _T("# Weather <condition name> <counter> #"
+ mir_snwprintf(LangPackStr, L"# Weather %s %i #", statusStr[i], j);
+ wcsncpy_s(LangPackStr1, TranslateW(LangPackStr), _TRUNCATE);
+ CharLowerBuff(LangPackStr1, (DWORD)mir_wstrlen(LangPackStr1));
+ if (wcsstr(cond, LangPackStr1) != nullptr)
+ return statusValue[i];
+ // loop until the translation string exists (ie, the translated string is differ from original)
+ } while (mir_wstrcmp(TranslateW(LangPackStr), LangPackStr));
+ }
+
+ return NA;
+}
+
+//============ STRING CONVERSIONS ============
+//
+// this function convert the string to the format with 1 upper case followed by lower case char
+void CaseConv(wchar_t *str)
+{
+ bool nextUp = true;
+
+ CharLowerBuffW(str, (DWORD)mir_wstrlen(str));
+ for (wchar_t *pstr = str; *pstr; pstr++) {
+ if (*pstr == ' ' || *pstr == '-')
+ nextUp = true;
+ else if (nextUp) {
+ CharUpperBuffW(pstr, 1);
+ nextUp = false;
+ }
+ }
+}
+
+// the next 2 functions are copied from miranda source
+// str = the string to modify
+//
+void TrimString(char *str)
+{
+ size_t len, start;
+
+ len = mir_strlen(str);
+ while (len && (unsigned char)str[len - 1] <= ' ') str[--len] = 0;
+ for (start = 0; (unsigned char)str[start] <= ' ' && str[start]; start++);
+ memmove(str, str + start, len - start + 1);
+}
+
+void TrimString(WCHAR *str)
+{
+ size_t len, start;
+
+ len = mir_wstrlen(str);
+ while (len && (unsigned char)str[len - 1] <= ' ') str[--len] = 0;
+ for (start = 0; (unsigned char)str[start] <= ' ' && str[start]; start++);
+ memmove(str, str + start, (len - start + 1)*sizeof(WCHAR));
+}
+
+// convert \t to tab and \n to linefeed
+void ConvertBackslashes(char *str)
+{
+ for (char *pstr = str; *pstr; pstr = CharNextA(pstr)) {
+ if (*pstr == '\\') {
+ switch (pstr[1]) {
+ case 'n': *pstr = '\n'; break;
+ case 't': *pstr = '\t'; break;
+ default: *pstr = pstr[1]; break;
+ }
+ memmove(pstr + 1, pstr + 2, mir_strlen(pstr + 2) + 1);
+ }
+ }
+}
+
+// replace spaces with _T("%20"
+// dis = original string
+// return value = the modified string with space -> _T("%20"
+char *GetSearchStr(char *dis)
+{
+ char *pstr = dis;
+ size_t len = mir_strlen(dis);
+ while (*pstr != 0) {
+ if (*pstr == ' ') {
+ memmove(pstr + 3, pstr + 1, len);
+ memcpy(pstr, L"%20", 3);
+ pstr += 2;
+ }
+ pstr++;
+ len--;
+ }
+ return dis;
+}
+
+//============ ICON ASSIGNMENT ============
+//
+// make display and history strings
+// w = WEATHERINFO data to be parsed
+// dis = the string to parse
+// return value = the parsed string
+wchar_t* GetDisplay(WEATHERINFO *w, const wchar_t *dis, wchar_t* str)
+{
+ wchar_t lpzDate[32], chr;
+ char name[256], temp[2];
+ DBVARIANT dbv;
+ size_t i;
+
+ // Clear the string
+ str[0] = 0;
+
+ // looking character by character
+ for (i = 0; i < mir_wstrlen(dis); i++) {
+ // for the escape characters
+ if (dis[i] == '\\') {
+ i++;
+ chr = dis[i];
+ switch (chr) {
+ case '%': mir_wstrcat(str, L"%"); break;
+ case 't': mir_wstrcat(str, L"\t"); break;
+ case 'n': mir_wstrcat(str, L"\r\n"); break;
+ case '\\': mir_wstrcat(str, L"\\"); break;
+ }
+ }
+
+ // for the % varaibles
+ else if (dis[i] == '%') {
+ i++;
+ chr = dis[i];
+ // turn capitalized characters to small case
+ if (chr < 'a' && chr != '[' && chr != '%') chr = (char)((int)chr + 32);
+ switch (chr) {
+ case 'c': mir_wstrcat(str, w->cond); break;
+ case 'd': // get the current date
+ GetDateFormat(LOCALE_USER_DEFAULT, DATE_SHORTDATE, nullptr, nullptr, lpzDate, _countof(lpzDate));
+ mir_wstrcat(str, lpzDate); break;
+ case 'e': mir_wstrcat(str, w->dewpoint); break;
+ case 'f': mir_wstrcat(str, w->feel); break;
+ case 'h': mir_wstrcat(str, w->high); break;
+ case 'i': mir_wstrcat(str, w->winddir); break;
+ case 'l': mir_wstrcat(str, w->low); break;
+ case 'm': mir_wstrcat(str, w->humid); break;
+ case 'n': mir_wstrcat(str, w->city); break;
+ case 'p': mir_wstrcat(str, w->pressure); break;
+ case 'r': mir_wstrcat(str, w->sunrise); break;
+ case 's': mir_wstrcat(str, w->id); break;
+ case 't': mir_wstrcat(str, w->temp); break;
+ case 'u':
+ if (mir_wstrcmp(w->update, NODATA)) mir_wstrcat(str, w->update);
+ else mir_wstrcat(str, TranslateT("<unknown time>"));
+ break;
+ case 'v': mir_wstrcat(str, w->vis); break;
+ case 'w': mir_wstrcat(str, w->wind); break;
+ case 'y': mir_wstrcat(str, w->sunset); break;
+ case '%': mir_wstrcat(str, L"%"); break;
+ case '[': // custom variables
+ i++;
+ name[0] = 0;
+ // read the entire variable name
+ while (dis[i] != ']' && i < mir_wstrlen(dis)) {
+ mir_snprintf(temp, "%c", dis[i++]);
+ mir_strcat(name, temp);
+ }
+ // access the database to get its value
+ if (!db_get_ws(w->hContact, WEATHERCONDITION, name, &dbv)) {
+ if (dbv.pwszVal != TranslateW(NODATA) && dbv.pwszVal != TranslateT("<Error>"))
+ mir_wstrcat(str, dbv.pwszVal);
+ db_free(&dbv);
+ }
+ break;
+ }
+ }
+ // if the character is not a variable, write the original character to the new string
+ else {
+ mir_snwprintf(lpzDate, L"%c", dis[i]);
+ mir_wstrcat(str, lpzDate);
+ }
+ }
+
+ return str;
+}
+
+wchar_t svcReturnText[MAX_TEXT_SIZE];
+INT_PTR GetDisplaySvcFunc(WPARAM wParam, LPARAM lParam)
+{
+ WEATHERINFO winfo = LoadWeatherInfo(wParam);
+ return (INT_PTR)GetDisplay(&winfo, (wchar_t*)lParam, svcReturnText);
+}
+
+//============ ID MANAGEMENT ============
+//
+// get service data module internal name
+// mod/id <- the mod part
+// pszID = original 2-part id, return the service internal name
+void GetSvc(wchar_t *pszID)
+{
+ wchar_t *chop = wcsstr(pszID, L"/");
+ if (chop != nullptr) *chop = '\0';
+ else pszID[0] = 0;
+}
+
+// get the id use for update without the service internal name
+// mod/id <- the id part
+// pszID = original 2-part id, return the single part id
+void GetID(wchar_t *pszID)
+{
+ wchar_t *chop = wcsstr(pszID, L"/");
+ if (chop != nullptr) mir_wstrcpy(pszID, chop + 1);
+ else pszID[0] = 0;
+}
+
+//============ WEATHER ERROR CODE ============
+//
+// Get the text when an error code is specified
+// code = the error code obtained when updating weather
+// str = the string for the error
+//
+wchar_t *GetError(int code)
+{
+ wchar_t *str, str2[100];
+ switch (code) {
+ case 10: str = E10; break;
+ case 11: str = E11; break;
+ case 12: str = E12; break;
+ case 20: str = E20; break;
+ case 30: str = E30; break;
+ case 40: str = E40; break;
+ case 42: str = E42; break;
+ case 43: str = E43; break;
+ case 99: str = E99; break;
+ case 204: str = E204; break;
+ case 301: str = E301; break;
+ case 305: str = E305; break;
+ case 307: str = E307; break;
+ case 400: str = E400; break;
+ case 401: str = E401; break;
+ case 402: str = E402; break;
+ case 403: str = E403; break;
+ case 404: str = E404; break;
+ case 405: str = E405; break;
+ case 407: str = E407; break;
+ case 410: str = E410; break;
+ case 500: str = E500; break;
+ case 502: str = E502; break;
+ case 503: str = E503; break;
+ case 504: str = E504; break;
+ default:
+ mir_snwprintf(str2, TranslateT("HTTP Error %i"), code);
+ str = str2;
+ break;
+ }
+ return mir_wstrdup(str);
+}
diff --git a/protocols/Weather/src/weather_data.cpp b/protocols/Weather/src/weather_data.cpp
new file mode 100644
index 0000000000..e36ae9dc5b
--- /dev/null
+++ b/protocols/Weather/src/weather_data.cpp
@@ -0,0 +1,439 @@
+/*
+Weather Protocol plugin for Miranda IM
+Copyright (c) 2012 Miranda NG team
+Copyright (c) 2005-2011 Boris Krasnovskiy All Rights Reserved
+Copyright (c) 2002-2005 Calvin Che
+
+This program is free software; you can redistribute it and/or
+modify it under the terms of the GNU General Public License
+as published by the Free Software Foundation; version 2
+of the License.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+/*
+This file contain the source related loading, obtaining, and
+saving individual weather data for a weather contact.
+*/
+
+#include "stdafx.h"
+
+//============ LOAD WEATHER INFO FROM A CONTACT ============
+// get station ID from DB
+// hContact = the current contact handle
+// return value = the string for station ID
+//
+void GetStationID(MCONTACT hContact, wchar_t* id, int idlen)
+{
+ // accessing the database
+ if (db_get_wstatic(hContact, MODULENAME, "ID", id, idlen))
+ id[0] = 0;
+}
+
+// initialize weather info by loading values from database
+// hContact = current contact handle
+// return value = the current weather information in WEATHERINFO struct
+WEATHERINFO LoadWeatherInfo(MCONTACT hContact)
+{
+ // obtaining values from the DB
+ // assuming station ID must exist at all time, but others does not have to
+ // if the string is not found in database, a value of "N/A" is stored in the field
+ WEATHERINFO winfo;
+ winfo.hContact = hContact;
+ GetStationID(hContact, winfo.id, _countof(winfo.id));
+
+ if (db_get_wstatic(hContact, MODULENAME, "Nick", winfo.city, _countof(winfo.city)))
+ wcsncpy(winfo.city, NODATA, _countof(winfo.city) - 1);
+ if (db_get_wstatic(hContact, WEATHERCONDITION, "Update", winfo.update, _countof(winfo.update)))
+ wcsncpy(winfo.update, NODATA, _countof(winfo.update) - 1);
+ if (db_get_wstatic(hContact, WEATHERCONDITION, "Condition", winfo.cond, _countof(winfo.cond)))
+ wcsncpy(winfo.cond, NODATA, _countof(winfo.cond) - 1);
+ if (db_get_wstatic(hContact, WEATHERCONDITION, "Temperature", winfo.temp, _countof(winfo.temp)))
+ wcsncpy(winfo.temp, NODATA, _countof(winfo.temp) - 1);
+ if (db_get_wstatic(hContact, WEATHERCONDITION, "High", winfo.high, _countof(winfo.high)))
+ wcsncpy(winfo.high, NODATA, _countof(winfo.high) - 1);
+ if (db_get_wstatic(hContact, WEATHERCONDITION, "Low", winfo.low, _countof(winfo.low)))
+ wcsncpy(winfo.low, NODATA, _countof(winfo.low) - 1);
+ if (db_get_wstatic(hContact, WEATHERCONDITION, "Sunset", winfo.sunset, _countof(winfo.sunset)))
+ wcsncpy(winfo.sunset, NODATA, _countof(winfo.sunset) - 1);
+ if (db_get_wstatic(hContact, WEATHERCONDITION, "Sunrise", winfo.sunrise, _countof(winfo.sunrise)))
+ wcsncpy(winfo.sunrise, NODATA, _countof(winfo.sunrise) - 1);
+ if (db_get_wstatic(hContact, WEATHERCONDITION, "Wind Speed", winfo.wind, _countof(winfo.wind)))
+ wcsncpy(winfo.wind, NODATA, _countof(winfo.wind) - 1);
+ if (db_get_wstatic(hContact, WEATHERCONDITION, "Wind Direction", winfo.winddir, _countof(winfo.winddir)))
+ wcsncpy(winfo.winddir, NODATA, _countof(winfo.winddir) - 1);
+ if (db_get_wstatic(hContact, WEATHERCONDITION, "Dewpoint", winfo.dewpoint, _countof(winfo.dewpoint)))
+ wcsncpy(winfo.dewpoint, NODATA, _countof(winfo.dewpoint) - 1);
+ if (db_get_wstatic(hContact, WEATHERCONDITION, "Pressure", winfo.pressure, _countof(winfo.pressure)))
+ wcsncpy(winfo.pressure, NODATA, _countof(winfo.pressure) - 1);
+ if (db_get_wstatic(hContact, WEATHERCONDITION, "Visibility", winfo.vis, _countof(winfo.vis)))
+ wcsncpy(winfo.vis, NODATA, _countof(winfo.vis) - 1);
+ if (db_get_wstatic(hContact, WEATHERCONDITION, "Humidity", winfo.humid, _countof(winfo.humid)))
+ wcsncpy(winfo.humid, NODATA, _countof(winfo.humid) - 1);
+ if (db_get_wstatic(hContact, WEATHERCONDITION, "Feel", winfo.feel, _countof(winfo.feel)))
+ wcsncpy(winfo.feel, NODATA, _countof(winfo.feel) - 1);
+
+ winfo.status = g_plugin.getWord(hContact, "StatusIcon", ID_STATUS_OFFLINE);
+ return winfo;
+}
+
+// getting weather setting from database
+// return 0 on success
+int DBGetData(MCONTACT hContact, char *setting, DBVARIANT *dbv)
+{
+ if (db_get_ws(hContact, WEATHERCONDITION, setting, dbv)) {
+ size_t len = mir_strlen(setting) + 1;
+ char *set = (char*)alloca(len + 1);
+ *set = '#';
+ memcpy(set + 1, setting, len);
+
+ if (db_get_ws(hContact, WEATHERCONDITION, set, dbv))
+ return 1;
+ }
+ return 0;
+}
+
+
+//============ ERASE OLD SETTINGS ============
+//
+// erase all current weather information from database
+// lastver = the last used version number in dword (using PLUGIN_MAKE_VERSION)
+void EraseAllInfo()
+{
+ wchar_t str[255];
+ int ContactCount = 0;
+ MCONTACT LastContact = NULL;
+ DBVARIANT dbv;
+ // loop through all contacts
+ for (auto &hContact : Contacts(MODULENAME)) {
+ g_plugin.setWord(hContact, "Status", ID_STATUS_OFFLINE);
+ g_plugin.setWord(hContact, "StatusIcon", ID_STATUS_OFFLINE);
+ db_unset(hContact, "CList", "MyHandle");
+ // clear all data
+ if (g_plugin.getWString(hContact, "Nick", &dbv)) {
+ g_plugin.setWString(hContact, "Nick", TranslateT("<Enter city name here>"));
+ g_plugin.setString(hContact, "LastLog", "never");
+ g_plugin.setString(hContact, "LastCondition", "None");
+ g_plugin.setString(hContact, "LastTemperature", "None");
+ }
+ else db_free(&dbv);
+
+ DBDataManage(hContact, WDBM_REMOVE, 0, 0);
+ db_set_s(hContact, "UserInfo", "MyNotes", "");
+ // reset update tag
+ g_plugin.setByte(hContact, "IsUpdated", FALSE);
+ // reset logging settings
+ if (!g_plugin.getWString(hContact, "Log", &dbv)) {
+ g_plugin.setByte(hContact, "File", (BYTE)(dbv.pwszVal[0] != 0));
+ db_free(&dbv);
+ }
+ else g_plugin.setByte(hContact, "File", FALSE);
+
+ // if no default station find, assign a new one
+ if (opt.Default[0] == 0) {
+ GetStationID(hContact, opt.Default, _countof(opt.Default));
+
+ opt.DefStn = hContact;
+ if (!g_plugin.getWString(hContact, "Nick", &dbv)) {
+ mir_snwprintf(str, TranslateT("%s is now the default weather station"), dbv.pwszVal);
+ db_free(&dbv);
+ MessageBox(nullptr, str, TranslateT("Weather Protocol"), MB_OK | MB_ICONINFORMATION);
+ }
+ }
+ // get the handle of the default station
+ if (opt.DefStn == NULL) {
+ if (!g_plugin.getWString(hContact, "ID", &dbv)) {
+ if (!mir_wstrcmp(dbv.pwszVal, opt.Default))
+ opt.DefStn = hContact;
+ db_free(&dbv);
+ }
+ }
+ ContactCount++; // increment counter
+ LastContact = hContact;
+ }
+
+ // if weather contact exists, set the status to online so it is ready for update
+ // if (ContactCount != 0) status = ONLINE;
+ // in case where the default station is missing
+ if (opt.DefStn == NULL && ContactCount != 0) {
+ if (!g_plugin.getWString(LastContact, "ID", &dbv)) {
+ wcsncpy(opt.Default, dbv.pwszVal, _countof(opt.Default) - 1);
+ db_free(&dbv);
+ }
+ opt.DefStn = LastContact;
+ if (!g_plugin.getWString(LastContact, "Nick", &dbv)) {
+ mir_snwprintf(str, TranslateT("%s is now the default weather station"), dbv.pwszVal);
+ db_free(&dbv);
+ MessageBox(nullptr, str, TranslateT("Weather Protocol"), MB_OK | MB_ICONINFORMATION);
+ }
+ }
+ // save option in case of default station changed
+ g_plugin.setWString("Default", opt.Default);
+}
+
+void ConvertDataValue(WIDATAITEM *UpdateData, wchar_t *Data)
+{
+ wchar_t str[MAX_DATA_LEN];
+
+ // convert the unit
+ if (mir_wstrcmp(Data, TranslateT("<Error>")) && mir_wstrcmp(Data, NODATA) && mir_wstrcmp(Data, TranslateW(NODATA))) {
+ // temperature
+ if (!mir_wstrcmp(UpdateData->Name, L"Temperature") || !mir_wstrcmp(UpdateData->Name, L"High") ||
+ !mir_wstrcmp(UpdateData->Name, L"Low") || !mir_wstrcmp(UpdateData->Name, L"Feel") ||
+ !mir_wstrcmp(UpdateData->Name, L"Dewpoint") ||
+ !mir_wstrcmpi(UpdateData->Unit, L"C") || !mir_wstrcmpi(UpdateData->Unit, L"F") ||
+ !mir_wstrcmpi(UpdateData->Unit, L"K")) {
+ GetTemp(Data, UpdateData->Unit, str);
+ mir_wstrcpy(Data, str);
+ }
+ // pressure
+ else if (!mir_wstrcmp(UpdateData->Name, L"Pressure") || !mir_wstrcmpi(UpdateData->Unit, L"HPA") ||
+ !mir_wstrcmpi(UpdateData->Unit, L"KPA") || !mir_wstrcmpi(UpdateData->Unit, L"MB") ||
+ !mir_wstrcmpi(UpdateData->Unit, L"TORR") || !mir_wstrcmpi(UpdateData->Unit, L"IN") ||
+ !mir_wstrcmpi(UpdateData->Unit, L"MM")) {
+ GetPressure(Data, UpdateData->Unit, str);
+ mir_wstrcpy(Data, str);
+ }
+ // speed
+ else if (!mir_wstrcmp(UpdateData->Name, L"Wind Speed") || !mir_wstrcmpi(UpdateData->Unit, L"KM/H") ||
+ !mir_wstrcmpi(UpdateData->Unit, L"M/S") || !mir_wstrcmpi(UpdateData->Unit, L"MPH") ||
+ !mir_wstrcmpi(UpdateData->Unit, L"KNOTS")) {
+ GetSpeed(Data, UpdateData->Unit, str);
+ mir_wstrcpy(Data, str);
+ }
+ // visibility
+ else if (!mir_wstrcmp(UpdateData->Name, L"Visibility") || !mir_wstrcmpi(UpdateData->Unit, L"KM") ||
+ !mir_wstrcmpi(UpdateData->Unit, L"MILES")) {
+ GetDist(Data, UpdateData->Unit, str);
+ mir_wstrcpy(Data, str);
+ }
+ // elevation
+ else if (!mir_wstrcmp(UpdateData->Name, L"Elevation") || !mir_wstrcmpi(UpdateData->Unit, L"FT") ||
+ !mir_wstrcmpi(UpdateData->Unit, L"M")) {
+ GetElev(Data, UpdateData->Unit, str);
+ mir_wstrcpy(Data, str);
+ }
+ // converting case for condition to the upper+lower format
+ else if (!mir_wstrcmpi(UpdateData->Unit, L"COND"))
+ CaseConv(Data);
+ // degree sign
+ else if (!mir_wstrcmpi(UpdateData->Unit, L"DEG")) {
+ if (!opt.DoNotAppendUnit) mir_wstrcat(Data, opt.DegreeSign);
+ }
+ // percent sign
+ else if (!mir_wstrcmpi(UpdateData->Unit, L"%")) {
+ if (!opt.DoNotAppendUnit) mir_wstrcat(Data, L"%");
+ }
+ // truncating strings for day/month to 2 or 3 characters
+ else if (!mir_wstrcmpi(UpdateData->Unit, L"DAY") || !mir_wstrcmpi(UpdateData->Unit, L"MONTH"))
+ if (opt.dUnit > 1 && mir_wstrlen(Data) > opt.dUnit)
+ Data[opt.dUnit] = '\0';
+ }
+}
+
+//============ GET THE VALUE OF A DATAITEM ============
+//
+// get the value of the data using the start, end strings
+// UpdateData = the WIDATAITEM struct containing start, end, unit
+// Data = the string containing weather data obtained from UpdateData
+// global var. used: szInfo = the downloaded string
+//
+void GetDataValue(WIDATAITEM *UpdateData, wchar_t *Data, wchar_t** szData)
+{
+ wchar_t last = 0, current, *start, *end;
+ unsigned startloc = 0, endloc = 0, respos = 0;
+ BOOL tag = FALSE, symb = FALSE;
+ wchar_t *szInfo = *szData;
+
+ Data[0] = 0;
+ // parse the data if available
+ if (UpdateData->Start[0] == 0 && UpdateData->End[0] == 0) return;
+ start = szInfo;
+ // the start string must be found
+ if (UpdateData->Start[0] != 0) {
+ start = wcsstr(szInfo, UpdateData->Start);
+ if (start != nullptr) {
+ // set the starting location for getting data
+ start += mir_wstrlen(UpdateData->Start);
+ szInfo = start;
+ }
+ }
+
+ // the end string must be found too
+ if (UpdateData->End[0] != 0)
+ end = wcsstr(szInfo, UpdateData->End);
+ else
+ end = wcsstr(szInfo, L" ");
+
+ if (end != nullptr) {
+ // set the ending location
+ startloc = 0;
+ endloc = end - szInfo;
+ end += mir_wstrlen(UpdateData->End);
+ last = '\n';
+ }
+
+ // ignore if not both of the string found - this prevent crashes
+ if (start != nullptr && end != nullptr) {
+ // begin reading the data from start location to end location
+ // remove all HTML tag in between, as well as leading space, ending space,
+ // multiple spaces, tabs, and return key
+ while (startloc < endloc) {
+ if (szInfo[startloc] == '<') tag = TRUE;
+ else if (szInfo[startloc] == '&' &&
+ (szInfo[startloc + 1] == ';' || szInfo[startloc + 2] == ';' || szInfo[startloc + 3] == ';' ||
+ szInfo[startloc + 4] == ';' || szInfo[startloc + 5] == ';' || szInfo[startloc + 6] == ';')) {
+ // ...but do NOT strip &minus;
+ if ((endloc - startloc) > 7 && wcsncmp(szInfo + startloc, L"&minus;", 7) == 0) {
+ Data[respos++] = '-';
+ startloc += 7;
+ continue;
+ }
+ symb = TRUE;
+ }
+ else if (szInfo[startloc] == '>') tag = FALSE;
+ else if (szInfo[startloc] == ';') symb = FALSE;
+ else {
+ if (!tag && !symb) {
+ current = szInfo[startloc];
+ if (current == '\n' || current == '\t' || current == ' ' || current == '\r')
+ current = ' ';
+ if (current != ' ' || last != ' ') {
+ if (last != '\n' && (respos != 0 || (respos == 0 && last != ' ')))
+ Data[respos++] = last;
+ last = current;
+ }
+ }
+ }
+ ++startloc;
+ // prevent crashes if the string go over maximun length -> generate an error
+ if (respos >= MAX_DATA_LEN) {
+ if (opt.ShowWarnings && UpdateData->Name[0] != 0 && mir_wstrcmp(UpdateData->Name, L"Ignore")) {
+ mir_snwprintf(Data, MAX_DATA_LEN, TranslateT("Error when obtaining data: %s"), UpdateData->Name);
+ WPShowMessage(Data, SM_WARNING);
+ }
+ wcsncpy(Data, TranslateT("<Error>"), MAX_DATA_LEN);
+ last = ' ';
+ respos = MAX_DATA_LEN - 1;
+ break;
+ }
+ }
+
+ // get the last character
+ if (last != ' ')
+ Data[respos++] = last;
+
+ // null terminate the string
+ Data[respos] = 0;
+
+ // convert the unit
+ ConvertDataValue(UpdateData, Data);
+
+ // remove the string before the data from szInfo
+ szInfo = end;
+ }
+ *szData = szInfo;
+}
+
+//============ ALLOCATE SPACE AND COPY STRING ============
+//
+// copy a string into a new memory location
+// Data = the field the data is copied to
+// Value = the original string, the string where data is copied from
+void wSetData(char **Data, const char *Value)
+{
+ if (Value[0] != 0)
+ *Data = mir_strdup(Value);
+ else
+ *Data = "";
+}
+
+void wSetData(WCHAR **Data, const char *Value)
+{
+ if (Value[0] != 0)
+ *Data = mir_a2u(Value);
+ else
+ *Data = L"";
+}
+
+void wSetData(WCHAR **Data, const WCHAR *Value)
+{
+ if (Value[0] != 0)
+ *Data = mir_wstrdup(Value);
+ else
+ *Data = L"";
+}
+
+// A safer free function that free memory for a string
+// Data = the string occuping the data to be freed
+void wfree(char **Data)
+{
+ if (*Data && mir_strlen(*Data) > 0)
+ mir_free(*Data);
+ *Data = nullptr;
+}
+
+void wfree(WCHAR **Data)
+{
+ if (*Data && mir_wstrlen(*Data) > 0)
+ mir_free(*Data);
+ *Data = nullptr;
+}
+
+//============ MANAGE THE ITEMS STORED IN DB ============
+// get single setting that is found
+// szSetting = the setting name
+// lparam = the counter
+int GetWeatherDataFromDB(const char *szSetting, void *lparam)
+{
+ LIST<char> *pList = (LIST<char>*)lparam;
+ pList->insert(mir_strdup(szSetting));
+ return 0;
+}
+
+// remove or display the weather information for a contact
+// hContact - the contact in which the info is going to be removed
+//
+void DBDataManage(MCONTACT hContact, WORD Mode, WPARAM wParam, LPARAM)
+{
+ // get all the settings and store them in a temporary list
+ LIST<char> arSettings(10);
+ db_enum_settings(hContact, GetWeatherDataFromDB, WEATHERCONDITION, &arSettings);
+
+ // begin deleting settings
+ auto T = arSettings.rev_iter();
+ for (auto &str : T) {
+ ptrW wszText(db_get_wsa(hContact, WEATHERCONDITION, str));
+ if (wszText == nullptr)
+ continue;
+
+ switch (Mode) {
+ case WDBM_REMOVE:
+ db_unset(hContact, WEATHERCONDITION, str);
+ break;
+
+ case WDBM_DETAILDISPLAY:
+ // skip the "WeatherInfo" variable
+ if (!mir_strcmp(str, "WeatherInfo") || !mir_strcmp(str, "Ignore") || str[0] == '#')
+ continue;
+
+ HWND hList = GetDlgItem((HWND)wParam, IDC_DATALIST);
+ LV_ITEM lvi = { 0 };
+ lvi.mask = LVIF_TEXT | LVIF_PARAM;
+ lvi.lParam = T.indexOf(&str);
+ lvi.pszText = TranslateW(_A2T(str));
+ lvi.iItem = ListView_InsertItem(hList, &lvi);
+ lvi.pszText = wszText;
+ ListView_SetItemText(hList, lvi.iItem, 1, wszText);
+ break;
+ }
+ mir_free(str);
+ }
+}
diff --git a/protocols/Weather/src/weather_http.cpp b/protocols/Weather/src/weather_http.cpp
new file mode 100644
index 0000000000..319663bfe7
--- /dev/null
+++ b/protocols/Weather/src/weather_http.cpp
@@ -0,0 +1,157 @@
+/*
+Weather Protocol plugin for Miranda IM
+Copyright (c) 2012 Miranda NG team
+Copyright (c) 2005-2011 Boris Krasnovskiy All Rights Reserved
+Copyright (c) 2002-2005 Calvin Che
+
+This program is free software; you can redistribute it and/or
+modify it under the terms of the GNU General Public License
+as published by the Free Software Foundation; version 2
+of the License.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+/*
+This file contain the source related to downloading weather info
+from the web using netlib
+*/
+
+#include "stdafx.h"
+
+HNETLIBUSER hNetlibUser;
+
+static int findHeader(const NETLIBHTTPREQUEST *nlhrReply, const char *hdr)
+{
+ for (int i = 0; i < nlhrReply->headersCount; i++) {
+ if (_stricmp(nlhrReply->headers[i].szName, hdr) == 0) {
+ return i;
+ }
+ }
+ return -1;
+}
+
+//============ DOWNLOAD NEW WEATHER ============
+//
+// function to download webpage from the internet
+// szUrl = URL of the webpage to be retrieved
+// return value = 0 for success, 1 or HTTP error code for failure
+// global var used: szData, szInfo = containing the retrieved data
+//
+int InternetDownloadFile(char *szUrl, char *cookie, char *userAgent, wchar_t **szData)
+{
+ if (userAgent == nullptr || userAgent[0] == 0)
+ userAgent = NETLIB_USER_AGENT;
+
+ NETLIBHTTPHEADER headers[5];
+ headers[0].szName = "User-Agent";
+ headers[0].szValue = userAgent;
+ headers[1].szName = "Cache-Control";
+ headers[1].szValue = "no-cache";
+ headers[2].szName = "Pragma";
+ headers[2].szValue = "no-cache";
+ headers[3].szName = "Connection";
+ headers[3].szValue = "close";
+ headers[4].szName = "Cookie";
+ headers[4].szValue = cookie;
+
+ // initialize the netlib request
+ NETLIBHTTPREQUEST nlhr = { sizeof(nlhr) };
+ nlhr.requestType = REQUEST_GET;
+ nlhr.flags = NLHRF_DUMPASTEXT | NLHRF_HTTP11 | NLHRF_REDIRECT;
+ nlhr.szUrl = szUrl;
+ nlhr.headers = headers;
+ nlhr.headersCount = _countof(headers);
+
+ if (cookie == nullptr || cookie[0] == 0)
+ --nlhr.headersCount;
+
+ // download the page
+ NETLIBHTTPREQUEST *nlhrReply = Netlib_HttpTransaction(hNetlibUser, &nlhr);
+ if (nlhrReply == nullptr) {
+ // if the data does not downloaded successfully (ie. disconnected), then return 1000 as error code
+ *szData = (wchar_t*)mir_alloc(512);
+ // store the error code in szData
+ mir_wstrcpy(*szData, L"NetLib error occurred!!");
+ return NLHRF_REDIRECT;
+ }
+
+ // if the recieved code is 200 OK
+ int result;
+ if (nlhrReply->resultCode == 200) {
+ if (nlhrReply->dataLength) {
+ bool bIsUtf = false;
+ result = 0;
+
+ // allocate memory and save the retrieved data
+ int i = findHeader(nlhrReply, "Content-Type");
+ // look for Content-Type=utf-8 in header
+ if (i != -1 && strstr(_strlwr(nlhrReply->headers[i].szValue), "utf-8"))
+ bIsUtf = true;
+ else {
+ char *end = nlhrReply->pData;
+ while (end) {
+ // look for
+ // <meta http-equiv="Content-Type" content="utf-8" />
+ char* beg = strstr(end, "<meta");
+ if (beg)
+ {
+ end = strchr(beg, '>');
+ if (end)
+ {
+ char tmp = *end;
+ *end = 0;
+
+ char *method = strstr(beg, "http-equiv=\"");
+ if (method && _strnicmp(method + 12, "Content-Type", 12) == 0 && strstr(method, "utf-8")) {
+ bIsUtf = true;
+ *end = tmp;
+ break;
+ }
+ else *end = tmp;
+ }
+ }
+ else
+ break;
+ }
+ }
+
+ wchar_t *retVal = nullptr;
+ if (bIsUtf)
+ retVal = mir_utf8decodeW(nlhrReply->pData);
+ if (retVal == nullptr)
+ retVal = mir_a2u(nlhrReply->pData);
+ *szData = retVal;
+ }
+ else result = DATA_EMPTY;
+ }
+ // return error code if the recieved code is neither 200 OK nor 302 Moved
+ else {
+ // store the error code in szData
+ CMStringW wszError(FORMAT, L"Error occured! HTTP Error: %i\n", nlhrReply->resultCode);
+ *szData = wszError.Detach();
+ result = nlhrReply->resultCode;
+ }
+
+ // make a copy of the retrieved data, then free the memory of the http reply
+ Netlib_FreeHttpRequest(nlhrReply);
+ return result;
+}
+
+//============ NETLIB INITIALIZATION ============
+//
+// initialize netlib support for weather protocol
+void NetlibInit(void)
+{
+ NETLIBUSER nlu = {};
+ nlu.flags = NUF_OUTGOING | NUF_HTTPCONNS | NUF_NOHTTPSOPTION | NUF_UNICODE;
+ nlu.szSettingsModule = MODULENAME;
+ nlu.szDescriptiveName.w = TranslateT("Weather HTTP connections");
+ hNetlibUser = Netlib_RegisterUser(&nlu);
+}
diff --git a/protocols/Weather/src/weather_icons.cpp b/protocols/Weather/src/weather_icons.cpp
new file mode 100644
index 0000000000..3e043d9280
--- /dev/null
+++ b/protocols/Weather/src/weather_icons.cpp
@@ -0,0 +1,64 @@
+/*
+Weather Protocol plugin for Miranda IM
+Copyright (c) 2012 Miranda NG team
+Copyright (c) 2005-2011 Boris Krasnovskiy All Rights Reserved
+
+This program is free software; you can redistribute it and/or
+modify it under the terms of the GNU General Public License
+as published by the Free Software Foundation; version 2
+of the License.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+
+#include "stdafx.h"
+
+HANDLE hIcoLibIconsChanged = nullptr;
+
+static IconItem iconList[] =
+{
+ { LPGEN("Protocol icon"), "main", IDI_ICON },
+ { LPGEN("Update Disabled"), "disabled", IDI_DISABLED },
+ { LPGEN("View Log"), "log", IDI_LOG },
+ { LPGEN("Update with Clear"), "update2", IDI_UPDATE2 },
+ { LPGEN("View Brief"), "brief", IDI_S },
+ { LPGEN("View Complete"), "read", IDI_READ },
+ { LPGEN("Weather Update"), "update", IDI_UPDATE },
+ { LPGEN("Weather Map"), "map", IDI_MAP },
+ { LPGEN("Popup"), "popup", IDI_POPUP },
+ { LPGEN("No Popup"), "nopopup", IDI_NOPOPUP },
+ { LPGEN("Edit Settings"), "edit", IDI_EDIT },
+};
+
+void InitIcons(void)
+{
+ g_plugin.registerIcon(MODULENAME, iconList, MODULENAME);
+}
+
+HICON LoadIconEx(const char* name, bool big)
+{
+ char szSettingName[100];
+ mir_snprintf(szSettingName, "%s_%s", MODULENAME, name);
+ return IcoLib_GetIcon(szSettingName, big);
+}
+
+HANDLE GetIconHandle(const char* name)
+{
+ for (auto &it : iconList)
+ if (mir_strcmp(it.szName, name) == 0)
+ return it.hIcolib;
+
+ return nullptr;
+}
+
+void ReleaseIconEx(HICON hIcon)
+{
+ IcoLib_ReleaseIcon(hIcon);
+}
diff --git a/protocols/Weather/src/weather_info.cpp b/protocols/Weather/src/weather_info.cpp
new file mode 100644
index 0000000000..a2395d9f69
--- /dev/null
+++ b/protocols/Weather/src/weather_info.cpp
@@ -0,0 +1,240 @@
+/*
+Weather Protocol plugin for Miranda IM
+Copyright (c) 2012 Miranda NG team
+Copyright (c) 2005-2011 Boris Krasnovskiy All Rights Reserved
+Copyright (c) 2002-2005 Calvin Che
+
+This program is free software; you can redistribute it and/or
+modify it under the terms of the GNU General Public License
+as published by the Free Software Foundation; version 2
+of the License.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+
+/*
+This file contain the source for displaying information for the
+ini files, as well as function that are used for debug purpose
+regrading the loading of ini contents
+*/
+
+#include "stdafx.h"
+
+//============ INI INFORMATION ============
+
+// List INI Information for all loaded INI files
+static void INIInfo(HWND hwndDlg)
+{
+ wchar_t str[16];
+ size_t memused = 0;
+
+
+ HWND hIniList = GetDlgItem(hwndDlg, IDC_INFOLIST);
+
+ ListView_DeleteAllItems(hIniList);
+
+ LVITEM lvi = { 0 };
+ lvi.mask = LVIF_TEXT;
+ lvi.iItem = 0;
+ for (WIDATALIST *Item = WIHead; Item != nullptr; Item = Item->next) {
+ // get the data for the ini file
+ lvi.iSubItem = 0;
+ lvi.pszText = Item->Data.InternalName;
+ ListView_InsertItem(hIniList, &lvi);
+ lvi.iSubItem = 1;
+ lvi.pszText = Item->Data.Author;
+ ListView_SetItem(hIniList, &lvi);
+ lvi.iSubItem = 2;
+ lvi.pszText = Item->Data.Version;
+ ListView_SetItem(hIniList, &lvi);
+ lvi.iSubItem = 3;
+ switch (Item->Data.InternalVer) {
+ case 1: lvi.pszText = L"1.0"; break;
+ case 2: lvi.pszText = L"1.1"; break;
+ case 3: lvi.pszText = L"1.1a"; break;
+ case 4: lvi.pszText = L"1.2"; break;
+ case 5: lvi.pszText = L"1.3"; break;
+ case 6: lvi.pszText = L"1.4"; break;
+ case 7: lvi.pszText = L"1.5"; break;
+ default: lvi.pszText = L""; break;
+ }
+ ListView_SetItem(hIniList, &lvi);
+ lvi.iSubItem = 4;
+ lvi.pszText = _ltow(Item->Data.UpdateDataCount, str, 10);
+ ListView_SetItem(hIniList, &lvi);
+ lvi.iSubItem = 5;
+ lvi.pszText = Item->Data.DisplayName;
+ ListView_SetItem(hIniList, &lvi);
+ lvi.iSubItem = 6;
+ lvi.pszText = Item->Data.ShortFileName;
+ ListView_SetItem(hIniList, &lvi);
+
+ memused += Item->Data.MemUsed;
+
+ ++lvi.iItem;
+ }
+ SetDlgItemText(hwndDlg, IDC_INICOUNT, _itow(lvi.iItem, str, 10));
+ SetDlgItemText(hwndDlg, IDC_MEMUSED, _ltow((long)memused, str, 10));
+}
+
+static const struct tag_Columns
+{
+ const wchar_t *name;
+ unsigned size;
+}
+columns[] =
+{
+ { LPGENW("Name"), 70 },
+ { LPGENW("Author"), 100 },
+ { LPGENW("File Version"), 70 },
+ { LPGENW("INI Version"), 70 },
+ { LPGENW("Items"), 40 },
+ { LPGENW("Display Name"), 200 },
+ { LPGENW("File Name"), 150 },
+};
+
+
+INT_PTR CALLBACK DlgProcINIPage(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM)
+{
+ switch (msg) {
+ case WM_INITDIALOG:
+ TranslateDialogDefault(hwndDlg);
+ {
+ HWND hIniList = GetDlgItem(hwndDlg, IDC_INFOLIST);
+ LVCOLUMN lvc = { 0 };
+
+ lvc.mask = LVCF_FMT | LVCF_SUBITEM | LVCF_TEXT | LVCF_WIDTH;
+ lvc.fmt = LVCFMT_LEFT;
+ for (int i = 0; i < 7; ++i) {
+ lvc.iSubItem = i;
+ lvc.pszText = TranslateW(columns[i].name);
+ lvc.cx = columns[i].size;
+ ListView_InsertColumn(hIniList, i, &lvc);
+ }
+ INIInfo(hwndDlg);
+ }
+
+ break;
+
+ case WM_DESTROY:
+ break;
+
+ case WM_COMMAND:
+ if (HIWORD(wParam) == BN_CLICKED &&
+ LOWORD(wParam) == IDC_RELOADINI) {
+ DestroyWIList();
+ LoadWIData(true);
+ INIInfo(hwndDlg);
+ }
+ break;
+ }
+ return 0;
+}
+
+
+// get the info of individual ini file
+// pszSvc = the internal name of the service to get the data
+void GetINIInfo(wchar_t *pszSvc)
+{
+ wchar_t str2[2048];
+ WIDATA *sData = GetWIData(pszSvc);
+ // if the service does not exist among the loaded INI's
+ if (sData == nullptr) {
+ mir_snwprintf(str2, TranslateT("The corresponding INI file for \"%s\" is not found."), pszSvc);
+ MessageBox(nullptr, str2, TranslateT("Weather INI information"), MB_OK | MB_ICONINFORMATION);
+ }
+ // if exist, get the information
+ else {
+ mir_snwprintf(str2, TranslateT("Weather INI information for \"%s\":"), pszSvc);
+ mir_wstrncat(str2, L"\n\n", _countof(str2) - mir_wstrlen(str2));
+ mir_wstrncat(str2, TranslateT("Name:"), _countof(str2) - mir_wstrlen(str2));
+ mir_wstrncat(str2, L"\t\t", _countof(str2) - mir_wstrlen(str2));
+ mir_wstrncat(str2, sData->DisplayName, _countof(str2) - mir_wstrlen(str2));
+ mir_wstrncat(str2, L"\n", _countof(str2) - mir_wstrlen(str2));
+ mir_wstrncat(str2, TranslateT("Internal Name:"), _countof(str2) - mir_wstrlen(str2));
+ mir_wstrncat(str2, L"\t", _countof(str2) - mir_wstrlen(str2));
+ mir_wstrncat(str2, sData->InternalName, _countof(str2) - mir_wstrlen(str2));
+ mir_wstrncat(str2, L"\n", _countof(str2) - mir_wstrlen(str2));
+ mir_wstrncat(str2, TranslateT("Author:"), _countof(str2) - mir_wstrlen(str2));
+ mir_wstrncat(str2, L"\t\t", _countof(str2) - mir_wstrlen(str2));
+ mir_wstrncat(str2, sData->Author, _countof(str2) - mir_wstrlen(str2));
+ mir_wstrncat(str2, L"\n", _countof(str2) - mir_wstrlen(str2));
+ mir_wstrncat(str2, TranslateT("Version:"), _countof(str2) - mir_wstrlen(str2));
+ mir_wstrncat(str2, L"\t\t", _countof(str2) - mir_wstrlen(str2));
+ mir_wstrncat(str2, sData->Version, _countof(str2) - mir_wstrlen(str2));
+ mir_wstrncat(str2, L"\n", _countof(str2) - mir_wstrlen(str2));
+ mir_wstrncat(str2, TranslateT("INI Version:"), _countof(str2) - mir_wstrlen(str2));
+ mir_wstrncat(str2, L"\t", _countof(str2) - mir_wstrlen(str2));
+ switch (sData->InternalVer) {
+ case 1: mir_wstrncat(str2, L"1.0", _countof(str2) - mir_wstrlen(str2)); break;
+ case 2: mir_wstrncat(str2, L"1.1", _countof(str2) - mir_wstrlen(str2)); break;
+ case 3: mir_wstrncat(str2, L"1.1a", _countof(str2) - mir_wstrlen(str2)); break;
+ case 4: mir_wstrncat(str2, L"1.2", _countof(str2) - mir_wstrlen(str2)); break;
+ case 5: mir_wstrncat(str2, L"1.3", _countof(str2) - mir_wstrlen(str2)); break;
+ case 6: mir_wstrncat(str2, L"1.4", _countof(str2) - mir_wstrlen(str2)); break;
+ case 7: mir_wstrncat(str2, L"1.5", _countof(str2) - mir_wstrlen(str2)); break;
+ }
+ mir_wstrncat(str2, L"\n", _countof(str2) - mir_wstrlen(str2));
+ mir_wstrncat(str2, TranslateT("File Name:"), _countof(str2) - mir_wstrlen(str2));
+ mir_wstrncat(str2, L"\t", _countof(str2) - mir_wstrlen(str2));
+ mir_wstrncat(str2, sData->ShortFileName, _countof(str2) - mir_wstrlen(str2));
+ mir_wstrncat(str2, L"\n", _countof(str2) - mir_wstrlen(str2));
+ mir_wstrncat(str2, TranslateT("Item Count:"), _countof(str2) - mir_wstrlen(str2));
+ mir_snwprintf(str2, L"%s\t%i\n", str2, sData->UpdateDataCount);
+ mir_wstrncat(str2, TranslateT("Memory Used:"), _countof(str2) - mir_wstrlen(str2));
+ mir_snwprintf(str2, L"%s\t%i ", str2, sData->MemUsed);
+ mir_wstrncat(str2, TranslateT("bytes"), _countof(str2) - mir_wstrlen(str2));
+ mir_wstrncat(str2, L"\n\n", _countof(str2) - mir_wstrlen(str2));
+ mir_wstrncat(str2, TranslateT("Description:"), _countof(str2) - mir_wstrlen(str2));
+ mir_wstrncat(str2, L"\n", _countof(str2) - mir_wstrlen(str2));
+ mir_wstrncat(str2, sData->Description, _countof(str2) - mir_wstrlen(str2));
+
+ // display the message box and quit
+ MessageBox(nullptr, str2, TranslateT("Weather INI information"), MB_OK | MB_ICONINFORMATION);
+ }
+}
+
+//============ DISPLAY A LIST FOR CUSTOM VARIABLES ============
+//
+// a message box for displaying the list of custom variables
+// can be found when click on "More" in text option dialog
+void MoreVarList(void)
+{
+ wchar_t str[10240], tempstr[1024];
+
+ // heading
+ wcsncpy(str, VARS_LIST, _countof(str) - 1);
+ mir_wstrncat(str, L"\n\n", _countof(str) - mir_wstrlen(str));
+ // loop through all weather services to find custom variables
+ for (WIDATALIST *Item = WIHead; Item != nullptr; Item = Item->next) {
+ // loop through all update items in a service
+ for (WIDATAITEMLIST *WItem = Item->Data.UpdateData; WItem != nullptr; WItem = WItem->Next) {
+ // the custom variable is defined as "%[<variable name>]"
+ // ignore the "hi" item and hidden items
+ if (mir_wstrcmp(WItem->Item.Name, L"Ignore") && WItem->Item.Name[0] != '#') {
+ mir_snwprintf(tempstr, L"%c[%s]", '%', WItem->Item.Name);
+ wchar_t *find = wcsstr(str, tempstr);
+ // if the custom variable does not exist in the list, add it to the list
+ if (find == nullptr) {
+ mir_wstrncat(str, tempstr, _countof(str) - mir_wstrlen(str));
+ mir_wstrncat(str, L", ", _countof(str) - mir_wstrlen(str));
+ }
+ }
+ }
+ }
+ // remove the last comma in the list
+ wchar_t* find = wcsrchr(str, ',');
+ if (find != nullptr)
+ *find = '\0';
+
+ // display the list in a message box
+ MessageBox(nullptr, str, TranslateT("More Variables"), MB_OK | MB_ICONINFORMATION | MB_TOPMOST);
+}
+
diff --git a/protocols/Weather/src/weather_ini.cpp b/protocols/Weather/src/weather_ini.cpp
new file mode 100644
index 0000000000..000eab1bc9
--- /dev/null
+++ b/protocols/Weather/src/weather_ini.cpp
@@ -0,0 +1,592 @@
+/*
+Weather Protocol plugin for Miranda IM
+Copyright (c) 2012 Miranda NG team
+Copyright (c) 2005-2011 Boris Krasnovskiy All Rights Reserved
+Copyright (c) 2002-2005 Calvin Che
+
+This program is free software; you can redistribute it and/or
+modify it under the terms of the GNU General Public License
+as published by the Free Software Foundation; version 2
+of the License.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+
+/*
+This file contain the source related to loading the reading the
+weather ini files and store them into memory. Also containing
+code for unloading and getting weather data from the ini settings.
+*/
+
+#include "stdafx.h"
+
+HWND hWndSetup;
+
+//============ DATA LIST (LINKED LIST) ============
+//
+// add an item into weather service data list
+// Data = the service data to be added to the list
+static void WIListAdd(WIDATA Data)
+{
+ // create a new datalist item and point to the data
+ WIDATALIST *newItem = (WIDATALIST*)mir_alloc(sizeof(WIDATALIST));
+ newItem->Data = Data;
+ // add to the linked list
+ newItem->next = nullptr;
+ if (WITail == nullptr) WIHead = newItem;
+ else WITail->next = newItem;
+ WITail = newItem;
+}
+
+// get the service data (from loaded ini file) by internal name
+// pszServ = internal name for the service
+// return value = the matching WIDATA struct for pszServ, NULL if no match found
+WIDATA* GetWIData(wchar_t *pszServ)
+{
+ // loop through the list to find matching internal name
+ for (WIDATALIST *Item = WIHead; Item != nullptr; Item = Item->next)
+ // if internal name found, return the data
+ if (mir_wstrcmp(Item->Data.InternalName, pszServ) == 0)
+ return &Item->Data;
+
+ // return NULL when no match found
+ return nullptr;
+}
+
+//============ DATA ITEM LIST (LINKED LIST) ============
+//
+// add a new update item into the current list
+void WIItemListAdd(WIDATAITEM *DataItem, WIDATA *Data)
+{
+ WIDATAITEMLIST *newItem = (WIDATAITEMLIST*)mir_alloc(sizeof(WIDATAITEMLIST));
+ newItem->Item = *DataItem;
+ newItem->Next = nullptr;
+ if (Data->UpdateData == nullptr) Data->UpdateData = newItem;
+ else Data->UpdateDataTail->Next = newItem;
+ Data->UpdateDataTail = newItem;
+}
+
+// reset the data item by using empty string
+// Item = the item to set
+// name = the string to store in the "name" field
+void ResetDataItem(WIDATAITEM *Item, const wchar_t *name)
+{
+ Item->Name = mir_wstrdup(name);
+ Item->Start = L"";
+ Item->End = L"";
+ Item->Unit = L"";
+ Item->Url = "";
+ Item->Break = L"";
+ Item->Type = 0;
+}
+
+// free the data item by using empty string
+// Item = the item to free
+void FreeDataItem(WIDATAITEM *Item)
+{
+ wfree(&Item->Name);
+ wfree(&Item->Start);
+ wfree(&Item->End);
+ wfree(&Item->Unit);
+ wfree(&Item->Url);
+ wfree(&Item->Break);
+}
+
+//============ Condition Icon List ============
+//
+// initiate icon assignmet list
+void WICondListInit(WICONDLIST *List)
+{
+ List->Tail = nullptr;
+ List->Head = nullptr;
+}
+
+// add a new update item into the current list
+void WICondListAdd(char *str, WICONDLIST *List)
+{
+ WICONDITEM *newItem = (WICONDITEM*)mir_alloc(sizeof(WICONDITEM));
+ wSetData(&newItem->Item, str);
+ CharLowerBuff(newItem->Item, (DWORD)mir_wstrlen(newItem->Item));
+ newItem->Next = nullptr;
+ if (List->Tail == nullptr) List->Head = newItem;
+ else List->Tail->Next = newItem;
+ List->Tail = newItem;
+}
+
+// check if the condition string matched for the assignment
+bool IsContainedInCondList(const wchar_t *pszStr, WICONDLIST *List)
+{
+ // loop through the list to find matching internal name
+ for (WICONDITEM *Item = List->Head; Item != nullptr; Item = Item->Next) {
+ // if internal name found, return true indicating that the data is found
+ if (wcsstr(pszStr, Item->Item))
+ return true;
+
+ }
+ // return false when no match found
+ return false;
+}
+
+// free the memory for icon assignment list
+void DestroyCondList(WICONDLIST *List)
+{
+ // free the list one by one
+ for (WICONDITEM *temp = List->Head; temp != nullptr; temp = List->Head) {
+ List->Head = temp->Next;
+ wfree(&temp->Item); // free the data struct
+ mir_free(temp);
+ }
+ // make sure the entire list is clear
+ List->Tail = nullptr;
+}
+
+
+//============ WEATHER INI SETUP DIALOG ============
+//
+static INT_PTR CALLBACK DlgProcSetup(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam)
+{
+ switch (msg) {
+ case WM_INITDIALOG:
+ TranslateDialogDefault(hwndDlg);
+
+ // make the buttons flat
+ SendDlgItemMessage(hwndDlg, IDC_STEP1, BUTTONSETASFLATBTN, TRUE, 0);
+ SendDlgItemMessage(hwndDlg, IDC_STEP2, BUTTONSETASFLATBTN, TRUE, 0);
+ SendDlgItemMessage(hwndDlg, IDC_STEP3, BUTTONSETASFLATBTN, TRUE, 0);
+ SendDlgItemMessage(hwndDlg, IDC_STEP4, BUTTONSETASFLATBTN, TRUE, 0);
+
+ // set icons
+ Window_SetIcon_IcoLib(hwndDlg, GetIconHandle("main"));
+
+ WindowList_Add(hWindowList, hwndDlg);
+ ShowWindow(hwndDlg, SW_SHOW);
+ break;
+
+ case WM_COMMAND:
+ switch (LOWORD(wParam)) {
+ case IDC_STEP1:
+ // update current data
+ Utils_OpenUrl("https://miranda-ng.org/");
+ break;
+
+ case IDC_STEP2:
+ {
+ wchar_t szPath[1024];
+ GetModuleFileName(GetModuleHandle(nullptr), szPath, _countof(szPath));
+ wchar_t *chop = wcsrchr(szPath, '\\');
+ if (chop) {
+ *chop = '\0';
+ mir_wstrncat(szPath, L"\\Plugins\\weather\\", _countof(szPath) - mir_wstrlen(szPath));
+ if (_wmkdir(szPath) == 0)
+ ShellExecute((HWND)lParam, L"open", szPath, L"", L"", SW_SHOW);
+ }
+ break;
+ }
+
+ case IDC_STEP3:
+ if (LoadWIData(false))
+ MessageBox(nullptr,
+ TranslateT("All update data has been reloaded."),
+ TranslateT("Weather Protocol"), MB_OK | MB_ICONINFORMATION);
+ break;
+
+ case IDC_STEP4:
+ WeatherAdd(0, 0);
+ __fallthrough;
+
+ case IDCANCEL:
+ // close the info window
+ DestroyWindow(hwndDlg);
+ break;
+ }
+ break;
+
+ case WM_CLOSE:
+ DestroyWindow(hwndDlg);
+ break;
+
+ case WM_DESTROY:
+ Window_FreeIcon_IcoLib(hwndDlg);
+ break;
+ }
+ return FALSE;
+}
+
+// load the station data from a file
+// pszFile = the file name + path for the ini file to be loaded
+// pszShortFile = the file name of the ini file, but not including the path
+// Data = the struct to load the ini content to, and return to previous function
+static void LoadStationData(wchar_t *pszFile, wchar_t *pszShortFile, WIDATA *Data)
+{
+ WIDATAITEM DataItem;
+ char *Group, *Temp;
+ char *ValName, *Value;
+
+ static const char *statusStr[10] =
+ {
+ "LIGHTNING",
+ "FOG",
+ "SNOW SHOWER",
+ "SNOW",
+ "RAIN SHOWER",
+ "RAIN",
+ "PARTLY CLOUDY",
+ "CLOUDY",
+ "SUNNY",
+ "N/A"
+ };
+
+ // clean up old stuff
+ memset(Data, 0, sizeof(*Data));
+ Data->Enabled = FALSE;
+
+ // open the ini file
+ FILE *pfile = _wfsopen(pszFile, L"rt", _SH_DENYWR);
+ if (pfile != nullptr) {
+ char Line[4096];
+ fgets(Line, _countof(Line), pfile);
+ TrimString(Line);
+
+ // make sure it is a valid weather protocol ini file
+ if (!mir_strcmp(Line, "[Weather 0.3.x Update Data]"))
+ Data->InternalVer = 1;
+ else if (!mir_strcmp(Line, "[Weather 0.3.x Update Data 1.1]"))
+ Data->InternalVer = 2;
+ else if (!mir_strcmp(Line, "[Weather 0.3.x Update Data 1.1a]"))
+ Data->InternalVer = 3;
+ else if (!mir_strcmp(Line, "[Weather 0.3.x Update Data 1.2]"))
+ Data->InternalVer = 4;
+ else if (!mir_strcmp(Line, "[Weather 0.3.x Update Data 1.3]"))
+ Data->InternalVer = 5;
+ else if (!mir_strcmp(Line, "[Weather 0.3.x Update Data 1.4]"))
+ Data->InternalVer = 6;
+ else if (!mir_strcmp(Line, "[Weather 0.3.x Update Data 1.5]"))
+ Data->InternalVer = 7;
+ else {
+ wchar_t str[4096];
+ mir_snwprintf(str, TranslateT("Invalid ini format for: %s"), pszFile);
+ MessageBox(nullptr, str, TranslateT("Weather Protocol"), MB_OK | MB_ICONERROR);
+ fclose(pfile);
+ return;
+ }
+
+ // initialize all data fields
+ Group = "";
+
+ Data->DisplayName = L"";
+ Data->InternalName = L"";
+ Data->Description = L"";
+ Data->Author = L"";
+ Data->Version = L"";
+ Data->DefaultURL = "";
+ Data->DefaultMap = L"";
+ Data->UpdateURL = "";
+ Data->UpdateURL2 = "";
+ Data->UpdateURL3 = "";
+ Data->UpdateURL4 = "";
+ Data->Cookie = "";
+ Data->UserAgent = "";
+ Data->IDSearch.SearchURL = "";
+ Data->IDSearch.NotFoundStr = L"";
+ Data->NameSearch.SearchURL = "";
+ Data->NameSearch.NotFoundStr = L"";
+ Data->NameSearch.SingleStr = L"";
+ Data->NameSearch.Single.First = L"";
+ Data->NameSearch.Multiple.First = L"";
+ Data->IDSearch.Available = FALSE;
+ Data->NameSearch.Single.Available = FALSE;
+ Data->NameSearch.Multiple.Available = FALSE;
+ wSetData(&Data->FileName, pszFile);
+ wSetData(&Data->ShortFileName, pszShortFile);
+
+ ResetDataItem(&Data->IDSearch.Name, L"ID Search - Station Name");
+ ResetDataItem(&Data->NameSearch.Single.Name, L"Name Search Single Result - Station Name");
+ ResetDataItem(&Data->NameSearch.Single.ID, L"Name Search Single Result - Station ID");
+ ResetDataItem(&Data->NameSearch.Multiple.Name, L"Name Search Multiple Result - Station Name");
+ ResetDataItem(&Data->NameSearch.Multiple.ID, L"Name Search Multiple Result - Station ID");
+
+ DataItem.Name = L"";
+ DataItem.Start = L"";
+ DataItem.End = L"";
+ DataItem.Unit = L"";
+ DataItem.Url = "";
+ DataItem.Break = L"";
+ DataItem.Type = 0;
+
+ Temp = "";
+
+ // initialize the linked list for update items
+ Data->UpdateDataCount = 0;
+ Data->MemUsed = sizeof(WIDATA) + sizeof(WIDATALIST) + (mir_wstrlen(pszShortFile) + mir_wstrlen(pszFile) + 20)*sizeof(wchar_t);
+ Data->UpdateData = nullptr;
+ Data->UpdateDataTail = nullptr;
+
+ // initialize the icon assignment list
+ for (int i = 0; i < 10; i++)
+ WICondListInit(&Data->CondList[i]);
+
+ while (!feof(pfile)) {
+ // determine current tag
+
+ if (fgets(Line, _countof(Line), pfile) == nullptr)
+ break;
+ TrimString(Line);
+
+ // if the line is a group header/footer
+ if (Line[0] == '[') {
+ char *chop = strchr(Line + 1, ']');
+ if (chop == nullptr)
+ continue;
+
+ if (Line[1] != '/') { // if it is not a footer (for old ini)
+ // save the group name
+ Temp = (char *)mir_alloc(mir_strlen(Line) + 10);
+ strncpy(Temp, Line + 1, chop - Line - 1);
+ Temp[chop - Line - 1] = 0;
+ wfree(&Group);
+ wSetData(&Group, Temp);
+ // see if it is a update item, if it is, add a new item to the linked list
+ // if (_stricmp(Group, "HEADER") && _stricmp(Group, "DEFAULT") && _stricmp(Group, "ID SEARCH") &&
+ // strcmpi(Group, "NAME SEARCH"))
+ // wSetData(&DataItem.Name, Group);
+ if (_stricmp(Group, "HEADER") && _stricmp(Group, "DEFAULT") && _stricmp(Group, "ID SEARCH") &&
+ _stricmp(Group, "NAME SEARCH") && _stricmp(Group, "ICONS")) {
+ wSetData(&DataItem.Name, Temp);
+ DataItem.Type = WID_NORMAL;
+ WIItemListAdd(&DataItem, Data);
+ Data->UpdateDataCount++;
+ }
+ mir_free(Temp);
+ }
+ else {
+ wfree(&Group);
+ wSetData(&Group, "");
+ }
+ }
+ // ignore comments and all lines without an '='
+ Value = strstr(Line, "=");
+ if (Value == nullptr) continue;
+
+ // get the string before '=' (ValName) and after '=' (Value)
+ ValName = (char *)mir_alloc(mir_strlen(Line) + 1);
+ strncpy(ValName, Line, Value - Line);
+ ValName[Value - Line] = 0;
+ Value++;
+ ConvertBackslashes(Value);
+ // store the value for each string
+ if (!_stricmp(Group, "HEADER")) {
+ if (!_stricmp(ValName, "NAME")) wSetData(&Data->DisplayName, Value);
+ else if (!_stricmp(ValName, "INTERNAL NAME")) wSetData(&Data->InternalName, Value);
+ else if (!_stricmp(ValName, "DESCRIPTION")) wSetData(&Data->Description, Value);
+ else if (!_stricmp(ValName, "AUTHOR")) wSetData(&Data->Author, Value);
+ else if (!_stricmp(ValName, "VERSION")) wSetData(&Data->Version, Value);
+ }
+ else if (!_stricmp(Group, "DEFAULT")) {
+ if (!_stricmp(ValName, "DEFAULT URL")) wSetData(&Data->DefaultURL, Value);
+ else if (!_stricmp(ValName, "DEFAULT MAP")) wSetData(&Data->DefaultMap, Value);
+ else if (!_stricmp(ValName, "UPDATE URL")) wSetData(&Data->UpdateURL, Value);
+ else if (!_stricmp(ValName, "UPDATE URL2")) wSetData(&Data->UpdateURL2, Value);
+ else if (!_stricmp(ValName, "UPDATE URL3")) wSetData(&Data->UpdateURL3, Value);
+ else if (!_stricmp(ValName, "UPDATE URL4")) wSetData(&Data->UpdateURL4, Value);
+ else if (!_stricmp(ValName, "COOKIE")) wSetData(&Data->Cookie, Value);
+ else if (!_stricmp(ValName, "USERAGENT")) wSetData(&Data->UserAgent, Value);
+ }
+ else if (!_stricmp(Group, "ID SEARCH")) {
+ if (!_stricmp(ValName, "AVAILABLE")) {
+ if (!_stricmp(Value, "TRUE")) Data->IDSearch.Available = TRUE;
+ else Data->IDSearch.Available = FALSE;
+ }
+ else if (!_stricmp(ValName, "SEARCH URL")) wSetData(&Data->IDSearch.SearchURL, Value);
+ else if (!_stricmp(ValName, "NOT FOUND STR")) wSetData(&Data->IDSearch.NotFoundStr, Value);
+ else if (!_stricmp(ValName, "NAME START")) wSetData(&Data->IDSearch.Name.Start, Value);
+ else if (!_stricmp(ValName, "NAME END")) wSetData(&Data->IDSearch.Name.End, Value);
+ }
+ else if (!_stricmp(Group, "NAME SEARCH")) {
+ if (!_stricmp(ValName, "SINGLE RESULT")) {
+ if (!_stricmp(Value, "TRUE")) Data->NameSearch.Single.Available = TRUE;
+ else Data->NameSearch.Single.Available = FALSE;
+ }
+ else if (!_stricmp(ValName, "MULTIPLE RESULT")) {
+ if (!_stricmp(Value, "TRUE")) Data->NameSearch.Multiple.Available = TRUE;
+ else Data->NameSearch.Multiple.Available = FALSE;
+ }
+ else if (!_stricmp(ValName, "SEARCH URL")) wSetData(&Data->NameSearch.SearchURL, Value);
+ else if (!_stricmp(ValName, "NOT FOUND STR")) wSetData(&Data->NameSearch.NotFoundStr, Value);
+ else if (!_stricmp(ValName, "SINGLE RESULT STR")) wSetData(&Data->NameSearch.SingleStr, Value);
+ else if (!_stricmp(ValName, "SINGLE FIRST")) wSetData(&Data->NameSearch.Single.First, Value);
+ else if (!_stricmp(ValName, "SINGLE NAME START"))wSetData(&Data->NameSearch.Single.Name.Start, Value);
+ else if (!_stricmp(ValName, "SINGLE NAME END")) wSetData(&Data->NameSearch.Single.Name.End, Value);
+ else if (!_stricmp(ValName, "SINGLE ID START")) wSetData(&Data->NameSearch.Single.ID.Start, Value);
+ else if (!_stricmp(ValName, "SINGLE ID END")) wSetData(&Data->NameSearch.Single.ID.End, Value);
+ else if (!_stricmp(ValName, "MULT FIRST")) wSetData(&Data->NameSearch.Multiple.First, Value);
+ else if (!_stricmp(ValName, "MULT NAME START")) wSetData(&Data->NameSearch.Multiple.Name.Start, Value);
+ else if (!_stricmp(ValName, "MULT NAME END")) wSetData(&Data->NameSearch.Multiple.Name.End, Value);
+ else if (!_stricmp(ValName, "MULT ID START")) wSetData(&Data->NameSearch.Multiple.ID.Start, Value);
+ else if (!_stricmp(ValName, "MULT ID END")) wSetData(&Data->NameSearch.Multiple.ID.End, Value);
+ }
+ else if (!_stricmp(Group, "ICONS")) {
+ for (int i = 0; i < 10; i++) {
+ if (!_stricmp(ValName, statusStr[i])) {
+ WICondListAdd(Value, &Data->CondList[i]);
+ break;
+ }
+ }
+ }
+ else if (Data->UpdateDataCount != 0) {
+ if (!_stricmp(ValName, "START")) wSetData(&Data->UpdateDataTail->Item.Start, Value);
+ else if (!_stricmp(ValName, "SOURCE")) wSetData(&Data->UpdateDataTail->Item.Start, Value);
+ else if (!_stricmp(ValName, "END")) wSetData(&Data->UpdateDataTail->Item.End, Value);
+ else if (!_stricmp(ValName, "UNIT")) wSetData(&Data->UpdateDataTail->Item.Unit, Value);
+ else if (!_stricmp(ValName, "URL")) wSetData(&Data->UpdateDataTail->Item.Url, Value);
+ else if (!_stricmp(ValName, "HIDDEN")) {
+ if (!_stricmp(Value, "TRUE")) {
+ wchar_t *nm = Data->UpdateDataTail->Item.Name;
+ size_t len = mir_wstrlen(nm) + 1;
+
+ Data->UpdateDataTail->Item.Name = nm = (wchar_t*)mir_realloc(nm, sizeof(wchar_t)*(len + 3));
+ memmove(nm + 1, nm, len*sizeof(wchar_t));
+ *nm = '#';
+ }
+ }
+ else if (!_stricmp(ValName, "SET DATA")) {
+ Data->UpdateDataTail->Item.Type = WID_SET;
+ wSetData(&Data->UpdateDataTail->Item.End, Value);
+ }
+ else if (!_stricmp(ValName, "BREAK DATA")) {
+ Data->UpdateDataTail->Item.Type = WID_BREAK;
+ wSetData(&Data->UpdateDataTail->Item.Break, Value);
+ }
+ }
+ // recalculate memory used
+ Data->MemUsed += (mir_strlen(Value) + 10);
+ wfree(&ValName);
+ }
+ // calcualate memory used for the ini and close the file
+ Data->MemUsed += sizeof(WIDATAITEMLIST)*Data->UpdateDataCount;
+ Data->Enabled = TRUE; // enable the service
+ fclose(pfile);
+ wfree(&Group);
+ }
+}
+
+//============ LOADING INI FILES ============
+//
+// load the weather update data form INI files
+bool LoadWIData(bool dial)
+{
+ // make sure that the current service data list is empty
+ WITail = nullptr;
+ WIHead = WITail;
+
+ // find all *.ini file in the plugin\weather directory
+ wchar_t szSearchPath[MAX_PATH], FileName[MAX_PATH];
+ GetModuleFileName(GetModuleHandle(nullptr), szSearchPath, _countof(szSearchPath));
+ wchar_t *chop = wcsrchr(szSearchPath, '\\');
+ if (chop == nullptr)
+ return false;
+ *chop = '\0';
+ mir_wstrncat(szSearchPath, L"\\Plugins\\Weather\\*.ini", _countof(szSearchPath) - mir_wstrlen(szSearchPath));
+ wcsncpy(FileName, szSearchPath, MAX_PATH - 1);
+
+ WIN32_FIND_DATA fd;
+ HANDLE hFind = FindFirstFile(szSearchPath, &fd);
+
+
+ // load the content of the ini file into memory
+ if (hFind != INVALID_HANDLE_VALUE) {
+ do {
+ chop = wcsrchr(FileName, '\\');
+ chop[1] = '\0';
+ mir_wstrncat(FileName, fd.cFileName, _countof(FileName) - mir_wstrlen(FileName));
+ if (mir_wstrcmpi(fd.cFileName, L"SAMPLE_INI.INI")) {
+ WIDATA Data;
+ LoadStationData(FileName, fd.cFileName, &Data);
+ if (Data.Enabled)
+ WIListAdd(Data);
+ }
+ // look through the entire "plugins\weather" directory
+ } while (FindNextFile(hFind, &fd));
+ FindClose(hFind);
+ }
+
+ if (WIHead == nullptr) {
+ // no ini found, display an error message box.
+ if (dial)
+ hWndSetup = CreateDialog(g_plugin.getInst(), MAKEINTRESOURCE(IDD_SETUP), nullptr, DlgProcSetup);
+ else
+ MessageBox(nullptr,
+ TranslateT("No update data file is found. Please check your Plugins\\Weather directory."),
+ TranslateT("Weather Protocol"), MB_OK | MB_ICONERROR);
+ return false;
+ }
+ return true;
+}
+
+//============ FREE WIDATA ITEM FROM MEMORY ============
+//
+// free the WIDATA struct from memory
+// Data = the struct to be freed
+static void FreeWIData(WIDATA *Data)
+{
+ // free update items linked list first
+ WIDATAITEMLIST *WItem = Data->UpdateData;
+ while (WItem != nullptr) {
+ Data->UpdateData = WItem->Next;
+ FreeDataItem(&WItem->Item);
+ mir_free(WItem);
+ WItem = Data->UpdateData;
+ }
+
+ // free the strings in the rest of the struct
+ wfree(&Data->DisplayName);
+ wfree(&Data->InternalName);
+ wfree(&Data->Description);
+ wfree(&Data->Author);
+ wfree(&Data->Version);
+ wfree(&Data->DefaultURL);
+ wfree(&Data->DefaultMap);
+ wfree(&Data->UpdateURL);
+ wfree(&Data->UpdateURL2);
+ wfree(&Data->UpdateURL3);
+ wfree(&Data->UpdateURL4);
+ wfree(&Data->Cookie);
+ wfree(&Data->UserAgent);
+ wfree(&Data->IDSearch.SearchURL);
+ wfree(&Data->IDSearch.NotFoundStr);
+ FreeDataItem(&Data->IDSearch.Name);
+ wfree(&Data->NameSearch.SearchURL);
+ wfree(&Data->NameSearch.NotFoundStr);
+ wfree(&Data->NameSearch.SingleStr);
+ wfree(&Data->NameSearch.Single.First);
+ FreeDataItem(&Data->NameSearch.Single.Name);
+ FreeDataItem(&Data->NameSearch.Single.ID);
+ wfree(&Data->NameSearch.Multiple.First);
+ FreeDataItem(&Data->NameSearch.Multiple.Name);
+ FreeDataItem(&Data->NameSearch.Multiple.ID);
+ wfree(&Data->ShortFileName);
+ wfree(&Data->FileName);
+ for (int i = 0; i < 10; i++)
+ DestroyCondList(&Data->CondList[i]);
+}
+
+// remove all service data from memory
+void DestroyWIList(void)
+{
+ // free the list one by one
+ while (WIHead != nullptr) {
+ WIDATALIST *wi = WIHead;
+ WIHead = wi->next;
+ FreeWIData(&wi->Data); // free the data struct
+ mir_free(wi);
+ }
+
+ // make sure the entire list is clear
+ WITail = nullptr;
+}
diff --git a/protocols/Weather/src/weather_mwin.cpp b/protocols/Weather/src/weather_mwin.cpp
new file mode 100644
index 0000000000..a240b01421
--- /dev/null
+++ b/protocols/Weather/src/weather_mwin.cpp
@@ -0,0 +1,364 @@
+/*
+Weather Protocol plugin for Miranda IM
+Copyright (c) 2012 Miranda NG team
+Copyright (c) 2006-2009 Boris Krasnovskiy All Rights Reserved
+Copyright (c) 2002-2006 Calvin Che
+
+This program is free software; you can redistribute it and/or
+modify it under the terms of the GNU General Public License
+as published by the Free Software Foundation; version 2
+of the License.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "stdafx.h"
+
+#define MS_TOOLTIP_SHOWTIP "mToolTip/ShowTip"
+#define MS_TOOLTIP_HIDETIP "mToolTip/HideTip"
+
+static MWindowList hMwinWindowList;
+static HANDLE hFontHook;
+
+HGENMENU hMwinMenu;
+
+typedef struct
+{
+ MCONTACT hContact;
+ HWND hAvt;
+ BOOL haveAvatar;
+} MWinDataType;
+
+#define WM_REDRAWWIN (WM_USER + 17369)
+
+static LRESULT CALLBACK wndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
+{
+ MWinDataType *data = (MWinDataType*)GetWindowLongPtr(hwnd, GWLP_USERDATA);
+
+ switch (msg) {
+ case WM_CREATE:
+ data = (MWinDataType*)mir_calloc(sizeof(MWinDataType));
+ SetWindowLongPtr(hwnd, GWLP_USERDATA, (LONG_PTR)data);
+
+ data->hContact = (DWORD_PTR)((LPCREATESTRUCT)lParam)->lpCreateParams;
+ data->hAvt = CreateWindow(AVATAR_CONTROL_CLASS, TEXT(""), WS_CHILD,
+ 0, 0, opt.AvatarSize, opt.AvatarSize, hwnd, nullptr, g_plugin.getInst(), nullptr);
+ if (data->hAvt) SendMessage(data->hAvt, AVATAR_SETCONTACT, 0, (LPARAM)data->hContact);
+ break;
+
+ case WM_DESTROY:
+ mir_free(data);
+ break;
+
+ case WM_CONTEXTMENU:
+ {
+ POINT pt;
+ GetCursorPos(&pt);
+ HMENU hMenu = Menu_BuildContactMenu(data->hContact);
+ TrackPopupMenu(hMenu, TPM_LEFTALIGN, pt.x, pt.y, 0, hwnd, nullptr);
+ DestroyMenu(hMenu);
+ }
+ break;
+
+ case WM_MOUSEMOVE:
+ {
+ TRACKMOUSEEVENT tme = { 0 };
+ tme.cbSize = sizeof(TRACKMOUSEEVENT);
+ tme.hwndTrack = hwnd;
+ tme.dwFlags = TME_QUERY;
+ TrackMouseEvent(&tme);
+
+ if (tme.dwFlags == 0) {
+ tme.dwFlags = TME_HOVER | TME_LEAVE;
+ tme.hwndTrack = hwnd;
+ tme.dwHoverTime = CallService(MS_CLC_GETINFOTIPHOVERTIME, 0, 0);
+ TrackMouseEvent(&tme);
+ }
+ }
+ break;
+
+ case WM_MOUSEHOVER:
+ {
+ POINT pt;
+ CLCINFOTIP ti = { 0 };
+
+ GetCursorPos(&pt);
+ GetWindowRect(hwnd, &ti.rcItem);
+
+ ti.cbSize = sizeof(ti);
+ ti.hItem = (HANDLE)data->hContact;
+ ti.ptCursor = pt;
+ ti.isTreeFocused = 1;
+ CallService(MS_TOOLTIP_SHOWTIP, 0, (LPARAM)&ti);
+ }
+ break;
+
+ case WM_LBUTTONDBLCLK:
+ BriefInfo(data->hContact, 0);
+ break;
+
+ case WM_COMMAND: //Needed by the contact's context menu
+ if (Clist_MenuProcessCommand(LOWORD(wParam), MPCF_CONTACTMENU, data->hContact))
+ break;
+ return FALSE;
+
+ case WM_MEASUREITEM: //Needed by the contact's context menu
+ return Menu_MeasureItem(lParam);
+
+ case WM_DRAWITEM: //Needed by the contact's context menu
+ return Menu_DrawItem(lParam);
+
+ case WM_NOTIFY:
+ if (((LPNMHDR)lParam)->code == NM_AVATAR_CHANGED) {
+ BOOL newava = CallService(MS_AV_GETAVATARBITMAP, data->hContact, 0) != 0;
+ if (newava != data->haveAvatar) {
+ LONG_PTR style = GetWindowLongPtr(data->hAvt, GWL_STYLE);
+ data->haveAvatar = newava;
+ SetWindowLongPtr(data->hAvt, GWL_STYLE, newava ? (style | WS_VISIBLE) : (style & ~WS_VISIBLE));
+ RedrawWindow(hwnd, nullptr, nullptr, RDW_INVALIDATE);
+ }
+ }
+ break;
+
+ case WM_REDRAWWIN:
+ if (data->hAvt != nullptr) MoveWindow(data->hAvt, 0, 0, opt.AvatarSize, opt.AvatarSize, TRUE);
+ RedrawWindow(hwnd, nullptr, nullptr, RDW_INVALIDATE | RDW_UPDATENOW);
+ break;
+
+ case WM_PAINT:
+ {
+ RECT r, rc;
+
+ if (GetUpdateRect(hwnd, &r, FALSE)) {
+ int picSize = opt.AvatarSize;
+ HICON hIcon = nullptr;
+
+ if (!data->haveAvatar) {
+ int statusIcon = g_plugin.getWord(data->hContact, "Status");
+
+ picSize = GetSystemMetrics(SM_CXICON);
+ hIcon = Skin_LoadProtoIcon(MODULENAME, statusIcon, true);
+ if ((INT_PTR)hIcon == CALLSERVICE_NOTFOUND) {
+ picSize = GetSystemMetrics(SM_CXSMICON);
+ hIcon = Skin_LoadProtoIcon(MODULENAME, statusIcon);
+ }
+ }
+
+ LOGFONT lfnt, lfnt1;
+ COLORREF clr = g_plugin.getDword("ColorMwinFrame", GetSysColor(COLOR_3DFACE));
+ COLORREF fntc = Font_GetW(_A2W(MODULENAME), LPGENW("Frame Font"), &lfnt);
+ COLORREF fntc1 = Font_GetW(_A2W(MODULENAME), LPGENW("Frame Title Font"), &lfnt1);
+
+ ptrW tszInfo(db_get_wsa(data->hContact, WEATHERCONDITION, "WeatherInfo"));
+
+ GetClientRect(hwnd, &rc);
+
+ PAINTSTRUCT ps;
+ HDC hdc = BeginPaint(hwnd, &ps);
+
+ if (ServiceExists(MS_SKIN_DRAWGLYPH)) {
+ SKINDRAWREQUEST rq;
+ memset(&rq, 0, sizeof(rq));
+ rq.hDC = hdc;
+ rq.rcDestRect = rc;
+ rq.rcClipRect = rc;
+
+ mir_strcpy(rq.szObjectID, "Main,ID=WeatherFrame");
+ CallService(MS_SKIN_DRAWGLYPH, (WPARAM)&rq, 0);
+ }
+
+ if (clr != 0xFFFFFFFF) {
+ HBRUSH hBkgBrush = CreateSolidBrush(clr);
+ FillRect(hdc, &rc, hBkgBrush);
+ DeleteObject(hBkgBrush);
+ }
+
+ if (!data->haveAvatar)
+ DrawIconEx(hdc, 1, 1, hIcon, 0, 0, 0, nullptr, DI_NORMAL);
+
+ SetBkMode(hdc, TRANSPARENT);
+
+ HFONT hfnt = CreateFontIndirect(&lfnt1);
+ HFONT hfntold = (HFONT)SelectObject(hdc, hfnt);
+
+ wchar_t *nick = Clist_GetContactDisplayName(data->hContact);
+
+ SIZE fontSize;
+ GetTextExtentPoint32(hdc, L"|", 1, &fontSize);
+
+ rc.top += 1;
+ rc.left += picSize + fontSize.cx;
+
+ SetTextColor(hdc, fntc1);
+ DrawText(hdc, nick, -1, &rc, DT_LEFT | DT_EXPANDTABS);
+
+ rc.top += fontSize.cy;
+
+ SelectObject(hdc, hfntold);
+ DeleteObject(hfnt);
+
+ if (tszInfo) {
+ HFONT hFont = CreateFontIndirect(&lfnt);
+ HFONT hFontOld = (HFONT)SelectObject(hdc, hFont);
+
+ SetTextColor(hdc, fntc);
+ DrawText(hdc, tszInfo, -1, &rc, DT_LEFT | DT_EXPANDTABS);
+
+ SelectObject(hdc, hFontOld);
+ DeleteObject(hFont);
+ }
+ EndPaint(hwnd, &ps);
+ IcoLib_ReleaseIcon(hIcon);
+ }
+ break;
+ }
+
+ default:
+ return DefWindowProc(hwnd, msg, wParam, lParam);
+ }
+ return(TRUE);
+}
+
+static void addWindow(MCONTACT hContact)
+{
+ DBVARIANT dbv;
+ if (g_plugin.getWString(hContact, "Nick", &dbv))
+ return;
+
+ wchar_t winname[512];
+ mir_snwprintf(winname, L"Weather: %s", dbv.pwszVal);
+ db_free(&dbv);
+
+ HWND hWnd = CreateWindow(L"WeatherFrame", L"", WS_CHILD | WS_VISIBLE,
+ 0, 0, 10, 10, g_clistApi.hwndContactList, nullptr, g_plugin.getInst(), (void*)hContact);
+ WindowList_Add(hMwinWindowList, hWnd, hContact);
+
+ CLISTFrame Frame = { 0 };
+ Frame.szName.w = winname;
+ Frame.hIcon = LoadIconEx("main", FALSE);
+ Frame.cbSize = sizeof(Frame);
+ Frame.hWnd = hWnd;
+ Frame.align = alBottom;
+ Frame.Flags = F_VISIBLE | F_NOBORDER | F_UNICODE;
+ Frame.height = 32;
+ int frameID = g_plugin.addFrame(&Frame);
+
+ g_plugin.setDword(hContact, "mwin", frameID);
+ db_set_b(hContact, "CList", "Hidden", TRUE);
+}
+
+void removeWindow(MCONTACT hContact)
+{
+ DWORD frameId = g_plugin.getDword(hContact, "mwin");
+
+ WindowList_Remove(hMwinWindowList, WindowList_Find(hMwinWindowList, hContact));
+ CallService(MS_CLIST_FRAMES_REMOVEFRAME, frameId, 0);
+
+ g_plugin.setDword(hContact, "mwin", 0);
+ db_unset(hContact, "CList", "Hidden");
+}
+
+void UpdateMwinData(MCONTACT hContact)
+{
+ HWND hwnd = WindowList_Find(hMwinWindowList, hContact);
+ if (hwnd != nullptr)
+ RedrawWindow(hwnd, nullptr, nullptr, RDW_INVALIDATE | RDW_UPDATENOW);
+}
+
+INT_PTR Mwin_MenuClicked(WPARAM wParam, LPARAM)
+{
+ BOOL addwnd = WindowList_Find(hMwinWindowList, wParam) == nullptr;
+ if (addwnd)
+ addWindow(wParam);
+ else
+ removeWindow(wParam);
+ return 0;
+}
+
+int BuildContactMenu(WPARAM wparam, LPARAM)
+{
+ int flags = g_plugin.getDword(wparam, "mwin") ? CMIF_CHECKED : 0;
+ Menu_ModifyItem(hMwinMenu, nullptr, INVALID_HANDLE_VALUE, flags);
+ return 0;
+}
+
+int RedrawFrame(WPARAM, LPARAM)
+{
+ WindowList_Broadcast(hMwinWindowList, WM_REDRAWWIN, 0, 0);
+ return 0;
+}
+
+void InitMwin(void)
+{
+ if (!ServiceExists(MS_CLIST_FRAMES_ADDFRAME))
+ return;
+
+ hMwinWindowList = WindowList_Create();
+
+ WNDCLASS wndclass;
+ wndclass.style = CS_DBLCLKS | CS_HREDRAW | CS_VREDRAW;
+ wndclass.lpfnWndProc = wndProc;
+ wndclass.cbClsExtra = 0;
+ wndclass.cbWndExtra = 0;
+ wndclass.hInstance = g_plugin.getInst();
+ wndclass.hIcon = nullptr;
+ wndclass.hCursor = LoadCursor(nullptr, IDC_ARROW);
+ wndclass.hbrBackground = nullptr; //(HBRUSH)(COLOR_3DFACE+1);
+ wndclass.lpszMenuName = nullptr;
+ wndclass.lpszClassName = L"WeatherFrame";
+ RegisterClass(&wndclass);
+
+ ColourIDW colourid = {};
+ mir_strcpy(colourid.dbSettingsGroup, MODULENAME);
+ mir_strcpy(colourid.setting, "ColorMwinFrame");
+ mir_wstrcpy(colourid.name, LPGENW("Frame Background"));
+ mir_wstrcpy(colourid.group, _A2W(MODULENAME));
+ colourid.defcolour = GetSysColor(COLOR_3DFACE);
+ g_plugin.addColor(&colourid);
+
+ FontIDW fontid = {};
+ fontid.flags = FIDF_ALLOWREREGISTER | FIDF_DEFAULTVALID;
+ mir_strcpy(fontid.dbSettingsGroup, MODULENAME);
+ mir_wstrcpy(fontid.group, _A2W(MODULENAME));
+ mir_wstrcpy(fontid.name, LPGENW("Frame Font"));
+ mir_strcpy(fontid.setting, "fnt0");
+
+ HDC hdc = GetDC(nullptr);
+ fontid.deffontsettings.size = -13;
+ ReleaseDC(nullptr, hdc);
+
+ fontid.deffontsettings.charset = DEFAULT_CHARSET;
+ mir_wstrcpy(fontid.deffontsettings.szFace, L"Verdana");
+ mir_wstrcpy(fontid.backgroundGroup, _A2W(MODULENAME));
+ mir_wstrcpy(fontid.backgroundName, LPGENW("Frame Background"));
+ g_plugin.addFont(&fontid);
+
+ fontid.deffontsettings.style = DBFONTF_BOLD;
+ mir_wstrcpy(fontid.name, LPGENW("Frame Title Font"));
+ mir_strcpy(fontid.setting, "fnt1");
+ g_plugin.addFont(&fontid);
+
+ for (auto &hContact : Contacts(MODULENAME))
+ if (g_plugin.getDword(hContact, "mwin"))
+ addWindow(hContact);
+
+ hFontHook = HookEvent(ME_FONT_RELOAD, RedrawFrame);
+}
+
+void DestroyMwin(void)
+{
+ for (auto &hContact : Contacts(MODULENAME)) {
+ DWORD frameId = g_plugin.getDword(hContact, "mwin");
+ if (frameId)
+ CallService(MS_CLIST_FRAMES_REMOVEFRAME, frameId, 0);
+ }
+ UnregisterClass(L"WeatherFrame", g_plugin.getInst());
+ WindowList_Destroy(hMwinWindowList);
+ UnhookEvent(hFontHook);
+}
diff --git a/protocols/Weather/src/weather_opt.cpp b/protocols/Weather/src/weather_opt.cpp
new file mode 100644
index 0000000000..daf84d36c7
--- /dev/null
+++ b/protocols/Weather/src/weather_opt.cpp
@@ -0,0 +1,601 @@
+/*
+Weather Protocol plugin for Miranda IM
+Copyright (c) 2012 Miranda NG team
+Copyright (c) 2005-2011 Boris Krasnovskiy All Rights Reserved
+Copyright (c) 2002-2005 Calvin Che
+
+This program is free software; you can redistribute it and/or
+modify it under the terms of the GNU General Public License
+as published by the Free Software Foundation; version 2
+of the License.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+/* This file contain the source related to weather option pages. It also
+contain code for saving/loading options from the database.
+*/
+
+#include "stdafx.h"
+
+static BOOL opt_startup;
+int RedrawFrame(WPARAM wParam, LPARAM lParam);
+
+//============ LOADING AND SAVING OPTIONS ===========
+//
+// set a string to default
+// in = string to determine which field to set default "CBNEHXPp"
+void SetTextDefault(const char* in)
+{
+ wchar_t str[MAX_TEXT_SIZE];
+
+ if (strchr(in, 'C') != nullptr) {
+ wcsncpy(str, C_DEFAULT, MAX_TEXT_SIZE - 1);
+ wSetData(&opt.cText, str);
+ }
+ if (strchr(in, 'b') != nullptr) {
+ wcsncpy(str, b_DEFAULT, MAX_TEXT_SIZE - 1);
+ wSetData(&opt.bTitle, str);
+ }
+ if (strchr(in, 'B') != nullptr) {
+ wcsncpy(str, B_DEFAULT, MAX_TEXT_SIZE - 1);
+ wSetData(&opt.bText, str);
+ }
+ if (strchr(in, 'N') != nullptr) {
+ wcsncpy(str, N_DEFAULT, MAX_TEXT_SIZE - 1);
+ wSetData(&opt.nText, str);
+ }
+ if (strchr(in, 'E') != nullptr) {
+ wcsncpy(str, E_DEFAULT, MAX_TEXT_SIZE - 1);
+ wSetData(&opt.eText, str);
+ }
+ if (strchr(in, 'H') != nullptr) {
+ wcsncpy(str, H_DEFAULT, MAX_TEXT_SIZE - 1);
+ wSetData(&opt.hText, str);
+ }
+ if (strchr(in, 'X') != nullptr) {
+ wcsncpy(str, X_DEFAULT, MAX_TEXT_SIZE - 1);
+ wSetData(&opt.xText, str);
+ }
+ if (strchr(in, 'P') != nullptr) {
+ wcsncpy(str, P_DEFAULT, MAX_TEXT_SIZE - 1);
+ wSetData(&opt.pTitle, str);
+ }
+ if (strchr(in, 'p') != nullptr) {
+ wcsncpy(str, p_DEFAULT, MAX_TEXT_SIZE - 1);
+ wSetData(&opt.pText, str);
+ }
+ if (strchr(in, 'S') != nullptr) {
+ wcsncpy(str, s_DEFAULT, MAX_TEXT_SIZE - 1);
+ wSetData(&opt.sText, str);
+ }
+}
+
+void DestroyOptions(void)
+{
+ wfree(&opt.cText);
+ wfree(&opt.bTitle);
+ wfree(&opt.bText);
+ wfree(&opt.nText);
+ wfree(&opt.eText);
+ wfree(&opt.hText);
+ wfree(&opt.xText);
+ wfree(&opt.pTitle);
+ wfree(&opt.pText);
+ wfree(&opt.sText);
+}
+
+// load options from database + set default if the setting does not exist
+void LoadOptions(void)
+{
+ memset(&opt, 0, sizeof(opt));
+
+ // main options
+ opt.StartupUpdate = g_plugin.getByte("StartupUpdate", true);
+ opt.AutoUpdate = g_plugin.getByte("AutoUpdate", true);
+ opt.UpdateTime = g_plugin.getWord("UpdateTime", 30);
+ opt.NoProtoCondition = g_plugin.getByte("NoStatus", true);
+ opt.UpdateOnlyConditionChanged = g_plugin.getByte("CondChangeAsUpdate", true);
+ opt.RemoveOldData = g_plugin.getByte("RemoveOld", false);
+ opt.MakeItalic = g_plugin.getByte("MakeItalic", true);
+ opt.AvatarSize = g_plugin.getByte("AvatarSize", 128);
+
+ // units
+ opt.tUnit = g_plugin.getWord("tUnit", 1);
+ opt.wUnit = g_plugin.getWord("wUnit", 2);
+ opt.vUnit = g_plugin.getWord("vUnit", 1);
+ opt.pUnit = g_plugin.getWord("pUnit", 4);
+ opt.dUnit = g_plugin.getWord("dUnit", 1);
+ opt.eUnit = g_plugin.getWord("eUnit", 2);
+
+ ptrW szValue(g_plugin.getWStringA("DegreeSign"));
+ wcsncpy_s(opt.DegreeSign, (szValue == NULL) ? L"" : szValue, _TRUNCATE);
+
+ opt.DoNotAppendUnit = g_plugin.getByte("DoNotAppendUnit", 0);
+ opt.NoFrac = g_plugin.getByte("NoFractions", 0);
+
+ // texts
+ if (szValue = g_plugin.getWStringA("DisplayText"))
+ wSetData(&opt.cText, TranslateW(szValue));
+ else
+ SetTextDefault("C");
+
+ if (szValue = g_plugin.getWStringA("BriefTextTitle"))
+ wSetData(&opt.bTitle, TranslateW(szValue));
+ else
+ SetTextDefault("b");
+
+ if (szValue = g_plugin.getWStringA("BriefText"))
+ wSetData(&opt.bText, TranslateW(szValue));
+ else
+ SetTextDefault("B");
+
+ if (szValue = g_plugin.getWStringA("NoteText"))
+ wSetData(&opt.nText, TranslateW(szValue));
+ else
+ SetTextDefault("N");
+
+ if (szValue = g_plugin.getWStringA("ExtText"))
+ wSetData(&opt.eText, TranslateW(szValue));
+ else
+ SetTextDefault("E");
+
+ if (szValue = g_plugin.getWStringA("HistoryText"))
+ wSetData(&opt.hText, TranslateW(szValue));
+ else
+ SetTextDefault("H");
+
+ if (szValue = g_plugin.getWStringA("ExtraText"))
+ wSetData(&opt.xText, TranslateW(szValue));
+ else
+ SetTextDefault("X");
+
+ if (szValue = g_plugin.getWStringA("StatusText"))
+ wSetData(&opt.sText, TranslateW(szValue));
+ else
+ SetTextDefault("S");
+
+ // advanced
+ opt.DisCondIcon = g_plugin.getByte("DisableConditionIcon", false);
+ // popup options
+ opt.UsePopup = g_plugin.getByte("UsePopUp", true);
+ opt.UpdatePopup = g_plugin.getByte("UpdatePopup", true);
+ opt.AlertPopup = g_plugin.getByte("AlertPopup", true);
+ opt.PopupOnChange = g_plugin.getByte("PopUpOnChange", true);
+ opt.ShowWarnings = g_plugin.getByte("ShowWarnings", true);
+ // popup colors
+ opt.BGColour = g_plugin.getDword("BackgroundColour", GetSysColor(COLOR_BTNFACE));
+ opt.TextColour = g_plugin.getDword("TextColour", GetSysColor(COLOR_WINDOWTEXT));
+ opt.UseWinColors = g_plugin.getByte("UseWinColors", false);
+ // popup actions
+ opt.LeftClickAction = g_plugin.getDword("LeftClickAction", IDM_M2);
+ opt.RightClickAction = g_plugin.getDword("RightClickAction", IDM_M1);
+ // popup delay
+ opt.pDelay = g_plugin.getDword("PopupDelay", 0);
+ // popup texts
+ if (szValue = g_plugin.getWStringA("PopupTitle"))
+ wSetData(&opt.pTitle, szValue);
+ else
+ SetTextDefault("P");
+
+ if (szValue = g_plugin.getWStringA("PopupText"))
+ wSetData(&opt.pText, szValue);
+ else
+ SetTextDefault("p");
+
+ // misc
+ if (szValue = g_plugin.getWStringA("Default"))
+ wcsncpy_s(opt.Default, szValue, _TRUNCATE);
+ else
+ opt.Default[0] = 0;
+}
+
+// save the options to database
+void SaveOptions(void)
+{
+ // main options
+ g_plugin.setByte("StartupUpdate", (BYTE)opt.StartupUpdate);
+ g_plugin.setByte("AutoUpdate", (BYTE)opt.AutoUpdate);
+ g_plugin.setWord("UpdateTime", opt.UpdateTime);
+ g_plugin.setByte("NoStatus", (BYTE)opt.NoProtoCondition);
+ g_plugin.setByte("CondChangeAsUpdate", (BYTE)opt.UpdateOnlyConditionChanged);
+ g_plugin.setByte("RemoveOld", (BYTE)opt.RemoveOldData);
+ g_plugin.setByte("MakeItalic", (BYTE)opt.MakeItalic);
+ g_plugin.setByte("AvatarSize", (BYTE)opt.AvatarSize);
+ // units
+ g_plugin.setWord("tUnit", opt.tUnit);
+ g_plugin.setWord("wUnit", opt.wUnit);
+ g_plugin.setWord("vUnit", opt.vUnit);
+ g_plugin.setWord("pUnit", opt.pUnit);
+ g_plugin.setWord("dUnit", opt.dUnit);
+ g_plugin.setWord("eUnit", opt.eUnit);
+ g_plugin.setWString("DegreeSign", opt.DegreeSign);
+ g_plugin.setByte("DoNotAppendUnit", (BYTE)opt.DoNotAppendUnit);
+ g_plugin.setByte("NoFractions", (BYTE)opt.NoFrac);
+ // texts
+ g_plugin.setWString("DisplayText", opt.cText);
+ g_plugin.setWString("BriefTextTitle", opt.bTitle);
+ g_plugin.setWString("BriefText", opt.bText);
+ g_plugin.setWString("NoteText", opt.nText);
+ g_plugin.setWString("ExtText", opt.eText);
+ g_plugin.setWString("HistoryText", opt.hText);
+ g_plugin.setWString("ExtraText", opt.xText);
+ g_plugin.setWString("StatusText", opt.sText);
+ // advanced
+ g_plugin.setByte("DisableConditionIcon", (BYTE)opt.DisCondIcon);
+ // popup options
+ g_plugin.setByte("UsePopUp", (BYTE)opt.UsePopup);
+ g_plugin.setByte("UpdatePopup", (BYTE)opt.UpdatePopup);
+ g_plugin.setByte("AlertPopup", (BYTE)opt.AlertPopup);
+ g_plugin.setByte("PopUpOnChange", (BYTE)opt.PopupOnChange);
+ g_plugin.setByte("ShowWarnings", (BYTE)opt.ShowWarnings);
+ // popup colors
+ g_plugin.setDword("BackgroundColour", opt.BGColour);
+ g_plugin.setDword("TextColour", opt.TextColour);
+ g_plugin.setByte("UseWinColors", (BYTE)opt.UseWinColors);
+ // popup actions
+ g_plugin.setDword("LeftClickAction", opt.LeftClickAction);
+ g_plugin.setDword("RightClickAction", opt.RightClickAction);
+ // popup delay
+ g_plugin.setDword("PopupDelay", opt.pDelay);
+ // popup texts
+ g_plugin.setWString("PopupTitle", opt.pTitle);
+ g_plugin.setWString("PopupText", opt.pText);
+ // misc stuff
+ g_plugin.setWString("Default", opt.Default);
+}
+//============ MAIN OPTIONS ============
+
+// weather options
+static INT_PTR CALLBACK OptionsProc(HWND hdlg, UINT msg, WPARAM wparam, LPARAM lparam)
+{
+ wchar_t str[512];
+
+ switch (msg) {
+ case WM_INITDIALOG:
+ opt_startup = TRUE;
+ TranslateDialogDefault(hdlg);
+ // load settings
+ _ltow(opt.UpdateTime, str, 10);
+ SetDlgItemText(hdlg, IDC_UPDATETIME, str);
+ SetDlgItemText(hdlg, IDC_DEGREE, opt.DegreeSign);
+
+ SendDlgItemMessage(hdlg, IDC_AVATARSPIN, UDM_SETRANGE32, 0, 999);
+ SendDlgItemMessage(hdlg, IDC_AVATARSPIN, UDM_SETPOS, 0, opt.AvatarSize);
+ SendDlgItemMessage(hdlg, IDC_AVATARSIZE, EM_LIMITTEXT, 3, 0);
+
+ CheckDlgButton(hdlg, IDC_STARTUPUPD, opt.StartupUpdate ? BST_CHECKED : BST_UNCHECKED);
+ CheckDlgButton(hdlg, IDC_UPDATE, opt.AutoUpdate ? BST_CHECKED : BST_UNCHECKED);
+ CheckDlgButton(hdlg, IDC_PROTOCOND, !opt.NoProtoCondition ? BST_CHECKED : BST_UNCHECKED);
+ CheckDlgButton(hdlg, IDC_UPDCONDCHG, opt.UpdateOnlyConditionChanged ? BST_CHECKED : BST_UNCHECKED);
+ CheckDlgButton(hdlg, IDC_REMOVEOLD, opt.RemoveOldData ? BST_CHECKED : BST_UNCHECKED);
+ CheckDlgButton(hdlg, IDC_MAKEI, opt.MakeItalic ? BST_CHECKED : BST_UNCHECKED);
+ CheckDlgButton(hdlg, IDC_DISCONDICON, opt.DisCondIcon ? BST_CHECKED : BST_UNCHECKED);
+ CheckDlgButton(hdlg, IDC_DONOTAPPUNITS, opt.DoNotAppendUnit ? BST_CHECKED : BST_UNCHECKED);
+ CheckDlgButton(hdlg, IDC_NOFRAC, opt.NoFrac ? BST_CHECKED : BST_UNCHECKED);
+
+ // load units
+ switch (opt.tUnit) { // temperature
+ case 1: CheckRadioButton(hdlg, IDC_T1, IDC_T2, IDC_T1); break;
+ case 2: CheckRadioButton(hdlg, IDC_T1, IDC_T2, IDC_T2); break;
+ }
+ switch (opt.wUnit) { // wind
+ case 1: CheckRadioButton(hdlg, IDC_W1, IDC_W4, IDC_W1); break;
+ case 2: CheckRadioButton(hdlg, IDC_W1, IDC_W4, IDC_W2); break;
+ case 3: CheckRadioButton(hdlg, IDC_W1, IDC_W4, IDC_W3); break;
+ case 4: CheckRadioButton(hdlg, IDC_W1, IDC_W4, IDC_W4); break;
+ }
+ switch (opt.vUnit) { // visibility
+ case 1: CheckRadioButton(hdlg, IDC_V1, IDC_V2, IDC_V1); break;
+ case 2: CheckRadioButton(hdlg, IDC_V1, IDC_V2, IDC_V2); break;
+ }
+ switch (opt.pUnit) { // pressure
+ case 1: CheckRadioButton(hdlg, IDC_P1, IDC_P4, IDC_P1); break;
+ case 2: CheckRadioButton(hdlg, IDC_P1, IDC_P4, IDC_P2); break;
+ case 3: CheckRadioButton(hdlg, IDC_P1, IDC_P4, IDC_P3); break;
+ case 4: CheckRadioButton(hdlg, IDC_P1, IDC_P4, IDC_P4); break;
+ }
+ switch (opt.dUnit) { // pressure
+ case 1: CheckRadioButton(hdlg, IDC_D1, IDC_D3, IDC_D1); break;
+ case 2: CheckRadioButton(hdlg, IDC_D1, IDC_D3, IDC_D2); break;
+ case 3: CheckRadioButton(hdlg, IDC_D1, IDC_D3, IDC_D3); break;
+ }
+
+ switch (opt.eUnit) { // elev
+ case 1: CheckRadioButton(hdlg, IDC_E1, IDC_E2, IDC_E1); break;
+ case 2: CheckRadioButton(hdlg, IDC_E1, IDC_E2, IDC_E2); break;
+ }
+
+ opt_startup = FALSE;
+ return 0;
+
+ case WM_COMMAND:
+ if (HIWORD(wparam) == BN_CLICKED && GetFocus() == (HWND)lparam)
+ if (!opt_startup) SendMessage(GetParent(hdlg), PSM_CHANGED, 0, 0);
+ if (!((LOWORD(wparam) == IDC_UPDATE || LOWORD(wparam) == IDC_DEGREE) &&
+ (HIWORD(wparam) != EN_CHANGE || (HWND)lparam != GetFocus())))
+ if (!opt_startup) SendMessage(GetParent(hdlg), PSM_CHANGED, 0, 0);
+ return 0;
+
+ case WM_NOTIFY:
+ switch (((LPNMHDR)lparam)->code) {
+ case PSN_APPLY:
+ // change the status for weather protocol
+ if (IsDlgButtonChecked(hdlg, IDC_PROTOCOND) && opt.DefStn != NULL) {
+ old_status = status;
+ status = g_plugin.getWord(opt.DefStn, "StatusIcon", NOSTATUSDATA);
+ ProtoBroadcastAck(MODULENAME, NULL, ACKTYPE_STATUS, ACKRESULT_SUCCESS, (HANDLE)old_status, status);
+ }
+
+ // get update time and remove the old timer
+ GetDlgItemText(hdlg, IDC_UPDATETIME, str, _countof(str));
+ opt.UpdateTime = (WORD)_wtoi(str);
+ if (opt.UpdateTime < 1) opt.UpdateTime = 1;
+ KillTimer(nullptr, timerId);
+ timerId = SetTimer(nullptr, 0, opt.UpdateTime * 60000, timerProc);
+
+ // other general options
+ GetDlgItemText(hdlg, IDC_DEGREE, opt.DegreeSign, _countof(opt.DegreeSign));
+ opt.StartupUpdate = IsDlgButtonChecked(hdlg, IDC_STARTUPUPD);
+ opt.AutoUpdate = IsDlgButtonChecked(hdlg, IDC_UPDATE);
+ opt.NoProtoCondition = BST_UNCHECKED == IsDlgButtonChecked(hdlg, IDC_PROTOCOND);
+ opt.DisCondIcon = IsDlgButtonChecked(hdlg, IDC_DISCONDICON);
+ opt.UpdateOnlyConditionChanged = (BYTE)IsDlgButtonChecked(hdlg, IDC_UPDCONDCHG);
+ opt.RemoveOldData = IsDlgButtonChecked(hdlg, IDC_REMOVEOLD);
+ opt.MakeItalic = IsDlgButtonChecked(hdlg, IDC_MAKEI);
+ opt.AvatarSize = GetDlgItemInt(hdlg, IDC_AVATARSIZE, nullptr, FALSE);
+ opt.DoNotAppendUnit = IsDlgButtonChecked(hdlg, IDC_DONOTAPPUNITS);
+ opt.NoFrac = IsDlgButtonChecked(hdlg, IDC_NOFRAC);
+ UpdateMenu(opt.AutoUpdate);
+
+ // save the units
+ if (IsDlgButtonChecked(hdlg, IDC_T1)) opt.tUnit = 1;
+ if (IsDlgButtonChecked(hdlg, IDC_T2)) opt.tUnit = 2;
+ if (IsDlgButtonChecked(hdlg, IDC_W1)) opt.wUnit = 1;
+ if (IsDlgButtonChecked(hdlg, IDC_W2)) opt.wUnit = 2;
+ if (IsDlgButtonChecked(hdlg, IDC_W3)) opt.wUnit = 3;
+ if (IsDlgButtonChecked(hdlg, IDC_W4)) opt.wUnit = 4;
+ if (IsDlgButtonChecked(hdlg, IDC_V1)) opt.vUnit = 1;
+ if (IsDlgButtonChecked(hdlg, IDC_V2)) opt.vUnit = 2;
+ if (IsDlgButtonChecked(hdlg, IDC_P1)) opt.pUnit = 1;
+ if (IsDlgButtonChecked(hdlg, IDC_P2)) opt.pUnit = 2;
+ if (IsDlgButtonChecked(hdlg, IDC_P3)) opt.pUnit = 3;
+ if (IsDlgButtonChecked(hdlg, IDC_P4)) opt.pUnit = 4;
+ if (IsDlgButtonChecked(hdlg, IDC_D1)) opt.dUnit = 1;
+ if (IsDlgButtonChecked(hdlg, IDC_D2)) opt.dUnit = 2;
+ if (IsDlgButtonChecked(hdlg, IDC_D3)) opt.dUnit = 3;
+ if (IsDlgButtonChecked(hdlg, IDC_E1)) opt.eUnit = 1;
+ if (IsDlgButtonChecked(hdlg, IDC_E2)) opt.eUnit = 2;
+
+ // save the new weather options
+ SaveOptions();
+
+ RedrawFrame(0, 0);
+
+ return 1;
+ }
+ break;
+ }
+ return 0;
+}
+
+//============ TEXT OPTION DIALOG ============
+
+static void LoadTextSettings(HWND hdlg)
+{
+ // load text option settings from memory
+ SetDlgItemText(hdlg, IDC_CTEXT, opt.cText);
+ SetDlgItemText(hdlg, IDC_BTITLE, opt.bTitle);
+ SetDlgItemText(hdlg, IDC_BTEXT, opt.bText);
+ SetDlgItemText(hdlg, IDC_ETEXT, opt.eText);
+ SetDlgItemText(hdlg, IDC_NTEXT, opt.nText);
+ SetDlgItemText(hdlg, IDC_HTEXT, opt.hText);
+ SetDlgItemText(hdlg, IDC_XTEXT, opt.xText);
+ SetDlgItemText(hdlg, IDC_BTITLE2, opt.sText);
+}
+
+// free the display text settings from memory
+static void FreeTextVar(void)
+{
+ wfree(&opt.cText);
+ wfree(&opt.bText);
+ wfree(&opt.bTitle);
+ wfree(&opt.eText);
+ wfree(&opt.nText);
+ wfree(&opt.hText);
+ wfree(&opt.xText);
+ wfree(&opt.sText);
+}
+
+// text option dialog
+
+static const char *varname[8] = { "C", "b", "B", "N", "X", "E", "H", "S" };
+static const int cname[8] = { IDC_CTEXT, IDC_BTITLE, IDC_BTEXT, IDC_NTEXT, IDC_XTEXT, IDC_ETEXT, IDC_HTEXT, IDC_BTITLE2 };
+static wchar_t* const *var[8] = { &opt.cText, &opt.bTitle, &opt.bText, &opt.nText, &opt.xText, &opt.eText, &opt.hText, &opt.sText };
+
+static INT_PTR CALLBACK DlgProcText(HWND hdlg, UINT msg, WPARAM wParam, LPARAM lParam)
+{
+ RECT rc, pos;
+ HWND button;
+ HMENU hMenu, hMenu1;
+ wchar_t str[4096];
+ switch (msg) {
+ case WM_INITDIALOG:
+ opt_startup = TRUE;
+ // set windows position, make it top-most
+ GetWindowRect(hdlg, &rc);
+ SetWindowPos(hdlg, HWND_TOPMOST, rc.left, rc.top, 0, 0, SWP_NOSIZE);
+ TranslateDialogDefault(hdlg);
+ // generate the display text for variable list
+ wcsncpy(str, VAR_LIST_OPT, _countof(str) - 1);
+ SetDlgItemText(hdlg, IDC_VARLIST, str);
+
+ // make the more variable and other buttons flat
+ SendDlgItemMessage(hdlg, IDC_MORE, BUTTONSETASFLATBTN, TRUE, 0);
+ SendDlgItemMessage(hdlg, IDC_TM1, BUTTONSETASFLATBTN, TRUE, 0);
+ SendDlgItemMessage(hdlg, IDC_TM2, BUTTONSETASFLATBTN, TRUE, 0);
+ SendDlgItemMessage(hdlg, IDC_TM3, BUTTONSETASFLATBTN, TRUE, 0);
+ SendDlgItemMessage(hdlg, IDC_TM4, BUTTONSETASFLATBTN, TRUE, 0);
+ SendDlgItemMessage(hdlg, IDC_TM5, BUTTONSETASFLATBTN, TRUE, 0);
+ SendDlgItemMessage(hdlg, IDC_TM6, BUTTONSETASFLATBTN, TRUE, 0);
+ SendDlgItemMessage(hdlg, IDC_TM7, BUTTONSETASFLATBTN, TRUE, 0);
+ SendDlgItemMessage(hdlg, IDC_TM8, BUTTONSETASFLATBTN, TRUE, 0);
+ SendDlgItemMessage(hdlg, IDC_RESET, BUTTONSETASFLATBTN, TRUE, 0);
+ // load the settings
+ LoadTextSettings(hdlg);
+ opt_startup = FALSE;
+ return TRUE;
+
+ case WM_COMMAND:
+ if (opt_startup) return TRUE;
+ switch (LOWORD(wParam)) {
+ case IDC_CTEXT:
+ case IDC_BTITLE:
+ case IDC_BTEXT:
+ case IDC_NTEXT:
+ case IDC_XTEXT:
+ case IDC_ETEXT:
+ case IDC_HTEXT:
+ case IDC_BTITLE2:
+ if (HIWORD(wParam) == EN_CHANGE)
+ SendMessage(GetParent(hdlg), PSM_CHANGED, 0, 0);
+ break;
+
+ case IDC_MORE:
+ // display custom variables list
+ MoreVarList();
+ break;
+
+ case IDC_TM1:
+ case IDC_TM2:
+ case IDC_TM3:
+ case IDC_TM4:
+ case IDC_TM5:
+ case IDC_TM6:
+ case IDC_TM7:
+ case IDC_TM8:
+ // display the menu
+ button = GetDlgItem(hdlg, LOWORD(wParam));
+ GetWindowRect(button, &pos);
+ hMenu = LoadMenu(g_plugin.getInst(), MAKEINTRESOURCE(IDR_TMMENU));
+ hMenu1 = GetSubMenu(hMenu, 0);
+ TranslateMenu(hMenu1);
+ switch (TrackPopupMenu(hMenu1, TPM_LEFTBUTTON | TPM_RETURNCMD, pos.left, pos.bottom, 0, hdlg, nullptr)) {
+ case ID_MPREVIEW:
+ {
+ // show the preview in a message box, using the weather data from the default station
+ WEATHERINFO winfo = LoadWeatherInfo(opt.DefStn);
+ GetDisplay(&winfo, *var[LOWORD(wParam) - IDC_TM1], str);
+ MessageBox(nullptr, str, TranslateT("Weather Protocol Text Preview"), MB_OK | MB_TOPMOST);
+ break;
+ }
+ case ID_MRESET:
+ unsigned varo = LOWORD(wParam) - IDC_TM1;
+ // remove the old setting from db and free memory
+ wchar_t* vartmp = *var[varo];
+ wfree(&vartmp);
+ SetTextDefault(varname[varo]);
+ SetDlgItemText(hdlg, cname[varo], *var[varo]);
+ break;
+ }
+ DestroyMenu(hMenu);
+ break;
+
+ case IDC_RESET:
+ // left click action selection menu
+ button = GetDlgItem(hdlg, IDC_RESET);
+ GetWindowRect(button, &pos);
+ hMenu = LoadMenu(g_plugin.getInst(), MAKEINTRESOURCE(IDR_TMENU));
+ hMenu1 = GetSubMenu(hMenu, 0);
+ TranslateMenu(hMenu1);
+ switch (TrackPopupMenu(hMenu1, TPM_LEFTBUTTON | TPM_RETURNCMD, pos.left, pos.bottom, 0, hdlg, nullptr)) {
+ case ID_T1:
+ // reset to the strings in memory, discard all changes
+ LoadTextSettings(hdlg);
+ break;
+
+ case ID_T2:
+ // reset to the default setting
+ FreeTextVar();
+ SetTextDefault("CbBENHX");
+ LoadTextSettings(hdlg);
+ break;
+ }
+ DestroyMenu(hMenu);
+ break;
+ }
+ return TRUE;
+ case WM_NOTIFY:
+ switch (((LPNMHDR)lParam)->code) {
+ case PSN_APPLY:
+ // save the option
+ wchar_t textstr[MAX_TEXT_SIZE];
+ // free memory for old settings
+ FreeTextVar();
+ // save new settings to memory
+ GetDlgItemText(hdlg, IDC_CTEXT, textstr, _countof(textstr));
+ wSetData(&opt.cText, textstr);
+ GetDlgItemText(hdlg, IDC_BTEXT, textstr, _countof(textstr));
+ wSetData(&opt.bText, textstr);
+ GetDlgItemText(hdlg, IDC_BTITLE, textstr, _countof(textstr));
+ wSetData(&opt.bTitle, textstr);
+ GetDlgItemText(hdlg, IDC_ETEXT, textstr, _countof(textstr));
+ wSetData(&opt.eText, textstr);
+ GetDlgItemText(hdlg, IDC_NTEXT, textstr, _countof(textstr));
+ wSetData(&opt.nText, textstr);
+ GetDlgItemText(hdlg, IDC_HTEXT, textstr, _countof(textstr));
+ wSetData(&opt.hText, textstr);
+ GetDlgItemText(hdlg, IDC_XTEXT, textstr, _countof(textstr));
+ wSetData(&opt.xText, textstr);
+ GetDlgItemText(hdlg, IDC_BTITLE2, textstr, _countof(textstr));
+ wSetData(&opt.sText, textstr);
+ SaveOptions();
+ UpdateAllInfo(0, 0);
+ break;
+ }
+ break;
+ }
+ return FALSE;
+}
+
+
+//============ OPTION INITIALIZATION ============
+
+// register the weather option pages
+int OptInit(WPARAM wParam, LPARAM)
+{
+ // plugin options
+ OPTIONSDIALOGPAGE odp = {};
+ odp.position = 95600;
+ odp.pszTemplate = MAKEINTRESOURCEA(IDD_OPTIONS);
+ odp.pfnDlgProc = OptionsProc;
+ odp.szGroup.a = LPGEN("Network");
+ odp.szTitle.a = WEATHERPROTOTEXT;
+ odp.szTab.a = LPGEN("General");
+ odp.flags = ODPF_BOLDGROUPS;
+ g_plugin.addOptions(wParam, &odp);
+
+ // text options
+ odp.pszTemplate = MAKEINTRESOURCEA(IDD_TEXTOPT);
+ odp.pfnDlgProc = DlgProcText;
+ odp.szTab.a = LPGEN("Display");
+ g_plugin.addOptions(wParam, &odp);
+
+ // if popup service exists, load the weather popup options
+ if ((ServiceExists(MS_POPUP_ADDPOPUPW))) {
+ odp.position = 100000000;
+ odp.pszTemplate = MAKEINTRESOURCEA(IDD_POPUP);
+ odp.szGroup.a = LPGEN("Popups");
+ odp.szTab.a = nullptr;
+ odp.pfnDlgProc = DlgPopupOpts;
+ g_plugin.addOptions(wParam, &odp);
+ }
+
+ return 0;
+}
diff --git a/protocols/Weather/src/weather_popup.cpp b/protocols/Weather/src/weather_popup.cpp
new file mode 100644
index 0000000000..6e72d5595e
--- /dev/null
+++ b/protocols/Weather/src/weather_popup.cpp
@@ -0,0 +1,428 @@
+/*
+Weather Protocol plugin for Miranda IM
+Copyright (c) 2012 Miranda NG team
+Copyright (c) 2005-2009 Boris Krasnovskiy All Rights Reserved
+Copyright (c) 2002-2005 Calvin Che
+
+This program is free software; you can redistribute it and/or
+modify it under the terms of the GNU General Public License
+as published by the Free Software Foundation; version 2
+of the License.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+/* This file contain the source related to weather popups, including popup
+ options, popup display, and the code for popup process.
+*/
+
+#include "stdafx.h"
+
+// variables for weather_popup.c
+static MCONTACT hPopupContact;
+
+//============ SHOW WEATHER POPUPS ============
+
+//============ WEATHER ERROR POPUPS ============
+
+// display weather error or notices (not threaded)
+// wParam = error text
+// lParam = display type
+// Type can either be SM_WARNING, SM_NOTIFY, or SM_WEATHERALERT
+int WeatherError(WPARAM wParam, LPARAM lParam)
+{
+ if (!opt.UsePopup)
+ return 0;
+
+ wchar_t* tszMsg = (wchar_t*)wParam;
+
+ if ((DWORD)lParam == SM_WARNING)
+ PUShowMessageW(tszMsg, SM_WARNING);
+ else if ((DWORD)lParam == SM_NOTIFY)
+ PUShowMessageW(tszMsg, SM_NOTIFY);
+ else if ((DWORD)lParam == SM_WEATHERALERT) {
+ POPUPDATAW ppd = { 0 };
+ wchar_t str1[512], str2[512];
+
+ // get the 2 strings
+ wcsncpy(str1, tszMsg, _countof(str1) - 1);
+ wcsncpy(str2, tszMsg, _countof(str2) - 1);
+ wchar_t *chop = wcschr(str1, 255);
+ if (chop != nullptr)
+ *chop = '\0';
+ else
+ str1[0] = 0;
+ chop = wcschr(str2, 255);
+ if (chop != nullptr)
+ wcsncpy(str2, chop + 1, _countof(str2) - 1);
+ else
+ str2[0] = 0;
+
+ // setup the popup
+ ppd.lchIcon = (HICON)LoadImage(nullptr, MAKEINTRESOURCE(OIC_BANG), IMAGE_ICON,
+ GetSystemMetrics(SM_CXSMICON), GetSystemMetrics(SM_CYSMICON), LR_SHARED);
+ mir_wstrcpy(ppd.lpwzContactName, str1);
+ mir_wstrcpy(ppd.lpwzText, str2);
+ ppd.colorBack = (opt.UseWinColors) ? GetSysColor(COLOR_BTNFACE) : opt.BGColour;
+ ppd.colorText = (opt.UseWinColors) ? GetSysColor(COLOR_WINDOWTEXT) : opt.TextColour;
+ ppd.iSeconds = opt.pDelay;
+ PUAddPopupW(&ppd);
+ }
+ return 0;
+}
+
+// wrapper function for displaying weather warning popup by triggering an event
+// (threaded)
+// lpzText = error text
+// kind = display type (see m_popup.h)
+int WPShowMessage(wchar_t* lpzText, WORD kind)
+{
+ NotifyEventHooks(hHookWeatherError, (WPARAM)lpzText, (LPARAM)kind);
+ return 0;
+}
+
+//============ WEATHER POPUP PROCESSES ============
+
+// popup dialog pocess
+// for selecting actions when click on the popup window
+// use for displaying contact menu
+static LRESULT CALLBACK PopupDlgProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
+{
+ DWORD ID = 0;
+ MCONTACT hContact;
+ hContact = PUGetContact(hWnd);
+
+ switch (message) {
+ case WM_COMMAND:
+ ID = opt.LeftClickAction;
+ if (ID != IDM_M7) PUDeletePopup(hWnd);
+ SendMessage(hPopupWindow, ID, hContact, 0);
+ return TRUE;
+
+ case WM_CONTEXTMENU:
+ ID = opt.RightClickAction;
+ if (ID != IDM_M7) PUDeletePopup(hWnd);
+ SendMessage(hPopupWindow, ID, hContact, 0);
+ return TRUE;
+
+ case UM_FREEPLUGINDATA:
+ IcoLib_ReleaseIcon((HICON)PUGetPluginData(hWnd));
+ return FALSE;
+ }
+
+ return DefWindowProc(hWnd, message, wParam, lParam);
+}
+
+// display weather popups
+// wParam = the contact to display popup
+// lParam = whether the weather data is changed or not
+int WeatherPopup(WPARAM hContact, LPARAM lParam)
+{
+ // determine if the popup should display or not
+ if (opt.UsePopup && opt.UpdatePopup && (!opt.PopupOnChange || (BOOL)lParam) && !g_plugin.getByte(hContact, "DPopUp")) {
+ WEATHERINFO winfo = LoadWeatherInfo(hContact);
+
+ // setup the popup
+ POPUPDATAW ppd = { 0 };
+ ppd.lchContact = hContact;
+ ppd.PluginData = ppd.lchIcon = Skin_LoadProtoIcon(MODULENAME, winfo.status);
+ GetDisplay(&winfo, opt.pTitle, ppd.lpwzContactName);
+ GetDisplay(&winfo, opt.pText, ppd.lpwzText);
+ ppd.PluginWindowProc = PopupDlgProc;
+ ppd.colorBack = (opt.UseWinColors) ? GetSysColor(COLOR_BTNFACE) : opt.BGColour;
+ ppd.colorText = (opt.UseWinColors) ? GetSysColor(COLOR_WINDOWTEXT) : opt.TextColour;
+ ppd.iSeconds = opt.pDelay;
+ PUAddPopupW(&ppd);
+ }
+ return 0;
+}
+
+
+// process for the popup window
+// containing the code for popup actions
+LRESULT CALLBACK PopupWndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
+{
+ POINT pt;
+ HMENU hMenu;
+ switch (uMsg) {
+ case IDM_M2: // brief info
+ BriefInfo(wParam, 0);
+ break;
+
+ case IDM_M3: // read complete forecast
+ LoadForecast(wParam, 0);
+ break;
+
+ case IDM_M4: // display weather map
+ WeatherMap(wParam, 0);
+ break;
+
+ case IDM_M5: // open history window
+ CallService(MS_HISTORY_SHOWCONTACTHISTORY, wParam, 0);
+ break;
+
+ case IDM_M6: // open external log
+ ViewLog(wParam, 0);
+ break;
+
+ case IDM_M7: // display contact menu
+ hMenu = Menu_BuildContactMenu(wParam);
+ GetCursorPos(&pt);
+ hPopupContact = wParam;
+ TrackPopupMenu(hMenu, TPM_LEFTALIGN, pt.x, pt.y, 0, hWnd, nullptr);
+ DestroyMenu(hMenu);
+ break;
+
+ case IDM_M8: // display contact detail
+ CallService(MS_USERINFO_SHOWDIALOG, wParam, 0);
+
+ case WM_COMMAND: //Needed by the contact's context menu
+ if (Clist_MenuProcessCommand(LOWORD(wParam), MPCF_CONTACTMENU, hPopupContact))
+ break;
+ return FALSE;
+
+ case WM_MEASUREITEM: //Needed by the contact's context menu
+ return Menu_MeasureItem(lParam);
+
+ case WM_DRAWITEM: //Needed by the contact's context menu
+ return Menu_DrawItem(lParam);
+ }
+
+ return DefWindowProc(hWnd, uMsg, wParam, lParam);//FALSE;
+}
+
+//============ POPUP OPTIONS ============
+
+// used to select the menu item for popup action menu
+static void SelectMenuItem(HMENU hMenu, int Check)
+{
+ for (int i = 0; i <= GetMenuItemCount(hMenu) - 1; i++)
+ CheckMenuItem(hMenu, i, MF_BYPOSITION | ((int)GetMenuItemID(hMenu, i) == Check) * 8);
+}
+
+// temporary read the current option to memory
+// but does not write to the database
+void ReadPopupOpt(HWND hdlg)
+{
+ wchar_t text[MAX_TEXT_SIZE];
+ wchar_t str[512];
+
+ // popup colour
+ opt.TextColour = SendDlgItemMessage(hdlg, IDC_TEXTCOLOUR, CPM_GETCOLOUR, 0, 0);
+ opt.BGColour = SendDlgItemMessage(hdlg, IDC_BGCOLOUR, CPM_GETCOLOUR, 0, 0);
+
+ // get delay time
+ GetDlgItemText(hdlg, IDC_DELAY, str, _countof(str));
+ int num = _wtoi(str);
+ opt.pDelay = num;
+
+ // other options
+ opt.UseWinColors = (BYTE)IsDlgButtonChecked(hdlg, IDC_USEWINCOLORS);
+ opt.UsePopup = (BYTE)IsDlgButtonChecked(hdlg, IDC_E);
+ opt.UpdatePopup = (BYTE)IsDlgButtonChecked(hdlg, IDC_POP1);
+ opt.AlertPopup = (BYTE)IsDlgButtonChecked(hdlg, IDC_POP2);
+ opt.PopupOnChange = (BYTE)IsDlgButtonChecked(hdlg, IDC_CH);
+ opt.ShowWarnings = (BYTE)IsDlgButtonChecked(hdlg, IDC_W);
+
+ // popup texts
+ wfree(&opt.pText);
+ wfree(&opt.pTitle);
+ GetDlgItemText(hdlg, IDC_PText, text, _countof(text));
+ wSetData(&opt.pText, text);
+ GetDlgItemText(hdlg, IDC_PTitle, text, _countof(text));
+ wSetData(&opt.pTitle, text);
+}
+
+// copied and modified from NewStatusNotify
+INT_PTR CALLBACK DlgPopupOpts(HWND hdlg, UINT msg, WPARAM wParam, LPARAM lParam)
+{
+ int ID;
+ wchar_t str[512];
+ HMENU hMenu, hMenu1;
+ RECT pos;
+ HWND button;
+ MCONTACT hContact;
+
+ switch (msg) {
+ case WM_INITDIALOG:
+ TranslateDialogDefault(hdlg);
+ SaveOptions();
+
+ // click actions
+ hMenu = LoadMenu(g_plugin.getInst(), MAKEINTRESOURCE(IDR_PMENU));
+ hMenu1 = GetSubMenu(hMenu, 0);
+ GetMenuString(hMenu1, opt.LeftClickAction, str, _countof(str), MF_BYCOMMAND);
+ SetDlgItemText(hdlg, IDC_LeftClick, TranslateW(str));
+ GetMenuString(hMenu1, opt.RightClickAction, str, _countof(str), MF_BYCOMMAND);
+ SetDlgItemText(hdlg, IDC_RightClick, TranslateW(str));
+ DestroyMenu(hMenu);
+
+ // other options
+ CheckDlgButton(hdlg, IDC_E, opt.UsePopup ? BST_CHECKED : BST_UNCHECKED);
+ CheckDlgButton(hdlg, IDC_POP2, opt.AlertPopup ? BST_CHECKED : BST_UNCHECKED);
+ CheckDlgButton(hdlg, IDC_POP1, opt.UpdatePopup ? BST_CHECKED : BST_UNCHECKED);
+ CheckDlgButton(hdlg, IDC_CH, opt.PopupOnChange ? BST_CHECKED : BST_UNCHECKED);
+ CheckDlgButton(hdlg, IDC_W, opt.ShowWarnings ? BST_CHECKED : BST_UNCHECKED);
+ SetDlgItemText(hdlg, IDC_PText, opt.pText);
+ SetDlgItemText(hdlg, IDC_PTitle, opt.pTitle);
+ // setting popup delay option
+ _ltow(opt.pDelay, str, 10);
+ SetDlgItemText(hdlg, IDC_DELAY, str);
+ if (opt.pDelay == -1)
+ CheckRadioButton(hdlg, IDC_PD1, IDC_PD3, IDC_PD2);
+ else if (opt.pDelay == 0)
+ CheckRadioButton(hdlg, IDC_PD1, IDC_PD3, IDC_PD1);
+ else
+ CheckRadioButton(hdlg, IDC_PD1, IDC_PD3, IDC_PD3);
+ //Colours. First step is configuring the colours.
+ SendDlgItemMessage(hdlg, IDC_BGCOLOUR, CPM_SETCOLOUR, 0, opt.BGColour);
+ SendDlgItemMessage(hdlg, IDC_TEXTCOLOUR, CPM_SETCOLOUR, 0, opt.TextColour);
+ //Second step is disabling them if we want to use default Windows ones.
+ CheckDlgButton(hdlg, IDC_USEWINCOLORS, opt.UseWinColors ? BST_CHECKED : BST_UNCHECKED);
+ EnableWindow(GetDlgItem(hdlg, IDC_BGCOLOUR), !opt.UseWinColors);
+ EnableWindow(GetDlgItem(hdlg, IDC_TEXTCOLOUR), !opt.UseWinColors);
+
+ // buttons
+ SendDlgItemMessage(hdlg, IDC_PREVIEW, BUTTONSETASFLATBTN, TRUE, 0);
+ SendDlgItemMessage(hdlg, IDC_PDEF, BUTTONSETASFLATBTN, TRUE, 0);
+ SendDlgItemMessage(hdlg, IDC_LeftClick, BUTTONSETASFLATBTN, TRUE, 0);
+ SendDlgItemMessage(hdlg, IDC_RightClick, BUTTONSETASFLATBTN, TRUE, 0);
+ SendDlgItemMessage(hdlg, IDC_VAR3, BUTTONSETASFLATBTN, TRUE, 0);
+ return TRUE;
+
+ case WM_COMMAND:
+ // enable the "apply" button
+ if (HIWORD(wParam) == BN_CLICKED && GetFocus() == (HWND)lParam)
+ SendMessage(GetParent(hdlg), PSM_CHANGED, 0, 0);
+ if (!((LOWORD(wParam) == IDC_UPDATE || LOWORD(wParam) == IDC_DEGREE) &&
+ (HIWORD(wParam) != EN_CHANGE || (HWND)lParam != GetFocus())))
+ SendMessage(GetParent(hdlg), PSM_CHANGED, 0, 0);
+ //These are simple clicks: we don't save, but we tell the Options Page to enable the "Apply" button.
+ switch (LOWORD(wParam)) {
+ case IDC_BGCOLOUR: //Fall through
+ case IDC_TEXTCOLOUR:
+ // select new colors
+ if (HIWORD(wParam) == CPN_COLOURCHANGED)
+ SendMessage(GetParent(hdlg), PSM_CHANGED, 0, 0);
+ break;
+
+ case IDC_USEWINCOLORS:
+ // use window color - enable/disable color selection controls
+ EnableWindow(GetDlgItem(hdlg, IDC_BGCOLOUR), !(opt.UseWinColors));
+ EnableWindow(GetDlgItem(hdlg, IDC_TEXTCOLOUR), !(opt.UseWinColors));
+ SendMessage(GetParent(hdlg), PSM_CHANGED, 0, 0);
+ break;
+
+ case IDC_E:
+ case IDC_CH:
+ SendMessage(GetParent(hdlg), PSM_CHANGED, 0, 0);
+ break;
+
+ case IDC_RightClick:
+ // right click action selection menu
+ button = GetDlgItem(hdlg, IDC_RightClick);
+ GetWindowRect(button, &pos);
+
+ hMenu = LoadMenu(g_plugin.getInst(), MAKEINTRESOURCE(IDR_PMENU));
+ hMenu1 = GetSubMenu(hMenu, 0);
+ TranslateMenu(hMenu1);
+ SelectMenuItem(hMenu1, opt.RightClickAction);
+ ID = TrackPopupMenu(hMenu1, TPM_LEFTBUTTON | TPM_RETURNCMD, pos.left, pos.bottom, 0, hdlg, nullptr);
+ if (ID)
+ opt.RightClickAction = ID;
+ DestroyMenu(hMenu);
+
+ hMenu = LoadMenu(g_plugin.getInst(), MAKEINTRESOURCE(IDR_PMENU));
+ hMenu1 = GetSubMenu(hMenu, 0);
+ GetMenuString(hMenu1, opt.RightClickAction, str, _countof(str), MF_BYCOMMAND);
+ SetDlgItemText(hdlg, IDC_RightClick, TranslateW(str));
+ DestroyMenu(hMenu);
+ break;
+
+ case IDC_LeftClick:
+ // left click action selection menu
+ button = GetDlgItem(hdlg, IDC_LeftClick);
+ GetWindowRect(button, &pos);
+
+ hMenu = LoadMenu(g_plugin.getInst(), MAKEINTRESOURCE(IDR_PMENU));
+ hMenu1 = GetSubMenu(hMenu, 0);
+ TranslateMenu(hMenu1);
+ SelectMenuItem(hMenu1, opt.LeftClickAction);
+ ID = TrackPopupMenu(hMenu1, TPM_LEFTBUTTON | TPM_RETURNCMD, pos.left, pos.bottom, 0, hdlg, nullptr);
+ if (ID) opt.LeftClickAction = ID;
+ DestroyMenu(hMenu);
+
+ hMenu = LoadMenu(g_plugin.getInst(), MAKEINTRESOURCE(IDR_PMENU));
+ hMenu1 = GetSubMenu(hMenu, 0);
+ GetMenuString(hMenu1, opt.LeftClickAction, str, _countof(str), MF_BYCOMMAND);
+ SetDlgItemText(hdlg, IDC_LeftClick, TranslateW(str));
+ DestroyMenu(hMenu);
+ break;
+
+ case IDC_PD1:
+ // Popup delay setting from Popup plugin
+ SetDlgItemText(hdlg, IDC_DELAY, L"0");
+ CheckRadioButton(hdlg, IDC_PD1, IDC_PD3, IDC_PD1);
+ break;
+
+ case IDC_PD2:
+ // Popup delay = permanent
+ SetDlgItemText(hdlg, IDC_DELAY, L"-1");
+ CheckRadioButton(hdlg, IDC_PD1, IDC_PD3, IDC_PD2);
+ break;
+
+ case IDC_DELAY:
+ // if text is edited
+ CheckRadioButton(hdlg, IDC_PD1, IDC_PD3, IDC_PD3);
+ break;
+
+ case IDC_PDEF:
+ // set the default value for popup texts
+ SetTextDefault("Pp");
+ SetDlgItemText(hdlg, IDC_PText, opt.pText);
+ SetDlgItemText(hdlg, IDC_PTitle, opt.pTitle);
+ wfree(&opt.pText);
+ wfree(&opt.pTitle);
+ break;
+
+ case IDC_VAR3:
+ // display variable list
+ wcsncpy(str, L" \n", _countof(str) - 1); // to make the message box wider
+ mir_wstrncat(str, VAR_LIST_POPUP, _countof(str) - mir_wstrlen(str));
+ mir_wstrncat(str, L"\n", _countof(str) - mir_wstrlen(str));
+ mir_wstrncat(str, CUSTOM_VARS, _countof(str) - mir_wstrlen(str));
+ MessageBox(nullptr, str, TranslateT("Variable List"), MB_OK | MB_ICONASTERISK | MB_TOPMOST);
+ break;
+
+ case IDC_PREVIEW:
+ // popup preview
+ hContact = opt.DefStn;
+ ReadPopupOpt(hdlg); // read new options to memory
+ WeatherPopup((WPARAM)opt.DefStn, (BOOL)TRUE); // display popup using new opt
+ DestroyOptions();
+ LoadOptions(); // restore old option in memory
+ opt.DefStn = hContact;
+ break;
+ }
+ break;
+
+ case WM_NOTIFY: //Here we have pressed either the OK or the APPLY button.
+ switch (((LPNMHDR)lParam)->code) {
+ case PSN_APPLY:
+ ReadPopupOpt(hdlg);
+
+ // save the options, and update main menu
+ SaveOptions();
+ UpdatePopupMenu(opt.UsePopup);
+ return TRUE;
+ }
+ break;
+ }
+ return FALSE;
+}
diff --git a/protocols/Weather/src/weather_svcs.cpp b/protocols/Weather/src/weather_svcs.cpp
new file mode 100644
index 0000000000..7c3d2611aa
--- /dev/null
+++ b/protocols/Weather/src/weather_svcs.cpp
@@ -0,0 +1,375 @@
+/*
+Weather Protocol plugin for Miranda IM
+Copyright (c) 2012 Miranda NG team
+Copyright (c) 2005-2011 Boris Krasnovskiy All Rights Reserved
+Copyright (c) 2002-2005 Calvin Che
+
+This program is free software; you can redistribute it and/or
+modify it under the terms of the GNU General Public License
+as published by the Free Software Foundation; version 2
+of the License.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+/*
+This file contain the source related to weather protocol services
+as required for a Miranda protocol. Also, it contains functions for
+building/changing the weather menu items.
+*/
+
+#include "stdafx.h"
+
+static HGENMENU hEnableDisablePopupMenu;
+static HGENMENU hEnableDisableMenu;
+
+//============ MIRANDA PROTOCOL SERVICES ============
+
+// protocol service function for setting weather protocol status
+INT_PTR WeatherSetStatus(WPARAM new_status, LPARAM)
+{
+ new_status = new_status != ID_STATUS_OFFLINE ? ID_STATUS_ONLINE : ID_STATUS_OFFLINE;
+
+ // if we don't want to show status for default station
+ if (!opt.NoProtoCondition && status != new_status) {
+ old_status = status;
+ status = new_status != ID_STATUS_OFFLINE ? ID_STATUS_ONLINE : ID_STATUS_OFFLINE;
+ ProtoBroadcastAck(MODULENAME, NULL, ACKTYPE_STATUS, ACKRESULT_SUCCESS, (HANDLE)old_status, status);
+
+ UpdateMenu(new_status != ID_STATUS_OFFLINE);
+ if (new_status != ID_STATUS_OFFLINE)
+ UpdateAll(FALSE, FALSE);
+ }
+
+ return 0;
+}
+
+// get capabilities protocol service function
+INT_PTR WeatherGetCaps(WPARAM wParam, LPARAM)
+{
+ INT_PTR ret = 0;
+
+ switch (wParam) {
+ case PFLAGNUM_1:
+ // support search and visible list
+ ret = PF1_BASICSEARCH | PF1_ADDSEARCHRES | PF1_EXTSEARCH | PF1_VISLIST | PF1_MODEMSGRECV;
+ break;
+
+ case PFLAGNUM_2:
+ ret = PF2_ONLINE | PF2_INVISIBLE | PF2_SHORTAWAY | PF2_LONGAWAY | PF2_LIGHTDND |
+ PF2_HEAVYDND | PF2_FREECHAT | PF2_OUTTOLUNCH | PF2_ONTHEPHONE;
+ break;
+
+ case PFLAGNUM_4:
+ ret = PF4_AVATARS | PF4_NOCUSTOMAUTH | PF4_NOAUTHDENYREASON | PF4_FORCEAUTH;
+ break;
+
+ case PFLAGNUM_5: /* this is PFLAGNUM_5 change when alpha SDK is released */
+ ret = PF2_INVISIBLE | PF2_SHORTAWAY | PF2_LONGAWAY | PF2_LIGHTDND | PF2_HEAVYDND |
+ PF2_FREECHAT | PF2_OUTTOLUNCH | PF2_ONTHEPHONE;
+ break;
+
+ case PFLAG_UNIQUEIDTEXT:
+ ret = (INT_PTR)Translate("Station ID");
+ break;
+ }
+ return ret;
+}
+
+// protocol service function to get weather protocol name
+INT_PTR WeatherGetName(WPARAM wParam, LPARAM lParam)
+{
+ strncpy((char*)lParam, WEATHERPROTOTEXT, wParam - 1);
+ *((char*)lParam + wParam - 1) = 0;
+ return 0;
+}
+
+// protocol service function to get the current status of the protocol
+INT_PTR WeatherGetStatus(WPARAM, LPARAM)
+{
+ return status;
+}
+
+// protocol service function to get the icon of the protocol
+INT_PTR WeatherLoadIcon(WPARAM wParam, LPARAM)
+{
+ return (LOWORD(wParam) == PLI_PROTOCOL) ? (INT_PTR)CopyIcon(LoadIconEx("main", FALSE)) : 0;
+}
+
+static void __cdecl AckThreadProc(HANDLE param)
+{
+ Sleep(100);
+ ProtoBroadcastAck(MODULENAME, (DWORD_PTR)param, ACKTYPE_GETINFO, ACKRESULT_SUCCESS, (HANDLE)1);
+}
+
+// nothing to do here because weather proto do not need to retrieve contact info form network
+// so just return a 0
+INT_PTR WeatherGetInfo(WPARAM, LPARAM lParam)
+{
+ CCSDATA *ccs = (CCSDATA *)lParam;
+ mir_forkthread(AckThreadProc, (void*)ccs->hContact);
+ return 0;
+}
+
+// avatars
+static const wchar_t *statusStr[] = { L"Light", L"Fog", L"SShower", L"Snow", L"RShower", L"Rain", L"PCloudy", L"Cloudy", L"Sunny", L"NA" };
+static const WORD statusValue[] = { LIGHT, FOG, SSHOWER, SNOW, RSHOWER, RAIN, PCLOUDY, CLOUDY, SUNNY, NA };
+
+INT_PTR WeatherGetAvatarInfo(WPARAM, LPARAM lParam)
+{
+ wchar_t szSearchPath[MAX_PATH], *chop;
+ unsigned i;
+ PROTO_AVATAR_INFORMATION *pai = (PROTO_AVATAR_INFORMATION*)lParam;
+
+ GetModuleFileName(GetModuleHandle(nullptr), szSearchPath, _countof(szSearchPath));
+ chop = wcsrchr(szSearchPath, '\\');
+
+ if (chop) *chop = '\0';
+ else szSearchPath[0] = 0;
+
+ int iStatus = g_plugin.getWord(pai->hContact, "StatusIcon");
+ for (i = 0; i < 10; i++)
+ if (statusValue[i] == iStatus)
+ break;
+
+ if (i >= 10)
+ return GAIR_NOAVATAR;
+
+ pai->format = PA_FORMAT_PNG;
+ mir_snwprintf(pai->filename, L"%s\\Plugins\\Weather\\%s.png", szSearchPath, statusStr[i]);
+ if (_waccess(pai->filename, 4) == 0)
+ return GAIR_SUCCESS;
+
+ pai->format = PA_FORMAT_GIF;
+ mir_snwprintf(pai->filename, L"%s\\Plugins\\Weather\\%s.gif", szSearchPath, statusStr[i]);
+ if (_waccess(pai->filename, 4) == 0)
+ return GAIR_SUCCESS;
+
+ pai->format = PA_FORMAT_UNKNOWN;
+ pai->filename[0] = 0;
+ return GAIR_NOAVATAR;
+}
+
+void AvatarDownloaded(MCONTACT hContact)
+{
+ PROTO_AVATAR_INFORMATION ai = { 0 };
+ ai.hContact = hContact;
+
+ if (WeatherGetAvatarInfo(GAIF_FORCE, (LPARAM)&ai) == GAIR_SUCCESS)
+ ProtoBroadcastAck(MODULENAME, hContact, ACKTYPE_AVATAR, ACKRESULT_SUCCESS, &ai);
+ else
+ ProtoBroadcastAck(MODULENAME, hContact, ACKTYPE_AVATAR, ACKRESULT_STATUS, nullptr);
+}
+
+static void __cdecl WeatherGetAwayMsgThread(void *arg)
+{
+ Sleep(100);
+
+ MCONTACT hContact = (DWORD_PTR)arg;
+ DBVARIANT dbv;
+ if (!db_get_ws(hContact, "CList", "StatusMsg", &dbv)) {
+ ProtoBroadcastAck(MODULENAME, hContact, ACKTYPE_AWAYMSG, ACKRESULT_SUCCESS, (HANDLE)1, (LPARAM)dbv.pwszVal);
+ db_free(&dbv);
+ }
+ else ProtoBroadcastAck(MODULENAME, hContact, ACKTYPE_AWAYMSG, ACKRESULT_SUCCESS, (HANDLE)1);
+}
+
+static INT_PTR WeatherGetAwayMsg(WPARAM, LPARAM lParam)
+{
+ CCSDATA* ccs = (CCSDATA*)lParam;
+ if (ccs == nullptr)
+ return 0;
+
+ mir_forkthread(WeatherGetAwayMsgThread, (void*)ccs->hContact);
+ return 1;
+}
+
+//============ PROTOCOL INITIALIZATION ============
+// protocol services
+void InitServices(void)
+{
+ CreateProtoServiceFunction(MODULENAME, PS_GETCAPS, WeatherGetCaps);
+ CreateProtoServiceFunction(MODULENAME, PS_GETNAME, WeatherGetName);
+ CreateProtoServiceFunction(MODULENAME, PS_LOADICON, WeatherLoadIcon);
+ CreateProtoServiceFunction(MODULENAME, PS_SETSTATUS, WeatherSetStatus);
+ CreateProtoServiceFunction(MODULENAME, PS_GETSTATUS, WeatherGetStatus);
+ CreateProtoServiceFunction(MODULENAME, PS_BASICSEARCH, WeatherBasicSearch);
+ CreateProtoServiceFunction(MODULENAME, PS_SEARCHBYEMAIL, WeatherBasicSearch);
+ CreateProtoServiceFunction(MODULENAME, PS_ADDTOLIST, WeatherAddToList);
+ CreateProtoServiceFunction(MODULENAME, PSS_GETINFO, WeatherGetInfo);
+ CreateProtoServiceFunction(MODULENAME, PS_GETAVATARINFO, WeatherGetAvatarInfo);
+ CreateProtoServiceFunction(MODULENAME, PSS_GETAWAYMSG, WeatherGetAwayMsg);
+ CreateProtoServiceFunction(MODULENAME, PS_CREATEADVSEARCHUI, WeatherCreateAdvancedSearchUI);
+ CreateProtoServiceFunction(MODULENAME, PS_SEARCHBYADVANCED, WeatherAdvancedSearch);
+
+ CreateProtoServiceFunction(MODULENAME, MS_WEATHER_GETDISPLAY, GetDisplaySvcFunc);
+}
+
+//============ MENU INITIALIZATION ============
+
+void UpdateMenu(BOOL State)
+{
+ // update option setting
+ opt.CAutoUpdate = State;
+ g_plugin.setByte("AutoUpdate", (BYTE)State);
+
+ if (State) { // to enable auto-update
+ Menu_ModifyItem(hEnableDisableMenu, LPGENW("Auto Update Enabled"), GetIconHandle("main"));
+ opt.AutoUpdate = 1;
+ }
+ else { // to disable auto-update
+ Menu_ModifyItem(hEnableDisableMenu, LPGENW("Auto Update Disabled"), GetIconHandle("disabled"));
+ opt.AutoUpdate = 0;
+ }
+
+ CallService(MS_TTB_SETBUTTONSTATE, (WPARAM)hTBButton, !State ? TTBST_PUSHED : 0);
+}
+
+void UpdatePopupMenu(BOOL State)
+{
+ // update option setting
+ opt.UsePopup = State;
+ g_plugin.setByte("UsePopup", (BYTE)opt.UsePopup);
+
+ if (State) // to enable popup
+ Menu_ModifyItem(hEnableDisablePopupMenu, LPGENW("Disable &weather notification"), GetIconHandle("popup"));
+ else // to disable popup
+ Menu_ModifyItem(hEnableDisablePopupMenu, LPGENW("Enable &weather notification"), GetIconHandle("nopopup"));
+}
+
+// update the weather auto-update menu item when click on it
+INT_PTR EnableDisableCmd(WPARAM wParam, LPARAM lParam)
+{
+ UpdateMenu(wParam == TRUE ? (BOOL)lParam : !opt.CAutoUpdate);
+ return 0;
+}
+
+// update the weather popup menu item when click on it
+INT_PTR MenuitemNotifyCmd(WPARAM, LPARAM)
+{
+ UpdatePopupMenu(!opt.UsePopup);
+ return 0;
+}
+
+// adding weather contact menus
+// copied and modified form "modified MSN Protocol"
+void AddMenuItems(void)
+{
+ CMenuItem mi(&g_plugin);
+
+ // contact menu
+ SET_UID(mi, 0x266ef52b, 0x869a, 0x4cac, 0xa9, 0xf8, 0xea, 0x5b, 0xb8, 0xab, 0xe0, 0x24);
+ CreateServiceFunction(MS_WEATHER_UPDATE, UpdateSingleStation);
+ mi.position = -0x7FFFFFFA;
+ mi.hIcolibItem = GetIconHandle("update");
+ mi.name.a = LPGEN("Update Weather");
+ mi.pszService = MS_WEATHER_UPDATE;
+ Menu_AddContactMenuItem(&mi, MODULENAME);
+
+ SET_UID(mi, 0x45361b4, 0x8de, 0x44b4, 0x8f, 0x11, 0x9b, 0xe9, 0x6e, 0xa8, 0x83, 0x54);
+ CreateServiceFunction(MS_WEATHER_REFRESH, UpdateSingleRemove);
+ mi.position = -0x7FFFFFF9;
+ mi.hIcolibItem = GetIconHandle("update2");
+ mi.name.a = LPGEN("Remove Old Data then Update");
+ mi.pszService = MS_WEATHER_REFRESH;
+ Menu_AddContactMenuItem(&mi, MODULENAME);
+
+ SET_UID(mi, 0x4232975e, 0xb181, 0x46a5, 0xb7, 0x6e, 0xd2, 0x5f, 0xef, 0xb8, 0xc4, 0x4d);
+ CreateServiceFunction(MS_WEATHER_BRIEF, BriefInfoSvc);
+ mi.position = -0x7FFFFFF8;
+ mi.hIcolibItem = GetIconHandle("brief");
+ mi.name.a = LPGEN("Brief Information");
+ mi.pszService = MS_WEATHER_BRIEF;
+ Menu_AddContactMenuItem(&mi, MODULENAME);
+
+ SET_UID(mi, 0x3d6ed729, 0xd49a, 0x4ae9, 0x8e, 0x2, 0x9f, 0xe0, 0xf0, 0x2c, 0xcc, 0xb1);
+ CreateServiceFunction(MS_WEATHER_COMPLETE, LoadForecast);
+ mi.position = -0x7FFFFFF7;
+ mi.hIcolibItem = GetIconHandle("read");
+ mi.name.a = LPGEN("Read Complete Forecast");
+ mi.pszService = MS_WEATHER_COMPLETE;
+ Menu_AddContactMenuItem(&mi, MODULENAME);
+
+ SET_UID(mi, 0xc4b6c5e0, 0x13c3, 0x4e02, 0x8a, 0xeb, 0xeb, 0x8a, 0xe2, 0x66, 0x40, 0xd4);
+ CreateServiceFunction(MS_WEATHER_MAP, WeatherMap);
+ mi.position = -0x7FFFFFF6;
+ mi.hIcolibItem = GetIconHandle("map");
+ mi.name.a = LPGEN("Weather Map");
+ mi.pszService = MS_WEATHER_MAP;
+ Menu_AddContactMenuItem(&mi, MODULENAME);
+
+ SET_UID(mi, 0xee3ad7f4, 0x3377, 0x4e4c, 0x8f, 0x3c, 0x3b, 0xf5, 0xd4, 0x86, 0x28, 0x25);
+ CreateServiceFunction(MS_WEATHER_LOG, ViewLog);
+ mi.position = -0x7FFFFFF5;
+ mi.hIcolibItem = GetIconHandle("log");
+ mi.name.a = LPGEN("View Log");
+ mi.pszService = MS_WEATHER_LOG;
+ Menu_AddContactMenuItem(&mi, MODULENAME);
+
+ SET_UID(mi, 0x1b01cd6a, 0xe5ee, 0x42b4, 0xa1, 0x6d, 0x43, 0xb9, 0x4, 0x58, 0x43, 0x2e);
+ CreateServiceFunction(MS_WEATHER_EDIT, EditSettings);
+ mi.position = -0x7FFFFFF4;
+ mi.hIcolibItem = GetIconHandle("edit");
+ mi.name.a = LPGEN("Edit Settings");
+ mi.pszService = MS_WEATHER_EDIT;
+ Menu_AddContactMenuItem(&mi, MODULENAME);
+
+ // adding main menu items
+ mi.root = g_plugin.addRootMenu(MO_MAIN, LPGENW("Weather"), 500099000);
+ Menu_ConfigureItem(mi.root, MCI_OPT_UID, "82809D2F-2CF0-4E15-9350-D257A7748552");
+
+ SET_UID(mi, 0x5ad16188, 0xe0a0, 0x4c31, 0x85, 0xc3, 0xe4, 0x85, 0x79, 0x7e, 0x4b, 0x9c);
+ CreateServiceFunction(MS_WEATHER_ENABLED, EnableDisableCmd);
+ mi.name.a = LPGEN("Enable/Disable Weather Update");
+ mi.hIcolibItem = GetIconHandle("main");
+ mi.position = 10100001;
+ mi.pszService = MS_WEATHER_ENABLED;
+ hEnableDisableMenu = Menu_AddMainMenuItem(&mi);
+ UpdateMenu(opt.AutoUpdate);
+
+ SET_UID(mi, 0x2b1c2054, 0x2991, 0x4025, 0x87, 0x73, 0xb6, 0xf7, 0x85, 0xac, 0xc7, 0x37);
+ CreateServiceFunction(MS_WEATHER_UPDATEALL, UpdateAllInfo);
+ mi.position = 20100001;
+ mi.hIcolibItem = GetIconHandle("update");
+ mi.name.a = LPGEN("Update All Weather");
+ mi.pszService = MS_WEATHER_UPDATEALL;
+ Menu_AddMainMenuItem(&mi);
+
+ SET_UID(mi, 0x8234c00e, 0x788e, 0x424f, 0xbc, 0xc4, 0x2, 0xfd, 0x67, 0x58, 0x2d, 0x19);
+ CreateServiceFunction(MS_WEATHER_REFRESHALL, UpdateAllRemove);
+ mi.position = 20100002;
+ mi.hIcolibItem = GetIconHandle("update2");
+ mi.name.a = LPGEN("Remove Old Data then Update All");
+ mi.pszService = MS_WEATHER_REFRESHALL;
+ Menu_AddMainMenuItem(&mi);
+
+ // only run if popup service exists
+ if (ServiceExists(MS_POPUP_ADDPOPUPW)) {
+ SET_UID(mi, 0xdc5411cb, 0xb7c7, 0x443b, 0x88, 0x5a, 0x90, 0x24, 0x43, 0xde, 0x54, 0x3e);
+ CreateServiceFunction(MODULENAME "/PopupMenu", MenuitemNotifyCmd);
+ mi.name.a = LPGEN("Weather Notification");
+ mi.hIcolibItem = GetIconHandle("popup");
+ mi.position = 0;
+ mi.root = g_plugin.addRootMenu(MO_MAIN, LPGENW("Popups"), 0);
+ mi.pszService = MODULENAME "/PopupMenu";
+ hEnableDisablePopupMenu = Menu_AddMainMenuItem(&mi);
+ UpdatePopupMenu(opt.UsePopup);
+ }
+
+ if (ServiceExists(MS_CLIST_FRAMES_ADDFRAME)) {
+ SET_UID(mi, 0xe193fe9b, 0xf6ad, 0x41ac, 0x95, 0x29, 0x45, 0x4, 0x44, 0xb1, 0xeb, 0x5d);
+ mi.pszService = "Weather/mwin_menu";
+ CreateServiceFunction(mi.pszService, Mwin_MenuClicked);
+ mi.position = -0x7FFFFFF0;
+ mi.hIcolibItem = nullptr;
+ mi.root = nullptr;
+ mi.name.a = LPGEN("Display in a frame");
+ hMwinMenu = Menu_AddContactMenuItem(&mi, MODULENAME);
+ }
+}
diff --git a/protocols/Weather/src/weather_update.cpp b/protocols/Weather/src/weather_update.cpp
new file mode 100644
index 0000000000..12736b35be
--- /dev/null
+++ b/protocols/Weather/src/weather_update.cpp
@@ -0,0 +1,607 @@
+/*
+Weather Protocol plugin for Miranda IM
+Copyright (c) 2012 Miranda NG team
+Copyright (c) 2005-2011 Boris Krasnovskiy All Rights Reserved
+Copyright (c) 2002-2005 Calvin Che
+
+This program is free software; you can redistribute it and/or
+modify it under the terms of the GNU General Public License
+as published by the Free Software Foundation; version 2
+of the License.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+/*
+This file contain the source related to updating new weather
+information, both automatic (by timer) and manually (by selecting
+menu items).
+*/
+
+#include "stdafx.h"
+
+UPDATELIST *UpdateListHead, *UpdateListTail;
+
+//============ RETRIEVE NEW WEATHER ============
+//
+// retrieve weather info and display / log them
+// hContact = current contact
+int UpdateWeather(MCONTACT hContact)
+{
+ wchar_t str[256], str2[MAX_TEXT_SIZE];
+ DBVARIANT dbv;
+ BOOL Ch = FALSE;
+
+ if (hContact == NULL) // some error prevention
+ return 1;
+
+ dbv.pszVal = "";
+
+ // log to netlib log for debug purpose
+ Netlib_LogfW(hNetlibUser, L"************************************************************************");
+ int dbres = g_plugin.getWString(hContact, "Nick", &dbv);
+
+ Netlib_LogfW(hNetlibUser, L"<-- Start update for station -->");
+
+ // download the info and parse it
+ // result are stored in database
+ int code = GetWeatherData(hContact);
+ if (code != 0) {
+ // error occurs if the return value is not equals to 0
+ if (opt.ShowWarnings) {
+ // show warnings by popup
+ mir_snwprintf(str, _countof(str) - 105,
+ TranslateT("Unable to retrieve weather information for %s"), dbv.pwszVal);
+ mir_wstrncat(str, L"\n", _countof(str) - mir_wstrlen(str));
+ wchar_t *tszError = GetError(code);
+ mir_wstrncat(str, tszError, _countof(str) - mir_wstrlen(str));
+ WPShowMessage(str, SM_WARNING);
+ mir_free(tszError);
+ }
+ // log to netlib
+ Netlib_LogfW(hNetlibUser, L"Error! Update cannot continue... Start to free memory");
+ Netlib_LogfW(hNetlibUser, L"<-- Error occurs while updating station: %s -->", dbv.pwszVal);
+ if (!dbres) db_free(&dbv);
+ return 1;
+ }
+ if (!dbres) db_free(&dbv);
+
+ // initialize, load new weather Data
+ WEATHERINFO winfo = LoadWeatherInfo(hContact);
+
+ // translate weather condition
+ mir_wstrcpy(winfo.cond, TranslateW(winfo.cond));
+
+ // compare the old condition and determine if the weather had changed
+ if (opt.UpdateOnlyConditionChanged) { // consider condition change
+ if (!g_plugin.getWString(hContact, "LastCondition", &dbv)) {
+ if (mir_wstrcmpi(winfo.cond, dbv.pwszVal)) Ch = TRUE; // the weather condition is changed
+ db_free(&dbv);
+ }
+ else Ch = TRUE;
+ if (!g_plugin.getWString(hContact, "LastTemperature", &dbv)) {
+ if (mir_wstrcmpi(winfo.temp, dbv.pwszVal)) Ch = TRUE; // the temperature is changed
+ db_free(&dbv);
+ }
+ else Ch = TRUE;
+ }
+ else { // consider update time change
+ if (!g_plugin.getWString(hContact, "LastUpdate", &dbv)) {
+ if (mir_wstrcmpi(winfo.update, dbv.pwszVal)) Ch = TRUE; // the update time is changed
+ db_free(&dbv);
+ }
+ else Ch = TRUE;
+ }
+
+ // have weather alert issued?
+ dbres = db_get_ws(hContact, WEATHERCONDITION, "Alert", &dbv);
+ if (!dbres && dbv.pwszVal[0] != 0) {
+ if (opt.AlertPopup && !g_plugin.getByte(hContact, "DPopUp") && Ch) {
+ // display alert popup
+ mir_snwprintf(str, L"Alert for %s%c%s", winfo.city, 255, dbv.pwszVal);
+ WPShowMessage(str, SM_WEATHERALERT);
+ }
+ // alert issued, set display to italic
+ if (opt.MakeItalic)
+ g_plugin.setWord(hContact, "ApparentMode", ID_STATUS_OFFLINE);
+ Skin_PlaySound("weatheralert");
+ }
+ // alert dropped, set the display back to normal
+ else g_plugin.delSetting(hContact, "ApparentMode");
+ if (!dbres) db_free(&dbv);
+
+ // backup current condition for checking if the weather is changed or not
+ g_plugin.setWString(hContact, "LastLog", winfo.update);
+ g_plugin.setWString(hContact, "LastCondition", winfo.cond);
+ g_plugin.setWString(hContact, "LastTemperature", winfo.temp);
+ g_plugin.setWString(hContact, "LastUpdate", winfo.update);
+
+ // display condition on contact list
+ if (opt.DisCondIcon && winfo.status != ID_STATUS_OFFLINE)
+ g_plugin.setWord(hContact, "Status", ID_STATUS_ONLINE);
+ else
+ g_plugin.setWord(hContact, "Status", winfo.status);
+ AvatarDownloaded(hContact);
+
+ GetDisplay(&winfo, opt.cText, str2);
+ db_set_ws(hContact, "CList", "MyHandle", str2);
+
+ GetDisplay(&winfo, opt.sText, str2);
+ if (str2[0])
+ db_set_ws(hContact, "CList", "StatusMsg", str2);
+ else
+ db_unset(hContact, "CList", "StatusMsg");
+
+ ProtoBroadcastAck(MODULENAME, hContact, ACKTYPE_AWAYMSG, ACKRESULT_SUCCESS, nullptr, (LPARAM)(str2[0] ? str2 : nullptr));
+
+ // save descriptions in MyNotes
+ GetDisplay(&winfo, opt.nText, str2);
+ db_set_ws(hContact, "UserInfo", "MyNotes", str2);
+ GetDisplay(&winfo, opt.xText, str2);
+ db_set_ws(hContact, WEATHERCONDITION, "WeatherInfo", str2);
+
+ // set the update tag
+ g_plugin.setByte(hContact, "IsUpdated", TRUE);
+
+ // save info for default weather condition
+ if (!mir_wstrcmp(winfo.id, opt.Default) && !opt.NoProtoCondition) {
+ // save current condition for default station to be displayed after the update
+ old_status = status;
+ status = winfo.status;
+ // a workaround for a default station that currently have an n/a icon assigned
+ if (status == ID_STATUS_OFFLINE) status = NOSTATUSDATA;
+ ProtoBroadcastAck(MODULENAME, NULL, ACKTYPE_STATUS, ACKRESULT_SUCCESS, (HANDLE)old_status, status);
+ }
+
+ // logging
+ if (Ch) {
+ // play the sound event
+ Skin_PlaySound("weatherupdated");
+
+ if (g_plugin.getByte(hContact, "File")) {
+ // external log
+ if (!g_plugin.getWString(hContact, "Log", &dbv)) {
+ // for the option for overwriting the file, delete old file first
+ if (g_plugin.getByte(hContact, "Overwrite"))
+ DeleteFile(dbv.pwszVal);
+
+ // open the file and set point to the end of file
+ FILE *file = _wfopen(dbv.pwszVal, L"a");
+ db_free(&dbv);
+ if (file != nullptr) {
+ // write data to the file and close
+ GetDisplay(&winfo, opt.eText, str2);
+ fputws(str2, file);
+ fclose(file);
+ }
+ }
+ }
+
+ if (g_plugin.getByte(hContact, "History")) {
+ // internal log using history
+ GetDisplay(&winfo, opt.hText, str2);
+
+ T2Utf szMessage(str2);
+
+ DBEVENTINFO dbei = {};
+ dbei.szModule = MODULENAME;
+ dbei.timestamp = (DWORD)time(0);
+ dbei.flags = DBEF_READ | DBEF_UTF;
+ dbei.eventType = EVENTTYPE_MESSAGE;
+ dbei.pBlob = szMessage;
+ dbei.cbBlob = (DWORD)mir_strlen(szMessage) + 1;
+ db_event_add(hContact, &dbei);
+ }
+
+ // show the popup
+ NotifyEventHooks(hHookWeatherUpdated, hContact, (LPARAM)Ch);
+ }
+
+ Netlib_LogfW(hNetlibUser, L"Update Completed - Start to free memory");
+ Netlib_LogfW(hNetlibUser, L"<-- Update successful for station -->");
+
+ // Update frame data
+ UpdateMwinData(hContact);
+
+ // update brief info if its opened
+ HWND hMoreDataDlg = WindowList_Find(hDataWindowList, hContact);
+ if (hMoreDataDlg != nullptr)
+ PostMessage(hMoreDataDlg, WM_UPDATEDATA, 0, 0);
+ return 0;
+}
+
+//============ UPDATE LIST ============
+//
+// a linked list queue for updating weather station
+// this function add a weather contact to the end of queue for update
+// hContact = current contact
+void UpdateListAdd(MCONTACT hContact)
+{
+ UPDATELIST *newItem = (UPDATELIST*)mir_alloc(sizeof(UPDATELIST));
+ newItem->hContact = hContact;
+ newItem->next = nullptr;
+
+ WaitForSingleObject(hUpdateMutex, INFINITE);
+
+ if (UpdateListTail == nullptr) UpdateListHead = newItem;
+ else UpdateListTail->next = newItem;
+ UpdateListTail = newItem;
+
+ ReleaseMutex(hUpdateMutex);
+}
+
+// get the first item from the update queue and remove it from the queue
+// return value = the contact for next update
+MCONTACT UpdateGetFirst()
+{
+ MCONTACT hContact = NULL;
+
+ WaitForSingleObject(hUpdateMutex, INFINITE);
+
+ if (UpdateListHead != nullptr) {
+ UPDATELIST* Item = UpdateListHead;
+
+ hContact = Item->hContact;
+ UpdateListHead = Item->next;
+ mir_free(Item);
+
+ if (UpdateListHead == nullptr)
+ UpdateListTail = nullptr;
+ }
+
+ ReleaseMutex(hUpdateMutex);
+
+ return hContact;
+}
+
+void DestroyUpdateList(void)
+{
+ WaitForSingleObject(hUpdateMutex, INFINITE);
+
+ // free the list one by one
+ UPDATELIST *temp = UpdateListHead;
+ while (temp != nullptr) {
+ UpdateListHead = temp->next;
+ mir_free(temp);
+ temp = UpdateListHead;
+ }
+ // make sure the entire list is clear
+ UpdateListTail = nullptr;
+
+ ReleaseMutex(hUpdateMutex);
+}
+
+// update all weather thread
+// this thread update each weather station from the queue
+static void UpdateThreadProc(void *)
+{
+ WaitForSingleObject(hUpdateMutex, INFINITE);
+ if (ThreadRunning) {
+ ReleaseMutex(hUpdateMutex);
+ return;
+ }
+ ThreadRunning = TRUE; // prevent 2 instance of this thread running
+ ReleaseMutex(hUpdateMutex);
+
+ // update weather by getting the first station from the queue until the queue is empty
+ while (UpdateListHead != nullptr && !Miranda_IsTerminated())
+ UpdateWeather(UpdateGetFirst());
+
+ // exit the update thread
+ ThreadRunning = FALSE;
+}
+
+//============ UPDATE WEATHER ============
+//
+// update all weather station
+// AutoUpdate = true if it is from automatic update using timer
+// false if it is from update by clicking the main menu
+void UpdateAll(BOOL AutoUpdate, BOOL RemoveData)
+{
+ // add all weather contact to the update queue list
+ for (auto &hContact : Contacts(MODULENAME))
+ if (!g_plugin.getByte(hContact, "AutoUpdate") || !AutoUpdate) {
+ if (RemoveData)
+ DBDataManage(hContact, WDBM_REMOVE, 0, 0);
+ UpdateListAdd(hContact);
+ }
+
+ // if it is not updating, then start the update thread process
+ // if it is updating, the stations just added to the queue will get updated by the already-running process
+ if (!ThreadRunning)
+ mir_forkthread(UpdateThreadProc);
+}
+
+// update a single station
+// wParam = handle for the weather station that is going to be updated
+INT_PTR UpdateSingleStation(WPARAM wParam, LPARAM)
+{
+ if (IsMyContact(wParam)) {
+ // add the station to the end of the update queue
+ UpdateListAdd(wParam);
+
+ // if it is not updating, then start the update thread process
+ // if it is updating, the stations just added to the queue will get
+ // updated by the already-running process
+ if (!ThreadRunning)
+ mir_forkthread(UpdateThreadProc);
+ }
+
+ return 0;
+}
+
+// update a single station with removing the old data
+// wParam = handle for the weather station that is going to be updated
+INT_PTR UpdateSingleRemove(WPARAM wParam, LPARAM)
+{
+ if (IsMyContact(wParam)) {
+ // add the station to the end of the update queue, and also remove old data
+ DBDataManage(wParam, WDBM_REMOVE, 0, 0);
+ UpdateListAdd(wParam);
+
+ // if it is not updating, then start the update thread process
+ // if it is updating, the stations just added to the queue will get updated by the already-running process
+ if (!ThreadRunning)
+ mir_forkthread(UpdateThreadProc);
+ }
+
+ return 0;
+}
+
+// the "Update All" menu item in main menu
+INT_PTR UpdateAllInfo(WPARAM, LPARAM)
+{
+ if (!ThreadRunning)
+ UpdateAll(FALSE, FALSE);
+ return 0;
+}
+
+// the "Update All" menu item in main menu and remove the old data
+INT_PTR UpdateAllRemove(WPARAM, LPARAM)
+{
+ if (!ThreadRunning)
+ UpdateAll(FALSE, TRUE);
+ return 0;
+}
+
+//============ GETTING WEATHER DATA ============
+//
+// getting weather data and save them into the database
+// hContact = the contact to get the data
+int GetWeatherData(MCONTACT hContact)
+{
+ // get each part of the id's
+ wchar_t id[256];
+ GetStationID(hContact, id, _countof(id));
+
+ // test ID format
+ wchar_t* szInfo = wcschr(id, '/');
+ if (szInfo == nullptr)
+ return INVALID_ID_FORMAT;
+
+ GetID(id);
+
+ wchar_t Svc[256];
+ GetStationID(hContact, Svc, _countof(Svc));
+ GetSvc(Svc);
+
+ // check for invalid station
+ if (id[0] == 0) return INVALID_ID;
+ if (Svc[0] == 0) return INVALID_SVC;
+
+ // get the update strings (loaded to memory from ini files)
+ WIDATA *Data = GetWIData(Svc);
+ if (Data == nullptr)
+ return SVC_NOT_FOUND; // the ini for the station cannot be found
+
+ WORD cond = NA;
+ char loc[256];
+ for (int i = 0; i < 4; ++i) {
+ // generate update URL
+ switch (i) {
+ case 0:
+ mir_snprintf(loc, Data->UpdateURL, _T2A(id));
+ break;
+
+ case 1:
+ mir_snprintf(loc, Data->UpdateURL2, _T2A(id));
+ break;
+
+ case 2:
+ mir_snprintf(loc, Data->UpdateURL3, _T2A(id));
+ break;
+
+ case 3:
+ mir_snprintf(loc, Data->UpdateURL4, _T2A(id));
+ break;
+
+ default:
+ continue;
+ }
+
+ if (loc[0] == 0)
+ continue;
+
+ // download the html file from the internet
+ wchar_t* szData = nullptr;
+ int retval = InternetDownloadFile(loc, Data->Cookie, Data->UserAgent, &szData);
+ if (retval != 0) {
+ mir_free(szData);
+ return retval;
+ }
+ if (wcsstr(szData, L"Document Not Found") != nullptr) {
+ mir_free(szData);
+ return DOC_NOT_FOUND;
+ }
+
+ szInfo = szData;
+ WIDATAITEMLIST *Item = Data->UpdateData;
+
+ // begin parsing item by item
+ while (Item != nullptr) {
+ if (Item->Item.Url[0] != 0 && Item->Item.Url[0] != (i + '1')) {
+ Item = Item->Next;
+ continue;
+ }
+
+ wchar_t DataValue[MAX_DATA_LEN];
+ switch (Item->Item.Type) {
+ case WID_NORMAL:
+ // if it is a normal item with start= and end=, then parse through the downloaded string
+ // to get a data value.
+ GetDataValue(&Item->Item, DataValue, &szInfo);
+ if (mir_wstrcmp(Item->Item.Name, L"Condition") && mir_wstrcmpi(Item->Item.Unit, L"Cond"))
+ wcsncpy(DataValue, TranslateW(DataValue), MAX_DATA_LEN - 1);
+ break;
+
+ case WID_SET:
+ {
+ // for the "Set Data=" operation
+ DBVARIANT dbv;
+ wchar_t *chop, *str, str2[MAX_DATA_LEN];
+ BOOL hasvar = FALSE;
+ size_t stl;
+
+ // get the set data operation string
+ str = Item->Item.End;
+ DataValue[0] = 0;
+ // go through each part of the operation string seperated by the & operator
+ do {
+ // the end of the string, last item
+ chop = wcsstr(str, L" & ");
+ if (chop == nullptr)
+ chop = wcschr(str, '\0');
+
+ stl = min(sizeof(str2) - 1, (unsigned)(chop - str - 2));
+ wcsncpy(str2, str + 1, stl);
+ str2[stl] = 0;
+
+ switch (str[0]) {
+ case '[': // variable, add the value to the result string
+ hasvar = TRUE;
+ if (!DBGetData(hContact, _T2A(str2), &dbv)) {
+ mir_wstrncat(DataValue, dbv.pwszVal, _countof(DataValue) - mir_wstrlen(DataValue));
+ DataValue[_countof(DataValue) - 1] = 0;
+ db_free(&dbv);
+ }
+ break;
+
+ case'\"': // constant, add it to the result string
+ mir_wstrncat(DataValue, TranslateW(str2), _countof(DataValue) - mir_wstrlen(DataValue));
+ DataValue[_countof(DataValue) - 1] = 0;
+ break;
+ }
+
+ // remove the front part of the string that is done and continue parsing
+ str = chop + 3;
+ } while (chop[0] && str[0]);
+
+ if (!hasvar) ConvertDataValue(&Item->Item, DataValue);
+ break;
+ }
+ case WID_BREAK:
+ {
+ // for the "Break Data=" operation
+ DBVARIANT dbv;
+ if (!DBGetData(hContact, _T2A(Item->Item.Start), &dbv)) {
+ wcsncpy(DataValue, dbv.pwszVal, _countof(DataValue));
+ DataValue[_countof(DataValue) - 1] = 0;
+ db_free(&dbv);
+ }
+ else {
+ DataValue[0] = 0;
+ break; // do not continue if the source is invalid
+ }
+
+ // generate the strings
+ wchar_t* end = wcsstr(DataValue, Item->Item.Break);
+ if (end == nullptr) {
+ DataValue[0] = 0;
+ break; // exit if break string is not found
+ }
+ *end = '\0';
+ end += mir_wstrlen(Item->Item.Break);
+ while (end[0] == ' ')
+ end++; // remove extra space
+
+ ConvertDataValue(&Item->Item, DataValue);
+
+ // write the 2 strings created from the break operation
+ if (Item->Item.End[0])
+ db_set_ws(hContact, WEATHERCONDITION, _T2A(Item->Item.End), end);
+ break;
+ }
+ }
+
+ // don't store data if it is not available
+ if ((DataValue[0] != 0 && mir_wstrcmp(DataValue, NODATA) &&
+ mir_wstrcmp(DataValue, TranslateW(NODATA)) && mir_wstrcmp(Item->Item.Name, L"Ignore")) ||
+ (!mir_wstrcmp(Item->Item.Name, L"Alert") && i == 0)) {
+ // temporary workaround for mToolTip to show feel-like temperature
+ if (!mir_wstrcmp(Item->Item.Name, L"Feel"))
+ db_set_ws(hContact, WEATHERCONDITION, "Heat Index", DataValue);
+ GetStationID(hContact, Svc, _countof(Svc));
+ if (!mir_wstrcmp(Svc, opt.Default))
+ db_set_ws(0, DEFCURRENTWEATHER, _T2A(Item->Item.Name), DataValue);
+ if (!mir_wstrcmp(Item->Item.Name, L"Condition")) {
+ wchar_t buf[128], *cbuf;
+ mir_snwprintf(buf, L"#%s Weather", DataValue);
+ cbuf = TranslateW(buf);
+ if (cbuf[0] == '#')
+ cbuf = TranslateW(DataValue);
+ db_set_ws(hContact, WEATHERCONDITION, _T2A(Item->Item.Name), cbuf);
+ CharLowerBuff(DataValue, (DWORD)mir_wstrlen(DataValue));
+ cond = GetIcon(DataValue, Data);
+ }
+ else if (mir_wstrcmpi(Item->Item.Unit, L"Cond") == 0) {
+ wchar_t buf[128], *cbuf;
+ mir_snwprintf(buf, L"#%s Weather", DataValue);
+ cbuf = TranslateW(buf);
+ if (cbuf[0] == '#')
+ cbuf = TranslateW(DataValue);
+ db_set_ws(hContact, WEATHERCONDITION, _T2A(Item->Item.Name), cbuf);
+ }
+ else db_set_ws(hContact, WEATHERCONDITION, _T2A(Item->Item.Name), DataValue);
+ }
+ Item = Item->Next;
+ }
+ mir_free(szData);
+ }
+
+ // assign condition icon
+ g_plugin.setWord(hContact, "StatusIcon", cond);
+ g_plugin.setWString(hContact, "MirVer", Data->DisplayName);
+ return 0;
+}
+
+//============ UPDATE TIMERS ============
+//
+// main auto-update timer
+void CALLBACK timerProc(HWND, UINT, UINT_PTR, DWORD)
+{
+ // only run if it is not current updating and the auto update option is enabled
+ if (!ThreadRunning && opt.CAutoUpdate && !Miranda_IsTerminated() && (opt.NoProtoCondition || status == ID_STATUS_ONLINE))
+ UpdateAll(TRUE, FALSE);
+}
+
+
+// temporary timer for first run
+// when this is run, it kill the old startup timer and create the permenant one above
+void CALLBACK timerProc2(HWND, UINT, UINT_PTR, DWORD)
+{
+ KillTimer(nullptr, timerId);
+ ThreadRunning = FALSE;
+
+ if (Miranda_IsTerminated())
+ return;
+
+ if (opt.StartupUpdate && opt.NoProtoCondition)
+ UpdateAll(FALSE, FALSE);
+ timerId = SetTimer(nullptr, 0, ((int)opt.UpdateTime) * 60000, timerProc);
+}
diff --git a/protocols/Weather/src/weather_userinfo.cpp b/protocols/Weather/src/weather_userinfo.cpp
new file mode 100644
index 0000000000..3ce9460c1b
--- /dev/null
+++ b/protocols/Weather/src/weather_userinfo.cpp
@@ -0,0 +1,358 @@
+/*
+Weather Protocol plugin for Miranda IM
+Copyright (c) 2012 Miranda NG team
+Copyright (c) 2005-2011 Boris Krasnovskiy All Rights Reserved
+Copyright (c) 2002-2005 Calvin Che
+
+This program is free software; you can redistribute it and/or
+modify it under the terms of the GNU General Public License
+as published by the Free Software Foundation; version 2
+of the License.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+
+/*
+This file contain the source that is related to display contact
+information, including the one shows in user detail and the brief
+information
+*/
+
+#include "stdafx.h"
+
+//============ BRIEF INFORMATION ============
+//
+static int BriefDlgResizer(HWND, LPARAM, UTILRESIZECONTROL *urc)
+{
+ switch (urc->wId) {
+ case IDC_HEADERBAR:
+ return RD_ANCHORX_LEFT | RD_ANCHORY_TOP | RD_ANCHORX_WIDTH;
+
+ case IDC_MTEXT:
+ case IDC_DATALIST:
+ return RD_ANCHORX_LEFT | RD_ANCHORY_TOP | RD_ANCHORX_WIDTH | RD_ANCHORY_HEIGHT;
+
+ case IDC_MUPDATE:
+ return RD_ANCHORX_LEFT | RD_ANCHORY_BOTTOM;
+
+ case IDC_MTOGGLE:
+ case IDC_MWEBPAGE:
+ case IDCANCEL:
+ return RD_ANCHORX_RIGHT | RD_ANCHORY_BOTTOM;
+ }
+ return RD_ANCHORX_LEFT | RD_ANCHORY_TOP;
+}
+
+// set the title of the dialog and on the which rectangle
+// also load brief info into message box
+static void LoadBriefInfoText(HWND hwndDlg, MCONTACT hContact)
+{
+ WEATHERINFO winfo;
+ wchar_t str[4096];
+
+ // load weather information from the contact into the WEATHERINFO struct
+ winfo = LoadWeatherInfo(hContact);
+ // check if data exist. If not, display error message box
+ if (!g_plugin.getByte(hContact, "IsUpdated"))
+ wcsncpy(str, WEATHER_NO_INFO, _countof(str) - 1);
+ else
+ // set the display text and show the message box
+ GetDisplay(&winfo, opt.bText, str);
+ SetDlgItemText(hwndDlg, IDC_MTEXT, str);
+
+ GetDisplay(&winfo, L"%c, %t", str);
+ SetWindowText(hwndDlg, winfo.city);
+ SetDlgItemText(hwndDlg, IDC_HEADERBAR, str);
+}
+
+// dialog process for more data in the user info window
+// lParam = contact handle
+static INT_PTR CALLBACK DlgProcMoreData(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam)
+{
+ static const unsigned tabstops = 48;
+ MCONTACT hContact = (MCONTACT)GetWindowLongPtr(hwndDlg, GWLP_USERDATA);
+
+ switch (msg) {
+ case WM_INITDIALOG:
+ // save the contact handle for later use
+ hContact = lParam;
+ SetWindowLongPtr(hwndDlg, GWLP_USERDATA, (LONG_PTR)hContact);
+
+ SendDlgItemMessage(hwndDlg, IDC_MTEXT, EM_AUTOURLDETECT, (WPARAM)TRUE, 0);
+ SendDlgItemMessage(hwndDlg, IDC_MTEXT, EM_SETEVENTMASK, 0, ENM_LINK);
+ SendDlgItemMessage(hwndDlg, IDC_MTEXT, EM_SETMARGINS, EC_LEFTMARGIN, 5);
+ SendDlgItemMessage(hwndDlg, IDC_MTEXT, EM_SETTABSTOPS, 1, (LPARAM)&tabstops);
+
+ // get the list to display
+ {
+ LV_COLUMN lvc = { 0 };
+ HWND hList = GetDlgItem(hwndDlg, IDC_DATALIST);
+ RECT aRect = { 0 };
+ GetClientRect(hList, &aRect);
+
+ // managing styles
+ lvc.mask = LVCF_WIDTH | LVCF_TEXT;
+ ListView_SetExtendedListViewStyleEx(hList,
+ LVS_EX_FULLROWSELECT | LVS_EX_INFOTIP,
+ LVS_EX_FULLROWSELECT | LVS_EX_INFOTIP);
+
+ // inserting columns
+ lvc.cx = LIST_COLUMN;
+ lvc.pszText = TranslateT("Variable");
+ ListView_InsertColumn(hList, 0, &lvc);
+
+ lvc.cx = aRect.right - LIST_COLUMN - GetSystemMetrics(SM_CXVSCROLL) - 3;
+ lvc.pszText = TranslateT("Information");
+ ListView_InsertColumn(hList, 1, &lvc);
+
+ // inserting data
+ SendMessage(hwndDlg, WM_UPDATEDATA, 0, 0);
+ }
+ TranslateDialogDefault(hwndDlg);
+
+ // prevent dups of the window
+ WindowList_Add(hDataWindowList, hwndDlg, hContact);
+
+ // restore window position
+ Utils_RestoreWindowPositionNoMove(hwndDlg, NULL, MODULENAME, "BriefInfo_");
+ return TRUE;
+
+ case WM_UPDATEDATA:
+ ListView_DeleteAllItems(GetDlgItem(hwndDlg, IDC_DATALIST));
+ LoadBriefInfoText(hwndDlg, hContact);
+ DBDataManage(hContact, WDBM_DETAILDISPLAY, (WPARAM)hwndDlg, 0);
+
+ // set icons
+ Window_FreeIcon_IcoLib(hwndDlg);
+ Window_SetProtoIcon_IcoLib(hwndDlg, MODULENAME, g_plugin.getWord(hContact, "StatusIcon", 0));
+
+ RedrawWindow(GetDlgItem(hwndDlg, IDC_HEADERBAR), nullptr, nullptr, RDW_INVALIDATE | RDW_UPDATENOW);
+ break;
+
+ case WM_SIZE:
+ {
+ RECT rc;
+ HWND hList = GetDlgItem(hwndDlg, IDC_DATALIST);
+ GetWindowRect(hList, &rc);
+ ListView_SetColumnWidth(hList, 1, ListView_GetColumnWidth(hList, 1) + (int)LOWORD(lParam) - (rc.right - rc.left));
+
+ Utils_ResizeDialog(hwndDlg, g_plugin.getInst(), MAKEINTRESOURCEA(IDD_BRIEF), BriefDlgResizer);
+ }
+ break;
+
+ case WM_GETMINMAXINFO:
+ {
+ LPMINMAXINFO mmi = (LPMINMAXINFO)lParam;
+
+ // The minimum width in points
+ mmi->ptMinTrackSize.x = 350;
+ // The minimum height in points
+ mmi->ptMinTrackSize.y = 300;
+ }
+ break;
+
+ case WM_COMMAND:
+ switch (LOWORD(wParam)) {
+ case IDCANCEL:
+ // close the info window
+ DestroyWindow(hwndDlg);
+ break;
+
+ case IDC_MUPDATE:
+ {
+ HWND hList = GetDlgItem(hwndDlg, IDC_DATALIST);
+
+ // update current data
+ // set the text to "updating"
+ SetDlgItemText(hwndDlg, IDC_MTEXT, TranslateT("Retrieving new data, please wait..."));
+ ListView_DeleteAllItems(hList);
+
+ LV_ITEM lvi = { 0 };
+ lvi.mask = LVIF_TEXT | LVIF_PARAM;
+ lvi.lParam = 1;
+ lvi.pszText = L"";
+ lvi.iItem = ListView_InsertItem(hList, &lvi);
+ lvi.pszText = TranslateT("Retrieving new data, please wait...");
+ ListView_SetItemText(hList, lvi.iItem, 1, lvi.pszText);
+ UpdateSingleStation(hContact, 0);
+ break;
+ }
+
+ case IDC_MWEBPAGE:
+ LoadForecast(hContact, 0); // read complete forecast
+ break;
+
+ case IDC_MTOGGLE:
+ if (IsWindowVisible(GetDlgItem(hwndDlg, IDC_DATALIST)))
+ SetDlgItemText(hwndDlg, IDC_MTOGGLE, TranslateT("More Info"));
+ else
+ SetDlgItemText(hwndDlg, IDC_MTOGGLE, TranslateT("Brief Info"));
+ ShowWindow(GetDlgItem(hwndDlg, IDC_DATALIST), (int)!IsWindowVisible(
+ GetDlgItem(hwndDlg, IDC_DATALIST)));
+ ShowWindow(GetDlgItem(hwndDlg, IDC_MTEXT), (int)!IsWindowVisible(GetDlgItem(hwndDlg, IDC_MTEXT)));
+ break;
+ }
+ break;
+
+ case WM_NOTIFY:
+ {
+ LPNMHDR pNmhdr = (LPNMHDR)lParam;
+ if (pNmhdr->idFrom == IDC_MTEXT && pNmhdr->code == EN_LINK) {
+ ENLINK *enlink = (ENLINK *)lParam;
+ switch (enlink->msg) {
+ case WM_LBUTTONUP:
+ TEXTRANGE tr;
+ tr.chrg = enlink->chrg;
+ tr.lpstrText = (wchar_t*)mir_alloc(sizeof(wchar_t)*(tr.chrg.cpMax - tr.chrg.cpMin + 8));
+ SendMessage(pNmhdr->hwndFrom, EM_GETTEXTRANGE, 0, (LPARAM)&tr);
+ Utils_OpenUrlW(tr.lpstrText);
+ mir_free(tr.lpstrText);
+ break;
+ }
+ }
+ }
+ break;
+
+ case WM_CLOSE:
+ DestroyWindow(hwndDlg);
+ break;
+
+ case WM_DESTROY:
+ Window_FreeIcon_IcoLib(hwndDlg);
+ Utils_SaveWindowPosition(hwndDlg, NULL, MODULENAME, "BriefInfo_");
+ WindowList_Remove(hDataWindowList, hwndDlg);
+ break;
+ }
+
+ return FALSE;
+}
+
+// dialog process for the weather tab under user info
+// lParam = current contact
+static INT_PTR CALLBACK DlgProcUIPage(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam)
+{
+ WEATHERINFO w;
+ wchar_t str[MAX_TEXT_SIZE];
+
+ MCONTACT hContact = (MCONTACT)GetWindowLongPtr(hwndDlg, GWLP_USERDATA);
+ switch (msg) {
+ case WM_INITDIALOG:
+ TranslateDialogDefault(hwndDlg);
+ SendDlgItemMessage(hwndDlg, IDC_MOREDETAIL, BUTTONSETASFLATBTN, TRUE, 0);
+ // save the contact handle for later use
+ hContact = lParam;
+ SetWindowLongPtr(hwndDlg, GWLP_USERDATA, (LONG_PTR)hContact);
+ // load weather info for the contact
+ w = LoadWeatherInfo(lParam);
+ SetDlgItemText(hwndDlg, IDC_INFO1, GetDisplay(&w, TranslateT("Current condition for %n"), str));
+
+ SendDlgItemMessage(hwndDlg, IDC_INFOICON, STM_SETICON, (WPARAM)Skin_LoadProtoIcon(MODULENAME, g_plugin.getWord(hContact, "StatusIcon")), 0);
+ {
+ // bold and enlarge the current condition
+ LOGFONT lf;
+ HFONT hNormalFont = (HFONT)SendDlgItemMessage(hwndDlg, IDC_INFO2, WM_GETFONT, 0, 0);
+ GetObject(hNormalFont, sizeof(lf), &lf);
+ lf.lfWeight = FW_BOLD;
+ lf.lfWidth = 7;
+ lf.lfHeight = 15;
+ SendDlgItemMessage(hwndDlg, IDC_INFO2, WM_SETFONT, (WPARAM)CreateFontIndirect(&lf), 0);
+ }
+ // set the text for displaying other current weather conditions data
+ GetDisplay(&w, L"%c %t", str);
+ SetDlgItemText(hwndDlg, IDC_INFO2, str);
+ SetDlgItemText(hwndDlg, IDC_INFO3, w.feel);
+ SetDlgItemText(hwndDlg, IDC_INFO4, w.pressure);
+ GetDisplay(&w, L"%i %w", str);
+ SetDlgItemText(hwndDlg, IDC_INFO5, str);
+ SetDlgItemText(hwndDlg, IDC_INFO6, w.dewpoint);
+ SetDlgItemText(hwndDlg, IDC_INFO7, w.sunrise);
+ SetDlgItemText(hwndDlg, IDC_INFO8, w.sunset);
+ SetDlgItemText(hwndDlg, IDC_INFO9, w.high);
+ SetDlgItemText(hwndDlg, IDC_INFO10, w.low);
+ GetDisplay(&w, TranslateT("Last update on: %u"), str);
+ SetDlgItemText(hwndDlg, IDC_INFO11, str);
+ SetDlgItemText(hwndDlg, IDC_INFO12, w.humid);
+ SetDlgItemText(hwndDlg, IDC_INFO13, w.vis);
+ break;
+
+ case WM_DESTROY:
+ IcoLib_ReleaseIcon((HICON)SendDlgItemMessage(hwndDlg, IDC_INFOICON, STM_SETICON, 0, 0));
+ DeleteObject((HFONT)SendDlgItemMessage(hwndDlg, IDC_INFO2, WM_GETFONT, 0, 0));
+ break;
+
+ case WM_COMMAND:
+ switch (LOWORD(wParam)) {
+ case IDC_MOREDETAIL:
+ HWND hMoreDataDlg = WindowList_Find(hDataWindowList, hContact);
+ if (hMoreDataDlg == nullptr)
+ hMoreDataDlg = CreateDialogParam(g_plugin.getInst(), MAKEINTRESOURCE(IDD_BRIEF), nullptr, DlgProcMoreData, hContact);
+ else {
+ SetForegroundWindow(hMoreDataDlg);
+ SetFocus(hMoreDataDlg);
+ }
+ ShowWindow(GetDlgItem(hMoreDataDlg, IDC_MTEXT), 0);
+ ShowWindow(GetDlgItem(hMoreDataDlg, IDC_DATALIST), 1);
+ }
+ break;
+ }
+ return 0;
+}
+
+//============ CONTACT INFORMATION ============
+//
+// initialize user info
+// lParam = current contact
+int UserInfoInit(WPARAM wParam, LPARAM hContact)
+{
+ OPTIONSDIALOGPAGE odp = {};
+ odp.position = 100000000;
+ odp.szTitle.a = MODULENAME;
+
+ if (hContact == 0) {
+ odp.pszTemplate = MAKEINTRESOURCEA(IDD_INFO);
+ odp.pfnDlgProc = DlgProcINIPage;
+ g_plugin.addUserInfo(wParam, &odp);
+ }
+ else if (IsMyContact(hContact)) { // check if it is a weather contact
+ // register the contact info page
+ odp.pszTemplate = MAKEINTRESOURCEA(IDD_USERINFO);
+ odp.pfnDlgProc = DlgProcUIPage;
+ odp.flags = ODPF_BOLDGROUPS;
+ g_plugin.addUserInfo(wParam, &odp);
+ }
+ return 0;
+}
+
+
+// show brief information dialog
+// wParam = current contact
+int BriefInfo(WPARAM wParam, LPARAM)
+{
+ // make sure that the contact is actually a weather one
+ if (IsMyContact(wParam)) {
+ HWND hMoreDataDlg = WindowList_Find(hDataWindowList, wParam);
+ if (hMoreDataDlg != nullptr) {
+ SetForegroundWindow(hMoreDataDlg);
+ SetFocus(hMoreDataDlg);
+ }
+ else hMoreDataDlg = CreateDialogParam(g_plugin.getInst(), MAKEINTRESOURCE(IDD_BRIEF), nullptr, DlgProcMoreData, (LPARAM)wParam);
+
+ ShowWindow(GetDlgItem(hMoreDataDlg, IDC_DATALIST), 0);
+ ShowWindow(GetDlgItem(hMoreDataDlg, IDC_MTEXT), 1);
+ SetDlgItemText(hMoreDataDlg, IDC_MTOGGLE, TranslateT("More Info"));
+ return 1;
+ }
+ return 0;
+}
+
+INT_PTR BriefInfoSvc(WPARAM wParam, LPARAM lParam)
+{
+ return BriefInfo(wParam, lParam);
+}
diff --git a/protocols/Weather/weather.vcxproj b/protocols/Weather/weather.vcxproj
new file mode 100644
index 0000000000..7624e51a7f
--- /dev/null
+++ b/protocols/Weather/weather.vcxproj
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <ItemGroup Label="ProjectConfigurations">
+ <ProjectConfiguration Include="Debug|Win32">
+ <Configuration>Debug</Configuration>
+ <Platform>Win32</Platform>
+ </ProjectConfiguration>
+ <ProjectConfiguration Include="Debug|x64">
+ <Configuration>Debug</Configuration>
+ <Platform>x64</Platform>
+ </ProjectConfiguration>
+ <ProjectConfiguration Include="Release|Win32">
+ <Configuration>Release</Configuration>
+ <Platform>Win32</Platform>
+ </ProjectConfiguration>
+ <ProjectConfiguration Include="Release|x64">
+ <Configuration>Release</Configuration>
+ <Platform>x64</Platform>
+ </ProjectConfiguration>
+ </ItemGroup>
+ <PropertyGroup Label="Globals">
+ <ProjectName>Weather</ProjectName>
+ <ProjectGuid>{6BFE3E13-BD5D-4C1C-BB29-A82FB51A16CE}</ProjectGuid>
+ </PropertyGroup>
+ <ImportGroup Label="PropertySheets">
+ <Import Project="$(ProjectDir)..\..\build\vc.common\plugin.props" />
+ </ImportGroup>
+</Project> \ No newline at end of file
diff --git a/protocols/Weather/weather.vcxproj.filters b/protocols/Weather/weather.vcxproj.filters
new file mode 100644
index 0000000000..fcae13a9d8
--- /dev/null
+++ b/protocols/Weather/weather.vcxproj.filters
@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <Import Project="$(ProjectDir)..\..\build\vc.common\common.filters" />
+</Project> \ No newline at end of file
diff --git a/protocols/WebView/docs/changelog.txt b/protocols/WebView/docs/changelog.txt
new file mode 100644
index 0000000000..17987cc60e
--- /dev/null
+++ b/protocols/WebView/docs/changelog.txt
@@ -0,0 +1,6 @@
+-0.1.3.10
+-Made separate Unicode and ANSI versions of plugin.
+-Removed some old unneeded code.
+
+
+ \ No newline at end of file
diff --git a/protocols/WebView/docs/license.txt b/protocols/WebView/docs/license.txt
new file mode 100644
index 0000000000..f3790d8623
--- /dev/null
+++ b/protocols/WebView/docs/license.txt
@@ -0,0 +1,340 @@
+ GNU GENERAL PUBLIC LICENSE
+ Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.
+ 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+ Preamble
+
+ The licenses for most software are designed to take away your
+freedom to share and change it. By contrast, the GNU General Public
+License is intended to guarantee your freedom to share and change free
+software--to make sure the software is free for all its users. This
+General Public License applies to most of the Free Software
+Foundation's software and to any other program whose authors commit to
+using it. (Some other Free Software Foundation software is covered by
+the GNU Library General Public License instead.) You can apply it to
+your programs, too.
+
+ When we speak of free software, we are referring to freedom, not
+price. Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+ To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if you
+distribute copies of the software, or if you modify it.
+
+ For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must give the recipients all the rights that
+you have. You must make sure that they, too, receive or can get the
+source code. And you must show them these terms so they know their
+rights.
+
+ We protect your rights with two steps: (1) copyright the software, and
+(2) offer you this license which gives you legal permission to copy,
+distribute and/or modify the software.
+
+ Also, for each author's protection and ours, we want to make certain
+that everyone understands that there is no warranty for this free
+software. If the software is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original, so
+that any problems introduced by others will not reflect on the original
+authors' reputations.
+
+ Finally, any free program is threatened constantly by software
+patents. We wish to avoid the danger that redistributors of a free
+program will individually obtain patent licenses, in effect making the
+program proprietary. To prevent this, we have made it clear that any
+patent must be licensed for everyone's free use or not licensed at all.
+
+ The precise terms and conditions for copying, distribution and
+modification follow.
+
+ GNU GENERAL PUBLIC LICENSE
+ TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+ 0. This License applies to any program or other work which contains
+a notice placed by the copyright holder saying it may be distributed
+under the terms of this General Public License. The "Program", below,
+refers to any such program or work, and a "work based on the Program"
+means either the Program or any derivative work under copyright law:
+that is to say, a work containing the Program or a portion of it,
+either verbatim or with modifications and/or translated into another
+language. (Hereinafter, translation is included without limitation in
+the term "modification".) Each licensee is addressed as "you".
+
+Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope. The act of
+running the Program is not restricted, and the output from the Program
+is covered only if its contents constitute a work based on the
+Program (independent of having been made by running the Program).
+Whether that is true depends on what the Program does.
+
+ 1. You may copy and distribute verbatim copies of the Program's
+source code as you receive it, in any medium, provided that you
+conspicuously and appropriately publish on each copy an appropriate
+copyright notice and disclaimer of warranty; keep intact all the
+notices that refer to this License and to the absence of any warranty;
+and give any other recipients of the Program a copy of this License
+along with the Program.
+
+You may charge a fee for the physical act of transferring a copy, and
+you may at your option offer warranty protection in exchange for a fee.
+
+ 2. You may modify your copy or copies of the Program or any portion
+of it, thus forming a work based on the Program, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+ a) You must cause the modified files to carry prominent notices
+ stating that you changed the files and the date of any change.
+
+ b) You must cause any work that you distribute or publish, that in
+ whole or in part contains or is derived from the Program or any
+ part thereof, to be licensed as a whole at no charge to all third
+ parties under the terms of this License.
+
+ c) If the modified program normally reads commands interactively
+ when run, you must cause it, when started running for such
+ interactive use in the most ordinary way, to print or display an
+ announcement including an appropriate copyright notice and a
+ notice that there is no warranty (or else, saying that you provide
+ a warranty) and that users may redistribute the program under
+ these conditions, and telling the user how to view a copy of this
+ License. (Exception: if the Program itself is interactive but
+ does not normally print such an announcement, your work based on
+ the Program is not required to print an announcement.)
+
+These requirements apply to the modified work as a whole. If
+identifiable sections of that work are not derived from the Program,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works. But when you
+distribute the same sections as part of a whole which is a work based
+on the Program, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Program.
+
+In addition, mere aggregation of another work not based on the Program
+with the Program (or with a work based on the Program) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+ 3. You may copy and distribute the Program (or a work based on it,
+under Section 2) in object code or executable form under the terms of
+Sections 1 and 2 above provided that you also do one of the following:
+
+ a) Accompany it with the complete corresponding machine-readable
+ source code, which must be distributed under the terms of Sections
+ 1 and 2 above on a medium customarily used for software interchange; or,
+
+ b) Accompany it with a written offer, valid for at least three
+ years, to give any third party, for a charge no more than your
+ cost of physically performing source distribution, a complete
+ machine-readable copy of the corresponding source code, to be
+ distributed under the terms of Sections 1 and 2 above on a medium
+ customarily used for software interchange; or,
+
+ c) Accompany it with the information you received as to the offer
+ to distribute corresponding source code. (This alternative is
+ allowed only for noncommercial distribution and only if you
+ received the program in object code or executable form with such
+ an offer, in accord with Subsection b above.)
+
+The source code for a work means the preferred form of the work for
+making modifications to it. For an executable work, complete source
+code means all the source code for all modules it contains, plus any
+associated interface definition files, plus the scripts used to
+control compilation and installation of the executable. However, as a
+special exception, the source code distributed need not include
+anything that is normally distributed (in either source or binary
+form) with the major components (compiler, kernel, and so on) of the
+operating system on which the executable runs, unless that component
+itself accompanies the executable.
+
+If distribution of executable or object code is made by offering
+access to copy from a designated place, then offering equivalent
+access to copy the source code from the same place counts as
+distribution of the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+ 4. You may not copy, modify, sublicense, or distribute the Program
+except as expressly provided under this License. Any attempt
+otherwise to copy, modify, sublicense or distribute the Program is
+void, and will automatically terminate your rights under this License.
+However, parties who have received copies, or rights, from you under
+this License will not have their licenses terminated so long as such
+parties remain in full compliance.
+
+ 5. You are not required to accept this License, since you have not
+signed it. However, nothing else grants you permission to modify or
+distribute the Program or its derivative works. These actions are
+prohibited by law if you do not accept this License. Therefore, by
+modifying or distributing the Program (or any work based on the
+Program), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Program or works based on it.
+
+ 6. Each time you redistribute the Program (or any work based on the
+Program), the recipient automatically receives a license from the
+original licensor to copy, distribute or modify the Program subject to
+these terms and conditions. You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+
+ 7. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License. If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Program at all. For example, if a patent
+license would not permit royalty-free redistribution of the Program by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Program.
+
+If any portion of this section is held invalid or unenforceable under
+any particular circumstance, the balance of the section is intended to
+apply and the section as a whole is intended to apply in other
+circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system, which is
+implemented by public license practices. Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+ 8. If the distribution and/or use of the Program is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Program under this License
+may add an explicit geographical distribution limitation excluding
+those countries, so that distribution is permitted only in or among
+countries not thus excluded. In such case, this License incorporates
+the limitation as if written in the body of this License.
+
+ 9. The Free Software Foundation may publish revised and/or new versions
+of the General Public License from time to time. Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+Each version is given a distinguishing version number. If the Program
+specifies a version number of this License which applies to it and "any
+later version", you have the option of following the terms and conditions
+either of that version or of any later version published by the Free
+Software Foundation. If the Program does not specify a version number of
+this License, you may choose any version ever published by the Free Software
+Foundation.
+
+ 10. If you wish to incorporate parts of the Program into other free
+programs whose distribution conditions are different, write to the author
+to ask for permission. For software which is copyrighted by the Free
+Software Foundation, write to the Free Software Foundation; we sometimes
+make exceptions for this. Our decision will be guided by the two goals
+of preserving the free status of all derivatives of our free software and
+of promoting the sharing and reuse of software generally.
+
+ NO WARRANTY
+
+ 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
+PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
+REPAIR OR CORRECTION.
+
+ 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGES.
+
+ END OF TERMS AND CONDITIONS
+
+ How to Apply These Terms to Your New Programs
+
+ If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+ To do so, attach the following notices to the program. It is safest
+to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+ <one line to give the program's name and a brief idea of what it does.>
+ Copyright (C) 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/WebView/docs/readme.txt b/protocols/WebView/docs/readme.txt
new file mode 100644
index 0000000000..59c5809488
--- /dev/null
+++ b/protocols/WebView/docs/readme.txt
@@ -0,0 +1,1000 @@
+***************************************
+* Webview Protocol Plugin by Bumper1 *
+***************************************
+
+
+
+About
+-----
+
+A plugin for Miranda IM which adds web pages as contacts to your contact list and can
+display text and/or changes within those pages in a window, as well as issue different types of
+alerts when changes occur.
+
+You need special status icons for this protocol, these icons are available here:
+http://www.miranda-im.org/download/details.php?action=viewfile&id=1274
+-------
+WARNING
+----------
+
+On a large site (approx ~50kbytes) with "clean up display" option enabled the processor
+may approach 100% until the tags are removed and text formatting is complete.
+To minimise this only select a section of the web page to be displayed (the larger
+the selection the longer it will take to remove the tags and format the text).
+
+
+Installation:
+
+Copy the dll file to your plugins folder like any other plugin, but if you want the ping fuction to work, copy psite.bat to the same folder as miranda32.exe
+
+Features
+--------
+Creates contacts on your Contact list representing web pages. A dialog displaying
+the text on that web page can be accessed through the contact menu of the contact
+that represents that web page.
+
+You can add more sites to the contact list using the Webview -> Add Contact
+item on the Main menu.
+You can update your Webview contacts all at once using the Webview -> Update All Webview
+Sites item on the Main menu.
+You can enable/disable timed updates of your contacts using the Webview -> Auto Update
+Enabled item on the Main menu.
+
+If you have the main menu items disabled and you have the TopToolbar plugin loaded Webview
+will load three buttons on the toolbar for Adding contacts, updating all Webview site and
+for enabling auto update.
+
+
+There are various options which you can set from each individual site/Webview contact on your
+contact list; you can set the name of the contact, the site URL, start string, end string, logging
+options, clean up of the display (removal of excess whitespace, tags and conversion of HTML
+character codes to displayable characters), and the action to take when double clicking on a
+contact (either open that site in a browser window or display site in the Webview data display
+window). You can adjust all these settings from the Contact Options item on each contact menu.
+The amount of white space removed can be set by the user for each contact.
+
+There is also an option to "Display whole web page"; if you use this option then it will
+display the whole web page in the data display window.
+If you use the option "Display between Start and End strings then you need to use
+unique strings on the web page to set the part of the page you want to display.
+
+The clean up display option stops tags being displayed in the data window.
+It also removes extra white space to help tidy up the display. The amount
+of white space removed can be set from options.
+
+You can also set various alerts on a contact by contact basis. You can set an alert to be
+issued if a certain string is present, if anything on the whole web page (or in the displayed
+portion of the web page) changes or you can have an alert issued only of a specific
+part of the web page changes.
+
+You can also set the method by which you want to be alerted on a contact by contact basis.
+You can set the alert to issue a popup using the PopUp plugin, open the data display
+window, display the alert using the OSD plugin or log to file.
+
+
+
+You can set the update interval, suppression of error messages, disabling of the main menu item
+(hiding main menu item requires a reboot for changes to be seen), whether to update data on
+Miranda startup, hiding/showing of the protocol icon on the status bar, updating data for a specfic
+site when its data display window is opened and text/background color all from the main
+Miranda Webview options. You can also set the text attributes.
+You can set an option to save the position of individual data display windows.
+
+You can set the error messages to be displayed using the PopUp
+plugin (or the OSD plugin if the Popup service isn't available).
+If you don't select errors to be displayed with the Popup plugin (or the OSD plugin), or neither
+the Popup or OSD plugins are loaded then the error is displayed using a balloon tip (if the OS
+supports it).
+
+When plugin is first installed the window updates once an hour.
+The timer can be set in options, setting timer to 0 disables updates
+( plugin will still do one update on start up even if timer=0).
+
+The "Update Data" button on the data window will re-download date from the specific website
+that data window uses.
+The "Stick to the front" button on the data window will allow or stop the display window
+staying on top of other windows.
+The "Find" button on the data window will allow you to find a word or phrase in the data
+window.
+
+You can copy, cut and delete text from the data display window as well
+as copy all, select all and clear all text by a drop down menu
+when you click with your right mouse key on the edit area of the data
+display window.
+
+The web page being available, down or lagging, server error returned or alert issued will all
+change the status icon on the contact list for the specific contact that even happened to.
+Online, offline, error and alert all have their own icon which can be set in Miranda's Icon
+options.
+
+N/A status icon means the site is offline or lagging.
+Away status icon means the server returned an error.
+Online status icon means site is working normally.
+Offline status icon means the protocol has been manually put offline.
+Occupied status icon means an alert has been issued for that site.
+DND status icon means plugin is downloading or processing data for that site.
+
+You can set the sound to be used when there is an alert in the Sounds section of Miranda
+Options.
+
+In PopUp options you can set the popup time out, various options for selecting the color of the
+popup and select left and right click options.
+
+You can view the complete source code for a web page if you set the Contact Options
+to display the whole web page, untick Clean Up Display then update (download)
+the data for that Webview contact.
+
+
+*****
+Here follow the essential settings you need to have
+right to get a result.
+*****
+
+There is an option in the contact options to put in the URL of the
+website you wish to display contents of.
+Note: Netlib doesn't support redirection, make sure you dont use
+plugin to monitor a site that does this because it will not work.
+
+There are two search string options which are used to find data on the
+web page. The first is the Start string, this is a string or sequences of tags and words in the source
+code of the web page where you wish to begin displaying data on your data window.
+The second is the End string, this is a string or sequences of tags and words in the source code of
+the web page where you wish to stop displaying data on your data window.
+Note: To find these display strings you should know how to look at the source code of
+the web page you are looking at. If you don't wish to use a browser to go find out what the
+source code looks the you can use the search strings like this:
+Start:<html
+End:</html>
+
+or
+Start:<HTML
+End:</HTML>
+
+If you do not want to have to use start and end strings you can select the option
+to display the whole site then the plugin will display the contents of the entire
+web page.
+
+There is a button to the Contact Options dialog to copy the display
+Start and End strings to the alert Start and End strings and set
+the event type to "Alert When A Specific Part of Web Page Changes".
+*****
+
+
+Requirements
+------------
+ - Miranda IM 0.7++
+(Popup plugin recommended
+ but not essential)
+
+Popup plugin is used for displaying error messages, but OSD plugin can also be used.
+
+
+To Do
+--------
+-Unicode support!!!
+-need to review the plugin documentation and see what needs to be added or removed from it.
+-window option to load cache into window and have it processed?
+-create webview group on contactlist and automatically add sites to it?
+-menu item to close all webview windows?
+
+
+
+Changelog
+----------
+0.0.1.0
+-Use SETI@Home 1.3.0.0 sources as
+ base code for Webview
+-Change icons
+-rename and remove various options
+ and DBKeys
+-Lets set some HTML headers to keep
+ some sites happy
+-Successfully displayed selected data from
+ a site using search strings
+0.0.2.0
+-Removed some old data window functions
+-Prevent users using an end string, thats present
+ in the data BEFORE the search string.
+-Created a dialog for displaying data,
+ discontinue using MessageBox()
+-Don't open another dialog if one is
+ already open
+-Update dialog automatically after download
+-Clear data in dialog only if new data exists
+-Display complete page if no search strings
+ set or if not present
+-Added back "stick to front" and "hide/show" features
+ to code.
+-Treat a destroyed window the same as a hidden
+ one in options and menus
+-Added back right-click menu and automove
+ to code(automove a little buggy)
+-Add hyperlink to dialog
+-Use dllname in titlebar
+-Add resize code
+-Added Multiwindow code(buggy)
+0.0.3.0
+-Back out displaying complete page if no search strings
+ set or if not present (results unpredictable)
+-Update hyperlink when changed in options
+-Back out code to allow automove to be used if
+ dragged with titlebar.Caused plugin to consume
+ all system resources when first minimized then attempted
+ to restore/maximise/close.
+-Make sure correct url value present before
+ opening it using the hyperlink
+-Removed option and key for disabling automove,
+ user can just drag with the titlebar
+-Removed all options and keys related to
+ saving to file, not really needed,
+ data can be copied and pasted from
+ data window.
+-Removed option for clearing old data.
+ Code now does this automatically if
+ needed
+-Removed common dialog library
+-#include <richedit.h>
+0.0.4.0
+-Got rid of the old data structures
+-Positioned the close button a little better
+-Check to see that Miranda version is at least
+ 0.3.2.0 before loading plugin
+-Added richedit control to dialog
+-Hotkeys working again
+-Backout Multiwindow code, much too buggy
+-Intermittant crash on startup.Cause seems
+ to be that popup service isn't threadsafe.
+ Don't call from thread, use a timer to call
+ an error function that will check for presence
+ of errors
+-Unregister then reset hotkeys after dialog is
+ created
+-Got rid of some old unused variables
+-rebase to 0x2d900000
+-Use modeless dialog instead of
+ MessageBox()
+-Make sure there isn't more than one error
+ dialog with same message created (assuming
+ user closes all the error messages)
+0.0.5.0
+-If the update interval is set to zero
+ don't activate the error reporting timer on
+ startup
+-Only do update on startup if interval is not
+ zero
+-If the update interval is changed to a value
+ other than zero then restart the error reporting
+ timer
+-Added advanced options to control displaying text
+ before or after the search strings
+-Got change background color option working
+-Error check is now run one minute after update
+-Added a button in advanced options to check
+ for errors
+-Make data dialog read only
+-Error timer not restarting with correct interval
+-Moved Load() to main.c
+-Added support for PluginUninstaller
+-Renamed license and readme to make
+ easier to uninstall
+-Got "use windows colors" option
+ working
+0.0.6.0
+-Replaced the right click menu with a button
+ on the data display window
+-Use main plugin icon for button
+-Improved code for setting background
+ color
+-Got text color working
+-Change memory usage depending
+ on data download size
+-Write downloaded data to the
+ database(maybe just a temporary
+ measure)
+-Clear display before write new data
+ to dialog
+-Don't allocate/free memory or use
+ download arrays if download unsuccessful
+-URL not showing on dialog after reboot
+-Initialise dialog with web data stored in
+ database
+-Cleaned up an icon
+-Removed writing data to database
+-Only free memory when new data available
+ and in Unload() so all functions can
+ access data
+0.0.7.0
+-Wrote basic data save to file function
+-Readded common dialog library and restored
+ the saving functions to similar level to
+ that in SETI@Home plugin
+-Changed the advanced search options a little
+ to avoid confusion.
+-got basic tag erasing code in place
+-Fixed crash in tag erasing code
+-Got tag with attributes erasing working
+-Support filtering both upper and lower
+ case tags
+-Remove excess whitespace
+-Improvments to background color code
+-small changes to text coloring code
+-Got rid of "Use windows colors" option
+-Put in an option to enable filtering
+ of tags and whitespace
+-Fixed crash while removing whitespace
+ if search strings were not found/set
+-Choice to enable using popup plugin or not
+ even if popup service exists
+-Fixed some error dialog bugs
+-Fixed automove, now works better
+ with titlebar, removed the easy move
+ feature for now
+-Don't save win size, position etc. when
+ window max'ed or min'ed, also don't
+ automove()
+-Save width of window
+-Fixed bug where the saved window size/position
+ wasn't being used
+-Save new window size/position after resizing
+-Holding down ctrl key while moving
+ data dialog disables automove
+-Load old NETLIBHTTPREQUEST struct
+ if Miranda version less than 0.3.3
+-Remove some old unneeded variables
+0.0.8.0
+-Warning on startup if Miranda version less than
+ 0.3.2
+-Disable "Use Popup Plugin" option if popup
+ service isn't loaded
+-Other small changes to Advanced Options
+-Resistered the webview protocol and
+ added basic services
+-Allow return to be allowed in the richedit
+ control with out closing the dialog
+-Add maximise and minimise buttons to data
+ dialog
+-Got rid of horizontal scroll bar on data
+ dialog, the richedit control automatically
+ wordwraps
+-Added contact to clist, make it name itself to
+ the same as the dllname
+-Don't add contact to list if a contact already
+ exists
+-Changed the minutes setting to spin control
+0.0.9.0
+-Change main menu items dynamically
+-Changed options dialog to make visually
+ better.Removed some options, changed others
+-Use balloon tip for error messages
+-Removed "use popup plugin option".
+ Plugin now uses the following 3 methods for
+ displaying errors(in decreasing priority)
+ *Balloon tip(if OS supports)
+ *popup plugin(if service loaded)
+ *Error dialog(if the neither balloon tip
+ or popup can be used)
+-If server is down but previously gave back
+ a server error then make sure the server error
+ is cleared before reporting that the server is down.
+-Control contact status by global status and protocol
+ status
+-Don't download data if current protocol status
+ is offline
+-Change contact status depending on download
+ *Download success = online
+ *server offline = n/a
+ *server error = away
+-Added item to contact menu to show/hide
+ data dialog
+-Treat <a> same as other tags for now
+-first public alpha release
+0.0.10.0
+-Remove support for 0.3.2 NetLib
+-Don't load plugin if Miranda version
+ less than 0.3.3
+-Remove hbrush, not used anymore
+-Fixed intermittant crash when contact
+ already exists
+-minor changes to options
+-added items to contact for update,stick to
+ front and open web page.
+-New icons for show/hide window om menu menu.
+-Dynamically change contact menu item text
+ and icons
+-Some changes to drop down menu
+-URLs now open webpage when clicked
+-Added new Unstick icon
+-Removed advanced search options.Search
+ strings are now always included in displayed
+ data (prior to tag filtering)
+-Added Webview Group to clist to hold
+ contacts generated by multiple instances
+ of the plugin
+0.0.11.0
+-make spin control work in the correct direction
+-Moved options to Network group
+-Dynamtically change text on data dialog
+ menu items
+-Remove stick to front and update data Main menu
+ items
+-Stop sending Content-Length header to sites
+-Moved save to file options from advanced
+ options dialog to options dialog
+-Removed check for errors option
+-Made logging to file an advanced option
+-Added multiple monitor support
+-Destroy data window when ME_SYSTEM_PRESHUTDOWN
+ event occurs
+-reduce disk I/O by storing colors,
+ window height and window position
+ in global variables.Variables only
+ read/written to DB on start/exit.
+-added copy/copy all/select all menu to right click
+0.0.12.0
+-Added size grip to data dialog
+-Added separate stick/unstick button to data dialog
+-Removed stick/unstick item from drop down menu
+-Made buttons into flat buttons
+-Make WM_CLOSE hide the data window instead of
+ destroying it.
+-Removed Update and Stick/Unstick contact menu
+ items
+-Moved main menu item position to the same place
+ as other protocols
+-Removed advanced option dialog for now
+-Updates to README
+0.0.13.0
+-Double clicking on contact opens web page in browser
+-Added some comments to menu items. Some menu items
+ will be removed in a future release, and other new
+ items will be added(new items are disabled for now)
+-New icons for Add user and Contact options menu items
+ and new icon for drop down menu button on data window
+-Added some more tags to the filter
+-Change (Latin, Numeric and some punctuation) HTML
+ character codes into characters.
+-Change data window caption to the URL.
+-Change contact name to the URL.
+0.0.14.0
+-Added icon to data window titlebar
+-Filter out some more tags
+-Added update button to data window
+-Removed drop down menu button (no
+ need for anymore, all of the functions
+ of it can be accessed from the data window)
+-Added Clear All, Paste, Cut and Delete
+ to right click menu
+-Fixed a bug where double clicking on any
+ contact from any protocol opened up
+ a page in a browser.. opps
+0.0.15.0
+-Added tooltips to buttons
+-added more tags to filter
+-Added contact options dialog (disabled
+ for now)
+-Crash when tag filter sometimes tries to write
+ outside of the array (hopefully fixed).
+-Crash with some sites crash if free
+ szInfo after tags are filtered
+ out(hopefully fixed)
+-Crash (possibly related to the crashes above),
+ no idea what causes it really but fixed by
+ a delay midway in the tag filtering function
+0.0.16.0
+-Added some more tags to filter
+-Opps..was dependant on other plugins
+ to load richedit into memory
+-Removed options in Miranda options
+ for hiding and sticking window to the
+ front(no longer needed because soon
+ will be moving to contact based options)
+0.0.17.0
+-Enabled the contact optons dialog
+-Removed Url, start string and start string
+ options from plugin options to the contact
+ options dialog
+-Store url, start string and start string
+ in the contact settings not in the plugin
+ module in the database.
+-reduced some crash risks
+-Added option to enable updating data on
+ Miranda startup
+0.0.18.0
+-possible crash when freeing memory in unload,
+ free in pre-shutdown instead (possibly isn't
+ the solution)
+-Enable the add contact menu item.
+-Some other changes to usage of malloc
+ and free
+-Small delay added before downloading data
+ on startup, also reduced a delay else
+ where in the code
+-Added code to check multiple sites
+-Some more code to try and avoid crashes
+-Change individual contact status to indicate
+ site status
+-Remove hotkeys (possibly temporarily)
+-Move save to file options to contact options
+0.0.19.0
+-More stability improvements
+-Stick to front option working again
+-Disable file save options in add contact dialog
+-Code cleanup
+0.0.20.0
+-URL sometimes corrupted
+-Got background and text color change options
+ working
+-Removed feature where timer set to zero stopped you
+ downloading data manually
+-Clear all data windows when changing text/background
+ color (possibly a temporary measure)
+-More code cleanup
+0.0.21.0
+-User can choose either to open web page
+ in a browser or opening the data window
+ as the action taken when double clicking
+ on a webview contact
+-Option to update data when data window
+ opened
+-Removed old show/hide contact menu item
+ and replaced with a new open/close menu item
+ with a new icon
+-New add contact icon and show more icons
+ on dialogs
+-Better handling of protocol/global status
+-Other minor fixes
+-Added a new contact option to add
+ contact/site name.
+-When adding a new site,if you leave the site name
+ blank then the site name will automatically be
+ the same as the sites URL
+0.0.22.0
+-Make an option to hide icon on status bar
+-show the icon again if there is a crash
+-Make the titlebar text of the contacts
+ data window the same as the name of the
+ contact
+-only look for end string further down
+ the page from the start string
+-Remove garbage from end of displayed
+ text
+0.0.23.0
+-Got the options on the data display window
+ working properly again
+-Fixed a bug where double clicking on a webview
+ contact sometimes opened a message window.
+-Cleaned up code
+0.0.24.0
+-Allow user to set separate double click action
+ for each webview contact from the contact options.
+-Updated icons.
+-Faster (and more stable) method for copying web data
+ into memory used.
+-Use Save As dialog instead of Open
+ to select log file.
+-Added a search button to Webview data window.
+ Search is pretty basic as yet but it shows you
+ the approximate area of the window where the search
+ keyword was found.
+-Use monospaced font in data window because its easier
+ to read text in window. Also made font bigger for the same
+ reason.
+-Status messages displayed on status bar of data window.
+-Code to remove more unsupported symbol codes and other
+ unwanted data from the data window when the clean
+ up display option is selected.
+-Updates to the README.
+0.0.25.0
+-The Find button now can find and highlight the
+ exact position of the requested word in the
+ data window.
+-The Find button's text search is no longer case
+ sensitive.
+-Status bar on data display window now tells you
+ the time the last update of data occured from
+ that window.
+-You can now set the exact amount of whitespace
+ to filter out of the data window display through
+ a trackerbar control in Miranda options.
+-Font face and size as well as attributes bold, italic
+ and underline can now be set from Miranda options.
+-Some stability fixes and slightly better support for
+ large sites.
+-Added more panes to the status bar.
+-Status bar on data display window now tells you
+ the number of bytes of data displayed in that
+ window and the number of bytes downloaded.
+-Fixed a bug which caused some of the text not to
+ be formatted correctly with larger sites.
+-Some other minor changes.
+0.0.26.0
+-Removed some spaces left in the formatted text by the
+ character code to symbol function.
+-Compiled code with some optimisations.
+-Added options to Miranda options to select
+ the method of tag filtering; accurate, fast
+ or dynamic filtering.
+-Moved Display Clean-up options to the contact
+ options dialog so you can set different options
+ for each site.
+-Moved options back to Plugins group.
+-Some bug fixes for the Add Contact/Contact
+ options window.
+-Fixed bug where part of the code regarded
+ a error reply from the server as a download
+ success.
+-Status messages for "Server down or lagging",
+ "Server replied with an error code" and "Download
+ successful now about to process data" added to
+ status bar messages on the data display window.
+-Some more tags added to tag filter
+-More changes to the README.
+0.0.27.0
+-Make sure the first letter of the plugin name
+ in options is always uppercase.
+-Error messages now show for each individual site
+ using either balloon message on the system tray
+ icon or using popup plugin if available. The
+ popup messages are better and that option is
+ recommended.
+-New Contact Options button added to the data
+ display window which replaces the Options menu item
+ on the contact menu.
+-Some changes to code that removes the parts of the webpage
+ that are supposed to remain hidden.
+-There is only one method of filtering now; the fast
+ filter. All options for choosing filter method removed.
+-Added Alert button to data display window.
+-There are two alert methods used for now; popup
+ plugin and sound file. There is one alert event
+ for now; string present in downloaded data.
+-Small problem with plugin's response to global
+ status changes fixed.
+0.0.28.0
+-Added some more translatable strings.
+-Fixed some bugs in and added some improvements
+ to the Alert Options dialog.
+-Log to file was removed from Contact Options
+ and is now an Alert option.
+0.0.29.0
+-Made the plugin information in the plugin listing
+ more descriptive.
+-Fixed bug with hyperlink on data display window by
+ making control a button.
+-Added cancel and Apply buttons to Add Webview Site,
+ Contact Options and Alert Options windows.
+-If the user does not supply a name when creating
+ a new webview contact then the plugin no longer just
+ uses the URL of the site as a name but requests
+ that the user supply a name. Using a URL as a
+ name just looked too messy.
+-When an alert is issued the date and time of the alert
+ is appended to the contact name.
+-The contact name in Contact Options is the contact name without
+ any alert time and date appended to it.
+-Fixed bug which where the presence of an ampersand in the
+ url caused letters to be underlined or missing in the
+ text of the url button on the data display window.
+-Removed the sound alert. Now you can instead set
+ a sound be played when an alert occurs from the
+ same Sounds group in options that other plugins
+ use.
+-Disabled the apply button on the add contact window.
+-Added more translatable strings including error
+ messages, menu items and status bar messages.
+-Fixed bug where the description of the amount
+ of white space removal was not showing in the
+ Add Webview Site window.
+-Other minor changes.
+0.0.30.0
+-Set the titlebar text of the display data window
+ to contact name without any alert time and date
+ appended to it.
+-Added event-type "Alert When The Web Page Change".
+ This produces a user-defined alert when the the
+ contents of a page change from what was on the page
+ when it was last checked. This option creates
+ a file on the users harddrive for every contact
+ this option is set for.
+-Update URL displayed on the data display window
+ if that URL is changed in Contact Options.
+-Fixed bug which caused buttons on data display
+ window not to work if URL was changed.
+-Use PUShowMessage to generate any popup error
+ messages.
+-Contact Options now requests that the user supply a name
+ for a contact if one is not already supplied.
+-Contact Options and Add Webview Site windows now check
+ to see if there are any invalid symbols in the contact name
+ (this is needed to make sure the file name is valid for the
+ cache file).
+-Change the titlebar text of the data display window when
+ the contact name is changed and the changes are applied (
+ used to work only if user pressed "Ok").
+-Made some more of the text on different windows titlebar's
+ translatable.Also made some changes to the code to allow
+ the translation of some of the dynamic strings which occur
+ on the data display windows status bar and in alert popups.
+-Added an alert type to open the data display window when
+ a user defined event occurs.
+-Fixed bug which caused the icon of the (Disable) Stick to the
+ Front button always to show the Disable icon when the
+ window was first opened by double clicking on a contact.
+0.0.31.0
+-Make sure the time and date is not appended to the contact
+ name on contact list UNLESS an alert has been issued.
+-Miranda Translator tool was not translating some strings
+ correctly even though they were translatable. Made changes
+ to the code to help the Translator extract the correct strings.
+-Make the appending of the time of the last alert to the contact
+ list name a contact option.
+-Added a Popup option dialog to the PopUps group in Miranda
+ options so users can set the color of the Alert popups separately
+ from the color of the data display window. The user can also set
+ the popup delay from this option dialog.
+-Added an option to Alert Options to allow the user to define whether
+ the date is added to the contact name as a suffix or a prefix.
+-increased thread safety for popups.
+-Added webview to the "KnownModules" list.
+-User can now control whether the time added to the contact name
+ is in 24 hour or 12 hour format.
+0.0.32.0
+-Made an install script for Miranda Installer.
+-Added an item to the Main menu to allow the user to update
+ all Webview sites at once.
+-Cleaned up indents in source code.
+-Fixed bug in the the code which removes unsupported character
+ code from the display.
+-Fixed bug in code which caused the plugin not to clean up the display
+ if one or more of the Start or End strings was not present on
+ the web page even if plugin didn't need to check for these strings.
+-Separated the sources out into smaller files.
+-There was no way of adding a new webview site if the user had disabled
+ the main menu items. Added options to take place of the main menu items
+ in the main Miranda options dialog and made sure these options are not
+ enabled unless the main menu is disabled.
+-Right clicking on a popup now opens the web site in a browser window.
+-Added "Only Update Window on Alert" to main Miranda options to prevent
+ contents of the data display window being overwritten if there
+ is not an alert.
+-Changed the automove function so it no longer moves the data display
+ window back on screen (if the user moves it off of it) but just
+ makes sure the position will be on screen the next time it is created.
+-If Miranda crashed on exit then the window colors were not being
+ saved; save colors when the color options are changed to prevent this
+ happening.
+-Added a main menu item to enable or disable automatic updates of webview
+ sites.
+-Increased time interval range from 0-99 minutes to 0-999 minutes.
+-Fixed some bugs in the the Popup options.
+-Added option to use the same colors in the alert popup as is
+ used in the data display window.
+-User can now set the left and right click popup actions from
+ popup options. User can set the actions to open data display window,
+ open web page or dismiss popup.
+0.1.0.0
+-First Beta release
+-Make sure the first letter of the Webview menu title on
+ the Main menu is uppercase.
+-Use the Miranda Find/Add Contacts dialog to add webview
+ sites to the contact list.
+-Use the URL to create a name for the contact.
+-Make sure the update button on the data display window
+ always can update the text in the window even if the
+ "Only Update Window on Alert" option ticked.
+-Fixed bug which caused an invalid window position to be written
+ to the database if data display window was minimised when
+ Miranda exited.
+-Make sure the site name in Contact options and on the data
+ display window's titlebar is the same as the contact name
+ on the contact list unless it has a date added to it.
+-If Miranda crashed on exit then the window position was not being
+ saved; save position when the window is closed to prevent this
+ happening.
+-On slower systems data display window was seen in a different
+ area of the screen when opened then it was seen to move to
+ the correct position on the screen. Put fixes in place to correct this.
+-Added an event type to test if a specific area of a webpage has changed
+-Fixed some bugs in the Alert Options dialog.
+-Fixed bug which caused update button to become disabled if the
+ user clicked the button when that site was already being downloaded.
+-Check for alerts BEFORE filtering cleaning up the text.
+-Added the option to display alerts using the OSD plugin.
+-Fixed a bug that caused the plugin to falsely report that
+ the monitored website had changed.
+-Make sure the Apply buttons on the Contact Options and the
+ Alert Options windows is disabled unless there is a change
+ made to the options.
+-If either the display or alert start/end strings aren't present on
+ on a site issue an alert.
+-Start/End string not present and invalid search parameter errors
+ now set the contact to Away status (just like server error codes).
+-Added a button to the Contact Options dialog to copy the display
+ Start and End strings to the alert Start and End strings and set
+ the event type to "Alert When A Specific Part of Web Page Changes".
+-If a server replies with an error code display the exact error code
+ returned.
+-Find/Add dialog was truncating URL's.
+-Added more compact Contact Options and Alert Options dialogs
+-Made the comboboxes in the Alert Options dialog translatable.
+-Some improvements to the code that fixes the underlined text
+ bug on the url button.
+-Disable both the Contact Options and the Alert Options button
+ when then either then Contact Options or the Alert Options
+ button is opened (need to do this to avoid a bug).
+-Allow user to have more than one contact with the same URL
+ if those contacts have different names. If more than one
+ contact has the same name and URL then issue a warning
+ when using buttons on those contacts data display window.
+-Allow user to add contacts with the same URL and an existing
+ Webview contact.
+-Append a random number to the contact name when it is created
+ to avoid creation of Webview contacts with the same name if
+ they are using the same URL.
+-Added a status bar message to tell the user that a site is currently
+ downloading if they try to update another site manually.
+-Error now display using either PopUp plugin or the OSD plugin
+ if the "display errors using PopUp plugin" option is selected.
+ The plugin tries to use the PopUp plugin first but if that service
+ is not available then it uses the OSD plugin (if plugin is loaded).
+-Removed some unneeded preshutdown code.
+-Removed support for Plugin Uninstaller (that plugin will not work in
+ Miranda 0.4 anyway).
+-Removed main Webview option control which was used to add new Webview
+ contacts (the user can easily do this through the main menu item or
+ by the Find/Add dialog if the main menu item is disabled).
+-Updates to the README.
+0.1.1.0
+-Some improvement to the code that converts HTML character entities to
+ symbols.
+-Remember contact previous status on startup.
+-Stop the User Details dialog from constantly displaying "...Updating...".
+--Button in the Contact Options dialog to copy the Start and End strings
+ was not setting the event type to "Alert When A Specific Part of Web Page Changes".
+-If "Update window only on Alert" option was ticked statusbar was always displaying
+ "processing data, please wait" if all the sites were updated at the same time. Corrected
+ and added another status message.
+-Make sure all existing Webview contacts are set to online status the first time this
+ version of Webview is loaded.
+-Added a control to the main options to allow the user to set a delay of up to 120
+ seconds before Webview updates on start-up.
+-Make sure the timed updates cannot occur until the update on start up is finished.
+-Don't log to file twice if both types of start/end strings are not present and there is an
+ alert to indicate this.
+-Automatically delete the cache file (if one exists) when deleting a Webview contact
+ or when alerts are disabled for that contact.
+-Webview now knows when a contact is renamed on the contact list.
+-Rename the cache file (if one exists) when a contact is renamed.
+-Added the option to save the position of individual data display windows.
+-Added some delays to make the plugin slightly less CPU usage intensive
+ during data download and processing.
+-Added an advanced option to disable the download protection code if
+ the user wishes to do this. This has the advantage of being able to
+ download more than one site at the same time but it also potentially
+ could cause corruption of data.
+-Fixed a bug in the main Webview options.
+-Display time/date in the logs and on the status bar in the
+ users own language.
+-Bug causing last letter in display to be sometimes repeated.
+ This isn't a complete fix but it should stop the worst cases.
+-Added option to Contact Options so user can choose to log
+ data to file in its raw state or with all the tags removed.
+-Added a new status (DND) to indicate the plugin is downloading or processing
+ data for a particular site.
+-Filter out (most) CSS attributes.
+-When part of the web page has changed, change the color of the text
+ and background (and select the text) in the part of the page you are
+ monitoring so that the user can find this portion of the page easier
+ within the larger body of the displayed text.
+-Made some more space for translation strings in options.
+-Fixed some bugs in the EraseBlock function which causes
+ the plugin to hang while processing data.
+-Data window too small when it opened the first time. Made
+ window bigger.
+-Use SkinAddNewSoundEx instead of SkinAddNewSound.
+-Prevent Miranda versions less than 0.4.0.0 from loading plugin.
+-Cleaned up code.
+-Added TopToolBar buttons for adding Webview sites,updating
+ all Webview sites and disabling/enabling auto update.
+-Only load TopToolBar buttons if Main Menu items are disabled.
+-0.1.3.1
+-added "prettier" icon resources.
+-Removed" Add Webview Site from main menu.
+-Added code to get ride of <style> </style>.
+-removed TopToolbar support
+-Added Contact Options and Contact Alert Options to the contact menu.
+-Moved from PLUGININFO to PLUGININFOEX structure
+-Moved Webview's options from "Plugins" to "Network" in Miranda's options page.
+-Improved language pack support.
+-Added menu item to open cache folder.
+-New icon for Update All main menu item and Open Web Page contact menu item.
+-Added main menu item to mark all sites read
+-Added contact menu item to update site data.
+-Added Contact Menu item to ping the web site to test if there is any issue with connectivity.
+-0.1.3.2
+-Fixed an old bug where a DB value was getting written to any contact which was double clicked
+ regardless of its protocol.
+-The URL of a Webview contact is now also the contact's "Web Page" in user details.
+-Stop displaying unneeded status icons on the status bar.
+-Removed BBCode from popups to make compatible with YAPP.
+-The progress of data processing is shown on the data window.
+-Added contact menu item to stop the data processing on a site.
+-0.1.3.3
+-Stopped translating some clist items that should not be translated except by the core.
+-Add random number to contacts name when contact is created, if its the same as the
+ name of another webview contact on the list.
+-When updating all sites, don't wait for one site to finish updating before updating
+ the next.
+-The contact's StatusMsg now reports the site updating, offline, online, alert issued and site errors.
+-Removed an old part of the data window that is no longer needed.
+-Added a button to the data window to allow the user to stop data processing.
+-Text in data window updates during data processing.
+-0.1.3.4
+-Backed out a change in the code which was causing false alerts. Contacts have to
+ wait for other sites to stop updating before updating themselves.
+-Smaller cache size.
+-0.1.3.5
+-Destroy services on exit.
+-Popup message when all sites have been updated.
+-If Miranda crashes, the status icon no longer reappears on the statusbar bar, if
+ the user had originally chosen to hide it.
+-0.1.3.6
+-Smaller dll size.
+-Swapped the stick and unstick icons.
+-Added option to Main Options to display site data in a Popup when there is an alert.
+-Show error message if psite.bat doesn't exist and user is attempting to ping a site.
+-Show error message if cache folder doesn't exist and user is attempting to open it.
+-0.1.3.7
+-Fixed a potential crash when updating contacts.
+-If user renames a contact to a name containing a forbidden character,
+ there is an error popup to inform them and the character is converted to a "_"
+ and a random number appended to the end of the name.
+ -0.1.3.8
+ -The "Update on Window Open" option has been changed to "Load Page on Window Open".
+This change means when the option is selected, the window will first of all attempt to
+load information into the window from the cache, and only if the cache file doesn't exist
+will it attempt to download the web page and display it.
+-Mark site as read when window is opened and window is set to load data on open.
+-0.1.3.9
+-Prevent a crash when "Add Contact" is used instead of "Find/Add Contact", and also when
+ "Find/Add Contact" is used incorrectly.
+- Opening a site in a browser window using double click, contact menu, the url button
+ on the data window or clicking on popups, all set the contacts status to online/read.
+-Added a counter to the Webview main menu, which shows how many minutes to the next update.
+-Changed the "Permanent" and "From Popup Plugin" options in popup options, from radio
+ buttons to buttons.
+-0.1.3.10
+-Made separate Unicode and ANSI versions of plugin.
+-Removed some old unneeded code.
+
+
+
+
+
+
+
+
+
+
+
+*********************
+Copyright
+---------
+Copyright (C) 2011 Vincent Joyce
+
+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.
+
+
+
diff --git a/protocols/WebView/docs/todo.txt b/protocols/WebView/docs/todo.txt
new file mode 100644
index 0000000000..b28b04f643
--- /dev/null
+++ b/protocols/WebView/docs/todo.txt
@@ -0,0 +1,3 @@
+
+
+
diff --git a/protocols/WebView/res/Icon_14.ico b/protocols/WebView/res/Icon_14.ico
new file mode 100644
index 0000000000..e7577d004b
--- /dev/null
+++ b/protocols/WebView/res/Icon_14.ico
Binary files differ
diff --git a/protocols/WebView/res/alert.ico b/protocols/WebView/res/alert.ico
new file mode 100644
index 0000000000..86d8a9819a
--- /dev/null
+++ b/protocols/WebView/res/alert.ico
Binary files differ
diff --git a/protocols/WebView/res/find.ico b/protocols/WebView/res/find.ico
new file mode 100644
index 0000000000..49ce7340b6
--- /dev/null
+++ b/protocols/WebView/res/find.ico
Binary files differ
diff --git a/protocols/WebView/res/folder.ico b/protocols/WebView/res/folder.ico
new file mode 100644
index 0000000000..e9777a4596
--- /dev/null
+++ b/protocols/WebView/res/folder.ico
Binary files differ
diff --git a/protocols/WebView/res/markallread.ico b/protocols/WebView/res/markallread.ico
new file mode 100644
index 0000000000..1fd4064a75
--- /dev/null
+++ b/protocols/WebView/res/markallread.ico
Binary files differ
diff --git a/protocols/WebView/res/options.ico b/protocols/WebView/res/options.ico
new file mode 100644
index 0000000000..ddb72fb8ca
--- /dev/null
+++ b/protocols/WebView/res/options.ico
Binary files differ
diff --git a/protocols/WebView/res/ping.ico b/protocols/WebView/res/ping.ico
new file mode 100644
index 0000000000..2f9b702beb
--- /dev/null
+++ b/protocols/WebView/res/ping.ico
Binary files differ
diff --git a/protocols/WebView/res/popup.ico b/protocols/WebView/res/popup.ico
new file mode 100644
index 0000000000..f83a62a64c
--- /dev/null
+++ b/protocols/WebView/res/popup.ico
Binary files differ
diff --git a/protocols/WebView/res/show_hide.ico b/protocols/WebView/res/show_hide.ico
new file mode 100644
index 0000000000..afae803b69
--- /dev/null
+++ b/protocols/WebView/res/show_hide.ico
Binary files differ
diff --git a/protocols/WebView/res/stick.ico b/protocols/WebView/res/stick.ico
new file mode 100644
index 0000000000..a11221d6c6
--- /dev/null
+++ b/protocols/WebView/res/stick.ico
Binary files differ
diff --git a/protocols/WebView/res/stop.ico b/protocols/WebView/res/stop.ico
new file mode 100644
index 0000000000..b62ed82acf
--- /dev/null
+++ b/protocols/WebView/res/stop.ico
Binary files differ
diff --git a/protocols/WebView/res/unstick.ico b/protocols/WebView/res/unstick.ico
new file mode 100644
index 0000000000..edb7c1f4e7
--- /dev/null
+++ b/protocols/WebView/res/unstick.ico
Binary files differ
diff --git a/protocols/WebView/res/update.ico b/protocols/WebView/res/update.ico
new file mode 100644
index 0000000000..c6e4c359a7
--- /dev/null
+++ b/protocols/WebView/res/update.ico
Binary files differ
diff --git a/protocols/WebView/res/updateall.ico b/protocols/WebView/res/updateall.ico
new file mode 100644
index 0000000000..482bbf2826
--- /dev/null
+++ b/protocols/WebView/res/updateall.ico
Binary files differ
diff --git a/protocols/WebView/res/url.ico b/protocols/WebView/res/url.ico
new file mode 100644
index 0000000000..6baf15c3c5
--- /dev/null
+++ b/protocols/WebView/res/url.ico
Binary files differ
diff --git a/protocols/WebView/res/version.rc b/protocols/WebView/res/version.rc
new file mode 100644
index 0000000000..5a5ddd63ed
--- /dev/null
+++ b/protocols/WebView/res/version.rc
@@ -0,0 +1,9 @@
+// Microsoft Visual C++ generated resource script.
+//
+#ifdef APSTUDIO_INVOKED
+#error this file is not editable by Microsoft Visual C++
+#endif //APSTUDIO_INVOKED
+
+#include "..\src\version.h"
+
+#include "..\..\build\Version.rc"
diff --git a/protocols/WebView/res/web.ico b/protocols/WebView/res/web.ico
new file mode 100644
index 0000000000..2b5a44dbf9
--- /dev/null
+++ b/protocols/WebView/res/web.ico
Binary files differ
diff --git a/protocols/WebView/res/webview.rc b/protocols/WebView/res/webview.rc
new file mode 100644
index 0000000000..0d92123c31
--- /dev/null
+++ b/protocols/WebView/res/webview.rc
@@ -0,0 +1,364 @@
+//////////////////
+#include <windows.h>
+#include "..\src\resource.h"
+///////////////////
+
+
+
+
+/////////////////////////////
+////Icons
+/////////////////////////////
+
+IDI_SITE ICON DISCARDABLE "web.ico"
+IDI_STICK ICON DISCARDABLE "stick.ico"
+IDI_UNSTICK ICON DISCARDABLE "unstick.ico"
+IDI_URL ICON DISCARDABLE "url.ico"
+IDI_OPTIONS ICON DISCARDABLE "options.ico"
+IDI_UPDATE ICON DISCARDABLE "update.ico"
+IDI_SHOW_HIDE ICON DISCARDABLE "show_hide.ico"
+IDI_FIND ICON DISCARDABLE "find.ico"
+IDI_ALERT ICON DISCARDABLE "alert.ico"
+IDI_FOLDER ICON DISCARDABLE "folder.ico"
+IDI_UPDATEALL ICON DISCARDABLE "updateall.ico"
+IDI_MARKALLREAD ICON DISCARDABLE "markallread.ico"
+IDI_PING ICON DISCARDABLE "ping.ico"
+IDI_STOP ICON DISCARDABLE "stop.ico"
+
+/////////////////////////////////////////////////////////////////////////////
+
+
+
+//////////////////////////
+//// Main Options
+///////////////////////////
+IDD_OPT DIALOGEX 0,0,280,231
+STYLE DS_SETFONT | DS_FIXEDSYS | WS_CHILD
+EXSTYLE WS_EX_CONTROLPARENT
+FONT 8, "MS Shell Dlg", 0, 0, 0x1
+BEGIN
+ //
+
+ GROUPBOX "Webview",IDC_STATIC,1,11,278,63,WS_GROUP
+ //
+ LTEXT "Update data every",IDC_STATIC,6,26,100,8
+ EDITTEXT IDC_TIME,84,26,28,12,ES_AUTOHSCROLL | ES_NUMBER
+ CONTROL "Spin1",IDC_SPIN1,"msctls_updown32",UDS_SETBUDDYINT |
+ UDS_ALIGNRIGHT | UDS_AUTOBUDDY | UDS_ARROWKEYS |
+ UDS_NOTHOUSANDS,125,11,7,11
+ LTEXT "minutes",IDC_STATIC,113,26,25,8
+ //
+ LTEXT "Delay update on start",IDC_STARTDELAYTXT,6,49,100,8
+ EDITTEXT IDC_START_DELAY,84,49,28,12,ES_AUTOHSCROLL | ES_NUMBER
+ CONTROL "Spin2",IDC_SPIN2,"msctls_updown32",UDS_SETBUDDYINT |
+ UDS_ALIGNRIGHT | UDS_AUTOBUDDY | UDS_ARROWKEYS |
+ UDS_NOTHOUSANDS,125,34,7,11
+ LTEXT "seconds",IDC_STDELAYSECTXT,113,49,36,8
+ //
+ CONTROL "Hide icon on status bar",IDC_HIDE_STATUS_ICON,"Button",
+ BS_AUTOCHECKBOX | WS_TABSTOP,150,20,128,8
+ CONTROL "Disable main menu items",IDC_DISABLEMENU,"Button",
+ BS_AUTOCHECKBOX | WS_TABSTOP,150,30,128,8
+ CONTROL "Load page on window open",IDC_UPDATE_ON_OPEN,"Button",
+ BS_AUTOCHECKBOX | WS_TABSTOP,150,40,128,8
+ CONTROL "Update data on startup",IDC_UPDATE_ONSTART,"Button",
+ BS_AUTOCHECKBOX | WS_TABSTOP,150,50,128,8
+ CONTROL "Only update window on alert",IDC_UPDATE_ONALERT,"Button",
+ BS_AUTOCHECKBOX | WS_TABSTOP,150,60,128,8
+
+///////////
+
+ GROUPBOX "Window appearance",IDC_STATIC,1,75,278,62
+ LTEXT "Background color:",IDC_STATIC,16,85,69,8
+ CONTROL "",IDC_BGCOLOR,"ColourPicker",WS_TABSTOP,85,85,20,8
+ LTEXT "Text color:",IDC_STATIC,16,95,69,8
+ CONTROL "",IDC_TXTCOLOR,"ColourPicker",WS_TABSTOP,85,95,20,8
+
+ COMBOBOX IDC_TYPEFACE,16,105,136,182,CBS_DROPDOWN | CBS_SORT |
+ WS_VSCROLL | WS_TABSTOP
+ COMBOBOX IDC_SCRIPT,58,120,72,68,CBS_DROPDOWNLIST | WS_VSCROLL |
+ WS_TABSTOP
+
+ COMBOBOX IDC_FONTSIZE,16,120,40,69,CBS_DROPDOWN | WS_VSCROLL |
+ WS_TABSTOP
+ CONTROL "Bold",IDC_FONT_BOLD,"Button",
+ BS_AUTOCHECKBOX | WS_TABSTOP,160,90,48,8
+ CONTROL "Italic",IDC_FONT_ITALIC,"Button",
+ BS_AUTOCHECKBOX | WS_TABSTOP,160,100,48,8
+ CONTROL "Underline",IDC_FONT_UNDERLINE,"Button",
+ BS_AUTOCHECKBOX | WS_TABSTOP,160,110,58,8
+ CONTROL "Save individual window positions",IDC_SAVE_INDIVID_POS,"Button",
+ BS_AUTOCHECKBOX | WS_TABSTOP,132,122,146,8
+
+///////////
+ GROUPBOX "Error messages",IDC_STATIC,1,137,278,25
+ CONTROL "Suppress error messages",IDC_SUPPRESS,"Button",
+ BS_AUTOCHECKBOX | WS_TABSTOP,16,149,113,8
+ CONTROL "Display using popup or OSD plugin",IDC_ERROR_POPUP,"Button",
+ BS_AUTOCHECKBOX | WS_TABSTOP,140,149,130,8
+//////////
+ GROUPBOX "Expert options",IDC_ADV_GRP,142,163,137,35,WS_GROUP
+ CONTROL "Disable download protection",IDC_NO_PROTECT,"Button",
+ BS_AUTOCHECKBOX | WS_TABSTOP,148,175,130,8
+ LTEXT "(not recommended)",IDC_NOT_RECOMND_TXT,148,185,122,8
+//////////
+ GROUPBOX "Display data in popup on alert",IDC_STATIC, 1, 164, 139, 34
+ CONTROL "Display data in popup", IDC_DATAPOPUP , "Button",
+ BS_AUTOCHECKBOX | WS_TABSTOP, 16, 177, 120, 8
+/////
+ LTEXT "You may need to restart Miranda NG for this change to take effect.",IDC_RESTART,
+ 30,220,230,8,NOT WS_VISIBLE
+
+
+END
+
+///////////////////////////////////////////////////////////////////////////////////
+//data window
+////////////////
+IDD_DISPLAY_DATA DIALOGEX 0, 0, 212, 150
+STYLE DS_MODALFRAME | DS_3DLOOK | DS_FIXEDSYS | DS_CENTER | WS_POPUP |
+ NOT WS_VISIBLE | WS_SYSMENU | WS_CAPTION | WS_THICKFRAME |WS_MAXIMIZEBOX |
+ WS_MINIMIZEBOX
+EXSTYLE WS_EX_CONTROLPARENT
+CAPTION ""
+FONT 8, "MS Shell Dlg", 0, 0, 0x1
+
+BEGIN
+
+CONTROL "",IDC_UPDATE_BUTTON,"MButtonClass",WS_TABSTOP,5,1,16,14
+CONTROL "",IDC_STICK_BUTTON,"MButtonClass",WS_TABSTOP,25,1,16,14
+CONTROL "",IDC_FIND_BUTTON,"MButtonClass",WS_TABSTOP,45,1,16,14
+CONTROL "",IDC_OPTIONS_BUTTON,"MButtonClass",WS_TABSTOP,65,1,16,14
+CONTROL "",IDC_ALERT_BUTTON ,"MButtonClass",WS_TABSTOP,85,1,16,14
+CONTROL "",IDC_STOP ,"MButtonClass",WS_TABSTOP,105,1,16,14
+CONTROL "",IDC_OPEN_URL ,"MButtonClass",WS_TABSTOP,1,19,212,8
+CONTROL "",IDC_DATA,"RichEdit50W", ES_LEFT | ES_MULTILINE | ES_WANTRETURN | WS_CHILD | WS_VISIBLE | WS_VSCROLL, 1, 28, 209, 110
+CONTROL "", IDC_STATUSBAR, "msctls_statusbar32", SBARS_SIZEGRIP | WS_CHILD | WS_VISIBLE, 128, 4, 60, 12
+
+END
+
+
+///////////////////////////////////////////////////////////////////////
+///contact options
+//////////
+IDD_CONTACT_OPT DIALOGEX 0, 0, 367, 115
+STYLE DS_MODALFRAME | DS_3DLOOK | DS_SETFONT | DS_FIXEDSYS | WS_POPUP | WS_CAPTION
+EXSTYLE WS_EX_CONTROLPARENT
+FONT 8, "MS Shell Dlg", 0, 0, 0x1
+BEGIN
+//
+ GROUPBOX "Webview",IDC_STATIC, 4, 1, 239, 44 ,WS_GROUP
+ RTEXT "Contact name:",IDC_STATIC,7, 14, 72, 8
+ EDITTEXT IDC_SITE_NAME, 80, 12, 158, 12 ,ES_AUTOHSCROLL
+ RTEXT "URL:",IDC_STATIC,7, 28, 72, 8
+ EDITTEXT IDC_URL, 80, 26, 158, 12,ES_AUTOHSCROLL
+ //
+ GROUPBOX "Display", IDC_STATIC, 245, 1, 120, 92,WS_GROUP
+ CONTROL "Between start and end strings",IDC_U_SE_STRINGS,"Button",
+ BS_AUTORADIOBUTTON, 249, 25, 113, 8
+ CONTROL "Whole web page",IDC_U_ALLSITE,"Button",
+ BS_AUTORADIOBUTTON, 249, 12, 113, 8
+ RTEXT "Start:",IDC_STATIC, 249, 39, 30, 8
+ EDITTEXT IDC_START, 280, 37, 70, 12 ,ES_AUTOHSCROLL
+ RTEXT "End:",IDC_STATIC,249, 53, 30, 8
+ EDITTEXT IDC_END, 280, 51, 70, 12 ,ES_AUTOHSCROLL
+ DEFPUSHBUTTON "Copy strings to alerts",IDC_CPY_STRINGS, 249, 66, 101, 12
+ //LTEXT "(pastes strings)",IDC_CPY_STR_TXT, 270, 81, 92, 8
+ //
+ GROUPBOX "Double click action",IDC_STATIC, 4, 47, 111, 47 ,WS_GROUP
+ CONTROL "Opens web page",IDC_DBLE_WEB,"Button",
+ BS_AUTORADIOBUTTON, 6, 68, 105, 8
+ CONTROL "Opens data window",IDC_DBLE_WIN,"Button",
+ BS_AUTORADIOBUTTON,6, 81, 105, 8
+ //
+ GROUPBOX "Display clean-up",IDC_STATIC, 117, 47, 126, 47 ,WS_GROUP
+ CONTROL "Remove HTML",IDC_CLEAN,"Button",
+ BS_AUTOCHECKBOX | WS_TABSTOP, 120, 59, 100, 8
+ CONTROL "Slider1",IDC_RWSPACE,"msctls_trackbar32",TBS_BOTH |
+ TBS_NOTICKS | WS_TABSTOP,120, 70, 100, 8
+ LTEXT "",IDC_RWSPC_TEXT, 120, 81, 120, 8 ,WS_VISIBLE
+ //
+ DEFPUSHBUTTON "OK",IDOK, 207, 98, 50, 14
+ PUSHBUTTON "Cancel",IDC_OPT_CANCEL, 261, 98, 50, 14
+ PUSHBUTTON "Apply",IDC_OPT_APPLY, 315, 98, 50, 14
+
+
+END
+
+/////////////////////////////////////////////////////////////////////////////////////
+//find window
+//////
+IDD_FIND DIALOGEX 0, 0, 230, 46
+STYLE DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU
+EXSTYLE WS_EX_CONTROLPARENT
+CAPTION "Find"
+FONT 8, "MS Shell Dlg", 0, 0, 0x1
+BEGIN
+ EDITTEXT IDC_FINDWHAT,48,11,115,12,ES_AUTOHSCROLL
+ DEFPUSHBUTTON "&Find next",IDC_OK,173,7,50,14
+ PUSHBUTTON "Cancel",IDC_CANCEL,173,24,50,14
+ LTEXT "Find what:",IDC_STATIC,7,13,39,9
+ GROUPBOX "",IDC_STATIC,48,24,115,18
+ LTEXT "Search was completed.",IDC_SEARCH_COMPLETE,
+ 52,30,90,8,NOT WS_VISIBLE
+END
+
+
+
+///////////////////////////////////
+//Alert Options
+////////
+IDD_ALRT_OPT DIALOGEX 0, 0, 337, 185
+STYLE DS_MODALFRAME | DS_3DLOOK | DS_SETFONT | DS_FIXEDSYS | WS_POPUP | WS_CAPTION
+EXSTYLE WS_EX_CONTROLPARENT
+FONT 8, "MS Shell Dlg", 0, 0, 0x1
+
+BEGIN
+
+ GROUPBOX "Events and alerts",IDC_STATIC,3, 4, 331, 71,WS_GROUP
+ CONTROL "Enable alerts",IDC_ENABLE_ALERTS,"Button",
+ BS_AUTOCHECKBOX | WS_TABSTOP, 9, 13, 82, 13
+ CONTROL "Always log to file",IDC_ALWAYS_LOG,"Button",
+ BS_AUTOCHECKBOX | WS_TABSTOP, 9, 25, 82, 13
+ //
+ GROUPBOX "",IDC_STATIC,7, 36, 324, 35 ,WS_GROUP
+ CONTROL "Add time and date of alert to contact name",IDC_ADD_DATE_NAME,"Button",
+ BS_AUTOCHECKBOX | WS_TABSTOP, 9, 42, 235, 13
+ CONTROL "Use 24 hour time format instead of 12 hour",IDC_24_HOUR,"Button",
+ BS_AUTOCHECKBOX | WS_TABSTOP,9, 57, 235, 13
+ CONTROL "Add as prefix",IDC_PREFIX,"Button",
+ BS_AUTORADIOBUTTON, 248, 46, 82, 8
+ CONTROL "Add as suffix",IDC_SUFFIX,"Button",
+ BS_AUTORADIOBUTTON, 248, 58, 82, 8
+ //
+ RTEXT "Alert when:",IDC_STATIC, 120, 13, 63, 9
+ COMBOBOX IDC_EVENT_TYPE,184, 11, 147, 63 ,CBS_DROPDOWN |
+ WS_VSCROLL | WS_TABSTOP
+ RTEXT "Alert type:",IDC_STATIC, 120, 27, 63, 9
+ COMBOBOX IDC_ALERT_TYPE, 184, 26, 147, 67 ,CBS_DROPDOWN |
+ WS_VSCROLL | WS_TABSTOP
+ //
+ //////////
+ GROUPBOX "Test conditions",IDC_STATIC, 3, 77, 331, 58 ,WS_GROUP
+ //
+ GROUPBOX "Alert when string is present on web page",IDC_STATIC, 7, 85, 144, 44 ,WS_GROUP
+ RTEXT "String:",IDC_STATIC, 10, 99, 34, 8
+ EDITTEXT IDC_ALERT_STRING, 45, 97, 103, 12 ,ES_AUTOHSCROLL
+ //
+ GROUPBOX "Alert when specific area of web page changes",IDC_STATIC,155, 85, 176, 44 ,WS_GROUP
+ RTEXT "Start:",IDC_STATIC, 163, 97, 36, 8
+ EDITTEXT IDC_START2,200, 95, 126, 12,ES_AUTOHSCROLL
+ RTEXT "End:",IDC_STATIC, 163, 112, 36, 8
+ EDITTEXT IDC_END2,200, 110, 125, 12,ES_AUTOHSCROLL
+ //
+ /////////
+ //
+ GROUPBOX "Log to file",IDC_STATIC, 3, 137, 246, 37,WS_GROUP
+ RTEXT "Log file:",IDC_STATIC, 8, 148, 39, 9
+ EDITTEXT IDC_FILENAME, 48, 147, 174, 12,ES_AUTOHSCROLL
+ PUSHBUTTON "...",IDC_BROWSE, 228, 148, 15, 11
+ CONTROL "Append data to file",IDC_APPEND,"Button",
+ BS_AUTOCHECKBOX | WS_TABSTOP,8, 161, 132, 8
+ CONTROL "Save as raw data",IDC_SAVE_AS_RAW,"Button",
+ BS_AUTOCHECKBOX | WS_TABSTOP,141, 161, 106, 8
+
+ //
+
+ DEFPUSHBUTTON "OK",IDC_OK2, 276, 137, 50, 14
+ PUSHBUTTON "Cancel",IDC_ALERT_CANCEL, 276, 153, 50, 14
+ PUSHBUTTON "Apply",IDC_ALERT_APPLY, 276, 169, 50, 14
+ //
+
+
+
+
+END
+//////////////
+//popup options
+///////
+IDD_POPUP DIALOGEX 0, 0, 306, 183
+STYLE DS_SETFONT | DS_FIXEDSYS | WS_CHILD
+EXSTYLE WS_EX_CONTROLPARENT
+FONT 8, "MS Shell Dlg", 0, 0, 0x1
+BEGIN
+ ////
+ GROUPBOX "Popup delay",IDC_STATIC,8,5,150,54,WS_GROUP
+ //CONTROL "Delay",IDC_PD3,"Button",BS_AUTORADIOBUTTON,18,15,47,8
+ LTEXT "Delay",IDC_STATIC,18,15,47,8
+ EDITTEXT IDC_DELAY,65,15,31,9,ES_RIGHT | ES_AUTOHSCROLL |
+ ES_NUMBER | NOT WS_BORDER,WS_EX_STATICEDGE
+ LTEXT "seconds",IDC_STATIC,106,15,34,10
+ //CONTROL "From popup plugin",IDC_PD1,"Button",BS_AUTORADIOBUTTON,
+ // 18,30,110,12
+ CONTROL "From popup plugin",IDC_PD1,"MButtonClass",WS_TABSTOP,
+ 18,30,110,12
+ //CONTROL "Permanent",IDC_PD2,"Button",BS_AUTORADIOBUTTON,18,45,
+ // 110,12
+ CONTROL "Permanent",IDC_PD2,"MButtonClass",WS_TABSTOP,18,45,
+ 110,12
+
+ ////
+ CONTROL "Preview",IDC_PREVIEW,"MButtonClass",WS_TABSTOP,223,30,
+ 45,11,0x18000000L
+ ////
+ GROUPBOX "Colors",IDC_STATIC,8,60,270,60,WS_GROUP
+ CONTROL "Use custom colors",IDC_POP_USECUSTCOLORS,"Button",
+ BS_AUTORADIOBUTTON,18,70,111,13
+ CONTROL "Use Windows colors",IDC_POP_USEWINCOLORS,"Button",
+ BS_AUTORADIOBUTTON,18,85,121,13
+ CONTROL "Use same colors as data window", IDC_POP_USESAMECOLORS,"Button",
+ BS_AUTORADIOBUTTON,18,100,161,13
+
+ LTEXT "Background",IDC_STATIC,223,65,50,8,SS_CENTERIMAGE
+ LTEXT "Text",IDC_STATIC,147,65,50,8,SS_CENTERIMAGE
+ CONTROL "",IDC_POP_BGCOLOUR,"ColourPicker",WS_TABSTOP,223,75,35,11
+ CONTROL "",IDC_POP_TEXTCOLOUR,"ColourPicker",WS_TABSTOP,147,75,35,11
+ ////
+
+ GROUPBOX "Left click action",IDC_STATIC,8,125,120,54,WS_GROUP
+ CONTROL "Open data display window",IDC_LCLK_WINDOW,"Button",
+ BS_AUTORADIOBUTTON,18,135,100,8
+ CONTROL "Open web page",IDC_LCLK_WEB_PGE,"Button",
+ BS_AUTORADIOBUTTON,18,150,100,8
+ CONTROL "Dismiss popup",IDC_LCLK_DISMISS,"Button",
+ BS_AUTORADIOBUTTON,18,165,100,8
+
+
+ GROUPBOX "Right click action",IDC_STATIC,160,125,120,54,WS_GROUP
+ CONTROL "Open data display window",IDC_RCLK_WINDOW,"Button",
+ BS_AUTORADIOBUTTON,170,135,100,8
+ CONTROL "Open web page",IDC_RCLK_WEB_PGE,"Button",
+ BS_AUTORADIOBUTTON,170,150,100,8
+ CONTROL "Dismiss popup",IDC_RCLK_DISMISS,"Button",
+ BS_AUTORADIOBUTTON,170,165,100,8
+
+ //CONTROL "Use popup plugins notify popups",IDC_PUALERT,"Button",
+ // BS_AUTOCHECKBOX | WS_TABSTOP,16,185,130,8
+
+END
+
+
+
+
+
+/////////////////////////////
+
+///////////////
+//Menus
+///////////////
+
+IDR_CONTEXT MENU DISCARDABLE
+BEGIN
+ POPUP "Log"
+ BEGIN
+ MENUITEM "&Copy", IDM_COPY
+ MENUITEM "C&ut", IDM_CUT
+ MENUITEM "&Delete", IDM_DELETE
+ MENUITEM "&Paste", IDM_PASTE
+ MENUITEM SEPARATOR
+ MENUITEM "Co&py all", IDM_COPYALL
+ MENUITEM "&Select all", IDM_SELECTALL
+ MENUITEM "C&lear all", IDM_CLEAR_ALL
+
+ END
+END
diff --git a/protocols/WebView/src/main.cpp b/protocols/WebView/src/main.cpp
new file mode 100644
index 0000000000..d53964c0af
--- /dev/null
+++ b/protocols/WebView/src/main.cpp
@@ -0,0 +1,285 @@
+/*
+ * A plugin for Miranda IM which displays web page text in a window.
+ * Copyright (C) 2005 Vincent Joyce.
+ *
+ * Miranda IM: the free icq client for MS Windows
+ * Copyright (C) 2000-2 Richard Hughes, Roland Rabien & Tristan Van de Vreede
+ *
+ * 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.
+ */
+
+#include "stdafx.h"
+#include "webview.h"
+
+MWindowList hWindowList;
+HNETLIBUSER hNetlibUser;
+HANDLE hHookDisplayDataAlert, hHookAlertPopup, hHookAlertWPopup, hHookErrorPopup, hHookAlertOSD;
+
+CMPlugin g_plugin;
+
+static HMODULE hRichEd = nullptr;
+
+/////////////////////////////////////////////////////////////////////////////////////////
+
+PLUGININFOEX pluginInfoEx = {
+ sizeof(PLUGININFOEX),
+ __PLUGIN_NAME,
+ PLUGIN_MAKE_VERSION(__MAJOR_VERSION, __MINOR_VERSION, __RELEASE_NUM, __BUILD_NUM),
+ __DESCRIPTION,
+ __AUTHOR,
+ __COPYRIGHT,
+ __AUTHORWEB,
+ UNICODE_AWARE,
+ // {CD5427FB-5320-4f65-B4BF-86B7CF7B5087}
+ {0xcd5427fb, 0x5320, 0x4f65, {0xb4, 0xbf, 0x86, 0xb7, 0xcf, 0x7b, 0x50, 0x87}}
+};
+
+CMPlugin::CMPlugin() :
+ PLUGIN<CMPlugin>(MODULENAME, pluginInfoEx)
+{
+ RegisterProtocol(PROTOTYPE_PROTOCOL);
+ SetUniqueId("PreserveName");
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+
+void InitServices()
+{
+ CreateProtoServiceFunction(MODULENAME, PS_GETCAPS, GetCaps);
+ CreateProtoServiceFunction(MODULENAME, PS_GETNAME, GetName);
+ CreateProtoServiceFunction(MODULENAME, PS_LOADICON, BPLoadIcon);
+ CreateProtoServiceFunction(MODULENAME, PS_SETSTATUS, SetStatus);
+ CreateProtoServiceFunction(MODULENAME, PS_GETSTATUS, GetStatus);
+ CreateProtoServiceFunction(MODULENAME, PS_BASICSEARCH, BasicSearch);
+ CreateProtoServiceFunction(MODULENAME, PS_ADDTOLIST, AddToList);
+ CreateProtoServiceFunction(MODULENAME, PSS_GETINFO, GetInfo);
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+
+void ChangeContactStatus(int con_stat)
+{
+ WORD status_code = 0;
+ if (con_stat == 0)
+ status_code = ID_STATUS_OFFLINE;
+ if (con_stat == 1)
+ status_code = ID_STATUS_ONLINE;
+ if (con_stat == 2)
+ status_code = ID_STATUS_AWAY;
+ if (con_stat == 3)
+ status_code = ID_STATUS_NA;
+
+ for (auto &hContact : Contacts(MODULENAME))
+ g_plugin.setWord(hContact, "Status", status_code);
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+
+extern "C" __declspec(dllexport) const MUUID MirandaInterfaces[] = { MIID_PROTOCOL, MIID_LAST };
+
+/////////////////////////////////////////////////////////////////////////////////////////
+
+int CMPlugin::Load()
+{
+ HookEvent(ME_CLIST_DOUBLECLICKED, Doubleclick);
+
+ hMenu = LoadMenu(g_plugin.getInst(), MAKEINTRESOURCE(IDR_CONTEXT));
+ hRichEd = LoadLibrary(L"Msftedit.dll");
+
+ /*TIMERS*/
+ if ((g_plugin.getDword(REFRESH_KEY, TIME) != 0)) {
+ timerId = SetTimer(nullptr, 0, ((g_plugin.getDword(REFRESH_KEY, TIME)) * MINUTE), timerfunc);
+ g_plugin.setDword(COUNTDOWN_KEY, 0);
+ Countdown = SetTimer(nullptr, 0, MINUTE, Countdownfunc);
+ }
+
+ InitialiseGlobals();
+
+ // register netlib handle
+ char tempNdesc[50];
+ mir_snprintf(tempNdesc, "%s connection settings", MODULENAME);
+
+ NETLIBUSER nlu = {};
+ nlu.flags = NUF_OUTGOING | NUF_HTTPCONNS;
+ nlu.szSettingsModule = MODULENAME;
+ nlu.szDescriptiveName.a = tempNdesc;
+ hNetlibUser = Netlib_RegisterUser(&nlu);
+
+ //protocol services
+ InitServices();
+
+ //add sound event to options
+ g_plugin.addSound("webviewalert", _A2W(MODULENAME), LPGENW("Alert event"));
+
+ //value is 1 if menu is disabled
+ g_plugin.setByte(MENU_IS_DISABLED_KEY, 1);
+
+ CMenuItem mi(&g_plugin);
+ mi.flags = CMIF_UNICODE;
+ if ( g_plugin.getByte(MENU_OFF, 0)) {
+ //value is 0 if menu is enabled
+ g_plugin.setByte(MENU_IS_DISABLED_KEY, 0);
+
+ mi.root = g_plugin.addRootMenu(MO_MAIN, _A2W(MODULENAME), 20200001);
+ Menu_ConfigureItem(mi.root, MCI_OPT_UID, "403BE07B-7954-4F3E-B318-4301571776B8");
+
+ /*DISABLE WEBVIEW*/
+ SET_UID(mi, 0xdedeb697, 0xfc10, 0x4622, 0x8b, 0x97, 0x74, 0x39, 0x32, 0x68, 0xa7, 0x7b);
+ CreateServiceFunction("DisableWebview", AutoUpdateMCmd);
+ mi.hIcolibItem = LoadIcon(g_plugin.getInst(), MAKEINTRESOURCE(IDI_SITE));
+ if (g_plugin.getByte(DISABLE_AUTOUPDATE_KEY, 0))
+ mi.name.w = LPGENW("Auto update disabled");
+ else
+ mi.name.w = LPGENW("Auto update enabled");
+ mi.pszService = "DisableWebview";
+ hMenuItem1 = Menu_AddMainMenuItem(&mi);
+
+ // Update all webview contacts
+ SET_UID(mi, 0xf324ede, 0xfdf, 0x498a, 0x8f, 0x49, 0x6d, 0x2a, 0x9f, 0xda, 0x58, 0x6);
+ CreateServiceFunction("UpdateAll", UpdateAllMenuCommand);
+ mi.position = 500090002;
+ mi.hIcolibItem = LoadIcon(g_plugin.getInst(), MAKEINTRESOURCE(IDI_UPDATEALL));
+ mi.name.w = LPGENW("Update all Webview sites");
+ mi.pszService = "UpdateAll";
+ Menu_AddMainMenuItem(&mi);
+
+ // Mark All Webview Sites As Read
+ SET_UID(mi, 0x1fa5fa21, 0x2ee1, 0x4372, 0xae, 0x3e, 0x3b, 0x96, 0xac, 0xd, 0xe8, 0x49);
+ CreateServiceFunction("MarkAllSitesRead", MarkAllReadMenuCommand);
+ mi.position = 500090099;
+ mi.hIcolibItem = LoadIcon(g_plugin.getInst(), MAKEINTRESOURCE(IDI_MARKALLREAD));
+ mi.name.w = LPGENW("Mark all Webview sites as read");
+ mi.pszService = "MarkAllSitesRead";
+ Menu_AddMainMenuItem(&mi);
+
+ // open cache directory
+ SET_UID(mi, 0xfed046a8, 0xaae5, 0x4cbe, 0xa8, 0xc, 0x3c, 0x50, 0x3e, 0x3e, 0x9b, 0x15);
+ CreateServiceFunction("OpenCacheFolder", OpenCacheDir);
+ mi.position = 500090099;
+ mi.hIcolibItem = LoadIcon(g_plugin.getInst(), MAKEINTRESOURCE(IDI_FOLDER));
+ mi.name.w = LPGENW("Open cache folder");
+ mi.pszService = "OpenCacheFolder";
+ Menu_AddMainMenuItem(&mi);
+
+ // Countdown test
+ SET_UID(mi, 0xbb1a94a9, 0xca63, 0x4966, 0x98, 0x48, 0x8b, 0x3f, 0x9d, 0xac, 0x6a, 0x10);
+ CreateServiceFunction("Countdown", CountdownMenuCommand);
+ mi.flags |= CMIF_KEEPUNTRANSLATED;
+ wchar_t countername[100];
+ mir_snwprintf(countername, TranslateT("%d minutes to update"), g_plugin.getDword(COUNTDOWN_KEY, 0));
+ mi.position = 600090099;
+ mi.hIcolibItem = LoadIcon(g_plugin.getInst(), MAKEINTRESOURCE(IDI_UPDATEALL));
+ mi.name.w = countername;
+ mi.pszService = "Countdown";
+ hMenuItemCountdown = Menu_AddMainMenuItem(&mi);
+ }
+
+ // contact menu
+ mi.flags = CMIF_UNICODE;
+
+ SET_UID(mi, 0xadc6a9a4, 0xdf7, 0x4f63, 0x89, 0x11, 0x8e, 0x42, 0x1d, 0xd6, 0x29, 0x31);
+ CreateServiceFunction("Open web page", WebsiteMenuCommand);
+ mi.position = 100;
+ mi.hIcolibItem = LoadIcon(g_plugin.getInst(), MAKEINTRESOURCE(IDI_URL));
+ mi.pszService = "Open web page";
+ mi.name.w = LPGENW("Open web page");
+ Menu_AddContactMenuItem(&mi, MODULENAME);
+
+ SET_UID(mi, 0x9d803e61, 0xc929, 0x4c6e, 0x9e, 0x7, 0x93, 0x0, 0xab, 0x14, 0x13, 0x50);
+ CreateServiceFunction("OpenClose Window", DataWndMenuCommand);
+ mi.pszService = "OpenClose Window";
+ mi.hIcolibItem = LoadIcon(g_plugin.getInst(), MAKEINTRESOURCE(IDI_SHOW_HIDE));
+ mi.name.w = LPGENW("Open/Close window");
+ Menu_AddContactMenuItem(&mi, MODULENAME);
+
+ SET_UID(mi, 0x3840cc71, 0xcc85, 0x448d, 0xb5, 0xc8, 0x1a, 0x7d, 0xfe, 0xf0, 0x8, 0x85);
+ mi.position = 2222220;
+ mi.pszService = "UpdateData";
+ mi.hIcolibItem = LoadIcon(g_plugin.getInst(), MAKEINTRESOURCE(IDI_UPDATE));
+ mi.name.w = LPGENW("Update data");
+ Menu_AddContactMenuItem(&mi, MODULENAME);
+
+ SET_UID(mi, 0xd1ab586c, 0x2c71, 0x429c, 0xb1, 0x79, 0x7b, 0x3a, 0x1d, 0x4a, 0xc1, 0x7d);
+ CreateServiceFunction("ContactOptions", CntOptionsMenuCommand);
+ mi.pszService = "ContactOptions";
+ mi.hIcolibItem = LoadIcon(g_plugin.getInst(), MAKEINTRESOURCE(IDI_OPTIONS));
+ mi.name.w = LPGENW("Contact options");
+ Menu_AddContactMenuItem(&mi, MODULENAME);
+
+ SET_UID(mi, 0xe4cda597, 0x9def, 0x4f54, 0x8a, 0xc6, 0x69, 0x3b, 0x5a, 0x7d, 0x77, 0xb6);
+ CreateServiceFunction("ContactAlertOpts", CntAlertMenuCommand);
+ mi.pszService = "ContactAlertOpts";
+ mi.hIcolibItem = LoadIcon(g_plugin.getInst(), MAKEINTRESOURCE(IDI_ALERT));
+ mi.name.w = LPGENW("Contact alert options");
+ Menu_AddContactMenuItem(&mi, MODULENAME);
+
+ SET_UID(mi, 0x63fdeed8, 0xf880, 0x423f, 0x95, 0xae, 0x20, 0x8c, 0x86, 0x3c, 0x5, 0xd8);
+ CreateServiceFunction("PingWebsite", PingWebsiteMenuCommand);
+ mi.pszService = "PingWebsite";
+ mi.hIcolibItem = LoadIcon(g_plugin.getInst(), MAKEINTRESOURCE(IDI_PING));
+ mi.name.w = LPGENW("Ping web site");
+ Menu_AddContactMenuItem(&mi, MODULENAME);
+
+ SET_UID(mi, 0x28fd36de, 0x6ce1, 0x43d0, 0xa1, 0x6e, 0x98, 0x71, 0x53, 0xe8, 0xc9, 0xf4);
+ CreateServiceFunction("StopDataProcessing", StpPrcssMenuCommand);
+ mi.pszService = "StopDataProcessing";
+ mi.hIcolibItem = LoadIcon(g_plugin.getInst(), MAKEINTRESOURCE(IDI_STOP));
+ mi.name.w = LPGENW("Stop data processing");
+ Menu_AddContactMenuItem(&mi, MODULENAME);
+
+ hWindowList = WindowList_Create();
+
+ HookEvent(ME_SYSTEM_MODULESLOADED, ModulesLoaded);
+ HookEvent(ME_DB_CONTACT_SETTINGCHANGED, DBSettingChanged);
+ HookEvent(ME_DB_CONTACT_DELETED, SiteDeleted);
+ HookEvent(ME_OPT_INITIALISE, OptInitialise);
+
+ g_plugin.setByte(HAS_CRASHED_KEY, 1);
+ return 0;
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+
+int CMPlugin::Unload()
+{
+ ChangeContactStatus(0);
+
+ KillTimer(nullptr, timerId);
+ KillTimer(nullptr, Countdown);
+
+ g_plugin.setByte(HAS_CRASHED_KEY, 0);
+ SavewinSettings();
+ if (hRichEd)
+ FreeLibrary(hRichEd);
+
+ if (hNetlibUser) {
+ Netlib_CloseHandle(hNetlibUser);
+ hNetlibUser = nullptr;
+ }
+
+ if (hHookDisplayDataAlert)
+ DestroyHookableEvent(hHookDisplayDataAlert);
+ if (hHookAlertPopup)
+ DestroyHookableEvent(hHookAlertPopup);
+ if (hHookAlertWPopup)
+ DestroyHookableEvent(hHookAlertWPopup);
+
+ if (h_font != nullptr)
+ DeleteObject(h_font);
+ if (hMenu)
+ DestroyMenu(hMenu);
+ WindowList_Destroy(hWindowList);
+ return 0;
+}
diff --git a/protocols/WebView/src/resource.h b/protocols/WebView/src/resource.h
new file mode 100644
index 0000000000..d0203c7cab
--- /dev/null
+++ b/protocols/WebView/src/resource.h
@@ -0,0 +1,139 @@
+#define UNI 1
+
+#define IDC_STATIC -1
+
+#define IDI_SITE 101
+#define IDI_STICK 102
+#define IDI_UNSTICK 103
+#define IDI_URL 104
+#define IDI_OPTIONS 105
+#define IDI_UPDATE 106
+#define IDI_SHOW_HIDE 107
+#define IDI_FIND 108
+#define IDI_ALERT 110
+#define IDI_FOLDER 111
+#define IDI_UPDATEALL 112
+#define IDI_MARKALLREAD 113
+#define IDI_PING 114
+#define IDI_STOP 115
+
+
+#define IDC_UPDATE_ONSTART 300
+#define IDC_DBLE_WEB 301
+#define IDC_DBLE_WIN 302
+#define IDC_UPDATE_ON_OPEN 303
+#define IDC_UPDATE_ONALERT 304
+
+#define IDD_OPT 443
+#define IDC_DISABLEMENU 446
+#define IDC_OPEN_WEBPAGE 447
+#define IDC_TIME 450
+
+#define IDC_BGCOLOR 451
+#define IDC_TXTCOLOR 452
+#define IDC_RESTART 453
+#define IDC_CLEAN 457
+#define IDC_SUPPRESS 458
+#define IDC_SPIN1 461
+#define IDC_HIDE_STATUS_ICON 464
+#define IDC_RWSPACE 465
+#define IDC_RWSPC_TEXT 466
+#define IDC_TYPEFACE 467
+#define IDC_FONT_BOLD 468
+#define IDC_FONT_ITALIC 469
+#define IDC_FONT_UNDERLINE 470
+#define IDC_FONTSIZE 471
+#define IDC_U_SE_STRINGS 475
+#define IDC_U_ALLSITE 476
+#define IDC_ERROR_POPUP 477
+#define IDC_START_DELAY 480
+#define IDC_SPIN2 481
+#define IDC_STARTDELAYTXT 482
+#define IDC_STDELAYSECTXT 483
+#define IDC_SAVE_INDIVID_POS 484
+#define IDC_ADV_GRP 485
+#define IDC_NO_PROTECT 486
+#define IDC_NOT_RECOMND_TXT 487
+#define IDC_SCRIPT 488
+#define IDC_DATAPOPUP 489
+
+#define IDR_CONTEXT 500
+#define IDM_CUT 501
+#define IDM_PASTE 502
+#define IDM_DELETE 503
+#define IDM_CLEAR_ALL 504
+#define IDM_COPY 505
+#define IDM_COPYALL 506
+#define IDM_SELECTALL 507
+
+#define IDC_SITE_NAME 551
+#define IDC_ERR_CHK 552
+#define IDC_APPEND 554
+#define IDC_FILENAME 555
+#define IDC_BROWSE 556
+#define IDC_SAVE_AS_RAW 557
+//#define IDC_AGENT 557//temp
+
+#define IDD_DISPLAY_DATA 600
+#define IDC_OPEN_URL 601
+#define IDC_DATA 602
+#define IDC_UPDATE_BUTTON 603
+#define IDC_STICK_BUTTON 604
+#define IDC_FIND_BUTTON 605
+#define IDC_STATUSBAR 606
+#define IDC_OPTIONS_BUTTON 607
+#define IDC_ALERT_BUTTON 608
+//#define IDC_HIDDEN_URL 609
+#define IDC_STOP 609
+
+#define IDC_ERRORMSG 620
+
+#define IDD_CONTACT_OPT 700
+#define IDC_END 701
+#define IDC_START 702
+#define IDC_URL 703
+#define IDC_OPT_CANCEL 704
+#define IDC_OPT_APPLY 705
+#define IDC_CPY_STRINGS 706
+
+
+#define IDD_FIND 750
+#define IDC_FINDWHAT 751
+#define IDC_OK 752
+#define IDC_CANCEL 753
+#define IDC_SEARCH_COMPLETE 754
+
+#define IDD_ALRT_OPT 801
+#define IDC_ENABLE_ALERTS 802
+#define IDC_OK2 803
+#define IDC_ALERT_STRING 804
+#define IDC_ALERT_TYPE 807
+#define IDC_EVENT_TYPE 808
+#define IDC_ALERT_CANCEL 809
+#define IDC_ALERT_APPLY 810
+#define IDC_START2 811
+#define IDC_END2 812
+#define IDC_ADD_DATE_NAME 813
+#define IDC_DELAY 814
+#define IDC_PREFIX 815
+#define IDC_SUFFIX 816
+#define IDC_24_HOUR 817
+#define IDC_ALWAYS_LOG 818
+
+#define IDD_POPUP 850
+#define IDC_POP_BGCOLOUR 851
+#define IDC_POP_TEXTCOLOUR 852
+#define IDC_PD1 853
+#define IDC_PD2 854
+//#define IDC_PD3 855
+#define IDC_PREVIEW 856
+#define IDC_POP_USEWINCOLORS 857
+#define IDC_POP_USESAMECOLORS 858
+#define IDC_POP_USECUSTCOLORS 859
+#define IDC_LCLK_WINDOW 860
+#define IDC_LCLK_WEB_PGE 861
+#define IDC_LCLK_DISMISS 862
+#define IDC_RCLK_WINDOW 863
+#define IDC_RCLK_WEB_PGE 864
+#define IDC_RCLK_DISMISS 865
+//#define IDC_PUALERT 866
diff --git a/protocols/WebView/src/stdafx.cxx b/protocols/WebView/src/stdafx.cxx
new file mode 100644
index 0000000000..1b563fc866
--- /dev/null
+++ b/protocols/WebView/src/stdafx.cxx
@@ -0,0 +1,18 @@
+/*
+Copyright (C) 2012-19 Miranda NG team (https://miranda-ng.org)
+
+This program is free software; you can redistribute it and/or
+modify it under the terms of the GNU General Public License
+as published by the Free Software Foundation version 2
+of the License.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "stdafx.h" \ No newline at end of file
diff --git a/protocols/WebView/src/stdafx.h b/protocols/WebView/src/stdafx.h
new file mode 100644
index 0000000000..91a1ac63c1
--- /dev/null
+++ b/protocols/WebView/src/stdafx.h
@@ -0,0 +1,36 @@
+#pragma once
+
+#include <windows.h>
+#include <shlwapi.h>
+#include <Richedit.h>
+#include <Commctrl.h>
+
+#include <ctype.h>
+#include <io.h>
+#include <locale.h>
+#include <process.h>
+#include <stdio.h>
+#include <string.h>
+#include <time.h>
+#include <wchar.h>
+
+#include <newpluginapi.h>
+#include <m_system.h>
+#include <m_clist.h>
+#include <m_clist.h>
+#include <m_database.h>
+#include <m_protocols.h>
+#include <m_protosvc.h>
+#include <m_button.h>
+#include <m_utils.h>
+#include <m_skin.h>
+#include <m_genmenu.h>
+#include <m_icolib.h>
+#include <m_options.h>
+#include <m_popup.h>
+#include <m_netlib.h>
+#include <m_langpack.h>
+#include <m_findadd.h>
+
+#include "resource.h"
+#include "version.h"
diff --git a/protocols/WebView/src/version.h b/protocols/WebView/src/version.h
new file mode 100644
index 0000000000..c2030de835
--- /dev/null
+++ b/protocols/WebView/src/version.h
@@ -0,0 +1,13 @@
+#define __MAJOR_VERSION 0
+#define __MINOR_VERSION 1
+#define __RELEASE_NUM 3
+#define __BUILD_NUM 2
+
+#include <stdver.h>
+
+#define __PLUGIN_NAME "Webview"
+#define __FILENAME "Webview.dll"
+#define __DESCRIPTION "Adds web pages as contacts to your contact list and can display text and/or issue change alerts from those pages in a window."
+#define __AUTHOR "Vincent Joyce"
+#define __AUTHORWEB "https://miranda-ng.org/p/WebView/"
+#define __COPYRIGHT "© 2011 Vincent Joyce"
diff --git a/protocols/WebView/src/webview.cpp b/protocols/WebView/src/webview.cpp
new file mode 100644
index 0000000000..87e5baf4a1
--- /dev/null
+++ b/protocols/WebView/src/webview.cpp
@@ -0,0 +1,481 @@
+/*
+* A plugin for Miranda IM which displays web page text in a window Copyright
+* (C) 2005 Vincent Joyce.
+*
+* Miranda IM: the free icq client for MS Windows Copyright (C) 2000-2
+* Richard Hughes, Roland Rabien & Tristan Van de Vreede
+*
+* 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.
+*/
+
+#include "stdafx.h"
+#include "webview.h"
+
+char* WndClass = "WEBWnd";
+WNDCLASSEX wincl;
+MSG messages;
+DWORD winheight;
+int StartUpDelay = 0;
+
+int Xposition, Yposition;
+int WindowHeight, WindowWidth;
+COLORREF BackgoundClr, TextClr;
+
+UINT_PTR timerId;
+UINT_PTR Countdown;
+LOGFONT g_lf;
+HFONT h_font;
+HMENU hMenu;
+int bpStatus;
+HGENMENU hMenuItem1;
+HGENMENU hMenuItemCountdown;
+
+/*****************************************************************************/
+void ChangeMenuItem1()
+{
+ // Enable or Disable auto updates
+ LPCTSTR ptszName;
+ if (!g_plugin.getByte(DISABLE_AUTOUPDATE_KEY, 0))
+ ptszName = LPGENW("Auto update enabled");
+ else
+ ptszName = LPGENW("Auto update disabled");
+
+ Menu_ModifyItem(hMenuItem1, ptszName, LoadIcon(g_plugin.getInst(), MAKEINTRESOURCE(IDI_SITE)));
+}
+
+/*****************************************************************************/
+void ChangeMenuItemCountdown()
+{
+ // countdown
+ HICON hIcon = LoadIcon(g_plugin.getInst(), MAKEINTRESOURCE(IDI_UPDATEALL));
+
+ wchar_t countername[100];
+ mir_snwprintf(countername, TranslateT("%d minutes to update"), g_plugin.getDword(COUNTDOWN_KEY, 0));
+
+ Menu_ModifyItem(hMenuItemCountdown, countername, hIcon, CMIF_KEEPUNTRANSLATED);
+}
+
+/*****************************************************************************/
+static int CALLBACK EnumFontsProc(ENUMLOGFONTEX *lpelfe, NEWTEXTMETRICEX*, int, LPARAM lParam)
+{
+ if (!IsWindow((HWND)lParam))
+ return FALSE;
+ if (SendMessage((HWND)lParam, CB_FINDSTRINGEXACT, -1, (LPARAM)lpelfe->elfLogFont.lfFaceName) == CB_ERR)
+ SendMessage((HWND)lParam, CB_ADDSTRING, 0, (LPARAM)lpelfe->elfLogFont.lfFaceName);
+ return TRUE;
+}
+
+void FillFontListThread(void *param)
+{
+ HDC hdc = GetDC((HWND)param);
+
+ LOGFONT lf = { 0 };
+ g_lf.lfCharSet = DEFAULT_CHARSET;
+ g_lf.lfFaceName[0] = 0;
+ g_lf.lfPitchAndFamily = 0;
+ EnumFontFamiliesEx(hdc, &lf, (FONTENUMPROC)EnumFontsProc, (LPARAM)GetDlgItem((HWND)param, IDC_TYPEFACE), 0);
+ ReleaseDC((HWND)param, hdc);
+}
+
+/*****************************************************************************/
+void TxtclrLoop()
+{
+ for (auto &hContact : Contacts(MODULENAME)) {
+ HWND hwndDlg = WindowList_Find(hWindowList, hContact);
+ SetDlgItemText(hwndDlg, IDC_DATA, L"");
+ InvalidateRect(hwndDlg, nullptr, 1);
+ }
+}
+
+/*****************************************************************************/
+void BGclrLoop()
+{
+ for (auto &hContact : Contacts(MODULENAME)) {
+ HWND hwndDlg = (WindowList_Find(hWindowList, hContact));
+ SetDlgItemText(hwndDlg, IDC_DATA, L"");
+ SendDlgItemMessage(hwndDlg, IDC_DATA, EM_SETBKGNDCOLOR, 0, BackgoundClr);
+ InvalidateRect(hwndDlg, nullptr, 1);
+ }
+}
+
+/*****************************************************************************/
+void StartUpdate(void*)
+{
+ StartUpDelay = 1;
+ Sleep(((g_plugin.getDword(START_DELAY_KEY, 0)) * SECOND));
+
+ for (auto &hContact : Contacts(MODULENAME))
+ GetData((void*)hContact);
+
+ StartUpDelay = 0;
+}
+
+/*****************************************************************************/
+void ContactLoop(void*)
+{
+ if (StartUpDelay == 0) {
+ for (auto &hContact : Contacts(MODULENAME)) {
+ GetData((void*)hContact);
+ Sleep(10); // avoid 100% CPU
+ }
+ }
+
+ WAlertPopup(NULL, TranslateT("All Webview sites have been updated."));
+}
+
+/*****************************************************************************/
+INT_PTR MarkAllReadMenuCommand(WPARAM, LPARAM)
+{
+ ChangeContactStatus(1);
+ return 0;
+}
+
+/*****************************************************************************/
+void InitialiseGlobals(void)
+{
+ Xposition = g_plugin.getDword(Xpos_WIN_KEY, 0);
+ Yposition = g_plugin.getDword(Ypos_WIN_KEY, 0);
+
+ if (Yposition == -32000)
+ Yposition = 100;
+
+ if (Xposition == -32000)
+ Xposition = 100;
+
+ BackgoundClr = g_plugin.getDword(BG_COLOR_KEY, Def_color_bg);
+ TextClr = g_plugin.getDword(TXT_COLOR_KEY, Def_color_txt);
+
+ WindowHeight = g_plugin.getDword(WIN_HEIGHT_KEY, Def_win_height);
+ WindowWidth = g_plugin.getDword(WIN_WIDTH_KEY, Def_win_width);
+}
+
+/*****************************************************************************/
+int Doubleclick(WPARAM wParam, LPARAM)
+{
+ MCONTACT hContact = wParam;
+ char *szProto = GetContactProto(hContact);
+ if (mir_strcmp(MODULENAME, szProto))
+ return 0;
+
+ int action = g_plugin.getByte(hContact, DBLE_WIN_KEY, 1);
+ if (action == 0) {
+ ptrW url(g_plugin.getWStringA(hContact, "URL"));
+ Utils_OpenUrlW(url);
+
+ g_plugin.setWord(hContact, "Status", ID_STATUS_ONLINE);
+ }
+ else if (action == 1) {
+ HWND hwndDlg = WindowList_Find(hWindowList, hContact);
+ if (hwndDlg) {
+ SetForegroundWindow(hwndDlg);
+ SetFocus(hwndDlg);
+ }
+ else {
+ hwndDlg = CreateDialogParam(g_plugin.getInst(), MAKEINTRESOURCE(IDD_DISPLAY_DATA), nullptr, DlgProcDisplayData, (LPARAM)hContact);
+ HWND hTopmost = g_plugin.getByte(hContact, ON_TOP_KEY, 0) ? HWND_TOPMOST : HWND_NOTOPMOST;
+ SendDlgItemMessage(hwndDlg, IDC_STICK_BUTTON, BM_SETIMAGE, IMAGE_ICON, (LPARAM)((HICON)LoadImage(g_plugin.getInst(), MAKEINTRESOURCE(IDI_STICK), IMAGE_ICON, GetSystemMetrics(SM_CXSMICON), GetSystemMetrics(SM_CYSMICON), 0)));
+
+ if (g_plugin.getByte(SAVE_INDIVID_POS_KEY, 0))
+ SetWindowPos(hwndDlg, hTopmost,
+ g_plugin.getDword(hContact, "WVx", 100), // Xposition,
+ g_plugin.getDword(hContact, "WVy", 100), // Yposition,
+ g_plugin.getDword(hContact, "WVwidth", 412), // WindowWidth,
+ g_plugin.getDword(hContact, "WVheight", 350), 0); // WindowHeight,
+ else
+ SetWindowPos(hwndDlg, HWND_TOPMOST, Xposition, Yposition, WindowWidth, WindowHeight, 0);
+ }
+
+ ShowWindow(hwndDlg, SW_SHOW);
+ SetActiveWindow(hwndDlg);
+
+ if (g_plugin.getByte(UPDATE_ON_OPEN_KEY, 0)) {
+ if (g_plugin.getByte(hContact, ENABLE_ALERTS_KEY, 0))
+ mir_forkthread(ReadFromFile, (void*)hContact);
+ else
+ mir_forkthread(GetData, (void*)hContact);
+ g_plugin.setWord(hContact, "Status", ID_STATUS_ONLINE);
+ }
+ }
+
+ return 1;
+}
+
+/*****************************************************************************/
+int SendToRichEdit(HWND hWindow, char *truncated, COLORREF rgbText, COLORREF rgbBack)
+{
+ DBVARIANT dbv;
+ DWORD bold = 0;
+ DWORD italic = 0;
+ DWORD underline = 0;
+
+ SetDlgItemText(hWindow, IDC_DATA, L"");
+
+ CHARFORMAT2 cfFM;
+ memset(&cfFM, 0, sizeof(cfFM));
+ cfFM.cbSize = sizeof(CHARFORMAT2);
+ cfFM.dwMask = CFM_COLOR | CFM_CHARSET | CFM_FACE | ENM_LINK | ENM_MOUSEEVENTS | CFM_BOLD | CFM_ITALIC | CFM_UNDERLINE | CFM_SIZE;
+
+ if (g_plugin.getByte(FONT_BOLD_KEY, 0))
+ bold = CFE_BOLD;
+
+ if (g_plugin.getByte(FONT_ITALIC_KEY, 0))
+ italic = CFE_ITALIC;
+
+ if (g_plugin.getByte(FONT_UNDERLINE_KEY, 0))
+ underline = CFE_UNDERLINE;
+
+ cfFM.dwEffects = bold | italic | underline;
+
+ if (!g_plugin.getWString(FONT_FACE_KEY, &dbv)) {
+ mir_wstrcpy(cfFM.szFaceName, dbv.pwszVal);
+ db_free(&dbv);
+ }
+ else mir_wstrcpy(cfFM.szFaceName, Def_font_face);
+
+ HDC hDC = GetDC(hWindow);
+ cfFM.yHeight = (BYTE)MulDiv(abs(g_lf.lfHeight), 120, GetDeviceCaps(GetDC(hWindow), LOGPIXELSY)) * (g_plugin.getByte(FONT_SIZE_KEY, 14));
+ ReleaseDC(hWindow, hDC);
+
+ cfFM.bCharSet = g_plugin.getByte(FONT_SCRIPT_KEY, 0);
+ cfFM.bPitchAndFamily = DEFAULT_PITCH | FF_DONTCARE;
+ cfFM.crTextColor = rgbText;
+ cfFM.crBackColor = rgbBack;
+ SendDlgItemMessage(hWindow, IDC_DATA, EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM)& cfFM);
+
+ SendDlgItemMessage(hWindow, IDC_DATA, EM_SETSEL, 0, -1);
+ SendDlgItemMessageA(hWindow, IDC_DATA, EM_REPLACESEL, FALSE, (LPARAM)truncated);
+ SendDlgItemMessage(hWindow, IDC_DATA, EM_SETCHARFORMAT, SCF_ALL, (LPARAM)&cfFM);
+ return 1;
+}
+
+/*****************************************************************************/
+void CALLBACK timerfunc(HWND, UINT, UINT_PTR, DWORD)
+{
+ g_plugin.setByte(HAS_CRASHED_KEY, 0);
+
+ if (!(g_plugin.getByte(OFFLINE_STATUS, 1)))
+ if (!(g_plugin.getByte(DISABLE_AUTOUPDATE_KEY, 0)))
+ mir_forkthread(ContactLoop);
+
+ g_plugin.setDword(COUNTDOWN_KEY, 0);
+}
+
+/*****************************************************************************/
+void CALLBACK Countdownfunc(HWND, UINT, UINT_PTR, DWORD)
+{
+ DWORD timetemp = g_plugin.getDword(COUNTDOWN_KEY, 100);
+ if (timetemp <= 0) {
+ timetemp = g_plugin.getDword(REFRESH_KEY, TIME);
+ g_plugin.setDword(COUNTDOWN_KEY, timetemp);
+ }
+
+ g_plugin.setDword(COUNTDOWN_KEY, timetemp - 1);
+
+ ChangeMenuItemCountdown();
+}
+
+/*****************************************************************************/
+
+int OptInitialise(WPARAM wParam, LPARAM)
+{
+ OPTIONSDIALOGPAGE odp = {};
+ odp.pszTemplate = MAKEINTRESOURCEA(IDD_OPT);
+ odp.szGroup.a = LPGEN("Network");
+ odp.szTitle.a = MODULENAME;
+ odp.pfnDlgProc = DlgProcOpt;
+ odp.flags = ODPF_BOLDGROUPS;
+ g_plugin.addOptions(wParam, &odp);
+
+ // if popup service exists
+ if ((ServiceExists(MS_POPUP_ADDPOPUPW))) {
+ odp.pszTemplate = MAKEINTRESOURCEA(IDD_POPUP);
+ odp.szGroup.a = LPGEN("Popups");
+ odp.pfnDlgProc = DlgPopUpOpts;
+ g_plugin.addOptions(wParam, &odp);
+ }
+ return 0;
+}
+
+/*****************************************************************************/
+void FontSettings(void)
+{
+ g_lf.lfHeight = 16;
+ g_lf.lfWidth = 0;
+ g_lf.lfEscapement = 0;
+ g_lf.lfOrientation = 0;
+ g_lf.lfWeight = FW_NORMAL;
+ g_lf.lfItalic = FALSE;
+ g_lf.lfUnderline = FALSE;
+ g_lf.lfStrikeOut = 0;
+ g_lf.lfCharSet = ANSI_CHARSET;
+ g_lf.lfOutPrecision = OUT_DEFAULT_PRECIS;
+ g_lf.lfClipPrecision = CLIP_DEFAULT_PRECIS;
+ g_lf.lfQuality = DEFAULT_QUALITY;
+ g_lf.lfPitchAndFamily = FIXED_PITCH | FF_MODERN;
+ mir_wstrcpy(g_lf.lfFaceName, Def_font_face);
+}
+
+/*****************************************************************************/
+int ModulesLoaded(WPARAM, LPARAM)
+{
+ hHookDisplayDataAlert = CreateHookableEvent(ME_DISPLAYDATA_ALERT);
+ HookEvent(ME_DISPLAYDATA_ALERT, DataWndAlertCommand);
+
+ hHookAlertPopup = CreateHookableEvent(ME_POPUP_ALERT);
+ HookEvent(ME_POPUP_ALERT, PopupAlert);
+
+ hHookErrorPopup = CreateHookableEvent(ME_POPUP_ERROR);
+ HookEvent(ME_POPUP_ERROR, ErrorMsgs);
+
+ hHookAlertOSD = CreateHookableEvent(ME_OSD_ALERT);
+ HookEvent(ME_OSD_ALERT, OSDAlert);
+
+ FontSettings();
+ h_font = CreateFontIndirect(&g_lf);
+
+ // get data on startup
+ if (g_plugin.getByte(UPDATE_ONSTART_KEY, 0))
+ mir_forkthread(StartUpdate);
+
+ return 0;
+}
+
+/*****************************************************************************/
+INT_PTR DataWndMenuCommand(WPARAM wParam, LPARAM)
+{
+ MCONTACT hContact = wParam;
+ HWND hwndDlg = WindowList_Find(hWindowList, hContact);
+ if (hwndDlg != nullptr) {
+ DestroyWindow(hwndDlg);
+ return 0;
+ }
+
+ HWND hTopmost = g_plugin.getByte(hContact, ON_TOP_KEY, 0) ? HWND_TOPMOST : HWND_NOTOPMOST;
+ hwndDlg = CreateDialogParam(g_plugin.getInst(), MAKEINTRESOURCE(IDD_DISPLAY_DATA), nullptr, DlgProcDisplayData, (LPARAM)hContact);
+ SendDlgItemMessage(hwndDlg, IDC_STICK_BUTTON, BM_SETIMAGE, IMAGE_ICON, (LPARAM)LoadImage(g_plugin.getInst(), MAKEINTRESOURCE(IDI_STICK), IMAGE_ICON, GetSystemMetrics(SM_CXSMICON), GetSystemMetrics(SM_CYSMICON), 0));
+ if (g_plugin.getByte(SAVE_INDIVID_POS_KEY, 0))
+ SetWindowPos(hwndDlg, hTopmost,
+ g_plugin.getDword(hContact, "WVx", 100), // Xposition,
+ g_plugin.getDword(hContact, "WVy", 100), // Yposition,
+ g_plugin.getDword(hContact, "WVwidth", 100), // WindowWidth,
+ g_plugin.getDword(hContact, "WVheight", 100), 0); // WindowHeight,
+ else
+ SetWindowPos(hwndDlg, HWND_TOPMOST, Xposition, Yposition, WindowWidth, WindowHeight, 0);
+
+ ShowWindow(hwndDlg, SW_SHOW);
+ SetActiveWindow(hwndDlg);
+
+ if (g_plugin.getByte(UPDATE_ON_OPEN_KEY, 0)) {
+ if (g_plugin.getByte(hContact, ENABLE_ALERTS_KEY, 0))
+ mir_forkthread(ReadFromFile, (void*)hContact);
+ else
+ mir_forkthread(GetData, (void*)hContact);
+ g_plugin.setWord(hContact, "Status", ID_STATUS_ONLINE);
+ }
+
+ return 0;
+}
+
+/*****************************************************************************/
+INT_PTR UpdateAllMenuCommand(WPARAM, LPARAM)
+{
+ mir_forkthread(ContactLoop);
+ return 0;
+}
+
+/*****************************************************************************/
+INT_PTR AutoUpdateMCmd(WPARAM, LPARAM)
+{
+ if (g_plugin.getByte(DISABLE_AUTOUPDATE_KEY, 0))
+ g_plugin.setByte(DISABLE_AUTOUPDATE_KEY, 0);
+ else
+ g_plugin.setByte(DISABLE_AUTOUPDATE_KEY, 1);
+
+ ChangeMenuItem1();
+ return 0;
+}
+
+/*****************************************************************************/
+INT_PTR AddContactMenuCommand(WPARAM, LPARAM)
+{
+ db_set_s(0, "FindAdd", "LastSearched", MODULENAME);
+ CallService(MS_FINDADD_FINDADD, 0, 0);
+ return 0;
+}
+
+/*****************************************************************************/
+int OnTopMenuCommand(WPARAM, LPARAM, MCONTACT singlecontact)
+{
+ int ontop = 0;
+ int done = 0;
+
+ if (((g_plugin.getByte(singlecontact, ON_TOP_KEY))) && done == 0) {
+ g_plugin.setByte(singlecontact, ON_TOP_KEY, 0);
+ ontop = 0;
+ done = 1;
+ }
+ if ((!(g_plugin.getByte(singlecontact, ON_TOP_KEY, 0))) && done == 0) {
+ g_plugin.setByte(singlecontact, ON_TOP_KEY, 1);
+ ontop = 1;
+ done = 1;
+ }
+ return 0;
+}
+
+/*****************************************************************************/
+INT_PTR WebsiteMenuCommand(WPARAM wParam, LPARAM)
+{
+ MCONTACT hContact = wParam;
+ ptrW url(g_plugin.getWStringA(hContact, "URL"));
+ if (url)
+ Utils_OpenUrlW(url);
+
+ g_plugin.setWord(hContact, "Status", ID_STATUS_ONLINE);
+ return 0;
+}
+
+/*****************************************************************************/
+int UpdateMenuCommand(WPARAM, LPARAM, MCONTACT singlecontact)
+{
+ mir_forkthread(GetData, (void*)singlecontact);
+ return 0;
+}
+
+/*****************************************************************************/
+int ContactMenuItemUpdateData(WPARAM wParam, LPARAM lParam)
+{
+ UpdateMenuCommand(wParam, lParam, wParam);
+ return 0;
+}
+
+/*****************************************************************************/
+INT_PTR CntOptionsMenuCommand(WPARAM wParam, LPARAM)
+{
+ DialogBoxParam(g_plugin.getInst(), MAKEINTRESOURCE(IDD_CONTACT_OPT), nullptr, DlgProcContactOpt, wParam);
+ return 0;
+}
+
+/*****************************************************************************/
+INT_PTR CntAlertMenuCommand(WPARAM wParam, LPARAM)
+{
+ DialogBoxParam(g_plugin.getInst(), MAKEINTRESOURCE(IDD_ALRT_OPT), nullptr, DlgProcAlertOpt, wParam);
+ return 0;
+}
+
+/*****************************************************************************/
+INT_PTR CountdownMenuCommand(WPARAM, LPARAM)
+{
+ return 0;
+}
diff --git a/protocols/WebView/src/webview.h b/protocols/WebView/src/webview.h
new file mode 100644
index 0000000000..e7bdd6c57b
--- /dev/null
+++ b/protocols/WebView/src/webview.h
@@ -0,0 +1,254 @@
+/*
+ * A plugin for Miranda IM which displays web page text in a window Copyright
+ * (C) 2005 Vincent Joyce.
+ *
+ * Miranda IM: the free icq client for MS Windows Copyright (C) 2000-2
+ * Richard Hughes, Roland Rabien & Tristan Van de Vreede
+ *
+ * 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.
+ */
+
+#pragma once
+
+#define CFM_BACKCOLOR 0x04000000
+
+#define MODULENAME "WebView"
+
+#define MENU_OFF "DisableMenu"
+#define REFRESH_KEY "Refresh interval"
+#define ON_TOP_KEY "Always on top"
+#define OFFLINE_STATUS "OfflineOnBoot"
+#define URL_KEY "URL"
+#define START_STRING_KEY "Start_string"
+#define END_STRING_KEY "End_String"
+#define DBLE_WIN_KEY "Doub_click_win"
+#define HIDE_STATUS_ICON_KEY "Hide_Status_Icon"
+#define HAS_CRASHED_KEY "Has_Crashed"
+#define U_ALLSITE_KEY "UseAllTheWebsite"
+#define MENU_IS_DISABLED_KEY "MainMenuReallyDisabled"
+#define UPDATE_ONALERT_KEY "WND_UPDATE_OALERY_ONLY"
+#define DISABLE_AUTOUPDATE_KEY "Disable_Auto_Update"
+#define RWSPACE_KEY "level_of_wspace_removal"
+#define PRESERVE_NAME_KEY "PreserveName"
+#define CLEAR_DISPLAY_KEY "Remove_tags_whitespace"
+#define ALRT_S_STRING_KEY "ALRT_S_STRING"
+#define ALRT_E_STRING_KEY "ALRT_E_STRING"
+#define ALRT_INDEX_KEY "AlertIndex"
+#define EVNT_INDEX_KEY "EventIndex"
+#define START_DELAY_KEY "StartUpDelay"
+#define ALWAYS_LOG_KEY "AlwaysLogToFile"
+#define SAVE_INDIVID_POS_KEY "SaveIndividWinPos"
+#define NO_PROTECT_KEY "NoDownloadProtection"
+#define SAVE_AS_RAW_KEY "SaveAsRaw"
+#define FONT_SCRIPT_KEY "FontScript"
+#define STOP_KEY "StopProcessing"
+#define DATA_POPUP_KEY "DisplayDataPopup"
+#define COUNTDOWN_KEY "Countdown"
+
+#define MINUTE 60000
+#define SECOND 1000
+
+#define MS_UPDATE_ALL "Webview/UpdateAll"
+#define MS_ADD_SITE "Webview/AddSite"
+#define MS_AUTO_UPDATE "Webview/AutoUpdate"
+
+#define CACHE_FILE_KEY "Filename"
+
+#define Xpos_WIN_KEY "win_Xpos"
+#define Ypos_WIN_KEY "win_Ypos"
+#define BG_COLOR_KEY "BgColor"
+#define TXT_COLOR_KEY "TxtColor"
+#define WIN_HEIGHT_KEY "Height"
+#define SUPPRESS_ERR_KEY "Suppress error messages"
+#define WIN_WIDTH_KEY "Width"
+#define FILE_KEY "Filename"
+#define APPEND_KEY "Append"
+#define UPDATE_ONSTART_KEY "update_onboot"
+#define UPDATE_ON_OPEN_KEY "update_on_Window_open"
+#define FONT_FACE_KEY "FontFace"
+#define FONT_BOLD_KEY "FontBold"
+#define FONT_ITALIC_KEY "FontItalic"
+#define FONT_UNDERLINE_KEY "FontUnderline"
+#define FONT_SIZE_KEY "FontSize"
+#define ERROR_POPUP_KEY "UsePopupPlugin"
+#define ENABLE_ALERTS_KEY "EnableAlerts"
+#define ALERT_STRING_KEY "ALERTSTRING"
+#define ALERT_TYPE_KEY "Alert_Type"
+#define APND_DATE_NAME_KEY "AppendDateContact"
+#define POP_DELAY_KEY "PopUpDelay"
+#define POP_BG_CLR_KEY "PopBGClr"
+#define POP_TXT_CLR_KEY "PopTxtClr"
+#define POP_USEWINCLRS_KEY "PopUseWinClrs"
+#define CONTACT_PREFIX_KEY "PrefixDateContact"
+#define USE_24_HOUR_KEY "Use24hourformat"
+#define POP_USESAMECLRS_KEY "PopUseSameClrs"
+#define POP_USECUSTCLRS_KEY "PopUseCustomClrs"
+#define LCLK_WINDOW_KEY "LeftClkWindow"
+#define LCLK_WEB_PGE_KEY "LeftClkWebPage"
+#define LCLK_DISMISS_KEY "LeftClkDismiss"
+#define RCLK_WINDOW_KEY "RightClkWindow"
+#define RCLK_WEB_PGE_KEY "RightClkWebPage"
+#define RCLK_DISMISS_KEY "RightClkDismiss"
+
+#define TIME 60
+#define Def_color_bg 0x00ffffff
+#define Def_color_txt 0x00000000
+#define Def_font_face L"Courier"
+#define Def_font_size 14
+#define HK_SHOWHIDE 3001
+
+#define MAXSIZE1 250000
+#define MAXSIZE2 500000
+#define MAXSIZE3 1000000
+
+#define Def_win_height 152
+#define Def_win_width 250
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// lets get rid of some warnings
+
+void CodetoSymbol(char *truncated);
+void GetData(void *param);
+void FillFontListThread(void *);
+
+INT_PTR CALLBACK DlgProcDisplayData(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam);
+INT_PTR CALLBACK DlgProcAlertOpt(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam);
+INT_PTR CALLBACK DlgProcOpt(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam);
+
+int DataWndAlertCommand(WPARAM wParam, LPARAM lParam);
+int PopupAlert(WPARAM wParam, LPARAM lParam);
+int ErrorMsgs(WPARAM wParam, LPARAM lParam);
+int OSDAlert(WPARAM wParam, LPARAM lParam);
+
+void ReadFromFile(void *hContact);
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// some globals for window settings
+
+extern int Xposition, Yposition, WindowHeight, WindowWidth;
+extern COLORREF BackgoundClr, TextClr;
+extern UINT_PTR timerId, Countdown;
+extern LOGFONT g_lf;
+extern HFONT h_font;
+extern HMENU hMenu;
+extern int bpStatus;
+extern HNETLIBUSER hNetlibUser;
+extern MWindowList hWindowList;
+extern HGENMENU hMenuItem1, hMenuItemCountdown;
+extern char optionsname[80];
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// lets get rid of some warnings
+
+void CALLBACK timerfunc(HWND, UINT, UINT_PTR, DWORD);
+void CALLBACK Countdownfunc(HWND, UINT, UINT_PTR, DWORD);
+void SavewinSettings(void);
+void ValidatePosition(HWND hwndDlg);
+int ModulesLoaded(WPARAM wParam, LPARAM lParam);
+wchar_t* FixButtonText(wchar_t *url, size_t len);
+int ContactMenuItemUpdateData (WPARAM wParam, LPARAM lParam);
+
+int Doubleclick(WPARAM wParam, LPARAM lParam);
+int DBSettingChanged(WPARAM wParam, LPARAM lParam);
+
+int SendToRichEdit(HWND hWindow, char *truncated, COLORREF rgbText, COLORREF rgbBack);
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// Services
+
+INT_PTR GetCaps(WPARAM wParam, LPARAM lParam);
+INT_PTR GetName(WPARAM wParam, LPARAM lParam);
+INT_PTR BPLoadIcon(WPARAM wParam, LPARAM lParam); // BPLoadIcon
+
+INT_PTR SetStatus(WPARAM wParam, LPARAM lParam);
+INT_PTR GetStatus(WPARAM wParam, LPARAM lParam);
+
+INT_PTR BasicSearch(WPARAM wParam, LPARAM lParam);
+INT_PTR AddToList(WPARAM wParam, LPARAM lParam);
+INT_PTR GetInfo(WPARAM wParam, LPARAM lParam);
+
+INT_PTR OpenCacheDir(WPARAM wParam, LPARAM lParam);
+
+INT_PTR UpdateAllMenuCommand(WPARAM wParam, LPARAM lParam);
+INT_PTR CountdownMenuCommand(WPARAM wParam, LPARAM lParam);
+INT_PTR MarkAllReadMenuCommand(WPARAM wParam, LPARAM lParam);
+INT_PTR WebsiteMenuCommand(WPARAM wParam, LPARAM lParam);
+INT_PTR AddContactMenuCommand(WPARAM wParam, LPARAM lParam);
+INT_PTR CntOptionsMenuCommand(WPARAM wParam, LPARAM lParam);
+INT_PTR CntAlertMenuCommand(WPARAM wParam, LPARAM lParam);
+INT_PTR DataWndMenuCommand(WPARAM wParam, LPARAM lParam);
+INT_PTR PingWebsiteMenuCommand(WPARAM wParam, LPARAM lParam);
+INT_PTR StpPrcssMenuCommand(WPARAM wParam, LPARAM lParam);
+
+int UpdateMenuCommand(WPARAM wParam, LPARAM lParam, MCONTACT singlecontact);
+int OnTopMenuCommand(WPARAM wParam, LPARAM lParam, MCONTACT singlecontact);
+
+/////////////////////////////////////////////////////////////////////////////////////////
+void ChangeContactStatus(int con_stat);
+void InitialiseGlobals(void);
+void FontSettings(void);
+
+/////////////////////////////////////////////////////////////////////////////////////////
+
+void Removewhitespace(char *truncated);
+void RemoveInvis(char *truncated, int AmountWspcRem);
+void RemoveTabs(char *truncated);
+void FastTagFilter(char *truncated);
+void EraseBlock(char *truncated);
+void EraseSymbols(char *truncated);
+int ProcessAlerts(MCONTACT hContact, char *truncated, char *tstr, char *contactname, int notpresent);
+
+INT_PTR CALLBACK DlgPopUpOpts(HWND hdlg, UINT msg, WPARAM wParam, LPARAM lParam);
+INT_PTR CALLBACK DlgProcFind(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam);
+int DataDialogResize(HWND hwndDlg, LPARAM lParam, UTILRESIZECONTROL * urc);
+int OptInitialise(WPARAM, LPARAM);
+
+void Filter(char *truncated);
+void TxtclrLoop();
+void BGclrLoop();
+void ContactLoop(void *dummy);
+void NumSymbols(char *truncated);
+
+INT_PTR AutoUpdateMCmd(WPARAM wParam, LPARAM lParam);
+INT_PTR CALLBACK DlgProcContactOpt(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam);
+int SiteDeleted(WPARAM wParam, LPARAM lParam);
+
+int WErrorPopup(MCONTACT hContact, wchar_t *textdisplay);
+int WAlertPopup(MCONTACT hContact, wchar_t *displaytext);
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// wrappers
+
+extern HANDLE hHookDisplayDataAlert;
+#define ME_DISPLAYDATA_ALERT "Miranda/ALERT/DISPLAYDATA"
+
+extern HANDLE hHookAlertPopup;
+#define ME_POPUP_ALERT "Miranda/ALERT/POPUP"
+
+extern HANDLE hHookErrorPopup;
+#define ME_POPUP_ERROR "Miranda/ERROR/POPUP"
+
+extern HANDLE hHookAlertOSD;
+#define ME_OSD_ALERT "Miranda/ALERT/OSD"
+
+/////////////////////////////////////////////////////////////////////////////////////////
+
+struct CMPlugin : public PLUGIN<CMPlugin>
+{
+ CMPlugin();
+
+ int Load() override;
+ int Unload() override;
+};
diff --git a/protocols/WebView/src/webview_alerts.cpp b/protocols/WebView/src/webview_alerts.cpp
new file mode 100644
index 0000000000..1b068f099e
--- /dev/null
+++ b/protocols/WebView/src/webview_alerts.cpp
@@ -0,0 +1,839 @@
+/*
+* A plugin for Miranda IM which displays web page text in a window Copyright
+* (C) 2005 Vincent Joyce.
+*
+* Miranda IM: the free icq client for MS Windows Copyright (C) 2000-2
+* Richard Hughes, Roland Rabien & Tristan Van de Vreede
+*
+* 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.
+*/
+
+#include "stdafx.h"
+#include "webview.h"
+
+/*****************************************************************************/
+int CALLBACK PopupDlgProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
+{
+ switch (message) {
+ case WM_COMMAND:
+ case WM_CONTEXTMENU:
+ MCONTACT hContact = PUGetContact(hWnd);
+ ptrW url(g_plugin.getWStringA(hContact, URL_KEY));
+
+ if (message == WM_COMMAND) { // left click
+ if (hContact != NULL) {
+ // open data window
+ if (g_plugin.getByte(LCLK_WINDOW_KEY, 0)) {
+ NotifyEventHooks(hHookDisplayDataAlert, (int)hContact, 0);
+ mir_forkthread(GetData, (void*)hContact);
+ PUDeletePopup(hWnd);
+ }
+ // open url
+ if (g_plugin.getByte(LCLK_WEB_PGE_KEY, 0)) {
+ Utils_OpenUrlW(url);
+ PUDeletePopup(hWnd);
+ g_plugin.setWord(wParam, "Status", ID_STATUS_ONLINE);
+ }
+ // dismiss
+ if (g_plugin.getByte(LCLK_DISMISS_KEY, 1))
+ PUDeletePopup(hWnd);
+ }
+ else if (hContact == NULL)
+ PUDeletePopup(hWnd);
+ }
+ else if (message == WM_CONTEXTMENU) { // right click
+ if (hContact != NULL) {
+ // open datA window
+ if (g_plugin.getByte(RCLK_WINDOW_KEY, 0)) {
+ NotifyEventHooks(hHookDisplayDataAlert, (int)hContact, 0);
+ mir_forkthread(GetData, (void*)hContact);
+ PUDeletePopup(hWnd);
+ }
+ // open url
+ if (g_plugin.getByte(RCLK_WEB_PGE_KEY, 1)) {
+ Utils_OpenUrlW(url);
+ PUDeletePopup(hWnd);
+ g_plugin.setWord(wParam, "Status", ID_STATUS_ONLINE);
+ }
+ // dismiss
+ if (g_plugin.getByte(RCLK_DISMISS_KEY, 0))
+ PUDeletePopup(hWnd);
+ }
+ else if (hContact == NULL)
+ PUDeletePopup(hWnd);
+ }
+ break;
+ }
+
+ return DefWindowProc(hWnd, message, wParam, lParam);
+}
+
+/*****************************************************************************/
+int WDisplayDataAlert(MCONTACT hContact)
+{
+ NotifyEventHooks(hHookDisplayDataAlert, hContact, 0);
+ return 0;
+}
+
+/*****************************************************************************/
+int WAlertPopup(MCONTACT hContact, wchar_t *displaytext)
+{
+ NotifyEventHooks(hHookAlertPopup, hContact, (LPARAM)displaytext);
+ return 0;
+}
+
+/*****************************************************************************/
+int WErrorPopup(MCONTACT hContact, wchar_t *textdisplay)
+{
+ NotifyEventHooks(hHookErrorPopup, hContact, (LPARAM)textdisplay);
+ return 0;
+}
+
+/*****************************************************************************/
+int WAlertOSD(MCONTACT hContact, wchar_t *displaytext)
+{
+ NotifyEventHooks(hHookAlertOSD, hContact, (LPARAM)displaytext);
+ return 0;
+}
+
+/*****************************************************************************/
+int PopupAlert(WPARAM hContact, LPARAM lParam)
+{
+ POPUPDATAW ppd = { 0 };
+
+ if (hContact != 0)
+ mir_wstrncpy(ppd.lpwzContactName, ptrW(g_plugin.getWStringA(hContact, PRESERVE_NAME_KEY)), _countof(ppd.lpwzContactName));
+ else
+ mir_wstrcpy(ppd.lpwzContactName, _A2W(MODULENAME));
+
+ ppd.lchContact = hContact;
+ ppd.lchIcon = LoadIcon(g_plugin.getInst(), MAKEINTRESOURCE(IDI_SITE));
+
+ wchar_t *displaytext = (wchar_t*)lParam;
+ if ((mir_wstrlen(displaytext) == MAX_SECONDLINE) || (mir_wstrlen(displaytext) > MAX_SECONDLINE))
+ mir_snwprintf(ppd.lpwzText, displaytext);
+ else if (mir_wstrlen(displaytext) < MAX_SECONDLINE)
+ mir_snwprintf(ppd.lpwzText, displaytext);
+
+ if (g_plugin.getByte(POP_USECUSTCLRS_KEY, 0)) {
+ ppd.colorBack = g_plugin.getDword(POP_BG_CLR_KEY, Def_color_bg);
+ ppd.colorText = g_plugin.getDword(POP_TXT_CLR_KEY, Def_color_txt);
+ }
+ else if (g_plugin.getByte(POP_USEWINCLRS_KEY, 0)) {
+ ppd.colorBack = GetSysColor(COLOR_BTNFACE);
+ ppd.colorText = GetSysColor(COLOR_WINDOWTEXT);
+ }
+ else if (g_plugin.getByte(POP_USESAMECLRS_KEY, 1)) {
+ ppd.colorBack = BackgoundClr;
+ ppd.colorText = TextClr;
+ }
+
+ ppd.PluginWindowProc = nullptr;
+ ppd.iSeconds = g_plugin.getDword(POP_DELAY_KEY, 0);
+
+ if (ServiceExists(MS_POPUP_ADDPOPUPW))
+ CallService(MS_POPUP_ADDPOPUPW, (WPARAM)&ppd, 0);
+
+ return 0;
+}
+
+/*****************************************************************************/
+int OSDAlert(WPARAM hContact, LPARAM lParam)
+{
+ char contactname[255], newdisplaytext[2000];
+ contactname[0] = 0;
+
+ if (hContact != NULL) {
+ DBVARIANT dbv;
+ if (!g_plugin.getString(hContact, PRESERVE_NAME_KEY, &dbv)) {
+ strncpy_s(contactname, _countof(contactname), dbv.pszVal, _TRUNCATE);
+ db_free(&dbv);
+ }
+ }
+ if (contactname[0] == 0)
+ strncpy_s(contactname, _countof(contactname), MODULENAME, _TRUNCATE);
+
+ char *displaytext = (char*)lParam;
+ mir_snprintf(newdisplaytext, "%s: %s", contactname, Translate(displaytext));
+
+ if (ServiceExists("OSD/Announce"))
+ CallService("OSD/Announce", (WPARAM)newdisplaytext, 0);
+
+ return 0;
+}
+
+/*****************************************************************************/
+int ErrorMsgs(WPARAM wParam, LPARAM lParam)
+{
+ MCONTACT hContact = wParam;
+ wchar_t newdisplaytext[2000], *displaytext = (wchar_t*)lParam;
+
+ if (g_plugin.getByte(SUPPRESS_ERR_KEY, 0))
+ return 0;
+
+ wchar_t *ptszContactName = Clist_GetContactDisplayName(hContact);
+ if (ServiceExists(MS_POPUP_ADDPOPUPW) && g_plugin.getByte(ERROR_POPUP_KEY, 0)) {
+ mir_snwprintf(newdisplaytext, L"%s\n%s", ptszContactName, displaytext);
+ PUShowMessageW(newdisplaytext, SM_WARNING);
+ }
+ else if (ServiceExists("OSD/Announce") && g_plugin.getByte(ERROR_POPUP_KEY, 0)) {
+ mir_snwprintf(newdisplaytext, L"%s: %s", ptszContactName, TranslateW(displaytext));
+ CallService("OSD/Announce", (WPARAM)newdisplaytext, 0);
+ }
+
+ Clist_TrayNotifyW(nullptr, ptszContactName, TranslateW(displaytext), NIIF_ERROR, 15000);
+ return 0;
+}
+
+/*****************************************************************************/
+void SaveToFile(MCONTACT hContact, char *truncated)
+{
+ char *mode;
+ if (!g_plugin.getByte(hContact, APPEND_KEY, 0))
+ mode = "w";
+ else
+ mode = "a";
+
+ char url[300]; url[0] = '\0';
+ DBVARIANT dbv;
+ if (!g_plugin.getString(hContact, URL_KEY, &dbv)) {
+ strncpy_s(url, _countof(url), dbv.pszVal, _TRUNCATE);
+ db_free(&dbv);
+ }
+
+ if (g_plugin.getString(hContact, FILE_KEY, &dbv))
+ return;
+
+ FILE *pfile = fopen(dbv.pszVal, mode);
+ if (pfile == nullptr)
+ WErrorPopup(hContact, TranslateT("Cannot write to file"));
+ else {
+ char timestring[128], timeprefix[32];
+ char temptime1[32], temptime2[32];
+
+ time_t ftime = time(0);
+ struct tm *nTime = localtime(&ftime);
+
+ mir_snprintf(timeprefix, " %s ", Translate("Last updated on"));
+ strftime(temptime1, 32, " %a, %b %d, %Y ", nTime);
+ strftime(temptime2, 32, " %I:%M %p.", nTime);
+ mir_snprintf(timestring, "(%s)%s\n%s,%s\n", MODULENAME, url, temptime1, temptime2);
+
+ fputs(timestring, pfile);
+ fwrite(truncated, mir_strlen(truncated), 1, pfile);
+ fputs("\n\n", pfile);
+ fclose(pfile);
+ }
+
+ db_free(&dbv);
+}
+
+/*****************************************************************************/
+int ProcessAlerts(MCONTACT hContact, char *truncated, char *tstr, char *contactname, int notpresent)
+{
+ char alertstring[255];
+ wchar_t displaystring[300];
+ FILE *pcachefile;
+ DBVARIANT tdbv;
+ int wasAlert = 0;
+
+ int statalertpos = 0, disalertpos = 0, statalertposend = 0;
+ char*alertpos;
+ char Alerttempstring[300], Alerttempstring2[300];
+ static char cachecompare[MAXSIZE1];
+ static char raw[MAXSIZE1];
+
+ int alertIndex = 0, eventIndex = 0;
+
+ char tempraw[MAXSIZE1];
+ memset(&tempraw, 0, sizeof(tempraw));
+ memset(&raw, 0, sizeof(raw));
+
+ strncpy(tempraw, truncated, _countof(tempraw));
+
+ memset(&alertstring, 0, sizeof(alertstring));
+ memset(&Alerttempstring, 0, sizeof(Alerttempstring));
+ memset(&Alerttempstring2, 0, sizeof(Alerttempstring2));
+ memset(&cachecompare, 0, sizeof(cachecompare));
+
+ // alerts
+ if (g_plugin.getByte(hContact, ENABLE_ALERTS_KEY, 0)) { // ALERTS
+ alertIndex = g_plugin.getByte(hContact, ALRT_INDEX_KEY, 0);
+ eventIndex = g_plugin.getByte(hContact, EVNT_INDEX_KEY, 0);
+ if (notpresent) {
+ if (alertIndex == 0) { // Popup
+ Sleep(1000);
+ WAlertPopup(hContact, TranslateT("Start/end strings not found or strings not set."));
+ // contactlist name//
+ if (g_plugin.getByte(hContact, APND_DATE_NAME_KEY, 0))
+ db_set_s(hContact, "CList", "MyHandle", tstr);
+ }
+ else if (alertIndex == 1) { // log to file
+ if (!g_plugin.getString(hContact, FILE_KEY, &tdbv)) {
+ int AmountWspcRem = 0;
+
+ if (!g_plugin.getByte(hContact, SAVE_AS_RAW_KEY, 0)) {
+ CodetoSymbol(tempraw);
+ Sleep(100); // avoid 100% CPU
+
+ EraseBlock(tempraw);
+ Sleep(100); // avoid 100% CPU
+
+ FastTagFilter(tempraw);
+ Sleep(100); // avoid 100% CPU
+
+ NumSymbols(tempraw);
+ Sleep(100); // avoid 100% CPU
+
+ EraseSymbols(tempraw);
+ Sleep(100); // avoid 100% CPU
+
+ AmountWspcRem = g_plugin.getByte(hContact, RWSPACE_KEY, 0);
+ RemoveInvis(tempraw, AmountWspcRem);
+ Sleep(100); // avoid 100% CPU
+
+ Removewhitespace(tempraw);
+ }
+
+ SaveToFile(hContact, tempraw);
+ db_free(&tdbv);
+
+ if (g_plugin.getByte(hContact, APND_DATE_NAME_KEY, 0))
+ db_set_s(hContact, "CList", "MyHandle", tstr);
+ }
+ }
+ else if (alertIndex == 3) {
+ WAlertOSD(hContact, TranslateT("Alert start/end strings not found or strings not set."));
+ if (g_plugin.getByte(hContact, APND_DATE_NAME_KEY, 0))
+ db_set_s(hContact, "CList", "MyHandle", tstr);
+ }
+ else if (eventIndex == 2) {
+ WDisplayDataAlert(hContact);
+
+ if (g_plugin.getByte(hContact, APND_DATE_NAME_KEY, 0))
+ db_set_s(hContact, "CList", "MyHandle", tstr);
+
+ HWND hwndDlg = (WindowList_Find(hWindowList, hContact));
+
+ SetDlgItemText(hwndDlg, IDC_STATUSBAR, TranslateT("Start/end strings not found or strings not set."));
+ }
+ else MessageBox(nullptr, TranslateT("Start/end strings not found or strings not set."), _A2W(MODULENAME), MB_OK);
+ }
+
+ if (eventIndex == 0) { // string present
+ if (!g_plugin.getString(hContact, ALERT_STRING_KEY, &tdbv)) {
+ strncpy_s(alertstring, _countof(alertstring), tdbv.pszVal, _TRUNCATE);
+ db_free(&tdbv);
+
+ if ((strstr(tempraw, alertstring)) != nullptr) { // // ENDALERT EVENT:CHECK FOR STRING
+ // there was an alert
+ wasAlert = 1;
+
+ // play sound?
+ Skin_PlaySound("webviewalert");
+ //
+ if ((!notpresent)) {
+ if (alertIndex == 0) { // popup
+ mir_snwprintf(displaystring, L"%s \"%S\" %s.", Translate("The string"), alertstring, Translate("has been found on the web page"));
+ WAlertPopup(hContact, displaystring);
+
+ // contactlist name//
+ if (g_plugin.getByte(hContact, APND_DATE_NAME_KEY, 0))
+ db_set_s(hContact, "CList", "MyHandle", tstr);
+ } //
+ else if (alertIndex == 1) {
+ if (!g_plugin.getString(hContact, FILE_KEY, &tdbv)) {
+ int AmountWspcRem = 0;
+ if (!g_plugin.getByte(hContact, SAVE_AS_RAW_KEY, 0)) {
+ CodetoSymbol(tempraw);
+ Sleep(100); // avoid 100% CPU
+
+ EraseBlock(tempraw);
+ Sleep(100); // avoid 100% CPU
+
+ FastTagFilter(tempraw);
+ Sleep(100); // avoid 100% CPU
+
+ NumSymbols(tempraw);
+ Sleep(100); // avoid 100% CPU
+
+ EraseSymbols(tempraw);
+ Sleep(100); // avoid 100% CPU
+
+ AmountWspcRem = g_plugin.getByte(hContact, RWSPACE_KEY, 0);
+ RemoveInvis(tempraw, AmountWspcRem);
+ Sleep(100); // avoid 100% CPU
+
+ Removewhitespace(tempraw);
+ }
+ SaveToFile(hContact, tempraw);
+ db_free(&tdbv);
+
+ if (g_plugin.getByte(hContact, APND_DATE_NAME_KEY, 0))
+ db_set_s(hContact, "CList", "MyHandle", tstr);
+ }
+ }
+ else if (alertIndex == 3) {
+ mir_snwprintf(displaystring, L"%s \"%s\" %s.", TranslateT("The string"), alertstring, TranslateT("has been found on the web page"));
+ WAlertOSD(hContact, displaystring);
+
+ // contactlist name//
+ if (g_plugin.getByte(hContact, APND_DATE_NAME_KEY, 0))
+ db_set_s(hContact, "CList", "MyHandle", tstr);
+ }
+ else if (alertIndex == 2) {
+ WDisplayDataAlert(hContact);
+ // contactlist name//
+ if (g_plugin.getByte(hContact, APND_DATE_NAME_KEY, 0))
+ db_set_s(hContact, "CList", "MyHandle", tstr);
+
+ HWND hwndDlg = WindowList_Find(hWindowList, hContact);
+ SetDlgItemText(hwndDlg, IDC_STATUSBAR, TranslateT("Download successful; about to process data..."));
+ }
+ else MessageBox(nullptr, TranslateT("Unknown alert type."), _A2W(MODULENAME), MB_OK);
+ }
+ }
+ }
+ }
+ else if (eventIndex == 1) { // webpage changed
+ // TEST GET NAME FOR CACHE
+ wchar_t cachepath[MAX_PATH], cachedirectorypath[MAX_PATH], newcachepath[MAX_PATH + 50];
+ GetModuleFileName(g_plugin.getInst(), cachepath, _countof(cachepath));
+ wchar_t *cacheend = wcsrchr(cachepath, '\\');
+ cacheend++;
+ *cacheend = '\0';
+
+ mir_snwprintf(cachedirectorypath, L"%s%S%S", cachepath, MODULENAME, "cache\\");
+ CreateDirectory(cachedirectorypath, nullptr);
+ mir_snwprintf(newcachepath, L"%s%S%S%S%S", cachepath, MODULENAME, "cache\\", contactname, ".txt");
+ // file exists?
+ if (_waccess(newcachepath, 0) != -1) {
+ if ((pcachefile = _wfopen(newcachepath, L"r")) == nullptr)
+ WErrorPopup((UINT_PTR)contactname, TranslateT("Cannot read from file"));
+ else {
+ memset(&cachecompare, 0, sizeof(cachecompare));
+ fread(cachecompare, sizeof(cachecompare), 1, pcachefile);
+ fclose(pcachefile);
+ }
+ }
+ // write to cache
+ if ((pcachefile = _wfopen(newcachepath, L"w")) == nullptr)
+ WErrorPopup((UINT_PTR)contactname, TranslateT("Cannot write to file 1"));
+ else {
+ fwrite(tempraw, mir_strlen(tempraw), 1, pcachefile); //smaller cache
+ fclose(pcachefile);
+ g_plugin.setWString(hContact, CACHE_FILE_KEY, newcachepath);
+ }
+ // end write to cache
+
+ if (strncmp(tempraw, cachecompare, mir_strlen(tempraw)) != 0) { //lets try this instead
+ // play sound?
+ Skin_PlaySound("webviewalert");
+ // there was an alert
+ wasAlert = 1;
+
+ if (!notpresent) {
+ if (alertIndex == 0) { // popup
+ WAlertPopup(hContact, TranslateT("The web page has changed."));
+ // contactlist name//
+ if (g_plugin.getByte(hContact, APND_DATE_NAME_KEY, 0))
+ db_set_s(hContact, "CList", "MyHandle", tstr);
+ }
+ else if (alertIndex == 3) { // osd
+ WAlertOSD(hContact, TranslateT("The web page has changed."));
+ // contactlist name//
+ if (g_plugin.getByte(hContact, APND_DATE_NAME_KEY, 0))
+ db_set_s(hContact, "CList", "MyHandle", tstr);
+ }
+ else if (alertIndex == 1) { // log
+ if (!g_plugin.getString(hContact, FILE_KEY, &tdbv)) {
+ int AmountWspcRem = 0;
+
+ if (!g_plugin.getByte(hContact, SAVE_AS_RAW_KEY, 0)) {
+ CodetoSymbol(tempraw);
+ Sleep(100); // avoid 100% CPU
+
+ EraseBlock(tempraw);
+ Sleep(100); // avoid 100% CPU
+
+ FastTagFilter(tempraw);
+ Sleep(100); // avoid 100% CPU
+
+ NumSymbols(tempraw);
+ Sleep(100); // avoid 100% CPU
+
+ EraseSymbols(tempraw);
+ Sleep(100); // avoid 100% CPU
+
+ AmountWspcRem = g_plugin.getByte(hContact, RWSPACE_KEY, 0);
+ RemoveInvis(tempraw, AmountWspcRem);
+ Sleep(100); // avoid 100% CPU
+
+ Removewhitespace(tempraw);
+ }
+
+ SaveToFile(hContact, tempraw);
+ db_free(&tdbv);
+ // contactlist name//
+ if (g_plugin.getByte(hContact, APND_DATE_NAME_KEY, 0))
+ db_set_s(hContact, "CList", "MyHandle", tstr);
+ }
+ }
+ else if (alertIndex == 2) { // window
+ WDisplayDataAlert(hContact);
+ // contactlist name//
+ if (g_plugin.getByte(hContact, APND_DATE_NAME_KEY, 0))
+ db_set_s(hContact, "CList", "MyHandle", tstr);
+ }
+ else MessageBox(nullptr, TranslateT("Unknown alert type."), _A2W(MODULENAME), MB_OK);
+ }
+ }
+ }
+
+ if (eventIndex == 2) { // part of webpage changed
+ Alerttempstring[0] = Alerttempstring2[0] = 0;
+ if (!g_plugin.getString(hContact, ALRT_S_STRING_KEY, &tdbv)) {
+ strncpy_s(Alerttempstring, _countof(Alerttempstring), tdbv.pszVal, _TRUNCATE);
+ db_free(&tdbv);
+ }
+ if (!g_plugin.getString(hContact, ALRT_E_STRING_KEY, &tdbv)) {
+ strncpy_s(Alerttempstring2, _countof(Alerttempstring2), tdbv.pszVal, _TRUNCATE);
+ db_free(&tdbv);
+ }
+
+ // putting data into string
+ if (((strstr(tempraw, Alerttempstring)) != nullptr) && ((strstr(tempraw, Alerttempstring2)) != nullptr)) {
+ //start string
+ alertpos = strstr(tempraw, Alerttempstring);
+ statalertpos = alertpos - tempraw;
+
+ memset(&alertpos, 0, sizeof(alertpos));
+ //end string
+ alertpos = strstr(tempraw, Alerttempstring2);
+ statalertposend = alertpos - tempraw + (int)mir_strlen(Alerttempstring2);
+
+ if (statalertpos > statalertposend) {
+ memset(&tempraw, ' ', statalertpos);
+ memset(&alertpos, 0, sizeof(alertpos));
+ alertpos = strstr(tempraw, Alerttempstring2);
+ statalertposend = alertpos - tempraw + (int)mir_strlen(Alerttempstring2);
+ }
+
+ if (statalertpos < statalertposend) {
+ memset(&raw, 0, sizeof(raw));
+
+ //start string
+ alertpos = strstr(tempraw, Alerttempstring);
+ statalertpos = alertpos - tempraw;
+
+ //end string
+ alertpos = strstr(tempraw, Alerttempstring2);
+ statalertposend = alertpos - tempraw + (int)mir_strlen(Alerttempstring2);
+
+ if (statalertpos > statalertposend) {
+ memset(&tempraw, ' ', statalertpos);
+ memset(&alertpos, 0, sizeof(alertpos));
+ alertpos = strstr(tempraw, Alerttempstring2);
+ statalertposend = alertpos - tempraw + (int)mir_strlen(Alerttempstring2);
+ }
+ disalertpos = 0;
+
+ //write selected data to string
+ strncpy(raw, &tempraw[statalertpos], (statalertposend - statalertpos));
+ raw[(statalertposend - statalertpos)] = '\0';
+ }
+ } // end putting data into string
+ else { // start and/or end string not present
+ if (alertIndex == 0) { // popup
+ Sleep(1000);
+ WAlertPopup(hContact, TranslateT("Alert start/end strings not found or strings not set."));
+ // contactlist name//
+ if (g_plugin.getByte(hContact, APND_DATE_NAME_KEY, 0))
+ db_set_s(hContact, "CList", "MyHandle", tstr);
+ }
+ else if (alertIndex == 1) { // LOG
+ if (!notpresent) { // dont log to file twice if both types of start/end strings not present
+ if (!g_plugin.getString(hContact, FILE_KEY, &tdbv)) {
+ int AmountWspcRem = 0;
+ if (!g_plugin.getByte(hContact, SAVE_AS_RAW_KEY, 0)) {
+ CodetoSymbol(tempraw);
+ Sleep(100); // avoid 100% CPU
+
+ EraseBlock(tempraw);
+ Sleep(100); // avoid 100% CPU
+
+ FastTagFilter(tempraw);
+ Sleep(100); // avoid 100% CPU
+
+ NumSymbols(tempraw);
+ Sleep(100); // avoid 100% CPU
+
+ EraseSymbols(tempraw);
+ Sleep(100); // avoid 100% CPU
+
+ AmountWspcRem = g_plugin.getByte(hContact, RWSPACE_KEY, 0);
+ RemoveInvis(tempraw, AmountWspcRem);
+ Sleep(100); // avoid 100% CPU
+
+ Removewhitespace(tempraw);
+ }
+
+ SaveToFile(hContact, tempraw);
+ db_free(&tdbv);
+ // contactlist name
+ if (g_plugin.getByte(hContact, APND_DATE_NAME_KEY, 0))
+ db_set_s(hContact, "CList", "MyHandle", tstr);
+ }
+ }
+ }
+ else if (alertIndex == 3) { // osd
+ WAlertOSD(hContact, TranslateT("Alert start/end strings not found or strings not set."));
+ // contactlist name//
+ if (g_plugin.getByte(hContact, APND_DATE_NAME_KEY, 0))
+ db_set_s(hContact, "CList", "MyHandle", tstr);
+ }
+ else if (alertIndex == 2) { // window
+ WDisplayDataAlert(hContact);
+ // contactlist name//
+ if (g_plugin.getByte(hContact, APND_DATE_NAME_KEY, 0))
+ db_set_s(hContact, "CList", "MyHandle", tstr);
+
+ HWND hwndDlg = (WindowList_Find(hWindowList, hContact));
+ SetDlgItemText(hwndDlg, IDC_STATUSBAR, TranslateT("Alert start/end strings not found or strings not set."));
+ }
+ else MessageBox(nullptr, TranslateT("Alert start/end strings not found or strings not set."), _A2W(MODULENAME), MB_OK);
+
+ g_plugin.setWord(hContact, "Status", ID_STATUS_AWAY);
+ }
+
+ ///////////////
+ if (((strstr(tempraw, Alerttempstring)) != nullptr) && ((strstr(tempraw, Alerttempstring2)) != nullptr)) {
+ // TEST GET NAME FOR CACHE
+ wchar_t cachepath[MAX_PATH], cachedirectorypath[MAX_PATH], newcachepath[MAX_PATH + 50];
+ GetModuleFileName(g_plugin.getInst(), cachepath, _countof(cachepath));
+ wchar_t *cacheend = wcsrchr(cachepath, '\\');
+ cacheend++;
+ *cacheend = '\0';
+
+ mir_snwprintf(cachedirectorypath, L"%s%S%S", cachepath, MODULENAME, "cache\\");
+ CreateDirectory(cachedirectorypath, nullptr);
+ mir_snwprintf(newcachepath, L"%s%S%S%S%S", cachepath, MODULENAME, "cache\\", contactname, ".txt");
+ // file exists?
+ if (_waccess(newcachepath, 0) != -1) {
+ if ((pcachefile = _wfopen(newcachepath, L"r")) == nullptr)
+ WErrorPopup((UINT_PTR)contactname, TranslateT("Cannot read from file"));
+ else {
+ memset(&cachecompare, 0, sizeof(cachecompare));
+ fread(cachecompare, sizeof(cachecompare), 1, pcachefile);
+ fclose(pcachefile);
+ }
+ }
+ // write to cache
+ if ((pcachefile = _wfopen(newcachepath, L"w")) == nullptr)
+ WErrorPopup((UINT_PTR)contactname, TranslateT("Cannot write to file 2"));
+ else {
+ fwrite(raw, mir_strlen(raw), 1, pcachefile); //smaller cache
+ g_plugin.setWString(hContact, CACHE_FILE_KEY, newcachepath);
+ fclose(pcachefile);
+ }
+ // end write to cache
+ if (strncmp(raw, cachecompare, (mir_strlen(raw))) != 0) { //lets try this instead
+ // play sound?
+ Skin_PlaySound("webviewalert");
+ // there was an alert
+ wasAlert = 1;
+
+ if (!notpresent) {
+ if (alertIndex == 0) { // popup
+ WAlertPopup(hContact, TranslateT("Specific part of the web page has changed."));
+ // contactlist name//
+ if (g_plugin.getByte(hContact, APND_DATE_NAME_KEY, 0))
+ db_set_s(hContact, "CList", "MyHandle", tstr);
+ }
+ else if (alertIndex == 3) { // osd
+ WAlertOSD(hContact, TranslateT("Specific part of the web page has changed."));
+ // contactlist name//
+ if (g_plugin.getByte(hContact, APND_DATE_NAME_KEY, 0))
+ db_set_s(hContact, "CList", "MyHandle", tstr);
+ }
+ else if (alertIndex == 1) { // log to file
+ if (!g_plugin.getString(hContact, FILE_KEY, &tdbv)) {
+ int AmountWspcRem = 0;
+ if (!g_plugin.getByte(hContact, SAVE_AS_RAW_KEY, 0)) {
+ CodetoSymbol(tempraw);
+ Sleep(100); // avoid 100% CPU
+
+ EraseBlock(tempraw);
+ Sleep(100); // avoid 100% CPU
+
+ FastTagFilter(tempraw);
+ Sleep(100); // avoid 100% CPU
+
+ NumSymbols(tempraw);
+ Sleep(100); // avoid 100% CPU
+
+ EraseSymbols(tempraw);
+ Sleep(100); // avoid 100% CPU
+
+ AmountWspcRem = g_plugin.getByte(hContact, RWSPACE_KEY, 0);
+ RemoveInvis(tempraw, AmountWspcRem);
+ Sleep(100); // avoid 100% CPU
+
+ Removewhitespace(tempraw);
+ }
+
+ SaveToFile(hContact, tempraw);
+ db_free(&tdbv);
+ // contactlist name
+ if (g_plugin.getByte(hContact, APND_DATE_NAME_KEY, 0))
+ db_set_s(hContact, "CList", "MyHandle", tstr);
+ }
+ }
+ else if (alertIndex == 2) { // window
+ WDisplayDataAlert(hContact);
+ // contactlist name//
+ if (g_plugin.getByte(hContact, APND_DATE_NAME_KEY, 0))
+ db_set_s(hContact, "CList", "MyHandle", tstr);
+ }
+ else MessageBox(nullptr, TranslateT("Unknown alert type."), _A2W(MODULENAME), MB_OK);
+ }
+ }
+ }
+ } // alert type
+ }
+ // end alerts
+
+ //if always log to file option is enabled do this
+ if (wasAlert && alertIndex != 1) { // dont do for log to file alert
+ if (g_plugin.getByte(hContact, ALWAYS_LOG_KEY, 0)) {
+ if (!g_plugin.getString(hContact, FILE_KEY, &tdbv)) {
+ int AmountWspcRem = 0;
+
+ if (!g_plugin.getByte(hContact, SAVE_AS_RAW_KEY, 0)) {
+ CodetoSymbol(tempraw);
+ Sleep(100); // avoid 100% CPU
+
+ EraseBlock(tempraw);
+ Sleep(100); // avoid 100% CPU
+
+ FastTagFilter(tempraw);
+ Sleep(100); // avoid 100% CPU
+
+ NumSymbols(tempraw);
+ Sleep(100); // avoid 100% CPU
+
+ EraseSymbols(tempraw);
+ Sleep(100); // avoid 100% CPU
+
+ AmountWspcRem = g_plugin.getByte(hContact, RWSPACE_KEY, 0);
+ RemoveInvis(tempraw, AmountWspcRem);
+ Sleep(100); // avoid 100% CPU
+
+ Removewhitespace(tempraw);
+ }
+
+ SaveToFile(hContact, tempraw);
+ db_free(&tdbv);
+ }
+ }
+ }
+ strncpy(truncated, tempraw, mir_strlen(truncated));
+ return wasAlert;
+}
+
+/*****************************************************************************/
+int DataWndAlertCommand(WPARAM wParam, LPARAM)
+{
+ MCONTACT hContact = wParam;
+ if (WindowList_Find(hWindowList, hContact))
+ return 0;
+
+ HWND hwndDlg = CreateDialogParam(g_plugin.getInst(), MAKEINTRESOURCE(IDD_DISPLAY_DATA), nullptr, DlgProcDisplayData, hContact);
+ HWND hTopmost = g_plugin.getByte(hContact, ON_TOP_KEY, 0) ? HWND_TOPMOST : HWND_NOTOPMOST;
+ SendDlgItemMessage(hwndDlg, IDC_STICK_BUTTON, BM_SETIMAGE, IMAGE_ICON, (LPARAM)((HICON)LoadImage(g_plugin.getInst(), MAKEINTRESOURCE(IDI_STICK), IMAGE_ICON, GetSystemMetrics(SM_CXSMICON), GetSystemMetrics(SM_CYSMICON), 0)));
+ if (g_plugin.getByte(SAVE_INDIVID_POS_KEY, 0))
+ SetWindowPos(hwndDlg, hTopmost,
+ g_plugin.getDword(hContact, "WVx", 100), // Xposition,
+ g_plugin.getDword(hContact, "WVy", 100), // Yposition,
+ g_plugin.getDword(hContact, "WVwidth", 100), // WindowWidth,
+ g_plugin.getDword(hContact, "WVheight", 100), 0); // WindowHeight,
+ else
+ SetWindowPos(hwndDlg, HWND_TOPMOST, Xposition, Yposition, WindowWidth, WindowHeight, 0);
+
+ ShowWindow(hwndDlg, SW_SHOW);
+ SetActiveWindow(hwndDlg);
+ return 0;
+}
+
+/*****************************************************************************/
+void ReadFromFile(void *param)
+{
+ MCONTACT hContact = (UINT_PTR)param;
+
+ DBVARIANT dbv;
+ char truncated[MAXSIZE1];
+ int AmountWspcRem = 0;
+ int fileexists = 0;
+
+ HWND hwndDlg = WindowList_Find(hWindowList, hContact);
+
+ char contactname[100]; contactname[0] = 0;
+ if (!db_get_s(hContact, "CList", "MyHandle", &dbv)) {
+ strncpy_s(contactname, _countof(contactname), dbv.pszVal, _TRUNCATE);
+ db_free(&dbv);
+ }
+
+ if (g_plugin.getString(hContact, CACHE_FILE_KEY, &dbv))
+ return;
+
+ FILE *pfile;
+ if ((pfile = fopen(dbv.pszVal, "r")) == nullptr) {
+ SendToRichEdit(hwndDlg, Translate("Cannot read from cache file"), TextClr, BackgoundClr);
+ fileexists = 0;
+ }
+ else {
+ fread(truncated, sizeof(truncated), 1, pfile);
+ fclose(pfile);
+ fileexists = 1;
+ }
+
+ db_free(&dbv);
+
+ if (fileexists) {
+ CodetoSymbol(truncated);
+ Sleep(100); // avoid 100% CPU
+
+ EraseBlock(truncated);
+ Sleep(100); // avoid 100% CPU
+
+ FastTagFilter(truncated);
+ Sleep(100); // avoid 100% CPU
+
+ NumSymbols(truncated);
+ Sleep(100); // avoid 100% CPU
+
+ EraseSymbols(truncated);
+ Sleep(100); // avoid 100% CPU
+
+ AmountWspcRem = g_plugin.getByte(hContact, RWSPACE_KEY, 0);
+ RemoveInvis(truncated, AmountWspcRem);
+ Sleep(100); // avoid 100% CPU
+
+ Removewhitespace(truncated);
+
+ SendToRichEdit(hwndDlg, truncated, TextClr, BackgoundClr);
+ SetDlgItemText(hwndDlg, IDC_STATUSBAR, TranslateT("Loaded from cache"));
+ }
+}
diff --git a/protocols/WebView/src/webview_cleanup.cpp b/protocols/WebView/src/webview_cleanup.cpp
new file mode 100644
index 0000000000..af620f7351
--- /dev/null
+++ b/protocols/WebView/src/webview_cleanup.cpp
@@ -0,0 +1,797 @@
+/*
+* A plugin for Miranda IM which displays web page text in a window Copyright
+* (C) 2005 Vincent Joyce.
+*
+* Miranda IM: the free icq client for MS Windows Copyright (C) 2000-2
+* Richard Hughes, Roland Rabien & Tristan Van de Vreede
+*
+* 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.
+*/
+
+#include "stdafx.h"
+#include "webview.h"
+
+// ///////////////////////
+// characters and symbols//
+// ///////////////////////
+
+#define AMOUNT3 164
+
+char*CharacterCodes[AMOUNT3] =
+{
+ "&quot;",
+ "&amp;",
+ "&lt;",
+ "&gt;",
+ "&nbsp;",
+ "&iexcl;",
+ "&cent;",
+ "&pound;",
+ "&curren;",
+ "&yen;",
+ "&brvbar",
+ "&sect;",
+ "&uml;",
+ "&copy;",
+ "&ordf;",
+ "&laquo;",
+ "&not;",
+ "&shy;",
+ "&reg;",
+ "&macr;",
+ "&deg;",
+ "&plusmn;",
+ "&sup2;",
+ "&sup3;",
+ "&acute;",
+ "&micro;",
+ "&para;",
+ "&middot;",
+ "&cedil;",
+ "&sup1;",
+ "&ordm;",
+ "&raquo;",
+ "&frac14;",
+ "&frac12;",
+ "&frac34;",
+ "&iquest;",
+ "&Agrave;",
+ "&Aacute;",
+ "&Acirc;",
+ "&Atilde;",
+ "&Auml;",
+ "&Aring;",
+ "&AElig;",
+ "&Ccedil;",
+ "&Egrave;",
+ "&Eacute;",
+ "&Ecirc;",
+ "&Euml;",
+ "&Igrave;",
+ "&Iacute;",
+ "&Icirc;",
+ "&Iuml;",
+ "&ETH;",
+ "&Ntilde;",
+ "&Ograve;",
+ "&Oacute;",
+ "&Ocirc;",
+ "&Otilde;",
+ "&Ouml;",
+ "&times;",
+ "&Oslash;",
+ "&Ugrave;",
+ "&Uacute;",
+ "&Ucirc;",
+ "&Uuml;",
+ "&Yacute;",
+ "&THORN;",
+ "&szlig;",
+ "&agrave;",
+ "&aacute;",
+ "&acirc;",
+ "&atilde;",
+ "&auml;",
+ "&aring;",
+ "&aelig;",
+ "&ccedil;",
+ "&egrave;",
+ "&eacute;",
+ "&ecirc;",
+ "&euml;",
+ "&igrave;",
+ "&iacute;",
+ "&icirc;",
+ "&iuml;",
+ "&eth;",
+ "&ntilde;",
+ "&ograve;",
+ "&oacute;",
+ "&ocirc;",
+ "&otilde;",
+ "&ouml;",
+ "&divide;",
+ "&oslash;",
+ "&ugrave;",
+ "&uacute;",
+ "&ucirc;",
+ "&uuml;",
+ "&yacute;",
+ "&thorn;",
+ "&yumil;",
+ "&#338;", // greater that 255, extra latin characters
+ "&#339;",
+ "&#352;",
+ "&#353;",
+ "&#376;",
+ "&#402;",
+ "&#710;",
+ "&#732;",
+ "&OElig;",
+ "&oelig;",
+ "&Scaron;",
+ "&scaron;",
+ "&Yuml;",
+ "&fnof;",
+ "&circ;",
+ "&tilde;",
+ "&#8211;", // Misc other characters
+ "&#8212;",
+ "&#8216;",
+ "&#8217;",
+ "&#8218;",
+ "&#8220;",
+ "&#8221;",
+ "&#8222;",
+ "&#8224;",
+ "&#8225;",
+ "&#8226;",
+ "&#8230;",
+ "&#8240;",
+ "&#8249;",
+ "&#8250;",
+ "&#8364;",
+ "&#8465;",
+ "&#8476;",
+ "&#8482;",
+ "&ndash;",
+ "&mdash;",
+ "&lsquo;",
+ "&rsquo;",
+ "&sbquo;",
+ "&ldquo;",
+ "&rdquo;",
+ "&bdquo;",
+ "&dagger;",
+ "&Dagger;",
+ "&bull;",
+ "&hellip;",
+ "&permil;",
+ "&lsaquo;",
+ "&rsaquo;",
+ "&euro;",
+ "&image;",
+ "&real;",
+ "&trade;",
+ "&ensp;",
+ "&emsp;",
+ "&thinsp;",
+ "&#8194;",
+ "&#8195;",
+ "&#8201;",
+ "&otilde;", // symbols without numeric code
+ "&iquest;",
+ "&brvbar;",
+ "&macr;"};
+
+char Characters[AMOUNT3] =
+{
+ '\"',
+ '&',
+ '<',
+ '>',
+ ' ',
+ '¡',
+ '¢',
+ '£',
+ '¤',
+ '¥',
+ '¦',
+ '§',
+ '¨',
+ '©',
+ 'ª',
+ '«',
+ '¬',
+ '­',
+ '®',
+ '¯',
+ '°',
+ '±',
+ '²',
+ '³',
+ '´',
+ 'µ',
+ '¶',
+ '·',
+ '¸',
+ '¹',
+ 'º',
+ '»',
+ '¼',
+ '½',
+ '¾',
+ '¿',
+ 'À',
+ 'Á',
+ 'Â',
+ 'Ã',
+ 'Ä',
+ 'Å',
+ 'Æ',
+ 'Ç',
+ 'È',
+ 'É',
+ 'Ê',
+ 'Ë',
+ 'Ì',
+ 'Í',
+ 'Î',
+ 'Ï',
+ 'Ð',
+ 'Ñ',
+ 'Ò',
+ 'Ó',
+ 'Ô',
+ 'Õ',
+ 'Ö',
+ '×',
+ 'Ø',
+ 'Ù',
+ 'Ú',
+ 'Û',
+ 'Ü',
+ 'Ý',
+ 'Þ',
+ 'ß',
+ 'à',
+ 'á',
+ 'â',
+ 'ã',
+ 'ä',
+ 'å',
+ 'æ',
+ 'ç',
+ 'è',
+ 'é',
+ 'ê',
+ 'ë',
+ 'ì',
+ 'í',
+ 'î',
+ 'ï',
+ 'ð',
+ 'ñ',
+ 'ò',
+ 'ó',
+ 'ô',
+ 'õ',
+ 'ö',
+ '÷',
+ 'ø',
+ 'ù',
+ 'ú',
+ 'û',
+ 'ü',
+ 'ý',
+ 'þ',
+ 'ÿ',
+ 'Œ', // greater than 255 extra latin characters
+ 'œ',
+ 'Š',
+ 'š',
+ 'Ÿ',
+ 'ƒ',
+ 'ˆ',
+ '˜',
+ 'Œ',
+ 'œ',
+ 'Š',
+ 'š',
+ 'Ÿ',
+ 'ƒ',
+ 'ˆ',
+ '˜',
+ '–',
+ '—', // misc other characters
+ '‘',
+ '’',
+ '‚',
+ '“',
+ '”',
+ '„',
+ '†',
+ '‡',
+ '•',
+ '…',
+ '‰',
+ '‹',
+ '›',
+ '€',
+ 'I',
+ 'R',
+ '™',
+ '–',
+ '—',
+ '‘',
+ '’',
+ '‚',
+ '“',
+ '”',
+ '„',
+ '†',
+ '‡',
+ '•',
+ '…',
+ '‰',
+ '‹',
+ '›',
+ '€',
+ 'I',
+ 'R',
+ '™',
+ ' ',
+ ' ',
+ ' ',
+ ' ',
+ ' ',
+ ' ',
+ 'õ',
+ '¿',
+ '¦',
+ '¯'};
+
+/*****************************************************************************/
+void CodetoSymbol(char *truncated)
+{
+ int counter = 0;
+ int position = 0, recpos = 0;
+ static char *stringfrompos;
+
+ for (int n = 0; n < AMOUNT3; n++) {
+ while (true) { // loop forever
+ Sleep(1); // avoid 100% CPU
+
+ if ( strstr(truncated, CharacterCodes[n]) != nullptr) { // does character code exist?
+ stringfrompos = strstr(truncated, CharacterCodes[n]);
+
+ position = stringfrompos - truncated;
+ counter = 0;
+ while (counter != mir_strlen(CharacterCodes[n])) {
+ truncated[position + counter] = ' ';
+ counter++;
+ }
+
+ truncated[(position + counter) - 1] = Characters[n];
+ strncpy(&truncated[position], &truncated[position + mir_strlen(CharacterCodes[n])] - 1, mir_strlen(&truncated[position]) - 1);
+ } // end does character code exist?
+
+ if (recpos == position)
+ break; // break out of loop if doesn't find new character code
+
+ recpos = position;
+ } // end loop forever
+ } // for
+}
+
+/*****************************************************************************/
+void EraseBlock(char *truncated)
+{
+ int counter = 0;
+ int positionStart = 0, positionEnd = 0;
+ char *stringfrompos;
+ int BlockLength = 0;
+
+ char* tempraw = (char*)malloc(MAXSIZE1);
+ if (truncated)
+ strncpy(tempraw, truncated, MAXSIZE1);
+
+ // ///////////////////////////
+
+ while (true) {
+ Sleep(1); // avoid 100% CPU
+ // /get start and end of block
+
+ if (strstr(tempraw, "<!--") != nullptr) // does tag exist?
+ {
+ stringfrompos = strstr(tempraw, "<!--");
+ positionStart = stringfrompos - tempraw;
+ }
+
+ if (strstr(tempraw, "-->") != nullptr) // does tag exist?
+ {
+ stringfrompos = strstr(tempraw, "-->");
+ positionEnd = stringfrompos - tempraw;
+ }
+ BlockLength = (positionEnd - positionStart) + 3;
+
+ if ((strstr(tempraw, "<!--") == nullptr) || (strstr(tempraw, "-->") == nullptr))
+ break;
+
+ /////////////////////////////////////////
+
+ if (strstr(tempraw, "<!--") != nullptr)
+ for (counter = 0; counter < BlockLength; counter++)
+ tempraw[positionStart + counter] = ' ';
+
+ if ((positionStart == 0) && (positionEnd == 0))
+ break;
+ if (positionStart > positionEnd)
+ break;
+
+ positionStart = 0;
+ positionEnd = 0;
+ }
+
+ // ///////////////////////////
+ positionStart = 0;
+ positionEnd = 0;
+
+ // 2//
+ while (true) {
+ Sleep(1); // avoid 100% CPU
+ // /get start and end of block
+
+ if (((strstr(tempraw, "<script")) != nullptr) || (strstr(tempraw, "<SCRIPT") != nullptr)) // does
+ {
+ if (strstr(tempraw, "<script") != nullptr)
+ stringfrompos = strstr(tempraw, "<script");
+ else
+ stringfrompos = strstr(tempraw, "<SCRIPT");
+
+ positionStart = stringfrompos - tempraw;
+ }
+
+ if (((strstr(tempraw, "</script")) != nullptr) || (strstr(tempraw, "</SCRIPT") != nullptr)) // does
+ {
+ if (strstr(tempraw, "<script") != nullptr)
+ stringfrompos = strstr(tempraw, "</script");
+ else
+ stringfrompos = strstr(tempraw, "</SCRIPT");
+
+ positionEnd = stringfrompos - tempraw;
+ }
+ BlockLength = (positionEnd - positionStart) + 9;
+
+ if ((strstr(tempraw, "<script") != nullptr) && (strstr(tempraw, "</script") == nullptr))
+ break;
+
+ if ((strstr(tempraw, "<SCRIPT") != nullptr) && (strstr(tempraw, "</SCRIPT") == nullptr))
+ break;
+
+ ///////////////////////////////////////
+
+ if (((strstr(tempraw, "<script")) != nullptr) || ((strstr(tempraw, "<SCRIPT")) != nullptr))
+ for (counter = 0; counter < BlockLength; counter++)
+ tempraw[positionStart + counter] = ' ';
+
+ if ((positionStart == 0) && (positionEnd == 0))
+ break;
+ if (positionStart > positionEnd)
+ break;
+
+ positionStart = 0;
+ positionEnd = 0;
+ }
+
+ // ////
+ // 3//
+ while (true)
+ {
+ Sleep(1); // avoid 100% CPU
+ // /get start and end of block
+
+ if (((strstr(tempraw, "<style")) != nullptr) || (strstr(tempraw, "<STYLE") != nullptr)) // does
+ {
+ if (strstr(tempraw, "<style") != nullptr)
+ stringfrompos = strstr(tempraw, "<style");
+ else
+ stringfrompos = strstr(tempraw, "<STYLE");
+
+ positionStart = stringfrompos - tempraw;
+ }
+
+ if (((strstr(tempraw, "</style")) != nullptr) || (strstr(tempraw, "</STYLE") != nullptr)) // does
+ {
+ if (strstr(tempraw, "<style") != nullptr)
+ stringfrompos = strstr(tempraw, "</style");
+ else
+ stringfrompos = strstr(tempraw, "</STYLE");
+
+ positionEnd = stringfrompos - tempraw;
+ }
+ BlockLength = (positionEnd - positionStart) + 8;
+
+ if ((strstr(tempraw, "<style") != nullptr) && (strstr(tempraw, "</style") == nullptr))
+ break;
+
+ if ((strstr(tempraw, "<STYLE") != nullptr) && (strstr(tempraw, "</STYLE") == nullptr))
+ break;
+
+ ///////////////////////////////////////
+ if (((strstr(tempraw, "<style")) != nullptr) || ((strstr(tempraw, "<STYLE")) != nullptr))
+ for (counter = 0; counter < BlockLength; counter++)
+ tempraw[positionStart + counter] = ' ';
+
+ if ((positionStart == 0) && (positionEnd == 0))
+ break;
+ if (positionStart > positionEnd)
+ break;
+
+ positionStart = 0;
+ positionEnd = 0;
+ }
+
+ // 4//
+
+ while (true) {
+ Sleep(1); // avoid 100% CPU
+ // /get start and end of block
+ if (strstr(tempraw, "{") != nullptr) // does tag exist?
+ {
+ stringfrompos = strstr(tempraw, "{");
+ positionStart = stringfrompos - tempraw;
+ }
+
+ if (strstr(tempraw, "}") != nullptr) // does tag exist?
+ {
+ stringfrompos = strstr(tempraw, "}");
+ positionEnd = stringfrompos - tempraw;
+ }
+ BlockLength = (positionEnd - positionStart) + 1;
+
+ if ((strstr(tempraw, "}") == nullptr) || (strstr(tempraw, "{") == nullptr))
+ break;
+
+ /////////////////////////////////////////
+ if (strstr(tempraw, "{") != nullptr)
+ for (counter = 0; counter < BlockLength; counter++)
+ tempraw[positionStart + counter] = ' ';
+
+ if ((positionStart == 0) && (positionEnd == 0))
+ break;
+ if (positionStart > positionEnd)
+ break;
+
+ positionStart = 0;
+ positionEnd = 0;
+ }
+
+ // ///////////////////////////
+ positionStart = 0;
+ positionEnd = 0;
+
+ strncpy(truncated, tempraw, mir_strlen(truncated));
+ free(tempraw);
+}
+
+/*****************************************************************************/
+void EraseSymbols(char *truncated)
+{
+ int counter = 0;
+ int position = 0, recpos = 0;
+ char *stringfrompos;
+
+ char *tempraw = (char*)malloc(MAXSIZE1);
+ if (truncated)
+ strncpy(tempraw, truncated, MAXSIZE1);
+
+ // //////
+ while (true) {
+ Sleep(1); // avoid 100% CPU
+
+ /**/
+ counter = 0;
+ if ((strstr(tempraw, "&#")) != nullptr) {
+ stringfrompos = strstr(tempraw, "&#");
+ position = stringfrompos - tempraw;
+
+ while (true) {
+ tempraw[position + counter] = ' ';
+ counter++;
+ if (counter > 20)
+ break;
+ if (tempraw[position + counter] == ' ')
+ break;
+ }
+ if (tempraw[position + counter] == ';')
+ tempraw[position + counter] = ' ';
+ }
+ if (recpos == position)
+ break;
+ recpos = position;
+ }
+
+ strncpy(truncated, tempraw, mir_strlen(truncated));
+ free(tempraw);
+}
+
+/*****************************************************************************/
+void NumSymbols(char *truncated)
+{
+ int counter = 0;
+ int position = 0, recpos = 0;
+ char*stringfrompos;
+ char symbol[20];
+ int character;
+
+ char *tempraw = (char*)malloc(MAXSIZE1);
+ if (truncated)
+ strncpy(tempraw, truncated, MAXSIZE1);
+
+ while (true) {
+ Sleep(1); // avoid 100% CPU
+
+ counter = 0;
+
+ if ((strstr(tempraw, "&#")) != nullptr) {
+ stringfrompos = strstr(tempraw, "&#");
+ position = stringfrompos - tempraw;
+
+ while (true) {
+ if (counter > 1)
+ symbol[counter - 2] = tempraw[position + counter];
+
+ tempraw[position + counter] = ' ';
+ counter++;
+ if (counter > 20)
+ break;
+
+ if ((tempraw[position + counter] == ';')) {
+ symbol[counter - 2] = '\0';
+ character = atoi(symbol);
+
+ if (character > 0 && character < 256)
+ memset(&tempraw[position], character, 1);
+ break;
+ }
+ }
+
+ if (tempraw[position + counter] == ';')
+ tempraw[position + counter] = ' ';
+ }
+ if (recpos == position)
+ break;
+ recpos = position;
+ }
+
+ strncpy(truncated, tempraw, mir_strlen(truncated));
+ free(tempraw);
+}
+
+/*****************************************************************************/
+void FastTagFilter(char *truncated)
+{
+ char *tempraw = (char*)malloc(MAXSIZE1);
+ if (truncated)
+ strncpy(tempraw, truncated, MAXSIZE1);
+
+ for (int counter = 0; counter < mir_strlen(tempraw); counter++) {
+ if (tempraw[counter] == '<') {
+ while (tempraw[counter] != '>') {
+ if (counter >= mir_strlen(tempraw))
+ break;
+
+ tempraw[counter] = ' ';
+ counter++;
+ }
+ if (tempraw[counter] == '>')
+ tempraw[counter] = ' ';
+ }
+ }
+
+ strncpy(truncated, tempraw, mir_strlen(truncated));
+ free(tempraw);
+}
+
+/*****************************************************************************/
+void RemoveInvis(char *truncated, int AmountWspcRem)
+{
+ int erase = 0;
+ int RemovalLevel = 0;
+
+ char *tempraw = (char*)malloc(MAXSIZE1);
+ if (truncated)
+ strncpy(tempraw, truncated, MAXSIZE1);
+
+ switch (AmountWspcRem) {
+ case 1:
+ RemovalLevel = 80; // small
+ break;
+ case 2:
+ RemovalLevel = 30; // medium
+ break;
+ case 3:
+ RemovalLevel = 10; // large
+ break;
+ }
+
+ for (int counter = 0; counter < mir_strlen(tempraw); counter++) {
+ if (AmountWspcRem != 0 && AmountWspcRem != 4) {
+ if ((tempraw[counter] == '\n') || (tempraw[counter] == ' ') || (tempraw[counter] == '\r'))
+ erase = erase + 1;
+ else
+ erase = 0;
+
+ if (erase > RemovalLevel)
+ tempraw[counter] = ' ';
+ }
+
+ if (AmountWspcRem == 4)
+ if ((tempraw[counter] == '\n') || (tempraw[counter] == ' ') || (tempraw[counter] == '\r'))
+ tempraw[counter] = ' ';
+ } // end for
+
+ strncpy(truncated, tempraw, mir_strlen(truncated));
+ free(tempraw);
+}
+
+/*****************************************************************************/
+void RemoveTabs(char *truncated)
+{
+ char *tempraw = (char*)malloc(MAXSIZE1);
+ if (truncated)
+ strncpy(tempraw, truncated, MAXSIZE1);
+
+ for (int counter = 0; counter < mir_strlen(tempraw); counter++)
+ if (tempraw[counter] == '\t')
+ tempraw[counter] = ' ';
+
+ strncpy(truncated, tempraw, mir_strlen(truncated));
+ free(tempraw);
+}
+
+/*****************************************************************************/
+void Removewhitespace(char *truncated)
+{
+ int counter2 = 0;
+ int pos1 = 0, pos2 = 0;
+
+ for (int counter = 0; counter < mir_strlen(truncated); counter++) {
+ if (truncated[counter] == ' ' && truncated[counter + 1] == ' ') {
+ pos1 = counter + 1;
+ counter2 = counter;
+
+ while (truncated[counter2] == ' ')
+ counter2++;
+
+ pos2 = counter2;
+ strncpy(&truncated[pos1], &truncated[pos2], mir_strlen(&truncated[pos1]) - 1);
+ } // end if
+ } // end for
+}
+
+/*****************************************************************************/
+void Filter(char *truncated)
+{
+ char tempraw[MAXSIZE1];
+ strncpy(tempraw, truncated, _countof(tempraw));
+
+ for (int counter = 0; counter < mir_strlen(tempraw); counter++)
+ if ((tempraw[counter] == '\n') || (tempraw[counter] == '\r') || (tempraw[counter] == '\t'))
+ strncpy(&tempraw[counter], &tempraw[counter + 1], mir_strlen(&tempraw[counter]) - 1);
+
+ strncpy(truncated, tempraw, mir_strlen(truncated));
+}
diff --git a/protocols/WebView/src/webview_datawnd.cpp b/protocols/WebView/src/webview_datawnd.cpp
new file mode 100644
index 0000000000..dc8b414547
--- /dev/null
+++ b/protocols/WebView/src/webview_datawnd.cpp
@@ -0,0 +1,514 @@
+/*
+* A plugin for Miranda IM which displays web page text in a window Copyright
+* (C) 2005 Vincent Joyce.
+*
+* Miranda IM: the free icq client for MS Windows Copyright (C) 2000-2
+* Richard Hughes, Roland Rabien & Tristan Van de Vreede
+*
+* 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.
+*/
+
+#include "stdafx.h"
+#include "webview.h"
+
+/*****************************************************************************/
+INT_PTR CALLBACK DlgProcFind(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam)
+{
+ static char Searchstr[128];
+ static int loc;
+ static int oldloc;
+ static int startposition;
+ static int OLDstartposition;
+
+ HWND ParentHwnd = GetParent(hwndDlg);
+
+ switch (msg) {
+ case WM_INITDIALOG:
+ TranslateDialogDefault(hwndDlg);
+ SetWindowLongPtr(hwndDlg, GWLP_USERDATA, lParam);
+ SetWindowText(hwndDlg, TranslateT("Find"));
+ SendMessage(hwndDlg, WM_SETICON, ICON_SMALL, (LPARAM)LoadIcon(g_plugin.getInst(), MAKEINTRESOURCE(IDI_FIND)));
+ return TRUE;
+
+ case WM_COMMAND:
+ switch (LOWORD(wParam)) {
+ case IDC_OK: // find Next
+ {
+ char NewSearchstr[128];
+ int location = 0;
+ int startsel = 0, endsel = 0;
+ char buff[MAXSIZE1];
+
+ memset(&NewSearchstr, 0, sizeof(NewSearchstr));
+
+ int len = GetWindowTextLength(GetDlgItem(ParentHwnd, IDC_DATA));
+
+ char *tempbuffer = (char*)malloc(len + 2);
+
+ GetDlgItemTextA(ParentHwnd, IDC_DATA, tempbuffer, len);
+ strncpy(buff, tempbuffer, _countof(buff));
+ free(tempbuffer);
+
+ Filter(buff);
+ CharUpperBuffA(buff, (int)mir_strlen(buff));
+
+ GetDlgItemTextA(hwndDlg, IDC_FINDWHAT, NewSearchstr, _countof(NewSearchstr));
+ CharUpperBuffA(NewSearchstr, (int)mir_strlen(NewSearchstr));
+
+ OLDstartposition = startposition;
+
+ if ((strstr(Searchstr, NewSearchstr)) != nullptr)
+ startposition = loc + (int)mir_strlen(Searchstr);
+ else {
+ oldloc = 0;
+ startposition = 0;
+ }
+
+ mir_strcpy(Searchstr, NewSearchstr);
+
+ if (!(startposition > (int)mir_strlen(buff)))
+ location = (strstr(buff + startposition, NewSearchstr)) - buff;
+
+ oldloc = loc;
+ loc = location;
+
+ if (loc == 0) {
+ ShowWindow(GetDlgItem(hwndDlg, IDC_SEARCH_COMPLETE), SW_SHOW);
+ loc = (strstr(buff, NewSearchstr)) - buff;
+ startsel = loc;
+ endsel = loc + (int)mir_strlen(NewSearchstr);
+ oldloc = 0;
+ startposition = 0;
+ }
+ else {
+ ShowWindow(GetDlgItem(hwndDlg, IDC_SEARCH_COMPLETE), SW_HIDE);
+ startsel = loc;
+ endsel = loc + (int)mir_strlen(NewSearchstr);
+ }
+
+ CHARRANGE sel2 = { startsel, endsel };
+ SendDlgItemMessage(ParentHwnd, IDC_DATA, EM_EXSETSEL, 0, (LPARAM)&sel2);
+ SetFocus(GetDlgItem(ParentHwnd, IDC_DATA));
+ }
+ return TRUE;
+
+ case WM_DESTROY:
+ case IDC_CANCEL:
+ EnableWindow(GetDlgItem(ParentHwnd, IDC_FIND_BUTTON), 1);
+ EnableWindow(ParentHwnd, 1);
+ DestroyWindow(hwndDlg);
+ }
+ break;
+ }
+ return FALSE;
+}
+
+/*****************************************************************************/
+
+static wchar_t tszSizeString[] = L"xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx";
+
+static MCONTACT FindContactByUrl(HWND hwndDlg)
+{
+ MCONTACT res = NULL;
+ wchar_t urltext[300], titlebartxt[300];
+ int contactcount = 0;
+
+ GetDlgItemText(hwndDlg, IDC_OPEN_URL, urltext, _countof(urltext));
+ GetWindowText(hwndDlg, titlebartxt, _countof(titlebartxt));
+
+ for (auto &hContact : Contacts(MODULENAME)) {
+ ptrW db1(g_plugin.getWStringA(hContact, URL_KEY));
+ ptrW db2(g_plugin.getWStringA(hContact, PRESERVE_NAME_KEY));
+
+ if (!mir_wstrcmp(urltext, db1) && !mir_wstrcmp(titlebartxt, db2)) {
+ contactcount++;
+ if (contactcount > 1) {
+ MessageBox(nullptr, TranslateT("ERROR: You have two or more Webview contacts with the same URL and contact name."), _A2W(MODULENAME), MB_OK);
+ return NULL;
+ }
+ res = hContact;
+ }
+ }
+ return res;
+}
+
+INT_PTR CALLBACK DlgProcDisplayData(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam)
+{
+ DBVARIANT dbv;
+ RECT rc;
+ wchar_t url[300];
+ MCONTACT hContact;
+
+ switch (msg) {
+ case WM_INITDIALOG:
+ TranslateDialogDefault(hwndDlg);
+ {
+ MCONTACT hContact2 = lParam;
+
+ SetWindowLongPtr(hwndDlg, GWLP_USERDATA, (LONG_PTR)hContact2);
+ WindowList_Add(hWindowList, hwndDlg, hContact2);
+
+ url[0] = '\0';
+ if (!g_plugin.getWString(hContact2, URL_KEY, &dbv)) {
+ wcsncpy_s(url, dbv.pwszVal, _TRUNCATE);
+ db_free(&dbv);
+ }
+ SetDlgItemText(hwndDlg, IDC_OPEN_URL, FixButtonText(url, _countof(url)));
+
+ char preservename[100];
+ if (!g_plugin.getString(hContact2, PRESERVE_NAME_KEY, &dbv)) {
+ strncpy_s(preservename, _countof(preservename), dbv.pszVal, _TRUNCATE);
+ db_free(&dbv);
+ }
+ else preservename[0] = 0;
+ SetWindowTextA(hwndDlg, preservename);
+
+ SendMessage(hwndDlg, WM_SETICON, ICON_SMALL, (LPARAM)LoadIcon(g_plugin.getInst(), MAKEINTRESOURCE(IDI_SITE)));
+
+ // //////
+ COLORREF colour = BackgoundClr;
+ COLORREF txtcolor;
+ SendDlgItemMessage(hwndDlg, IDC_DATA, EM_SETBKGNDCOLOR, 0, colour);
+
+ SendDlgItemMessage(hwndDlg, IDC_UPDATE_BUTTON, BM_SETIMAGE, IMAGE_ICON, (LPARAM)LoadImage(g_plugin.getInst(), MAKEINTRESOURCE(IDI_UPDATE), IMAGE_ICON, GetSystemMetrics(SM_CXSMICON), GetSystemMetrics(SM_CYSMICON), 0));
+ SendDlgItemMessage(hwndDlg, IDC_UPDATE_BUTTON, BUTTONADDTOOLTIP, (WPARAM)TranslateT("Update data"), BATF_UNICODE);
+
+ SendDlgItemMessage(hwndDlg, IDC_FIND_BUTTON, BM_SETIMAGE, IMAGE_ICON, (LPARAM)LoadImage(g_plugin.getInst(), MAKEINTRESOURCE(IDI_FIND), IMAGE_ICON, GetSystemMetrics(SM_CXSMICON), GetSystemMetrics(SM_CYSMICON), 0));
+ SendDlgItemMessage(hwndDlg, IDC_FIND_BUTTON, BUTTONADDTOOLTIP, (WPARAM)TranslateT("Find"), BATF_UNICODE);
+
+ SendDlgItemMessage(hwndDlg, IDC_OPTIONS_BUTTON, BM_SETIMAGE, IMAGE_ICON, (LPARAM)LoadImage(g_plugin.getInst(), MAKEINTRESOURCE(IDI_OPTIONS), IMAGE_ICON, GetSystemMetrics(SM_CXSMICON), GetSystemMetrics(SM_CYSMICON), 0));
+ SendDlgItemMessage(hwndDlg, IDC_OPTIONS_BUTTON, BUTTONADDTOOLTIP, (WPARAM)TranslateT("Contact options"), BATF_UNICODE);
+
+ SendDlgItemMessage(hwndDlg, IDC_ALERT_BUTTON, BM_SETIMAGE, IMAGE_ICON, (LPARAM)LoadImage(g_plugin.getInst(), MAKEINTRESOURCE(IDI_ALERT), IMAGE_ICON, GetSystemMetrics(SM_CXSMICON), GetSystemMetrics(SM_CYSMICON), 0));
+ SendDlgItemMessage(hwndDlg, IDC_ALERT_BUTTON, BUTTONADDTOOLTIP, (WPARAM)TranslateT("Alert options"), BATF_UNICODE);
+
+ SendDlgItemMessage(hwndDlg, IDC_STOP, BM_SETIMAGE, IMAGE_ICON, (LPARAM)LoadImage(g_plugin.getInst(), MAKEINTRESOURCE(IDI_STOP), IMAGE_ICON, GetSystemMetrics(SM_CXSMICON), GetSystemMetrics(SM_CYSMICON), 0));
+ SendDlgItemMessage(hwndDlg, IDC_STOP, BUTTONADDTOOLTIP, (WPARAM)TranslateT("Stop processing"), BATF_UNICODE);
+
+ SendDlgItemMessage(hwndDlg, IDC_OPEN_URL, BUTTONADDTOOLTIP, (WPARAM)TranslateT("Click here to open this URL in a browser window."), BATF_UNICODE);
+
+ if (!g_plugin.getByte(hContact2, ON_TOP_KEY)) {
+ SendDlgItemMessage(hwndDlg, IDC_STICK_BUTTON, BM_SETIMAGE, IMAGE_ICON, (LPARAM)LoadImage(g_plugin.getInst(), MAKEINTRESOURCE(IDI_UNSTICK), IMAGE_ICON, GetSystemMetrics(SM_CXSMICON), GetSystemMetrics(SM_CYSMICON), 0));
+ SendDlgItemMessage(hwndDlg, IDC_STICK_BUTTON, BUTTONADDTOOLTIP, (WPARAM)TranslateT("Stick to the front"), BATF_UNICODE);
+ }
+ else {
+ SendDlgItemMessage(hwndDlg, IDC_STICK_BUTTON, BM_SETIMAGE, IMAGE_ICON, (LPARAM)LoadImage(g_plugin.getInst(), MAKEINTRESOURCE(IDI_STICK), IMAGE_ICON, GetSystemMetrics(SM_CXSMICON), GetSystemMetrics(SM_CYSMICON), 0));
+ SendDlgItemMessage(hwndDlg, IDC_STICK_BUTTON, BUTTONADDTOOLTIP, (WPARAM)TranslateT("Disable stick to the front"), BATF_UNICODE);
+ }
+
+ SendDlgItemMessage(hwndDlg, IDC_DATA, WM_SETFONT, (WPARAM)h_font, 1);
+
+ txtcolor = TextClr;
+
+ SetDlgItemText(hwndDlg, IDC_DATA, L"");
+
+ InvalidateRect(hwndDlg, nullptr, 1);
+
+ SendDlgItemMessage(hwndDlg, IDC_DATA, EM_AUTOURLDETECT, 1, 0);
+ int mask = (int)SendDlgItemMessage(hwndDlg, IDC_DATA, EM_GETEVENTMASK, 0, 0);
+
+ SendDlgItemMessage(hwndDlg, IDC_DATA, EM_SETEVENTMASK, 0, mask | ENM_LINK | ENM_MOUSEEVENTS);
+
+ SendDlgItemMessage(hwndDlg, IDC_STICK_BUTTON, BUTTONSETASFLATBTN, 0, 0);
+ SendDlgItemMessage(hwndDlg, IDC_UPDATE_BUTTON, BUTTONSETASFLATBTN, 0, 0);
+ SendDlgItemMessage(hwndDlg, IDC_FIND_BUTTON, BUTTONSETASFLATBTN, 0, 0);
+ SendDlgItemMessage(hwndDlg, IDC_OPTIONS_BUTTON, BUTTONSETASFLATBTN, 0, 0);
+ SendDlgItemMessage(hwndDlg, IDC_ALERT_BUTTON, BUTTONSETASFLATBTN, 0, 0);
+ SendDlgItemMessage(hwndDlg, IDC_STOP, BUTTONSETASFLATBTN, 0, 0);
+
+ SendDlgItemMessage(hwndDlg, IDC_OPEN_URL, BUTTONSETASFLATBTN, 0, 0);
+
+ HDC hdc = GetDC(GetDlgItem(hwndDlg, IDC_STATUSBAR));
+ SelectObject(hdc, (HFONT)SendDlgItemMessage(hwndDlg, IDC_STATUSBAR, WM_GETFONT, 0, 0));
+ SIZE textSize;
+ GetTextExtentPoint32(hdc, tszSizeString, _countof(tszSizeString), &textSize);
+ int partWidth[2] = { textSize.cx, -1 };
+ ReleaseDC(GetDlgItem(hwndDlg, IDC_STATUSBAR), hdc);
+
+ SendDlgItemMessage(hwndDlg, IDC_STATUSBAR, SB_SETPARTS, _countof(partWidth), (LPARAM)partWidth);
+ SendDlgItemMessage(hwndDlg, IDC_STATUSBAR, SB_SETTEXT, 1 | SBT_OWNERDRAW, 0);
+
+ if (g_plugin.getByte(SAVE_INDIVID_POS_KEY, 0))
+ Utils_RestoreWindowPosition(hwndDlg, hContact2, MODULENAME, "WV");
+ }
+ break;
+
+ case WM_NOTIFY:
+ switch (((NMHDR *)lParam)->code) {
+ case EN_MSGFILTER:
+ switch (((MSGFILTER *)lParam)->msg) {
+ case WM_RBUTTONUP:
+ {
+ POINT pt;
+ CHARRANGE sel, all = { 0, -1 };
+
+ HMENU hSubMenu = GetSubMenu(hMenu, 0);
+ TranslateMenu(hSubMenu);
+ SendMessage(((NMHDR *)lParam)->hwndFrom, EM_EXGETSEL, 0, (LPARAM)& sel);
+
+ EnableMenuItem(hSubMenu, IDM_COPY, MF_ENABLED);
+ EnableMenuItem(hSubMenu, IDM_CUT, MF_ENABLED);
+ EnableMenuItem(hSubMenu, IDM_DELETE, MF_ENABLED);
+
+ if (sel.cpMin == sel.cpMax) {
+ EnableMenuItem(hSubMenu, IDM_COPY, MF_BYCOMMAND | MF_GRAYED);
+ EnableMenuItem(hSubMenu, IDM_CUT, MF_BYCOMMAND | MF_GRAYED);
+ EnableMenuItem(hSubMenu, IDM_DELETE, MF_BYCOMMAND | MF_GRAYED);
+ }
+ pt.x = (short)LOWORD(((ENLINK *)lParam)->lParam);
+ pt.y = (short)HIWORD(((ENLINK *)lParam)->lParam);
+ ClientToScreen(((NMHDR *)lParam)->hwndFrom, &pt);
+ switch (TrackPopupMenu(hSubMenu, TPM_RETURNCMD, pt.x, pt.y, 0, hwndDlg, nullptr)) {
+ case IDM_COPY:
+ SendMessage(((NMHDR *)lParam)->hwndFrom, WM_COPY, 0, 0);
+ break;
+
+ case IDM_COPYALL:
+ SendMessage(((NMHDR *)lParam)->hwndFrom, EM_EXSETSEL, 0, (LPARAM)& all);
+ SendMessage(((NMHDR *)lParam)->hwndFrom, WM_COPY, 0, 0);
+ SendMessage(((NMHDR *)lParam)->hwndFrom, EM_EXSETSEL, 0, (LPARAM)& sel);
+ break;
+
+ case IDM_SELECTALL:
+ SendMessage(((NMHDR *)lParam)->hwndFrom, EM_EXSETSEL, 0, (LPARAM)& all);
+ break;
+
+ case IDM_CUT:
+ SendMessage(((NMHDR *)lParam)->hwndFrom, WM_CUT, 0, 0);
+ break;
+
+ case IDM_PASTE:
+ SendMessage(((NMHDR *)lParam)->hwndFrom, WM_PASTE, 0, 0);
+ break;
+
+ case IDM_DELETE:
+ SendMessage(((NMHDR *)lParam)->hwndFrom, WM_CLEAR, 0, 0);
+ break;
+
+ case IDM_CLEAR_ALL:
+ SetDlgItemTextA(hwndDlg, IDC_DATA, "");
+ SetFocus(GetDlgItem(hwndDlg, IDC_DATA));
+ break;
+ }
+ }
+ }
+ break;
+
+ case EN_LINK:
+ switch (((ENLINK *)lParam)->msg) {
+ case WM_RBUTTONDOWN:
+ case WM_LBUTTONUP:
+ CHARRANGE sel;
+ SendDlgItemMessage(hwndDlg, IDC_DATA, EM_EXGETSEL, 0, (LPARAM)& sel);
+ if (sel.cpMin != sel.cpMax)
+ break;
+
+ TEXTRANGEA tr;
+ tr.chrg = ((ENLINK *)lParam)->chrg;
+ tr.lpstrText = (char*)malloc(tr.chrg.cpMax - tr.chrg.cpMin + 8);
+
+ SendDlgItemMessage(hwndDlg, IDC_DATA, EM_GETTEXTRANGE, 0, (LPARAM)& tr);
+ if (strchr(tr.lpstrText, '@') != nullptr && strchr(tr.lpstrText, ':') == nullptr && strchr(tr.lpstrText, '/') == nullptr) {
+ memmove(tr.lpstrText + 7, tr.lpstrText, tr.chrg.cpMax - tr.chrg.cpMin + 1);
+ memcpy(tr.lpstrText, "mailto:", 7);
+ }
+
+ Utils_OpenUrl(tr.lpstrText);
+ SetFocus(GetDlgItem(hwndDlg, IDC_DATA));
+
+ free(tr.lpstrText);
+ break;
+ }
+ }
+ break; // notify
+
+ case WM_COMMAND:
+ switch (LOWORD(wParam)) {
+ case IDC_OPEN_URL:
+ GetDlgItemText(hwndDlg, IDC_OPEN_URL, url, _countof(url));
+ Utils_OpenUrlW(url);
+ g_plugin.setWord(wParam, "Status", ID_STATUS_ONLINE);
+ break;
+
+ case IDC_UPDATE_BUTTON:
+ if (hContact = FindContactByUrl(hwndDlg)) {
+ EnableWindow(GetDlgItem(hwndDlg, IDC_UPDATE_BUTTON), 0);
+ UpdateMenuCommand(wParam, lParam, hContact);
+ }
+ break;
+
+ case IDC_STOP:
+ if (hContact = FindContactByUrl(hwndDlg))
+ g_plugin.setByte(hContact, STOP_KEY, 1);
+ break;
+
+ case IDC_STICK_BUTTON:
+ if (hContact = FindContactByUrl(hwndDlg))
+ OnTopMenuCommand(wParam, lParam, hContact);
+ {
+ wchar_t *ptszToolTip;
+ HWND hTopmost;
+ if (!g_plugin.getByte(hContact, ON_TOP_KEY, 0)) {
+ hTopmost = HWND_NOTOPMOST;
+ ptszToolTip = TranslateT("Stick to the front");
+ }
+ else {
+ hTopmost = HWND_TOPMOST;
+ ptszToolTip = TranslateT("Disable stick to the front");
+ }
+ SendDlgItemMessage(hwndDlg, IDC_STICK_BUTTON, BM_SETIMAGE, IMAGE_ICON, (LPARAM)LoadImage(g_plugin.getInst(), MAKEINTRESOURCE(IDI_UNSTICK), IMAGE_ICON, GetSystemMetrics(SM_CXSMICON), GetSystemMetrics(SM_CYSMICON), 0));
+ SendDlgItemMessage(hwndDlg, IDC_STICK_BUTTON, BUTTONADDTOOLTIP, (WPARAM)ptszToolTip, BATF_UNICODE);
+ SetWindowPos(hwndDlg, hTopmost, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE);
+ }
+ break;
+
+ case IDC_FIND_BUTTON:
+ {
+ HWND hwndFind = CreateDialogParam(g_plugin.getInst(), MAKEINTRESOURCE(IDD_FIND), hwndDlg, DlgProcFind, (LPARAM)wParam);
+ ShowWindow(hwndFind, SW_SHOW);
+ EnableWindow(GetDlgItem(hwndDlg, IDC_FIND_BUTTON), 0);
+ }
+ break;
+
+ case IDC_OPTIONS_BUTTON:
+ if (hContact = FindContactByUrl(hwndDlg))
+ DialogBoxParam(g_plugin.getInst(), MAKEINTRESOURCE(IDD_CONTACT_OPT), hwndDlg, DlgProcContactOpt, hContact);
+ break;
+
+ case IDC_ALERT_BUTTON:
+ if (hContact = FindContactByUrl(hwndDlg))
+ DialogBoxParam(g_plugin.getInst(), MAKEINTRESOURCE(IDD_ALRT_OPT), hwndDlg, DlgProcAlertOpt, hContact);
+ break;
+
+ case IDOK:
+ case IDCANCEL:
+ if (hwndDlg != nullptr)
+ DestroyWindow(hwndDlg);
+ return TRUE;
+ }
+ break;
+
+ case WM_CLOSE:
+ if (Yposition == -32000)
+ Yposition = 100;
+
+ if (Xposition == -32000)
+ Xposition = 100;
+
+ SavewinSettings();
+
+ if (hContact = FindContactByUrl(hwndDlg))
+ Utils_SaveWindowPosition(hwndDlg, hContact, MODULENAME, "WV");
+
+ if (hwndDlg != nullptr)
+ DestroyWindow(hwndDlg);
+ return 0;
+
+ case WM_DESTROY:
+ WindowList_Remove(hWindowList, hwndDlg);
+ return 0;
+
+ case WM_SIZE:
+ Utils_ResizeDialog(hwndDlg, g_plugin.getInst(), MAKEINTRESOURCEA(IDD_DISPLAY_DATA), DataDialogResize);
+ InvalidateRect(hwndDlg, nullptr, TRUE);
+
+ // global
+ GetWindowRect(hwndDlg, &rc);
+ Xposition = rc.left;
+ Yposition = rc.top;
+ WindowHeight = rc.bottom - rc.top;
+ WindowWidth = rc.right - rc.left;
+ break;
+
+ case WM_MOVE:
+ if (!IsIconic(hwndDlg) && !IsZoomed(hwndDlg)) {
+ GetWindowRect(hwndDlg, &rc);
+ // global
+ Xposition = rc.left;
+ Yposition = rc.top;
+ WindowHeight = rc.bottom - rc.top;
+ WindowWidth = rc.right - rc.left;
+
+ if ((GetAsyncKeyState(VK_CONTROL) & 0x8000))
+ break;
+
+ ValidatePosition(hwndDlg);
+ }
+ }
+ return FALSE;
+}
+
+/*****************************************************************************/
+
+int DataDialogResize(HWND, LPARAM, UTILRESIZECONTROL *urc)
+{
+ switch (urc->wId) {
+ case IDC_OPEN_URL:
+ return RD_ANCHORX_WIDTH | RD_ANCHORY_TOP;
+ case IDC_DATA:
+ return RD_ANCHORX_WIDTH | RD_ANCHORY_HEIGHT;
+ case IDC_STATUSBAR:
+ return RD_ANCHORX_WIDTH | RD_ANCHORX_RIGHT;
+
+ }
+ return RD_ANCHORX_LEFT | RD_ANCHORY_TOP;
+}
+
+/*****************************************************************************/
+
+void SavewinSettings(void)
+{
+ if (Yposition == -32000)
+ Yposition = 100;
+
+ if (Xposition == -32000)
+ Xposition = 100;
+
+ g_plugin.setDword(Xpos_WIN_KEY, Xposition);
+ g_plugin.setDword(Ypos_WIN_KEY, Yposition);
+
+ g_plugin.setDword(BG_COLOR_KEY, BackgoundClr);
+ g_plugin.setDword(TXT_COLOR_KEY, TextClr);
+ g_plugin.setDword(WIN_HEIGHT_KEY, WindowHeight);
+ g_plugin.setDword(WIN_WIDTH_KEY, WindowWidth);
+
+}
+
+/*****************************************************************************/
+void ValidatePosition(HWND)
+{
+ RECT r;
+ SystemParametersInfo(SPI_GETWORKAREA, 0, &r, 0);
+
+ POINT pt = { 0, 0 };
+ HMONITOR hMonitor = MonitorFromPoint(pt, MONITOR_DEFAULTTONEAREST); // always
+
+ MONITORINFO monitorInfo;
+ monitorInfo.cbSize = sizeof(MONITORINFO);
+ if (GetMonitorInfo(hMonitor, &monitorInfo))
+ memcpy(&r, &monitorInfo.rcMonitor, sizeof(RECT));
+
+ // /window going off right of screen*
+ if (Xposition + WindowWidth >= r.right)
+ Xposition = r.right - WindowWidth;
+
+ // window going off bottom of screen
+ if (Yposition + WindowHeight >= r.bottom)
+ Yposition = r.bottom - WindowHeight;
+
+ // window going off left of screen
+ if (Xposition >= r.right)
+ Xposition = 0;
+}
diff --git a/protocols/WebView/src/webview_getdata.cpp b/protocols/WebView/src/webview_getdata.cpp
new file mode 100644
index 0000000000..155f1be6c9
--- /dev/null
+++ b/protocols/WebView/src/webview_getdata.cpp
@@ -0,0 +1,511 @@
+/*
+* A plugin for Miranda IM which displays web page text in a window Copyright
+* (C) 2005 Vincent Joyce.
+*
+* Miranda IM: the free icq client for MS Windows Copyright (C) 2000-2
+* Richard Hughes, Roland Rabien & Tristan Van de Vreede
+*
+* 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.
+*/
+
+#include "stdafx.h"
+#include "webview.h"
+
+int Startingup = 1;
+int AlreadyDownloading = 0;
+
+/*******************/
+void GetData(void *param)
+{
+ MCONTACT hContact = (DWORD_PTR)param;
+ int statpos = 0, dispos = 0, statposend = 0;
+ char*pos;
+ DBVARIANT dbv;
+ char tempstring[300], tempstring2[300];
+ int MallocSize = 0;
+ int DownloadSuccess = 0;
+ char*raw;
+ char truncated[MAXSIZE1];
+ char truncated2[MAXSIZE2];
+ int trunccount = 0;
+ char url[300];
+ unsigned long downloadsize = 0;
+ int AmountWspcRem = 0;
+ static char contactname[100];
+ int TherewasAlert = 0;
+ int PosButnClick = 0;
+ char tstr[128];
+ static char timestring[128];
+ int eventIndex = 0;
+ int location = 0;
+ int location2 = 0;
+
+ if (Startingup)
+ Sleep(2000);
+
+ HWND hwndDlg = (WindowList_Find(hWindowList, hContact));
+
+ Startingup = 0;
+
+ memset(&url, 0, sizeof(url));
+ memset(&contactname, 0, sizeof(contactname));
+ memset(&tempstring, 0, sizeof(tempstring));
+ memset(&tempstring2, 0, sizeof(tempstring2));
+ memset(&dbv, 0, sizeof(dbv));
+ memset(&tstr, 0, sizeof(tstr));
+ memset(&timestring, 0, sizeof(timestring));
+
+ g_plugin.setByte(hContact, STOP_KEY, 0);
+
+ if (g_plugin.getString(hContact, PRESERVE_NAME_KEY, &dbv)) {
+ if (!db_get_s(hContact, "CList", "MyHandle", &dbv)) {
+ g_plugin.setString(hContact, PRESERVE_NAME_KEY, dbv.pszVal);
+ db_free(&dbv);
+ }
+ }
+
+ if (!g_plugin.getString(hContact, PRESERVE_NAME_KEY, &dbv)) {
+ strncpy_s(contactname, _countof(contactname), dbv.pszVal, _TRUNCATE);
+ db_free(&dbv);
+ }
+
+ url[0] = '\0';
+
+ if (!Startingup)
+ g_plugin.setByte(HAS_CRASHED_KEY, 1);
+
+ if (!g_plugin.getString(hContact, START_STRING_KEY, &dbv)) {
+ strncpy_s(tempstring, _countof(tempstring), dbv.pszVal, _TRUNCATE);
+ db_free(&dbv);
+ }
+
+ if (!g_plugin.getString(hContact, END_STRING_KEY, &dbv)) {
+ strncpy_s(tempstring2, _countof(tempstring2), dbv.pszVal, _TRUNCATE);
+ db_free(&dbv);
+ }
+
+ if (!g_plugin.getString(hContact, URL_KEY, &dbv)) {
+ strncpy_s(url, _countof(url), dbv.pszVal, _TRUNCATE);
+ db_free(&dbv);
+ }
+
+ if (mir_strlen(url) < 3)
+ WErrorPopup(hContact, TranslateT("URL not supplied"));
+
+ NETLIBHTTPREQUEST nlhr = { sizeof(nlhr) };
+ nlhr.requestType = REQUEST_GET;
+ nlhr.flags = NLHRF_DUMPASTEXT;
+ nlhr.szUrl = url;
+ nlhr.headersCount = 2;
+
+ NETLIBHTTPHEADER headers[2];
+ headers[0].szName = "User-Agent";
+ headers[0].szValue = NETLIB_USER_AGENT;
+
+ headers[1].szName = "Content-Length";
+ headers[1].szValue = nullptr;
+
+ nlhr.headers = headers;
+
+ if ( g_plugin.getByte(NO_PROTECT_KEY, 0)) // disable
+ AlreadyDownloading = 0;
+
+ // //try site////
+ if (!AlreadyDownloading) { // not already downloading
+ if (IsWindowEnabled(GetDlgItem(hwndDlg, IDC_UPDATE_BUTTON)))
+ PosButnClick = 0;
+ else
+ PosButnClick = 1;
+ EnableWindow(GetDlgItem(hwndDlg, IDC_UPDATE_BUTTON), 1);
+
+ SetDlgItemText(hwndDlg, IDC_STATUSBAR, TranslateT("Download in progress, please wait..."));
+ db_set_ws(hContact, "CList", "StatusMsg", TranslateT("Updating..."));
+ g_plugin.setWord(hContact, "Status", ID_STATUS_DND); // download
+
+ NETLIBHTTPREQUEST *nlhrReply = Netlib_HttpTransaction(hNetlibUser, &nlhr);
+ if (nlhrReply) {
+ if (nlhrReply->resultCode < 200 || nlhrReply->resultCode >= 300) {
+ g_plugin.setWord(hContact, "Status", ID_STATUS_AWAY);
+
+ wchar_t *statusText = TranslateT("The server replied with a failure code");
+ SetDlgItemText(hwndDlg, IDC_STATUSBAR, statusText);
+ WErrorPopup(hContact, statusText);
+ db_set_ws(hContact, "CList", "StatusMsg", statusText);
+ }
+ if (nlhrReply->dataLength) {
+ trunccount = 0;
+ downloadsize = (ULONG)mir_strlen(nlhrReply->pData);
+ strncpy_s(truncated2, nlhrReply->pData, _TRUNCATE);
+ AlreadyDownloading = 1;
+ } // END DATELENGTH
+ } // END REPLY
+
+ if (!nlhrReply) {
+ g_plugin.setWord(hContact, "Status", ID_STATUS_NA);
+
+ wchar_t *statusText = TranslateT("The server is down or lagging.");
+ SetDlgItemText(hwndDlg, IDC_STATUSBAR, statusText);
+ WErrorPopup(hContact, statusText);
+ db_set_ws(hContact, "CList", "StatusMsg", statusText);
+ }
+
+ if (!(nlhrReply))
+ DownloadSuccess = 0;
+
+ if ((nlhrReply) && (nlhrReply->resultCode < 200 || nlhrReply->resultCode >= 300))
+ DownloadSuccess = 0;
+ else if (nlhrReply)
+ DownloadSuccess = 1;
+
+ Netlib_FreeHttpRequest(nlhrReply);
+
+ if (DownloadSuccess)
+ SetDlgItemText(hwndDlg, IDC_STATUSBAR, TranslateT("Download successful; about to process data..."));
+
+ // download successful
+ if (DownloadSuccess) {
+ // all the site
+ if (g_plugin.getByte(hContact, U_ALLSITE_KEY, 0) == 1)
+ mir_strncpy(truncated, truncated2, MAXSIZE1);
+ else { // use start and end string
+ // putting data into string
+ if (((strstr(truncated2, tempstring)) != nullptr) && ((strstr(truncated2, tempstring2)) != nullptr)) {
+ // start string
+ pos = strstr(truncated2, tempstring);
+ statpos = pos - truncated2;
+
+ memset(&pos, 0, sizeof(pos)); // XXX: looks bad.
+ // end string
+ pos = strstr(truncated2, tempstring2);
+ statposend = pos - truncated2 + (int)mir_strlen(tempstring2);
+
+ if (statpos > statposend) {
+ memset(&truncated2, ' ', statpos);
+ memset(&pos, 0, sizeof(pos)); // XXX: looks bad.
+ pos = strstr(truncated2, tempstring2);
+ statposend = pos - truncated2 + (int)mir_strlen(tempstring2);
+ }
+ if (statpos < statposend) {
+ memset(&raw, 0, sizeof(raw));
+
+ // get size for malloc
+ MallocSize = statposend - statpos;
+ raw = (char *) malloc(MallocSize + 1);
+
+ // start string
+ pos = strstr(truncated2, tempstring);
+ statpos = pos - truncated2;
+
+ // end string
+ pos = strstr(truncated2, tempstring2);
+ statposend = pos - truncated2 + (int)mir_strlen(tempstring2);
+
+ if (statpos > statposend) {
+ memset(&truncated2, ' ', statpos);
+ memset(&pos, 0, sizeof(pos)); // XXX
+ pos = strstr(truncated2, tempstring2);
+ statposend = pos - truncated2 + (int)mir_strlen(tempstring2);
+ }
+ dispos = 0;
+
+ strncpy(raw, &truncated2[statpos], MallocSize);
+ raw[MallocSize] = '\0';
+
+ trunccount = 0;
+
+ mir_strncpy(truncated, raw, MAXSIZE1);
+
+ free(raw);
+
+ DownloadSuccess = 1;
+ }
+ else if (g_plugin.getByte(hContact, U_ALLSITE_KEY, 0) == 0) {
+ wchar_t *szStatusText = TranslateT("Invalid search parameters.");
+ WErrorPopup(hContact, szStatusText);
+
+ DownloadSuccess = 0;
+ SetDlgItemText(hwndDlg, IDC_STATUSBAR, szStatusText);
+ g_plugin.setWord(hContact, "Status", ID_STATUS_AWAY);
+ }
+ } // end putting data into string
+ } // end use start and end strings
+ } // end download success
+
+ if (DownloadSuccess) { // download success
+ if (statpos == 0 && statposend == 0) {
+ if (g_plugin.getByte(hContact, U_ALLSITE_KEY, 0) == 0) {
+ wchar_t *statusText = TranslateT("Both search strings not found or strings not set.");
+ WErrorPopup(hContact, statusText);
+ db_set_ws(hContact, "CList", "StatusMsg", statusText);
+
+ DownloadSuccess = 0;
+ SetDlgItemText(hwndDlg, IDC_STATUSBAR, statusText);
+ TherewasAlert = ProcessAlerts(hContact, _T2A(statusText), contactname, contactname, 1);
+ g_plugin.setWord(hContact, "Status", ID_STATUS_AWAY);
+ }
+ }
+ } // end download success
+
+ if (DownloadSuccess) { // download success
+ char timeprefix[32];
+ char temptime1[32];
+ char timeat[16];
+ char temptime2[32];
+ char temptime[128];
+ time_t ftime;
+ struct tm *nTime;
+
+ if (!g_plugin.getString(hContact, PRESERVE_NAME_KEY, &dbv)) {
+ memset(&temptime, 0, sizeof(temptime));
+ memset(&tstr, 0, sizeof(tstr));
+ ftime = time(0);
+ nTime = localtime(&ftime);
+ // 12 hour
+ if (g_plugin.getByte(hContact, USE_24_HOUR_KEY, 0) == 0)
+ strftime(temptime, 128, "(%b %d,%I:%M %p)", nTime);
+ // 24 hour
+ if (g_plugin.getByte(hContact, USE_24_HOUR_KEY, 0) == 1)
+ strftime(temptime, 128, "(%b %d,%H:%M:%S)", nTime);
+
+ if (g_plugin.getByte(hContact, CONTACT_PREFIX_KEY, 1) == 1)
+ mir_snprintf(tstr, "%s %s", temptime, dbv.pszVal);
+ if (g_plugin.getByte(hContact, CONTACT_PREFIX_KEY, 1) == 0)
+ mir_snprintf(tstr, "%s %s", dbv.pszVal, temptime);
+ db_free(&dbv);
+ }
+ else {
+ db_get_ws(hContact, "CList", "MyHandle", &dbv);
+ memset(&temptime, 0, sizeof(temptime));
+ memset(&tstr, 0, sizeof(tstr));
+ ftime = time(0);
+ nTime = localtime(&ftime);
+ // 12 hour
+ if (g_plugin.getByte(hContact, USE_24_HOUR_KEY, 0) == 0)
+ strftime(temptime, 128, "(%b %d,%I:%M %p)", nTime);
+ // 24 hour
+ if (g_plugin.getByte(hContact, USE_24_HOUR_KEY, 0) == 1)
+ strftime(temptime, 128, "(%b %d,%H:%M:%S)", nTime);
+
+ g_plugin.setWString(hContact, PRESERVE_NAME_KEY, dbv.pwszVal);
+ if (g_plugin.getByte(hContact, CONTACT_PREFIX_KEY, 1) == 1)
+ mir_snprintf(tstr, "%s %s", temptime, dbv.pszVal);
+ if (g_plugin.getByte(hContact, CONTACT_PREFIX_KEY, 1) == 0)
+ mir_snprintf(tstr, "%s %s", dbv.pszVal, temptime);
+ db_free(&dbv);
+ }
+
+ ftime = time(0);
+ nTime = localtime(&ftime);
+
+ strncpy_s(timeprefix, _countof(timeprefix), Translate("Last updated on"), _TRUNCATE);
+ strncpy_s(timeat, _countof(timeat), Translate("at the time"), _TRUNCATE);
+ strftime(temptime1, 32, " %a, %b %d, %Y ", nTime);
+ strftime(temptime2, 32, " %I:%M %p.", nTime);
+ mir_snprintf(timestring, " %s %s%s%s", timeprefix, temptime1, timeat, temptime2);
+ } // end download success
+
+ if (DownloadSuccess) {
+ TherewasAlert = ProcessAlerts(hContact, truncated, tstr, contactname, 0);
+
+ // get range of text to be highlighted when part of change changes
+ if (TherewasAlert) {
+ // ////////////////////////
+ static char buff[MAXSIZE1];
+ char Alerttempstring[300], Alerttempstring2[300];
+
+ eventIndex = g_plugin.getByte(hContact, EVNT_INDEX_KEY, 0);
+ if (eventIndex == 2) {
+ strncpy(buff, truncated, _countof(buff));
+ Filter(buff);
+
+ if (!g_plugin.getString(hContact, ALRT_S_STRING_KEY, &dbv)) {
+ strncpy_s(Alerttempstring, _countof(Alerttempstring), dbv.pszVal, _TRUNCATE);
+ db_free(&dbv);
+ }
+ if (!g_plugin.getString(hContact, ALRT_E_STRING_KEY, &dbv)) {
+ strncpy_s(Alerttempstring2, _countof(Alerttempstring2), dbv.pszVal, _TRUNCATE);
+ db_free(&dbv);
+ }
+
+ // putting data into string
+ if (((strstr(buff, Alerttempstring)) != nullptr) && ((strstr(buff, Alerttempstring2)) != nullptr)) {
+ location = (strstr(buff, Alerttempstring)) - buff;
+ location2 = (strstr(buff, Alerttempstring2)) - buff;
+ }
+ }
+ }
+
+ if ((((strstr(truncated2, tempstring)) != nullptr) && ((strstr(truncated2, tempstring2)) != nullptr) && (g_plugin.getByte(hContact, U_ALLSITE_KEY, 0) == 0)) || (g_plugin.getByte(hContact, U_ALLSITE_KEY, 0) == 1)) {
+ RemoveTabs(truncated);
+
+ if ( g_plugin.getByte(hContact, CLEAR_DISPLAY_KEY, 0)) {
+ SendToRichEdit(hwndDlg, truncated, TextClr, BackgoundClr);
+ SetDlgItemText(hwndDlg, IDC_STATUSBAR, TranslateT("Processing data (Stage 1)"));
+
+ if (g_plugin.getByte(hContact, STOP_KEY, 1) == 1) {
+LBL_Stop: wchar_t *statusText = TranslateT("Processing data stopped by user.");
+ SetDlgItemText(hwndDlg, IDC_STATUSBAR, statusText);
+ g_plugin.setByte(hContact, STOP_KEY, 0);
+ g_plugin.setWord(hContact, "Status", ID_STATUS_ONLINE);
+ db_set_ws(hContact, "CList", "StatusMsg", statusText);
+ AlreadyDownloading = 0;
+ return;
+ }
+
+ CodetoSymbol(truncated);
+ Sleep(100); // avoid 100% CPU
+
+ SendToRichEdit(hwndDlg, truncated, TextClr, BackgoundClr);
+ SetDlgItemText(hwndDlg, IDC_STATUSBAR, TranslateT("Processing data (Stage 2)"));
+ if (g_plugin.getByte(hContact, STOP_KEY, 1) == 1)
+ goto LBL_Stop;
+
+ EraseBlock(truncated);
+ Sleep(100); // avoid 100% CPU
+
+ SendToRichEdit(hwndDlg, truncated, TextClr, BackgoundClr);
+ SetDlgItemText(hwndDlg, IDC_STATUSBAR, TranslateT("Processing data (Stage 3)"));
+ if (g_plugin.getByte(hContact, STOP_KEY, 1) == 1)
+ goto LBL_Stop;
+
+ FastTagFilter(truncated);
+ Sleep(100); // avoid 100% CPU
+
+ SendToRichEdit(hwndDlg, truncated, TextClr, BackgoundClr);
+ SetDlgItemText(hwndDlg, IDC_STATUSBAR, TranslateT("Processing data (Stage 4)"));
+ if (g_plugin.getByte(hContact, STOP_KEY, 1) == 1)
+ goto LBL_Stop;
+
+ NumSymbols(truncated);
+ Sleep(100); // avoid 100% CPU
+
+ SendToRichEdit(hwndDlg, truncated, TextClr, BackgoundClr);
+ SetDlgItemText(hwndDlg, IDC_STATUSBAR, TranslateT("Processing data (Stage 5)"));
+ if (g_plugin.getByte(hContact, STOP_KEY, 1) == 1)
+ goto LBL_Stop;
+
+ EraseSymbols(truncated);
+ Sleep(100); // avoid 100% CPU
+
+ SendToRichEdit(hwndDlg, truncated, TextClr, BackgoundClr);
+ SetDlgItemText(hwndDlg, IDC_STATUSBAR, TranslateT("Processing data (Stage 6)"));
+
+ AmountWspcRem = g_plugin.getByte(hContact, RWSPACE_KEY, 0);
+ if (g_plugin.getByte(hContact, STOP_KEY, 1) == 1)
+ goto LBL_Stop;
+
+ RemoveInvis(truncated, AmountWspcRem);
+ Sleep(100); // avoid 100% CPU
+
+ SendToRichEdit(hwndDlg, truncated, TextClr, BackgoundClr);
+ SetDlgItemText(hwndDlg, IDC_STATUSBAR, TranslateT("Processing data (Stage 7)"));
+ if (g_plugin.getByte(hContact, STOP_KEY, 1) == 1)
+ goto LBL_Stop;
+
+ Removewhitespace(truncated);
+
+ SendToRichEdit(hwndDlg, truncated, TextClr, BackgoundClr);
+ SetDlgItemText(hwndDlg, IDC_STATUSBAR, TranslateT("Processing data (Stage 8)"));
+
+ //data in popup
+ if (TherewasAlert)
+ if ( g_plugin.getByte(DATA_POPUP_KEY, 0))
+ WAlertPopup(hContact, _A2T(truncated));
+
+ if (g_plugin.getByte(hContact, STOP_KEY, 1) == 1)
+ goto LBL_Stop;
+
+ // removed any excess characters at the end.
+ if ((truncated[mir_strlen(truncated) - 1] == truncated[mir_strlen(truncated) - 2]) && (truncated[mir_strlen(truncated) - 2] == truncated[mir_strlen(truncated) - 3])) {
+ int counterx = 0;
+
+ while (true) {
+ counterx++;
+ if (truncated[mir_strlen(truncated) - counterx] != truncated[mir_strlen(truncated) - 1]) {
+ truncated[(mir_strlen(truncated) - counterx) + 2] = '\0';
+ break;
+ }
+ }
+ }
+ }
+ }
+
+ if (TherewasAlert) {
+ g_plugin.setWord(hContact, "Status", ID_STATUS_OCCUPIED);
+ db_set_ws(hContact, "CList", "StatusMsg", TranslateT("Alert!"));
+ }
+ else {
+ g_plugin.setWord(hContact, "Status", ID_STATUS_ONLINE);
+ db_set_ws(hContact, "CList", "StatusMsg", TranslateT("Online"));
+ }
+ }
+
+ if (g_plugin.getByte(hContact, U_ALLSITE_KEY, 0) == 0) {
+ if (statpos > statposend)
+ DownloadSuccess = 0;
+ else if (statpos == 0 && statposend == 0)
+ DownloadSuccess = 0;
+ else
+ DownloadSuccess = 1;
+ }
+
+ AlreadyDownloading = 0;
+ } // end not already downloading
+
+ if (AlreadyDownloading)
+ SetDlgItemText(hwndDlg, IDC_STATUSBAR, TranslateT("A site is already downloading, try again in a moment."));
+
+ if (DownloadSuccess) { // download success
+ char BytesString[128];
+
+ // update window if the update only on alert option isn't ticked or
+ // there was an alert or the update button was clicked
+ if ((!(g_plugin.getByte(UPDATE_ONALERT_KEY, 0))) || (TherewasAlert == 1) || (PosButnClick == 1)) {
+ SendToRichEdit(hwndDlg, truncated, TextClr, BackgoundClr);
+
+ if (TherewasAlert) {
+ // highlight text when part of change changes
+ if (eventIndex == 2) {
+ CHARRANGE sel2 = {location, location2};
+
+ SendDlgItemMessage(hwndDlg, IDC_DATA, EM_EXSETSEL, 0, (LPARAM)&sel2);
+ SetFocus(GetDlgItem(hwndDlg, IDC_DATA));
+
+ DWORD HiBackgoundClr = g_plugin.getDword(BG_COLOR_KEY, Def_color_bg);
+ DWORD HiTextClr = g_plugin.getDword(TXT_COLOR_KEY, Def_color_txt);
+
+ CHARFORMAT2 Format;
+ memset(&Format, 0, sizeof(Format));
+ Format.cbSize = sizeof(Format);
+ Format.dwMask = CFM_BOLD | CFM_COLOR | CFM_BACKCOLOR;
+ Format.dwEffects = CFE_BOLD;
+ Format.crBackColor = ((~HiBackgoundClr) & 0x00ffffff);
+ Format.crTextColor = ((~HiTextClr) & 0x00ffffff);
+ SendDlgItemMessage(hwndDlg, IDC_DATA, EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM)&Format);
+ }
+ }
+
+ SetDlgItemTextA(hwndDlg, IDC_STATUSBAR, timestring);
+ sprintf(BytesString, "%s: %d | %s: %lu", (Translate("Bytes in display")), (GetWindowTextLength(GetDlgItem(hwndDlg, IDC_DATA))), (Translate("Bytes downloaded")), downloadsize);
+
+ SendDlgItemMessage(hwndDlg, IDC_STATUSBAR, SB_SETTEXT, 1, (LPARAM)BytesString);
+ }
+ else SetDlgItemText(hwndDlg, IDC_STATUSBAR, TranslateT("Alert test conditions not met; press the refresh button to view content."));
+ }
+ EnableWindow(GetDlgItem(hwndDlg, IDC_UPDATE_BUTTON), 1);
+
+ if (!Startingup)
+ g_plugin.setByte(HAS_CRASHED_KEY, 0);
+}
diff --git a/protocols/WebView/src/webview_opts.cpp b/protocols/WebView/src/webview_opts.cpp
new file mode 100644
index 0000000000..0c51759b42
--- /dev/null
+++ b/protocols/WebView/src/webview_opts.cpp
@@ -0,0 +1,1265 @@
+/*
+* A plugin for Miranda IM which displays web page text in a window
+* Copyright (C) 2005 Vincent Joyce.
+*
+* Miranda IM: the free icq client for MS Windows Copyright (C) 2000-2
+* Richard Hughes, Roland Rabien & Tristan Van de Vreede
+*
+* 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.
+*/
+
+#include "stdafx.h"
+#include "webview.h"
+
+const wchar_t *szTrackerBarDescr[] = {
+ LPGENW("No whitespace removal"),
+ LPGENW("Minimal level of whitespace removal"),
+ LPGENW("Medium level of whitespace removal"),
+ LPGENW("Large level of whitespace removal"),
+ LPGENW("Remove all whitespace")
+};
+
+static char *fontSizes[] = { "8", "10", "14", "16", "18", "20", "24", "28" };
+static wchar_t *AlertTypes[] = { LPGENW("Popup plugin"), LPGENW("Log to file"), LPGENW("Open data display window"), LPGENW("Use OSD plugin") };
+static wchar_t *EventTypes[] = { LPGENW("A string is present"), LPGENW("The web page changes"), LPGENW("A specific part of web page changes") };
+
+#define M_FILLSCRIPTCOMBO (WM_USER+16)
+
+wchar_t* FixButtonText(wchar_t *url, size_t len)
+{
+ wchar_t buttontext[256], stringbefore[256], newbuttontext[256];
+ wcsncpy_s(buttontext, url, _TRUNCATE);
+ wcsncpy_s(newbuttontext, url, _TRUNCATE);
+
+ if (wcschr(newbuttontext, '&') != nullptr) {
+ while (true) {
+ if (wcschr(newbuttontext, '&') == nullptr)
+ break;
+
+ wcsncpy_s(buttontext, newbuttontext, _TRUNCATE);
+ wchar_t *stringafter = wcschr(buttontext, '&');
+ int pos = (stringafter - buttontext);
+ int posbefore = (stringafter - buttontext) - 1;
+ int posafter = (stringafter - buttontext) + 1;
+ strdelw(stringafter, 1);
+ wcsncpy_s(stringbefore, pos, buttontext, _TRUNCATE);
+ mir_snwprintf(newbuttontext, L"%s!!%s", stringbefore, stringafter);
+
+ posafter = 0;
+ posbefore = 0;
+ }
+
+ while (true) {
+ if (wcschr(newbuttontext, '!') != nullptr) {
+ wchar_t *stringafter = wcschr(newbuttontext, '!');
+ int pos = (stringafter - newbuttontext);
+ newbuttontext[pos] = '&';
+ }
+ if (wcschr(newbuttontext, '!') == nullptr)
+ break;
+ }
+ }
+
+ wcsncpy_s(url, len, newbuttontext, _TRUNCATE);
+ return url;
+}
+
+/*****************************************************************************/
+static int CALLBACK EnumFontScriptsProc(ENUMLOGFONTEX * lpelfe, NEWTEXTMETRICEX*, int, LPARAM lParam)
+{
+ if (SendMessage((HWND)lParam, CB_FINDSTRINGEXACT, -1, (LPARAM)lpelfe->elfScript) == CB_ERR) {
+ int i = SendMessage((HWND)lParam, CB_ADDSTRING, 0, (LPARAM)lpelfe->elfScript);
+
+ SendMessage((HWND)lParam, CB_SETITEMDATA, i, lpelfe->elfLogFont.lfCharSet);
+ }
+ return TRUE;
+}
+
+/*****************************************************************************/
+// copied and modified from NewStatusNotify
+INT_PTR CALLBACK DlgPopUpOpts(HWND hdlg, UINT msg, WPARAM wParam, LPARAM lParam)
+{
+
+ char str[512];
+ DWORD BGColour = 0;
+ DWORD TextColour = 0;
+ DWORD delay = 0;
+ static int test = 0;
+
+ switch (msg) {
+ case WM_INITDIALOG:
+ TranslateDialogDefault(hdlg);
+
+ delay = g_plugin.getDword(POP_DELAY_KEY, 0);
+
+ // setting popup delay option
+ _itoa(delay, str, 10);
+ SetDlgItemTextA(hdlg, IDC_DELAY, str);
+
+ BGColour = g_plugin.getDword(POP_BG_CLR_KEY, Def_color_bg);
+ TextColour = g_plugin.getDword(POP_TXT_CLR_KEY, Def_color_txt);
+
+ // Colours. First step is configuring the colours.
+ SendDlgItemMessage(hdlg, IDC_POP_BGCOLOUR, CPM_SETCOLOUR, 0, BGColour);
+ SendDlgItemMessage(hdlg, IDC_POP_TEXTCOLOUR, CPM_SETCOLOUR, 0, TextColour);
+ // Second step is disabling them if we want to use default Windows
+ // ones.
+ CheckDlgButton(hdlg, IDC_POP_USEWINCOLORS, g_plugin.getByte(POP_USEWINCLRS_KEY, 0) ? BST_CHECKED : BST_UNCHECKED);
+ CheckDlgButton(hdlg, IDC_POP_USESAMECOLORS, g_plugin.getByte(POP_USESAMECLRS_KEY, 1) ? BST_CHECKED : BST_UNCHECKED);
+ CheckDlgButton(hdlg, IDC_POP_USECUSTCOLORS, g_plugin.getByte(POP_USECUSTCLRS_KEY, 0) ? BST_CHECKED : BST_UNCHECKED);
+
+ if (IsDlgButtonChecked(hdlg, IDC_POP_USEWINCOLORS) || IsDlgButtonChecked(hdlg, IDC_POP_USESAMECOLORS)) {
+ EnableWindow(GetDlgItem(hdlg, IDC_POP_BGCOLOUR), 0);
+ EnableWindow(GetDlgItem(hdlg, IDC_POP_TEXTCOLOUR), 0);
+ }
+
+ CheckDlgButton(hdlg, IDC_LCLK_WINDOW, g_plugin.getByte(LCLK_WINDOW_KEY, 0) ? BST_CHECKED : BST_UNCHECKED);
+ CheckDlgButton(hdlg, IDC_LCLK_WEB_PGE, g_plugin.getByte(LCLK_WEB_PGE_KEY, 0) ? BST_CHECKED : BST_UNCHECKED);
+ CheckDlgButton(hdlg, IDC_LCLK_DISMISS, g_plugin.getByte(LCLK_DISMISS_KEY, 1) ? BST_CHECKED : BST_UNCHECKED);
+
+ CheckDlgButton(hdlg, IDC_RCLK_WINDOW, g_plugin.getByte(RCLK_WINDOW_KEY, 0) ? BST_CHECKED : BST_UNCHECKED);
+ CheckDlgButton(hdlg, IDC_RCLK_WEB_PGE, g_plugin.getByte(RCLK_WEB_PGE_KEY, 1) ? BST_CHECKED : BST_UNCHECKED);
+ CheckDlgButton(hdlg, IDC_RCLK_DISMISS, g_plugin.getByte(RCLK_DISMISS_KEY, 0) ? BST_CHECKED : BST_UNCHECKED);
+ return TRUE;
+
+ case WM_COMMAND:
+ // enable the "apply" button
+ if (HIWORD(wParam) == BN_CLICKED && GetFocus() == (HWND)lParam)
+ SendMessage(GetParent(hdlg), PSM_CHANGED, 0, 0);
+ // These are simple clicks: we don't save, but we tell the Options Page
+ // to enable the "Apply" button.
+ switch (LOWORD(wParam)) {
+ case IDC_POP_BGCOLOUR: // Fall through
+ case IDC_POP_TEXTCOLOUR:
+ // select new colors
+ if (HIWORD(wParam) == CPN_COLOURCHANGED)
+ SendMessage(GetParent(hdlg), PSM_CHANGED, 0, 0);
+ break;
+
+ case IDC_POP_USESAMECOLORS:
+ // use same color as data window - enable/disable color selection
+ // controls
+ EnableWindow(GetDlgItem(hdlg, IDC_POP_BGCOLOUR), !((BYTE)IsDlgButtonChecked(hdlg, IDC_POP_USESAMECOLORS)));
+ EnableWindow(GetDlgItem(hdlg, IDC_POP_TEXTCOLOUR), !((BYTE)IsDlgButtonChecked(hdlg, IDC_POP_USESAMECOLORS)));
+ SendMessage(GetParent(hdlg), PSM_CHANGED, 0, 0);
+ break;
+
+ case IDC_POP_USEWINCOLORS:
+ // use window color - enable/disable color selection controls
+ EnableWindow(GetDlgItem(hdlg, IDC_POP_BGCOLOUR), !((BYTE)IsDlgButtonChecked(hdlg, IDC_POP_USEWINCOLORS)));
+ EnableWindow(GetDlgItem(hdlg, IDC_POP_TEXTCOLOUR), !((BYTE)IsDlgButtonChecked(hdlg, IDC_POP_USEWINCOLORS)));
+ SendMessage(GetParent(hdlg), PSM_CHANGED, 0, 0);
+ break;
+
+ case IDC_POP_USECUSTCOLORS:
+ EnableWindow(GetDlgItem(hdlg, IDC_POP_BGCOLOUR), ((BYTE)IsDlgButtonChecked(hdlg, IDC_POP_USECUSTCOLORS)));
+ EnableWindow(GetDlgItem(hdlg, IDC_POP_TEXTCOLOUR), ((BYTE)IsDlgButtonChecked(hdlg, IDC_POP_USECUSTCOLORS)));
+ break;
+
+ case IDC_PD1:
+ SetDlgItemText(hdlg, IDC_DELAY, L"0");
+ break;
+ case IDC_PD2:
+ // Popup delay = permanent
+ SetDlgItemText(hdlg, IDC_DELAY, L"-1");
+ break;
+
+ case IDC_DELAY:
+ if (HIWORD(wParam) == EN_CHANGE)
+ test++;
+ if (test > 1) {
+ //CheckRadioButton(hdlg, IDC_PD1, IDC_PD3, IDC_PD3);
+ SendMessage(GetParent(hdlg), PSM_CHANGED, 0, 0);
+ }
+ break;
+
+ case IDC_PREVIEW:
+ wchar_t str3[512];
+ POPUPDATAW ppd = { 0 };
+
+ GetDlgItemText(hdlg, IDC_DELAY, str3, _countof(str3));
+
+ if (IsDlgButtonChecked(hdlg, IDC_POP_USECUSTCOLORS)) {
+ BGColour = (SendDlgItemMessage(hdlg, IDC_POP_BGCOLOUR, CPM_GETCOLOUR, 0, 0));
+ TextColour = (SendDlgItemMessage(hdlg, IDC_POP_TEXTCOLOUR, CPM_GETCOLOUR, 0, 0));
+ }
+ if (IsDlgButtonChecked(hdlg, IDC_POP_USEWINCOLORS)) {
+ BGColour = GetSysColor(COLOR_BTNFACE);
+ TextColour = GetSysColor(COLOR_WINDOWTEXT);
+ }
+ if (IsDlgButtonChecked(hdlg, IDC_POP_USESAMECOLORS)) {
+ BGColour = BackgoundClr;
+ TextColour = TextClr;
+ }
+ ppd.lchContact = NULL;
+ mir_wstrcpy(ppd.lpwzContactName, _A2W(MODULENAME));
+ ppd.lchIcon = LoadIcon(g_plugin.getInst(), MAKEINTRESOURCE(IDI_SITE));
+ mir_wstrcpy(ppd.lpwzText, TranslateT("This is a preview popup."));
+ ppd.colorBack = BGColour;
+ ppd.colorText = TextColour;
+ ppd.PluginWindowProc = nullptr;
+ ppd.iSeconds = _wtol(str3);
+ // display popups
+ PUAddPopupW(&ppd);
+ }
+ break;
+
+ case WM_NOTIFY: // Here we have pressed either the OK or the APPLY button.
+ switch (((LPNMHDR)lParam)->code) {
+ case PSN_APPLY:
+ int popupdelayval = 0;
+ wchar_t str2[512];
+ GetDlgItemText(hdlg, IDC_DELAY, str2, _countof(str2));
+
+ popupdelayval = _wtol(str2);
+ g_plugin.setDword(POP_DELAY_KEY, popupdelayval);
+
+ g_plugin.setByte(LCLK_WINDOW_KEY, (BYTE)IsDlgButtonChecked(hdlg, IDC_LCLK_WINDOW));
+ g_plugin.setByte(LCLK_WEB_PGE_KEY, (BYTE)IsDlgButtonChecked(hdlg, IDC_LCLK_WEB_PGE));
+ g_plugin.setByte(LCLK_DISMISS_KEY, (BYTE)IsDlgButtonChecked(hdlg, IDC_LCLK_DISMISS));
+
+ g_plugin.setByte(RCLK_WINDOW_KEY, (BYTE)IsDlgButtonChecked(hdlg, IDC_RCLK_WINDOW));
+ g_plugin.setByte(RCLK_WEB_PGE_KEY, (BYTE)IsDlgButtonChecked(hdlg, IDC_RCLK_WEB_PGE));
+ g_plugin.setByte(RCLK_DISMISS_KEY, (BYTE)IsDlgButtonChecked(hdlg, IDC_RCLK_DISMISS));
+
+ g_plugin.setByte(POP_USECUSTCLRS_KEY, (BYTE)IsDlgButtonChecked(hdlg, IDC_POP_USECUSTCOLORS));
+ g_plugin.setByte(POP_USEWINCLRS_KEY, (BYTE)IsDlgButtonChecked(hdlg, IDC_POP_USEWINCOLORS));
+ g_plugin.setByte(POP_USESAMECLRS_KEY, (BYTE)IsDlgButtonChecked(hdlg, IDC_POP_USESAMECOLORS));
+
+ BGColour = (SendDlgItemMessage(hdlg, IDC_POP_BGCOLOUR, CPM_GETCOLOUR, 0, 0));
+ TextColour = (SendDlgItemMessage(hdlg, IDC_POP_TEXTCOLOUR, CPM_GETCOLOUR, 0, 0));
+
+ g_plugin.setDword(POP_BG_CLR_KEY, BGColour);
+ g_plugin.setDword(POP_TXT_CLR_KEY, TextColour);
+
+ test = 0;
+ return TRUE;
+ }
+ break;
+ }
+ return FALSE;
+}
+
+/*****************************************************************************/
+INT_PTR CALLBACK DlgProcAlertOpt(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam)
+{
+ HWND ParentHwnd;
+ DBVARIANT dbv;
+ int i;
+ int alertIndex = 0;
+ int eventIndex = 0;
+ static int test;
+ MCONTACT hContact;
+
+ ParentHwnd = GetParent(hwndDlg);
+
+ switch (msg) {
+ case WM_INITDIALOG:
+ test = 0;
+ TranslateDialogDefault(hwndDlg);
+ hContact = lParam;
+ SetWindowLongPtr(hwndDlg, GWLP_USERDATA, lParam);
+
+ SetWindowText(hwndDlg, TranslateT("Alert options"));
+
+ SendMessage(hwndDlg, WM_SETICON, ICON_SMALL, (LPARAM)LoadIcon(g_plugin.getInst(), MAKEINTRESOURCE(IDI_ALERT)));
+
+ EnableWindow(GetDlgItem(hwndDlg, IDC_ALERT_APPLY), 0);
+
+ if (!g_plugin.getWString(hContact, ALERT_STRING_KEY, &dbv)) {
+ SetDlgItemText(hwndDlg, IDC_ALERT_STRING, dbv.pwszVal);
+ db_free(&dbv);
+ }
+ if (!g_plugin.getWString(hContact, ALRT_S_STRING_KEY, &dbv)) {
+ SetDlgItemText(hwndDlg, IDC_START2, dbv.pwszVal);
+ db_free(&dbv);
+ }
+ if (!g_plugin.getWString(hContact, ALRT_E_STRING_KEY, &dbv)) {
+ SetDlgItemText(hwndDlg, IDC_END2, dbv.pwszVal);
+ db_free(&dbv);
+ }
+ CheckDlgButton(hwndDlg, IDC_ENABLE_ALERTS, g_plugin.getByte(hContact, ENABLE_ALERTS_KEY, 0) ? BST_CHECKED : BST_UNCHECKED);
+ CheckDlgButton(hwndDlg, IDC_ADD_DATE_NAME, g_plugin.getByte(hContact, APND_DATE_NAME_KEY, 0) ? BST_CHECKED : BST_UNCHECKED);
+ CheckDlgButton(hwndDlg, IDC_24_HOUR, g_plugin.getByte(hContact, USE_24_HOUR_KEY, 0) ? BST_CHECKED : BST_UNCHECKED);
+ CheckDlgButton(hwndDlg, IDC_ALWAYS_LOG, g_plugin.getByte(hContact, ALWAYS_LOG_KEY, 0) ? BST_CHECKED : BST_UNCHECKED);
+
+ SetDlgItemText(hwndDlg, IDC_ALERT_TYPE, TranslateW(AlertTypes[g_plugin.getByte(hContact, ALRT_INDEX_KEY, 0)]));
+ SetDlgItemText(hwndDlg, IDC_EVENT_TYPE, TranslateW(EventTypes[g_plugin.getByte(hContact, EVNT_INDEX_KEY, 0)]));
+
+ for (i = 0; i < _countof(AlertTypes); i++)
+ SendDlgItemMessage(hwndDlg, IDC_ALERT_TYPE, CB_ADDSTRING, 0, (LPARAM)TranslateW(AlertTypes[i]));
+
+ for (i = 0; i < _countof(EventTypes); i++)
+ SendDlgItemMessage(hwndDlg, IDC_EVENT_TYPE, CB_ADDSTRING, 0, (LPARAM)TranslateW(EventTypes[i]));
+
+ if (g_plugin.getByte(hContact, ENABLE_ALERTS_KEY, 0)) {
+ CheckDlgButton(hwndDlg, IDC_ENABLE_ALERTS, BST_UNCHECKED);
+ CheckDlgButton(hwndDlg, IDC_ADD_DATE_NAME, BST_UNCHECKED);
+ CheckDlgButton(hwndDlg, IDC_24_HOUR, BST_UNCHECKED);
+ CheckDlgButton(hwndDlg, IDC_PREFIX, BST_UNCHECKED);
+ }
+ EnableWindow(GetDlgItem(hwndDlg, IDC_EVENT_TYPE), (IsDlgButtonChecked(hwndDlg, IDC_ENABLE_ALERTS)));
+ EnableWindow(GetDlgItem(hwndDlg, IDC_ADD_DATE_NAME), (IsDlgButtonChecked(hwndDlg, IDC_ENABLE_ALERTS)));
+
+ if (IsDlgButtonChecked(hwndDlg, IDC_ADD_DATE_NAME)) {
+ EnableWindow(GetDlgItem(hwndDlg, IDC_PREFIX), (IsDlgButtonChecked(hwndDlg, IDC_ENABLE_ALERTS)));
+ EnableWindow(GetDlgItem(hwndDlg, IDC_SUFFIX), (IsDlgButtonChecked(hwndDlg, IDC_ENABLE_ALERTS)));
+ EnableWindow(GetDlgItem(hwndDlg, IDC_24_HOUR), (IsDlgButtonChecked(hwndDlg, IDC_ENABLE_ALERTS)));
+ }
+ else {
+ EnableWindow(GetDlgItem(hwndDlg, IDC_PREFIX), 0);
+ EnableWindow(GetDlgItem(hwndDlg, IDC_SUFFIX), 0);
+ EnableWindow(GetDlgItem(hwndDlg, IDC_24_HOUR), 0);
+ }
+
+ EnableWindow(GetDlgItem(hwndDlg, IDC_ALERT_TYPE), (IsDlgButtonChecked(hwndDlg, IDC_ENABLE_ALERTS)));
+ EnableWindow(GetDlgItem(hwndDlg, IDC_ALERT_STRING), (IsDlgButtonChecked(hwndDlg, IDC_ENABLE_ALERTS)));
+ EnableWindow(GetDlgItem(hwndDlg, IDC_FILENAME), (IsDlgButtonChecked(hwndDlg, IDC_ENABLE_ALERTS)));
+ EnableWindow(GetDlgItem(hwndDlg, IDC_BROWSE), (IsDlgButtonChecked(hwndDlg, IDC_ENABLE_ALERTS)));
+ EnableWindow(GetDlgItem(hwndDlg, IDC_APPEND), (IsDlgButtonChecked(hwndDlg, IDC_ENABLE_ALERTS)));
+ EnableWindow(GetDlgItem(hwndDlg, IDC_START2), (IsDlgButtonChecked(hwndDlg, IDC_ENABLE_ALERTS)));
+ EnableWindow(GetDlgItem(hwndDlg, IDC_END2), (IsDlgButtonChecked(hwndDlg, IDC_ENABLE_ALERTS)));
+ EnableWindow(GetDlgItem(hwndDlg, IDC_ALWAYS_LOG), (IsDlgButtonChecked(hwndDlg, IDC_ENABLE_ALERTS)));
+ EnableWindow(GetDlgItem(hwndDlg, IDC_SAVE_AS_RAW), (IsDlgButtonChecked(hwndDlg, IDC_ENABLE_ALERTS)));
+
+ if (!g_plugin.getString(hContact, EVNT_INDEX_KEY, &dbv)) {
+ eventIndex = g_plugin.getByte(hContact, EVNT_INDEX_KEY, 0);
+ db_free(&dbv);
+ }
+ if (!g_plugin.getString(hContact, ALRT_INDEX_KEY, &dbv)) {
+ alertIndex = g_plugin.getByte(hContact, ALRT_INDEX_KEY, 0);
+ db_free(&dbv);
+ }
+
+ // alerts
+ if (alertIndex == 0) // Popup
+ {
+ if (IsDlgButtonChecked(hwndDlg, IDC_ENABLE_ALERTS)) {
+ EnableWindow(GetDlgItem(hwndDlg, IDC_APPEND), 0);
+ EnableWindow(GetDlgItem(hwndDlg, IDC_FILENAME), 0);
+ EnableWindow(GetDlgItem(hwndDlg, IDC_BROWSE), 0);
+ EnableWindow(GetDlgItem(hwndDlg, IDC_SAVE_AS_RAW), 0);
+ }
+ }
+ else if (alertIndex == 1) // file
+ {
+ if (IsDlgButtonChecked(hwndDlg, IDC_ENABLE_ALERTS)) {
+ EnableWindow(GetDlgItem(hwndDlg, IDC_APPEND), 1);
+ EnableWindow(GetDlgItem(hwndDlg, IDC_FILENAME), 1);
+ EnableWindow(GetDlgItem(hwndDlg, IDC_BROWSE), 1);
+ EnableWindow(GetDlgItem(hwndDlg, IDC_SAVE_AS_RAW), 1);
+ }
+ }
+ else if (alertIndex == 2) // datawindow
+ {
+ if (IsDlgButtonChecked(hwndDlg, IDC_ENABLE_ALERTS)) {
+ EnableWindow(GetDlgItem(hwndDlg, IDC_APPEND), 0);
+ EnableWindow(GetDlgItem(hwndDlg, IDC_FILENAME), 0);
+ EnableWindow(GetDlgItem(hwndDlg, IDC_BROWSE), 0);
+ EnableWindow(GetDlgItem(hwndDlg, IDC_SAVE_AS_RAW), 0);
+ }
+ }
+ else if (alertIndex == 3) // osd
+ {
+ if (IsDlgButtonChecked(hwndDlg, IDC_ENABLE_ALERTS)) {
+ EnableWindow(GetDlgItem(hwndDlg, IDC_APPEND), 0);
+ EnableWindow(GetDlgItem(hwndDlg, IDC_FILENAME), 0);
+ EnableWindow(GetDlgItem(hwndDlg, IDC_BROWSE), 0);
+ EnableWindow(GetDlgItem(hwndDlg, IDC_SAVE_AS_RAW), 0);
+ }
+ }
+
+ // events
+ if (eventIndex == 0) // string is present
+ {
+ if (IsDlgButtonChecked(hwndDlg, IDC_ENABLE_ALERTS)) {
+ EnableWindow(GetDlgItem(hwndDlg, IDC_START2), 0);
+ EnableWindow(GetDlgItem(hwndDlg, IDC_END2), 0);
+ EnableWindow(GetDlgItem(hwndDlg, IDC_ALERT_STRING), 1);
+ }
+ }
+ else if (eventIndex == 1) // webpage changed
+ {
+ if (IsDlgButtonChecked(hwndDlg, IDC_ENABLE_ALERTS)) {
+ EnableWindow(GetDlgItem(hwndDlg, IDC_START2), 0);
+ EnableWindow(GetDlgItem(hwndDlg, IDC_END2), 0);
+ EnableWindow(GetDlgItem(hwndDlg, IDC_ALERT_STRING), 0);
+ }
+ }
+ else if (eventIndex == 2) // part of page changed
+ {
+ if (IsDlgButtonChecked(hwndDlg, IDC_ENABLE_ALERTS)) {
+ EnableWindow(GetDlgItem(hwndDlg, IDC_START2), 1);
+ EnableWindow(GetDlgItem(hwndDlg, IDC_END2), 1);
+ EnableWindow(GetDlgItem(hwndDlg, IDC_ALERT_STRING), 0);
+ }
+ }
+
+ if (!g_plugin.getWString(hContact, FILE_KEY, &dbv)) {
+ SetDlgItemText(hwndDlg, IDC_FILENAME, dbv.pwszVal);
+ db_free(&dbv);
+ }
+
+ CheckDlgButton(hwndDlg, IDC_APPEND, g_plugin.getByte(hContact, APPEND_KEY, 0) ? BST_CHECKED : BST_UNCHECKED);
+ CheckDlgButton(hwndDlg, IDC_SAVE_AS_RAW, g_plugin.getByte(hContact, SAVE_AS_RAW_KEY, 0) ? BST_CHECKED : BST_UNCHECKED);
+
+ if (g_plugin.getByte(hContact, CONTACT_PREFIX_KEY, 1) == 1)
+ CheckRadioButton(hwndDlg, IDC_PREFIX, IDC_SUFFIX, IDC_PREFIX);
+ else
+ CheckRadioButton(hwndDlg, IDC_PREFIX, IDC_SUFFIX, IDC_SUFFIX);
+
+ if (g_plugin.getByte(hContact, ALWAYS_LOG_KEY, 0)) {
+ if (IsDlgButtonChecked(hwndDlg, IDC_ENABLE_ALERTS)) {
+ EnableWindow(GetDlgItem(hwndDlg, IDC_APPEND), 1);
+ EnableWindow(GetDlgItem(hwndDlg, IDC_FILENAME), 1);
+ EnableWindow(GetDlgItem(hwndDlg, IDC_BROWSE), 1);
+ EnableWindow(GetDlgItem(hwndDlg, IDC_SAVE_AS_RAW), 1);
+ }
+ }
+ return TRUE;
+
+ case WM_COMMAND:
+ switch (LOWORD(wParam)) {
+ case IDC_BROWSE:
+ {
+ wchar_t szFileName[MAX_PATH];
+ GetDlgItemText(hwndDlg, IDC_FILENAME, szFileName, _countof(szFileName));
+
+ OPENFILENAME ofn = { 0 };
+ ofn.lStructSize = sizeof(ofn);
+ ofn.hwndOwner = hwndDlg;
+ ofn.hInstance = nullptr;
+ ofn.lpstrFilter = L"TEXT Files (*.txt)\0*.txt\0All Files (*.*)\0*.*\0\0";
+ ofn.lpstrFile = szFileName;
+ ofn.Flags = OFN_HIDEREADONLY | OFN_OVERWRITEPROMPT;
+ ofn.nMaxFile = _countof(szFileName);
+ ofn.nMaxFileTitle = MAX_PATH;
+ ofn.lpstrDefExt = L"txt";
+ if (!GetSaveFileName(&ofn))
+ break;
+
+ SetDlgItemText(hwndDlg, IDC_FILENAME, szFileName);
+ EnableWindow(GetDlgItem(hwndDlg, IDC_ALERT_APPLY), 1);
+ }
+ break;
+
+ case IDC_ADD_DATE_NAME:
+ EnableWindow(GetDlgItem(hwndDlg, IDC_PREFIX), (IsDlgButtonChecked(hwndDlg, IDC_ADD_DATE_NAME)));
+ EnableWindow(GetDlgItem(hwndDlg, IDC_SUFFIX), (IsDlgButtonChecked(hwndDlg, IDC_ADD_DATE_NAME)));
+ EnableWindow(GetDlgItem(hwndDlg, IDC_24_HOUR), (IsDlgButtonChecked(hwndDlg, IDC_ADD_DATE_NAME)));
+ EnableWindow(GetDlgItem(hwndDlg, IDC_ALERT_APPLY), 1);
+ break;
+
+ case IDC_24_HOUR:
+ case IDC_SUFFIX:
+ case IDC_PREFIX:
+ EnableWindow(GetDlgItem(hwndDlg, IDC_ALERT_APPLY), 1);
+ break;
+
+ case IDC_ALERT_STRING:
+ if (HIWORD(wParam) == EN_CHANGE)
+ test++;
+ if (test > 1)
+ EnableWindow(GetDlgItem(hwndDlg, IDC_ALERT_APPLY), 1);
+ break;
+
+ case IDC_START2:
+ case IDC_END2:
+ if (HIWORD(wParam) == EN_CHANGE)
+ test++;
+ if (test > 3)
+ EnableWindow(GetDlgItem(hwndDlg, IDC_ALERT_APPLY), 1);
+ break;
+
+ case IDC_APPEND:
+ EnableWindow(GetDlgItem(hwndDlg, IDC_ALERT_APPLY), 1);
+ break;
+
+ case IDC_SAVE_AS_RAW:
+ EnableWindow(GetDlgItem(hwndDlg, IDC_ALERT_APPLY), 1);
+ break;
+
+ case IDC_ENABLE_ALERTS:
+ hContact = (MCONTACT)GetWindowLongPtr(hwndDlg, GWLP_USERDATA);
+ EnableWindow(GetDlgItem(hwndDlg, IDC_ADD_DATE_NAME), (IsDlgButtonChecked(hwndDlg, IDC_ENABLE_ALERTS)));
+
+ if (IsDlgButtonChecked(hwndDlg, IDC_ADD_DATE_NAME)) {
+ EnableWindow(GetDlgItem(hwndDlg, IDC_PREFIX), (IsDlgButtonChecked(hwndDlg, IDC_ENABLE_ALERTS)));
+ EnableWindow(GetDlgItem(hwndDlg, IDC_SUFFIX), (IsDlgButtonChecked(hwndDlg, IDC_ENABLE_ALERTS)));
+ EnableWindow(GetDlgItem(hwndDlg, IDC_24_HOUR), (IsDlgButtonChecked(hwndDlg, IDC_ENABLE_ALERTS)));
+ }
+ else {
+ EnableWindow(GetDlgItem(hwndDlg, IDC_PREFIX), 0);
+ EnableWindow(GetDlgItem(hwndDlg, IDC_SUFFIX), 0);
+ EnableWindow(GetDlgItem(hwndDlg, IDC_24_HOUR), 0);
+ }
+
+ EnableWindow(GetDlgItem(hwndDlg, IDC_EVENT_TYPE), (IsDlgButtonChecked(hwndDlg, IDC_ENABLE_ALERTS)));
+ EnableWindow(GetDlgItem(hwndDlg, IDC_ALERT_TYPE), (IsDlgButtonChecked(hwndDlg, IDC_ENABLE_ALERTS)));
+ EnableWindow(GetDlgItem(hwndDlg, IDC_ALWAYS_LOG), (IsDlgButtonChecked(hwndDlg, IDC_ENABLE_ALERTS)));
+
+ eventIndex = g_plugin.getByte(hContact, EVNT_INDEX_KEY, 0);
+ alertIndex = g_plugin.getByte(hContact, ALRT_INDEX_KEY, 0);
+
+ if (eventIndex == 2) { // part of webpage changed
+ EnableWindow(GetDlgItem(hwndDlg, IDC_START2), (IsDlgButtonChecked(hwndDlg, IDC_ENABLE_ALERTS)));
+ EnableWindow(GetDlgItem(hwndDlg, IDC_END2), (IsDlgButtonChecked(hwndDlg, IDC_ENABLE_ALERTS)));
+ }
+ else {
+ EnableWindow(GetDlgItem(hwndDlg, IDC_START2), 0);
+ EnableWindow(GetDlgItem(hwndDlg, IDC_END2), 0);
+ }
+
+ // ////////
+ if (alertIndex == 0) { // popup
+ if (IsDlgButtonChecked(hwndDlg, IDC_ENABLE_ALERTS)) {
+ EnableWindow(GetDlgItem(hwndDlg, IDC_APPEND), 0);
+ EnableWindow(GetDlgItem(hwndDlg, IDC_FILENAME), 0);
+ EnableWindow(GetDlgItem(hwndDlg, IDC_BROWSE), 0);
+ EnableWindow(GetDlgItem(hwndDlg, IDC_SAVE_AS_RAW), 0);
+
+ if (eventIndex == 2) // part of webpage changed
+ EnableWindow(GetDlgItem(hwndDlg, IDC_ALERT_STRING), 0);
+ if (eventIndex == 1) // webpage changed
+ EnableWindow(GetDlgItem(hwndDlg, IDC_ALERT_STRING), 0);
+ if (eventIndex == 0) // string present
+ EnableWindow(GetDlgItem(hwndDlg, IDC_ALERT_STRING), (IsDlgButtonChecked(hwndDlg, IDC_ENABLE_ALERTS)));
+ }
+ }
+ else if (alertIndex == 1) { // log to file
+ if (IsDlgButtonChecked(hwndDlg, IDC_ENABLE_ALERTS)) {
+ EnableWindow(GetDlgItem(hwndDlg, IDC_APPEND), 1);
+ EnableWindow(GetDlgItem(hwndDlg, IDC_FILENAME), 1);
+ EnableWindow(GetDlgItem(hwndDlg, IDC_BROWSE), 1);
+ EnableWindow(GetDlgItem(hwndDlg, IDC_SAVE_AS_RAW), 1);
+
+ if (eventIndex == 1) // webpage changed
+ EnableWindow(GetDlgItem(hwndDlg, IDC_ALERT_STRING), 0);
+ if (eventIndex == 0) // string present
+ EnableWindow(GetDlgItem(hwndDlg, IDC_ALERT_STRING), (IsDlgButtonChecked(hwndDlg, IDC_ENABLE_ALERTS)));
+ }
+ else {
+ EnableWindow(GetDlgItem(hwndDlg, IDC_APPEND), 0);
+ EnableWindow(GetDlgItem(hwndDlg, IDC_FILENAME), 0);
+ EnableWindow(GetDlgItem(hwndDlg, IDC_BROWSE), 0);
+ EnableWindow(GetDlgItem(hwndDlg, IDC_SAVE_AS_RAW), 0);
+ }
+ }
+ else if (alertIndex == 2) { // display window
+ if (IsDlgButtonChecked(hwndDlg, IDC_ENABLE_ALERTS)) {
+ EnableWindow(GetDlgItem(hwndDlg, IDC_APPEND), 0);
+ EnableWindow(GetDlgItem(hwndDlg, IDC_FILENAME), 0);
+ EnableWindow(GetDlgItem(hwndDlg, IDC_BROWSE), 0);
+ EnableWindow(GetDlgItem(hwndDlg, IDC_SAVE_AS_RAW), 0);
+
+ if (eventIndex == 1) // webpage changed
+ EnableWindow(GetDlgItem(hwndDlg, IDC_ALERT_STRING), 0);
+ if (eventIndex == 0) // string present
+ EnableWindow(GetDlgItem(hwndDlg, IDC_ALERT_STRING), (IsDlgButtonChecked(hwndDlg, IDC_ENABLE_ALERTS)));
+ }
+ }
+ else if (alertIndex == 3) { // osd
+ if (IsDlgButtonChecked(hwndDlg, IDC_ENABLE_ALERTS)) {
+ EnableWindow(GetDlgItem(hwndDlg, IDC_APPEND), 0);
+ EnableWindow(GetDlgItem(hwndDlg, IDC_FILENAME), 0);
+ EnableWindow(GetDlgItem(hwndDlg, IDC_BROWSE), 0);
+ EnableWindow(GetDlgItem(hwndDlg, IDC_SAVE_AS_RAW), 0);
+
+ if (eventIndex == 1) // webpage changed
+ EnableWindow(GetDlgItem(hwndDlg, IDC_ALERT_STRING), 0);
+ if (eventIndex == 0) // string present
+ EnableWindow(GetDlgItem(hwndDlg, IDC_ALERT_STRING), (IsDlgButtonChecked(hwndDlg, IDC_ENABLE_ALERTS)));
+ }
+ }
+
+ if (eventIndex == 0) // string present
+ EnableWindow(GetDlgItem(hwndDlg, IDC_ALERT_STRING), (IsDlgButtonChecked(hwndDlg, IDC_ENABLE_ALERTS)));
+
+ EnableWindow(GetDlgItem(hwndDlg, IDC_ALERT_APPLY), 1);
+
+ if (IsDlgButtonChecked(hwndDlg, IDC_ALWAYS_LOG)) {
+ if (IsDlgButtonChecked(hwndDlg, IDC_ENABLE_ALERTS)) {
+ EnableWindow(GetDlgItem(hwndDlg, IDC_APPEND), 1);
+ EnableWindow(GetDlgItem(hwndDlg, IDC_FILENAME), 1);
+ EnableWindow(GetDlgItem(hwndDlg, IDC_BROWSE), 1);
+ EnableWindow(GetDlgItem(hwndDlg, IDC_SAVE_AS_RAW), 1);
+ }
+ else {
+ EnableWindow(GetDlgItem(hwndDlg, IDC_APPEND), 0);
+ EnableWindow(GetDlgItem(hwndDlg, IDC_FILENAME), 0);
+ EnableWindow(GetDlgItem(hwndDlg, IDC_BROWSE), 0);
+ EnableWindow(GetDlgItem(hwndDlg, IDC_SAVE_AS_RAW), 0);
+ }
+ }
+ break;
+
+ case IDC_ALWAYS_LOG:
+ EnableWindow(GetDlgItem(hwndDlg, IDC_APPEND), (IsDlgButtonChecked(hwndDlg, IDC_ALWAYS_LOG)));
+ EnableWindow(GetDlgItem(hwndDlg, IDC_FILENAME), (IsDlgButtonChecked(hwndDlg, IDC_ALWAYS_LOG)));
+ EnableWindow(GetDlgItem(hwndDlg, IDC_BROWSE), (IsDlgButtonChecked(hwndDlg, IDC_ALWAYS_LOG)));
+ EnableWindow(GetDlgItem(hwndDlg, IDC_SAVE_AS_RAW), (IsDlgButtonChecked(hwndDlg, IDC_ALWAYS_LOG)));
+ break;
+
+ case IDC_ALERT_TYPE:
+ if (HIWORD(wParam) == CBN_SELCHANGE || HIWORD(wParam) == CBN_EDITCHANGE) {
+ hContact = (MCONTACT)GetWindowLongPtr(hwndDlg, GWLP_USERDATA);
+ alertIndex = SendDlgItemMessage(hwndDlg, IDC_ALERT_TYPE, CB_GETCURSEL, 0, 0);
+
+ if (HIWORD(wParam) == CBN_SELCHANGE) {
+ g_plugin.setByte(hContact, ALRT_INDEX_KEY, alertIndex);
+ if (alertIndex == 0) {
+ // PopUp
+ EnableWindow(GetDlgItem(hwndDlg, IDC_APPEND), 0);
+ EnableWindow(GetDlgItem(hwndDlg, IDC_FILENAME), 0);
+ EnableWindow(GetDlgItem(hwndDlg, IDC_BROWSE), 0);
+ EnableWindow(GetDlgItem(hwndDlg, IDC_SAVE_AS_RAW), 0);
+ }
+ else if (alertIndex == 1) {
+ // log to file
+ EnableWindow(GetDlgItem(hwndDlg, IDC_APPEND), 1);
+ EnableWindow(GetDlgItem(hwndDlg, IDC_FILENAME), 1);
+ EnableWindow(GetDlgItem(hwndDlg, IDC_BROWSE), 1);
+ EnableWindow(GetDlgItem(hwndDlg, IDC_SAVE_AS_RAW), 1);
+ }
+ else if (alertIndex == 2) {
+ // data window
+ EnableWindow(GetDlgItem(hwndDlg, IDC_APPEND), 0);
+ EnableWindow(GetDlgItem(hwndDlg, IDC_FILENAME), 0);
+ EnableWindow(GetDlgItem(hwndDlg, IDC_BROWSE), 0);
+ EnableWindow(GetDlgItem(hwndDlg, IDC_SAVE_AS_RAW), 0);
+ }
+ else if (alertIndex == 3) {
+ // OSD
+ EnableWindow(GetDlgItem(hwndDlg, IDC_APPEND), 0);
+ EnableWindow(GetDlgItem(hwndDlg, IDC_FILENAME), 0);
+ EnableWindow(GetDlgItem(hwndDlg, IDC_BROWSE), 0);
+ EnableWindow(GetDlgItem(hwndDlg, IDC_SAVE_AS_RAW), 0);
+ }
+
+ if (IsDlgButtonChecked(hwndDlg, IDC_ALWAYS_LOG)) {
+ EnableWindow(GetDlgItem(hwndDlg, IDC_APPEND), (IsDlgButtonChecked(hwndDlg, IDC_ALWAYS_LOG)));
+ EnableWindow(GetDlgItem(hwndDlg, IDC_FILENAME), (IsDlgButtonChecked(hwndDlg, IDC_ALWAYS_LOG)));
+ EnableWindow(GetDlgItem(hwndDlg, IDC_BROWSE), (IsDlgButtonChecked(hwndDlg, IDC_ALWAYS_LOG)));
+ EnableWindow(GetDlgItem(hwndDlg, IDC_SAVE_AS_RAW), (IsDlgButtonChecked(hwndDlg, IDC_ALWAYS_LOG)));
+ }
+ }
+ EnableWindow(GetDlgItem(hwndDlg, IDC_ALERT_APPLY), 1);
+ }
+ break;
+
+ case IDC_EVENT_TYPE:
+ if (HIWORD(wParam) == CBN_SELCHANGE || HIWORD(wParam) == CBN_EDITCHANGE) {
+ hContact = (MCONTACT)GetWindowLongPtr(hwndDlg, GWLP_USERDATA);
+ eventIndex = SendDlgItemMessage(hwndDlg, IDC_EVENT_TYPE, CB_GETCURSEL, 0, 0);
+
+ if (HIWORD(wParam) == CBN_SELCHANGE) {
+ g_plugin.setByte(hContact, EVNT_INDEX_KEY, eventIndex);
+ if (eventIndex == 0) {
+ // event when string is present
+ EnableWindow(GetDlgItem(hwndDlg, IDC_ALERT_STRING), 1);
+ EnableWindow(GetDlgItem(hwndDlg, IDC_START2), 0);
+ EnableWindow(GetDlgItem(hwndDlg, IDC_END2), 0);
+ }
+ else if (eventIndex == 1) {
+ // event when web page changes
+ EnableWindow(GetDlgItem(hwndDlg, IDC_ALERT_STRING), 0);
+ EnableWindow(GetDlgItem(hwndDlg, IDC_START2), 0);
+ EnableWindow(GetDlgItem(hwndDlg, IDC_END2), 0);
+ }
+ else if (eventIndex == 2) {
+ // event when part of web page changes
+ EnableWindow(GetDlgItem(hwndDlg, IDC_ALERT_STRING), 0);
+ EnableWindow(GetDlgItem(hwndDlg, IDC_START2), 1);
+ EnableWindow(GetDlgItem(hwndDlg, IDC_END2), 1);
+ }
+ }
+ EnableWindow(GetDlgItem(hwndDlg, IDC_ALERT_APPLY), 1);
+ }
+ break;
+
+ case IDC_ALERT_APPLY:
+ case IDC_OK2:
+ {
+ hContact = (MCONTACT)GetWindowLongPtr(hwndDlg, GWLP_USERDATA);
+
+ eventIndex = g_plugin.getByte(hContact, EVNT_INDEX_KEY, 0);
+ alertIndex = g_plugin.getByte(hContact, ALRT_INDEX_KEY, 0);
+
+ g_plugin.setByte(hContact, ENABLE_ALERTS_KEY, (BYTE)IsDlgButtonChecked(hwndDlg, IDC_ENABLE_ALERTS));
+ g_plugin.setByte(hContact, APND_DATE_NAME_KEY, (BYTE)IsDlgButtonChecked(hwndDlg, IDC_ADD_DATE_NAME));
+ g_plugin.setByte(hContact, USE_24_HOUR_KEY, (BYTE)IsDlgButtonChecked(hwndDlg, IDC_24_HOUR));
+ g_plugin.setByte(hContact, ALWAYS_LOG_KEY, (BYTE)IsDlgButtonChecked(hwndDlg, IDC_ALWAYS_LOG));
+
+ //if alerts is unticked delete the cache
+ if (!(IsDlgButtonChecked(hwndDlg, IDC_ENABLE_ALERTS)))
+ SiteDeleted(hContact, 0);
+
+ if (eventIndex == 0) // string present
+ if (!(GetWindowTextLength(GetDlgItem(hwndDlg, IDC_ALERT_STRING))))
+ if (IsDlgButtonChecked(hwndDlg, IDC_ENABLE_ALERTS)) {
+ MessageBox(nullptr, TranslateT("You need to supply a search string."), _A2W(MODULENAME), MB_OK);
+ break;
+ }
+
+ if (eventIndex == 2) // part of web page changed
+ if (IsDlgButtonChecked(hwndDlg, IDC_ENABLE_ALERTS)) {
+ if (!(GetWindowTextLength(GetDlgItem(hwndDlg, IDC_START2)))) {
+ MessageBox(nullptr, TranslateT("You need to supply a start string."), _A2W(MODULENAME), MB_OK);
+ break;
+ }
+ if (!(GetWindowTextLength(GetDlgItem(hwndDlg, IDC_END2)))) {
+ MessageBox(nullptr, TranslateT("You need to supply an end string."), _A2W(MODULENAME), MB_OK);
+ break;
+ }
+ }
+
+ if (alertIndex == 1) // log to file
+ if (!(GetWindowTextLength(GetDlgItem(hwndDlg, IDC_FILENAME))))
+ if (IsDlgButtonChecked(hwndDlg, IDC_ENABLE_ALERTS)) {
+ MessageBox(nullptr, TranslateT("You need to supply a file name and path."), _A2W(MODULENAME), MB_OK);
+ break;
+ }
+
+ if (IsDlgButtonChecked(hwndDlg, IDC_ALWAYS_LOG))
+ if (!(GetWindowTextLength(GetDlgItem(hwndDlg, IDC_FILENAME))))
+ if (IsDlgButtonChecked(hwndDlg, IDC_ENABLE_ALERTS)) {
+ MessageBox(nullptr, TranslateT("You need to supply a file name and path."), _A2W(MODULENAME), MB_OK);
+ break;
+ }
+
+ wchar_t buf[MAX_PATH];
+ GetDlgItemText(hwndDlg, IDC_FILENAME, buf, _countof(buf));
+ g_plugin.setWString(hContact, FILE_KEY, buf);
+
+ g_plugin.setByte(hContact, APPEND_KEY, (BYTE)IsDlgButtonChecked(hwndDlg, IDC_APPEND));
+ g_plugin.setByte(hContact, SAVE_AS_RAW_KEY, (BYTE)IsDlgButtonChecked(hwndDlg, IDC_SAVE_AS_RAW));
+
+ GetDlgItemText(hwndDlg, IDC_ALERT_STRING, buf, _countof(buf));
+ g_plugin.setWString(hContact, ALERT_STRING_KEY, buf);
+
+ GetDlgItemText(hwndDlg, IDC_START2, buf, _countof(buf));
+ g_plugin.setWString(hContact, ALRT_S_STRING_KEY, buf);
+
+ GetDlgItemText(hwndDlg, IDC_END2, buf, _countof(buf));
+ g_plugin.setWString(hContact, ALRT_E_STRING_KEY, buf);
+
+ g_plugin.setByte(hContact, CONTACT_PREFIX_KEY, (BYTE)IsDlgButtonChecked(hwndDlg, IDC_PREFIX));
+
+ EnableWindow(GetDlgItem(hwndDlg, IDC_ALERT_APPLY), 0);
+
+ if (LOWORD(wParam) == IDC_OK2)
+ EndDialog(hwndDlg, 1);
+ }
+ break;
+
+ case IDC_ALERT_CANCEL:
+ case IDC_CANCEL:
+ EndDialog(hwndDlg, 0);
+ }
+ }
+ return FALSE;
+}
+
+/*****************************************************************************/
+
+INT_PTR CALLBACK DlgProcContactOpt(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam)
+{
+ DBVARIANT dbv;
+ wchar_t url[300];
+ HWND ParentHwnd = GetParent(hwndDlg);
+ static int test;
+ static int test2;
+ MCONTACT hContact;
+
+ switch (msg) {
+ case WM_INITDIALOG:
+ TranslateDialogDefault(hwndDlg);
+
+ hContact = (MCONTACT)lParam;
+
+ test = 0;
+ test2 = 0;
+
+ SetWindowLongPtr(hwndDlg, GWLP_USERDATA, (LONG_PTR)hContact);
+
+ SetWindowText(hwndDlg, TranslateT("Contact options"));
+
+ SendMessage(hwndDlg, WM_SETICON, ICON_SMALL, (LPARAM)LoadIcon(g_plugin.getInst(), MAKEINTRESOURCE(IDI_OPTIONS)));
+
+ EnableWindow(GetDlgItem(hwndDlg, IDC_OPT_APPLY), 0);
+
+ if (!g_plugin.getWString(hContact, URL_KEY, &dbv)) {
+ SetDlgItemText(hwndDlg, IDC_URL, dbv.pwszVal);
+ db_free(&dbv);
+ }
+ if (!g_plugin.getWString(hContact, START_STRING_KEY, &dbv)) {
+ SetDlgItemText(hwndDlg, IDC_START, dbv.pwszVal);
+ db_free(&dbv);
+ }
+ if (!g_plugin.getWString(hContact, END_STRING_KEY, &dbv)) {
+ SetDlgItemText(hwndDlg, IDC_END, dbv.pwszVal);
+ db_free(&dbv);
+ }
+ if (g_plugin.getWString(hContact, PRESERVE_NAME_KEY, &dbv)) {
+ db_free(&dbv);
+ db_get_ws(hContact, "CList", "MyHandle", &dbv);
+ g_plugin.setWString(hContact, PRESERVE_NAME_KEY, dbv.pwszVal);
+ db_free(&dbv);
+ }
+ if (!g_plugin.getWString(hContact, PRESERVE_NAME_KEY, &dbv)) {
+ SetDlgItemText(hwndDlg, IDC_SITE_NAME, dbv.pwszVal);
+ db_free(&dbv);
+ }
+
+ CheckDlgButton(hwndDlg, IDC_CLEAN, g_plugin.getByte(hContact, CLEAR_DISPLAY_KEY, 0) ? BST_CHECKED : BST_UNCHECKED);
+
+ SendDlgItemMessage(hwndDlg, IDC_RWSPACE, TBM_SETRANGE, FALSE, MAKELONG(0, 4));
+ SendDlgItemMessage(hwndDlg, IDC_RWSPACE, TBM_SETPOS, TRUE, g_plugin.getByte(hContact, RWSPACE_KEY, 0));
+ SetDlgItemText(hwndDlg, IDC_RWSPC_TEXT, TranslateW(szTrackerBarDescr[SendDlgItemMessage(hwndDlg, IDC_RWSPACE, TBM_GETPOS, 0, 0)]));
+
+ EnableWindow(GetDlgItem(hwndDlg, IDC_RWSPACE), (IsDlgButtonChecked(hwndDlg, IDC_CLEAN)));
+ EnableWindow(GetDlgItem(hwndDlg, IDC_RWSPC_TEXT), (IsDlgButtonChecked(hwndDlg, IDC_CLEAN)));
+
+ if (g_plugin.getByte(hContact, DBLE_WIN_KEY, 1) == 1)
+ CheckRadioButton(hwndDlg, IDC_DBLE_WEB, IDC_DBLE_WIN, IDC_DBLE_WIN);
+ else
+ CheckRadioButton(hwndDlg, IDC_DBLE_WEB, IDC_DBLE_WIN, IDC_DBLE_WEB);
+
+ if (g_plugin.getByte(hContact, U_ALLSITE_KEY, 0) == 1) {
+ CheckRadioButton(hwndDlg, IDC_U_SE_STRINGS, IDC_U_ALLSITE, IDC_U_ALLSITE);
+ EnableWindow(GetDlgItem(hwndDlg, IDC_START), 0);
+ EnableWindow(GetDlgItem(hwndDlg, IDC_END), 0);
+ EnableWindow(GetDlgItem(hwndDlg, IDC_CPY_STRINGS), 0);
+ }
+ else {
+ CheckRadioButton(hwndDlg, IDC_U_SE_STRINGS, IDC_U_ALLSITE, IDC_U_SE_STRINGS);
+ EnableWindow(GetDlgItem(hwndDlg, IDC_START), 1);
+ EnableWindow(GetDlgItem(hwndDlg, IDC_END), 1);
+ EnableWindow(GetDlgItem(hwndDlg, IDC_CPY_STRINGS), 1);
+ //EnableWindow(GetDlgItem(hwndDlg, IDC_CPY_STR_TXT), 1);
+ }
+ break;
+
+ case WM_HSCROLL:
+ SetDlgItemText(hwndDlg, IDC_RWSPC_TEXT, TranslateW(szTrackerBarDescr[SendDlgItemMessage(hwndDlg, IDC_RWSPACE, TBM_GETPOS, 0, 0)]));
+ SendMessage(GetParent(hwndDlg), PSM_CHANGED, 0, 0);
+ EnableWindow(GetDlgItem(hwndDlg, IDC_OPT_APPLY), 1);
+ break;
+
+ case WM_COMMAND:
+ switch (LOWORD(wParam)) {
+ case WM_CLOSE:
+ case IDCANCEL:
+ if (hwndDlg) {
+ DestroyWindow(hwndDlg);
+ hwndDlg = nullptr;
+ }
+ return TRUE;
+
+ case IDC_SITE_NAME:
+ case IDC_URL:
+ if (HIWORD(wParam) == EN_CHANGE)
+ test++;
+ if (test > 2)
+ EnableWindow(GetDlgItem(hwndDlg, IDC_OPT_APPLY), 1);
+ break;
+
+ case IDC_DBLE_WEB:
+ case IDC_DBLE_WIN:
+ EnableWindow(GetDlgItem(hwndDlg, IDC_OPT_APPLY), 1);
+ break;
+
+ case IDC_START:
+ case IDC_END:
+ if (HIWORD(wParam) == EN_CHANGE)
+ test2++;
+ if (test2 > 2)
+ EnableWindow(GetDlgItem(hwndDlg, IDC_OPT_APPLY), 1);
+ break;
+
+ case IDC_CPY_STRINGS:
+ {
+ wchar_t string[128];
+ hContact = (MCONTACT)GetWindowLongPtr(hwndDlg, GWLP_USERDATA);
+
+ GetDlgItemText(hwndDlg, IDC_START, string, _countof(string));
+ g_plugin.setWString(hContact, ALRT_S_STRING_KEY, string);
+
+ GetDlgItemText(hwndDlg, IDC_END, string, _countof(string));
+ g_plugin.setWString(hContact, ALRT_E_STRING_KEY, string);
+
+ g_plugin.setWord(hContact, EVNT_INDEX_KEY, 2);
+ }
+ break;
+
+ case IDC_CLEAN:
+ EnableWindow(GetDlgItem(hwndDlg, IDC_RWSPACE), (IsDlgButtonChecked(hwndDlg, IDC_CLEAN)));
+ EnableWindow(GetDlgItem(hwndDlg, IDC_RWSPC_TEXT), (IsDlgButtonChecked(hwndDlg, IDC_CLEAN)));
+ EnableWindow(GetDlgItem(hwndDlg, IDC_OPT_APPLY), 1);
+ break;
+
+ case IDC_U_SE_STRINGS:
+ EnableWindow(GetDlgItem(hwndDlg, IDC_START), (IsDlgButtonChecked(hwndDlg, IDC_U_SE_STRINGS)));
+ EnableWindow(GetDlgItem(hwndDlg, IDC_END), (IsDlgButtonChecked(hwndDlg, IDC_U_SE_STRINGS)));
+ EnableWindow(GetDlgItem(hwndDlg, IDC_CPY_STRINGS), (IsDlgButtonChecked(hwndDlg, IDC_U_SE_STRINGS)));
+ EnableWindow(GetDlgItem(hwndDlg, IDC_OPT_APPLY), 1);
+ break;
+
+ case IDC_U_ALLSITE:
+ EnableWindow(GetDlgItem(hwndDlg, IDC_START), (IsDlgButtonChecked(hwndDlg, IDC_U_SE_STRINGS)));
+ EnableWindow(GetDlgItem(hwndDlg, IDC_END), (IsDlgButtonChecked(hwndDlg, IDC_U_SE_STRINGS)));
+ EnableWindow(GetDlgItem(hwndDlg, IDC_CPY_STRINGS), (IsDlgButtonChecked(hwndDlg, IDC_U_SE_STRINGS)));
+ EnableWindow(GetDlgItem(hwndDlg, IDC_OPT_APPLY), 1);
+ break;
+
+ case IDC_OPT_APPLY:
+ case IDOK:
+ {
+ wchar_t str[128], contactname[128];
+ if (!GetWindowTextLength(GetDlgItem(hwndDlg, IDC_URL))) {
+ MessageBox(nullptr, TranslateT("You need to supply a URL."), _A2W(MODULENAME), MB_OK);
+ break;
+ }
+ if (!GetWindowTextLength(GetDlgItem(hwndDlg, IDC_START))) {
+ if (IsDlgButtonChecked(hwndDlg, IDC_U_SE_STRINGS)) {
+ MessageBox(nullptr, TranslateT("You need to supply a start string."), _A2W(MODULENAME), MB_OK);
+ break;
+ }
+ }
+ if (!GetWindowTextLength(GetDlgItem(hwndDlg, IDC_END))) {
+ if (IsDlgButtonChecked(hwndDlg, IDC_U_SE_STRINGS)) {
+ MessageBox(nullptr, TranslateT("You need to supply an end string."), _A2W(MODULENAME), MB_OK);
+ break;
+ }
+ }
+ if (!GetWindowTextLength(GetDlgItem(hwndDlg, IDC_SITE_NAME))) {
+ MessageBox(nullptr, TranslateT("You need to supply a name for the contact."), _A2W(MODULENAME), MB_OK);
+ break;
+ }
+
+ GetDlgItemText(hwndDlg, IDC_SITE_NAME, contactname, _countof(contactname));
+ if (wcschr(contactname, '\\') != nullptr) {
+ MessageBox(nullptr, TranslateT("Invalid symbol present in contact name."), _A2W(MODULENAME), MB_OK);
+ break;
+ }
+ if (wcschr(contactname, '/') != nullptr) {
+ MessageBox(nullptr, TranslateT("Invalid symbol present in contact name."), _A2W(MODULENAME), MB_OK);
+ break;
+ }
+ if (wcschr(contactname, ':') != nullptr) {
+ MessageBox(nullptr, TranslateT("Invalid symbol present in contact name."), _A2W(MODULENAME), MB_OK);
+ break;
+ }
+ if (wcschr(contactname, '*') != nullptr) {
+ MessageBox(nullptr, TranslateT("Invalid symbol present in contact name."), _A2W(MODULENAME), MB_OK);
+ break;
+ }
+ if (wcschr(contactname, '?') != nullptr) {
+ MessageBox(nullptr, TranslateT("Invalid symbol present in contact name."), _A2W(MODULENAME), MB_OK);
+ break;
+ }
+ if (wcschr(contactname, '\"') != nullptr) {
+ MessageBox(nullptr, TranslateT("Invalid symbol present in contact name."), _A2W(MODULENAME), MB_OK);
+ break;
+ }
+ if (wcschr(contactname, '<') != nullptr) {
+ MessageBox(nullptr, TranslateT("Invalid symbol present in contact name."), _A2W(MODULENAME), MB_OK);
+ break;
+ }
+ if (wcschr(contactname, '>') != nullptr) {
+ MessageBox(nullptr, TranslateT("Invalid symbol present in contact name."), _A2W(MODULENAME), MB_OK);
+ break;
+ }
+ if (wcschr(contactname, '|') != nullptr) {
+ MessageBox(nullptr, TranslateT("Invalid symbol present in contact name."), _A2W(MODULENAME), MB_OK);
+ break;
+ }
+
+ hContact = (MCONTACT)GetWindowLongPtr(hwndDlg, GWLP_USERDATA);
+
+ GetDlgItemText(hwndDlg, IDC_URL, url, _countof(url));
+ g_plugin.setWString(hContact, URL_KEY, url);
+ g_plugin.setWString(hContact, "Homepage", url);
+
+ GetDlgItemText(hwndDlg, IDC_START, str, _countof(str));
+ g_plugin.setWString(hContact, START_STRING_KEY, str);
+
+ GetDlgItemText(hwndDlg, IDC_END, str, _countof(str));
+ g_plugin.setWString(hContact, END_STRING_KEY, str);
+
+ GetDlgItemText(hwndDlg, IDC_SITE_NAME, str, _countof(str));
+ db_set_ws(hContact, "CList", "MyHandle", str);
+
+ g_plugin.setByte(hContact, DBLE_WIN_KEY, (BYTE)IsDlgButtonChecked(hwndDlg, IDC_DBLE_WIN));
+ g_plugin.setByte(hContact, U_ALLSITE_KEY, (BYTE)IsDlgButtonChecked(hwndDlg, IDC_U_ALLSITE));
+
+ g_plugin.setByte(hContact, CLEAR_DISPLAY_KEY, (BYTE)IsDlgButtonChecked(hwndDlg, IDC_CLEAN));
+ g_plugin.setByte(hContact, RWSPACE_KEY, (BYTE)(SendDlgItemMessage(hwndDlg, IDC_RWSPACE, TBM_GETPOS, 0, 0)));
+
+ SetDlgItemText(ParentHwnd, IDC_OPEN_URL, FixButtonText(url, _countof(url)));
+
+ SetWindowText(ParentHwnd, str);
+ EnableWindow(GetDlgItem(hwndDlg, IDC_OPT_APPLY), 0);
+
+ if (LOWORD(wParam) == IDOK)
+ EndDialog(hwndDlg, 1);
+ }
+ break;
+
+ case IDC_OPT_CANCEL:
+ EndDialog(hwndDlg, 0);
+ }
+ break;
+ }
+ return FALSE;
+}
+
+/*****************************************************************************/
+INT_PTR CALLBACK DlgProcOpt(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
+{
+ DWORD timerval, delaytime, oldcolor;
+ DBVARIANT dbv;
+ static int test = 0;
+ static int test2 = 0;
+
+ switch (uMsg) {
+ case WM_INITDIALOG:
+ TranslateDialogDefault(hwndDlg);
+ {
+ test = 0;
+
+ SendDlgItemMessage(hwndDlg, IDC_SPIN1, UDM_SETRANGE, 0, MAKELONG(999, 0));
+ SendDlgItemMessage(hwndDlg, IDC_SPIN2, UDM_SETRANGE, 0, MAKELONG(120, 0));
+
+ SetDlgItemInt(hwndDlg, IDC_TIME, g_plugin.getDword(REFRESH_KEY, TIME), FALSE);
+ SetDlgItemInt(hwndDlg, IDC_START_DELAY, g_plugin.getWord(START_DELAY_KEY, 0), FALSE);
+
+ mir_forkthread(FillFontListThread, hwndDlg);
+
+ CheckDlgButton(hwndDlg, IDC_DISABLEMENU, g_plugin.getByte(MENU_OFF, 0) ? BST_CHECKED : BST_UNCHECKED);
+ CheckDlgButton(hwndDlg, IDC_SUPPRESS, g_plugin.getByte(SUPPRESS_ERR_KEY, 0) ? BST_CHECKED : BST_UNCHECKED);
+ CheckDlgButton(hwndDlg, IDC_UPDATE_ONSTART, g_plugin.getByte(UPDATE_ONSTART_KEY, 0) ? BST_CHECKED : BST_UNCHECKED);
+ CheckDlgButton(hwndDlg, IDC_UPDATE_ON_OPEN, g_plugin.getByte(UPDATE_ON_OPEN_KEY, 0) ? BST_CHECKED : BST_UNCHECKED);
+ CheckDlgButton(hwndDlg, IDC_HIDE_STATUS_ICON, g_plugin.getByte(HIDE_STATUS_ICON_KEY, 0) ? BST_CHECKED : BST_UNCHECKED);
+ CheckDlgButton(hwndDlg, IDC_FONT_BOLD, g_plugin.getByte(FONT_BOLD_KEY, 0) ? BST_CHECKED : BST_UNCHECKED);
+ CheckDlgButton(hwndDlg, IDC_FONT_ITALIC, g_plugin.getByte(FONT_ITALIC_KEY, 0) ? BST_CHECKED : BST_UNCHECKED);
+ CheckDlgButton(hwndDlg, IDC_FONT_UNDERLINE, g_plugin.getByte(FONT_UNDERLINE_KEY, 0) ? BST_CHECKED : BST_UNCHECKED);
+ CheckDlgButton(hwndDlg, IDC_ERROR_POPUP, g_plugin.getByte(ERROR_POPUP_KEY, 0) ? BST_CHECKED : BST_UNCHECKED);
+ CheckDlgButton(hwndDlg, IDC_UPDATE_ONALERT, g_plugin.getByte(UPDATE_ONALERT_KEY, 0) ? BST_CHECKED : BST_UNCHECKED);
+ CheckDlgButton(hwndDlg, IDC_SAVE_INDIVID_POS, g_plugin.getByte(SAVE_INDIVID_POS_KEY, 0) ? BST_CHECKED : BST_UNCHECKED);
+ CheckDlgButton(hwndDlg, IDC_NO_PROTECT, g_plugin.getByte(NO_PROTECT_KEY, 0) ? BST_CHECKED : BST_UNCHECKED);
+ CheckDlgButton(hwndDlg, IDC_DATAPOPUP, g_plugin.getByte(DATA_POPUP_KEY, 0) ? BST_CHECKED : BST_UNCHECKED);
+
+ if (!g_plugin.getWString(FONT_FACE_KEY, &dbv)) {
+ SetDlgItemText(hwndDlg, IDC_TYPEFACE, dbv.pwszVal);
+ db_free(&dbv);
+ }
+ else SetDlgItemText(hwndDlg, IDC_TYPEFACE, Def_font_face);
+
+ for (int i = 0; i < _countof(fontSizes); i++)
+ SendDlgItemMessage(hwndDlg, IDC_FONTSIZE, CB_ADDSTRING, 0, (LPARAM)fontSizes[i]);
+
+ SendMessage(hwndDlg, M_FILLSCRIPTCOMBO, wParam, 0);
+
+ SetDlgItemInt(hwndDlg, IDC_FONTSIZE, g_plugin.getByte(FONT_SIZE_KEY, 14), FALSE);
+
+ EnableWindow(GetDlgItem(hwndDlg, IDC_FIND_BUTTON), 0);
+ EnableWindow(GetDlgItem(hwndDlg, IDC_ALERT_BUTTON), 0);
+
+ SendDlgItemMessage(hwndDlg, IDC_BGCOLOR, CPM_SETCOLOUR, 0, (BackgoundClr));
+ SendDlgItemMessage(hwndDlg, IDC_TXTCOLOR, CPM_SETCOLOUR, 0, (TextClr));
+
+ /*
+ * record bg value for later comparison
+ */
+ oldcolor = BackgoundClr;
+
+ if (g_plugin.getByte(SUPPRESS_ERR_KEY, 0)) {
+ CheckDlgButton(hwndDlg, IDC_SUPPRESS, BST_CHECKED);
+ EnableWindow(GetDlgItem(hwndDlg, IDC_ERROR_POPUP), 0);
+ }
+ else {
+ CheckDlgButton(hwndDlg, IDC_SUPPRESS, BST_UNCHECKED);
+ if ((ServiceExists(MS_POPUP_ADDPOPUPW) != 0))
+ EnableWindow(GetDlgItem(hwndDlg, IDC_ERROR_POPUP), 1);
+ }
+
+ if (ServiceExists(MS_POPUP_ADDPOPUPW) == 0)
+ EnableWindow(GetDlgItem(hwndDlg, IDC_ERROR_POPUP), 0);
+
+ if (g_plugin.getByte(UPDATE_ONSTART_KEY, 0)) {
+ EnableWindow(GetDlgItem(hwndDlg, IDC_START_DELAY), 1);
+ EnableWindow(GetDlgItem(hwndDlg, IDC_SPIN2), 1);
+ EnableWindow(GetDlgItem(hwndDlg, IDC_STARTDELAYTXT), 1);
+ EnableWindow(GetDlgItem(hwndDlg, IDC_STDELAYSECTXT), 1);
+ }
+ else {
+ EnableWindow(GetDlgItem(hwndDlg, IDC_START_DELAY), 0);
+ EnableWindow(GetDlgItem(hwndDlg, IDC_SPIN2), 0);
+ EnableWindow(GetDlgItem(hwndDlg, IDC_STARTDELAYTXT), 0);
+ EnableWindow(GetDlgItem(hwndDlg, IDC_STDELAYSECTXT), 0);
+ }
+ }
+ break;
+
+ case M_FILLSCRIPTCOMBO: // fill the script combo box and set the
+ // selection to the value for fontid wParam
+
+ {
+ LOGFONT lf = { 0 };
+ int i;
+ HDC hdc = GetDC(hwndDlg);
+
+ lf.lfCharSet = DEFAULT_CHARSET;
+ GetDlgItemText(hwndDlg, IDC_TYPEFACE, lf.lfFaceName, _countof(lf.lfFaceName));
+ lf.lfPitchAndFamily = 0;
+ SendDlgItemMessage(hwndDlg, IDC_SCRIPT, CB_RESETCONTENT, 0, 0);
+ EnumFontFamiliesEx(hdc, &lf, (FONTENUMPROC)EnumFontScriptsProc, (LPARAM)GetDlgItem(hwndDlg, IDC_SCRIPT), 0);
+ ReleaseDC(hwndDlg, hdc);
+ for (i = SendDlgItemMessage(hwndDlg, IDC_SCRIPT, CB_GETCOUNT, 0, 0) - 1; i >= 0; i--) {
+ if (SendDlgItemMessage(hwndDlg, IDC_SCRIPT, CB_GETITEMDATA, i, 0) == (BYTE)((g_plugin.getByte(FONT_SCRIPT_KEY, 0)))) {
+ SendDlgItemMessage(hwndDlg, IDC_SCRIPT, CB_SETCURSEL, i, 0);
+ break;
+ }
+ }
+ if (i < 0)
+ SendDlgItemMessage(hwndDlg, IDC_SCRIPT, CB_SETCURSEL, 0, 0);
+ }
+ break;
+
+ case WM_COMMAND:
+ if (HIWORD(wParam) == BN_CLICKED && GetFocus() == (HWND)lParam)
+ SendMessage(GetParent(hwndDlg), PSM_CHANGED, 0, 0);
+
+ switch (LOWORD(wParam)) {
+ case IDC_TXTCOLOR:
+ TextClr = SendDlgItemMessage(hwndDlg, IDC_TXTCOLOR, CPM_GETCOLOUR, 0, 0);
+ g_plugin.setDword(TXT_COLOR_KEY, TextClr);
+ if (HIWORD(wParam) == CPN_COLOURCHANGED) {
+ SendMessage(GetParent(hwndDlg), PSM_CHANGED, 0, 0);
+ TxtclrLoop();
+ }
+ break;
+
+ case IDC_BGCOLOR:
+ BackgoundClr = SendDlgItemMessage(hwndDlg, IDC_BGCOLOR, CPM_GETCOLOUR, 0, 0);
+ g_plugin.setDword(BG_COLOR_KEY, BackgoundClr);
+ if (HIWORD(wParam) == CPN_COLOURCHANGED) {
+ SendMessage(GetParent(hwndDlg), PSM_CHANGED, 0, 0);
+ BGclrLoop();
+ }
+ break;
+
+ case IDC_HIDE_STATUS_ICON:
+ ShowWindow(GetDlgItem(hwndDlg, IDC_RESTART), SW_SHOW);
+ break;
+
+ case IDC_SUPPRESS:
+ if ((ServiceExists(MS_POPUP_ADDPOPUPW) != 0))
+ EnableWindow(GetDlgItem(hwndDlg, IDC_ERROR_POPUP), (!(IsDlgButtonChecked(hwndDlg, IDC_SUPPRESS))));
+ break;
+
+ case IDC_UPDATE_ONSTART:
+ EnableWindow(GetDlgItem(hwndDlg, IDC_START_DELAY), ((IsDlgButtonChecked(hwndDlg, IDC_UPDATE_ONSTART))));
+ EnableWindow(GetDlgItem(hwndDlg, IDC_SPIN2), ((IsDlgButtonChecked(hwndDlg, IDC_UPDATE_ONSTART))));
+ EnableWindow(GetDlgItem(hwndDlg, IDC_STARTDELAYTXT), ((IsDlgButtonChecked(hwndDlg, IDC_UPDATE_ONSTART))));
+ EnableWindow(GetDlgItem(hwndDlg, IDC_STDELAYSECTXT), ((IsDlgButtonChecked(hwndDlg, IDC_UPDATE_ONSTART))));
+ break;
+
+ case IDC_DISABLEMENU:
+ ShowWindow(GetDlgItem(hwndDlg, IDC_RESTART), SW_SHOW);
+ break;
+
+ case IDC_TYPEFACE:
+ SendMessage(hwndDlg, M_FILLSCRIPTCOMBO, wParam, 0);
+ case IDC_FONTSIZE:
+ case IDC_SCRIPT:
+ SendMessage(GetParent(hwndDlg), PSM_CHANGED, 0, 0);
+ break;
+
+ case IDC_START_DELAY:
+ if (HIWORD(wParam) == EN_CHANGE)
+ test++;
+ if (test > 1)
+ SendMessage(GetParent(hwndDlg), PSM_CHANGED, 0, 0);
+ break;
+
+ case IDC_TIME:
+ if (HIWORD(wParam) == EN_CHANGE)
+ test2++;
+ if (test2 > 2)
+ SendMessage(GetParent(hwndDlg), PSM_CHANGED, 0, 0);
+ break;
+ } // end WM_COMMAND
+ break;
+
+ case WM_DESTROY:
+ test = 0;
+ test2 = 0;
+ break;
+
+ case WM_NOTIFY:
+ switch (((LPNMHDR)lParam)->code) {
+ case PSN_APPLY:
+ g_plugin.setByte(MENU_OFF, (BYTE)IsDlgButtonChecked(hwndDlg, IDC_DISABLEMENU));
+ g_plugin.setByte(SUPPRESS_ERR_KEY, (BYTE)IsDlgButtonChecked(hwndDlg, IDC_SUPPRESS));
+ g_plugin.setByte(UPDATE_ONSTART_KEY, (BYTE)IsDlgButtonChecked(hwndDlg, IDC_UPDATE_ONSTART));
+ g_plugin.setByte(UPDATE_ON_OPEN_KEY, (BYTE)IsDlgButtonChecked(hwndDlg, IDC_UPDATE_ON_OPEN));
+ g_plugin.setByte(HIDE_STATUS_ICON_KEY, (BYTE)IsDlgButtonChecked(hwndDlg, IDC_HIDE_STATUS_ICON));
+ g_plugin.setByte(FONT_BOLD_KEY, (BYTE)IsDlgButtonChecked(hwndDlg, IDC_FONT_BOLD));
+ g_plugin.setByte(FONT_ITALIC_KEY, (BYTE)IsDlgButtonChecked(hwndDlg, IDC_FONT_ITALIC));
+ g_plugin.setByte(FONT_UNDERLINE_KEY, (BYTE)IsDlgButtonChecked(hwndDlg, IDC_FONT_UNDERLINE));
+ g_plugin.setByte(UPDATE_ONALERT_KEY, (BYTE)IsDlgButtonChecked(hwndDlg, IDC_UPDATE_ONALERT));
+ g_plugin.setByte(SAVE_INDIVID_POS_KEY, (BYTE)IsDlgButtonChecked(hwndDlg, IDC_SAVE_INDIVID_POS));
+ g_plugin.setByte(NO_PROTECT_KEY, (BYTE)IsDlgButtonChecked(hwndDlg, IDC_NO_PROTECT));
+ g_plugin.setByte(DATA_POPUP_KEY, (BYTE)IsDlgButtonChecked(hwndDlg, IDC_DATAPOPUP));
+
+ wchar_t str[100];
+ GetDlgItemText(hwndDlg, IDC_TYPEFACE, str, _countof(str));
+ g_plugin.setWString(FONT_FACE_KEY, str);
+
+ g_plugin.setByte(FONT_SIZE_KEY, (GetDlgItemInt(hwndDlg, IDC_FONTSIZE, nullptr, FALSE)));
+ g_plugin.setByte(FONT_SCRIPT_KEY, ((BYTE)SendDlgItemMessage(hwndDlg, IDC_SCRIPT, CB_GETITEMDATA, SendDlgItemMessage(hwndDlg, IDC_SCRIPT, CB_GETCURSEL, 0, 0), 0)));
+
+ g_plugin.setByte(ERROR_POPUP_KEY, (BYTE)IsDlgButtonChecked(hwndDlg, IDC_ERROR_POPUP));
+
+ timerval = GetDlgItemInt(hwndDlg, IDC_TIME, nullptr, FALSE);
+ g_plugin.setDword(REFRESH_KEY, timerval);
+ g_plugin.setDword(COUNTDOWN_KEY, timerval);
+
+
+ delaytime = GetDlgItemInt(hwndDlg, IDC_START_DELAY, nullptr, FALSE);
+ g_plugin.setDword(START_DELAY_KEY, delaytime);
+
+ BackgoundClr = (SendDlgItemMessage(hwndDlg, IDC_BGCOLOR, CPM_GETCOLOUR, 0, 0));
+ TextClr = (SendDlgItemMessage(hwndDlg, IDC_TXTCOLOR, CPM_GETCOLOUR, 0, 0));
+
+ if ((g_plugin.getDword(REFRESH_KEY, 0) != 0)) {
+ KillTimer(nullptr, timerId);
+ KillTimer(nullptr, Countdown);
+ timerId = SetTimer(nullptr, 0, ((g_plugin.getDword(REFRESH_KEY, 0)) * MINUTE), timerfunc);
+ Countdown = SetTimer(nullptr, 0, MINUTE, Countdownfunc);
+ }
+ if ((g_plugin.getDword(REFRESH_KEY, 0) == 0)) {
+ KillTimer(nullptr, timerId);
+ KillTimer(nullptr, Countdown);
+ }
+ test = 0;
+ }
+ break; // end apply
+ }
+
+ return 0;
+}
diff --git a/protocols/WebView/src/webview_services.cpp b/protocols/WebView/src/webview_services.cpp
new file mode 100644
index 0000000000..4957120181
--- /dev/null
+++ b/protocols/WebView/src/webview_services.cpp
@@ -0,0 +1,458 @@
+/*
+* A plugin for Miranda IM which displays web page text in a window Copyright
+* (C) 2005 Vincent Joyce.
+*
+* Miranda IM: the free icq client for MS Windows Copyright (C) 2000-2
+* Richard Hughes, Roland Rabien & Tristan Van de Vreede
+*
+* 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.
+*/
+
+#include "stdafx.h"
+#include "webview.h"
+
+static int searchId = -1;
+
+/*****************************************************************************/
+static char szInvalidChars[] = { '\\', '/', ':', '*', '?', '\"', '<', '>', '|' };
+
+int DBSettingChanged(WPARAM wParam, LPARAM lParam)
+{
+ // We can't upload changes to NULL contact
+ MCONTACT hContact = wParam;
+ if (hContact == NULL)
+ return 0;
+
+ DBCONTACTWRITESETTING *cws = (DBCONTACTWRITESETTING *)lParam;
+ if (!strcmp(cws->szModule, "CList")) {
+ int invalidpresent = 0;
+
+ char *szProto = GetContactProto(hContact);
+ if (szProto == nullptr || strcmp(szProto, MODULENAME))
+ return 0;
+
+ // A contact is renamed
+ if (!strcmp(cws->szSetting, "MyHandle")) {
+ ptrW oldName(g_plugin.getWStringA(hContact, PRESERVE_NAME_KEY));
+ if (oldName == NULL)
+ return 0;
+
+ wchar_t nick[100];
+ ptrW oldnick(db_get_wsa(hContact, "CList", "MyHandle"));
+ if (oldnick != NULL)
+ wcsncpy_s(nick, oldnick, _TRUNCATE);
+ else
+ nick[0] = 0;
+
+ for (int i = 0; i < _countof(szInvalidChars); i++) {
+ wchar_t *p = wcschr(nick, szInvalidChars[i]);
+ if (p != nullptr) {
+ WErrorPopup((UINT_PTR)"ERROR", TranslateT("Invalid symbol present in contact name."));
+ *p = '_';
+ invalidpresent = 1;
+ }
+ }
+
+ if (invalidpresent) {
+ srand((unsigned)time(0));
+ wchar_t ranStr[7];
+ _itow((int)10000 * rand() / (RAND_MAX + 1.0), ranStr, 10);
+ mir_wstrcat(nick, ranStr);
+ }
+
+ if (wcschr(nick, '(') == nullptr) {
+ g_plugin.setWString(hContact, PRESERVE_NAME_KEY, nick);
+ g_plugin.setWString(hContact, "Nick", nick);
+ db_set_ws(hContact, "CList", "MyHandle", nick);
+ }
+
+ // TEST GET NAME FOR CACHE
+ wchar_t cachepath[MAX_PATH], cachedirectorypath[MAX_PATH];
+ GetModuleFileName(g_plugin.getInst(), cachepath, _countof(cachepath));
+ wchar_t *cacheend = wcsrchr(cachepath, '\\');
+ cacheend++;
+ *cacheend = '\0';
+ mir_snwprintf(cachedirectorypath, L"%s" _A2W(MODULENAME) L"cache\\", cachepath);
+ CreateDirectory(cachedirectorypath, nullptr);
+
+ wchar_t newcachepath[MAX_PATH + 50], renamedcachepath[MAX_PATH + 50];
+ mir_snwprintf(newcachepath, L"%s" _A2W(MODULENAME) L"cache\\%s.txt", cachepath, oldName);
+ mir_snwprintf(renamedcachepath, L"%s" _A2W(MODULENAME) L"cache\\%s.txt", cachepath, nick);
+
+ // file exists?
+ if (_waccess(newcachepath, 0) != -1) {
+ FILE *pcachefile = _wfopen(newcachepath, L"r");
+ if (pcachefile != nullptr) {
+ fclose(pcachefile);
+ if (mir_wstrcmp(newcachepath, renamedcachepath)) {
+ MoveFile(newcachepath, renamedcachepath);
+ g_plugin.setWString(hContact, CACHE_FILE_KEY, renamedcachepath);
+ }
+ }
+ }
+ }
+ }
+ return 0;
+}
+
+/*****************************************************************************/
+int SiteDeleted(WPARAM wParam, LPARAM)
+{
+ MCONTACT hContact = wParam;
+ if (mir_strcmp(GetContactProto(hContact), MODULENAME))
+ return 0;
+
+ ptrW contactName(g_plugin.getWStringA(hContact, PRESERVE_NAME_KEY));
+
+ // TEST GET NAME FOR CACHE
+ wchar_t cachepath[MAX_PATH], cachedirectorypath[MAX_PATH], newcachepath[MAX_PATH + 50];
+ GetModuleFileName(g_plugin.getInst(), cachepath, _countof(cachepath));
+ wchar_t *cacheend = wcsrchr(cachepath, '\\');
+ cacheend++;
+ *cacheend = '\0';
+
+ mir_snwprintf(cachedirectorypath, L"%s" _A2W(MODULENAME) L"cache\\", cachepath);
+ CreateDirectory(cachedirectorypath, nullptr);
+ mir_snwprintf(newcachepath, L"%s" _A2W(MODULENAME) L"cache\\%s.txt", cachepath, contactName);
+ // file exists?
+ if (_waccess(newcachepath, 0) != -1) {
+ FILE *pcachefile = _wfopen(newcachepath, L"r");
+ if (pcachefile != nullptr) {
+ fclose(pcachefile);
+ DeleteFile(newcachepath);
+ g_plugin.setString(hContact, CACHE_FILE_KEY, "");
+ }
+ }
+ return 0;
+}
+
+/*****************************************************************************/
+INT_PTR OpenCacheDir(WPARAM, LPARAM)
+{
+ //GET NAME FOR CACHE
+ wchar_t cachepath[MAX_PATH], cachedirectorypath[MAX_PATH];
+ GetModuleFileName(g_plugin.getInst(), cachepath, _countof(cachepath));
+ wchar_t *cacheend = wcsrchr(cachepath, '\\');
+ cacheend++;
+ *cacheend = '\0';
+
+ mir_snwprintf(cachedirectorypath, L"%s" _A2W(MODULENAME) L"cache\\%s", cachepath, cacheend);
+
+ if (_waccess(cachedirectorypath, 0) != 0)
+ WErrorPopup((UINT_PTR)"ERROR", TranslateT("Cache folder does not exist."));
+ else
+ ShellExecute(nullptr, L"open", cachedirectorypath, nullptr, nullptr, SW_SHOWNORMAL);
+ return 0;
+}
+
+/*****************************************************************************/
+INT_PTR PingWebsiteMenuCommand(WPARAM wParam, LPARAM)
+{
+ FILE *pfile = fopen("psite.bat", "r");
+ if (pfile == nullptr) {
+ WErrorPopup((UINT_PTR)"ERROR", TranslateT("Missing \"psite.bat\" file."));
+ return 0;
+ }
+
+ ptrW url(g_plugin.getWStringA(wParam, "URL"));
+ if (url == NULL)
+ return 0;
+
+ wchar_t Cnick[200], *Oldnick;
+ wcsncpy(Cnick, url, _countof(Cnick));
+ if ((Oldnick = wcsstr(Cnick, L"://")) != nullptr)
+ Oldnick += 3;
+ else
+ Oldnick = Cnick;
+
+ wchar_t *Nend = wcschr(Oldnick, '/');
+ if (Nend) *Nend = '\0';
+
+ ShellExecute(nullptr, L"open", L"psite.bat", Oldnick, nullptr, SW_HIDE);
+ return 0;
+}
+
+/*****************************************************************************/
+INT_PTR StpPrcssMenuCommand(WPARAM wParam, LPARAM)
+{
+ g_plugin.setByte(wParam, STOP_KEY, 1);
+ return 0;
+}
+
+//=======================================================
+// GetCaps
+// =======================================================
+
+INT_PTR GetCaps(WPARAM wParam, LPARAM)
+{
+ switch (wParam) {
+ case PFLAGNUM_1:
+ return PF1_BASICSEARCH | PF1_ADDSEARCHRES | PF1_VISLIST;
+ case PFLAGNUM_2:
+ return g_plugin.getByte(HIDE_STATUS_ICON_KEY, 0) ? 0 : (PF2_ONLINE | PF2_SHORTAWAY | PF2_LONGAWAY | PF2_LIGHTDND | PF2_HEAVYDND);
+ case PFLAGNUM_3:
+ return 0;
+ case PFLAGNUM_4:
+ return PF4_NOCUSTOMAUTH | PF4_NOAUTHDENYREASON;
+ case PFLAGNUM_5:
+ return PF2_INVISIBLE | PF2_SHORTAWAY | PF2_LONGAWAY | PF2_LIGHTDND | PF2_HEAVYDND | PF2_FREECHAT | PF2_OUTTOLUNCH | PF2_ONTHEPHONE;
+ case PFLAG_UNIQUEIDTEXT:
+ return (INT_PTR)Translate("Site URL");
+ default:
+ return 0;
+ }
+}
+
+// =======================================================
+// GetName
+// =======================================================
+
+INT_PTR GetName(WPARAM wParam, LPARAM lParam)
+{
+ mir_strncpy((char*)lParam, MODULENAME, wParam);
+ return 0;
+}
+
+//=======================================================
+// SetStatus
+// =======================================================
+
+INT_PTR SetStatus(WPARAM wParam, LPARAM)
+{
+ int oldStatus = bpStatus;
+
+ if (wParam == ID_STATUS_ONLINE)
+ wParam = ID_STATUS_ONLINE;
+ else if (wParam == ID_STATUS_OFFLINE)
+ wParam = ID_STATUS_OFFLINE;
+ else
+ wParam = ID_STATUS_ONLINE;
+
+ // broadcast the message
+ bpStatus = wParam;
+
+ ProtoBroadcastAck(MODULENAME, NULL, ACKTYPE_STATUS, ACKRESULT_SUCCESS, (HANDLE)oldStatus, wParam);
+
+ // Make sure no contact has offline status for any reason on first time run
+ if (g_plugin.getByte("FirstTime", 100) == 100) {
+ for (auto &hContact : Contacts(MODULENAME))
+ g_plugin.setWord(hContact, "Status", ID_STATUS_ONLINE);
+
+ g_plugin.setByte("FirstTime", 1);
+ }
+
+ g_plugin.setByte(OFFLINE_STATUS, bpStatus == ID_STATUS_OFFLINE);
+ return 0;
+}
+
+//=======================================================
+// GetStatus
+// =======================================================
+
+INT_PTR GetStatus(WPARAM, LPARAM)
+{
+ if (bpStatus == ID_STATUS_ONLINE)
+ return ID_STATUS_ONLINE;
+ if (bpStatus == ID_STATUS_AWAY)
+ return ID_STATUS_AWAY;
+ if (bpStatus == ID_STATUS_NA)
+ return ID_STATUS_NA;
+ if (bpStatus == ID_STATUS_OCCUPIED)
+ return ID_STATUS_OCCUPIED;
+ if (bpStatus == ID_STATUS_DND)
+ return ID_STATUS_DND;
+ return ID_STATUS_OFFLINE;
+}
+
+//=======================================================
+// BPLoadIcon
+// =======================================================
+
+INT_PTR BPLoadIcon(WPARAM wParam, LPARAM)
+{
+ UINT id;
+
+ switch (wParam & 0xFFFF) {
+ case PLI_PROTOCOL:
+ id = IDI_SITE;
+ break;
+ default:
+ return 0;
+ }
+ return (INT_PTR)LoadImage(g_plugin.getInst(), MAKEINTRESOURCE(id), IMAGE_ICON,
+ GetSystemMetrics(wParam & PLIF_SMALL ? SM_CXSMICON : SM_CXICON),
+ GetSystemMetrics(wParam & PLIF_SMALL ? SM_CYSMICON : SM_CYICON), 0);
+}
+
+/*****************************************************************************/
+static void __cdecl BasicSearchTimerProc(wchar_t *pszNick)
+{
+ PROTOSEARCHRESULT psr = { sizeof(psr) };
+ psr.flags = PSR_UNICODE;
+ psr.nick.w = pszNick;
+
+ // broadcast the search result
+ ProtoBroadcastAck(MODULENAME, NULL, ACKTYPE_SEARCH, ACKRESULT_DATA, (HANDLE)1, (LPARAM)&psr);
+ ProtoBroadcastAck(MODULENAME, NULL, ACKTYPE_SEARCH, ACKRESULT_SUCCESS, (HANDLE)1, 0);
+
+ // exit the search
+ searchId = -1;
+ mir_free(pszNick);
+}
+
+INT_PTR BasicSearch(WPARAM, LPARAM lParam)
+{
+ if (searchId != -1)
+ return 0; // only one search at a time
+
+ searchId = 1;
+
+ // create a thread for the ID search
+ mir_forkThread<wchar_t>(BasicSearchTimerProc, mir_wstrdup((const wchar_t*)lParam));
+ return searchId;
+}
+
+/*****************************************************************************/
+INT_PTR AddToList(WPARAM, LPARAM lParam)
+{
+ PROTOSEARCHRESULT *psr = (PROTOSEARCHRESULT *)lParam;
+ DBVARIANT dbv;
+ int sameurl = 0;
+ int samename = 0;
+
+ if (psr == nullptr)
+ return 0;
+ if (psr->nick.w == nullptr) {
+ WErrorPopup((UINT_PTR)"ERROR", TranslateT("Please select site in Find/Add contacts..."));
+ return 0;
+ }
+ // if contact with the same ID was not found, add it
+ if (psr->cbSize != sizeof(PROTOSEARCHRESULT))
+ return NULL;
+ // search for existing contact
+ for (auto &hContact : Contacts(MODULENAME)) {
+ // check ID to see if the contact already exist in the database
+ if (g_plugin.getWString(hContact, "URL", &dbv))
+ continue;
+ if (!mir_wstrcmpi(psr->nick.w, dbv.pwszVal)) {
+ // remove the flag for not on list and hidden, thus make the
+ // contact visible
+ // and add them on the list
+ sameurl++;
+ if (db_get_b(hContact, "CList", "NotOnList", 1)) {
+ db_unset(hContact, "CList", "NotOnList");
+ db_unset(hContact, "CList", "Hidden");
+ }
+ }
+ db_free(&dbv);
+ }
+
+ MCONTACT hContact = db_add_contact();
+ Proto_AddToContact(hContact, MODULENAME);
+
+ /////////write to db
+ g_plugin.setByte(hContact, ON_TOP_KEY, 0);
+ g_plugin.setByte(hContact, DBLE_WIN_KEY, 1);
+ g_plugin.setString(hContact, END_STRING_KEY, "");
+ g_plugin.setByte(hContact, RWSPACE_KEY, 1);
+
+ //Convert url into a name for contact
+ wchar_t Cnick[255];
+ if (psr->nick.w != nullptr)
+ wcsncpy(Cnick, psr->nick.w, _countof(Cnick));
+ else
+ Cnick[0] = 0;
+
+ wchar_t *Oldnick = wcsstr(Cnick, L"://");
+ if (Oldnick != nullptr)
+ Oldnick += 3;
+ else
+ Oldnick = Cnick;
+
+ wchar_t *Newnick = wcsstr(Oldnick, L"www.");
+ if (Newnick != nullptr)
+ Newnick += 4;
+ else {
+ Newnick = wcsstr(Oldnick, L"WWW.");
+ if (Newnick != nullptr)
+ Newnick += 4;
+ else
+ Newnick = Oldnick;
+ }
+
+ wchar_t *Nend = wcschr(Newnick, '.');
+ if (Nend) *Nend = '\0';
+
+ for (auto &hContact2 : Contacts(MODULENAME)) {
+ if (!db_get_ws(hContact2, MODULENAME, PRESERVE_NAME_KEY, &dbv)) {
+ if (!mir_wstrcmpi(Newnick, dbv.pwszVal)) {
+ // remove the flag for not on list and hidden, thus make the
+ // contact visible
+ // and add them on the list
+ samename++;
+ if (db_get_b(hContact2, "CList", "NotOnList", 1)) {
+ db_unset(hContact2, "CList", "NotOnList");
+ db_unset(hContact2, "CList", "Hidden");
+ }
+ db_free(&dbv);
+ }
+ }
+ db_free(&dbv);
+ }
+
+ if ((sameurl > 0) || (samename > 0)) // contact has the same url or name as another contact, add rand num to name
+ {
+ srand((unsigned)time(0));
+
+ wchar_t ranStr[10];
+ _itow((int)10000 * rand() / (RAND_MAX + 1.0), ranStr, 10);
+ mir_wstrcat(Newnick, ranStr);
+ }
+ //end convert
+
+ db_set_ws(hContact, "CList", "MyHandle", Newnick);
+ g_plugin.setWString(hContact, PRESERVE_NAME_KEY, Newnick);
+ g_plugin.setWString(hContact, "Nick", Newnick);
+ g_plugin.setByte(hContact, CLEAR_DISPLAY_KEY, 1);
+ g_plugin.setString(hContact, START_STRING_KEY, "");
+ g_plugin.setWString(hContact, URL_KEY, psr->nick.w);
+ g_plugin.setWString(hContact, "Homepage", psr->nick.w);
+ g_plugin.setByte(hContact, U_ALLSITE_KEY, 1);
+ g_plugin.setWord(hContact, "Status", ID_STATUS_ONLINE);
+
+ // ignore status change
+ db_set_dw(hContact, "Ignore", "Mask", 8);
+
+ Sleep(2);
+
+ db_free(&dbv);
+
+
+ return (INT_PTR)hContact;
+}
+
+/*****************************************************************************/
+
+static void __cdecl AckFunc(void*)
+{
+ for (auto &hContact : Contacts(MODULENAME))
+ ProtoBroadcastAck(MODULENAME, hContact, ACKTYPE_GETINFO, ACKRESULT_SUCCESS, (HANDLE)1, 0);
+}
+
+INT_PTR GetInfo(WPARAM, LPARAM)
+{
+ mir_forkthread(AckFunc);
+ return 1;
+}
diff --git a/protocols/WebView/webview.vcxproj b/protocols/WebView/webview.vcxproj
new file mode 100644
index 0000000000..58927876e7
--- /dev/null
+++ b/protocols/WebView/webview.vcxproj
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <ItemGroup Label="ProjectConfigurations">
+ <ProjectConfiguration Include="Debug|Win32">
+ <Configuration>Debug</Configuration>
+ <Platform>Win32</Platform>
+ </ProjectConfiguration>
+ <ProjectConfiguration Include="Debug|x64">
+ <Configuration>Debug</Configuration>
+ <Platform>x64</Platform>
+ </ProjectConfiguration>
+ <ProjectConfiguration Include="Release|Win32">
+ <Configuration>Release</Configuration>
+ <Platform>Win32</Platform>
+ </ProjectConfiguration>
+ <ProjectConfiguration Include="Release|x64">
+ <Configuration>Release</Configuration>
+ <Platform>x64</Platform>
+ </ProjectConfiguration>
+ </ItemGroup>
+ <PropertyGroup Label="Globals">
+ <ProjectName>WebView</ProjectName>
+ <ProjectGuid>{475ED6ED-C311-4188-ACB2-1C41830B22EE}</ProjectGuid>
+ </PropertyGroup>
+ <ImportGroup Label="PropertySheets">
+ <Import Project="$(ProjectDir)..\..\build\vc.common\plugin.props" />
+ </ImportGroup>
+</Project> \ No newline at end of file
diff --git a/protocols/WebView/webview.vcxproj.filters b/protocols/WebView/webview.vcxproj.filters
new file mode 100644
index 0000000000..fcae13a9d8
--- /dev/null
+++ b/protocols/WebView/webview.vcxproj.filters
@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <Import Project="$(ProjectDir)..\..\build\vc.common\common.filters" />
+</Project> \ No newline at end of file
diff --git a/protocols/YAMN/YAMN.vcxproj b/protocols/YAMN/YAMN.vcxproj
new file mode 100644
index 0000000000..419862de67
--- /dev/null
+++ b/protocols/YAMN/YAMN.vcxproj
@@ -0,0 +1,53 @@
+<?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>
+ <ImportGroup Label="PropertySheets">
+ <Import Project="$(ProjectDir)..\..\build\vc.common\plugin.props" />
+ </ImportGroup>
+ <ItemDefinitionGroup>
+ <ClCompile>
+ <ExceptionHandling>Sync</ExceptionHandling>
+ </ClCompile>
+ </ItemDefinitionGroup>
+ <ItemGroup>
+ <ClCompile Include="src\browser\*.cpp">
+ <PrecompiledHeaderFile>..\stdafx.h</PrecompiledHeaderFile>
+ </ClCompile>
+ <ClCompile Include="src\mails\*.cpp">
+ <PrecompiledHeaderFile>..\stdafx.h</PrecompiledHeaderFile>
+ </ClCompile>
+ <ClCompile Include="src\proto\*.cpp">
+ <PrecompiledHeaderFile>..\stdafx.h</PrecompiledHeaderFile>
+ </ClCompile>
+ <ClCompile Include="src\proto\pop3\*.cpp">
+ <PrecompiledHeaderFile>..\..\stdafx.h</PrecompiledHeaderFile>
+ </ClCompile>
+ </ItemGroup>
+ <ItemGroup>
+ <ClInclude Include="src\browser\*.h" />
+ <ClInclude Include="src\mails\*.h" />
+ <ClInclude Include="src\proto\*.h" />
+ <ClInclude Include="src\proto\pop3\*.h" />
+ </ItemGroup>
+</Project> \ No newline at end of file
diff --git a/protocols/YAMN/YAMN.vcxproj.filters b/protocols/YAMN/YAMN.vcxproj.filters
new file mode 100644
index 0000000000..fcae13a9d8
--- /dev/null
+++ b/protocols/YAMN/YAMN.vcxproj.filters
@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <Import Project="$(ProjectDir)..\..\build\vc.common\common.filters" />
+</Project> \ No newline at end of file
diff --git a/protocols/YAMN/docs/ChangeLog.txt b/protocols/YAMN/docs/ChangeLog.txt
new file mode 100644
index 0000000000..0088e3c684
--- /dev/null
+++ b/protocols/YAMN/docs/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 stdafx.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/docs/InstallScript.xml b/protocols/YAMN/docs/InstallScript.xml
new file mode 100644
index 0000000000..d389dbfa09
--- /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/license.txt b/protocols/YAMN/docs/license.txt
new file mode 100644
index 0000000000..f3790d8623
--- /dev/null
+++ b/protocols/YAMN/docs/license.txt
@@ -0,0 +1,340 @@
+ GNU GENERAL PUBLIC LICENSE
+ Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.
+ 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+ Preamble
+
+ The licenses for most software are designed to take away your
+freedom to share and change it. By contrast, the GNU General Public
+License is intended to guarantee your freedom to share and change free
+software--to make sure the software is free for all its users. This
+General Public License applies to most of the Free Software
+Foundation's software and to any other program whose authors commit to
+using it. (Some other Free Software Foundation software is covered by
+the GNU Library General Public License instead.) You can apply it to
+your programs, too.
+
+ When we speak of free software, we are referring to freedom, not
+price. Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+ To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if you
+distribute copies of the software, or if you modify it.
+
+ For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must give the recipients all the rights that
+you have. You must make sure that they, too, receive or can get the
+source code. And you must show them these terms so they know their
+rights.
+
+ We protect your rights with two steps: (1) copyright the software, and
+(2) offer you this license which gives you legal permission to copy,
+distribute and/or modify the software.
+
+ Also, for each author's protection and ours, we want to make certain
+that everyone understands that there is no warranty for this free
+software. If the software is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original, so
+that any problems introduced by others will not reflect on the original
+authors' reputations.
+
+ Finally, any free program is threatened constantly by software
+patents. We wish to avoid the danger that redistributors of a free
+program will individually obtain patent licenses, in effect making the
+program proprietary. To prevent this, we have made it clear that any
+patent must be licensed for everyone's free use or not licensed at all.
+
+ The precise terms and conditions for copying, distribution and
+modification follow.
+
+ GNU GENERAL PUBLIC LICENSE
+ TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+ 0. This License applies to any program or other work which contains
+a notice placed by the copyright holder saying it may be distributed
+under the terms of this General Public License. The "Program", below,
+refers to any such program or work, and a "work based on the Program"
+means either the Program or any derivative work under copyright law:
+that is to say, a work containing the Program or a portion of it,
+either verbatim or with modifications and/or translated into another
+language. (Hereinafter, translation is included without limitation in
+the term "modification".) Each licensee is addressed as "you".
+
+Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope. The act of
+running the Program is not restricted, and the output from the Program
+is covered only if its contents constitute a work based on the
+Program (independent of having been made by running the Program).
+Whether that is true depends on what the Program does.
+
+ 1. You may copy and distribute verbatim copies of the Program's
+source code as you receive it, in any medium, provided that you
+conspicuously and appropriately publish on each copy an appropriate
+copyright notice and disclaimer of warranty; keep intact all the
+notices that refer to this License and to the absence of any warranty;
+and give any other recipients of the Program a copy of this License
+along with the Program.
+
+You may charge a fee for the physical act of transferring a copy, and
+you may at your option offer warranty protection in exchange for a fee.
+
+ 2. You may modify your copy or copies of the Program or any portion
+of it, thus forming a work based on the Program, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+ a) You must cause the modified files to carry prominent notices
+ stating that you changed the files and the date of any change.
+
+ b) You must cause any work that you distribute or publish, that in
+ whole or in part contains or is derived from the Program or any
+ part thereof, to be licensed as a whole at no charge to all third
+ parties under the terms of this License.
+
+ c) If the modified program normally reads commands interactively
+ when run, you must cause it, when started running for such
+ interactive use in the most ordinary way, to print or display an
+ announcement including an appropriate copyright notice and a
+ notice that there is no warranty (or else, saying that you provide
+ a warranty) and that users may redistribute the program under
+ these conditions, and telling the user how to view a copy of this
+ License. (Exception: if the Program itself is interactive but
+ does not normally print such an announcement, your work based on
+ the Program is not required to print an announcement.)
+
+These requirements apply to the modified work as a whole. If
+identifiable sections of that work are not derived from the Program,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works. But when you
+distribute the same sections as part of a whole which is a work based
+on the Program, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Program.
+
+In addition, mere aggregation of another work not based on the Program
+with the Program (or with a work based on the Program) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+ 3. You may copy and distribute the Program (or a work based on it,
+under Section 2) in object code or executable form under the terms of
+Sections 1 and 2 above provided that you also do one of the following:
+
+ a) Accompany it with the complete corresponding machine-readable
+ source code, which must be distributed under the terms of Sections
+ 1 and 2 above on a medium customarily used for software interchange; or,
+
+ b) Accompany it with a written offer, valid for at least three
+ years, to give any third party, for a charge no more than your
+ cost of physically performing source distribution, a complete
+ machine-readable copy of the corresponding source code, to be
+ distributed under the terms of Sections 1 and 2 above on a medium
+ customarily used for software interchange; or,
+
+ c) Accompany it with the information you received as to the offer
+ to distribute corresponding source code. (This alternative is
+ allowed only for noncommercial distribution and only if you
+ received the program in object code or executable form with such
+ an offer, in accord with Subsection b above.)
+
+The source code for a work means the preferred form of the work for
+making modifications to it. For an executable work, complete source
+code means all the source code for all modules it contains, plus any
+associated interface definition files, plus the scripts used to
+control compilation and installation of the executable. However, as a
+special exception, the source code distributed need not include
+anything that is normally distributed (in either source or binary
+form) with the major components (compiler, kernel, and so on) of the
+operating system on which the executable runs, unless that component
+itself accompanies the executable.
+
+If distribution of executable or object code is made by offering
+access to copy from a designated place, then offering equivalent
+access to copy the source code from the same place counts as
+distribution of the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+ 4. You may not copy, modify, sublicense, or distribute the Program
+except as expressly provided under this License. Any attempt
+otherwise to copy, modify, sublicense or distribute the Program is
+void, and will automatically terminate your rights under this License.
+However, parties who have received copies, or rights, from you under
+this License will not have their licenses terminated so long as such
+parties remain in full compliance.
+
+ 5. You are not required to accept this License, since you have not
+signed it. However, nothing else grants you permission to modify or
+distribute the Program or its derivative works. These actions are
+prohibited by law if you do not accept this License. Therefore, by
+modifying or distributing the Program (or any work based on the
+Program), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Program or works based on it.
+
+ 6. Each time you redistribute the Program (or any work based on the
+Program), the recipient automatically receives a license from the
+original licensor to copy, distribute or modify the Program subject to
+these terms and conditions. You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+
+ 7. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License. If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Program at all. For example, if a patent
+license would not permit royalty-free redistribution of the Program by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Program.
+
+If any portion of this section is held invalid or unenforceable under
+any particular circumstance, the balance of the section is intended to
+apply and the section as a whole is intended to apply in other
+circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system, which is
+implemented by public license practices. Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+ 8. If the distribution and/or use of the Program is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Program under this License
+may add an explicit geographical distribution limitation excluding
+those countries, so that distribution is permitted only in or among
+countries not thus excluded. In such case, this License incorporates
+the limitation as if written in the body of this License.
+
+ 9. The Free Software Foundation may publish revised and/or new versions
+of the General Public License from time to time. Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+Each version is given a distinguishing version number. If the Program
+specifies a version number of this License which applies to it and "any
+later version", you have the option of following the terms and conditions
+either of that version or of any later version published by the Free
+Software Foundation. If the Program does not specify a version number of
+this License, you may choose any version ever published by the Free Software
+Foundation.
+
+ 10. If you wish to incorporate parts of the Program into other free
+programs whose distribution conditions are different, write to the author
+to ask for permission. For software which is copyrighted by the Free
+Software Foundation, write to the Free Software Foundation; we sometimes
+make exceptions for this. Our decision will be guided by the two goals
+of preserving the free status of all derivatives of our free software and
+of promoting the sharing and reuse of software generally.
+
+ NO WARRANTY
+
+ 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
+PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
+REPAIR OR CORRECTION.
+
+ 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGES.
+
+ END OF TERMS AND CONDITIONS
+
+ How to Apply These Terms to Your New Programs
+
+ If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+ To do so, attach the following notices to the program. It is safest
+to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+ <one line to give the program's name and a brief idea of what it does.>
+ Copyright (C) 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/readme.developers.txt b/protocols/YAMN/docs/readme.developers.txt
new file mode 100644
index 0000000000..4ab336da8a
--- /dev/null
+++ b/protocols/YAMN/docs/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/readme.txt b/protocols/YAMN/docs/readme.txt
new file mode 100644
index 0000000000..075a3a2a0a
--- /dev/null
+++ b/protocols/YAMN/docs/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/proto_yamn/proto_YAMN.vcxproj b/protocols/YAMN/proto_yamn/proto_YAMN.vcxproj
new file mode 100644
index 0000000000..b66216a4b3
--- /dev/null
+++ b/protocols/YAMN/proto_yamn/proto_YAMN.vcxproj
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <ItemGroup Label="ProjectConfigurations">
+ <ProjectConfiguration Include="Debug|Win32">
+ <Configuration>Debug</Configuration>
+ <Platform>Win32</Platform>
+ </ProjectConfiguration>
+ <ProjectConfiguration Include="Debug|x64">
+ <Configuration>Debug</Configuration>
+ <Platform>x64</Platform>
+ </ProjectConfiguration>
+ <ProjectConfiguration Include="Release|Win32">
+ <Configuration>Release</Configuration>
+ <Platform>Win32</Platform>
+ </ProjectConfiguration>
+ <ProjectConfiguration Include="Release|x64">
+ <Configuration>Release</Configuration>
+ <Platform>x64</Platform>
+ </ProjectConfiguration>
+ </ItemGroup>
+ <PropertyGroup Label="Globals">
+ <ProjectName>Proto_YAMN</ProjectName>
+ <ProjectGuid>{C1CDB82C-6BBF-496E-88F4-CC57E60B0CA9}</ProjectGuid>
+ </PropertyGroup>
+ <ImportGroup Label="PropertySheets">
+ <Import Project="$(ProjectDir)..\..\..\build\vc.common\icons.props" />
+ </ImportGroup>
+</Project> \ No newline at end of file
diff --git a/protocols/YAMN/proto_yamn/proto_YAMN.vcxproj.filters b/protocols/YAMN/proto_yamn/proto_YAMN.vcxproj.filters
new file mode 100644
index 0000000000..28f81e7f1b
--- /dev/null
+++ b/protocols/YAMN/proto_yamn/proto_YAMN.vcxproj.filters
@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <Import Project="$(ProjectDir)..\..\..\build\vc.common\common.filters" />
+</Project> \ No newline at end of file
diff --git a/protocols/YAMN/proto_yamn/res/icoaway.ico b/protocols/YAMN/proto_yamn/res/icoaway.ico
new file mode 100644
index 0000000000..9c5be2ef5c
--- /dev/null
+++ b/protocols/YAMN/proto_yamn/res/icoaway.ico
Binary files differ
diff --git a/protocols/YAMN/proto_yamn/res/icooccupied.ico b/protocols/YAMN/proto_yamn/res/icooccupied.ico
new file mode 100644
index 0000000000..e7ba6d35b7
--- /dev/null
+++ b/protocols/YAMN/proto_yamn/res/icooccupied.ico
Binary files differ
diff --git a/protocols/YAMN/proto_yamn/res/icooffline.ico b/protocols/YAMN/proto_yamn/res/icooffline.ico
new file mode 100644
index 0000000000..9f7f6082e9
--- /dev/null
+++ b/protocols/YAMN/proto_yamn/res/icooffline.ico
Binary files differ
diff --git a/protocols/YAMN/proto_yamn/res/icoonline.ico b/protocols/YAMN/proto_yamn/res/icoonline.ico
new file mode 100644
index 0000000000..5c7f3d7e79
--- /dev/null
+++ b/protocols/YAMN/proto_yamn/res/icoonline.ico
Binary files differ
diff --git a/protocols/YAMN/proto_yamn/res/proto_YAMN.rc b/protocols/YAMN/proto_yamn/res/proto_YAMN.rc
new file mode 100644
index 0000000000..e0ddf4671e
--- /dev/null
+++ b/protocols/YAMN/proto_yamn/res/proto_YAMN.rc
@@ -0,0 +1,16 @@
+#include "..\src\resource.h"
+
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Icon
+//
+
+// Icon with lowest ID value placed first to ensure application icon
+// remains consistent on all systems.
+
+IDI_ICON1 ICON "icooffline.ico"
+IDI_ICON2 ICON "icoonline.ico"
+IDI_ICON5 ICON "icooffline.ico"
+IDI_ICON7 ICON "icooccupied.ico"
+IDI_ICON3 ICON "icoaway.ico"
diff --git a/protocols/YAMN/proto_yamn/src/resource.h b/protocols/YAMN/proto_yamn/src/resource.h
new file mode 100644
index 0000000000..f8b30c37ed
--- /dev/null
+++ b/protocols/YAMN/proto_yamn/src/resource.h
@@ -0,0 +1,20 @@
+//{{NO_DEPENDENCIES}}
+// Microsoft Visual C++ generated include file.
+// Used by Proto_YAMN.rc
+//
+#define IDI_ICON1 105
+#define IDI_ICON2 104
+#define IDI_ICON3 128
+#define IDI_ICON5 131
+#define IDI_ICON7 159
+
+// Next default values for new objects
+//
+#ifdef APSTUDIO_INVOKED
+#ifndef APSTUDIO_READONLY_SYMBOLS
+#define _APS_NEXT_RESOURCE_VALUE 110
+#define _APS_NEXT_COMMAND_VALUE 40001
+#define _APS_NEXT_CONTROL_VALUE 1001
+#define _APS_NEXT_SYMED_VALUE 101
+#endif
+#endif
diff --git a/protocols/YAMN/res/Version.rc b/protocols/YAMN/res/Version.rc
new file mode 100644
index 0000000000..5a5ddd63ed
--- /dev/null
+++ b/protocols/YAMN/res/Version.rc
@@ -0,0 +1,9 @@
+// Microsoft Visual C++ generated resource script.
+//
+#ifdef APSTUDIO_INVOKED
+#error this file is not editable by Microsoft Visual C++
+#endif //APSTUDIO_INVOKED
+
+#include "..\src\version.h"
+
+#include "..\..\build\Version.rc"
diff --git a/protocols/YAMN/res/YAMN.rc b/protocols/YAMN/res/YAMN.rc
new file mode 100644
index 0000000000..d86dfe6cdd
--- /dev/null
+++ b/protocols/YAMN/res/YAMN.rc
@@ -0,0 +1,330 @@
+// Microsoft Visual C++ generated resource script.
+//
+#include "..\src\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
+ "..\\src\\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_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 | WS_CHILD
+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 "Homepage:",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 | WS_CHILD
+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
+ PUSHBUTTON "+",IDC_BTNADD,118,6,15,13
+ PUSHBUTTON "-",IDC_BTNDEL,140,6,15,13
+ GROUPBOX "Account",IDC_STATIC,4,22,151,120
+ LTEXT "Name:",IDC_STATIC,10,34,44,10
+ EDITTEXT IDC_EDITNAME,56,32,92,12,ES_AUTOHSCROLL
+ LTEXT "Server:",IDC_STSERVER,10,50,44,8
+ EDITTEXT IDC_EDITSERVER,56,48,92,12,ES_AUTOHSCROLL | WS_GROUP
+ 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 "APOP",IDC_CHECKAPOP,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,119,66,34,10
+ 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
+ PUSHBUTTON "Default",IDC_BTNDEFAULT,9,124,54,13
+ CONTROL "Disable STLS",IDC_CHECKNOTLS,"Button",BS_AUTOCHECKBOX | BS_LEFT | WS_TABSTOP,83,125,69,10
+ LTEXT "Status:",IDC_STATIC,164,2,80,8
+ LTEXT "",IDC_STSTATUS,164,13,143,8,SS_CENTERIMAGE
+ GROUPBOX "Options",IDC_STATIC,161,22,147,120
+ CONTROL "Check this account",IDC_CHECK,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,167,32,118,10,WS_EX_TRANSPARENT
+ CONTROL "Startup check",IDC_CHECKSTART,"Button",BS_AUTOCHECKBOX | BS_NOTIFY | WS_TABSTOP,167,43,78,10
+ LTEXT "Check interval [min]:",IDC_STINTERVAL,168,56,94,8
+ EDITTEXT IDC_EDITINTERVAL,259,53,20,12,ES_AUTOHSCROLL | ES_NUMBER,WS_EX_TRANSPARENT
+ PUSHBUTTON "Only check when...",IDC_BTNSTATUS,195,69,81,13
+ 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
+ CONTROL "Use contact notification for this account",IDC_CHECKCONTACT,
+ "Button",BS_AUTOCHECKBOX | WS_TABSTOP,166,107,138,10,WS_EX_TRANSPARENT
+ CONTROL "Replace nickname",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
+ GROUPBOX "Notifications",IDC_GBNEWMAIL,4,143,304,87
+ GROUPBOX "New Mail",IDC_STATIC,7,153,149,73
+ 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 "Keyboard Flash",IDC_CHECKKBN,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,12,186,132,9
+ CONTROL "Tray Icon",IDC_CHECKICO,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,85,163,65,10
+ 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
+ GROUPBOX "Errors",IDC_STATIC,161,153,143,44
+ 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
+ LTEXT "",IDC_STTIMELEFT,163,216,141,8
+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 "Not available",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 "Do not disturb",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 | WS_CHILD
+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 localized 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 color",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 "Persistent message",IDC_CHECKNMSGP,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,23,188,110,10
+ CONTROL "Use custom color",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 color",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 color",IDC_STATIC,177,184,108,10
+ LTEXT "Text color",IDC_STATIC,177,200,107,10
+ LTEXT "Background color",IDC_STATIC,177,120,108,10
+ LTEXT "Text color",IDC_STATIC,177,136,107,10
+ LTEXT "Background color",IDC_STATIC,177,69,108,10
+ LTEXT "Text color",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_CHECKMAIL ICON "checkmail.ico"
+IDI_LAUNCHAPP ICON "launchapp.ico"
+IDI_BADCONNECT ICON "badconnect.ico"
+IDI_NEWMAIL ICON "newmail.ico"
+#endif // Neutral resources
+/////////////////////////////////////////////////////////////////////////////
+
+
+
+#ifndef APSTUDIO_INVOKED
+/////////////////////////////////////////////////////////////////////////////
+//
+// Generated from the TEXTINCLUDE 3 resource.
+//
+
+
+/////////////////////////////////////////////////////////////////////////////
+#endif // not APSTUDIO_INVOKED
+
diff --git a/protocols/YAMN/res/badconnect.ico b/protocols/YAMN/res/badconnect.ico
new file mode 100644
index 0000000000..9f7f6082e9
--- /dev/null
+++ b/protocols/YAMN/res/badconnect.ico
Binary files differ
diff --git a/protocols/YAMN/res/checkmail.ico b/protocols/YAMN/res/checkmail.ico
new file mode 100644
index 0000000000..5c7f3d7e79
--- /dev/null
+++ b/protocols/YAMN/res/checkmail.ico
Binary files differ
diff --git a/protocols/YAMN/res/launchapp.ico b/protocols/YAMN/res/launchapp.ico
new file mode 100644
index 0000000000..e7ba6d35b7
--- /dev/null
+++ b/protocols/YAMN/res/launchapp.ico
Binary files differ
diff --git a/protocols/YAMN/res/newmail.ico b/protocols/YAMN/res/newmail.ico
new file mode 100644
index 0000000000..9c5be2ef5c
--- /dev/null
+++ b/protocols/YAMN/res/newmail.ico
Binary files differ
diff --git a/protocols/YAMN/src/account.cpp b/protocols/YAMN/src/account.cpp
new file mode 100644
index 0000000000..0755276f7b
--- /dev/null
+++ b/protocols/YAMN/src/account.cpp
@@ -0,0 +1,1246 @@
+/*
+ * 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 "stdafx.h"
+
+// 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.
+static mir_cs csAccountStatusCS;
+
+// File Writing CS
+// When 2 threads want to write to file...
+static mir_cs csFileWritingCS;
+
+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;
+
+ //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 != nullptr)
+ {
+ HACCOUNT NewAccount;
+ if (Plugin->Fcn->NewAccountFcnPtr != nullptr)
+ //Let plugin create its own structure, which can be derived from CAccount structure
+ NewAccount = Plugin->Fcn->NewAccountFcnPtr(Plugin, YAMN_ACCOUNTVERSION);
+ else
+ //We suggest plugin uses standard CAccount structure, so we create it
+ NewAccount = new struct CAccount;
+
+ //If not created successfully
+ if (NewAccount == nullptr)
+ return NULL;
+
+ NewAccount->Plugin = Plugin;
+ //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 != nullptr)
+ {
+ //Deinit every members and allocated fields of structure used by YAMN
+ DeInitAccount(OldAccount);
+ if (OldAccount->Plugin->Fcn->DeleteAccountFcnPtr != nullptr)
+ {
+ //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, nullptr);
+ Which->MessagesAccessSO = new SWMRG;
+ SWMRGInitialize(Which->MessagesAccessSO, nullptr);
+ Which->UsingThreads = new SCOUNTER;
+ SWMRGInitialize(Which->MessagesAccessSO, nullptr);
+
+ //zero memory, where timestamps are stored
+ memset(&Which->LastChecked, 0, sizeof(Which->LastChecked));
+ memset(&Which->LastSChecked, 0, sizeof(Which->LastSChecked));
+ memset(&Which->LastSynchronised, 0, sizeof(Which->LastSynchronised));
+ memset(&Which->LastMail, 0, sizeof(Which->LastMail));
+
+ Which->Name = nullptr;
+ Which->Mails = nullptr;
+ Which->Interval = 0;
+ Which->Flags = 0;
+ Which->StatusFlags = 0;
+ Which->Next = nullptr;
+
+ Which->Server = new struct CServer;
+ Which->AbleToWork = TRUE;
+
+ return 1;
+}
+
+void DeInitAccount(HACCOUNT Which)
+{
+ //delete YAMN allocated fields
+ if (Which->Name != nullptr)
+ delete[] Which->Name;
+ if (Which->Server != nullptr) {
+ if (Which->Server->Name != nullptr)
+ delete[] Which->Server->Name;
+ if (Which->Server->Login != nullptr)
+ delete[] Which->Server->Login;
+ if (Which->Server->Passwd != nullptr)
+ delete[] Which->Server->Passwd;
+ 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)
+{
+ wchar_t Code = STARTCODEPSW;
+
+ if (Dest == nullptr)
+ return;
+
+ for (; *Dest != (wchar_t)0; Dest++)
+ {
+ if (Encrypt)
+ *Dest = *Dest + Code;
+ else
+ *Dest = *Dest - Code;
+ Code += (wchar_t)ADDCODEPSW;
+ }
+}
+
+static DWORD PostFileToMemory(HANDLE File, char **MemFile, char **End)
+{
+ DWORD FileSize, ReadBytes;
+ if (!(FileSize = GetFileSize(File, nullptr))) {
+ CloseHandle(File);
+ return EACC_FILESIZE;
+ }
+
+ //allocate space in memory, where we copy the whole file
+ if (nullptr == (*MemFile = new char[FileSize]))
+ {
+ CloseHandle(File);
+ return EACC_ALLOC;
+ }
+
+ //copy file to memory
+ if (!ReadFile(File, (LPVOID)*MemFile, FileSize, &ReadBytes, nullptr))
+ {
+ CloseHandle(File);
+ delete[] * MemFile;
+ return EACC_SYSTEM;
+ }
+ CloseHandle(File);
+ *End = *MemFile + FileSize;
+ return 0;
+}
+
+DWORD FileToMemory(wchar_t *FileName, char **MemFile, char **End)
+{
+ HANDLE hFile = CreateFile(FileName, GENERIC_READ, FILE_SHARE_READ, nullptr, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, nullptr);
+ if (hFile == INVALID_HANDLE_VALUE)
+ return EACC_SYSTEM;
+
+ return PostFileToMemory(hFile, MemFile, End);
+}
+
+#if defined(DEBUG_FILEREAD) || defined(DEBUG_FILEREADMESSAGES)
+DWORD ReadStringFromMemory(char **Parser,wchar_t *End,char **StoreTo,wchar_t *DebugString)
+{
+ //This is the debug version of ReadStringFromMemory function. This version shows MessageBox where
+ //read string is displayed
+ wchar_t *Dest,*Finder;
+ DWORD Size;
+ wchar_t Debug[65536];
+
+ Finder=*Parser;
+ while((*Finder != (wchar_t)0) && (Finder<=End)) Finder++;
+ mir_snwprintf(Debug, L"%s: %s,length is %d, remaining %d chars", DebugString, *Parser, Finder-*Parser, End-Finder);
+ MessageBox(NULL,Debug,L"debug",MB_OK);
+ if (Finder>=End)
+ return EACC_FILECOMPATIBILITY;
+ if (Size=Finder-*Parser)
+ {
+ if (NULL==(Dest=*StoreTo=new wchar_t[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 != (wchar_t)0) && (Finder <= End)) Finder++;
+ if (Finder >= End)
+ return EACC_FILECOMPATIBILITY;
+ if (Size = Finder - *Parser)
+ {
+ if (nullptr == (Dest = *StoreTo = new char[Size + 1]))
+ return EACC_ALLOC;
+ for (; *Parser <= Finder; (*Parser)++, Dest++)
+ *Dest = **Parser;
+ }
+ else
+ {
+ *StoreTo = nullptr;
+ (*Parser)++;
+ }
+ return 0;
+}
+
+#if defined(DEBUG_FILEREAD) || defined(DEBUG_FILEREADMESSAGES)
+DWORD ReadStringFromMemoryW(WCHAR **Parser,wchar_t *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++;
+ mir_snwprintf(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 (nullptr == (Dest = *StoreTo = new WCHAR[Size + 1]))
+ return EACC_ALLOC;
+ for (; *Parser <= Finder; (*Parser)++, Dest++)
+ *Dest = **Parser;
+ }
+ else
+ {
+ *StoreTo = nullptr;
+ (*Parser)++;
+ }
+ return 0;
+}
+
+static DWORD ReadNotificationFromMemory(char **Parser, char *End, YAMN_NOTIFICATION *Which)
+{
+ DWORD Stat;
+#ifdef DEBUG_FILEREAD
+ wchar_t Debug[65536];
+#endif
+
+ Which->Flags = *(DWORD *)(*Parser);
+ (*Parser) += sizeof(DWORD);
+ if (*Parser >= End)
+ return EACC_FILECOMPATIBILITY;
+#ifdef DEBUG_FILEREAD
+ mir_snwprintf(Debug, L"NFlags: %04x, remaining %d chars", Which->Flags, End-*Parser);
+ MessageBox(NULL,Debug,L"debug",MB_OK);
+#endif
+
+ Which->PopupB = *(COLORREF *)(*Parser);
+ (*Parser) += sizeof(COLORREF);
+ if (*Parser >= End)
+ return EACC_FILECOMPATIBILITY;
+#ifdef DEBUG_FILEREAD
+ mir_snwprintf(Debug, L"PopupB: %04x, remaining %d chars", Which->PopupB, End-*Parser);
+ MessageBox(NULL,Debug,L"debug",MB_OK);
+#endif
+ Which->PopupT = *(COLORREF *)(*Parser);
+ (*Parser) += sizeof(COLORREF);
+ if (*Parser >= End)
+ return EACC_FILECOMPATIBILITY;
+#ifdef DEBUG_FILEREAD
+ mir_snwprintf(Debug, L"PopupT: %04x, remaining %d chars", Which->PopupT, End-*Parser);
+ MessageBox(NULL,Debug,L"debug",MB_OK);
+#endif
+ Which->PopupTime = *(DWORD *)(*Parser);
+ (*Parser) += sizeof(DWORD);
+ if (*Parser >= End)
+ return EACC_FILECOMPATIBILITY;
+#ifdef DEBUG_FILEREAD
+ mir_snwprintf(Debug, L"PopupTime: %04x, remaining %d chars", Which->PopupTime, End-*Parser);
+ MessageBox(NULL,Debug,L"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 = nullptr;
+ struct CMimeItem *items;
+ char *ReadString;
+
+#ifdef DEBUG_FILEREAD
+ MessageBox(NULL,L"going to read messages, if any...",L"debug",MB_OK);
+#endif
+ do
+ {
+ Finder = *Parser;
+ while ((*Finder != (wchar_t)0) && (Finder <= End)) Finder++;
+ if (Finder >= End)
+ return EACC_FILECOMPATIBILITY;
+ if (Size = Finder - *Parser)
+ {
+ if (Which->Mails == nullptr) //First message in queue
+ {
+ if (nullptr == (Which->Mails = ActualMail = CreateAccountMail(Which)))
+ return EACC_ALLOC;
+ }
+ else
+ {
+ if (nullptr == (ActualMail->Next = CreateAccountMail(Which))) {
+ return EACC_ALLOC;
+ }
+ ActualMail = ActualMail->Next;
+ }
+ items = nullptr;
+#ifdef DEBUG_FILEREADMESSAGES
+ if (Stat=ReadStringFromMemory(Parser,End,&ActualMail->ID,L"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 ((nullptr != Which->Plugin->MailFcn) && (nullptr != 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,L"Name"))
+#else
+ if (Stat = ReadStringFromMemory(Parser, End, &ReadString))
+#endif
+ return Stat;
+ if (ReadString == nullptr)
+ break;
+
+#ifdef DEBUG_DECODE
+ DebugLog(DecodeFile,"<read name>%s</read name>",ReadString);
+#endif
+
+ if (items == nullptr)
+ items = ActualMail->MailData->TranslatedHeader = new struct CMimeItem;
+ else
+ {
+ items->Next = new struct CMimeItem;
+ items = items->Next;
+ }
+ if (items == nullptr)
+ return EACC_ALLOC;
+ items->name = ReadString;
+
+#ifdef DEBUG_FILEREADMESSAGES
+ if (Stat=ReadStringFromMemory(Parser,End,&ReadString,L"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
+ wchar_t Debug[65536];
+#endif
+ //Read name of account
+
+#ifdef DEBUG_FILEREAD
+ if (Stat=ReadStringFromMemory(Parser,End,&Which->Name,L"Name"))
+#else
+ if (Stat = ReadStringFromMemory(Parser, End, &Which->Name))
+#endif
+ return Stat;
+ if (Which->Name == nullptr)
+ return EACC_FILECOMPATIBILITY;
+
+ //Read server parameters
+#ifdef DEBUG_FILEREAD
+ if (Stat=ReadStringFromMemory(Parser,End,&Which->Server->Name,L"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
+ mir_snwprintf(Debug, L"Port: %d, remaining %d chars", Which->Server->Port, End-*Parser);
+ MessageBox(NULL,Debug,L"debug",MB_OK);
+#endif
+#ifdef DEBUG_FILEREAD
+ if (Stat=ReadStringFromMemory(Parser,End,&Which->Server->Login,L"Login"))
+#else
+ if (Stat = ReadStringFromMemory(Parser, End, &Which->Server->Login))
+#endif
+ return Stat;
+#ifdef DEBUG_FILEREAD
+ if (Stat=ReadStringFromMemory(Parser,End,&Which->Server->Passwd,L"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
+ mir_snwprintf(Debug, L"Flags: %04x, remaining %d chars", Which->Flags, End-*Parser);
+ MessageBox(NULL,Debug,L"debug",MB_OK);
+#endif
+ Which->StatusFlags = *(DWORD *)(*Parser);
+ (*Parser) += sizeof(DWORD);
+#ifdef DEBUG_FILEREAD
+ mir_snwprintf(Debug, L"STFlags: %04x, remaining %d chars", Which->StatusFlags, End-*Parser);
+ MessageBox(NULL,Debug,L"debug",MB_OK);
+#endif
+ Which->PluginFlags = *(DWORD *)(*Parser);
+ (*Parser) += sizeof(DWORD);
+#ifdef DEBUG_FILEREAD
+ mir_snwprintf(Debug, L"PFlags: %04x, remaining %d chars", Which->PluginFlags, End-*Parser);
+ MessageBox(NULL,Debug,L"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
+ mir_snwprintf(Debug, L"Interval: %d, remaining %d chars", Which->Interval, End-*Parser);
+ MessageBox(NULL,Debug,L"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 != nullptr && Which->Plugin->Fcn->ReadPluginOptsFcnPtr != nullptr)
+ 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
+ mir_snwprintf(Debug, L"LastChecked: %04x, remaining %d chars", Which->LastChecked, End-*Parser);
+ MessageBox(NULL,Debug,L"debug",MB_OK);
+#endif
+ Which->LastSChecked = *(SYSTEMTIME *)(*Parser);
+ (*Parser) += sizeof(SYSTEMTIME);
+ if (*Parser >= End)
+ return EACC_FILECOMPATIBILITY;
+#ifdef DEBUG_FILEREAD
+ mir_snwprintf(Debug, L"LastSChecked: %04x, remaining %d chars", Which->LastSChecked, End-*Parser);
+ MessageBox(NULL,Debug,L"debug",MB_OK);
+#endif
+ Which->LastSynchronised = *(SYSTEMTIME *)(*Parser);
+ (*Parser) += sizeof(SYSTEMTIME);
+ if (*Parser >= End)
+ return EACC_FILECOMPATIBILITY;
+#ifdef DEBUG_FILEREAD
+ mir_snwprintf(Debug, L"LastSynchronised: %04x, remaining %d chars", Which->LastSynchronised, End-*Parser);
+ MessageBox(NULL,Debug,L"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
+ mir_snwprintf(Debug, L"LastMail: %04x, remaining %d chars", Which->LastMail, End-*Parser);
+ MessageBox(NULL,Debug,L"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 (nullptr == (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 != nullptr; ActualAccount = Temp)
+ {
+ Temp = ActualAccount->Next;
+ delete ActualAccount;
+ }
+ delete[] MemFile;
+ if (Plugin->FirstAccount == FirstAllocatedAccount)
+ Plugin->FirstAccount = nullptr;
+#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) && (nullptr == (ActualAccount = (HACCOUNT)CallService(MS_YAMN_GETNEXTFREEACCOUNT, (WPARAM)Plugin, (LPARAM)YAMN_ACCOUNTVERSION))))
+ {
+ for (ActualAccount = FirstAllocatedAccount; ActualAccount != nullptr; ActualAccount = Temp)
+ {
+ Temp = ActualAccount->Next;
+ delete ActualAccount;
+ }
+ delete[] MemFile;
+ if (Plugin->FirstAccount == FirstAllocatedAccount)
+ Plugin->FirstAccount = nullptr;
+#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((wchar_t*)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 == nullptr) || !(Length = (DWORD)mir_strlen(Source))) {
+ if (!WriteFile(File, &null, 1, &WrittenBytes, nullptr)) {
+ CloseHandle(File);
+ return EACC_SYSTEM;
+ }
+ }
+ else if (!WriteFile(File, Source, (Length + 1), &WrittenBytes, nullptr)) {
+ CloseHandle(File);
+ return EACC_SYSTEM;
+ }
+ return 0;
+}
+
+DWORD WriteStringToFileW(HANDLE File, WCHAR *Source)
+{
+ DWORD Length, WrittenBytes;
+ WCHAR null = (WCHAR)0;
+
+ if ((Source == nullptr) || !(Length = (DWORD)mir_wstrlen(Source)))
+ {
+ if (!WriteFile(File, &null, sizeof(WCHAR), &WrittenBytes, nullptr))
+ {
+ CloseHandle(File);
+ return EACC_SYSTEM;
+ }
+ }
+ else if (!WriteFile(File, Source, (Length + 1)*sizeof(WCHAR), &WrittenBytes, nullptr))
+ return EACC_SYSTEM;
+ return 0;
+}
+
+DWORD WriteMessagesToFile(HANDLE File, HACCOUNT Which)
+{
+ DWORD WrittenBytes, Stat;
+ HYAMNMAIL ActualMail = (HYAMNMAIL)Which->Mails;
+ struct CMimeItem *items;
+
+ while (ActualMail != nullptr)
+ {
+ if (Stat = WriteStringToFile(File, ActualMail->ID))
+ return Stat;
+ if (!WriteFile(File, (char *)&ActualMail->MailData->Size, sizeof(ActualMail->MailData->Size), &WrittenBytes, nullptr) ||
+ !WriteFile(File, (char *)&ActualMail->Flags, sizeof(ActualMail->Flags), &WrittenBytes, nullptr) ||
+ !WriteFile(File, (char *)&ActualMail->Number, sizeof(ActualMail->Number), &WrittenBytes, nullptr))
+ return EACC_SYSTEM;
+ if ((nullptr != Which->Plugin->MailFcn) && (nullptr != Which->Plugin->MailFcn->WriteMailOptsFcnPtr))
+ Which->Plugin->MailFcn->WriteMailOptsFcnPtr(File, ActualMail); //write plugin mail options to file
+ for (items = ActualMail->MailData->TranslatedHeader; items != nullptr; 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 != nullptr; ActualAccount = ActualAccount->Next)
+ {
+#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 == nullptr) || (*ActualAccount->Name == (wchar_t)0))
+ {
+#ifdef DEBUG_SYNCHRO
+ DebugLog(SynchroFile,"WriteAccountsToFile:ActualAccountSO-read done\n");
+#endif
+ ReadDoneFcn(ActualAccount->AccountAccessSO);
+ continue;
+ }
+
+ if (!Writed && !WriteFile(File, &Ver, sizeof(Ver), &WrittenBytes, nullptr))
+ 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, nullptr))
+ 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, nullptr) ||
+ (!WriteFile(File, (char *)&ActualAccount->StatusFlags, sizeof(DWORD), &WrittenBytes, nullptr)) ||
+ (!WriteFile(File, (char *)&ActualAccount->PluginFlags, sizeof(DWORD), &WrittenBytes, nullptr))))
+ throw (DWORD)EACC_SYSTEM;
+
+ if (!WriteFile(File, (char *)&ActualAccount->Interval, sizeof(WORD), &WrittenBytes, nullptr))
+ throw (DWORD)EACC_SYSTEM;
+
+ if ((!WriteFile(File, (char *)&ActualAccount->NewMailN.Flags, sizeof(DWORD), &WrittenBytes, nullptr)) ||
+ (!WriteFile(File, (char *)&ActualAccount->NewMailN.PopupB, sizeof(COLORREF), &WrittenBytes, nullptr)) ||
+ (!WriteFile(File, (char *)&ActualAccount->NewMailN.PopupT, sizeof(COLORREF), &WrittenBytes, nullptr)) ||
+ (!WriteFile(File, (char *)&ActualAccount->NewMailN.PopupTime, sizeof(DWORD), &WrittenBytes, nullptr)))
+ 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, nullptr)) ||
+ (!WriteFile(File, (char *)&ActualAccount->NoNewMailN.PopupB, sizeof(COLORREF), &WrittenBytes, nullptr)) ||
+ (!WriteFile(File, (char *)&ActualAccount->NoNewMailN.PopupT, sizeof(COLORREF), &WrittenBytes, nullptr)) ||
+ (!WriteFile(File, (char *)&ActualAccount->NoNewMailN.PopupTime, sizeof(DWORD), &WrittenBytes, nullptr)))
+ 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, nullptr)) ||
+ (!WriteFile(File, (char *)&ActualAccount->BadConnectN.PopupB, sizeof(COLORREF), &WrittenBytes, nullptr)) ||
+ (!WriteFile(File, (char *)&ActualAccount->BadConnectN.PopupT, sizeof(COLORREF), &WrittenBytes, nullptr)) ||
+ (!WriteFile(File, (char *)&ActualAccount->BadConnectN.PopupTime, sizeof(DWORD), &WrittenBytes, nullptr)))
+ 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 != nullptr && ActualAccount->Plugin->Fcn->WritePluginOptsFcnPtr != nullptr)
+ 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, nullptr)) ||
+ (!WriteFile(File, (char *)&ActualAccount->LastSChecked, sizeof(SYSTEMTIME), &WrittenBytes, nullptr)) ||
+ (!WriteFile(File, (char *)&ActualAccount->LastSynchronised, sizeof(SYSTEMTIME), &WrittenBytes, nullptr)) ||
+ (!WriteFile(File, (char *)&ActualAccount->LastMail, sizeof(SYSTEMTIME), &WrittenBytes, nullptr)))
+ 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;
+
+ mir_cslock lck(csFileWritingCS);
+ HANDLE hFile = CreateFile((wchar_t*)lParam, GENERIC_WRITE, FILE_SHARE_WRITE, nullptr, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, nullptr);
+ if (hFile == INVALID_HANDLE_VALUE)
+ return EACC_SYSTEM;
+
+ return PerformAccountWriting(Plugin, hFile);
+}
+
+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 != nullptr; Finder = Finder->Next)
+ if ((Finder->Name != nullptr) && (0 == mir_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 == nullptr)
+ {
+ Plugin->FirstAccount = (HACCOUNT)CallService(MS_YAMN_CREATEPLUGINACCOUNT, wParam, lParam);
+ return (INT_PTR)Plugin->FirstAccount;
+ }
+ for (Finder = Plugin->FirstAccount; Finder->Next != nullptr; 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;
+
+ //1. set stop signal
+ StopSignalFcn(Which);
+ WindowList_BroadcastAsync(YAMNVar.MessageWnds, WM_YAMN_STOPACCOUNT, (WPARAM)Which, 0);
+ if (Plugin->Fcn->StopAccountFcnPtr != nullptr)
+ 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 == nullptr)
+ {
+#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 != nullptr) && (Plugin->Fcn->WriteAccountsFcnPtr != nullptr))
+ Plugin->Fcn->WriteAccountsFcnPtr();
+ CloseHandle(mir_forkthread(DeleteAccountInBackground, (void*)Which));
+
+ //Now, plugin can consider account as deleted, but plugin really can achieve deleting this account from memory when using
+ //event UsingThreads.
+ return 1;
+}
+
+void __cdecl DeleteAccountInBackground(void *Value)
+{
+ HACCOUNT Which = (HACCOUNT)Value;
+ WaitForSingleObject(Which->UsingThreads->Event, INFINITE);
+ CallService(MS_YAMN_DELETEPLUGINACCOUNT, (WPARAM)Which, 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 != nullptr; Finder = Finder->Next)
+ {
+ //2. set stop signal
+ StopSignalFcn(Finder);
+ WindowList_BroadcastAsync(YAMNVar.MessageWnds, WM_YAMN_STOPACCOUNT, (WPARAM)Finder, 0);
+ if (Plugin->Fcn->StopAccountFcnPtr != nullptr)
+ 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 != nullptr; 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 != nullptr;)
+ {
+ HACCOUNT Next = Finder->Next;
+ DeletePluginAccountSvc((WPARAM)Finder, 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, wchar_t *Value)
+{
+ if (Which == nullptr)
+ return;
+
+ mir_cslock lck(csAccountStatusCS);
+ mir_wstrcpy(Value, Which->Status);
+}
+
+void WINAPI SetStatusFcn(HACCOUNT Which, wchar_t *Value)
+{
+ if (Which != nullptr) {
+ mir_cslock lck(csAccountStatusCS);
+ mir_wstrcpy(Which->Status, Value);
+ }
+
+ WindowList_BroadcastAsync(YAMNVar.MessageWnds, WM_YAMN_CHANGESTATUS, (WPARAM)Which, 0);
+}
diff --git a/protocols/YAMN/src/browser/badconnect.cpp b/protocols/YAMN/src/browser/badconnect.cpp
new file mode 100644
index 0000000000..aacae630d7
--- /dev/null
+++ b/protocols/YAMN/src/browser/badconnect.cpp
@@ -0,0 +1,296 @@
+/*
+ * This code implements window handling (connection error)
+ *
+ * (c) majvan 2002,2004
+ */
+
+#include "../stdafx.h"
+
+#define BADCONNECTTITLE LPGEN("%s - connection error")
+#define BADCONNECTMSG LPGEN("An error occurred. Error code: %d")//is in use?
+
+ //--------------------------------------------------------------------------------------------------
+
+LRESULT CALLBACK BadConnectPopupProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
+{
+ DWORD PluginParam;
+ switch (msg) {
+ case WM_COMMAND:
+ // if clicked and it's new mail popup window
+ if ((HIWORD(wParam) == STN_CLICKED) && (CallService(MS_POPUP_GETPLUGINDATA, (WPARAM)hWnd, (LPARAM)&PluginParam))) {
+ PROCESS_INFORMATION pi;
+ STARTUPINFOW si;
+ memset(&si, 0, sizeof(si));
+ si.cb = sizeof(si);
+ HACCOUNT ActualAccount = (HACCOUNT)CallService(MS_POPUP_GETPLUGINDATA, (WPARAM)hWnd, 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 != nullptr) {
+ WCHAR *Command;
+ if (ActualAccount->BadConnectN.AppParam != nullptr)
+ Command = new WCHAR[mir_wstrlen(ActualAccount->BadConnectN.App) + mir_wstrlen(ActualAccount->BadConnectN.AppParam) + 6];
+ else
+ Command = new WCHAR[mir_wstrlen(ActualAccount->BadConnectN.App) + 6];
+
+ if (Command != nullptr) {
+ mir_wstrcpy(Command, L"\"");
+ mir_wstrcat(Command, ActualAccount->BadConnectN.App);
+ mir_wstrcat(Command, L"\" ");
+ if (ActualAccount->BadConnectN.AppParam != nullptr)
+ mir_wstrcat(Command, ActualAccount->BadConnectN.AppParam);
+ CreateProcessW(nullptr, Command, nullptr, nullptr, FALSE, NORMAL_PRIORITY_CLASS, nullptr, nullptr, &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
+ PUDeletePopup(hWnd);
+ }
+ 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:
+ PUDeletePopup(hWnd);
+ break;
+ }
+ return DefWindowProc(hWnd, msg, wParam, lParam);
+}
+
+INT_PTR 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 = nullptr;
+ wchar_t *Message1W = nullptr;
+ POPUPDATAW 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
+ int size = (int)(mir_strlen(ActualAccount->Name) + mir_strlen(Translate(BADCONNECTTITLE)));
+ TitleStrA = new char[size];
+ mir_snprintf(TitleStrA, size, 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.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 = BadConnectPopupProc;
+ BadConnectPopup.PluginData = ActualAccount;
+ mir_wstrncpy(BadConnectPopup.lpwzContactName, _A2T(ActualAccount->Name), _countof(BadConnectPopup.lpwzContactName));
+ }
+
+ if (ActualAccount->Plugin->Fcn != nullptr && ActualAccount->Plugin->Fcn->GetErrorStringWFcnPtr != nullptr) {
+ Message1W = ActualAccount->Plugin->Fcn->GetErrorStringWFcnPtr(ErrorCode);
+ SetDlgItemText(hDlg, IDC_STATICMSG, Message1W);
+ wcsncpy_s(BadConnectPopup.lpwzText, Message1W, _TRUNCATE);
+ if (ShowPopup)
+ PUAddPopupW(&BadConnectPopup);
+ }
+ else if (ActualAccount->Plugin->Fcn != nullptr && ActualAccount->Plugin->Fcn->GetErrorStringAFcnPtr != nullptr) {
+ Message1W = ActualAccount->Plugin->Fcn->GetErrorStringWFcnPtr(ErrorCode);
+ SetDlgItemText(hDlg, IDC_STATICMSG, Message1W);
+ wcsncpy_s(BadConnectPopup.lpwzText, Message1W, _TRUNCATE);
+ if (ShowPopup)
+ PUAddPopupW(&BadConnectPopup);
+ }
+ else {
+ Message1W = TranslateT("Unknown error");
+ SetDlgItemText(hDlg, IDC_STATICMSG, Message1W);
+ wcsncpy_s(BadConnectPopup.lpwzText, Message1W, _TRUNCATE);
+ if (ShowPopup)
+ PUAddPopupW(&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 != nullptr)
+ delete[] Message1A;
+ if (ActualAccount->Plugin->Fcn != nullptr && ActualAccount->Plugin->Fcn->DeleteErrorStringFcnPtr != nullptr && Message1A != nullptr)
+ ActualAccount->Plugin->Fcn->DeleteErrorStringFcnPtr(Message1A);
+ if (ActualAccount->Plugin->Fcn != nullptr && ActualAccount->Plugin->Fcn->DeleteErrorStringFcnPtr != nullptr && Message1W != nullptr)
+ ActualAccount->Plugin->Fcn->DeleteErrorStringFcnPtr(Message1W);
+ return 0;
+ }
+ case WM_DESTROY:
+ {
+ NOTIFYICONDATA nid;
+
+ memset(&nid, 0, 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 ((wchar_t)wParam) {
+ case 27:
+ case 13:
+ DestroyWindow(hDlg);
+ break;
+ }
+ break;
+ case WM_SYSCOMMAND:
+ switch (wParam) {
+ case SC_CLOSE:
+ DestroyWindow(hDlg);
+ }
+ break;
+ case WM_COMMAND:
+ switch (LOWORD(wParam)) {
+ case IDC_BTNOK:
+ DestroyWindow(hDlg);
+ }
+ break;
+ }
+ return 0;
+}
+
+void __cdecl BadConnection(void *Param)
+{
+ MSG msg;
+ HWND hBadConnect;
+ HACCOUNT ActualAccount;
+
+ struct BadConnectionParam 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(g_plugin.getInst(), MAKEINTRESOURCE(IDD_DLGBADCONNECT), nullptr, DlgProcYAMNBadConnection, (LPARAM)&MyParam);
+ Window_SetIcon_IcoLib(hBadConnect, g_GetIconHandle(3));
+
+#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;
+ }
+#ifdef DEBUG_SYNCHRO
+ DebugLog(SynchroFile, "BadConnect:ActualAccountSO-read enter\n");
+#endif
+ if (ActualAccount->BadConnectN.Flags & YAMN_ACC_SND)
+ Skin_PlaySound(YAMN_CONNECTFAILSOUND);
+
+ if (ActualAccount->BadConnectN.Flags & YAMN_ACC_MSG)
+ ShowWindow(hBadConnect, SW_SHOWNORMAL);
+
+ if (ActualAccount->BadConnectN.Flags & YAMN_ACC_ICO) {
+ NOTIFYICONDATA nid = {};
+ nid.cbSize = sizeof(nid);
+ nid.hWnd = hBadConnect;
+ nid.hIcon = g_LoadIconEx(3);
+ nid.uFlags = NIF_ICON | NIF_MESSAGE | NIF_TIP;
+ nid.uCallbackMessage = WM_YAMN_NOTIFYICON;
+ mir_snwprintf(nid.szTip, L"%S%s", ActualAccount->Name, TranslateT(" - connection error"));
+ Shell_NotifyIcon(NIM_ADD, &nid);
+ }
+
+#ifdef DEBUG_SYNCHRO
+ DebugLog(SynchroFile, "BadConnect:ActualAccountSO-read done\n");
+#endif
+ ReadDoneFcn(ActualAccount->AccountAccessSO);
+
+ UpdateWindow(hBadConnect);
+ while (GetMessage(&msg, nullptr, 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 != nullptr) && (ActualAccount->Plugin->Fcn->WriteAccountsFcnPtr != nullptr) && 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);
+ }
+}
+
+
+INT_PTR RunBadConnectionSvc(WPARAM wParam, LPARAM lParam)
+{
+ // an event for successfull copy parameters to which point a pointer in stack for new thread
+ PYAMN_BADCONNECTIONPARAM Param = (PYAMN_BADCONNECTIONPARAM)wParam;
+ if ((DWORD)lParam != YAMN_BADCONNECTIONVERSION)
+ return 0;
+
+ HANDLE ThreadRunningEV = CreateEvent(nullptr, FALSE, FALSE, nullptr);
+ Param->ThreadRunningEV = ThreadRunningEV;
+
+ HANDLE NewThread = mir_forkthread(BadConnection, Param);
+ if (nullptr == NewThread)
+ return 0;
+
+ WaitForSingleObject(ThreadRunningEV, INFINITE);
+ CloseHandle(ThreadRunningEV);
+ return 1;
+}
diff --git a/protocols/YAMN/src/browser/browser.h b/protocols/YAMN/src/browser/browser.h
new file mode 100644
index 0000000000..abab95f761
--- /dev/null
+++ b/protocols/YAMN/src/browser/browser.h
@@ -0,0 +1,39 @@
+#ifndef __MAILBROWSER_H
+#define __MAILBROWSER_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/src/browser/mailbrowser.cpp b/protocols/YAMN/src/browser/mailbrowser.cpp
new file mode 100644
index 0000000000..bbac178d15
--- /dev/null
+++ b/protocols/YAMN/src/browser/mailbrowser.cpp
@@ -0,0 +1,2369 @@
+/*
+ * 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 :)
+ */
+
+#include "../stdafx.h"
+
+#define TIMER_FLASHING 0x09061979
+#define MAILBROWSER_MINXSIZE 200 //min size of mail browser window
+#define MAILBROWSER_MINYSIZE 130
+
+#define MAILBROWSERTITLE LPGEN("%s - %d new mail messages, %d total")
+
+void __cdecl ShowEmailThread(void *Param);
+
+//--------------------------------------------------------------------------------------------------
+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);
+
+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);
+
+// 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, 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
+INT_PTR CALLBACK DlgProcYAMNMailBrowser(HWND hDlg, UINT msg, WPARAM wParam, LPARAM lParam);
+
+// MailBrowser thread function creates window if needed, tray icon and plays sound
+void __cdecl MailBrowser(void *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)
+ wchar_t 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 = (struct CMailWinUserInfo *)GetWindowLongPtr(hDlg, DWLP_USER);
+
+ return (mwui == nullptr) ? nullptr : 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)
+{
+ struct CMailNumbers MN;
+
+ BOOL Loaded;
+ BOOL RunMailBrowser, RunPopups;
+
+ struct CMailWinUserInfo *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, 0, 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, 0, 0);
+ return UPDATE_FAIL;
+ }
+#ifdef DEBUG_SYNCHRO
+ DebugLog(SynchroFile, "UpdateMails:ActualAccountMsgsSO-write enter\n");
+#endif
+
+ memset(&MN, 0, sizeof(MN));
+
+ for (HYAMNMAIL msgq = (HYAMNMAIL)ActualAccount->Mails; msgq != nullptr; msgq = msgq->Next) {
+ if (!LoadedMailData(msgq)) //check if mail is already in memory
+ {
+ Loaded = false;
+ if (nullptr == 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 != nullptr)
+ 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 != nullptr) && !(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 some popups with mails are needed to show
+ if ((nflags & YAMN_ACC_POP) && (ActualAccount->Flags & YAMN_ACC_POPN) && (MN.Real.PopupNC + MN.Virtual.PopupNC))
+ RunPopups = TRUE;
+ else RunPopups = FALSE;
+
+ if (RunMailBrowser)
+ ChangeExistingMailStatus(GetDlgItem(hDlg, IDC_LISTMAILS), ActualAccount);
+ if (RunMailBrowser || RunPopups)
+ AddNewMailsToListView(hDlg == nullptr ? nullptr : GetDlgItem(hDlg, IDC_LISTMAILS), ActualAccount, nflags);
+
+ if (RunMailBrowser) {
+ size_t len = mir_strlen(ActualAccount->Name) + mir_strlen(Translate(MAILBROWSERTITLE)) + 10; //+10 chars for numbers
+ char *TitleStrA = new char[len];
+ WCHAR *TitleStrW = new WCHAR[len];
+
+ mir_snprintf(TitleStrA, len, 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)mir_strlen(TitleStrA) + 1);
+ SetWindowTextW(hDlg, 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 != nullptr) {
+ 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 != nullptr)
+ DestroyWindow(hDlg);
+
+ return 1;
+}
+
+int ChangeExistingMailStatus(HWND hListView, HACCOUNT ActualAccount)
+{
+ LVITEM item;
+ HYAMNMAIL mail, msgq;
+
+ int in = ListView_GetItemCount(hListView);
+ item.mask = LVIF_PARAM;
+
+ for (int 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 != nullptr) && (msgq != mail); msgq = msgq->Next); //found the same mail in account queue
+ if (msgq == nullptr) //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, DWORD nflags)
+{
+ WCHAR *FromStr;
+ WCHAR SizeStr[20];
+ WCHAR LocalDateStr[128];
+
+ LVITEMW item;
+ LVFINDINFO fi;
+
+ int foundi = 0, lfoundi = 0;
+ struct CHeader UnicodeHeader;
+ BOOL Loaded, Extracted, FromStrNew = FALSE;
+
+ memset(&item, 0, sizeof(item));
+ memset(&UnicodeHeader, 0, sizeof(UnicodeHeader));
+
+ if (hListView != nullptr) {
+ item.mask = LVIF_TEXT | LVIF_PARAM;
+ item.iItem = 0;
+ memset(&fi, 0, sizeof(fi));
+ fi.flags = LVFI_PARAM; //let's go search item by lParam number
+ lfoundi = 0;
+ }
+
+ POPUPDATAW NewMailPopup = { 0 };
+ NewMailPopup.lchContact = (ActualAccount->hContact != NULL) ? ActualAccount->hContact : (UINT_PTR)ActualAccount;
+ NewMailPopup.lchIcon = g_LoadIconEx(2);
+ if (nflags & YAMN_ACC_POPC) {
+ NewMailPopup.colorBack = ActualAccount->NewMailN.PopupB;
+ NewMailPopup.colorText = ActualAccount->NewMailN.PopupT;
+ }
+ else {
+ NewMailPopup.colorBack = GetSysColor(COLOR_BTNFACE);
+ NewMailPopup.colorText = GetSysColor(COLOR_WINDOWTEXT);
+ }
+ NewMailPopup.iSeconds = ActualAccount->NewMailN.PopupTime;
+
+ NewMailPopup.PluginWindowProc = NewMailPopupProc;
+ NewMailPopup.PluginData = nullptr; //it's new mail popup
+
+ for (HYAMNMAIL msgq = (HYAMNMAIL)ActualAccount->Mails; msgq != nullptr; 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 = nullptr; FromStrNew = FALSE;
+
+ if (hListView != nullptr) {
+ 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 (nullptr == 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 != nullptr) && (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 != nullptr) && (UnicodeHeader.FromNick != nullptr)) {
+ size_t size = mir_wstrlen(UnicodeHeader.From) + mir_wstrlen(UnicodeHeader.FromNick) + 4;
+ FromStr = new WCHAR[size];
+ mir_snwprintf(FromStr, size, L"%s <%s>", UnicodeHeader.FromNick, UnicodeHeader.From);
+ FromStrNew = TRUE;
+ }
+ else if (UnicodeHeader.From != nullptr)
+ FromStr = UnicodeHeader.From;
+ else if (UnicodeHeader.FromNick != nullptr)
+ FromStr = UnicodeHeader.FromNick;
+ else if (UnicodeHeader.ReturnPath != nullptr)
+ FromStr = UnicodeHeader.ReturnPath;
+
+ if (nullptr == FromStr) {
+ FromStr = L"";
+ FromStrNew = FALSE;
+ }
+ }
+
+ if ((hListView != nullptr) && (msgq->Flags & YAMN_MSG_DISPLAY)) {
+ item.iSubItem = 0;
+ item.pszText = FromStr;
+ item.iItem = SendMessage(hListView, LVM_INSERTITEM, 0, (LPARAM)&item);
+
+ item.iSubItem = 1;
+ item.pszText = (nullptr != UnicodeHeader.Subject ? UnicodeHeader.Subject : (WCHAR*)L"");
+ SendMessage(hListView, LVM_SETITEMTEXT, (WPARAM)item.iItem, (LPARAM)&item);
+
+ item.iSubItem = 2;
+ mir_snwprintf(SizeStr, L"%d kB", msgq->MailData->Size / 1024);
+ item.pszText = SizeStr;
+ SendMessage(hListView, LVM_SETITEMTEXT, (WPARAM)item.iItem, (LPARAM)&item);
+
+ item.iSubItem = 3;
+ item.pszText = L"";
+
+ for (CMimeItem *heads = msgq->MailData->TranslatedHeader; heads != nullptr; heads = heads->Next) {
+ if (!_stricmp(heads->name, "Date")) {
+ MimeDateToLocalizedDateTime(heads->value, LocalDateStr, 128);
+ item.pszText = LocalDateStr;
+ break;
+ }
+ }
+ SendMessage(hListView, LVM_SETITEMTEXT, (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)) {
+ mir_wstrncpy(NewMailPopup.lpwzContactName, FromStr, _countof(NewMailPopup.lpwzContactName));
+ mir_wstrncpy(NewMailPopup.lpwzText, UnicodeHeader.Subject, _countof(NewMailPopup.lpwzText));
+
+ PYAMN_MAILSHOWPARAM MailParam = (PYAMN_MAILSHOWPARAM)malloc(sizeof(YAMN_MAILSHOWPARAM));
+ if (MailParam) {
+ MailParam->account = ActualAccount;
+ MailParam->mail = msgq;
+ MailParam->ThreadRunningEV = nullptr;
+ NewMailPopup.PluginData = MailParam;
+ PUAddPopupW(&NewMailPopup);
+ }
+ }
+
+ if ((msgq->Flags & YAMN_MSG_UNSEEN) && (ActualAccount->NewMailN.Flags & YAMN_ACC_KBN))
+ CallService(MS_KBDNOTIFY_EVENTSOPENED, 1, NULL);
+
+ if (FromStrNew)
+ delete[] FromStr;
+
+ if (Extracted) {
+ DeleteHeaderContent(&UnicodeHeader);
+ memset(&UnicodeHeader, 0, 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)
+{
+ NOTIFYICONDATA nid = {};
+ nid.cbSize = sizeof(nid);
+ nid.hWnd = hDlg;
+
+ 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)) {
+ wchar_t tszMsg[250];
+ mir_snwprintf(tszMsg, TranslateT("%s : %d new mail message(s), %d total"), _A2T(ActualAccount->Name), MN->Real.PopupNC + MN->Virtual.PopupNC, MN->Real.PopupTC + MN->Virtual.PopupTC);
+
+ if (!(nflags & YAMN_ACC_CONTNOEVENT)) {
+ CLISTEVENT evt = {};
+ evt.flags = CLEF_UNICODE;
+ evt.hContact = ActualAccount->hContact;
+ evt.hIcon = g_LoadIconEx(2);
+ evt.hDbEvent = ActualAccount->hContact;
+ evt.lParam = ActualAccount->hContact;
+ evt.pszService = MS_YAMN_CLISTDBLCLICK;
+ evt.szTooltip.w = tszMsg;
+ g_clistApi.pfnAddEvent(&evt);
+ }
+ db_set_ws(ActualAccount->hContact, "CList", "StatusMsg", tszMsg);
+
+ if (nflags & YAMN_ACC_CONTNICK)
+ g_plugin.setWString(ActualAccount->hContact, "Nick", tszMsg);
+ }
+
+ if ((nflags & YAMN_ACC_POP) &&
+ !(ActualAccount->Flags & YAMN_ACC_POPN) &&
+ (MN->Real.PopupRun + MN->Virtual.PopupRun)) {
+ POPUPDATAW NewMailPopup = { 0 };
+
+ NewMailPopup.lchContact = (ActualAccount->hContact != NULL) ? ActualAccount->hContact : (UINT_PTR)ActualAccount;
+ NewMailPopup.lchIcon = g_LoadIconEx(2);
+ if (nflags & YAMN_ACC_POPC) {
+ NewMailPopup.colorBack = ActualAccount->NewMailN.PopupB;
+ NewMailPopup.colorText = ActualAccount->NewMailN.PopupT;
+ }
+ else {
+ NewMailPopup.colorBack = GetSysColor(COLOR_BTNFACE);
+ NewMailPopup.colorText = GetSysColor(COLOR_WINDOWTEXT);
+ }
+ NewMailPopup.iSeconds = ActualAccount->NewMailN.PopupTime;
+
+ NewMailPopup.PluginWindowProc = NewMailPopupProc;
+ NewMailPopup.PluginData = (void *)nullptr; //multiple popups
+
+ mir_wstrncpy(NewMailPopup.lpwzContactName, _A2T(ActualAccount->Name), _countof(NewMailPopup.lpwzContactName));
+ mir_snwprintf(NewMailPopup.lpwzText, TranslateT("%d new mail message(s), %d total"), MN->Real.PopupNC + MN->Virtual.PopupNC, MN->Real.PopupTC + MN->Virtual.PopupTC);
+ PUAddPopupW(&NewMailPopup);
+ }
+
+ // destroy tray icon if no new mail
+ if ((MN->Real.SysTrayUC + MN->Virtual.SysTrayUC == 0) && (hDlg != nullptr))
+ 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))
+ g_clistApi.pfnRemoveEvent(ActualAccount->hContact, ActualAccount->hContact);
+
+ if ((MN->Real.BrowserUC + MN->Virtual.BrowserUC == 0) && (hDlg != nullptr)) {
+ if (!IsWindowVisible(hDlg) && !(nflags & YAMN_ACC_MSG))
+ PostMessage(hDlg, WM_DESTROY, 0, 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 != nullptr) //else insert icon and set window if new mails
+ {
+ SendDlgItemMessageW(hDlg, IDC_LISTMAILS, LVM_SCROLL, 0, (LPARAM)0x7ffffff);
+
+ if ((nflags & YAMN_ACC_ICO) && (MN->Real.SysTrayUC + MN->Virtual.SysTrayUC)) {
+ nid.hIcon = g_LoadIconEx(2);
+ nid.uFlags = NIF_ICON | NIF_MESSAGE | NIF_TIP;
+ nid.uCallbackMessage = WM_YAMN_NOTIFYICON;
+ mir_snwprintf(nid.szTip, L"%S %s", ActualAccount->Name, TranslateT("- new mail message(s)"));
+ Shell_NotifyIcon(NIM_ADD, &nid);
+ SetTimer(hDlg, TIMER_FLASHING, 500, nullptr);
+ }
+ 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;
+ memset(&si, 0, sizeof(si));
+ si.cb = sizeof(si);
+
+ if (ActualAccount->NewMailN.App != nullptr) {
+ WCHAR *Command;
+ if (ActualAccount->NewMailN.AppParam != nullptr)
+ Command = new WCHAR[mir_wstrlen(ActualAccount->NewMailN.App) + mir_wstrlen(ActualAccount->NewMailN.AppParam) + 6];
+ else
+ Command = new WCHAR[mir_wstrlen(ActualAccount->NewMailN.App) + 6];
+
+ if (Command != nullptr) {
+ mir_wstrcpy(Command, L"\"");
+ mir_wstrcat(Command, ActualAccount->NewMailN.App);
+ mir_wstrcat(Command, L"\" ");
+ if (ActualAccount->NewMailN.AppParam != nullptr)
+ mir_wstrcat(Command, ActualAccount->NewMailN.AppParam);
+ CreateProcessW(nullptr, Command, nullptr, nullptr, FALSE, NORMAL_PRIORITY_CLASS, nullptr, nullptr, &si, &pi);
+ delete[] Command;
+ }
+ }
+ }
+ }
+
+ if (MN->Real.SoundNC + MN->Virtual.SoundNC != 0)
+ if (nflags & YAMN_ACC_SND)
+ Skin_PlaySound(YAMN_NEWMAILSOUND);
+
+ if ((nnflags & YAMN_ACC_POP) && (MN->Real.PopupRun + MN->Virtual.PopupRun == 0)) {
+ POPUPDATAW NoNewMailPopup;
+
+ NoNewMailPopup.lchContact = (ActualAccount->hContact != NULL) ? ActualAccount->hContact : (UINT_PTR)ActualAccount;
+ NoNewMailPopup.lchIcon = g_LoadIconEx(1);
+ if (nflags & YAMN_ACC_POPC) {
+ NoNewMailPopup.colorBack = ActualAccount->NoNewMailN.PopupB;
+ NoNewMailPopup.colorText = ActualAccount->NoNewMailN.PopupT;
+ }
+ else {
+ NoNewMailPopup.colorBack = GetSysColor(COLOR_BTNFACE);
+ NoNewMailPopup.colorText = GetSysColor(COLOR_WINDOWTEXT);
+ }
+ NoNewMailPopup.iSeconds = ActualAccount->NoNewMailN.PopupTime;
+
+ NoNewMailPopup.PluginWindowProc = NoNewMailPopupProc;
+ NoNewMailPopup.PluginData = nullptr; //it's not new mail popup
+
+ mir_wstrncpy(NoNewMailPopup.lpwzContactName, _A2T(ActualAccount->Name), _countof(NoNewMailPopup.lpwzContactName));
+ if (MN->Real.PopupSL2NC + MN->Virtual.PopupSL2NC)
+ mir_snwprintf(NoNewMailPopup.lpwzText, TranslateT("No new mail message, %d spam(s)"), MN->Real.PopupSL2NC + MN->Virtual.PopupSL2NC);
+ else
+ mir_wstrncpy(NoNewMailPopup.lpwzText, TranslateT("No new mail message"), _countof(NoNewMailPopup.lpwzText));
+ PUAddPopupW(&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];
+ mir_snprintf(tmp, Translate("%d new mail message(s), %d total"), MN->Real.PopupNC + MN->Virtual.PopupNC, MN->Real.PopupTC + MN->Virtual.PopupTC);
+ db_set_s(ActualAccount->hContact, "CList", "StatusMsg", tmp);
+ }
+ else db_set_s(ActualAccount->hContact, "CList", "StatusMsg", Translate("No new mail message"));
+
+ if (nflags & YAMN_ACC_CONTNICK)
+ g_plugin.setString(ActualAccount->hContact, "Nick", ActualAccount->Name);
+ }
+ }
+ return;
+}
+
+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)))) {
+ MCONTACT 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;
+ mir_forkthread(ShowEmailThread, MailParam);
+ }
+ else {
+ DBVARIANT dbv;
+
+ hContact = PUGetContact(hWnd);
+
+ if (!g_plugin.getString(hContact, "Id", &dbv)) {
+ Account = (HACCOUNT)CallService(MS_YAMN_FINDACCOUNTBYNAME, (WPARAM)POP3Plugin, (LPARAM)dbv.pszVal);
+ db_free(&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)nullptr, 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))
+ g_clistApi.pfnRemoveEvent(hContact, hContact);
+ }
+ __fallthrough;
+
+ case WM_CONTEXTMENU:
+ PUDeletePopup(hWnd);
+ break;
+ case UM_FREEPLUGINDATA:
+ {
+ PYAMN_MAILSHOWPARAM mpd = (PYAMN_MAILSHOWPARAM)PUGetPluginData(hWnd);
+ 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);
+ break;
+ case UM_DESTROYPOPUP:
+ WindowList_Remove(YAMNVar.MessageWnds, hWnd);
+ break;
+ case WM_YAMN_STOPACCOUNT:
+ {
+ HACCOUNT ActualAccount;
+ DBVARIANT dbv;
+
+ MCONTACT hContact = PUGetContact(hWnd);
+
+ if (!g_plugin.getString(hContact, "Id", &dbv)) {
+ ActualAccount = (HACCOUNT)CallService(MS_YAMN_FINDACCOUNTBYNAME, (WPARAM)POP3Plugin, (LPARAM)dbv.pszVal);
+ db_free(&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;
+ DBVARIANT dbv;
+
+ MCONTACT hContact = PUGetContact(hWnd);
+
+ if (!g_plugin.getString(hContact, "Id", &dbv)) {
+ ActualAccount = (HACCOUNT)CallService(MS_YAMN_FINDACCOUNTBYNAME, (WPARAM)POP3Plugin, (LPARAM)dbv.pszVal);
+ db_free(&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)nullptr, ActualAccount, ActualAccount->NewMailN.Flags, ActualAccount->NoNewMailN.Flags, nullptr };
+
+ 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
+ PUDeletePopup(hWnd);
+ }
+ break;
+
+ case WM_CONTEXTMENU:
+ PUDeletePopup(hWnd);
+ 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);
+ break;
+ case UM_DESTROYPOPUP:
+ WindowList_Remove(YAMNVar.MessageWnds, hWnd);
+ break;
+ case WM_YAMN_STOPACCOUNT:
+ {
+ HACCOUNT ActualAccount;
+ DBVARIANT dbv;
+
+ MCONTACT hContact = PUGetContact(hWnd);
+
+ if (!g_plugin.getString(hContact, "Id", &dbv)) {
+ ActualAccount = (HACCOUNT)CallService(MS_YAMN_FINDACCOUNTBYNAME, (WPARAM)POP3Plugin, (LPARAM)dbv.pszVal);
+ db_free(&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 = nullptr, *month = nullptr, *year = nullptr, *time = nullptr, *shift = nullptr;
+ SYSTEMTIME st;
+ ULONGLONG res = 0;
+ int wShiftSeconds = TimeZone_ToLocal(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 (mir_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 = nullptr;
+ 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 (mir_strlen(shift) < 4) {
+ //has only hour
+ wShiftSeconds = (atoi(shift)) * 3600;
+ }
+ else {
+ char *smin = shift + mir_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 = Langpack_GetDefaultLocale();
+ //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, TranslateT("Invalid"), lendateout);
+ return;
+ }
+ SYSTEMTIME st;
+ WORD wTodayYear = 0, wTodayMonth = 0, wTodayDay = 0;
+ 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, nullptr, dateout, lendateout - 2);
+ dateout[templen - 1] = ' ';
+ }
+ if (templen < (lendateout - 1)) {
+ GetTimeFormatW(localeID, (optDateTime&SHOWDATENOSECONDS) ? TIME_NOSECONDS : 0, &st, nullptr, &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;
+ memset(&Header1, 0, sizeof(Header1));
+ memset(&Header2, 0, sizeof(Header2));
+
+ try {
+ ExtractShortHeader(email1->MailData->TranslatedHeader, &Header1);
+ ExtractShortHeader(email2->MailData->TranslatedHeader, &Header2);
+
+ switch ((int)lParamSort) {
+ case 0: //From
+ if (Header1.FromNick == nullptr)
+ str1 = Header1.From;
+ else str1 = Header1.FromNick;
+
+ if (Header2.FromNick == nullptr)
+ str2 = Header2.From;
+ else str2 = Header2.FromNick;
+
+ nResult = mir_strcmp(str1, str2);
+
+ if (bFrom) nResult = -nResult;
+ break;
+ case 1: //Subject
+ if (Header1.Subject == nullptr)
+ str1 = " ";
+ else str1 = Header1.Subject;
+
+ if (Header2.Subject == nullptr)
+ str2 = " ";
+ else str2 = Header2.Subject;
+
+ nResult = mir_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 == nullptr) str1 = " ";
+ else str1 = Header1.Subject;
+
+ if (Header2.Subject == nullptr) str2 = " ";
+ else str2 = Header2.Subject;
+
+ nResult = mir_strcmp(str1, str2);
+ break;
+ }
+ //MessageBox(NULL,str1,str2,0);
+ }
+ catch (...) {
+ }
+
+ //free mem
+ DeleteShortHeaderContent(&Header1);
+ DeleteShortHeaderContent(&Header2);
+ return nResult;
+
+}
+
+HCURSOR hCurSplitNS, hCurSplitWE;
+#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 mir_callNextSubclass(hwnd, SplitterSubclassProc, 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:
+ {
+ PYAMN_MAILSHOWPARAM MailParam = (PYAMN_MAILSHOWPARAM)lParam;
+ WCHAR *iHeaderW = nullptr;
+ WCHAR *iValueW = nullptr;
+ int StrLen;
+ HWND hListView = GetDlgItem(hDlg, IDC_LISTHEADERS);
+ mir_subclassWindow(GetDlgItem(hDlg, IDC_SPLITTER), SplitterSubclassProc);
+ SetWindowLongPtr(hDlg, DWLP_USER, (LONG_PTR)MailParam);
+ Window_SetIcon_IcoLib(hDlg, g_GetIconHandle(2));
+
+ ListView_SetUnicodeFormat(hListView, TRUE);
+ ListView_SetExtendedListViewStyle(hListView, LVS_EX_FULLROWSELECT);
+
+ StrLen = MultiByteToWideChar(CP_ACP, MB_USEGLYPHCHARS, Translate("Header"), -1, nullptr, 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, nullptr, 0);
+ iValueW = new WCHAR[StrLen + 1];
+ MultiByteToWideChar(CP_ACP, MB_USEGLYPHCHARS, Translate("Value"), -1, iValueW, StrLen);
+
+ LVCOLUMN lvc0 = { LVCF_FMT | LVCF_TEXT | LVCF_WIDTH, LVCFMT_LEFT, 130, iHeaderW, 0, 0 };
+ LVCOLUMN lvc1 = { LVCF_FMT | LVCF_TEXT | LVCF_WIDTH, LVCFMT_LEFT, 400, iValueW, 0, 0 };
+ SendMessage(hListView, LVM_INSERTCOLUMN, 0, (LPARAM)&lvc0);
+ SendMessage(hListView, LVM_INSERTCOLUMN, 1, (LPARAM)&lvc1);
+ if (nullptr != iHeaderW)
+ delete[] iHeaderW;
+ if (nullptr != iValueW)
+ delete[] iValueW;
+
+ 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 = nullptr, *Subj = nullptr;
+ char *contentType = nullptr, *transEncoding = nullptr, *body = nullptr; //should not be delete[]-ed
+ for (Header = MailParam->mail->MailData->TranslatedHeader; Header != nullptr; Header = Header->Next) {
+ WCHAR *str1 = nullptr;
+ WCHAR *str2 = nullptr;
+ WCHAR str_nul[2] = { 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, nullptr, 0);
+ str1 = (WCHAR *)malloc(sizeof(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 *)str_nul; }// the header value may be NULL
+ if (!From) if (!_stricmp(Header->name, "From")) {
+ From = new WCHAR[mir_wstrlen(str2) + 1];
+ mir_wstrcpy(From, str2);
+ }
+ if (!Subj) if (!_stricmp(Header->name, "Subject")) {
+ Subj = new WCHAR[mir_wstrlen(str2) + 1];
+ mir_wstrcpy(Subj, str2);
+ }
+ //if (!hasBody) if (!mir_strcmp(Header->name,"Body")) hasBody = true;
+ int count = 0; WCHAR **split = nullptr;
+ 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 = nullptr;
+ }
+ item.iItem = SendMessage(hListView, LVM_INSERTITEM, 0, (LPARAM)&item);
+ item.iSubItem = 1;
+ item.pszText = str2 ? split[i] : nullptr;
+ SendMessage(hListView, LVM_SETITEMTEXT, (WPARAM)item.iItem, (LPARAM)&item);
+ }
+ delete[] split;
+
+ if (str1)
+ free(str1);
+ if (str2 != (WCHAR *)str_nul)
+ free(str2);
+ }
+ if (body) {
+ WCHAR *bodyDecoded = nullptr;
+ char *localBody = nullptr;
+ if (contentType) {
+ if (!_strnicmp(contentType, "text", 4)) {
+ if (transEncoding) {
+ if (!_stricmp(transEncoding, "base64")) {
+ int size = (int)mir_strlen(body) * 3 / 4 + 5;
+ localBody = new char[size + 1];
+ DecodeBase64(body, localBody, size);
+ }
+ else if (!_stricmp(transEncoding, "quoted-printable")) {
+ int size = (int)mir_strlen(body) + 2;
+ localBody = new char[size + 1];
+ DecodeQuotedPrintable(body, localBody, size, FALSE);
+ }
+ }
+ }
+ else if (!_strnicmp(contentType, "multipart/", 10)) {
+ char *bondary = nullptr;
+ if (nullptr != (bondary = ExtractFromContentType(contentType, "boundary="))) {
+ bodyDecoded = ParseMultipartBody(body, bondary);
+ delete[] bondary;
+ }
+ }
+ }
+ if (!bodyDecoded)ConvertStringToUnicode(localBody ? localBody : body, MailParam->mail->MailData->CP, &bodyDecoded);
+ SetWindowTextW(hEdit, 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 = WindowList_Find(YAMNVar.NewMailAccountWnd, (UINT_PTR)MailParam->account);
+ if (hMailBrowser) {
+ struct CChangeContent Params = { MailParam->account->NewMailN.Flags | YAMN_ACC_MSGP, MailParam->account->NoNewMailN.Flags | YAMN_ACC_MSGP };
+ SendMessage(hMailBrowser, WM_YAMN_CHANGECONTENT, (WPARAM)MailParam->account, (LPARAM)&Params);
+ }
+ else UpdateMails(nullptr, 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 = nullptr;
+ size_t size = (From ? mir_wstrlen(From) : 0) + (Subj ? mir_wstrlen(Subj) : 0) + 4;
+ title = new WCHAR[size];
+ if (From && Subj)
+ mir_snwprintf(title, size, L"%s (%s)", Subj, From);
+ else if (From)
+ wcsncpy_s(title, size, From, _TRUNCATE);
+ else if (Subj)
+ wcsncpy_s(title, size, Subj, _TRUNCATE);
+ else
+ wcsncpy_s(title, size, L"none", _TRUNCATE);
+ if (Subj) delete[] Subj;
+ if (From) delete[] From;
+ SetWindowTextW(hDlg, 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 (nullptr == 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:
+ Window_FreeIcon_IcoLib(hDlg);
+ {
+ 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 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));
+ //}
+ }
+ 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 = { GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam) };
+ 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, nullptr);
+ AppendMenu(hMenu, MF_STRING, (UINT_PTR)0, TranslateT("Cancel"));
+ int nReturnCmd = TrackPopupMenu(hMenu, TPM_RETURNCMD, pt.x, pt.y, 0, hDlg, nullptr);
+ DestroyMenu(hMenu);
+ if (nReturnCmd > 0) {
+ int courRow = 0;
+ size_t sizeNeeded = 0;
+ wchar_t 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, _countof(headname));
+ ListView_GetItemText(hList, courRow, 1, headvalue, _countof(headvalue));
+ size_t headnamelen = mir_wstrlen(headname);
+ if (headnamelen) sizeNeeded += 1 + headnamelen;
+ sizeNeeded += 3 + mir_wstrlen(headvalue);
+ }
+ if (sizeNeeded && OpenClipboard(hDlg)) {
+ EmptyClipboard();
+ HGLOBAL hData = GlobalAlloc(GMEM_MOVEABLE, (sizeNeeded + 1) * sizeof(wchar_t));
+ wchar_t *buff = (wchar_t*)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, _countof(headname));
+ ListView_GetItemText(hList, courRow, 1, headvalue, _countof(headvalue));
+ if (mir_wstrlen(headname)) courPos += mir_snwprintf(&buff[courPos], sizeNeeded + 1, L"%s:\t%s\r\n", headname, headvalue);
+ else courPos += mir_snwprintf(&buff[courPos], sizeNeeded + 1, L"\t%s\r\n", headvalue);
+ }
+ GlobalUnlock(hData);
+
+ SetClipboardData(CF_UNICODETEXT, hData);
+
+ CloseClipboard();
+ }
+ }
+ }
+ }
+ break; // just in case
+ }
+ return 0;
+}
+
+void __cdecl ShowEmailThread(void *Param)
+{
+ struct MailShowMsgWinParam 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);
+
+ 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 = nullptr;
+ goto CREADTEVIEWMESSAGEWINDOW;
+ }
+
+ if (IsIconic(MyParam.mail->MsgWindow))
+ OpenIcon(MyParam.mail->MsgWindow);
+ }
+ else {
+CREADTEVIEWMESSAGEWINDOW:
+ MyParam.mail->MsgWindow = CreateDialogParamW(g_plugin.getInst(), MAKEINTRESOURCEW(IDD_DLGSHOWMESSAGE), nullptr, DlgProcYAMNShowMessage, (LPARAM)&MyParam);
+ WindowList_Add(YAMNVar.MessageWnds, MyParam.mail->MsgWindow);
+ MSG msg;
+ while (GetMessage(&msg, nullptr, 0, 0)) {
+ if (MyParam.mail->MsgWindow == nullptr || !IsDialogMessage(MyParam.mail->MsgWindow, &msg)) { /* Wine fix. */
+ TranslateMessage(&msg);
+ DispatchMessage(&msg);
+ }
+ }
+ WindowList_Remove(YAMNVar.MessageWnds, MyParam.mail->MsgWindow);
+ MyParam.mail->MsgWindow = nullptr;
+ }
+#ifdef DEBUG_SYNCHRO
+ DebugLog(SynchroFile, "ShowMessage:Decrementing \"using threads\" %x (account %x)\n", MyParam.account->UsingThreads, MyParam.account);
+#endif
+ SCDecFcn(MyParam.account->UsingThreads);
+ delete (struct MailShowMsgWinParam*)Param;
+}
+
+INT_PTR CALLBACK DlgProcYAMNMailBrowser(HWND hDlg, UINT msg, WPARAM wParam, LPARAM lParam)
+{
+ HACCOUNT ActualAccount;
+ int Items;
+
+ switch (msg) {
+ case WM_INITDIALOG:
+ {
+ struct MailBrowserWinParam *MyParam = (struct MailBrowserWinParam *)lParam;
+
+ ListView_SetUnicodeFormat(GetDlgItem(hDlg, IDC_LISTMAILS), TRUE);
+ ListView_SetExtendedListViewStyle(GetDlgItem(hDlg, IDC_LISTMAILS), LVS_EX_FULLROWSELECT);
+
+ ActualAccount = MyParam->account;
+ struct CMailWinUserInfo *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);
+ if (WAIT_OBJECT_0 != WaitToReadFcn(ActualAccount->AccountAccessSO)) {
+ DestroyWindow(hDlg);
+ return FALSE;
+ }
+
+ SetDlgItemText(hDlg, IDC_BTNAPP, TranslateT("Run application"));
+ SetDlgItemText(hDlg, IDC_BTNDEL, TranslateT("Delete selected"));
+ SetDlgItemText(hDlg, IDC_BTNCHECKALL, TranslateT("Select All"));
+ SetDlgItemText(hDlg, IDC_BTNOK, TranslateT("OK"));
+
+ LVCOLUMN lvc0 = { LVCF_FMT | LVCF_TEXT | LVCF_WIDTH, LVCFMT_LEFT, FromWidth, TranslateT("From"), 0, 0 };
+ LVCOLUMN lvc1 = { LVCF_FMT | LVCF_TEXT | LVCF_WIDTH, LVCFMT_LEFT, SubjectWidth, TranslateT("Subject"), 0, 0 };
+ LVCOLUMN lvc2 = { LVCF_FMT | LVCF_TEXT | LVCF_WIDTH, LVCFMT_LEFT, SizeWidth, TranslateT("Size"), 0, 0 };
+ LVCOLUMN lvc3 = { LVCF_FMT | LVCF_TEXT | LVCF_WIDTH, LVCFMT_LEFT, SizeDate, TranslateT("Date"), 0, 0 };
+ SendDlgItemMessage(hDlg, IDC_LISTMAILS, LVM_INSERTCOLUMN, 0, (LPARAM)&lvc0);
+ SendDlgItemMessage(hDlg, IDC_LISTMAILS, LVM_INSERTCOLUMN, 1, (LPARAM)&lvc1);
+ SendDlgItemMessage(hDlg, IDC_LISTMAILS, LVM_INSERTCOLUMN, (WPARAM)2, (LPARAM)&lvc2);
+ SendDlgItemMessage(hDlg, IDC_LISTMAILS, LVM_INSERTCOLUMN, (WPARAM)3, (LPARAM)&lvc3);
+
+ if ((ActualAccount->NewMailN.App != nullptr) && (mir_wstrlen(ActualAccount->NewMailN.App)))
+ EnableWindow(GetDlgItem(hDlg, IDC_BTNAPP), TRUE);
+ else
+ EnableWindow(GetDlgItem(hDlg, IDC_BTNAPP), FALSE);
+
+ ReadDoneFcn(ActualAccount->AccountAccessSO);
+
+ WindowList_Add(YAMNVar.MessageWnds, hDlg);
+ WindowList_Add(YAMNVar.NewMailAccountWnd, hDlg, (UINT_PTR)ActualAccount);
+
+ {
+ wchar_t accstatus[512];
+ GetStatusFcn(ActualAccount, accstatus);
+ SetDlgItemText(hDlg, IDC_STSTATUS, accstatus);
+ }
+ SetTimer(hDlg, TIMER_FLASHING, 500, nullptr);
+
+ if (ActualAccount->hContact != NULL)
+ g_clistApi.pfnRemoveEvent(ActualAccount->hContact, (LPARAM)"yamn new mail message");
+
+ mir_subclassWindow(GetDlgItem(hDlg, IDC_LISTMAILS), ListViewSubclassProc);
+ }
+ break;
+
+ case WM_DESTROY:
+ {
+ RECT coord;
+ LVCOLUMN ColInfo;
+ HYAMNMAIL Parser;
+
+ Window_FreeIcon_IcoLib(hDlg);
+
+ struct CMailWinUserInfo *mwui = (struct CMailWinUserInfo *)GetWindowLongPtr(hDlg, DWLP_USER);
+ if (nullptr == (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;
+ g_plugin.setDword(YAMN_DBPOSX, PosX);
+ g_plugin.setDword(YAMN_DBPOSY, PosY);
+ g_plugin.setDword(YAMN_DBSIZEX, SizeX);
+ g_plugin.setDword(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 != nullptr; 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);
+
+ NOTIFYICONDATA nid;
+ memset(&nid, 0, sizeof(NOTIFYICONDATA));
+
+ delete mwui;
+ SetWindowLongPtr(hDlg, DWLP_USER, 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 = (struct CMailWinUserInfo *)GetWindowLongPtr(hDlg, DWLP_USER);
+
+ if (mwui == nullptr)
+ return 0;
+ mwui->Seen = TRUE;
+ }
+
+ case WM_YAMN_CHANGESTATUS:
+ if (nullptr == (ActualAccount = GetWindowAccount(hDlg)))
+ break;
+
+ if ((HACCOUNT)wParam != ActualAccount)
+ break;
+
+ wchar_t accstatus[512];
+ GetStatusFcn(ActualAccount, accstatus);
+ SetDlgItemText(hDlg, IDC_STSTATUS, accstatus);
+ return 1;
+
+ case WM_YAMN_CHANGECONTENT:
+ {
+ struct CUpdateMails UpdateParams;
+ BOOL ThisThreadWindow = (GetCurrentThreadId() == GetWindowThreadProcessId(hDlg, nullptr));
+
+ if (nullptr == (UpdateParams.Copied = CreateEvent(nullptr, FALSE, FALSE, nullptr))) {
+ 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:
+ {
+ struct CUpdateMails *um = (struct CUpdateMails *)lParam;
+ DWORD nflags, nnflags;
+
+#ifdef DEBUG_SYNCHRO
+ DebugLog(SynchroFile, "MailBrowser:UPDATEMAILS\n");
+#endif
+
+ if (nullptr == (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:
+ if (nullptr == (ActualAccount = GetWindowAccount(hDlg)))
+ break;
+ if ((HACCOUNT)wParam != ActualAccount)
+ break;
+ PostQuitMessage(0);
+ return 1;
+
+ case WM_YAMN_NOTIFYICON:
+ if (nullptr == (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 = SendDlgItemMessage(hDlg, IDC_LISTMAILS, LVM_GETNEXTITEM, -1, MAKELPARAM((UINT)LVNI_FOCUSED, 0)); // return item selected
+ if (iSelect != -1) {
+ LV_ITEMW item;
+
+ item.iItem = iSelect;
+ item.iSubItem = 0;
+ item.mask = LVIF_PARAM | LVIF_STATE;
+ item.stateMask = 0xFFFFFFFF;
+ ListView_GetItem(GetDlgItem(hDlg, IDC_LISTMAILS), &item);
+ HYAMNMAIL ActualMail = (HYAMNMAIL)item.lParam;
+ if (nullptr != ActualMail) {
+ PYAMN_MAILSHOWPARAM MailParam = new YAMN_MAILSHOWPARAM;
+ MailParam->account = GetWindowAccount(hDlg);
+ MailParam->mail = ActualMail;
+ mir_forkthread(ShowEmailThread, MailParam);
+ }
+ }
+ }
+ break;
+
+ case WM_SYSCOMMAND:
+ if (nullptr == (ActualAccount = GetWindowAccount(hDlg)))
+ break;
+ switch (wParam) {
+ case SC_CLOSE:
+ DestroyWindow(hDlg);
+ break;
+ }
+ break;
+
+ case WM_COMMAND:
+ if (nullptr == (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;
+
+ memset(&si, 0, sizeof(si));
+ si.cb = sizeof(si);
+
+ if (WAIT_OBJECT_0 == WaitToReadFcn(ActualAccount->AccountAccessSO)) {
+ if (ActualAccount->NewMailN.App != nullptr) {
+ WCHAR *Command;
+ if (ActualAccount->NewMailN.AppParam != nullptr)
+ Command = new WCHAR[mir_wstrlen(ActualAccount->NewMailN.App) + mir_wstrlen(ActualAccount->NewMailN.AppParam) + 6];
+ else
+ Command = new WCHAR[mir_wstrlen(ActualAccount->NewMailN.App) + 6];
+
+ if (Command != nullptr) {
+ mir_wstrcpy(Command, L"\"");
+ mir_wstrcat(Command, ActualAccount->NewMailN.App);
+ mir_wstrcat(Command, L"\" ");
+ if (ActualAccount->NewMailN.AppParam != nullptr)
+ mir_wstrcat(Command, ActualAccount->NewMailN.AppParam);
+ CreateProcessW(nullptr, Command, nullptr, nullptr, FALSE, NORMAL_PRIORITY_CLASS, nullptr, nullptr, &si, &pi);
+ delete[] Command;
+ }
+ }
+
+ ReadDoneFcn(ActualAccount->AccountAccessSO);
+ }
+
+ if (!(GetKeyState(VK_SHIFT) & 0x8000) && !(GetKeyState(VK_CONTROL) & 0x8000))
+ DestroyWindow(hDlg);
+ }
+ break;
+
+ case IDC_BTNDEL:
+ {
+ HYAMNMAIL ActualMail;
+ DWORD Total = 0;
+
+ // we use event to signal, that running thread has all needed stack parameters copied
+ HANDLE ThreadRunningEV = CreateEvent(nullptr, FALSE, FALSE, nullptr);
+ if (ThreadRunningEV == nullptr)
+ break;
+
+ Items = ListView_GetItemCount(GetDlgItem(hDlg, IDC_LISTMAILS));
+
+ LVITEM item;
+ item.stateMask = 0xFFFFFFFF;
+
+ if (WAIT_OBJECT_0 == WaitToWriteFcn(ActualAccount->MessagesAccessSO)) {
+ 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 (nullptr == 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
+ WriteDoneFcn(ActualAccount->MessagesAccessSO);
+
+ if (Total) {
+ wchar_t DeleteMsg[1024];
+
+ mir_snwprintf(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, nullptr };
+
+ // Find if there's mail marked to delete, which was deleted before
+ if (WAIT_OBJECT_0 == WaitToWriteFcn(ActualAccount->MessagesAccessSO)) {
+ for (ActualMail = (HYAMNMAIL)ActualAccount->Mails; ActualMail != nullptr; 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 = mir_forkthread(ActualAccount->Plugin->Fcn->DeleteMailsFcnPtr, &ParamToDeleteMails);
+ if (NewThread != nullptr)
+ WaitForSingleObject(ThreadRunningEV, INFINITE);
+
+ // Enable write-access to mails
+ 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 (g_plugin.getByte(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
+ }
+ 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);
+
+ memset(&nid, 0, 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:
+ if (nullptr != (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);
+ ReadDoneFcn(ActualAccount->AccountAccessSO);
+ }
+ }
+ break;
+
+ case NM_CUSTOMDRAW:
+ {
+ LPNMLVCUSTOMDRAW cd = (LPNMLVCUSTOMDRAW)lParam;
+ LONG_PTR PaintCode;
+
+ if (nullptr == (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:
+ {
+ BOOL umma;
+ {
+ struct CMailWinUserInfo *mwui = (struct CMailWinUserInfo *)GetWindowLongPtr(hDlg, DWLP_USER);
+ umma = mwui->UpdateMailsMessagesAccess;
+ }
+ HYAMNMAIL ActualMail = (HYAMNMAIL)cd->nmcd.lItemlParam;
+ if (!ActualMail)
+ ActualMail = (HYAMNMAIL)readItemLParam(cd->nmcd.hdr.hwndFrom, cd->nmcd.dwItemSpec);
+
+ if (!umma)
+ if (WAIT_OBJECT_0 != WaitToReadFcn(ActualAccount->MessagesAccessSO))
+ return 0;
+
+ 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)
+ ReadDoneFcn(ActualAccount->MessagesAccessSO);
+ break;
+ }
+ default:
+ PaintCode = 0;
+ }
+ 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 = { GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam) };
+ 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, nullptr);
+ AppendMenu(hMenu, MF_STRING, (UINT_PTR)0, TranslateT("Cancel"));
+ int nReturnCmd = TrackPopupMenu(hMenu, TPM_RETURNCMD, pt.x, pt.y, 0, hDlg, nullptr);
+ DestroyMenu(hMenu);
+ if (nReturnCmd > 0) {
+ int courRow = 0;
+ size_t sizeNeeded = 0;
+ wchar_t 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, _countof(from));
+ ListView_GetItemText(hList, courRow, 1, subject, _countof(subject));
+ ListView_GetItemText(hList, courRow, 2, size, _countof(size));
+ ListView_GetItemText(hList, courRow, 3, date, _countof(date));
+ sizeNeeded += 5 + mir_wstrlen(from) + mir_wstrlen(subject) + mir_wstrlen(size) + mir_wstrlen(date);
+ }
+ if (sizeNeeded && OpenClipboard(hDlg)) {
+ EmptyClipboard();
+ HGLOBAL hData = GlobalAlloc(GMEM_MOVEABLE, (sizeNeeded + 1) * sizeof(wchar_t));
+ wchar_t *buff = (wchar_t *)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, _countof(from));
+ ListView_GetItemText(hList, courRow, 1, subject, _countof(subject));
+ ListView_GetItemText(hList, courRow, 2, size, _countof(size));
+ ListView_GetItemText(hList, courRow, 3, date, _countof(date));
+ courPos += mir_snwprintf(&buff[courPos], sizeNeeded + 1, L"%s\t%s\t%s\t%s\r\n", from, subject, size, date);
+ }
+ GlobalUnlock(hData);
+
+ SetClipboardData(CF_UNICODETEXT, hData);
+
+ CloseClipboard();
+ }
+ }
+ }
+ }
+ break; // just in case
+ }
+ return 0;
+}
+
+LRESULT CALLBACK ListViewSubclassProc(HWND hDlg, UINT msg, WPARAM wParam, LPARAM lParam)
+{
+ HWND hwndParent = GetParent(hDlg);
+
+ switch (msg) {
+ case WM_GETDLGCODE:
+ {
+ LPMSG lpmsg = (LPMSG)lParam;
+ if (lpmsg != nullptr) {
+ 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 mir_callNextSubclass(hDlg, ListViewSubclassProc, msg, wParam, lParam);
+}
+
+void __cdecl MailBrowser(void *Param)
+{
+ MSG msg;
+
+ HWND hMailBrowser;
+ BOOL WndFound = FALSE;
+
+ struct MailBrowserWinParam MyParam = *(struct MailBrowserWinParam *)Param;
+ HACCOUNT ActualAccount = MyParam.account;
+ SCIncFcn(ActualAccount->UsingThreads);
+
+ // we will not use params in stack anymore
+ SetEvent(MyParam.ThreadRunningEV);
+
+ __try {
+ if (WAIT_OBJECT_0 != WaitToReadFcn(ActualAccount->AccountAccessSO))
+ return;
+
+ 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;
+
+ ReadDoneFcn(ActualAccount->AccountAccessSO);
+
+ if (nullptr != (hMailBrowser = WindowList_Find(YAMNVar.NewMailAccountWnd, (UINT_PTR)ActualAccount)))
+ WndFound = TRUE;
+
+ if ((hMailBrowser == nullptr) && ((MyParam.nflags & YAMN_ACC_MSG) || (MyParam.nflags & YAMN_ACC_ICO) || (MyParam.nnflags & YAMN_ACC_MSG))) {
+ hMailBrowser = CreateDialogParamW(g_plugin.getInst(), MAKEINTRESOURCEW(IDD_DLGVIEWMESSAGES), nullptr, DlgProcYAMNMailBrowser, (LPARAM)&MyParam);
+ Window_SetIcon_IcoLib(hMailBrowser, g_GetIconHandle(2));
+ MoveWindow(hMailBrowser, PosX, PosY, SizeX, SizeY, TRUE);
+ }
+
+ if (hMailBrowser != nullptr) {
+ struct CChangeContent Params = { MyParam.nflags, MyParam.nnflags }; //if this thread created window, just post message to update mails
+
+ SendMessage(hMailBrowser, WM_YAMN_CHANGECONTENT, (WPARAM)ActualAccount, (LPARAM)&Params); //we ensure this will do the thread who created the browser window
+ }
+ else
+ UpdateMails(nullptr, ActualAccount, MyParam.nflags, MyParam.nnflags); //update mails without displaying or refreshing any window
+
+ if ((hMailBrowser != nullptr) && !WndFound) { //we process message loop only for thread that created window
+ while (GetMessage(&msg, nullptr, 0, 0)) {
+ if (hMailBrowser == nullptr || !IsDialogMessage(hMailBrowser, &msg)) { /* Wine fix. */
+ TranslateMessage(&msg);
+ DispatchMessage(&msg);
+ }
+ }
+ }
+
+ if ((!WndFound) && (ActualAccount->Plugin->Fcn != nullptr) && (ActualAccount->Plugin->Fcn->WriteAccountsFcnPtr != nullptr) && ActualAccount->AbleToWork)
+ ActualAccount->Plugin->Fcn->WriteAccountsFcnPtr();
+ }
+ __finally {
+ SCDecFcn(ActualAccount->UsingThreads);
+ }
+}
+
+INT_PTR RunMailBrowserSvc(WPARAM wParam, LPARAM lParam)
+{
+ PYAMN_MAILBROWSERPARAM Param = (PYAMN_MAILBROWSERPARAM)wParam;
+
+ if ((DWORD)lParam != YAMN_MAILBROWSERVERSION)
+ return 0;
+
+ //an event for successfull copy parameters to which point a pointer in stack for new thread
+ HANDLE ThreadRunningEV = CreateEvent(nullptr, FALSE, FALSE, nullptr);
+ Param->ThreadRunningEV = ThreadRunningEV;
+
+ HANDLE NewThread = mir_forkthread(MailBrowser, Param);
+ if (NewThread != nullptr)
+ WaitForSingleObject(ThreadRunningEV, INFINITE);
+
+ CloseHandle(ThreadRunningEV);
+ return 1;
+}
diff --git a/protocols/YAMN/src/debug.cpp b/protocols/YAMN/src/debug.cpp
new file mode 100644
index 0000000000..971b3dcbce
--- /dev/null
+++ b/protocols/YAMN/src/debug.cpp
@@ -0,0 +1,127 @@
+/*
+ * 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 "stdafx.h"
+
+#ifdef _DEBUG
+
+//--------------------------------------------------------------------------------------------------
+//--------------------------------------------------------------------------------------------------
+
+wchar_t DebugUserDirectory[MAX_PATH] = L".";
+CRITICAL_SECTION FileAccessCS;
+
+#ifdef DEBUG_SYNCHRO
+wchar_t DebugSynchroFileName2[]=L"%s\\yamn-debug.synchro.log";
+HANDLE SynchroFile;
+#endif
+
+#ifdef DEBUG_COMM
+wchar_t DebugCommFileName2[]=L"%s\\yamn-debug.comm.log";
+HANDLE CommFile;
+#endif
+
+#ifdef DEBUG_DECODE
+wchar_t DebugDecodeFileName2[]=L"%s\\yamn-debug.decode.log";
+HANDLE DecodeFile;
+#endif
+
+//--------------------------------------------------------------------------------------------------
+//--------------------------------------------------------------------------------------------------
+
+void InitDebug()
+{
+#if defined (DEBUG_SYNCHRO) || defined (DEBUG_COMM) || defined (DEBUG_DECODE)
+ wchar_t DebugFileName[MAX_PATH];
+#endif
+ InitializeCriticalSection(&FileAccessCS);
+
+#ifdef DEBUG_SYNCHRO
+ mir_snwprintf(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
+ mir_snwprintf(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
+ mir_snwprintf(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()
+{
+ DeleteCriticalSection(&FileAccessCS);
+#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, "[%x]",GetCurrentThreadId());
+ while(mir_vsnprintf(str, strsize, fmt, vararg)==-1)
+ str=(char *)realloc(str,strsize+=65536);
+ va_end(vararg);
+ EnterCriticalSection(&FileAccessCS);
+ WriteFile(File,tids,(DWORD)mir_strlen(tids),&Written,nullptr);
+ WriteFile(File,str,(DWORD)mir_strlen(str),&Written,nullptr);
+ 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, "[%x]",GetCurrentThreadId());
+ while(mir_vsnwprintf(str, strsize, fmt, vararg)==-1)
+ str=(WCHAR *)realloc(str,(strsize+=65536)*sizeof(WCHAR));
+ va_end(vararg);
+ EnterCriticalSection(&FileAccessCS);
+ WriteFile(File,tids,(DWORD)mir_strlen(tids),&Written,nullptr);
+ WriteFile(File,str,(DWORD)mir_wstrlen(str)*sizeof(WCHAR),&Written,nullptr);
+ LeaveCriticalSection(&FileAccessCS);
+ free(str);
+}
+
+#endif //ifdef DEBUG \ No newline at end of file
diff --git a/protocols/YAMN/src/debug.h b/protocols/YAMN/src/debug.h
new file mode 100644
index 0000000000..a28add5662
--- /dev/null
+++ b/protocols/YAMN/src/debug.h
@@ -0,0 +1,51 @@
+#ifndef __DEBUG_H
+#define __DEBUG_H
+
+#ifdef _DEBUG
+
+//#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);
+
+DWORD ReadStringFromMemoryW(char **Parser,wchar_t *End,char **StoreTo,wchar_t *DebugString);
+
+#else
+DWORD ReadStringFromMemory(char **Parser,char *End,char **StoreTo);
+
+DWORD ReadStringFromMemoryW(WCHAR **Parser,WCHAR *End,WCHAR **StoreTo);
+
+#endif
+
+//#ifdef DEBUG_ACCOUNTS
+//int GetAccounts();
+//void WriteAccounts();
+//#endif
+
+#endif //YAMN_DEBUG
+#endif //_DEBUG_H
diff --git a/protocols/YAMN/src/filterplugin.cpp b/protocols/YAMN/src/filterplugin.cpp
new file mode 100644
index 0000000000..dca5780152
--- /dev/null
+++ b/protocols/YAMN/src/filterplugin.cpp
@@ -0,0 +1,200 @@
+/*
+ * YAMN plugin export functions for filtering
+ *
+ * (c) majvan 2002-2004
+ */
+
+#include "stdafx.h"
+
+//--------------------------------------------------------------------------------------------------
+//--------------------------------------------------------------------------------------------------
+
+PYAMN_FILTERPLUGINQUEUE FirstFilterPlugin=nullptr;
+
+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==nullptr) || (Registration->Ver==nullptr))
+ return NULL;
+ if (nullptr==(Plugin=new YAMN_FILTERPLUGIN))
+ return NULL;
+
+ Plugin->PluginInfo=Registration;
+
+ Plugin->FilterFcn=nullptr;
+
+#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 != nullptr) && (Plugin != Parser->Next->Plugin);Parser=Parser->Next);
+ if (Parser->Next != nullptr)
+ {
+ Found=Parser->Next;
+ Parser->Next=Parser->Next->Next;
+ }
+ else
+ Found=nullptr;
+ }
+ if (Found != nullptr)
+ {
+ if (Plugin->FilterFcn->UnLoadFcn != nullptr)
+ Plugin->FilterFcn->UnLoadFcn((void *)nullptr);
+
+ 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)
+{
+ HYAMNFILTERPLUGIN Plugin=(HYAMNFILTERPLUGIN)wParam;
+
+ mir_cslock lck(PluginRegCS);
+ UnregisterFilterPlugin(Plugin);
+ return 1;
+}
+
+INT_PTR UnregisterFilterPlugins()
+{
+ mir_cslock lck(PluginRegCS);
+
+ // We remove protocols from the protocol list
+ while(FirstFilterPlugin != nullptr)
+ UnregisterFilterPlugin(FirstFilterPlugin->Plugin);
+ 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==nullptr)
+ return 0;
+
+#ifdef DEBUG_SYNCHRO
+ DebugLog(SynchroFile,"::: YAMN- filter %0x import succeed :::\n",Plugin);
+#endif
+ Plugin->Importance=Importance;
+ Plugin->FilterFcn=YAMNFilterFcn;
+
+ mir_cslock lck(PluginRegCS);
+ // We add protocol to the protocol list
+ for (Previous = nullptr, Parser = FirstFilterPlugin; Parser != nullptr && Parser->Next != nullptr && Parser->Plugin->Importance <= Importance; Previous = Parser, Parser = Parser->Next);
+ if (Previous==nullptr) //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
+ }
+ return 1;
+}
+
+INT_PTR FilterMailSvc(WPARAM wParam,LPARAM lParam)
+{
+ HACCOUNT Account=(HACCOUNT)wParam;
+ HYAMNMAIL Mail=(HYAMNMAIL)lParam;
+ PYAMN_FILTERPLUGINQUEUE ActualPlugin;
+
+ mir_cslock lck(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 != nullptr;ActualPlugin=ActualPlugin->Next)
+ {
+ if (ActualPlugin->Plugin->FilterFcn->FilterMailFcnPtr != nullptr)
+ {
+#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);
+ return 1;
+}
diff --git a/protocols/YAMN/src/mails/decode.cpp b/protocols/YAMN/src/mails/decode.cpp
new file mode 100644
index 0000000000..5ac1346c7c
--- /dev/null
+++ b/protocols/YAMN/src/mails/decode.cpp
@@ -0,0 +1,555 @@
+/*
+ * 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 "../stdafx.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 = _countof(CodePageNamesAll);
+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])==nullptr)
+ 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 = 0;
+
+#ifdef DEBUG_DECODECODEPAGE
+ DebugLog(DecodeFile,"<CodePage>%s</CodePage>",pout);
+#endif
+ for (int i=0;i<CPLENALL;i++) {
+ size_t len = mir_strlen(CodePageNamesAll[i].NameBase);
+ if (0==strncmp(pout,CodePageNamesAll[i].NameBase,len)) {
+ if (0==mir_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;(*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=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,nullptr,0);
+ else
+ streamlen=MultiByteToWideChar(cp,MB_USEGLYPHCHARS,stream,-1,nullptr,0);
+
+ if (*out != nullptr)
+ outlen=mir_wstrlen(*out);
+ else
+ outlen=0;
+ temp=new WCHAR[streamlen+outlen+1];
+
+ if (*out != nullptr)
+ {
+ 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;
+
+ if (stream==nullptr)
+ return;
+
+ while(WS(start)) start++;
+ WCHAR *tempstore=nullptr;
+ if (!ConvertStringToUnicode(stream,cp,&tempstore))return;
+
+ size_t tempstoreLength = mir_wstrlen(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 = 0,codeend;
+ char *pcodeend = nullptr;
+
+ 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--;
+ }
+ 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;
+ }
+
+ char *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=mir_strlen(DecodedResult);
+ DecodedResult[len]=' ';
+ DecodedResult[len+1]=0;
+ finderend++;
+ }
+ WCHAR *oneWord=nullptr;
+ if (ConvertStringToUnicode(DecodedResult,cp,&oneWord)) {
+ size_t len = mir_wstrlen(oneWord);
+ memcpy(&tempstore[outind],oneWord,len*sizeof(WCHAR));
+ outind += len;
+ }
+ delete oneWord;
+ oneWord = nullptr;
+ delete[] DecodedResult;
+ 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/src/mails/decode.h b/protocols/YAMN/src/mails/decode.h
new file mode 100644
index 0000000000..cc643594b2
--- /dev/null
+++ b/protocols/YAMN/src/mails/decode.h
@@ -0,0 +1,23 @@
+#ifndef __DECODE_H
+#define __DECODE_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/src/mails/mails.cpp b/protocols/YAMN/src/mails/mails.cpp
new file mode 100644
index 0000000000..ee570fa8e2
--- /dev/null
+++ b/protocols/YAMN/src/mails/mails.cpp
@@ -0,0 +1,494 @@
+/*
+ * This code implements retrieving info from MIME header
+ *
+ * (c) majvan 2002-2004
+ */
+
+#include "../stdafx.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 != nullptr)
+ {
+ if (Account->Plugin->MailFcn->NewMailFcnPtr != nullptr)
+ {
+//Let plugin create its own structure, which can be derived from CAccount structure
+ if (nullptr==(NewMail=Account->Plugin->MailFcn->NewMailFcnPtr(Account,YAMN_MAILVERSION)))
+ return NULL;
+ }
+ else
+ {
+//We suggest plugin uses standard CAccount structure, so we create it
+ if (nullptr==(NewMail=new YAMNMAIL))
+//If not created successfully
+ return NULL;
+ NewMail->MailData=nullptr;
+ }
+//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 != nullptr) {
+ if (Plugin->MailFcn->DeleteMailFcnPtr != nullptr) {
+ //Let plugin delete its own CMimeMsgQueue derived structure
+ Plugin->MailFcn->DeleteMailFcnPtr(OldMail);
+ return 1;
+ }
+ }
+ if (OldMail->MailData != nullptr) {
+ if (OldMail->MailData->Body != nullptr)
+ delete[] OldMail->MailData->Body;
+ if ((TH=OldMail->MailData->TranslatedHeader) != nullptr)
+ for (;OldMail->MailData->TranslatedHeader != nullptr;) {
+ TH=TH->Next;
+ if (OldMail->MailData->TranslatedHeader->name != nullptr)
+ delete[] OldMail->MailData->TranslatedHeader->name;
+ if (OldMail->MailData->TranslatedHeader->value != nullptr)
+ delete[] OldMail->MailData->TranslatedHeader->value;
+ delete OldMail->MailData->TranslatedHeader;
+ OldMail->MailData->TranslatedHeader=TH;
+ }
+ delete OldMail->MailData;
+ }
+ if (OldMail->ID != nullptr)
+ 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 != nullptr) 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, LPARAM)
+{
+ return 1;
+}
+
+INT_PTR SaveMailDataSvc(WPARAM, LPARAM lParam)
+{
+ 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 =nullptr;
+ HYAMNMAIL RemovedNewParser =nullptr;
+ if (RemovedOld != nullptr) *RemovedOld=nullptr;
+ if (RemovedNew != nullptr) *RemovedNew=nullptr;
+
+ for (FinderPrev=nullptr,Finder=*OldQueue;Finder != nullptr;)
+ {
+ 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=nullptr,Parser=*NewQueue;Parser != nullptr;ParserPrev=Parser,Parser=Parser->Next)
+ {
+ if (Parser->Flags & YAMN_MSG_DELETED)
+ continue;
+
+ if (Parser->ID==nullptr) //simply ignore the message, that has not filled its ID
+ continue;
+
+ if (0==mir_strcmp(Parser->ID,Finder->ID)) //search for equal message in new queue
+ break;
+ }
+ if (Parser != nullptr) //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==nullptr) //delete from new queue
+ DeleteAccountMailSvc((WPARAM)Account->Plugin,(LPARAM)Parser);
+ else //or move to RemovedNew
+ {
+ if (RemovedNewParser==nullptr) //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=nullptr;
+ }
+ 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==nullptr) //delete from old queue
+ DeleteAccountMailSvc((WPARAM)Account->Plugin,(LPARAM)Finder);
+ else //or move to RemovedOld
+ {
+ if (RemovedOldParser==nullptr) //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=nullptr;
+ }
+ Finder=*OldQueue;
+ }
+ else
+ {
+ FinderPrev->Next=Finder->Next;
+ if (RemovedOld==nullptr) //delete from old queue
+ DeleteAccountMailSvc((WPARAM)Account->Plugin,(LPARAM)Finder);
+ else //or move to RemovedOld
+ {
+ if (RemovedOldParser==nullptr) //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=nullptr;
+ }
+ Finder=FinderPrev->Next;
+ }
+ }
+ }
+}
+
+void WINAPI DeleteMessagesToEndFcn(HACCOUNT Account,HYAMNMAIL From)
+{
+ HYAMNMAIL Temp;
+ while(From != nullptr)
+ {
+ 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 != nullptr;Parser=Parser->Next)
+ if (Parser->Number>Number) Parser->Number--;
+}
+
+void DeleteMessagesFromQueue(HYAMNMAIL *From,HYAMNMAIL Which,int mode=0)
+{
+ HYAMNMAIL Parser;
+
+ for (Parser=Which;Parser != nullptr;Parser=Parser->Next)
+ DeleteMessageFromQueueFcn(From,Parser,mode);
+}
+
+HYAMNMAIL WINAPI FindMessageByIDFcn(HYAMNMAIL From,char *ID)
+{
+ HYAMNMAIL Browser;
+
+ for (Browser=From;Browser != nullptr;Browser=Browser->Next)
+ if (0==mir_strcmp(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=nullptr;
+
+ 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 != nullptr)
+ {
+ if (nullptr==(Item->Next=new struct CMimeItem))
+ break;
+ Item=Item->Next;
+ }
+ else
+ {
+ Item = new CMimeItem;
+ *head = Item;
+ }
+
+ Item->Next=nullptr;
+ Item->name=new char [prev2-prev1+1];
+ mir_strncpy(Item->name,prev1,prev2-prev1+1);
+ Item->value=new char [finder-prev3+1];
+ mir_strncpy(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 (nullptr==(Item->Next=new struct CMimeItem)) break; // Cant create new item?!
+ Item=Item->Next;
+ Item->Next=nullptr;//just in case;
+ Item->name=new char[5]; strncpy(Item->name,"Body",5);
+ Item->value=new char [prev2-prev1];
+ mir_strncpy(Item->value,prev1,prev2-prev1-1);
+ }
+ break; // there is nothing else
+ }
+ }
+ }
+ }
+ catch(...)
+ {
+ MessageBoxA(nullptr,"Translate header error","",0);
+ }
+}
+
+HYAMNMAIL WINAPI CreateNewDeleteQueueFcn(HYAMNMAIL From)
+{
+ HYAMNMAIL FirstMail,Browser = nullptr;
+
+ for (FirstMail=nullptr;From != nullptr;From=From->Next)
+ {
+ if ((From->Flags & (YAMN_MSG_USERDELETE | YAMN_MSG_AUTODELETE)) && !(From->Flags & YAMN_MSG_DELETED))
+ {
+ if (FirstMail==nullptr)
+ {
+ FirstMail=Browser=new YAMNMAIL;
+ if (FirstMail==nullptr)
+ break;
+ }
+ else
+ {
+ Browser->Next=new YAMNMAIL;
+ Browser=Browser->Next;
+ }
+ Browser->ID=new char[mir_strlen(From->ID)+1];
+ mir_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 != nullptr;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/src/mails/mime.cpp b/protocols/YAMN/src/mails/mime.cpp
new file mode 100644
index 0000000000..52ac1a5ff7
--- /dev/null
+++ b/protocols/YAMN/src/mails/mime.cpp
@@ -0,0 +1,718 @@
+/*
+ * This code implements retrieving info from MIME header
+ *
+ * (c) majvan 2002-2004
+ */
+
+#include "../stdafx.h"
+
+//--------------------------------------------------------------------------------------------------
+
+//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==nullptr)
+ return;
+ if (srcstart>=srcend)
+ return;
+
+ if ((mode==MIME_MAIL) && (((*srcstart=='"') && (*(srcend-1)=='"')) || ((*srcstart=='<') && (*(srcend-1)=='>'))))
+ {
+ srcstart++;
+ srcend--;
+ }
+
+ if (srcstart>=srcend)
+ return;
+
+ if (nullptr != *dest)
+ delete[] *dest;
+ if (nullptr==(*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==nullptr)
+ {
+ *storeto=*storetonick=nullptr;
+ 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==nullptr)
+ {
+ *storeto=nullptr;
+ 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==nullptr) {
+ free (lowered);
+ return nullptr;
+ }
+ 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 nullptr;
+ finder=finder+mir_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 (nullptr==(CopiedString=new char[++temp-finder+1]))
+ return nullptr;
+ 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 != nullptr;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==nullptr)
+ 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==nullptr)
+ 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==nullptr)
+ 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==nullptr)
+ 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==nullptr)
+ 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==nullptr)
+ continue;
+
+ char *ContentType=nullptr,*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 (nullptr != (CharSetStr=ExtractFromContentType(ContentType,"charset=")))
+ {
+ head->CP=GetCharsetFromString(CharSetStr,mir_strlen(CharSetStr));
+ delete[] CharSetStr;
+ }
+ delete[] ContentType;
+ }
+ else if (0==_strnicmp(items->name,"Importance",10))
+ {
+ if (items->value==nullptr)
+ 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==nullptr)
+ 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;
+
+ memset(&ShortHeader, 0, 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 != nullptr) delete[] head->From;
+ if (head->FromNick != nullptr) delete[] head->FromNick;
+ if (head->ReturnPath != nullptr) delete[] head->ReturnPath;
+ if (head->ReturnPathNick != nullptr) delete[] head->ReturnPathNick;
+ if (head->Subject != nullptr) delete[] head->Subject;
+ if (head->Date != nullptr) delete[] head->Date;
+ if (head->To != nullptr) DeleteShortNames(head->To);
+ if (head->Cc != nullptr) DeleteShortNames(head->Cc);
+ if (head->Bcc != nullptr) DeleteShortNames(head->Bcc);
+ if (head->Body != nullptr) delete[] head->Body;
+}
+
+void DeleteHeaderContent(struct CHeader *head)
+{
+ if (head->From != nullptr) delete[] head->From;
+ if (head->FromNick != nullptr) delete[] head->FromNick;
+ if (head->ReturnPath != nullptr) delete[] head->ReturnPath;
+ if (head->ReturnPathNick != nullptr) delete[] head->ReturnPathNick;
+ if (head->Subject != nullptr) delete[] head->Subject;
+ if (head->Date != nullptr) delete[] head->Date;
+ if (head->Body != nullptr) delete[] head->Body;
+ if (head->To != nullptr) DeleteNames(head->To);
+ if (head->Cc != nullptr) DeleteNames(head->Cc);
+ if (head->Bcc != nullptr) DeleteNames(head->Bcc);
+}
+
+void DeleteNames(PYAMN_MIMENAMES Names)
+{
+ PYAMN_MIMENAMES Parser=Names,Old;
+ for (;Parser != nullptr;Parser=Parser->Next)
+ {
+ if (Parser->Value != nullptr)
+ delete[] Parser->Value;
+ if (Parser->ValueNick != nullptr)
+ delete[] Parser->ValueNick;
+ Old=Parser;
+ Parser=Parser->Next;
+ delete Old;
+ }
+}
+
+void DeleteShortNames(PYAMN_MIMESHORTNAMES Names)
+{
+ PYAMN_MIMESHORTNAMES Parser=Names,Old;
+ for (;Parser != nullptr;Parser=Parser->Next)
+ {
+ if (Parser->Value != nullptr)
+ delete[] Parser->Value;
+ if (Parser->ValueNick != nullptr)
+ 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 = mir_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(nullptr, TranslateT("Translate header error"), L"", 0);
+ }
+ if (data->body) data->bodyLen = (int)mir_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 = mir_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 (nullptr != (CharSetStr=ExtractFromContentType(partData[i].ContType,"charset=")))
+ {
+ partData[i].CodePage=GetCharsetFromString(CharSetStr,mir_strlen(CharSetStr));
+ delete[] CharSetStr;
+ }
+ }
+ if (partData[i].ContType && !_strnicmp(partData[i].ContType,"text",4)) {
+ char *localBody=nullptr;
+ 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=nullptr;
+ if (nullptr != (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 += mir_wstrlen(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[1024]; size_t linesize = 0;
+ mir_snprintf(infoline, "%s %d", Translate("Part"), i);
+ linesize = mir_strlen(infoline);
+ if (partData[i].TransEnc) {
+ mir_snprintf(infoline + linesize, _countof(infoline) - linesize, "; %s", partData[i].TransEnc);
+ linesize = mir_strlen(infoline);
+ }
+ if (partData[i].ContType) {
+ char *CharSetStr=strchr(partData[i].ContType,';');
+ if (CharSetStr) {
+ CharSetStr[0]=0;
+ mir_snprintf(infoline + linesize, _countof(infoline) - linesize, "; %s", partData[i].ContType);
+ linesize = mir_strlen(infoline);
+ partData[i].ContType=CharSetStr+1;
+ if (nullptr != (CharSetStr=ExtractFromContentType(partData[i].ContType,"charset="))) {
+ mir_snprintf(infoline + linesize, _countof(infoline) - linesize, "; %s", CharSetStr);
+ linesize = mir_strlen(infoline);
+ delete[] CharSetStr;
+ }
+ if (nullptr != (CharSetStr=ExtractFromContentType(partData[i].ContType,"name="))) {
+ mir_snprintf(infoline + linesize, _countof(infoline) - linesize, "; \"%s\"", CharSetStr);
+ linesize = mir_strlen(infoline);
+ delete[] CharSetStr;
+ }
+ }
+ else {
+ mir_snprintf(infoline + linesize, _countof(infoline) - linesize, "; %s", partData[i].ContType);
+ linesize = mir_strlen(infoline);
+ }
+ }
+ mir_snprintf(infoline + linesize, _countof(infoline) - linesize, ".\r\n");
+ {
+ WCHAR *temp=nullptr;
+ dest[destpos] = dest[destpos+1] = dest[destpos+2] = 0x2022; // bullet;
+ destpos += 3;
+ ConvertStringToUnicode(infoline,CP_ACP,&temp);
+ size_t wsize = mir_wstrlen(temp);
+ mir_wstrcpy(&dest[destpos],temp);
+ destpos += wsize;
+ delete[] temp;
+ }
+ } // if (i)
+
+ if (partData[i].wBody) {
+ size_t wsize = mir_wstrlen(partData[i].wBody);
+ mir_wstrcpy(&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/src/main.cpp b/protocols/YAMN/src/main.cpp
new file mode 100644
index 0000000000..75a7ea1896
--- /dev/null
+++ b/protocols/YAMN/src/main.cpp
@@ -0,0 +1,353 @@
+/*
+ * 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 "stdafx.h"
+
+ //--------------------------------------------------------------------------------------------------
+
+wchar_t ProfileName[MAX_PATH];
+wchar_t UserDirectory[MAX_PATH];
+
+wchar_t szMirandaDir[MAX_PATH];
+wchar_t szProfileDir[MAX_PATH];
+
+int YAMN_STATUS;
+
+BOOL UninstallPlugins;
+
+HANDLE hAccountFolder;
+
+HINSTANCE *hDllPlugins;
+static int iDllPlugins = 0;
+
+YAMN_VARIABLES YAMNVar;
+
+CMPlugin g_plugin;
+
+HANDLE hNewMailHook;
+HANDLE NoWriterEV;
+HANDLE hTTButton;
+
+UINT SecTimer;
+
+HGENMENU hMenuItemMain = nullptr;
+HGENMENU hMenuItemCont = nullptr;
+HGENMENU hMenuItemContApp = nullptr;
+
+#define FIXED_TAB_SIZE 100 // default value for fixed width tabs
+
+static void GetProfileDirectory(wchar_t *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
+{
+ wchar_t tszOldPath[MAX_PATH];
+ Profile_GetPathW(_countof(tszOldPath), tszOldPath);
+ mir_wstrcat(tszOldPath, L"\\*.book");
+
+ VARSW ptszNewPath(L"%miranda_userdata%");
+
+ SHFILEOPSTRUCT file_op = {
+ nullptr,
+ FO_MOVE,
+ tszOldPath,
+ ptszNewPath,
+ FOF_NOERRORUI | FOF_NOCONFIRMATION | FOF_SILENT,
+ false,
+ nullptr,
+ L"" };
+ SHFileOperation(&file_op);
+
+ wcsncpy(szPath, ptszNewPath, cbPath);
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+
+extern "C" __declspec(dllexport) const MUUID MirandaInterfaces[] = { MIID_PROTOCOL, MIID_LAST };
+
+/////////////////////////////////////////////////////////////////////////////////////////
+
+PLUGININFOEX pluginInfoEx = {
+ sizeof(PLUGININFOEX),
+ __PLUGIN_NAME,
+ PLUGIN_MAKE_VERSION(__MAJOR_VERSION, __MINOR_VERSION, __RELEASE_NUM, __BUILD_NUM),
+ __DESCRIPTION,
+ __AUTHOR,
+ __COPYRIGHT,
+ __AUTHORWEB,
+ UNICODE_AWARE,
+ // {B047A7E5-027A-4CFC-8B18-EDA8345D2790}
+ {0xb047a7e5, 0x27a, 0x4cfc, {0x8b, 0x18, 0xed, 0xa8, 0x34, 0x5d, 0x27, 0x90}}
+};
+
+CMPlugin::CMPlugin() :
+ PLUGIN<CMPlugin>(YAMN_DBMODULE, pluginInfoEx)
+{
+ RegisterProtocol(PROTOTYPE_VIRTUAL);
+ SetUniqueId("Id");
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// The callback function
+
+BOOL CALLBACK EnumSystemCodePagesProc(LPTSTR cpStr)
+{
+ // Convert code page string to number
+ UINT cp = _wtoi(cpStr);
+ if (!IsValidCodePage(cp))
+ return TRUE;
+
+ // Get Code Page name
+ CPINFOEX info;
+ if (GetCPInfoEx(cp, 0, &info)) {
+ for (int i = 1; i < CPLENALL; i++) if (CodePageNamesAll[i].CP == cp) {
+ CodePageNamesAll[i].isValid = TRUE;
+ CPLENSUPP++;
+ break;
+ }
+ }
+ return TRUE;
+}
+
+void CheckMenuItems()
+{
+ Menu_ShowItem(hMenuItemMain, g_plugin.getByte(YAMN_SHOWMAINMENU, 1) != 0);
+}
+
+int SystemModulesLoaded(WPARAM, LPARAM)
+{
+ //Insert "Check mail (YAMN)" item to Miranda's menu
+ CMenuItem mi(&g_plugin);
+
+ SET_UID(mi, 0xa01ff3d9, 0x53cb, 0x4406, 0x85, 0xd9, 0xf1, 0x90, 0x3a, 0x94, 0xed, 0xf4);
+ mi.position = 0xb0000000;
+ mi.hIcolibItem = g_GetIconHandle(0);
+ mi.name.a = LPGEN("Check &mail (All Account)");
+ mi.pszService = MS_YAMN_FORCECHECK;
+ hMenuItemMain = Menu_AddMainMenuItem(&mi);
+
+ SET_UID(mi, 0xfe22191f, 0x40c8, 0x479f, 0x93, 0x5d, 0xa5, 0x17, 0x1f, 0x57, 0x2f, 0xcb);
+ mi.name.a = LPGEN("Check &mail (This Account)");
+ mi.pszService = MS_YAMN_CLISTCONTEXT;
+ hMenuItemCont = Menu_AddContactMenuItem(&mi, YAMN_DBMODULE);
+
+ SET_UID(mi, 0x147c7800, 0x12d0, 0x4209, 0xab, 0xcc, 0xfa, 0x64, 0xc6, 0xb0, 0xa6, 0xeb);
+ mi.hIcolibItem = g_GetIconHandle(1);
+ mi.name.a = LPGEN("Launch application");
+ mi.pszService = MS_YAMN_CLISTCONTEXTAPP;
+ hMenuItemContApp = Menu_AddContactMenuItem(&mi, YAMN_DBMODULE);
+
+ CheckMenuItems();
+
+ if (hAccountFolder = FoldersRegisterCustomPathT(LPGEN("YAMN"), LPGEN("YAMN Account Folder"), UserDirectory))
+ FoldersGetCustomPathT(hAccountFolder, UserDirectory, MAX_PATH, UserDirectory);
+
+ RegisterPOP3Plugin(0, 0);
+ return 0;
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+
+static IconItem iconList[] =
+{
+ { LPGEN("Check mail"), "YAMN_Check", IDI_CHECKMAIL },
+ { LPGEN("Launch application"), "YAMN_Launch", IDI_LAUNCHAPP },
+ { LPGEN("New Mail"), "YAMN_NewMail", IDI_NEWMAIL },
+ { LPGEN("Connect Fail"), "YAMN_ConnectFail", IDI_BADCONNECT },
+};
+
+void LoadIcons()
+{
+ g_plugin.registerIcon("YAMN", iconList);
+}
+
+HANDLE WINAPI g_GetIconHandle(int idx)
+{
+ if (idx >= _countof(iconList))
+ return nullptr;
+ return iconList[idx].hIcolib;
+}
+
+HICON WINAPI g_LoadIconEx(int idx, bool big)
+{
+ if (idx >= _countof(iconList))
+ return nullptr;
+ return IcoLib_GetIcon(iconList[idx].szName, big);
+}
+
+static void LoadPlugins()
+{
+ wchar_t szSearchPath[MAX_PATH];
+ mir_snwprintf(szSearchPath, L"%s\\Plugins\\YAMN\\*.dll", szMirandaDir);
+
+ hDllPlugins = nullptr;
+
+ WIN32_FIND_DATA fd;
+ HANDLE hFind = FindFirstFile(szSearchPath, &fd);
+ if (hFind != INVALID_HANDLE_VALUE) {
+ do {
+ //rewritten from Miranda sources... Needed because Win32 API has a bug in FindFirstFile, search is done for *.dlllllll... too
+ wchar_t *dot = wcsrchr(fd.cFileName, '.');
+ if (dot == nullptr)
+ continue;
+
+ // we have a dot
+ int len = (int)mir_wstrlen(fd.cFileName); // find the length of the string
+ wchar_t* 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) || (mir_wstrcmpi(dot + 1, L"dll") != 0)) //not bound, however the "dll" string should mean only 3 chars are compared
+ continue;
+
+ wchar_t szPluginPath[MAX_PATH];
+ mir_snwprintf(szPluginPath, L"%s\\Plugins\\YAMN\\%s", szMirandaDir, fd.cFileName);
+ HINSTANCE hDll = LoadLibrary(szPluginPath);
+ if (hDll == nullptr)
+ continue;
+
+ LOADFILTERFCN LoadFilter = (LOADFILTERFCN)GetProcAddress(hDll, "LoadFilter");
+ if (nullptr == LoadFilter) {
+ FreeLibrary(hDll);
+ hDll = nullptr;
+ continue;
+ }
+
+ if (!LoadFilter(GetFcnPtrSvc)) {
+ FreeLibrary(hDll);
+ hDll = nullptr;
+ }
+
+ if (hDll != nullptr) {
+ hDllPlugins = (HINSTANCE *)realloc(hDllPlugins, (iDllPlugins + 1) * sizeof(HINSTANCE));
+ hDllPlugins[iDllPlugins++] = hDll;
+ }
+ } while (FindNextFile(hFind, &fd));
+
+ FindClose(hFind);
+ }
+}
+
+int CMPlugin::Load()
+{
+ YAMN_STATUS = ID_STATUS_OFFLINE;
+
+ // we get the Miranda Root Path
+ PathToAbsoluteW(L".", szMirandaDir);
+
+ // retrieve the current profile name
+ Profile_GetNameW(_countof(ProfileName), ProfileName);
+ wchar_t *fc = wcsrchr(ProfileName, '.');
+ if (fc != nullptr) *fc = 0;
+
+ // we get the user path where our yamn-account.book.ini is stored from mirandaboot.ini file
+ GetProfileDirectory(UserDirectory, _countof(UserDirectory));
+
+ // Enumerate all the code pages available for the System Locale
+ EnumSystemCodePages(EnumSystemCodePagesProc, CP_INSTALLED);
+ CodePageNamesSupp = new _tcptable[CPLENSUPP];
+ for (int i = 0, k = 0; i < CPLENALL; i++) {
+ if (CodePageNamesAll[i].isValid) {
+ CodePageNamesSupp[k] = CodePageNamesAll[i];
+ k++;
+ }
+ }
+
+ if (nullptr == (NoWriterEV = CreateEvent(nullptr, TRUE, TRUE, nullptr)))
+ return 1;
+ if (nullptr == (WriteToFileEV = CreateEvent(nullptr, FALSE, FALSE, nullptr)))
+ return 1;
+ if (nullptr == (ExitEV = CreateEvent(nullptr, TRUE, FALSE, nullptr)))
+ return 1;
+
+ PosX = g_plugin.getDword(YAMN_DBPOSX, 0);
+ PosY = g_plugin.getDword(YAMN_DBPOSY, 0);
+ SizeX = g_plugin.getDword(YAMN_DBSIZEX, 800);
+ SizeY = g_plugin.getDword(YAMN_DBSIZEY, 200);
+
+ HeadPosX = g_plugin.getDword(YAMN_DBMSGPOSX, 0);
+ HeadPosY = g_plugin.getDword(YAMN_DBMSGPOSY, 0);
+ HeadSizeX = g_plugin.getDword(YAMN_DBMSGSIZEX, 690);
+ HeadSizeY = g_plugin.getDword(YAMN_DBMSGSIZEY, 300);
+ HeadSplitPos = g_plugin.getWord(YAMN_DBMSGPOSSPLIT, 250);
+
+ optDateTime = g_plugin.getByte(YAMN_DBTIMEOPTIONS, optDateTime);
+
+ // Create new window queues for broadcast messages
+ YAMNVar.MessageWnds = WindowList_Create();
+ YAMNVar.NewMailAccountWnd = WindowList_Create();
+ YAMNVar.Shutdown = FALSE;
+
+ hCurSplitNS = LoadCursor(nullptr, IDC_SIZENS);
+ hCurSplitWE = LoadCursor(nullptr, IDC_SIZEWE);
+
+#ifdef _DEBUG
+ InitDebug();
+#endif
+
+ CreateServiceFunctions();
+
+ g_plugin.addSound(YAMN_NEWMAILSOUND, L"YAMN", YAMN_NEWMAILSNDDESC);
+ g_plugin.addSound(YAMN_CONNECTFAILSOUND, L"YAMN", YAMN_CONNECTFAILSNDDESC);
+
+ HookEvents();
+
+ LoadIcons();
+ LoadPlugins();
+
+ HOTKEYDESC hkd = {};
+ hkd.pszName = "YAMN_hotkey";
+ hkd.pszService = MS_YAMN_FORCECHECK;
+ hkd.szSection.a = YAMN_DBMODULE;
+ hkd.szDescription.a = LPGEN("Check mail");
+ hkd.DefHotKey = HOTKEYCODE(HOTKEYF_CONTROL, VK_F11);
+ g_plugin.addHotkey(&hkd);
+
+ //Create thread that will be executed every second
+ if (!(SecTimer = SetTimer(nullptr, 0, 1000, TimerProc)))
+ return 1;
+
+ return 0;
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+
+static void UnloadPlugins()
+{
+ if (hDllPlugins == nullptr)
+ return;
+ for (int i = iDllPlugins - 1; i >= 0; i--) {
+ if (FreeLibrary(hDllPlugins[i])) {
+ hDllPlugins[i] = nullptr; //for safety
+ iDllPlugins--;
+ }
+ }
+ free((void *)hDllPlugins);
+ hDllPlugins = nullptr;
+}
+
+int CMPlugin::Unload()
+{
+#ifdef _DEBUG
+ UnInitDebug();
+#endif
+
+ WindowList_Destroy(YAMNVar.MessageWnds);
+ WindowList_Destroy(YAMNVar.NewMailAccountWnd);
+
+ DestroyCursor(hCurSplitNS);
+ DestroyCursor(hCurSplitWE);
+
+ CloseHandle(NoWriterEV);
+ CloseHandle(WriteToFileEV);
+ CloseHandle(ExitEV);
+
+ UnloadPlugins();
+
+ delete[] CodePageNamesSupp;
+ return 0;
+}
diff --git a/protocols/YAMN/src/main.h b/protocols/YAMN/src/main.h
new file mode 100644
index 0000000000..bbfee0e6cf
--- /dev/null
+++ b/protocols/YAMN/src/main.h
@@ -0,0 +1,39 @@
+#ifndef __MAIN_H
+#define __MAIN_H
+
+#define YAMN_NEWMAILSNDDESC LPGENW("New mail message")
+#define YAMN_CONNECTFAILSNDDESC LPGENW("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();
+
+typedef INT_PTR (*LOADFILTERFCN)(MIRANDASERVICE GetYAMNFcn);
+
+#endif
+
diff --git a/protocols/YAMN/src/proto/netclient.h b/protocols/YAMN/src/proto/netclient.h
new file mode 100644
index 0000000000..99ec0888f1
--- /dev/null
+++ b/protocols/YAMN/src/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= nullptr, 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/src/proto/netlib.cpp b/protocols/YAMN/src/proto/netlib.cpp
new file mode 100644
index 0000000000..02fb6d3cdc
--- /dev/null
+++ b/protocols/YAMN/src/proto/netlib.cpp
@@ -0,0 +1,242 @@
+/*
+ * This code implements communication based on Miranda netlib library
+ *
+ * (c) majvan 2002-2004
+ */
+
+#include "../stdafx.h"
+
+ //--------------------------------------------------------------------------------------------------
+ //--------------------------------------------------------------------------------------------------
+
+BOOL SSLLoaded = FALSE;
+HNETLIBUSER hNetlibUser = nullptr;
+
+void __stdcall SSL_DebugLog(const char *fmt, ...)
+{
+ char str[4096];
+ va_list vararg;
+
+ va_start(vararg, fmt);
+ int tBytes = mir_vsnprintf(str, _countof(str), fmt, vararg);
+ if (tBytes == 0)
+ return;
+
+ if (tBytes > 0)
+ str[tBytes] = 0;
+ else
+ str[sizeof(str) - 1] = 0;
+
+ Netlib_Log(hNetlibUser, str);
+ va_end(vararg);
+}
+
+HANDLE RegisterNLClient(const char *name)
+{
+ char desc[128];
+
+ mir_snprintf(desc, Translate("%s connection"), name);
+
+ #ifdef DEBUG_COMM
+ DebugLog(CommFile, "<Register PROXY support>");
+ #endif
+
+ NETLIBUSER nlu = {};
+ nlu.flags = NUF_OUTGOING | NUF_HTTPCONNS;
+ nlu.szDescriptiveName.a = desc;
+ nlu.szSettingsModule = (char *)name;
+ hNetlibUser = Netlib_RegisterUser(&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 = Netlib_GetSocket(hConnection);
+ if (socket != INVALID_SOCKET) {
+ #ifdef DEBUG_COMM
+ SSL_DebugLog("Staring netlib core SSL");
+ #endif
+ if (Netlib_StartSsl(hConnection, nullptr)) {
+ #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)
+{
+ NetworkError = SystemError = 0;
+ isTLSed = false;
+
+ #ifdef DEBUG_COMM
+ DebugLog(CommFile, "<connect>\n");
+ #endif
+ try {
+ NETLIBOPENCONNECTION nloc;
+ nloc.cbSize = sizeof(NETLIBOPENCONNECTION);
+ nloc.szHost = servername;
+ nloc.wPort = port;
+ nloc.flags = 0;
+ if (nullptr == (hConnection = Netlib_OpenConnection(hNetlibUser, &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(HNETLIBCONN hConn, const char *buf, int len, int flags)
+{
+ return Netlib_Send(hConn, buf, len, flags);
+}
+
+void CNLClient::Send(const char *query) throw(DWORD)
+{
+ unsigned int Sent;
+
+ if (nullptr == query)
+ return;
+ if (hConnection == nullptr)
+ return;
+ #ifdef DEBUG_COMM
+ DebugLog(CommFile, "<send>%s", query);
+ #endif
+ try {
+ if ((SOCKET_ERROR == (Sent = LocalNetlib_Send(hConnection, query, (int)mir_strlen(query), MSG_DUMPASTEXT))) || Sent != (unsigned int)mir_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(HNETLIBCONN hConn, char *buf, int len, int flags)
+{
+ int iReturn = Netlib_Recv(hConn, buf, len, flags);
+ 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 == nullptr)
+ buf = (char *)malloc(sizeof(char)*(buflen + 1));
+ if (buf == nullptr)
+ throw NetworkError = (DWORD)ENL_RECVALLOC;
+
+ if (!isTLSed) {
+ NETLIBSELECT nls = {};
+ nls.dwTimeout = 60000;
+ nls.hReadConns[0] = hConnection;
+ switch (Netlib_Select(&nls)) {
+ case SOCKET_ERROR:
+ free(buf);
+ SystemError = WSAGetLastError();
+ throw NetworkError = (DWORD)ENL_RECV;
+ case 0: // time out!
+ free(buf);
+ throw NetworkError = (DWORD)ENL_TIMEOUT;
+ }
+ }
+
+ memset(buf, 0, 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 = nullptr;
+}
+
+//Uninitializes netlib library
+void UnregisterNLClient()
+{
+ #ifdef DEBUG_COMM
+ DebugLog(CommFile, "<Unregister PROXY support>");
+ #endif
+
+ Netlib_CloseHandle(hNetlibUser);
+ hNetlibUser = nullptr;
+ #ifdef DEBUG_COMM
+ DebugLog(CommFile, "</Unregister PROXY support>\n");
+ #endif
+}
diff --git a/protocols/YAMN/src/proto/netlib.h b/protocols/YAMN/src/proto/netlib.h
new file mode 100644
index 0000000000..778d6497ed
--- /dev/null
+++ b/protocols/YAMN/src/proto/netlib.h
@@ -0,0 +1,51 @@
+#ifndef __NETLIB_H
+#define __NETLIB_H
+
+class CNLClient: public CNetClient
+{
+public:
+ CNLClient(): hConnection(nullptr) {}
+ void Connect(const char* servername, const int port) throw(DWORD);
+ void Send(const char *query) throw(DWORD);
+ char* Recv(char *buf= nullptr, int buflen = 65536) throw(DWORD);
+ void Disconnect();
+ void SSLify()throw(DWORD);
+
+ inline BOOL Connected() {return hConnection != nullptr;}
+
+protected:
+ HNETLIBCONN hConnection;
+ BOOL isTLSed;
+ int LocalNetlib_Send(HNETLIBCONN hConn, const char *buf, int len, int flags);
+ int LocalNetlib_Recv(HNETLIBCONN 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/src/proto/pop3/pop3.cpp b/protocols/YAMN/src/proto/pop3/pop3.cpp
new file mode 100644
index 0000000000..d47fac4836
--- /dev/null
+++ b/protocols/YAMN/src/proto/pop3/pop3.cpp
@@ -0,0 +1,356 @@
+/*
+ * 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
+ *
+ */
+
+#include "../../stdafx.h"
+
+//--------------------------------------------------------------------------------------------------
+//--------------------------------------------------------------------------------------------------
+
+//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 = nullptr;
+ if (Stopped) //check if we can work with this POP3 client session
+ throw POP3Error=(DWORD)EPOP3_STOPPED;
+
+ if (NetClient != nullptr)
+ 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 nullptr;
+ }
+ }
+
+ 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 nullptr;
+ }
+// 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 != nullptr)
+ free(PrevString);
+ throw POP3Error=(DWORD)EPOP3_STOPPED;
+ }
+ if (SizeLeft==0) //if block is full
+ {
+ SizeRead+=size;
+ SizeLeft=size;
+ LastString=NetClient->Recv(nullptr,SizeLeft);
+ PrevString=(char *)realloc(PrevString,sizeof(char)*(SizeRead+size));
+ if (PrevString==nullptr)
+ 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;
+ }
+ 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;
+
+ mir_snprintf(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;
+
+ mir_snprintf(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];
+
+ if (timestamp==nullptr)
+ throw POP3Error=(DWORD)EPOP3_APOP;
+ mir_md5_state_s ctx;
+ mir_md5_init(&ctx);
+ mir_md5_append(&ctx,(const unsigned char *)timestamp,(unsigned int)mir_strlen(timestamp));
+ mir_md5_append(&ctx,(const unsigned char *)pw,(unsigned int)mir_strlen(pw));
+ mir_md5_finish(&ctx, digest);
+
+ char hexdigest[40];
+ mir_snprintf(query, "APOP %s %s\r\n", name, bin2hex(digest, sizeof(digest), 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];
+
+ mir_snprintf(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)
+ {
+ mir_snprintf(query, "UIDL %d\r\n", nr);
+ NetClient->Send(query);
+ return RecvRest(NetClient->Recv(),POP3_SEARCHACK);
+ }
+ mir_snprintf(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];
+
+ mir_snprintf(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];
+
+ mir_snprintf(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/src/proto/pop3/pop3.h b/protocols/YAMN/src/proto/pop3/pop3.h
new file mode 100644
index 0000000000..1fd7994bed
--- /dev/null
+++ b/protocols/YAMN/src/proto/pop3/pop3.h
@@ -0,0 +1,63 @@
+#ifndef __POP3_H
+#define __POP3_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 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(nullptr), Stopped(FALSE) {}
+ ~CPop3Client() {if (NetClient != nullptr) 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/src/proto/pop3/pop3comm.cpp b/protocols/YAMN/src/proto/pop3/pop3comm.cpp
new file mode 100644
index 0000000000..dad9ee1e28
--- /dev/null
+++ b/protocols/YAMN/src/proto/pop3/pop3comm.cpp
@@ -0,0 +1,1558 @@
+/*
+ * 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
+ */
+
+
+#include "../../stdafx.h"
+
+#define ERRORSTR_MAXLEN 1024 //in wide-chars
+
+//--------------------------------------------------------------------------------------------------
+
+HANDLE hNetLib = nullptr;
+PSCOUNTER CPOP3Account::AccountWriterSO = nullptr;
+
+//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
+void __cdecl DeleteMailsPOP3(void *param);
+
+//Function makes readable message about error. It sends it back to YAMN, so YAMN then
+//can show it to the message window
+wchar_t* 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 *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 = nullptr;
+MailExportedFcns *pYAMNMailFcn = nullptr;
+
+YAMN_PROTOIMPORTFCN POP3ProtocolFunctions =
+{
+ CreatePOP3Account,
+ DeletePOP3Account,
+ StopPOP3Account,
+ WritePOP3Options,
+ ReadPOP3Options,
+ SynchroPOP3,
+ SynchroPOP3,
+ SynchroPOP3,
+ DeleteMailsPOP3,
+ GetErrorString,
+ nullptr,
+ DeleteErrorString,
+ WritePOP3Accounts,
+ nullptr,
+ UnLoadPOP3,
+};
+
+YAMN_MAILIMPORTFCN POP3MailFunctions =
+{
+ CreatePOP3Mail,
+ nullptr,
+ nullptr,
+ nullptr,
+};
+
+PYAMN_VARIABLES pYAMNVar = nullptr;
+HYAMNPROTOPLUGIN POP3Plugin = nullptr;
+
+YAMN_PROTOREGISTRATION POP3ProtocolRegistration =
+{
+ "POP3 protocol (internal)",
+ __VERSION_STRING_DOTS,
+ __COPYRIGHT,
+ __DESCRIPTION,
+ __AUTHORWEB,
+};
+
+static wchar_t *FileName = nullptr;
+
+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(nullptr, FALSE, TRUE, nullptr);
+ InternetQueries = new SCOUNTER;
+ AbilityFlags = YAMN_ACC_BROWSE | YAMN_ACC_POPUP;
+
+ SetAccountStatus((HACCOUNT)this, TranslateT("Disconnected"));
+}
+
+CPOP3Account::~CPOP3Account()
+{
+ CloseHandle(UseInternetFree);
+ if (InternetQueries != nullptr)
+ delete InternetQueries;
+}
+
+HACCOUNT WINAPI CreatePOP3Account(HYAMNPROTOPLUGIN, DWORD)
+{
+ //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 != nullptr) //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 (nullptr == (pYAMNVar = (PYAMN_VARIABLES)CallService(MS_YAMN_GETVARIABLES, (WPARAM)YAMN_VARIABLESVERSION, 0)))
+ return 0;
+
+ //We have to get pointers to YAMN exported functions: allocate structure and fill it
+ if (nullptr == (pYAMNFcn = new struct YAMNExportedFcns))
+ {
+ UnLoadPOP3(nullptr); return 0;
+ }
+
+ //Register new pop3 user in netlib
+ if (nullptr == (hNetLib = RegisterNLClient("YAMN-POP3")))
+ {
+ UnLoadPOP3(nullptr); return 0;
+ }
+
+ pYAMNFcn->SetProtocolPluginFcnImportFcn = (YAMN_SETPROTOCOLPLUGINFCNIMPORTFCN)CallService(MS_YAMN_GETFCNPTR, (WPARAM)YAMN_SETPROTOCOLPLUGINFCNIMPORTID, 0);
+ pYAMNFcn->WaitToWriteFcn = (YAMN_WAITTOWRITEFCN)CallService(MS_YAMN_GETFCNPTR, (WPARAM)YAMN_WAITTOWRITEID, 0);
+ pYAMNFcn->WriteDoneFcn = (YAMN_WRITEDONEFCN)CallService(MS_YAMN_GETFCNPTR, (WPARAM)YAMN_WRITEDONEID, 0);
+ pYAMNFcn->WaitToReadFcn = (YAMN_WAITTOREADFCN)CallService(MS_YAMN_GETFCNPTR, (WPARAM)YAMN_WAITTOREADID, 0);
+ pYAMNFcn->ReadDoneFcn = (YAMN_READDONEFCN)CallService(MS_YAMN_GETFCNPTR, (WPARAM)YAMN_READDONEID, 0);
+ pYAMNFcn->SCGetNumberFcn = (YAMN_SCMANAGEFCN)CallService(MS_YAMN_GETFCNPTR, (WPARAM)YAMN_SCGETNUMBERID, 0);
+ pYAMNFcn->SCIncFcn = (YAMN_SCMANAGEFCN)CallService(MS_YAMN_GETFCNPTR, (WPARAM)YAMN_SCINCID, 0);
+ pYAMNFcn->SCDecFcn = (YAMN_SCMANAGEFCN)CallService(MS_YAMN_GETFCNPTR, (WPARAM)YAMN_SCDECID, 0);
+ pYAMNFcn->SetStatusFcn = (YAMN_SETSTATUSFCN)CallService(MS_YAMN_GETFCNPTR, (WPARAM)YAMN_SETSTATUSID, 0);
+ pYAMNFcn->GetStatusFcn = (YAMN_GETSTATUSFCN)CallService(MS_YAMN_GETFCNPTR, (WPARAM)YAMN_GETSTATUSID, 0);
+
+ if (nullptr == (pYAMNMailFcn = new struct MailExportedFcns))
+ {
+ UnLoadPOP3(nullptr); return 0;
+ }
+
+ pYAMNMailFcn->SynchroMessagesFcn = (YAMN_SYNCHROMIMEMSGSFCN)CallService(MS_YAMN_GETFCNPTR, (WPARAM)YAMN_SYNCHROMIMEMSGSID, 0);
+ pYAMNMailFcn->TranslateHeaderFcn = (YAMN_TRANSLATEHEADERFCN)CallService(MS_YAMN_GETFCNPTR, (WPARAM)YAMN_TRANSLATEHEADERID, 0);
+ pYAMNMailFcn->AppendQueueFcn = (YAMN_APPENDQUEUEFCN)CallService(MS_YAMN_GETFCNPTR, (WPARAM)YAMN_APPENDQUEUEID, 0);
+ pYAMNMailFcn->DeleteMessagesToEndFcn = (YAMN_DELETEMIMEQUEUEFCN)CallService(MS_YAMN_GETFCNPTR, (WPARAM)YAMN_DELETEMIMEQUEUEID, 0);
+ pYAMNMailFcn->DeleteMessageFromQueueFcn = (YAMN_DELETEMIMEMESSAGEFCN)CallService(MS_YAMN_GETFCNPTR, (WPARAM)YAMN_DELETEMIMEMESSAGEID, 0);
+ pYAMNMailFcn->FindMessageByIDFcn = (YAMN_FINDMIMEMESSAGEFCN)CallService(MS_YAMN_GETFCNPTR, (WPARAM)YAMN_FINDMIMEMESSAGEID, 0);
+ pYAMNMailFcn->CreateNewDeleteQueueFcn = (YAMN_CREATENEWDELETEQUEUEFCN)CallService(MS_YAMN_GETFCNPTR, (WPARAM)YAMN_CREATENEWDELETEQUEUEID, 0);
+
+ //set static variable
+ if (CPOP3Account::AccountWriterSO == nullptr) {
+ if (nullptr == (CPOP3Account::AccountWriterSO = new SCOUNTER))
+ {
+ UnLoadPOP3(nullptr); 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(__DESCRIPTION);
+ if (nullptr == (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 = (wchar_t *)CallService(MS_YAMN_GETFILENAME, (WPARAM)L"pop3", 0);
+
+ switch (CallService(MS_YAMN_READACCOUNTS, (WPARAM)POP3Plugin, (LPARAM)FileName)) {
+ case EACC_FILEVERSION:
+ MessageBox(nullptr, 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, 0);
+ FileName = nullptr;
+ return 0;
+ case EACC_FILECOMPATIBILITY:
+ MessageBox(nullptr, TranslateT("Error reading account file. Account file corrupted."), TranslateT("YAMN (internal POP3) read error"), MB_OK);
+ CallService(MS_YAMN_DELETEFILENAME, (WPARAM)FileName, 0);
+ FileName = nullptr;
+ return 0;
+ case EACC_ALLOC:
+ MessageBox(nullptr, TranslateT("Memory allocation error while data reading"), TranslateT("YAMN (internal POP3) read error"), MB_OK);
+ CallService(MS_YAMN_DELETEFILENAME, (WPARAM)FileName, 0);
+ FileName = nullptr;
+ return 0;
+ case EACC_SYSTEM:
+ if (ERROR_FILE_NOT_FOUND != GetLastError())
+ {
+ wchar_t temp[1024] = { 0 };
+ mir_snwprintf(temp, L"%s\n%s", TranslateT("Reading file error. File already in use?"), FileName);
+ MessageBox(nullptr, temp, TranslateT("YAMN (internal POP3) read error"), MB_OK);
+ CallService(MS_YAMN_DELETEFILENAME, (WPARAM)FileName, 0);
+ FileName = nullptr;
+ return 0;
+ }
+ break;
+ }
+
+ HACCOUNT Finder;
+ DBVARIANT dbv;
+
+ for (Finder = POP3Plugin->FirstAccount; Finder != nullptr; Finder = Finder->Next) {
+ Finder->hContact = NULL;
+ for (auto &hContact : Contacts(YAMN_DBMODULE)) {
+ if (!g_plugin.getString(hContact, "Id", &dbv)) {
+ if (mir_strcmp(dbv.pszVal, Finder->Name) == 0) {
+ Finder->hContact = hContact;
+ g_plugin.setWord(Finder->hContact, "Status", ID_STATUS_ONLINE);
+ db_set_s(Finder->hContact, "CList", "StatusMsg", Translate("No new mail message"));
+ if ((Finder->Flags & YAMN_ACC_ENA) && (Finder->NewMailN.Flags & YAMN_ACC_CONT))
+ db_unset(Finder->hContact, "CList", "Hidden");
+
+ if (!(Finder->Flags & YAMN_ACC_ENA) || !(Finder->NewMailN.Flags & YAMN_ACC_CONT))
+ db_set_b(Finder->hContact, "CList", "Hidden", 1);
+ }
+ db_free(&dbv);
+ }
+ }
+
+ if (!Finder->hContact && (Finder->Flags & YAMN_ACC_ENA) && (Finder->NewMailN.Flags & YAMN_ACC_CONT)) {
+ // No account contact found, have to create one
+ Finder->hContact = db_add_contact();
+ Proto_AddToContact(Finder->hContact, YAMN_DBMODULE);
+ g_plugin.setString(Finder->hContact, "Id", Finder->Name);
+ g_plugin.setString(Finder->hContact, "Nick", Finder->Name);
+ g_plugin.setWord(Finder->hContact, "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 = nullptr;
+ }
+ if (CPOP3Account::AccountWriterSO) {
+ delete CPOP3Account::AccountWriterSO; CPOP3Account::AccountWriterSO = nullptr;
+ }
+ if (pYAMNMailFcn) {
+ delete pYAMNMailFcn; pYAMNMailFcn = nullptr;
+ }
+ if (pYAMNFcn) {
+ delete pYAMNFcn; pYAMNFcn = nullptr;
+ }
+ if (FileName) {
+ CallService(MS_YAMN_DELETEFILENAME, (WPARAM)FileName, 0); FileName = nullptr;
+ }
+
+#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) {
+ wchar_t temp[1024] = { 0 };
+ mir_snwprintf(temp, L"%s\n%s", TranslateT("Error while copying data to disk occurred. Is file in use?"), FileName);
+ MessageBox(nullptr, 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, nullptr)) ||
+ (!WriteFile(File, (char *)&((HPOP3ACCOUNT)Which)->CP, sizeof(WORD), &WrittenBytes, nullptr)))
+ return EACC_SYSTEM;
+ return 0;
+}
+
+DWORD WINAPI ReadPOP3Options(HACCOUNT Which, char **Parser, char *End)
+{
+ DWORD Ver;
+#ifdef DEBUG_FILEREAD
+ wchar_t 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
+ mir_snwprintf(Debug, L"CodePage: %d, remaining %d chars", ((HPOP3ACCOUNT)Which)->CP, End-*Parser);
+ MessageBox(NULL,Debug,L"debug",MB_OK);
+#endif
+ return 0;
+}
+
+HYAMNMAIL WINAPI CreatePOP3Mail(HACCOUNT Account, DWORD)
+{
+ 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 (nullptr == (NewMail = new YAMNMAIL))
+ return nullptr;
+
+ if (nullptr == (NewMail->MailData = new MAILDATA))
+ {
+ delete NewMail;
+ return nullptr;
+ }
+ 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))
+ g_plugin.setWord(account->hContact, "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 (nullptr != (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 != nullptr)
+ 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 == nullptr)
+ {
+ 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 == nullptr)
+ return;
+
+ if ((ActualAccount->BadConnectN.Flags & YAMN_ACC_MSG) || (ActualAccount->BadConnectN.Flags & YAMN_ACC_ICO) || (ActualAccount->BadConnectN.Flags & YAMN_ACC_POP))
+ {
+ YAMN_BADCONNECTIONPARAM cp = { (HANDLE)nullptr, 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 = nullptr, MsgQueuePtr = nullptr;
+ char* DataRX = nullptr, *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 == nullptr) || !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 = nullptr;
+
+ if (DataRX != nullptr)
+ {
+ 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 = nullptr;
+ }
+
+ SetAccountStatus(ActualAccount, TranslateT("Entering POP3 account"));
+
+ if (ActualCopied.Flags & YAMN_ACC_APOP)
+ {
+ DataRX = MyClient->APOP(ActualCopied.ServerLogin, ActualCopied.ServerPasswd, timestamp);
+ if (DataRX != nullptr)
+ free(DataRX);
+ DataRX = nullptr;
+ delete[] timestamp;
+ }
+ else {
+ DataRX = MyClient->User(ActualCopied.ServerLogin);
+ if (DataRX != nullptr)
+ free(DataRX);
+ DataRX = nullptr;
+ DataRX = MyClient->Pass(ActualCopied.ServerPasswd);
+ if (DataRX != nullptr)
+ free(DataRX);
+ DataRX = nullptr;
+ }
+ }
+ 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, &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 != nullptr)
+ free(DataRX);
+ DataRX = nullptr;
+ 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 == nullptr)
+ {
+ 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 != nullptr)
+ free(DataRX);
+ DataRX = nullptr;
+
+#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 != nullptr)
+ free(DataRX);
+ DataRX = nullptr;
+ }
+#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 != nullptr; MsgQueuePtr = MsgQueuePtr->Next) {
+ if (MsgQueuePtr->Flags&YAMN_MSG_BODYREQUESTED) {
+ HYAMNMAIL NewMsgsPtr = nullptr;
+ for (NewMsgsPtr = (HYAMNMAIL)NewMails; NewMsgsPtr != nullptr; NewMsgsPtr = NewMsgsPtr->Next) {
+ if (!mir_strcmp(MsgQueuePtr->ID, NewMsgsPtr->ID)) {
+ wchar_t accstatus[512];
+ mir_snwprintf(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 != nullptr)
+ {
+ 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 != nullptr;)
+ {
+ TH = TH->Next;
+ if (MsgQueuePtr->MailData->TranslatedHeader->name != nullptr)
+ delete[] MsgQueuePtr->MailData->TranslatedHeader->name;
+ if (MsgQueuePtr->MailData->TranslatedHeader->value != nullptr)
+ 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 != nullptr)
+ free(DataRX);
+ DataRX = nullptr;
+ break;
+ }
+ }
+ }
+ }
+
+ SynchroMessages(ActualAccount, (HYAMNMAIL *)&ActualAccount->Mails, nullptr, (HYAMNMAIL *)&NewMails, nullptr); //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 != nullptr; 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 != nullptr; MsgQueuePtr = MsgQueuePtr->Next, msgs++); //get number of new mails
+
+ try
+ {
+ wchar_t accstatus[512];
+
+ for (i = 0, MsgQueuePtr = NewMails; MsgQueuePtr != nullptr; i++)
+ {
+ BOOL autoretr = (ActualAccount->Flags & YAMN_ACC_BODY) != 0;
+ DataRX = MyClient->Top(MsgQueuePtr->Number, autoretr ? 100 : 0);
+ mir_snwprintf(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 != nullptr)
+ {
+ 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 != nullptr)
+ free(DataRX);
+ DataRX = nullptr;
+
+ //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 == nullptr)
+ 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 != nullptr)
+ free(DataRX);
+ DataRX = nullptr;
+ 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)nullptr, 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 != nullptr)
+ free(DataRX);
+ DataRX = nullptr;
+ 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;
+}
+
+void __cdecl DeleteMailsPOP3(void *param)
+{
+ DeleteParam *WhichTemp = (DeleteParam *)param;
+
+ CPop3Client *MyClient;
+ HYAMNMAIL DeleteMails, NewMails = nullptr, MsgQueuePtr = nullptr;
+ char* DataRX = nullptr;
+ int mboxsize = 0, msgs = 0, 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".
+ // }
+
+ HPOP3ACCOUNT ActualAccount = (HPOP3ACCOUNT)WhichTemp->AccountParam; //copy address of structure from calling thread to stack of this thread
+ LPVOID YAMNParam = WhichTemp->BrowserParam;
+ UINT_PTR 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;
+ }
+#ifdef DEBUG_SYNCHRO
+ DebugLog(SynchroFile,"DeleteMailsPOP3:ActualAccountSO-read enter\n");
+#endif
+ if (nullptr == (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)nullptr, 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;
+ }
+ 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 == nullptr) || !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 = nullptr;
+ if (DataRX != nullptr) {
+ 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 = nullptr;
+ }
+ SetAccountStatus(ActualAccount, TranslateT("Entering POP3 account"));
+
+ if (ActualAccount->Flags & YAMN_ACC_APOP)
+ {
+ DataRX = MyClient->APOP(ActualCopied.ServerLogin, ActualCopied.ServerPasswd, timestamp);
+ if (DataRX != nullptr)
+ free(DataRX);
+ DataRX = nullptr;
+ delete[] timestamp;
+ }
+ else {
+ DataRX = MyClient->User(ActualCopied.ServerLogin);
+ if (DataRX != nullptr)
+ free(DataRX);
+ DataRX = nullptr;
+ DataRX = MyClient->Pass(ActualCopied.ServerPasswd);
+ if (DataRX != nullptr)
+ free(DataRX);
+ DataRX = nullptr;
+ }
+ }
+
+#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, &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 != nullptr)
+ free(DataRX);
+ DataRX = nullptr;
+ 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 == nullptr)
+ {
+ 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 != nullptr)
+ free(DataRX);
+ DataRX = nullptr;
+ // 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, nullptr, (HYAMNMAIL *)&NewMails, nullptr);
+ }
+ }
+ 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 != nullptr; 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 != nullptr)
+ free(DataRX);
+ DataRX = nullptr;
+ }
+ 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 != nullptr)
+ // 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, nullptr, (HYAMNMAIL *)&NewMails, nullptr);
+ // 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 = nullptr;
+ }
+ }
+ else
+ {
+ DeleteMIMEQueue(ActualAccount, (HYAMNMAIL)ActualAccount->Mails);
+ ActualAccount->Mails = nullptr;
+ }
+#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)nullptr, 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 != nullptr)
+ free(DataRX);
+ DataRX = nullptr;
+ 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 != nullptr)
+ 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;
+}
+
+void ExtractStat(char *stream, 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 != nullptr) && (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++;
+ }
+}
+
+wchar_t* WINAPI GetErrorString(DWORD Code)
+{
+ static wchar_t *POP3Errors[] =
+ {
+ LPGENW("Memory allocation error."), //memory allocation
+ LPGENW("Account is about to be stopped."), //stop account
+ LPGENW("Cannot connect to POP3 server."),
+ LPGENW("Cannot allocate memory for received data."),
+ LPGENW("Cannot login to POP3 server."),
+ LPGENW("Bad user or password."),
+ LPGENW("Server does not support APOP authorization."),
+ LPGENW("Error while executing POP3 command."),
+ LPGENW("Error while executing POP3 command."),
+ LPGENW("Error while executing POP3 command."),
+ };
+
+ static wchar_t *NetlibErrors[] =
+ {
+ LPGENW("Cannot connect to server with NetLib."),
+ LPGENW("Cannot send data."),
+ LPGENW("Cannot receive data."),
+ LPGENW("Cannot allocate memory for received data."),
+ };
+
+ static wchar_t *SSLErrors[] =
+ {
+ LPGENW("OpenSSL not loaded."),
+ LPGENW("Windows socket 2.0 init failed."),
+ LPGENW("DNS lookup error."),
+ LPGENW("Error while creating base socket."),
+ LPGENW("Error connecting to server with socket."),
+ LPGENW("Error while creating SSL structure."),
+ LPGENW("Error connecting socket with SSL."),
+ LPGENW("Server rejected connection with SSL."),
+ LPGENW("Cannot write SSL data."),
+ LPGENW("Cannot read SSL data."),
+ LPGENW("Cannot allocate memory for received data."),
+ };
+
+ wchar_t *ErrorString = new wchar_t[ERRORSTR_MAXLEN];
+ POP3_ERRORCODE *ErrorCode = (POP3_ERRORCODE *)(UINT_PTR)Code;
+
+ mir_snwprintf(ErrorString, ERRORSTR_MAXLEN, TranslateT("Error %d-%d-%d-%d:"), ErrorCode->AppError, ErrorCode->POP3Error, ErrorCode->NetError, ErrorCode->SystemError);
+ if (ErrorCode->POP3Error)
+ mir_snwprintf(ErrorString, ERRORSTR_MAXLEN, L"%s\n%s", ErrorString, TranslateW(POP3Errors[ErrorCode->POP3Error - 1]));
+ if (ErrorCode->NetError) {
+ if (ErrorCode->SSL)
+ mir_snwprintf(ErrorString, ERRORSTR_MAXLEN, L"%s\n%s", ErrorString, TranslateW(SSLErrors[ErrorCode->NetError - 1]));
+ else
+ mir_snwprintf(ErrorString, ERRORSTR_MAXLEN, L"%s\n%s", ErrorString, TranslateW(NetlibErrors[ErrorCode->NetError - 4]));
+ }
+
+ return ErrorString;
+}
+
+void WINAPI DeleteErrorString(LPVOID String)
+{
+ delete (char *)String;
+}
diff --git a/protocols/YAMN/src/proto/pop3/pop3comm.h b/protocols/YAMN/src/proto/pop3/pop3comm.h
new file mode 100644
index 0000000000..3d98675d3c
--- /dev/null
+++ b/protocols/YAMN/src/proto/pop3/pop3comm.h
@@ -0,0 +1,83 @@
+#ifndef __POP3COMM_H
+#define __POP3COMM_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/src/proto/pop3/pop3opt.cpp b/protocols/YAMN/src/proto/pop3/pop3opt.cpp
new file mode 100644
index 0000000000..b22b237e47
--- /dev/null
+++ b/protocols/YAMN/src/proto/pop3/pop3opt.cpp
@@ -0,0 +1,1481 @@
+/*
+ * This code implements POP3 options window handling
+ *
+ * (c) majvan 2002-2003
+*/
+
+#include "../../stdafx.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, g_plugin.getByte(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, g_plugin.getByte(YAMN_SHOWMAINMENU, 1) ? BST_CHECKED : BST_UNCHECKED);
+ CheckDlgButton(hDlg, IDC_YAMNASPROTO, g_plugin.getByte(YAMN_SHOWASPROTO, 1) ? BST_CHECKED : BST_UNCHECKED);
+ CheckDlgButton(hDlg, IDC_CLOSEONDELETE, g_plugin.getByte(YAMN_CLOSEDELETE, 0) ? BST_CHECKED : BST_UNCHECKED);
+ 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:
+ g_plugin.setByte(YAMN_SHOWASPROTO, IsDlgButtonChecked(hDlg, IDC_YAMNASPROTO));
+ g_plugin.setByte(YAMN_SHOWMAINMENU, IsDlgButtonChecked(hDlg, IDC_MAINMENU));
+ g_plugin.setByte(YAMN_CLOSEDELETE, IsDlgButtonChecked(hDlg, IDC_CLOSEONDELETE));
+ g_plugin.setByte(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;
+ g_plugin.setByte(YAMN_DBTIMEOPTIONS, optDateTime);
+ }
+ }
+ break;
+ }
+
+ return FALSE;
+}
+
+INT_PTR CALLBACK DlgProcPluginOpt(HWND hDlg, UINT msg, WPARAM wParam, 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, 0);
+
+ mir_cslock lck(PluginRegCS);
+ for (PParser = FirstProtoPlugin; PParser != nullptr; 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 == nullptr ? "" : PParser->Plugin->PluginInfo->Description);
+ SetDlgItemTextA(hDlg, IDC_STCOPY, PParser->Plugin->PluginInfo->Copyright == nullptr ? "" : PParser->Plugin->PluginInfo->Copyright);
+ SetDlgItemTextA(hDlg, IDC_STWWW, PParser->Plugin->PluginInfo->WWW == nullptr ? "" : PParser->Plugin->PluginInfo->WWW);
+ break;
+ }
+ for (FParser = FirstFilterPlugin; FParser != nullptr; 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 == nullptr ? "" : FParser->Plugin->PluginInfo->Description);
+ SetDlgItemTextA(hDlg, IDC_STCOPY, FParser->Plugin->PluginInfo->Copyright == nullptr ? "" : FParser->Plugin->PluginInfo->Copyright);
+ SetDlgItemTextA(hDlg, IDC_STWWW, FParser->Plugin->PluginInfo->WWW == nullptr ? "" : FParser->Plugin->PluginInfo->WWW);
+ break;
+ }
+ }
+ break;
+ case IDC_STWWW:
+ {
+ char str[1024];
+ GetDlgItemTextA(hDlg, IDC_STWWW, str, _countof(str));
+ Utils_OpenUrl(str);
+ break;
+ }
+
+ }
+ break;
+ }
+ case WM_SHOWWINDOW:
+ if (TRUE == (BOOL)wParam) {
+ {
+ mir_cslock lck(PluginRegCS);
+ for (PYAMN_PROTOPLUGINQUEUE PParser = FirstProtoPlugin; PParser != nullptr; PParser = PParser->Next) {
+ int index = SendDlgItemMessageA(hDlg, IDC_COMBOPLUGINS, CB_ADDSTRING, 0, (LPARAM)PParser->Plugin->PluginInfo->Name);
+ SendDlgItemMessage(hDlg, IDC_COMBOPLUGINS, CB_SETITEMDATA, (WPARAM)index, (LPARAM)PParser->Plugin);
+ }
+ for (PYAMN_FILTERPLUGINQUEUE FParser = FirstFilterPlugin; FParser != nullptr; FParser = FParser->Next) {
+ int index = SendDlgItemMessageA(hDlg, IDC_COMBOPLUGINS, CB_ADDSTRING, 0, (LPARAM)FParser->Plugin->PluginInfo->Name);
+ SendDlgItemMessage(hDlg, IDC_COMBOPLUGINS, CB_SETITEMDATA, (WPARAM)index, (LPARAM)FParser->Plugin);
+ }
+ }
+
+ SendDlgItemMessage(hDlg, IDC_COMBOPLUGINS, CB_SETCURSEL, 0, 0);
+ SendMessage(hDlg, WM_COMMAND, MAKELONG(IDC_COMBOPLUGINS, CBN_SELCHANGE), 0);
+ break;
+ }
+ else { //delete all items in combobox
+ int cbn = SendDlgItemMessage(hDlg, IDC_COMBOPLUGINS, CB_GETCOUNT, 0, 0);
+ for (int i = 0; i < cbn; i++)
+ SendDlgItemMessage(hDlg, IDC_COMBOPLUGINS, CB_DELETESTRING, 0, 0);
+ break;
+ }
+ }
+
+ return FALSE;
+}
+
+
+int YAMNOptInitSvc(WPARAM wParam, LPARAM)
+{
+ OPTIONSDIALOGPAGE odp = {};
+ odp.szGroup.a = LPGEN("Network");
+ odp.szTitle.a = LPGEN("YAMN");
+ odp.flags = ODPF_BOLDGROUPS;
+
+ odp.szTab.a = LPGEN("Accounts");
+ odp.pszTemplate = MAKEINTRESOURCEA(IDD_POP3ACCOUNTOPT);
+ odp.pfnDlgProc = DlgProcPOP3AccOpt;
+ g_plugin.addOptions(wParam, &odp);
+
+ odp.szTab.a = LPGEN("General");
+ odp.pszTemplate = MAKEINTRESOURCEA(IDD_YAMNOPT);
+ odp.pfnDlgProc = DlgProcYAMNOpt;
+ g_plugin.addOptions(wParam, &odp);
+
+ odp.szTab.a = LPGEN("Plugins");
+ odp.pszTemplate = MAKEINTRESOURCEA(IDD_PLUGINOPT);
+ odp.pfnDlgProc = DlgProcPluginOpt;
+ g_plugin.addOptions(wParam, &odp);
+
+ if (ServiceExists(MS_POPUP_ADDPOPUPW)) {
+ odp.szGroup.a = LPGEN("Popups");
+ odp.szTab.a = LPGEN("YAMN");
+ odp.pszTemplate = MAKEINTRESOURCEA(IDD_POP3ACCOUNTPOPUP);
+ odp.pfnDlgProc = DlgProcPOP3AccPopup;
+ g_plugin.addOptions(wParam, &odp);
+ }
+ return 0;
+}
+
+//--------------------------------------------------------------------------------------------------
+//--------------------------------------------------------------------------------------------------
+BOOL DlgEnableAccountStatus(HWND hDlg, WPARAM wParam, 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)
+{
+ 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)
+{
+ 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) {
+ wchar_t 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)) {
+ SendDlgItemMessage(hDlg, IDC_COMBOCP, CB_SETCURSEL, (WPARAM)i, 0);
+ break;
+ }
+ if (i == CPLENSUPP)
+ SendDlgItemMessage(hDlg, IDC_COMBOCP, CB_SETCURSEL, (WPARAM)CPDEFINDEX, 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, nullptr);
+ DlgSetItemText(hDlg, (WPARAM)IDC_EDITNAME, nullptr);
+ DlgSetItemText(hDlg, (WPARAM)IDC_EDITLOGIN, nullptr);
+ DlgSetItemText(hDlg, (WPARAM)IDC_EDITPASS, nullptr);
+ DlgSetItemText(hDlg, (WPARAM)IDC_EDITAPP, nullptr);
+ DlgSetItemText(hDlg, (WPARAM)IDC_EDITAPPPARAM, nullptr);
+ DlgSetItemText(hDlg, (WPARAM)IDC_STTIMELEFT, nullptr);
+ 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);
+ SendDlgItemMessage(hDlg, IDC_COMBOCP, CB_SETCURSEL, (WPARAM)CPDEFINDEX, 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, 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 == nullptr)
+ SetDlgItemTextA(hDlg, wParam, "");
+ else
+ SetDlgItemTextA(hDlg, wParam, str);
+ return TRUE;
+}
+
+BOOL DlgSetItemTextW(HWND hDlg, WPARAM wParam, const WCHAR* str)
+{
+ if (str == nullptr)
+ SetDlgItemTextW(hDlg, wParam, L"");
+ else
+ SetDlgItemTextW(hDlg, wParam, str);
+ return TRUE;
+}
+
+INT_PTR CALLBACK DlgProcPOP3AccStatusOpt(HWND hDlg, UINT msg, WPARAM wParam, LPARAM)
+{
+ static HPOP3ACCOUNT ActualAccount;
+ switch (msg) {
+ case WM_INITDIALOG:
+ ActualAccount = (HPOP3ACCOUNT)CallService(MS_YAMN_FINDACCOUNTBYNAME, (WPARAM)POP3Plugin, (LPARAM)DlgInput);
+ if (ActualAccount != nullptr) {
+ DlgShowAccountStatus(hDlg, (WPARAM)M_SHOWACTUAL, (LPARAM)ActualAccount);
+ DlgEnableAccountStatus(hDlg, TRUE, 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;
+
+ case WM_COMMAND:
+ 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, 0, 0);
+ EndDialog(hDlg, 0);
+ DestroyWindow(hDlg);
+ break;
+
+ case IDCANCEL:
+ EndDialog(hDlg, 0);
+ DestroyWindow(hDlg);
+ 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, FALSE, 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 != nullptr; ActualAccount = (HPOP3ACCOUNT)ActualAccount->Next)
+ if (ActualAccount->Name != nullptr)
+ 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 = mir_wstrlen(info.CodePageName + 7);
+ info.CodePageName[len + 6] = 0;
+ SendDlgItemMessage(hDlg, IDC_COMBOCP, CB_ADDSTRING, 0, (LPARAM)(info.CodePageName + 7));
+ }
+
+ SendDlgItemMessage(hDlg, IDC_COMBOCP, CB_SETCURSEL, (WPARAM)CPDEFINDEX, 0);
+ ActualAccount = nullptr;
+ 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, 0);
+ }
+ else WindowList_Add(pYAMNVar->MessageWnds, hDlg);
+ return TRUE;
+
+ case WM_YAMN_CHANGESTATUS:
+ if ((HPOP3ACCOUNT)wParam == ActualAccount) {
+ wchar_t 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) {
+ wchar_t Text[256];
+ mir_snwprintf(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 = nullptr;
+ DlgSetItemText(hDlg, (WPARAM)IDC_STTIMELEFT, nullptr);
+
+ if (GetDlgItemTextA(hDlg, IDC_COMBOACCOUNT, DlgInput, _countof(DlgInput)))
+ DlgEnableAccount(hDlg, TRUE, FALSE);
+ else
+ DlgEnableAccount(hDlg, FALSE, FALSE);
+ break;
+
+ case CBN_KILLFOCUS:
+ GetDlgItemTextA(hDlg, IDC_COMBOACCOUNT, DlgInput, _countof(DlgInput));
+ if (nullptr == (ActualAccount = (HPOP3ACCOUNT)CallService(MS_YAMN_FINDACCOUNTBYNAME, (WPARAM)POP3Plugin, (LPARAM)DlgInput))) {
+ DlgSetItemText(hDlg, (WPARAM)IDC_STTIMELEFT, nullptr);
+ EnableWindow(GetDlgItem(hDlg, IDC_BTNDEL), FALSE);
+ if (mir_strlen(DlgInput))
+ DlgEnableAccount(hDlg, TRUE, TRUE);
+ else
+ DlgEnableAccount(hDlg, FALSE, FALSE);
+ }
+ else {
+ DlgShowAccount(hDlg, (WPARAM)M_SHOWACTUAL, (LPARAM)ActualAccount);
+ DlgEnableAccount(hDlg, TRUE, 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) || (nullptr == (ActualAccount = (HPOP3ACCOUNT)CallService(MS_YAMN_FINDACCOUNTBYNAME, (WPARAM)POP3Plugin, (LPARAM)DlgInput)))) {
+ DlgSetItemText(hDlg, (WPARAM)IDC_STTIMELEFT, nullptr);
+ EnableWindow(GetDlgItem(hDlg, IDC_BTNDEL), FALSE);
+ }
+ else {
+ DlgShowAccount(hDlg, (WPARAM)M_SHOWACTUAL, (LPARAM)ActualAccount);
+ DlgEnableAccount(hDlg, TRUE, 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(g_plugin.getInst(), MAKEINTRESOURCEW(IDD_CHOOSESTATUSMODES), hDlg, DlgProcPOP3AccStatusOpt, NULL);
+ break;
+
+ case IDC_BTNADD:
+ DlgSetItemText(hDlg, (WPARAM)IDC_STTIMELEFT, nullptr);
+ DlgShowAccount(hDlg, (WPARAM)M_SHOWDEFAULT, 0);
+ DlgEnableAccount(hDlg, TRUE, 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:
+ {
+ wchar_t filter[MAX_PATH];
+ mir_snwprintf(filter, L"%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 wchar_t[MAX_PATH];
+ OFNStruct.lpstrFile[0] = (wchar_t)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, TranslateT("Dialog box error"), TranslateT("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, _countof(DlgInput));
+ EnableWindow(GetDlgItem(hDlg, IDC_BTNDEL), FALSE);
+ if ((CB_ERR == (Result = SendDlgItemMessage(hDlg, IDC_COMBOACCOUNT, CB_GETCURSEL, 0, 0)))
+ || (nullptr == (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)
+ db_delete_contact(ActualAccount->hContact);
+
+ 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, nullptr);
+ DlgEnableAccount(hDlg, FALSE, 0);
+ DlgShowAccount(hDlg, (WPARAM)M_SHOWDEFAULT, 0);
+ break;
+
+ case IDC_BTNRESET:
+ if (ActualAccount != nullptr)
+ 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, _countof(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, _countof(Text));
+ if (CheckApp && !(Length = mir_strlen(Text))) {
+ MessageBox(hDlg, TranslateT("Please select application to run"), TranslateT("Input error"), MB_OK);
+ break;
+ }
+
+ GetDlgItemTextA(hDlg, IDC_COMBOACCOUNT, Text, _countof(Text));
+ if (!(Length = mir_strlen(Text))) {
+ GetDlgItemTextA(hDlg, IDC_EDITNAME, Text, _countof(Text));
+ if (!(Length = mir_strlen(Text)))
+ break;
+ }
+
+ DlgSetItemTextT(hDlg, IDC_STTIMELEFT, TranslateT("Please wait while no account is in use."));
+
+ if (nullptr == (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 (nullptr == (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, _countof(Text));
+ if (!(Length = mir_strlen(Text)))
+ break;
+ if (nullptr != ActualAccount->Name)
+ delete[] ActualAccount->Name;
+ ActualAccount->Name = new char[mir_strlen(Text) + 1];
+ mir_strcpy(ActualAccount->Name, Text);
+
+ GetDlgItemTextA(hDlg, IDC_EDITSERVER, Text, _countof(Text));
+ if (nullptr != ActualAccount->Server->Name)
+ delete[] ActualAccount->Server->Name;
+ ActualAccount->Server->Name = new char[mir_strlen(Text) + 1];
+ mir_strcpy(ActualAccount->Server->Name, Text);
+
+ GetDlgItemTextA(hDlg, IDC_EDITLOGIN, Text, _countof(Text));
+ if (nullptr != ActualAccount->Server->Login)
+ delete[] ActualAccount->Server->Login;
+ ActualAccount->Server->Login = new char[mir_strlen(Text) + 1];
+ mir_strcpy(ActualAccount->Server->Login, Text);
+
+ GetDlgItemTextA(hDlg, IDC_EDITPASS, Text, _countof(Text));
+ if (nullptr != ActualAccount->Server->Passwd)
+ delete[] ActualAccount->Server->Passwd;
+ ActualAccount->Server->Passwd = new char[mir_strlen(Text) + 1];
+ mir_strcpy(ActualAccount->Server->Passwd, Text);
+
+ GetDlgItemTextW(hDlg, IDC_EDITAPP, TextW, _countof(TextW));
+ if (nullptr != ActualAccount->NewMailN.App)
+ delete[] ActualAccount->NewMailN.App;
+ ActualAccount->NewMailN.App = new WCHAR[mir_wstrlen(TextW) + 1];
+ mir_wstrcpy(ActualAccount->NewMailN.App, TextW);
+
+ GetDlgItemTextW(hDlg, IDC_EDITAPPPARAM, TextW, _countof(TextW));
+ if (nullptr != ActualAccount->NewMailN.AppParam)
+ delete[] ActualAccount->NewMailN.AppParam;
+ ActualAccount->NewMailN.AppParam = new WCHAR[mir_wstrlen(TextW) + 1];
+ mir_wstrcpy(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, nullptr);
+
+ index = SendDlgItemMessage(hDlg, IDC_COMBOACCOUNT, CB_GETCURSEL, 0, 0);
+
+ HPOP3ACCOUNT temp = ActualAccount;
+
+ SendDlgItemMessage(hDlg, IDC_COMBOACCOUNT, CB_RESETCONTENT, 0, 0);
+ if (POP3Plugin->FirstAccount != nullptr)
+ for (ActualAccount = (HPOP3ACCOUNT)POP3Plugin->FirstAccount; ActualAccount != nullptr; ActualAccount = (HPOP3ACCOUNT)ActualAccount->Next)
+ if (ActualAccount->Name != nullptr)
+ 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, FALSE, 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 != nullptr)
+ for (ActualAccount = (HPOP3ACCOUNT)POP3Plugin->FirstAccount; ActualAccount != nullptr; ActualAccount = (HPOP3ACCOUNT)ActualAccount->Next)
+ if (ActualAccount->Name != nullptr)
+ 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 = nullptr;
+
+
+ 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, 0);
+ }
+ else {
+ WindowList_Add(pYAMNVar->MessageWnds, hDlg);
+
+ int index = SendDlgItemMessage(hDlg, IDC_COMBOACCOUNT, CB_GETCURSEL, 0, 0);
+ HPOP3ACCOUNT temp = ActualAccount;
+ SendDlgItemMessage(hDlg, IDC_COMBOACCOUNT, CB_RESETCONTENT, 0, 0);
+
+ if (POP3Plugin->FirstAccount != nullptr)
+ for (ActualAccount = (HPOP3ACCOUNT)POP3Plugin->FirstAccount; ActualAccount != nullptr; ActualAccount = (HPOP3ACCOUNT)ActualAccount->Next)
+ if (ActualAccount->Name != nullptr)
+ SendDlgItemMessageA(hDlg, IDC_COMBOACCOUNT, CB_ADDSTRING, 0, (LPARAM)ActualAccount->Name);
+
+ ActualAccount = temp;
+
+ if (ActualAccount != nullptr) {
+ 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, TRUE, FALSE);
+ }
+ else {
+ DlgShowAccountPopup(hDlg, (WPARAM)M_SHOWDEFAULT, 0);
+ DlgEnableAccountPopup(hDlg, FALSE, 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, _countof(DlgInput));
+ if (nullptr == (ActualAccount = (HPOP3ACCOUNT)CallService(MS_YAMN_FINDACCOUNTBYNAME, (WPARAM)POP3Plugin, (LPARAM)DlgInput))) {
+ DlgSetItemText(hDlg, (WPARAM)IDC_STTIMELEFT, nullptr);
+ if (mir_strlen(DlgInput))
+ DlgEnableAccountPopup(hDlg, TRUE, TRUE);
+ else
+ DlgEnableAccountPopup(hDlg, FALSE, FALSE);
+ }
+ else {
+ DlgShowAccount(hDlg, (WPARAM)M_SHOWACTUAL, (LPARAM)ActualAccount);
+ DlgShowAccountColors(hDlg, 0, (LPARAM)ActualAccount);
+ DlgEnableAccountPopup(hDlg, TRUE, 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) || (nullptr == (ActualAccount = (HPOP3ACCOUNT)CallService(MS_YAMN_FINDACCOUNTBYNAME, (WPARAM)POP3Plugin, (LPARAM)DlgInput)))) {
+ DlgSetItemText(hDlg, (WPARAM)IDC_STTIMELEFT, nullptr);
+ }
+ else {
+ DlgShowAccount(hDlg, (WPARAM)M_SHOWACTUAL, (LPARAM)ActualAccount);
+ DlgShowAccountColors(hDlg, 0, (LPARAM)ActualAccount);
+ DlgEnableAccountPopup(hDlg, TRUE, 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:
+ {
+ POPUPDATAW Tester;
+ POPUPDATAW TesterF;
+ POPUPDATAW 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);
+
+ memset(&Tester, 0, sizeof(Tester));
+ memset(&TesterF, 0, sizeof(TesterF));
+ memset(&TesterN, 0, sizeof(TesterN));
+ Tester.lchIcon = g_LoadIconEx(2);
+ TesterF.lchIcon = g_LoadIconEx(3);
+ TesterN.lchIcon = g_LoadIconEx(1);
+
+ mir_wstrncpy(Tester.lpwzContactName, TranslateT("Account Test"), MAX_CONTACTNAME);
+ mir_wstrncpy(TesterF.lpwzContactName, TranslateT("Account Test (failed)"), MAX_CONTACTNAME);
+ mir_wstrncpy(TesterN.lpwzContactName, TranslateT("Account Test"), MAX_CONTACTNAME);
+ mir_wstrncpy(Tester.lpwzText, TranslateT("You have N new mail messages"), MAX_SECONDLINE);
+ mir_wstrncpy(TesterF.lpwzText, TranslateT("Connection failed message"), MAX_SECONDLINE);
+ mir_wstrncpy(TesterN.lpwzText, TranslateT("No new mail message"), MAX_SECONDLINE);
+ 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 = nullptr;
+ TesterF.PluginWindowProc = nullptr;
+ TesterN.PluginWindowProc = nullptr;
+ Tester.PluginData = nullptr;
+ TesterF.PluginData = nullptr;
+ TesterN.PluginData = nullptr;
+
+ if (IsDlgButtonChecked(hDlg, IDC_CHECKPOP) == BST_CHECKED)
+ PUAddPopupW(&Tester);
+ if (IsDlgButtonChecked(hDlg, IDC_CHECKFPOP) == BST_CHECKED)
+ PUAddPopupW(&TesterF);
+ if (IsDlgButtonChecked(hDlg, IDC_CHECKNPOP) == BST_CHECKED)
+ PUAddPopupW(&TesterN);
+ 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:
+ {
+ wchar_t Text[MAX_PATH];
+ BOOL Translated, CheckPopup, CheckPopupW;
+ BOOL CheckNPopup, CheckNPopupW, CheckFPopup, CheckFPopupW;
+ BOOL CheckPopN;
+ UINT Time, TimeN, TimeF;
+
+ if (GetDlgItemText(hDlg, IDC_COMBOACCOUNT, Text, _countof(Text))) {
+ 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);
+
+ WritePOP3Accounts();
+ RefreshContact();
+ return TRUE;
+ }
+ }
+ break;
+ }
+ break;
+ }
+ break;
+ }
+ if (Changed)
+ SendMessage(GetParent(hDlg), PSM_CHANGED, 0, 0);
+ return FALSE;
+}
diff --git a/protocols/YAMN/src/proto/pop3/pop3opt.h b/protocols/YAMN/src/proto/pop3/pop3opt.h
new file mode 100644
index 0000000000..245f7679a4
--- /dev/null
+++ b/protocols/YAMN/src/proto/pop3/pop3opt.h
@@ -0,0 +1,40 @@
+#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
+INT_PTR 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*);
+
+
+#define DlgSetItemTextT DlgSetItemTextW
+
+
+#endif
diff --git a/protocols/YAMN/src/protoplugin.cpp b/protocols/YAMN/src/protoplugin.cpp
new file mode 100644
index 0000000000..4999b69401
--- /dev/null
+++ b/protocols/YAMN/src/protoplugin.cpp
@@ -0,0 +1,192 @@
+/*
+ * YAMN plugin export functions for protocols
+ *
+ * (c) majvan 2002-2004
+ */
+
+#include "stdafx.h"
+
+//--------------------------------------------------------------------------------------------------
+//--------------------------------------------------------------------------------------------------
+
+PYAMN_PROTOPLUGINQUEUE FirstProtoPlugin=nullptr;
+
+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==nullptr) || (Registration->Ver==nullptr))
+ return (INT_PTR)NULL;
+ if (nullptr==(Plugin=new YAMN_PROTOPLUGIN))
+ return (INT_PTR)NULL;
+
+ Plugin->PluginInfo=Registration;
+
+ Plugin->FirstAccount=nullptr;
+
+ Plugin->AccountBrowserSO=new SWMRG;
+ SWMRGInitialize(Plugin->AccountBrowserSO,nullptr);
+
+ Plugin->Fcn=nullptr;
+ Plugin->MailFcn=nullptr;
+
+#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==nullptr)
+ return 0;
+ if (YAMNMailFcn==nullptr)
+ return 0;
+
+#ifdef DEBUG_SYNCHRO
+ DebugLog(SynchroFile,"::: YAMN- protocol %0x import succeed :::\n",Plugin);
+#endif
+ Plugin->Fcn=YAMNFcn;
+ Plugin->MailFcn=YAMNMailFcn;
+
+ mir_cslock lck(PluginRegCS);
+ // We add protocol to the protocol list
+ for (Parser=FirstProtoPlugin;Parser != nullptr && Parser->Next != nullptr;Parser=Parser->Next);
+ if (Parser==nullptr)
+ {
+ FirstProtoPlugin=new YAMN_PROTOPLUGINQUEUE;
+ Parser=FirstProtoPlugin;
+ }
+ else
+ {
+ Parser->Next=new YAMN_PROTOPLUGINQUEUE;
+ Parser=Parser->Next;
+ }
+
+ Parser->Plugin=Plugin;
+ Parser->Next=nullptr;
+ 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 != nullptr) && (Plugin != Parser->Next->Plugin);Parser=Parser->Next);
+ if (Parser->Next != nullptr)
+ {
+ Found=Parser->Next;
+ Parser->Next=Parser->Next->Next;
+ }
+ else
+ Found=nullptr;
+ }
+ if (Found != nullptr)
+ {
+ StopAccounts(Plugin);
+ DeleteAccounts(Plugin);
+ if (Plugin->Fcn->UnLoadFcn != nullptr)
+ Plugin->Fcn->UnLoadFcn((void *)nullptr);
+
+ 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)
+{
+ HYAMNPROTOPLUGIN Plugin=(HYAMNPROTOPLUGIN)wParam;
+
+ mir_cslock lck(PluginRegCS);
+ UnregisterProtocolPlugin(Plugin);
+ return 1;
+}
+
+INT_PTR UnregisterProtoPlugins()
+{
+ mir_cslock lck(PluginRegCS);
+ // We remove protocols from the protocol list
+ while(FirstProtoPlugin != nullptr)
+ UnregisterProtocolPlugin(FirstProtoPlugin->Plugin);
+ return 1;
+}
+
+INT_PTR GetFileNameSvc(WPARAM wParam,LPARAM)
+{
+ wchar_t *FileName = new wchar_t[MAX_PATH];
+ if (FileName == nullptr)
+ return NULL;
+
+ mir_snwprintf(FileName, MAX_PATH, L"%s\\yamn-accounts.%s.%s.book", UserDirectory, wParam, ProfileName);
+ return (INT_PTR)FileName;
+}
+
+INT_PTR DeleteFileNameSvc(WPARAM wParam,LPARAM)
+{
+ if (( wchar_t* )wParam != nullptr)
+ delete[] ( wchar_t* ) wParam;
+
+ return 0;
+}
diff --git a/protocols/YAMN/src/resource.h b/protocols/YAMN/src/resource.h
new file mode 100644
index 0000000000..4c76c05bf9
--- /dev/null
+++ b/protocols/YAMN/src/resource.h
@@ -0,0 +1,127 @@
+//{{NO_DEPENDENCIES}}
+// Microsoft Developer Studio generated include file.
+// Used by YAMN.rc
+//
+#define IDI_CHECKMAIL 104
+#define IDI_LAUNCHAPP 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 IDI_BADCONNECT 131
+#define IDI_ICOTTBUP 138
+#define IDD_PLUGINOPT 141
+#define IDI_NEWMAIL 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_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/src/services.cpp b/protocols/YAMN/src/services.cpp
new file mode 100644
index 0000000000..e9ba7b0aaf
--- /dev/null
+++ b/protocols/YAMN/src/services.cpp
@@ -0,0 +1,450 @@
+#include "stdafx.h"
+
+static INT_PTR Service_GetCaps(WPARAM wParam, 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 == PFLAGNUM_2)
+ return PF2_ONLINE | PF2_SHORTAWAY | PF2_LONGAWAY | PF2_LIGHTDND;
+ if (wParam == PFLAGNUM_5) {
+ if (g_plugin.getByte(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, LPARAM)
+{
+ return YAMN_STATUS;
+}
+
+static INT_PTR Service_SetStatus(WPARAM wParam, 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)
+{
+ mir_strncpy((char *)lParam, YAMN_DBMODULE, wParam);
+ return 0;
+}
+
+static INT_PTR Service_LoadIcon(WPARAM wParam, 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, 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)
+{
+ char *szProto = GetContactProto(wParam);
+ if (mir_strcmp(szProto, YAMN_DBMODULE))
+ return 0;
+
+ DBVARIANT dbv;
+ if (g_plugin.getString(wParam, "Id", &dbv))
+ return 0;
+
+ HACCOUNT ActualAccount = (HACCOUNT)CallService(MS_YAMN_FINDACCOUNTBYNAME, (WPARAM)POP3Plugin, (LPARAM)dbv.pszVal);
+ if (ActualAccount != nullptr) {
+ 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 != nullptr) {
+ WCHAR *Command;
+ if (ActualAccount->NewMailN.AppParam != nullptr)
+ Command = new WCHAR[mir_wstrlen(ActualAccount->NewMailN.App) + mir_wstrlen(ActualAccount->NewMailN.AppParam) + 6];
+ else
+ Command = new WCHAR[mir_wstrlen(ActualAccount->NewMailN.App) + 6];
+
+ if (Command != nullptr) {
+ mir_wstrcpy(Command, L"\"");
+ mir_wstrcat(Command, ActualAccount->NewMailN.App);
+ mir_wstrcat(Command, L"\" ");
+ if (ActualAccount->NewMailN.AppParam != nullptr)
+ mir_wstrcat(Command, ActualAccount->NewMailN.AppParam);
+
+ PROCESS_INFORMATION pi;
+ CreateProcessW(nullptr, Command, nullptr, nullptr, FALSE, NORMAL_PRIORITY_CLASS, nullptr, nullptr, &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
+ }
+ db_free(&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;
+ // copy/paste make mistakes
+ if (ActualAccount != nullptr) {
+ //we use event to signal, that running thread has all needed stack parameters copied
+ HANDLE ThreadRunningEV = CreateEvent(nullptr, FALSE, FALSE, nullptr);
+ if (ThreadRunningEV == nullptr)
+ 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;
+
+ mir_cslock lck(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) {
+ CheckParam ParamToPlugin = { YAMN_CHECKVERSION, ThreadRunningEV, ActualAccount, lParam ? YAMN_FORCECHECK : YAMN_NORMALCHECK, nullptr, nullptr };
+
+ ActualAccount->TimeLeft = ActualAccount->Interval;
+ DWORD tid;
+ HANDLE NewThread = CreateThread(nullptr, 0, (YAMN_STANDARDFCN)ActualAccount->Plugin->Fcn->SynchroFcnPtr, &ParamToPlugin, 0, &tid);
+ if (NewThread) {
+ WaitForSingleObject(ThreadRunningEV, INFINITE);
+ CloseHandle(NewThread);
+ }
+ }
+ ReadDoneFcn(ActualAccount->AccountAccessSO);
+ }
+ CloseHandle(ThreadRunningEV);
+ }
+ return 0;
+}
+
+static INT_PTR ContactMailCheck(WPARAM hContact, LPARAM)
+{
+ char *szProto = GetContactProto(hContact);
+ if (mir_strcmp(szProto, YAMN_DBMODULE))
+ return 0;
+
+ DBVARIANT dbv;
+ if (g_plugin.getString(hContact, "Id", &dbv))
+ return 0;
+
+ HACCOUNT ActualAccount = (HACCOUNT)CallService(MS_YAMN_FINDACCOUNTBYNAME, (WPARAM)POP3Plugin, (LPARAM)dbv.pszVal);
+ if (ActualAccount != nullptr) {
+ //we use event to signal, that running thread has all needed stack parameters copied
+ HANDLE ThreadRunningEV;
+ if (nullptr == (ThreadRunningEV = CreateEvent(nullptr, FALSE, FALSE, nullptr)))
+ 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;
+ mir_cslock lck(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 == nullptr)
+ ReadDoneFcn(ActualAccount->AccountAccessSO);
+
+ DWORD tid;
+ struct CheckParam ParamToPlugin = { YAMN_CHECKVERSION, ThreadRunningEV, ActualAccount, YAMN_FORCECHECK, (void *)nullptr, nullptr };
+ if (nullptr == CreateThread(nullptr, 0, (YAMN_STANDARDFCN)ActualAccount->Plugin->Fcn->ForceCheckFcnPtr, &ParamToPlugin, 0, &tid))
+ ReadDoneFcn(ActualAccount->AccountAccessSO);
+ else
+ WaitForSingleObject(ThreadRunningEV, INFINITE);
+ }
+ ReadDoneFcn(ActualAccount->AccountAccessSO);
+ }
+ CloseHandle(ThreadRunningEV);
+ }
+ db_free(&dbv);
+ return 0;
+}
+
+/*static*/ void ContactDoubleclicked(WPARAM wParam, LPARAM)
+{
+ char *szProto = GetContactProto(wParam);
+ if (mir_strcmp(szProto, YAMN_DBMODULE))
+ return;
+
+ DBVARIANT dbv;
+ if (g_plugin.getString(wParam, "Id", &dbv))
+ return;
+
+ HACCOUNT ActualAccount = (HACCOUNT)CallService(MS_YAMN_FINDACCOUNTBYNAME, (WPARAM)POP3Plugin, (LPARAM)dbv.pszVal);
+ if (ActualAccount != nullptr) {
+#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 = { nullptr, ActualAccount, ActualAccount->NewMailN.Flags, ActualAccount->NoNewMailN.Flags, nullptr };
+
+ 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, 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
+
+ }
+ db_free(&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;
+
+ RECT rc;
+ rc.top = rc.left = 0;
+ rc.right = bih.biWidth;
+ rc.bottom = bih.biHeight;
+
+ HDC hdc = GetDC(nullptr);
+ 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, nullptr, DI_NORMAL);
+ SelectObject(hdcMem, hoBmp);
+ return hBmp;
+}
+
+int AddTopToolbarIcon(WPARAM, LPARAM)
+{
+ if (g_plugin.getByte(YAMN_TTBFCHECK, 1)) {
+ if (ServiceExists(MS_TTB_REMOVEBUTTON) && hTTButton == nullptr) {
+ TTBButton btn = {};
+ btn.pszService = MS_YAMN_FORCECHECK;
+ btn.dwFlags = TTBBF_VISIBLE | TTBBF_SHOWTOOLTIP;
+ btn.hIconHandleUp = btn.hIconHandleDn = g_GetIconHandle(0);
+ btn.name = btn.pszTooltipUp = LPGEN("Check mail");
+ hTTButton = g_plugin.addTTB(&btn);
+ }
+ }
+ else {
+ if (hTTButton != nullptr) {
+ CallService(MS_TTB_REMOVEBUTTON, (WPARAM)hTTButton, 0);
+ hTTButton = nullptr;
+ }
+ }
+
+ return 0;
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+
+int Shutdown(WPARAM, LPARAM)
+{
+ CallService(MS_TTB_REMOVEBUTTON, (WPARAM)hTTButton, 0);
+
+ g_plugin.setDword(YAMN_DBMSGPOSX, HeadPosX);
+ g_plugin.setDword(YAMN_DBMSGPOSY, HeadPosY);
+ g_plugin.setDword(YAMN_DBMSGSIZEX, HeadSizeX);
+ g_plugin.setDword(YAMN_DBMSGSIZEY, HeadSizeY);
+ g_plugin.setWord(YAMN_DBMSGPOSSPLIT, HeadSplitPos);
+ YAMNVar.Shutdown = TRUE;
+ KillTimer(nullptr, SecTimer);
+
+ UnregisterProtoPlugins();
+ UnregisterFilterPlugins();
+ return 0;
+}
+
+int SystemModulesLoaded(WPARAM, LPARAM); //in main.cpp
+
+void HookEvents(void)
+{
+ HookEvent(ME_SYSTEM_MODULESLOADED, SystemModulesLoaded);
+ HookEvent(ME_TTB_MODULELOADED, AddTopToolbarIcon);
+ HookEvent(ME_OPT_INITIALISE, YAMNOptInitSvc);
+ HookEvent(ME_SYSTEM_PRESHUTDOWN, Shutdown);
+ HookEvent(ME_CLIST_DOUBLECLICKED, Service_ContactDoubleclicked);
+}
+
+void CreateServiceFunctions(void)
+{
+ // Standard 'protocol' services
+ CreateServiceFunction(YAMN_DBMODULE PS_GETCAPS, Service_GetCaps);
+ CreateServiceFunction(YAMN_DBMODULE PS_GETSTATUS, Service_GetStatus);
+ CreateServiceFunction(YAMN_DBMODULE PS_SETSTATUS, Service_SetStatus);
+ CreateServiceFunction(YAMN_DBMODULE PS_GETNAME, Service_GetName);
+ CreateServiceFunction(YAMN_DBMODULE PS_LOADICON, Service_LoadIcon);
+
+ // Function with which protocol plugin can register
+ CreateServiceFunction(MS_YAMN_GETFCNPTR, GetFcnPtrSvc);
+
+ // Function returns pointer to YAMN variables
+ CreateServiceFunction(MS_YAMN_GETVARIABLES, GetVariablesSvc);
+
+ // Function with which protocol plugin can register
+ CreateServiceFunction(MS_YAMN_REGISTERPROTOPLUGIN, RegisterProtocolPluginSvc);
+
+ // Function with which protocol plugin can unregister
+ CreateServiceFunction(MS_YAMN_UNREGISTERPROTOPLUGIN, UnregisterProtocolPluginSvc);
+
+ // Function creates an account for plugin
+ CreateServiceFunction(MS_YAMN_CREATEPLUGINACCOUNT, CreatePluginAccountSvc);
+
+ // Function deletes plugin account
+ CreateServiceFunction(MS_YAMN_DELETEPLUGINACCOUNT, DeletePluginAccountSvc);
+
+ // Finds account for plugin by name
+ CreateServiceFunction(MS_YAMN_FINDACCOUNTBYNAME, FindAccountByNameSvc);
+
+ // Creates next account for plugin
+ CreateServiceFunction(MS_YAMN_GETNEXTFREEACCOUNT, GetNextFreeAccountSvc);
+
+ // Function removes account from YAMN queue. Does not delete it from memory
+ CreateServiceFunction(MS_YAMN_DELETEACCOUNT, DeleteAccountSvc);
+
+ // Function finds accounts for specified plugin
+ CreateServiceFunction(MS_YAMN_READACCOUNTS, AddAccountsFromFileSvc);
+
+ // Function that stores all plugin mails to one file
+ CreateServiceFunction(MS_YAMN_WRITEACCOUNTS, WriteAccountsToFileSvc);
+
+ // Function that returns user's filename
+ CreateServiceFunction(MS_YAMN_GETFILENAME, GetFileNameSvc);
+
+ // Releases unicode string from memory
+ CreateServiceFunction(MS_YAMN_DELETEFILENAME, DeleteFileNameSvc);
+
+ // Checks mail
+ CreateServiceFunction(MS_YAMN_FORCECHECK, ForceCheckSvc);
+
+ // Runs YAMN's mail browser
+ CreateServiceFunction(MS_YAMN_MAILBROWSER, RunMailBrowserSvc);
+
+ // Runs YAMN's bad conenction window
+ CreateServiceFunction(MS_YAMN_BADCONNECTION, RunBadConnectionSvc);
+
+ // Function creates new mail for plugin
+ CreateServiceFunction(MS_YAMN_CREATEACCOUNTMAIL, CreateAccountMailSvc);
+
+ // Function deletes plugin account
+ CreateServiceFunction(MS_YAMN_DELETEACCOUNTMAIL, DeleteAccountMailSvc);
+
+ // Function with which filter plugin can register
+ CreateServiceFunction(MS_YAMN_REGISTERFILTERPLUGIN, RegisterFilterPluginSvc);
+
+ // Function with which filter plugin can unregister
+ CreateServiceFunction(MS_YAMN_UNREGISTERFILTERPLUGIN, UnregisterFilterPluginSvc);
+
+ // Function filters mail
+ CreateServiceFunction(MS_YAMN_FILTERMAIL, FilterMailSvc);
+
+ // Function contact list double click
+ CreateServiceFunction(MS_YAMN_CLISTDBLCLICK, ClistContactDoubleclicked);
+
+ // Function to check individual account
+ CreateServiceFunction(MS_YAMN_ACCOUNTCHECK, AccountMailCheck);
+
+ // Function contact list context menu click
+ CreateServiceFunction(MS_YAMN_CLISTCONTEXT, ContactMailCheck);
+
+ // Function contact list context menu click
+ CreateServiceFunction(MS_YAMN_CLISTCONTEXTAPP, ContactApplication);
+}
+
+//Function to put all enabled contact to the Online status
+void RefreshContact(void)
+{
+ HACCOUNT Finder;
+ for (Finder = POP3Plugin->FirstAccount; Finder != nullptr; Finder = Finder->Next) {
+ if (Finder->hContact != NULL) {
+ if ((Finder->Flags & YAMN_ACC_ENA) && (Finder->NewMailN.Flags & YAMN_ACC_CONT))
+ db_unset(Finder->hContact, "CList", "Hidden");
+ else
+ db_set_b(Finder->hContact, "CList", "Hidden", 1);
+ }
+ else if ((Finder->Flags & YAMN_ACC_ENA) && (Finder->NewMailN.Flags & YAMN_ACC_CONT)) {
+ Finder->hContact = db_add_contact();
+ Proto_AddToContact(Finder->hContact, YAMN_DBMODULE);
+ g_plugin.setString(Finder->hContact, "Id", Finder->Name);
+ g_plugin.setString(Finder->hContact, "Nick", Finder->Name);
+ g_plugin.setWord(Finder->hContact, "Status", ID_STATUS_ONLINE);
+ db_set_s(Finder->hContact, "CList", "StatusMsg", Translate("No new mail message"));
+ }
+ }
+}
diff --git a/protocols/YAMN/src/stdafx.cxx b/protocols/YAMN/src/stdafx.cxx
new file mode 100644
index 0000000000..1b563fc866
--- /dev/null
+++ b/protocols/YAMN/src/stdafx.cxx
@@ -0,0 +1,18 @@
+/*
+Copyright (C) 2012-19 Miranda NG team (https://miranda-ng.org)
+
+This program is free software; you can redistribute it and/or
+modify it under the terms of the GNU General Public License
+as published by the Free Software Foundation version 2
+of the License.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "stdafx.h" \ No newline at end of file
diff --git a/protocols/YAMN/src/stdafx.h b/protocols/YAMN/src/stdafx.h
new file mode 100644
index 0000000000..246e9468fa
--- /dev/null
+++ b/protocols/YAMN/src/stdafx.h
@@ -0,0 +1,262 @@
+
+#ifndef __YAMN_H
+#define __YAMN_H
+
+#define VC_EXTRALEAN
+
+#include <windows.h>
+#include <windowsx.h>
+#include <commctrl.h>
+
+#include <win2k.h>
+#include <newpluginapi.h>
+#include <m_skin.h>
+#include <m_langpack.h>
+#include <m_clistint.h>
+#include <m_options.h>
+#include <m_database.h>
+#include <m_protosvc.h>
+#include <m_icolib.h>
+#include <m_popup.h>
+#include <m_messages.h>
+#include <m_netlib.h>
+#include <m_hotkeys.h>
+#include <m_timezones.h>
+
+#include <m_toptoolbar.h>
+#include <m_kbdnotify.h>
+#include <m_filterplugin.h>
+#include <m_yamn.h>
+#include <m_protoplugin.h>
+#include <m_folders.h>
+
+#include "main.h"
+#include "mails/decode.h"
+#include "browser/browser.h"
+#include "resource.h"
+#include "debug.h"
+#include "version.h"
+#include "proto/netclient.h"
+#include "proto/netlib.h"
+#include "proto/pop3/pop3.h"
+#include "proto/pop3/pop3comm.h"
+#include "proto/pop3/pop3opt.h"
+
+struct CMPlugin : public PLUGIN<CMPlugin>
+{
+ CMPlugin();
+
+ int Load() override;
+ int Unload() override;
+};
+
+// From services.cpp
+void CreateServiceFunctions(void);
+void HookEvents(void);
+void RefreshContact(void);
+void ContactDoubleclicked(WPARAM wParam, LPARAM lParam);
+INT_PTR ClistContactDoubleclicked(WPARAM wParam, LPARAM lParam);
+
+extern mir_cs PluginRegCS;
+extern SCOUNTER *AccountWriterSO;
+extern HANDLE ExitEV;
+extern HANDLE WriteToFileEV;
+
+// From debug.cpp
+#ifdef _DEBUG
+void InitDebug();
+void UnInitDebug();
+#endif
+
+// From yamn.cpp
+INT_PTR GetFcnPtrSvc(WPARAM wParam, LPARAM lParam);
+INT_PTR GetVariablesSvc(WPARAM, LPARAM);
+void CALLBACK TimerProc(HWND, UINT, UINT_PTR, DWORD);
+INT_PTR ForceCheckSvc(WPARAM, LPARAM);
+
+extern struct YAMNExportedFcns *pYAMNFcn;
+
+// From account.cpp
+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(wchar_t *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);
+DWORD ReadMessagesFromMemory(HACCOUNT Which, char **Parser, char *End);
+DWORD ReadAccountFromMemory(HACCOUNT Which, char **Parser, wchar_t *End);
+INT_PTR AddAccountsFromFileSvc(WPARAM wParam, LPARAM lParam);
+
+DWORD WriteStringToFile(HANDLE File, char *Source);
+DWORD WriteStringToFileW(HANDLE File, WCHAR *Source);
+
+
+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);
+void __cdecl DeleteAccountInBackground(void *Which);
+int StopAccounts(HYAMNPROTOPLUGIN Plugin);
+int WaitForAllAccounts(HYAMNPROTOPLUGIN Plugin, BOOL GetAccountBrowserAccess = FALSE);
+int DeleteAccounts(HYAMNPROTOPLUGIN Plugin);
+
+void WINAPI GetStatusFcn(HACCOUNT Which, wchar_t *Value);
+void WINAPI SetStatusFcn(HACCOUNT Which, wchar_t *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 wchar_t UserDirectory[]; //e.g. "F:\WINNT\Profiles\UserXYZ"
+extern wchar_t ProfileName[]; //e.g. "majvan"
+extern SWMRG *AccountBrowserSO;
+extern YAMN_VARIABLES YAMNVar;
+extern HANDLE hNewMailHook;
+extern HANDLE hTTButton;
+extern HCURSOR hCurSplitNS, hCurSplitWE;
+extern UINT SecTimer;
+
+HANDLE WINAPI g_GetIconHandle(int idx);
+HICON WINAPI g_LoadIconEx(int idx, bool big = false);
+
+//From synchro.cpp
+void WINAPI DeleteMessagesToEndFcn(HACCOUNT Account, HYAMNMAIL From);
+DWORD WINAPI WaitToWriteFcn(PSWMRG SObject, PSCOUNTER SCounter = nullptr);
+void WINAPI WriteDoneFcn(PSWMRG SObject, PSCOUNTER SCounter = nullptr);
+DWORD WINAPI WaitToReadFcn(PSWMRG SObject);
+void WINAPI ReadDoneFcn(PSWMRG SObject);
+DWORD WINAPI SCIncFcn(PSCOUNTER SCounter);
+DWORD WINAPI SCDecFcn(PSCOUNTER SCounter);
+BOOL WINAPI SWMRGInitialize(PSWMRG, wchar_t *);
+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, wchar_t *Value);
+
+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 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 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 void __cdecl MailBrowser(void *Param);
+extern DWORD WINAPI NoNewMailProc(LPVOID Param);
+extern void __cdecl BadConnection(void *Param);
+extern PVOID TLSCtx;
+extern PVOID SSLCtx;
+
+extern HGENMENU hMenuItemMain, hMenuItemCont, hMenuItemContApp;
+extern PYAMN_VARIABLES pYAMNVar;
+
+#endif
diff --git a/protocols/YAMN/src/synchro.cpp b/protocols/YAMN/src/synchro.cpp
new file mode 100644
index 0000000000..433f0768b6
--- /dev/null
+++ b/protocols/YAMN/src/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 "stdafx.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,wchar_t *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 (nullptr != pSWMRG->hEventNoWriter)
+ CloseHandle(pSWMRG->hEventNoWriter);
+ if (nullptr != pSWMRG->hEventNoReaders)
+ CloseHandle(pSWMRG->hEventNoReaders);
+ if (nullptr != pSWMRG->hSemNumReaders)
+ CloseHandle(pSWMRG->hSemNumReaders);
+ if (nullptr != pSWMRG->hFinishEV)
+ CloseHandle(pSWMRG->hFinishEV);
+}
+
+BOOL WINAPI SWMRGInitialize(PSWMRG pSWMRG,wchar_t *Name)
+{
+ pSWMRG->hEventNoWriter=nullptr;
+ pSWMRG->hEventNoReaders=nullptr;
+ pSWMRG->hSemNumReaders=nullptr;
+ pSWMRG->hFinishEV=nullptr;
+
+// Creates the automatic-reset event that is signalled when
+// no writer threads are writing.
+// Initially no reader threads are reading.
+ if (Name != nullptr)
+ Name[0]=(wchar_t)'W';
+ pSWMRG->hEventNoWriter=CreateEvent(nullptr,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 != nullptr)
+ Name[0]=(wchar_t)'R';
+ pSWMRG->hEventNoReaders=CreateEvent(nullptr,TRUE,TRUE,Name);
+
+// Initializes the variable that indicates the number of
+// reader threads that are reading.
+// Initially no reader threads are reading.
+ if (Name != nullptr)
+ Name[0]=(wchar_t)'C';
+ pSWMRG->hSemNumReaders=CreateSemaphore(nullptr,0,0x7FFFFFFF,Name);
+
+ if (Name != nullptr)
+ Name[0]=(wchar_t)'F';
+ pSWMRG->hFinishEV=CreateEvent(nullptr,TRUE,FALSE,Name);
+
+// If a synchronization object could not be created,
+// destroys any created objects and return failure.
+ if ((nullptr==pSWMRG->hEventNoWriter) || (nullptr==pSWMRG->hEventNoReaders) || (nullptr==pSWMRG->hSemNumReaders) || (nullptr==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 != nullptr)
+ 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 != nullptr)
+ 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/src/version.h b/protocols/YAMN/src/version.h
new file mode 100644
index 0000000000..20429be688
--- /dev/null
+++ b/protocols/YAMN/src/version.h
@@ -0,0 +1,13 @@
+#define __MAJOR_VERSION 0
+#define __MINOR_VERSION 1
+#define __RELEASE_NUM 2
+#define __BUILD_NUM 6
+
+#include <stdver.h>
+
+#define __PLUGIN_NAME "Mail Notifier"
+#define __FILENAME "YAMN.dll"
+#define __DESCRIPTION "Mail notifier and browser for Miranda NG. Included POP3 protocol."
+#define __AUTHOR "y_b, tweety, majvan"
+#define __AUTHORWEB "https://miranda-ng.org/p/YAMN/"
+#define __COPYRIGHT "© 2002-2004 majvan, 2005-2007 tweety, y_b, Miranda community"
diff --git a/protocols/YAMN/src/yamn.cpp b/protocols/YAMN/src/yamn.cpp
new file mode 100644
index 0000000000..e45e22f06e
--- /dev/null
+++ b/protocols/YAMN/src/yamn.cpp
@@ -0,0 +1,320 @@
+/*
+ * This code implements miscellaneous usefull functions
+ *
+ * (c) majvan 2002-2004
+ */
+
+#include "stdafx.h"
+
+//--------------------------------------------------------------------------------------------------
+//--------------------------------------------------------------------------------------------------
+
+//Plugin registration CS
+//Used if we add (register) plugin to YAMN plugins and when we browse through registered plugins
+mir_cs 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)
+{
+ register int i;
+
+ for (i=0;i<sizeof(ProtoPluginExportedFcn)/sizeof(ProtoPluginExportedFcn[0]);i++)
+ if (0==mir_strcmp((char *)wParam, ProtoPluginExportedFcn[i].ID))
+ return (INT_PTR)ProtoPluginExportedFcn[i].Ptr;
+ for (i=0;i<sizeof(ProtoPluginExportedSvc)/sizeof(ProtoPluginExportedSvc[0]);i++)
+ if (0==mir_strcmp((char *)wParam, ProtoPluginExportedSvc[i].ID))
+ return (INT_PTR)ProtoPluginExportedSvc[i].Ptr;
+ for (i=0;i<sizeof(SynchroExportedFcn)/sizeof(SynchroExportedFcn[0]);i++)
+ if (0==mir_strcmp((char *)wParam, SynchroExportedFcn[i].ID))
+ return (INT_PTR)SynchroExportedFcn[i].Ptr;
+ for (i=0;i<sizeof(AccountExportedFcn)/sizeof(AccountExportedFcn[0]);i++)
+ if (0==mir_strcmp((char *)wParam, AccountExportedFcn[i].ID))
+ return (INT_PTR)AccountExportedFcn[i].Ptr;
+ for (i=0;i<sizeof(AccountExportedSvc)/sizeof(AccountExportedSvc[0]);i++)
+ if (0==mir_strcmp((char *)wParam, AccountExportedSvc[i].ID))
+ return (INT_PTR)AccountExportedSvc[i].Ptr;
+ for (i=0;i<sizeof(MailExportedFcn)/sizeof(MailExportedFcn[0]);i++)
+ if (0==mir_strcmp((char *)wParam, MailExportedFcn[i].ID))
+ return (INT_PTR)MailExportedFcn[i].Ptr;
+ for (i=0;i<sizeof(MailExportedSvc)/sizeof(MailExportedSvc[0]);i++)
+ if (0==mir_strcmp((char *)wParam, MailExportedSvc[i].ID))
+ return (INT_PTR)MailExportedSvc[i].Ptr;
+ for (i=0;i<sizeof(FilterPluginExportedFcn)/sizeof(FilterPluginExportedFcn[0]);i++)
+ if (0==mir_strcmp((char *)wParam, FilterPluginExportedFcn[i].ID))
+ return (INT_PTR)FilterPluginExportedFcn[i].Ptr;
+ for (i=0;i<sizeof(FilterPluginExportedSvc)/sizeof(FilterPluginExportedSvc[0]);i++)
+ if (0==mir_strcmp((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_PTR, DWORD)
+{
+ HACCOUNT ActualAccount;
+ DWORD Status, tid;
+
+// we use event to signal, that running thread has all needed stack parameters copied
+ HANDLE ThreadRunningEV = CreateEvent(nullptr, FALSE, FALSE, nullptr);
+ if (ThreadRunningEV == nullptr)
+ 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);
+
+ mir_cslock lck(PluginRegCS);
+ for (PYAMN_PROTOPLUGINQUEUE ActualPlugin = FirstProtoPlugin; ActualPlugin != nullptr; 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
+ return;
+ }
+#ifdef DEBUG_SYNCHRO
+ DebugLog(SynchroFile, "TimerProc:AccountBrowserSO-read enter\n");
+#endif
+ for (ActualAccount=ActualPlugin->Plugin->FirstAccount;ActualAccount != nullptr;ActualAccount=ActualAccount->Next)
+ {
+ if (ActualAccount->Plugin==nullptr || ActualAccount->Plugin->Fcn==nullptr) //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==nullptr)
+ {
+ 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 *)nullptr, nullptr};
+
+ ActualAccount->TimeLeft=ActualAccount->Interval;
+ HANDLE NewThread = CreateThread(nullptr, 0, (YAMN_STANDARDFCN)ActualAccount->Plugin->Fcn->TimeoutFcnPtr, &ParamToPlugin, 0, &tid);
+ if (NewThread == nullptr)
+ {
+#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 = g_plugin.getWord(ActualAccount->hContact, "Status");
+ switch (cStatus) {
+ case ID_STATUS_ONLINE:
+ case ID_STATUS_OFFLINE:
+ g_plugin.setWord(ActualAccount->hContact, "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);
+ }
+ CloseHandle(ThreadRunningEV);
+}
+
+INT_PTR ForceCheckSvc(WPARAM, LPARAM)
+{
+ HACCOUNT ActualAccount;
+ DWORD tid;
+
+ //we use event to signal, that running thread has all needed stack parameters copied
+ HANDLE ThreadRunningEV = CreateEvent(nullptr, FALSE, FALSE, nullptr);
+ if (ThreadRunningEV == nullptr)
+ 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;
+
+ {
+ mir_cslock lck(PluginRegCS);
+ for (PYAMN_PROTOPLUGINQUEUE ActualPlugin = FirstProtoPlugin; ActualPlugin != nullptr; 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 != nullptr; ActualAccount = ActualAccount->Next) {
+ if (ActualAccount->Plugin->Fcn == nullptr) //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 == nullptr) {
+ ReadDoneFcn(ActualAccount->AccountAccessSO);
+ continue;
+ }
+ struct CheckParam ParamToPlugin = { YAMN_CHECKVERSION, ThreadRunningEV, ActualAccount, YAMN_FORCECHECK, (void *)nullptr, nullptr };
+
+ if (nullptr == CreateThread(nullptr, 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);
+ }
+ }
+
+ CloseHandle(ThreadRunningEV);
+
+ if (hTTButton)
+ CallService(MS_TTB_SETBUTTONSTATE, (WPARAM)hTTButton, 0);
+ return 1;
+}