diff options
Diffstat (limited to 'protocols/CurrencyRates')
87 files changed, 8057 insertions, 0 deletions
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 Binary files differnew file mode 100644 index 0000000000..9006c9f9c0 --- /dev/null +++ b/protocols/CurrencyRates/CurrencyRatesChart/bin/x32/CurrencyRatesChart.exe diff --git a/protocols/CurrencyRates/CurrencyRatesChart/bin/x64/CurrencyRatesChart.exe b/protocols/CurrencyRates/CurrencyRatesChart/bin/x64/CurrencyRatesChart.exe Binary files differnew file mode 100644 index 0000000000..221a27d11b --- /dev/null +++ b/protocols/CurrencyRates/CurrencyRatesChart/bin/x64/CurrencyRatesChart.exe diff --git a/protocols/CurrencyRates/CurrencyRatesChart/main.ico b/protocols/CurrencyRates/CurrencyRatesChart/main.ico Binary files differnew file mode 100644 index 0000000000..da85d1f7c6 --- /dev/null +++ b/protocols/CurrencyRates/CurrencyRatesChart/main.ico 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 Binary files differnew file mode 100644 index 0000000000..71c90785aa --- /dev/null +++ b/protocols/CurrencyRates/proto_CurrencyRates/res/proto_na.ico diff --git a/protocols/CurrencyRates/proto_CurrencyRates/res/proto_offline.ico b/protocols/CurrencyRates/proto_CurrencyRates/res/proto_offline.ico Binary files differnew file mode 100644 index 0000000000..f6fc5e9f20 --- /dev/null +++ b/protocols/CurrencyRates/proto_CurrencyRates/res/proto_offline.ico diff --git a/protocols/CurrencyRates/proto_CurrencyRates/res/proto_online.ico b/protocols/CurrencyRates/proto_CurrencyRates/res/proto_online.ico Binary files differnew file mode 100644 index 0000000000..da85d1f7c6 --- /dev/null +++ b/protocols/CurrencyRates/proto_CurrencyRates/res/proto_online.ico diff --git a/protocols/CurrencyRates/res/AutoUpdateDisabled.ico b/protocols/CurrencyRates/res/AutoUpdateDisabled.ico Binary files differnew file mode 100644 index 0000000000..30c9dbf220 --- /dev/null +++ b/protocols/CurrencyRates/res/AutoUpdateDisabled.ico diff --git a/protocols/CurrencyRates/res/CurrencyConverter.ico b/protocols/CurrencyRates/res/CurrencyConverter.ico Binary files differnew file mode 100644 index 0000000000..67ac2095f5 --- /dev/null +++ b/protocols/CurrencyRates/res/CurrencyConverter.ico diff --git a/protocols/CurrencyRates/res/Export currencyrates.ico b/protocols/CurrencyRates/res/Export currencyrates.ico Binary files differnew file mode 100644 index 0000000000..31c7aa2ba1 --- /dev/null +++ b/protocols/CurrencyRates/res/Export currencyrates.ico 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 Binary files differnew file mode 100644 index 0000000000..506aa62af3 --- /dev/null +++ b/protocols/CurrencyRates/res/Import currencyrates.ico diff --git a/protocols/CurrencyRates/res/Refresh.ico b/protocols/CurrencyRates/res/Refresh.ico Binary files differnew file mode 100644 index 0000000000..f09a47cd9e --- /dev/null +++ b/protocols/CurrencyRates/res/Refresh.ico diff --git a/protocols/CurrencyRates/res/Section.ico b/protocols/CurrencyRates/res/Section.ico Binary files differnew file mode 100644 index 0000000000..768b3775aa --- /dev/null +++ b/protocols/CurrencyRates/res/Section.ico 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 Binary files differnew file mode 100644 index 0000000000..1367c475d6 --- /dev/null +++ b/protocols/CurrencyRates/res/currencyrate.ico diff --git a/protocols/CurrencyRates/res/down.ico b/protocols/CurrencyRates/res/down.ico Binary files differnew file mode 100644 index 0000000000..20722f63ca --- /dev/null +++ b/protocols/CurrencyRates/res/down.ico diff --git a/protocols/CurrencyRates/res/main.ico b/protocols/CurrencyRates/res/main.ico Binary files differnew file mode 100644 index 0000000000..da85d1f7c6 --- /dev/null +++ b/protocols/CurrencyRates/res/main.ico diff --git a/protocols/CurrencyRates/res/notchanged.ico b/protocols/CurrencyRates/res/notchanged.ico Binary files differnew file mode 100644 index 0000000000..39a8f1ea3c --- /dev/null +++ b/protocols/CurrencyRates/res/notchanged.ico diff --git a/protocols/CurrencyRates/res/swap.ico b/protocols/CurrencyRates/res/swap.ico Binary files differnew file mode 100644 index 0000000000..f4a410da41 --- /dev/null +++ b/protocols/CurrencyRates/res/swap.ico diff --git a/protocols/CurrencyRates/res/up.ico b/protocols/CurrencyRates/res/up.ico Binary files differnew file mode 100644 index 0000000000..0379c80d17 --- /dev/null +++ b/protocols/CurrencyRates/res/up.ico 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>(©data_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 "" |