voile/Voile/FirstRunWizard.cs
2026-02-01 20:10:36 +01:00

453 lines
13 KiB
C#

using Org.BouncyCastle.Utilities;
using Org.BouncyCastle.X509;
using Sophia.Net.DRM;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using Voile.Patchouli.Data;
using Voile.Patchouli.Reflection;
using Voile.Properties;
namespace Voile
{
public partial class FirstRunWizard : Form
{
public FirstRunWizard()
{
InitializeComponent();
DisplayTabPage(0);
}
private TabPage[] allPages;
private int currentTabPage;
private Stack<int> pastPages;
private bool beginnerMode;
private FileInfo licenceCertificateFileInfo;
private byte[] licenseBuffer;
private int licenseState;
private X509Certificate licenseCertificate;
private bool sharewareMode;
private VoilePluginInfo selectedDataStorage;
private IVoileDataStorageFactory voileDataStorageFactory;
private bool dataStorageConnectionSucessful;
public void DisplayTabPage(int target)
{
if (pastPages == null)
pastPages = new Stack<int>();
else
pastPages.Push(currentTabPage);
if (allPages == null)
{
allPages = new TabPage[tabControl1.TabPages.Count];
for (int i = 0; i < tabControl1.TabPages.Count; i++)
{
allPages[i] = tabControl1.TabPages[i];
}
}
tabControl1.TabPages.Clear();
tabControl1.TabPages.Add(allPages[target]);
currentTabPage = target;
RefreshView();
}
void RefreshView()
{
loadFileButton.Visible = false;
buttonBack.Enabled = false;
buttonNext.Enabled = false;
if (pastPages != null)
{
if (pastPages.Count > 0)
{
buttonBack.Enabled = true;
}
}
switch (currentTabPage)
{
case 0:
beginnerMode = radioButtonAmBegginer.Checked;
buttonNext.Enabled = radioButtonAmBegginer.Checked || radioButtonAmExpert.Checked;
break;
case 1:
//Lizenzstatus validieren.
buttonValidateLicense.Enabled = ((licenceCertificateFileInfo != null) & radioButtonHasLicense.Checked);
buttonLoadLicenseFile.Enabled = radioButtonHasLicense.Checked;
pictureBox2.Visible = radioButtonHasLicense.Checked;
if (pictureBox2.Visible)
{
switch (licenseState)
{
case 0: //Noch nichts geladen.
pictureBox2.Image = Resources.SETUPAPI_18_1_32x32x4; //Fragezeichen
break;
case 1: //Root cert konnte nicht geladen werden.
case 2: //Lizenz file konnte nicht geladen werden.
case 3: //Lizenzzertifikat wurde nicht von sophia.net ausgestellt.
case 4: //Lizennzertifikat enthält keine sophia.net extensions
case 5: //sophia.net extension ist leer
case 7: //sophia.net extension hat ungültige länge
pictureBox2.Image = Resources.TRFFC10C_1_32x32x4; //rote Ampel
break;
case 6: //gültige lizenz
pictureBox2.Image = Resources.TRFFC10A_1_32x32x4; //grüne Ampel
break;
case 8:
default:
pictureBox2.Image = Resources.iblicense_133_1_32x32x4; //Ausrufezeichen
licenseState = 8;
break;
}
}
//Können wir weiter machen?
sharewareMode = radioButtonNoLicense.Checked;
buttonNext.Enabled = (sharewareMode) | (licenseState == 6);
break;
case 2:
labelDataStorageHint.Text = " ";
if (!dataStorageRadioButtonsGenerated)
GenerateDataStorageRadioButtons();
//TODO: Hier zusätzlich Lizenzvalidierung einfügen.
buttonNext.Enabled = selectedDataStorage != null;
break;
case 3:
loadFileButton.Visible = selectedDataStorage.CanSaveFile.Enable;
dbSettingsErrorLabel.Text = "";
if (voileDataStorageFactory == null)
{
dbSettingsPropertyGrid.SelectedObject = selectedDataStorage.GetPluginInstance();
}
break;
default:
MessageBox.Show("Could not find handler for the current tab page.");
return;
}
}
private bool dataStorageRadioButtonsGenerated;
private RadioButton[] dataStorageRadioButtons;
private void GenerateDataStorageRadioButtons()
{
VoilePluginManager pluginManager = VoilePluginManager.GetInstance();
IReadOnlyList<VoilePluginInfo> dataStoragePlugins = pluginManager.GetDataStorages();
dataStorageRadioButtons = new RadioButton[dataStoragePlugins.Count];
int top = labelDataStorageHint.Top;
top += labelDataStorageHint.Height;
int left = labelDataStorageHint.Left;
for (int i = 0; i < dataStorageRadioButtons.Length; i++)
{
RadioButton childRadioButton = new RadioButton();
childRadioButton.Parent = tabPagePickDataStorage;
if (dataStoragePlugins[i].Incomplete)
childRadioButton.Enabled = false;
string radioButtonLabel = dataStoragePlugins[i].DisplayName;
if (dataStoragePlugins[i].NeededEntitlement.HasValue)
radioButtonLabel += " (needs license)";
childRadioButton.AutoSize = true;
childRadioButton.Text = radioButtonLabel;
if (selectedDataStorage != null)
childRadioButton.Checked = (selectedDataStorage.Id == dataStoragePlugins[i].Id);
childRadioButton.Top = top;
childRadioButton.Left = left;
childRadioButton.Tag = dataStoragePlugins[i];
top += childRadioButton.Height;
dataStorageRadioButtons[i] = childRadioButton;
dataStorageRadioButtons[i].CheckedChanged += OnDataStrorageSelected;
}
dataStorageRadioButtonsGenerated = true;
}
private void OnDataStrorageSelected(object? sender, EventArgs e)
{
RadioButton senderUnboxed = sender as RadioButton;
if (senderUnboxed == null)
throw new Voile.Common.VoileException("Could not unbox sender.");
VoilePluginInfo pluginInfo = senderUnboxed.Tag as VoilePluginInfo;
if (pluginInfo == null)
throw new Common.VoileException("Could not unbox plugin info");
selectedDataStorage = pluginInfo;
RefreshView();
}
private void radioButton3_CheckedChanged(object sender, EventArgs e)
{
RefreshView();
}
private void radioButtonAmBegginer_CheckedChanged(object sender, EventArgs e)
{
RefreshView();
}
private void radioButtonAmExpert_CheckedChanged(object sender, EventArgs e)
{
RefreshView();
}
private void radioButtonNoLicense_CheckedChanged(object sender, EventArgs e)
{
RefreshView();
}
private void pictureBox2_Click(object sender, EventArgs e)
{
}
private void buttonNext_Click(object sender, EventArgs e)
{
if (currentTabPage == 0)
{
//Wir sind auf der Willkommensseite, hier wird ausgewählt ob Anfänger oder Experte.
//Es wird nach der Lizenz gefragt
DisplayTabPage(1);
}
else if (currentTabPage == 1)
{
//Hier soll der Nutzer auswählen ob einfach oder schwierig.
if (beginnerMode)
{
//TODO: Automatisch SQLite und Directory Storage auswählen
}
else
{
DisplayTabPage(2);
}
}
else if (currentTabPage == 2)
{
//Hier soll der Nutzer auswählen, welche DB verwendet werden soll.
DisplayTabPage(3);
}
}
private void buttonLoadLicenseFile_Click(object sender, EventArgs e)
{
if (openFileDialogCertificate.ShowDialog() == DialogResult.OK)
{
licenceCertificateFileInfo = new FileInfo(openFileDialogCertificate.FileName);
licenseBuffer = File.ReadAllBytes(licenceCertificateFileInfo.FullName);
textBox1.Text = licenceCertificateFileInfo.FullName;
licenseState = 0;
pictureBox2.Image = Resources.SETUPAPI_18_1_32x32x4;
}
RefreshView();
}
private void buttonValidateLicense_Click(object sender, EventArgs e)
{
VoileContext voileContext = VoileContext.GetContext();
if (voileContext.SophiaNetRootCertificate == null)
{
try
{
byte[] sophianetCertBuffer = Resources.sophianet_cert;
voileContext.SophiaNetRootCertificate = SophiaNetDrmApi.ImportCertificate(sophianetCertBuffer);
}
catch (Exception ex)
{
licenseState = 1;
RefreshView();
return;
}
}
try
{
licenseCertificate = SophiaNetDrmApi.ImportCertificate(licenseBuffer);
}
catch (Exception f)
{
licenseState = 2;
RefreshView();
return;
}
bool certificateChainValid = SophiaNetDrmApi.ValidateCertificateChain(licenseCertificate, voileContext.SophiaNetRootCertificate);
if (!certificateChainValid)
{
licenseState = 3;
RefreshView();
return;
}
byte[] sophiaNetExtensionBuffer;
try
{
sophiaNetExtensionBuffer = SophiaNetDrmApi.GetSophiaNetExtensionFromCertificate(licenseCertificate);
}
catch (Exception g)
{
licenseState = 4;
RefreshView();
return;
}
if (sophiaNetExtensionBuffer.Length == 0)
{
licenseState = 5;
RefreshView();
return;
}
if (sophiaNetExtensionBuffer.Length % 16 != 0)
{
licenseState = 7;
RefreshView();
return;
}
licenseState = 6;
RefreshView();
return;
}
private void dbTestButton_Click(object sender, EventArgs e)
{
dataStorageConnectionSucessful = false;
if (voileDataStorageFactory == null)
{
IVoileDataStorageFactory newDs = selectedDataStorage.GetPluginInstance() as IVoileDataStorageFactory;
if (newDs == null)
{
dbSettingsErrorLabel.Text = "The selected plugin is not a Data Storage plugin. This is a bug in voile, please report it.";
dbTestTrafficLight.Image = Resources.TRFFC10C_1_32x32x4;
return;
}
voileDataStorageFactory = newDs;
}
IVoileDataStorage dataStorage = null;
try
{
dataStorage = voileDataStorageFactory.CreateDataStorage();
}
catch (Exception ex)
{
dbSettingsErrorLabel.Text = ex.Message;
dbTestTrafficLight.Image = Resources.TRFFC10C_1_32x32x4;
return;
}
try
{
Exception pingResult = dataStorage.Ping();
if (pingResult != null)
{
dbSettingsErrorLabel.Text = pingResult.Message;
dbTestTrafficLight.Image = Resources.TRFFC10C_1_32x32x4;
return;
}
}
catch (Exception ex2)
{
dbSettingsErrorLabel.Text = ex2.Message;
dbTestTrafficLight.Image = Resources.TRFFC10C_1_32x32x4;
return;
}
dbSettingsErrorLabel.Text = "Database connection sucessful!";
pictureBox2.Image = Resources.TRFFC10A_1_32x32x4; //grüne Ampel
dataStorageConnectionSucessful = true;
}
private void buttonBack_Click(object sender, EventArgs e)
{
int previousTabPageId = pastPages.Pop();
tabControl1.TabPages.Clear();
tabControl1.TabPages.Add(allPages[previousTabPageId]);
currentTabPage = previousTabPageId;
RefreshView();
}
private void loadFileButton_Click(object sender, EventArgs e)
{
switch (currentTabPage)
{
case 3:
VoilePluginCanSaveFileAttribute canSaveFile = selectedDataStorage.CanSaveFile;
switch (canSaveFile.Mode)
{
case CanSaveFileMode.SaveFile:
SaveFileDialog sfd = new SaveFileDialog();
sfd.Filter = canSaveFile.Filter;
sfd.OverwritePrompt = canSaveFile.FileMustExist;
DialogResult dialogResult = sfd.ShowDialog(this);
if (dialogResult == DialogResult.OK)
{
if (voileDataStorageFactory == null)
{
voileDataStorageFactory = selectedDataStorage.GetPluginInstance() as IVoileDataStorageFactory;
}
SetFileNameProperty(voileDataStorageFactory, sfd.FileName);
dbSettingsPropertyGrid.Refresh();
}
break;
default:
MessageBox.Show(this, String.Format("Don't know what to do with a {1} dialog on page {0}.", currentTabPage, canSaveFile.Mode), allPages[currentTabPage].Text, MessageBoxButtons.OK, MessageBoxIcon.Hand);
break;
}
break;
default:
MessageBox.Show(this, String.Format("Don't know what to do on page {0}", currentTabPage), allPages[currentTabPage].Text, MessageBoxButtons.OK, MessageBoxIcon.Hand);
return;
}
}
private void SetFileNameProperty(object voilePlugin, string targetFileName)
{
Type type = voilePlugin.GetType();
System.Reflection.PropertyInfo[] propertyInfos = type.GetProperties();
foreach (System.Reflection.PropertyInfo propertyInfo in propertyInfos)
{
if (!propertyInfo.CanWrite)
continue;
string name = propertyInfo.Name.ToLower();
switch (name)
{
case "filepath":
propertyInfo.SetValue(voilePlugin, targetFileName, null);
return;
}
}
}
private void dbTestTrafficLight_Click(object sender, EventArgs e)
{
MessageBox.Show("Adjust the settings as needed, and when you're ready, click \"Test Settings\" to verify the connection before moving on.", string.Format("Configuring {0}", selectedDataStorage.DisplayName),MessageBoxButtons.OK,MessageBoxIcon.Information);
}
}
}