1595 lines
70 KiB
C#
1595 lines
70 KiB
C#
using System;
|
|
using System.Collections.Generic;
|
|
using System.ComponentModel;
|
|
using System.Drawing;
|
|
using System.Linq;
|
|
using System.Windows.Forms;
|
|
using SafeMobileLib;
|
|
using Telerik.WinControls.UI;
|
|
using System.Collections;
|
|
using System.IO;
|
|
using Nini.Config;
|
|
using SafeMobileLib.DBmanagers;
|
|
using System.Drawing.Imaging;
|
|
using Telerik.WinControls.Layouts;
|
|
using System.Text.RegularExpressions;
|
|
using System.Threading;
|
|
using Telerik.WinControls;
|
|
using Newtonsoft.Json.Linq;
|
|
using System.Collections.Specialized;
|
|
|
|
/// <summary>
|
|
/// Must add a new checkbox for GDPR Emergency only positions and save the bool in the userSettings -> user_id = 0 value FALSE
|
|
///
|
|
/// AppServer - Location Thread: MainForm.dbSettings.getSettingValue(0, Utils.StolenNoGPSFix);
|
|
/// </summary>
|
|
|
|
|
|
namespace SubscriberAndUserManager
|
|
{
|
|
public partial class controlSettings : UserControl
|
|
{
|
|
private static SafeMobileLib.IconTheme crtIconTheme = SafeMobileLib.IconTheme.PIN;
|
|
private IConfigSource source = null;
|
|
DBbackup backup;
|
|
string lastBackup="";
|
|
private DBemailServiceManager DB;
|
|
private DBiconsManager DBIcons;
|
|
private DBalarmManager DBAlarm;
|
|
private DBsettingsManager DBSettings;
|
|
private EmailService eService;
|
|
private Boolean PollAfterSMS = false;
|
|
private Boolean BackupButtonPressed = false;
|
|
private Boolean RefreshButtonPressed = false;
|
|
|
|
private EmailServerSSL emailServerSSL = new EmailServerSSL();
|
|
private BindingList<DropListItem> iconThemesList;
|
|
private WaitingForm waitingForm;
|
|
public controlSettings(string DBuser, string DBname, string DBserv, DBemailServiceManager DB, DBalarmManager DBAlarm, DBiconsManager DBIcons, DBsettingsManager DBSettings)
|
|
{
|
|
InitializeComponent();
|
|
|
|
txLanIP.Culture = txNatIP.Culture = System.Globalization.CultureInfo.InvariantCulture;
|
|
RadMessageBox.SetThemeName("TelerikMetroBlue");
|
|
|
|
|
|
// event when the POP Server was verified
|
|
emailServerSSL.OnPopServerCheckResponseReceived += delegate(bool isValid, string responseMessage)
|
|
{
|
|
this.Invoke((MethodInvoker)delegate
|
|
{
|
|
btCheckPopServer.Enabled = true;
|
|
btCheckSmtpServer.Enabled = true;
|
|
if (!isValid)
|
|
// RadMessageBox.Show("POP Server settings are invalid. Please check the settings again.", "POP Server Settings", MessageBoxButtons.OK, RadMessageIcon.Error);
|
|
//else
|
|
// RadMessageBox.Show("POP Server settings are valid. ", "POP Server Settings", MessageBoxButtons.OK, RadMessageIcon.);
|
|
|
|
CustomMessageBox.Show(CustomMessageBoxType.exclamation, "POP Server settings are invalid. Please check the settings again.", "POP Server Settings");
|
|
else
|
|
CustomMessageBox.Show(CustomMessageBoxType.check, "POP Server settings are valid.", "POP Server Settings");
|
|
});
|
|
};
|
|
|
|
// event when the SMTP Server was verified
|
|
emailServerSSL.OnSmtpServerCheckResponseReceived += delegate(bool isValid, string responseMessage)
|
|
{
|
|
this.Invoke((MethodInvoker)delegate
|
|
{
|
|
btCheckSmtpServer.Enabled = true;
|
|
btCheckPopServer.Enabled = true;
|
|
if (!isValid)
|
|
// RadMessageBox.Show("SMTP Server settings are invalid", "SMTP Server Settings", MessageBoxButtons.OK, RadMessageIcon.Error);
|
|
//else
|
|
// RadMessageBox.Show("SMTP Server settings are valid. We've sent a test mail on your email account. Please verify it just to be sure. Thank you.",
|
|
// "SMTP Server Settings", MessageBoxButtons.OK, RadMessageIcon.Info);
|
|
CustomMessageBox.Show(CustomMessageBoxType.exclamation, "SMTP Server settings are invalid", "SMTP Server Settings");
|
|
else
|
|
CustomMessageBox.Show(CustomMessageBoxType.check, "SMTP Server settings are valid.\n We've sent a test mail on your email account.\n Please verify it just to be sure. Thank you.", "SMTP Server Settings");
|
|
});
|
|
|
|
};
|
|
|
|
|
|
RadCheckedListDataItem radCheckedListDataItem1 = new RadCheckedListDataItem(MainForm.returnLNGString(Utils.StolenArs), true);
|
|
radCheckedListDataItem1.Tag = Utils.StolenArs;
|
|
RadCheckedListDataItem radCheckedListDataItem2 = new RadCheckedListDataItem(MainForm.returnLNGString(Utils.StolenValidGPS), true);
|
|
radCheckedListDataItem2.Tag = Utils.StolenValidGPS;
|
|
RadCheckedListDataItem radCheckedListDataItem3 = new RadCheckedListDataItem(MainForm.returnLNGString(Utils.StolenNoGPSFix), true);
|
|
radCheckedListDataItem3.Tag = Utils.StolenNoGPSFix;
|
|
this.rcbddAlertType.Items.Add(radCheckedListDataItem1);
|
|
this.rcbddAlertType.Items.Add(radCheckedListDataItem2);
|
|
this.rcbddAlertType.Items.Add(radCheckedListDataItem3);
|
|
rcbddAlertType.NullText = MainForm.returnLNGString("stolen_hint");
|
|
|
|
Hashtable values = new Hashtable();
|
|
try
|
|
{
|
|
values = DBSettings.getAllSettings(0);
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
Console.WriteLine(ex.ToString());
|
|
//CustomMessageBox.Show(CustomMessageBoxType.exclamation, "Database connection error!!!", "Error");
|
|
return;
|
|
}
|
|
|
|
bool areItemsChecked = false;
|
|
// set last used values
|
|
foreach (RadCheckedListDataItem item in rcbddAlertType.Items)
|
|
{
|
|
if (values.ContainsKey(item.Tag.ToString()))
|
|
{
|
|
bool val = true;
|
|
bool.TryParse(values[item.Tag.ToString()].ToString(), out val);
|
|
item.Checked = val; //(bool)(values[item.Tag.ToString()]);
|
|
|
|
if (val == true)
|
|
areItemsChecked = true;
|
|
|
|
}
|
|
else
|
|
DBSettings.addSetting(0, item.Tag.ToString(), item.Selected ? "true" : "false");
|
|
}
|
|
|
|
// check all if no one is selected
|
|
if (!areItemsChecked)
|
|
{
|
|
foreach (RadCheckedListDataItem item in rcbddAlertType.Items)
|
|
{
|
|
item.Checked = true;
|
|
DBSettings.updateSettingValue(0, item.Tag.ToString(), "true");
|
|
}
|
|
}
|
|
|
|
rcbddAlertType.ItemCheckedChanging += delegate (object sender, RadCheckedListDataItemCancelEventArgs e)
|
|
{
|
|
int count = 0;
|
|
bool itemWillbeUnchecked = false;
|
|
foreach (RadCheckedListDataItem item in rcbddAlertType.Items)
|
|
{
|
|
if (item.Checked)
|
|
count++;
|
|
|
|
if (e.Item.DataBoundItem == item.DataBoundItem && e.Item.Checked)
|
|
itemWillbeUnchecked = true;
|
|
}
|
|
|
|
|
|
|
|
if (count == 1 && itemWillbeUnchecked)
|
|
e.Cancel = true;
|
|
|
|
};
|
|
|
|
rcbddAlertType.ItemCheckedChanged += delegate (object sender, RadCheckedListDataItemEventArgs e)
|
|
{
|
|
foreach (RadCheckedListDataItem item in rcbddAlertType.Items)
|
|
DBSettings.updateSettingValue(0, item.Tag.ToString(), item.Checked ? "true" : "false");
|
|
};
|
|
|
|
RadButtonElement button = new RadButtonElement();
|
|
button.Click += delegate(object sender, EventArgs e)
|
|
{
|
|
if (tbPsw.PasswordChar.Equals('*'))
|
|
{
|
|
tbPsw.PasswordChar = tbEmailAddress.PasswordChar;
|
|
}
|
|
else
|
|
{
|
|
tbPsw.PasswordChar = '*';
|
|
}
|
|
};
|
|
button.Padding = new Padding(0, 0, 0, 0);
|
|
button.Margin = new Padding(0, 0, 0, 0);
|
|
button.Image = SubscriberAndUserManager.Properties.Resources.eye2;
|
|
button.Size = new System.Drawing.Size(18, 18);
|
|
RadTextBoxItem tbItem = tbPsw.TextBoxElement.TextBoxItem;
|
|
tbPsw.TextBoxElement.Children.Remove(tbItem);
|
|
StackLayoutElement stackPanel = new StackLayoutElement();
|
|
stackPanel.Orientation = Orientation.Horizontal;
|
|
stackPanel.Margin = new Padding(0, 0, 0, 0);
|
|
stackPanel.Children.Add(button);
|
|
DockLayoutPanel dockPanel = new DockLayoutPanel();
|
|
dockPanel.Children.Add(stackPanel);
|
|
dockPanel.Children.Add(tbItem);
|
|
DockLayoutPanel.SetDock(tbItem, Telerik.WinControls.Layouts.Dock.Left);
|
|
DockLayoutPanel.SetDock(stackPanel, Telerik.WinControls.Layouts.Dock.Right);
|
|
tbPsw.TextBoxElement.Children.Add(dockPanel);
|
|
tbPsw.TextBoxElement.Padding = new Padding(2, 0, 0, 0);
|
|
tbItem.Margin = new Padding(0, 0, 0, 0);
|
|
|
|
this.DB = DB;
|
|
this.DBAlarm = DBAlarm;
|
|
this.DBIcons = DBIcons;
|
|
this.DBSettings = DBSettings;
|
|
|
|
//lbBackupTime.Text = "";
|
|
lbStatus.Text = "";
|
|
backup = new DBbackup(DBuser, DBname, DBserv);
|
|
LoadConfig();
|
|
setLanguage();
|
|
InitVoiceSettingsPanel();
|
|
// update the values with the ones from the DB
|
|
tbEmailAddress.Text = eService.EmailAddress;
|
|
tbPsw.Text = eService.Pass;
|
|
cbEmailServiceEnable.Checked = eService.Enable;
|
|
tbPopServer.Text = eService.PopServer;
|
|
tbPopPort.Value = eService.PopPort;
|
|
tbSmtpServer.Text = eService.SmtpServer;
|
|
tbSmtpPort.Value = eService.SmtpPort;
|
|
cbPopSSLEncryption.Checked = eService.IsPopSSL;
|
|
cbSmtpSSLEncryption.Checked = eService.IsSmtpSSL;
|
|
|
|
txLanIP.Value = DBSettings.getSettingValue(0, "lanLinxServer");
|
|
txNatIP.Value = DBSettings.getSettingValue(0, "natLinxServer");
|
|
txLanSipPort.Value = DBSettings.getSettingValue(0, "lanSipPort");
|
|
txNatSipPort.Value = DBSettings.getSettingValue(0, "natSipPort");
|
|
txLanSigPort.Value = DBSettings.getSettingValue(0, "lanSigPort");
|
|
txNatSigPort.Value = DBSettings.getSettingValue(0, "natSigPort");
|
|
txUdpStart.Value = DBSettings.getSettingValue(0, "rtpStart");
|
|
txUdpEnd.Value = DBSettings.getSettingValue(0, "rtpEnd");
|
|
|
|
tbExceraIP.Value = DBSettings.getSettingValue(0, "lanLinxServer");
|
|
tbExceraPort.Value = DBSettings.getSettingValue(0, "lanSipPort");
|
|
cbEmergency.Checked = IsGPSCheckboxChecked();
|
|
|
|
cbEmergency.ToggleStateChanged += this.cbEmergency_ToggleStateChanged;
|
|
// enable or disable the email settings group
|
|
cbEmailServiceEnable_ToggleStateChanged(cbEmailServiceEnable, null);
|
|
|
|
|
|
ckpollAfterSMS.Checked = PollAfterSMS;
|
|
|
|
if ((MainForm.radioType == RADIOTYPE.HARRIS)||(MainForm.radioType == RADIOTYPE.ATLAS))
|
|
{
|
|
lbPsw.ForeColor = MainForm.HarTextColor;
|
|
lbStatus.ForeColor = MainForm.HarTextColor;
|
|
lbUserName.ForeColor = MainForm.HarTextColor;
|
|
radLabel1.ForeColor = MainForm.HarTextColor;
|
|
this.gbStolenSett.GroupBoxElement.ForeColor = MainForm.HarTextColor;
|
|
this.gbDBbackup.GroupBoxElement.ForeColor = MainForm.HarTextColor;
|
|
this.gbEmailServer.GroupBoxElement.ForeColor = MainForm.HarTextColor;
|
|
this.cbEmailServiceEnable.ButtonElement.TextElement.ForeColor = MainForm.HarTextColor;
|
|
lbType.ForeColor = MainForm.HarTextColor;
|
|
lbIcon.ForeColor = MainForm.HarTextColor;
|
|
lbIconName.ForeColor = MainForm.HarTextColor;
|
|
|
|
this.gbIconManager.GroupBoxElement.ForeColor = MainForm.HarTextColor;
|
|
//this.gbDeleteIcons.GroupBoxElement.ForeColor = MainForm.HarTextColor;
|
|
rbPlaces.ButtonElement.TextElement.ForeColor = MainForm.HarTextColor;
|
|
rbUnits.ButtonElement.TextElement.ForeColor = MainForm.HarTextColor;
|
|
}
|
|
|
|
if (MainForm.radioType == RADIOTYPE.SIMOCO)
|
|
{
|
|
//decide after we see all idea of desing
|
|
}
|
|
ckpollAfterSMS.Visible = MainForm.radioType != RADIOTYPE.LINX && MainForm.radioType != RADIOTYPE.SIMOCO && MainForm.radioType != RADIOTYPE.EXCERA;
|
|
gbStolenSett.Visible = MainForm.radioType != RADIOTYPE.LINX && MainForm.radioType != RADIOTYPE.SIMOCO && MainForm.radioType != RADIOTYPE.EXCERA;
|
|
//send list request
|
|
SendBackupListRequest();
|
|
|
|
//load imagelist for place and units
|
|
LoadImageListUnits();
|
|
//LoadImageListPlaces();
|
|
PopulateUnitsIcons();
|
|
PopulateIconThemes();
|
|
//gbSIPSettings.Visible = MainForm.radioType != RADIOTYPE.SIMOCO;
|
|
gbExceraSipSettings.Visible = MainForm.radioType == RADIOTYPE.EXCERA;
|
|
gbSIPSettings.Visible = !MainForm.hideLinxFeatures;
|
|
gbVoiceSettings.Visible = MainForm.radioType != RADIOTYPE.LISF;
|
|
gbStolenSett.Visible = MainForm.radioType != RADIOTYPE.LISF;
|
|
|
|
|
|
}
|
|
|
|
private string defaultSampleRate = "8000";
|
|
private string defaultBufferMilliseconds = "32";
|
|
private string defaultBitDepth = "16";
|
|
private void InitVoiceSettingsPanel()
|
|
{
|
|
List<int> sampleRate = new List<int>();
|
|
sampleRate.Add(8000);
|
|
sampleRate.Add(44100);
|
|
sampleRate.Add(48000);
|
|
cbSampleRate.DataSource = sampleRate;
|
|
List<int> bitdepth = new List<int>();
|
|
bitdepth.Add(16);
|
|
bitdepth.Add(24);
|
|
bitdepth.Add(32);
|
|
cbBitDepth.DataSource = bitdepth;
|
|
cbSampleRate.SelectedIndex = cbSampleRate.FindString(DBSettings.getSettingValue(0, "sampleRate"));
|
|
txtBufferMilliseconds.Value = Convert.ToDecimal(DBSettings.getSettingValue(0, "bufferMilliseconds"));
|
|
cbBitDepth.SelectedIndex = cbBitDepth.FindString(DBSettings.getSettingValue(0, "bitDepth"));
|
|
}
|
|
public void parseMultiCastData(Int32 opCode,String status)
|
|
{
|
|
switch (opCode)
|
|
{
|
|
case (byte)61:
|
|
updateStaus(status);
|
|
SendBackupListRequest();
|
|
break;
|
|
|
|
case (byte)71:
|
|
updateStaus(status);
|
|
SendBackupListRequest();
|
|
break;
|
|
|
|
case (byte)62:
|
|
updateStaus(status);
|
|
break;
|
|
|
|
case (byte)72:
|
|
updateStaus(status);
|
|
break;
|
|
|
|
case (byte)63:
|
|
updateStaus(status);
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
private ArrayList ListofUnits;
|
|
private void LoadImageListUnits()
|
|
{
|
|
try
|
|
{
|
|
List<Car> ret = DBIcons.getAllUnitIcons();
|
|
|
|
|
|
// check if resource directory exists
|
|
if (!Directory.Exists("resource"))
|
|
{
|
|
Directory.CreateDirectory("resource");
|
|
}
|
|
|
|
// check if resource directory exists
|
|
if (!Directory.Exists("resource/cars"))
|
|
{
|
|
Directory.CreateDirectory("resource/cars");
|
|
}
|
|
|
|
// for every car in the DB
|
|
foreach (Car obj in ret)
|
|
{
|
|
String fileNamePattern = crtIconTheme + "_" + obj.iconPattern;
|
|
|
|
// check if the image exists on the local hard disk
|
|
if (File.Exists(Application.StartupPath
|
|
+ @"\resource\cars\" + crtIconTheme + "_" + obj.iconPattern + ".png") && !obj.iconPattern.StartsWith("custom_"))
|
|
{
|
|
obj.fileName = System.Windows.Forms.Application.StartupPath + @"\resource\cars\"
|
|
+ crtIconTheme + "_" + obj.iconPattern + ".png";
|
|
obj.listFilePath = System.Windows.Forms.Application.StartupPath + @"\resource\cars\"
|
|
+ (crtIconTheme == SafeMobileLib.IconTheme.CLASSIC ? "" : "list_")
|
|
+ crtIconTheme + "_" + obj.iconPattern + ".png";
|
|
}
|
|
else
|
|
{
|
|
// the car icon doesn't exists
|
|
Utils.WriteLine("Fetching icon for unit " + obj.DisplayedName);
|
|
obj.fileName = System.Windows.Forms.Application.StartupPath + @"\resource\cars\"
|
|
+ crtIconTheme + "_" + obj.iconPattern + ".png";
|
|
obj.listFilePath = System.Windows.Forms.Application.StartupPath + @"\resource\cars\"
|
|
+ (crtIconTheme == SafeMobileLib.IconTheme.CLASSIC ? "" : "list_")
|
|
+ crtIconTheme + "_" + obj.iconPattern + ".png";
|
|
|
|
byte[] iconBytes = null;
|
|
|
|
// get the icon from the database if exists or replace it with a default one
|
|
if ((iconBytes = DBIcons.Get_Unit_Image(obj.idx)) == null)
|
|
{
|
|
|
|
// get unknown image from the resources
|
|
System.Reflection.Assembly a = System.Reflection.Assembly.GetExecutingAssembly();
|
|
|
|
using (Stream resFilestream = a.GetManifestResourceStream("SubscriberAndUserManager.Resources.classic_unknown.png"))
|
|
{
|
|
byte[] buffer = new byte[1024];
|
|
using (MemoryStream ms = new MemoryStream())
|
|
{
|
|
while (true)
|
|
{
|
|
int read = resFilestream.Read(buffer, 0, buffer.Length);
|
|
if (read <= 0)
|
|
{
|
|
// reached the end of the resource file
|
|
iconBytes = ms.ToArray();
|
|
break;
|
|
}
|
|
// add read buffer into the memory stream
|
|
ms.Write(buffer, 0, read);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
try
|
|
{
|
|
using (var m = new MemoryStream(iconBytes))
|
|
{
|
|
// save the image received from the database to a png file
|
|
Bitmap bmp = new Bitmap(m);
|
|
bmp.Save(System.Windows.Forms.Application.StartupPath + @"\resource\cars\" + fileNamePattern + ".png", ImageFormat.Png);
|
|
|
|
|
|
// save image for the list if the theme type is not classic
|
|
if (crtIconTheme == SafeMobileLib.IconTheme.PIN)
|
|
{
|
|
(new Bitmap(m)).Save(System.Windows.Forms.Application.StartupPath + @"\resource\cars\" + "list_" + fileNamePattern + ".png", ImageFormat.Png);
|
|
}
|
|
Utils.WriteLine("Done Writing file to folder: " + fileNamePattern, ConsoleColor.DarkGray);
|
|
}
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
SM.Debug("Error write car icon to folder: " + ex.ToString() + "\n" + fileNamePattern);
|
|
}
|
|
}
|
|
}
|
|
|
|
imageListUnits.Images.Clear();
|
|
Image image;
|
|
ListofUnits = new ArrayList();
|
|
//PLACE
|
|
foreach (Car obj in ret)
|
|
ListofUnits.Add(obj);
|
|
//ListofUnits.Sort(new UnitIconsComparer());
|
|
foreach (Car obj in ListofUnits)
|
|
{
|
|
|
|
//Console.WriteLine("Load pic:"+obj.Pic);
|
|
try
|
|
{
|
|
Bitmap bmp = new Bitmap(obj.listFilePath);
|
|
image = bmp;
|
|
imageListUnits.Images.Add(image);
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
Utils.WriteLine("");
|
|
}
|
|
}
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
SM.Debug("Error unit: " + ex.ToString());
|
|
}
|
|
}
|
|
|
|
private void PopulateIconThemes()
|
|
{
|
|
// save which icon should be selected
|
|
int selectedIndex = 0;
|
|
int count = 0;
|
|
iconThemesList = new BindingList<DropListItem>();
|
|
try
|
|
{
|
|
List<SafeMobileLib.DBmanagers.IconTheme> ret = DBIcons.GetIconThemes();
|
|
foreach(SafeMobileLib.DBmanagers.IconTheme theme in ret)
|
|
{
|
|
if (crtIconTheme.ToString().Equals(theme.Prefix))
|
|
{
|
|
Utils.WriteLine(crtIconTheme.ToString() + " | " + theme.Prefix, ConsoleColor.Red);
|
|
selectedIndex = count;
|
|
}
|
|
count++;
|
|
|
|
byte[] iconBytes = null;
|
|
|
|
// get unknown image from the resources
|
|
System.Reflection.Assembly a = System.Reflection.Assembly.GetExecutingAssembly();
|
|
|
|
using (Stream resFilestream = a.GetManifestResourceStream("SubscriberAndUserManager.Resources." + theme.Prefix + "_default.png"))
|
|
{
|
|
byte[] buffer = new byte[1024];
|
|
using (MemoryStream ms = new MemoryStream())
|
|
{
|
|
while (true)
|
|
{
|
|
int read = resFilestream.Read(buffer, 0, buffer.Length);
|
|
if (read <= 0)
|
|
{
|
|
// reached the end of the resource file
|
|
iconBytes = ms.ToArray();
|
|
break;
|
|
}
|
|
// add read buffer into the memory stream
|
|
ms.Write(buffer, 0, read);
|
|
}
|
|
}
|
|
}
|
|
|
|
// save the image received from the database to a png file
|
|
Bitmap bmp = new Bitmap(new MemoryStream(iconBytes));
|
|
Image tmp2 = bmp;
|
|
|
|
DropListItem item = new DropListItem()
|
|
{
|
|
ID = theme.Id,
|
|
Name = theme.Name,
|
|
Prefix = theme.Prefix,
|
|
Image = tmp2
|
|
};
|
|
|
|
iconThemesList.Add(item);
|
|
}
|
|
|
|
// add the datasource for the vehicles ComboBox
|
|
rcbIconThemes.DataSource = iconThemesList;
|
|
|
|
//cbVehName.DataSource = vehicleListNames;
|
|
//cbVehName.DisplayMember = "Name";
|
|
if (rcbIconThemes.Items.Count > selectedIndex)
|
|
{
|
|
rcbIconThemes.SelectedIndex = selectedIndex;
|
|
}
|
|
else if (rcbIconThemes.Items.Count > 0)
|
|
rcbIconThemes.SelectedIndex = 0;
|
|
|
|
}
|
|
catch (Exception ex) {
|
|
Utils.WriteLine(" POPULATE ICON THEMES" + ex.ToString(), ConsoleColor.Red);
|
|
}
|
|
}
|
|
|
|
private void PopulatePlaceIcons()
|
|
{
|
|
cbDeleteIcons.DataSource = ListofPlaces;
|
|
cbDeleteIcons.DisplayMember = "Placename";
|
|
if (ListofPlaces!= null && ListofPlaces.Count > 0)
|
|
{
|
|
cbDeleteIcons.SelectedIndex = 0;
|
|
picBoxDelete.Image = imageListPlaces.Images[0];
|
|
}
|
|
}
|
|
|
|
private void PopulateUnitsIcons()
|
|
{
|
|
cbDeleteIcons.DataSource = ListofUnits;
|
|
cbDeleteIcons.DisplayMember = "DisplayedName";
|
|
if (ListofUnits.Count > 0)
|
|
{
|
|
cbDeleteIcons.SelectedIndex = 0;
|
|
picBoxDelete.Image = imageListUnits.Images[0];
|
|
}
|
|
}
|
|
|
|
private ArrayList ListofPlaces;
|
|
|
|
private static ImageCodecInfo GetEncoderInfo(String mimeType)
|
|
{
|
|
int j;
|
|
ImageCodecInfo[] encoders;
|
|
encoders = ImageCodecInfo.GetImageEncoders();
|
|
for (j = 0; j < encoders.Length; ++j)
|
|
{
|
|
if (encoders[j].MimeType == mimeType)
|
|
return encoders[j];
|
|
}
|
|
return null;
|
|
}
|
|
|
|
private void LoadImageListPlaces()
|
|
{
|
|
try
|
|
{
|
|
List<Place> ret = DBIcons.getAllPlaceIcons();
|
|
// check if resource directory exists
|
|
if (!Directory.Exists("resource"))
|
|
{
|
|
Directory.CreateDirectory("resource");
|
|
}
|
|
|
|
// check if places directory exists
|
|
if (!Directory.Exists("resource/places"))
|
|
{
|
|
Directory.CreateDirectory("resource/places");
|
|
}
|
|
|
|
foreach (Place obj in ret)
|
|
{
|
|
|
|
String placeFileNamePattern = obj.type;
|
|
|
|
// check if the image exists on the local hard disk
|
|
if (System.IO.File.Exists(System.Windows.Forms.Application.StartupPath
|
|
+ @"\resource\places\" + obj.type + ".png"))
|
|
{
|
|
obj.pic = System.Windows.Forms.Application.StartupPath + @"\resource\places\"
|
|
+ obj.type + ".png";
|
|
}
|
|
else
|
|
{
|
|
try
|
|
{
|
|
// the car icon doesn't exists
|
|
Utils.WriteLine("Fetching icon for place " + obj.Type);
|
|
obj.pic = System.Windows.Forms.Application.StartupPath + @"\resource\places\"
|
|
+ obj.type + ".png";
|
|
|
|
byte[] iconBytes = null;
|
|
// get the icon from the database if exists or replace it with a default one
|
|
if ((iconBytes = DBIcons.Get_Place_Image(obj.idx)) == null)
|
|
{
|
|
|
|
// get unknown image from the resources
|
|
System.Reflection.Assembly a = System.Reflection.Assembly.GetExecutingAssembly();
|
|
|
|
using (Stream resFilestream = a.GetManifestResourceStream("Dispatcher.Resources.default.png"))
|
|
{
|
|
byte[] buffer = new byte[1024];
|
|
using (MemoryStream ms = new MemoryStream())
|
|
{
|
|
while (true)
|
|
{
|
|
int read = resFilestream.Read(buffer, 0, buffer.Length);
|
|
if (read <= 0)
|
|
{
|
|
// reached the end of the resource file
|
|
iconBytes = ms.ToArray();
|
|
break;
|
|
}
|
|
// add read buffer into the memory stream
|
|
ms.Write(buffer, 0, read);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
// save the image received from the database to a png file
|
|
Bitmap bmp = new Bitmap(new MemoryStream(iconBytes));
|
|
bmp.Save(System.Windows.Forms.Application.StartupPath + @"\resource\places\" + placeFileNamePattern + ".png", ImageFormat.Png);
|
|
Utils.WriteLine("Done Writing place file to folder -> " + placeFileNamePattern, ConsoleColor.DarkGray);
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
SM.Debug("Error write car icon to folder: " + ex.ToString() + "\n" + placeFileNamePattern);
|
|
}
|
|
}
|
|
}
|
|
|
|
imageListPlaces.Images.Clear();
|
|
Image image;
|
|
ListofPlaces = new ArrayList();
|
|
//PLACE
|
|
foreach (Place obj in ret)
|
|
ListofPlaces.Add(obj);
|
|
//ListofPlaces.Sort(new PlaceIconsComparer());
|
|
foreach (Place obj in ListofPlaces)
|
|
{
|
|
//Console.WriteLine("Load pic on PLACE:" + obj.Pic);
|
|
|
|
// skip this icons because it's not valid
|
|
if (obj.pic.Length < 1)
|
|
continue;
|
|
|
|
Bitmap place = new Bitmap(obj.pic);
|
|
image = place;
|
|
imageListPlaces.Images.Add(place);
|
|
imageListPlaces.ImageSize = place.Size;
|
|
}
|
|
|
|
cbDeleteIcons.DataSource = ListofPlaces;
|
|
cbDeleteIcons.DisplayMember = "Type";
|
|
if (ret.Count > 0 && imageListPlaces.Images.Count > 0)
|
|
{
|
|
cbDeleteIcons.SelectedIndex = 0;
|
|
picBoxDelete.Image = imageListPlaces.Images[0];
|
|
}
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
SM.Debug("Error place: " + ex.ToString());
|
|
}
|
|
}
|
|
|
|
private void setLanguage()
|
|
{
|
|
gbEmailServer.Text = MainForm.returnLNGString("email");
|
|
lbUserName.Text = "Email address";//MainForm.returnLNGString("usename");
|
|
lbPsw.Text = MainForm.returnLNGString("pass");
|
|
gbDBbackup.Text = MainForm.returnLNGString("dbbackup");
|
|
radLabel1.Text = MainForm.returnLNGString("stat")+":";
|
|
btnBackup.Text = MainForm.returnLNGString("backup");
|
|
btnRestore.Text = MainForm.returnLNGString("restore");
|
|
cbEmailServiceEnable.Text = "Email Server Settings";//MainForm.returnLNGString("email");
|
|
gbStolenSett.Text = MainForm.returnLNGString("stolenSettings");
|
|
btACKAll.Text = MainForm.returnLNGString("alarmALLACK");
|
|
radLabel5.Text = MainForm.returnLNGString("disableStolen");
|
|
|
|
lbAddIcon.Text = MainForm.returnLNGString("gbAddIcons");
|
|
gbIconManager.Text = MainForm.returnLNGString("gbIconManager");
|
|
//gbDeleteIcons.Text = MainForm.returnLNGString("gbDeleteIcons");
|
|
//lbIconName.Text = MainForm.returnLNGString("lbIconName");
|
|
//lbIcon.Text = MainForm.returnLNGString("lbIconFormDatabase");
|
|
btBrowser.Text = MainForm.returnLNGString("btBrowser");
|
|
btAddIcon.Text = MainForm.returnLNGString("btAddIcon");
|
|
btDeleteIcon.Text = MainForm.returnLNGString("btDeleteIcon");
|
|
|
|
lbType.Text = MainForm.returnLNGString("lbType");
|
|
rbUnits.Text = MainForm.returnLNGString("rbUnits");
|
|
rbPlaces.Text = MainForm.returnLNGString("rbPlaces");
|
|
btSaveEmail.Text = MainForm.returnLNGString("saveemail");
|
|
cbEmailServiceEnable.Text = MainForm.returnLNGString("EmailServerSettings");
|
|
cbPopSSLEncryption.Text = MainForm.returnLNGString("POPSSL");
|
|
cbSmtpSSLEncryption.Text = MainForm.returnLNGString("SMTPSSL");
|
|
radLabel4.Text = MainForm.returnLNGString("IconThemePreview");
|
|
lbIconName.Text = MainForm.returnLNGString("IconName");
|
|
label1.Text = MainForm.returnLNGString("DeleteDatabaseIcons");
|
|
ckpollAfterSMS.Text = MainForm.returnLNGString("SendPOLL");
|
|
lbIcon.Text = MainForm.returnLNGString("icon1");
|
|
btCheckPopServer.Text = MainForm.returnLNGString("Test");
|
|
btCheckSmtpServer.Text = MainForm.returnLNGString("Test");
|
|
btnRefresh.Text = MainForm.returnLNGString("Refresh");
|
|
lbUserName.Text = MainForm.returnLNGString("EmailAddress");
|
|
radLabel3.Text = MainForm.returnLNGString("POP");
|
|
gbSIPSettings.Text = MainForm.returnLNGString("LinxSettings");
|
|
#region excera labels
|
|
gbExceraSipSettings.Text = MainForm.returnLNGString("exceraSipSettings");
|
|
tbExceraPort.Text = MainForm.returnLNGString("sipPort");
|
|
btnSaveExceraSettings.Text = MainForm.returnLNGString("save");
|
|
#endregion
|
|
radLabel2.Text = MainForm.returnLNGString("SMTP");
|
|
gbVoiceSettings.Text = MainForm.returnLNGString("voiceSettings");
|
|
lbSampleRate.Text = MainForm.returnLNGString("sampleRate");
|
|
lbBufferMilliseconds.Text = MainForm.returnLNGString("bufferMilliseconds");
|
|
lbBitDepth.Text = MainForm.returnLNGString("bitDepth");
|
|
toolTipHelp.SetToolTip(this.cbSampleRate, MainForm.returnLNGString("sampleRateToolTip"));
|
|
toolTipHelp.SetToolTip(this.cbBitDepth, MainForm.returnLNGString("bitDepthToolTip"));
|
|
toolTipHelp.SetToolTip(this.txtBufferMilliseconds, MainForm.returnLNGString("bufferMillisecondsToolTip"));
|
|
btnSaveVoiceSettings.Text = MainForm.returnLNGString("save");
|
|
btnResetVoiceSettings.Text = MainForm.returnLNGString("reset");
|
|
}
|
|
|
|
private void btnBackup_Click(object sender, EventArgs e)
|
|
{
|
|
BackupButtonPressed = true;
|
|
RefreshButtonPressed = false;
|
|
SendBackupRequest();
|
|
updateStaus("Backup message sent to Application server.");
|
|
waitingForm = new WaitingForm();
|
|
waitingForm.SetLabels(MainForm.returnLNGString("plsWait"), MainForm.returnLNGString("prfBk"));
|
|
|
|
}
|
|
|
|
private void btnRestore_Click(object sender, EventArgs e)
|
|
{
|
|
if (listBackups.SelectedIndex != -1)
|
|
{
|
|
Console.WriteLine(listBackups.Items[listBackups.SelectedIndex].Text);
|
|
SendRestoreRequest(listBackups.Items[listBackups.SelectedIndex].Text);
|
|
updateStaus("Restore message sent to Application server.");
|
|
waitingForm = new WaitingForm();
|
|
waitingForm.SetLabels(MainForm.returnLNGString("plsWait"), MainForm.returnLNGString("prfRst"));
|
|
waitingForm.ShowDialog();
|
|
}
|
|
else
|
|
{
|
|
CustomMessageBox.Show(CustomMessageBoxType.exclamation, "Please select one file for restore!", MainForm.returnLNGString("err"));
|
|
}
|
|
}
|
|
|
|
private void LoadConfig()
|
|
{
|
|
try
|
|
{
|
|
source = new IniConfigSource(MainForm.CFG_FILE);
|
|
|
|
if (source.Configs["Database"] == null)
|
|
source.Configs.Add("Database");
|
|
|
|
lastBackup = source.Configs["Database"].Get("backupTime");
|
|
eService = DB.GetEmailServiceSettings();
|
|
PollAfterSMS = DB.GetPollSMSServiceSettings();
|
|
}
|
|
catch (Exception e)
|
|
{
|
|
Console.WriteLine(e.Message + " " + e.StackTrace + " " + e.Source);
|
|
}
|
|
}
|
|
|
|
public void SaveConfig()
|
|
{
|
|
try
|
|
{
|
|
SM.Debug("Saving backup time :" + DateTime.Now);
|
|
source = new IniConfigSource(MainForm.CFG_FILE);
|
|
DateTime time = DateTime.Now;
|
|
string format = "MMM ddd d HH:mm yyyy";
|
|
lastBackup = time.ToString(format);
|
|
|
|
if (source.Configs["Database"] == null)
|
|
source.Configs.Add("Database");
|
|
|
|
source.Configs["Database"].Set("lastBackup", lastBackup);
|
|
source.Save();
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
Console.WriteLine(ex.ToString());
|
|
}
|
|
}
|
|
|
|
public Boolean SaveEmailServiceSettings()
|
|
{
|
|
Boolean validanswer = true;
|
|
EmailService eser = new EmailService(tbEmailAddress.Text, tbPsw.Text, cbEmailServiceEnable.Checked);
|
|
eser.IsPopSSL = cbPopSSLEncryption.Checked;
|
|
eser.IsSmtpSSL = cbSmtpSSLEncryption.Checked;
|
|
eser.PopPort = (Int32)tbPopPort.Value;
|
|
eser.PopServer = tbPopServer.Text;
|
|
eser.SmtpPort = (Int32)tbSmtpPort.Value;
|
|
eser.SmtpServer = tbSmtpServer.Text;
|
|
eser.LastEmailTime = 0;
|
|
|
|
DB.SetEmailServiceSettings(eser);
|
|
|
|
return validanswer;
|
|
}
|
|
|
|
private void SendBackupListRequest()
|
|
{
|
|
if(MainForm.udp != null)
|
|
MainForm.udp.Send(Utils.Convert_text_For_multicast("#0.0#53#1#"), Utils.Convert_text_For_multicast("#0.0#53#1#").Length);
|
|
}
|
|
private void SendBackupRequest()
|
|
{
|
|
if (MainForm.udp != null)
|
|
MainForm.udp.Send(Utils.Convert_text_For_multicast("#0.0#51#1#"), Utils.Convert_text_For_multicast("#0.0#51#1#").Length);
|
|
}
|
|
private void SendRestoreRequest(string filename)
|
|
{
|
|
if (MainForm.udp != null)
|
|
MainForm.udp.Send(Utils.Convert_text_For_multicast("#0.0#52#" + filename + "#"), Utils.Convert_text_For_multicast("#0.0#52#" + filename + "#").Length);
|
|
}
|
|
|
|
delegate void UpdateList(string fileNames);
|
|
private void updateList(string fileNames)
|
|
{
|
|
if (this.listBackups.InvokeRequired)
|
|
{
|
|
UpdateList d = new UpdateList(updateList);
|
|
listBackups.Invoke(d, new object[] { fileNames });
|
|
}
|
|
else
|
|
{
|
|
listBackups.Items.Clear();
|
|
string[] fileNameArr = fileNames.Split(";".ToCharArray());
|
|
if (fileNameArr != null && fileNameArr.Length > 0)
|
|
{
|
|
foreach (string fName in fileNameArr)
|
|
{
|
|
if (fName != "")
|
|
{
|
|
listBackups.Items.Add(new RadListDataItem(fName));
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
delegate void UpdateStatus(string text);
|
|
private void updateStaus(string text)
|
|
{
|
|
// if (this.lbStatus.InvokeRequired)
|
|
// {
|
|
// UpdateList d = new UpdateList(updateStaus);
|
|
// lbStatus.Invoke(d, new object[] { text });
|
|
// }
|
|
// else
|
|
// {
|
|
//lbStatus.Text = text;
|
|
this.Invoke((MethodInvoker)delegate ()
|
|
{
|
|
if (text.Contains(".tar"))
|
|
{
|
|
string[] backupList = text.Substring(0, text.Length - 1).Split(";".ToCharArray());
|
|
listBackups.Items.Clear();
|
|
foreach (string bk in backupList)
|
|
listBackups.Items.Add(bk);
|
|
if (BackupButtonPressed) lbStatus.Text = MainForm.returnLNGString("backup") + MainForm.returnLNGString("done");
|
|
if (RefreshButtonPressed) lbStatus.Text = MainForm.returnLNGString("bkupLoaded");
|
|
if (waitingForm != null && !waitingForm.IsDisposed)
|
|
waitingForm.Close();
|
|
}
|
|
else if (text.Contains(MainForm.returnLNGString("failed")) || text.Contains(MainForm.returnLNGString("done")))
|
|
{
|
|
lbStatus.Text = text;
|
|
if (!waitingForm.IsDisposed)
|
|
waitingForm.Close();
|
|
}
|
|
});
|
|
//}
|
|
}
|
|
|
|
WaitingForm wf = null;
|
|
private void btACKAll_Click(object sender, EventArgs e)
|
|
{
|
|
Thread t = new Thread(AckAlarmsWorker);
|
|
t.Start();
|
|
wf = new WaitingForm();
|
|
if (t.IsAlive)
|
|
wf.ShowDialog();
|
|
|
|
}
|
|
|
|
private void AckAlarmsWorker()
|
|
{
|
|
Thread.Sleep(100);
|
|
sqlResponse resp = DBAlarm.ACKALLalarms();
|
|
this.Invoke((MethodInvoker)delegate ()
|
|
{
|
|
if (wf != null)
|
|
{
|
|
wf.Hide();
|
|
wf.Close();
|
|
}
|
|
if (resp == sqlResponse.done)
|
|
CustomMessageBox.Show(CustomMessageBoxType.check, MainForm.returnLNGString("alarmack"), MainForm.returnLNGString("done"));
|
|
else
|
|
CustomMessageBox.Show(CustomMessageBoxType.exclamation, MainForm.returnLNGString("alarmErr"), MainForm.returnLNGString("err"));
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private void btnRefresh_Click(object sender, EventArgs e)
|
|
{
|
|
RefreshButtonPressed = true;
|
|
BackupButtonPressed = false;
|
|
SendBackupListRequest();
|
|
updateStaus(MainForm.returnLNGString("bkupRefresh"));
|
|
}
|
|
|
|
private Bitmap bmpIcon = null;
|
|
|
|
private void btBrowser_Click(object sender, EventArgs e)
|
|
{
|
|
try
|
|
{
|
|
OpenFileDialog openFileDialogImage = new OpenFileDialog();
|
|
|
|
//openFileDialogImage.Filter = "Bitmap Files (.bmp)|*.bmp|All Files (*.*)|*.*";
|
|
openFileDialogImage.Filter = "Png Files (.png)|*.png|All Files (*.*)|*.*";
|
|
openFileDialogImage.FilterIndex = 1;
|
|
openFileDialogImage.Title = MainForm.returnLNGString("imagesize");
|
|
|
|
Boolean userClickedOK = false;
|
|
if (openFileDialogImage.ShowDialog() == DialogResult.OK) userClickedOK = true;
|
|
|
|
bmpIcon = null;
|
|
if (userClickedOK)
|
|
{
|
|
//SM.Debug("File name to load is:"+openFileDialogImage.FileName);
|
|
bmpIcon = new Bitmap(openFileDialogImage.FileName);
|
|
/*
|
|
//if ((bmpIcon.Size.Width != 32) || (bmpIcon.Size.Height != 32))
|
|
{
|
|
DialogResult dr = CustomMessageBox.Show(CustomMessageBoxType.exclamation, MainForm.returnLNGString("dimensionisnotcorect"), MainForm.returnLNGString("errorloadImage"));
|
|
bmpIcon = null;
|
|
}
|
|
else*/
|
|
{
|
|
picBoxAdd.Image = Utils.ScaleImage(bmpIcon, 32, 32);
|
|
}
|
|
}
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
SM.Debug("Error on load new image:"+ex.ToString());
|
|
}
|
|
}
|
|
|
|
private void btDeleteIcon_Click(object sender, EventArgs e)
|
|
{
|
|
try
|
|
{
|
|
DialogResult dr;
|
|
if (rbPlaces.IsChecked)
|
|
dr = CustomMessageBox.Show(CustomMessageBoxType.check, String.Format(MainForm.returnLNGString("aredelplaceType"), cbDeleteIcons.SelectedItem.Text), MainForm.returnLNGString("confdelete"), true);
|
|
else
|
|
dr = CustomMessageBox.Show(CustomMessageBoxType.check, String.Format(MainForm.returnLNGString("aredelunitType"), cbDeleteIcons.SelectedItem.Text), MainForm.returnLNGString("confdelete"), true);
|
|
if (dr == DialogResult.Yes)
|
|
{
|
|
// if (rbPlaces.IsChecked && imageListPlaces.Images.Count > 1)
|
|
// {
|
|
// DBIcons.Delete_Place_Icons(((PlaceIcons)ListofPlaces[cbDeleteIcons.SelectedIndex]).Id, ((PlaceIcons)ListofPlaces[0]).Id);
|
|
// LoadImageListPlaces();
|
|
// PopulatePlaceIcons();
|
|
// }
|
|
// else
|
|
// {
|
|
if (imageListUnits.Images.Count == 1)
|
|
{
|
|
CustomMessageBox.Show(CustomMessageBoxType.exclamation, String.Format(MainForm.returnLNGString("noDeleteIcon")), MainForm.returnLNGString("err"));
|
|
LoadImageListUnits();
|
|
PopulateUnitsIcons();
|
|
}
|
|
else if (((Car)ListofUnits[cbDeleteIcons.SelectedIndex]).idx == ((Car)ListofUnits[0]).idx)
|
|
{
|
|
DBIcons.Delete_Units_Icons(((Car)ListofUnits[cbDeleteIcons.SelectedIndex]).idx, ((Car)ListofUnits[cbDeleteIcons.SelectedIndex + 1]).idx);
|
|
LoadImageListUnits();
|
|
PopulateUnitsIcons();
|
|
}
|
|
else
|
|
{
|
|
DBIcons.Delete_Units_Icons(((Car)ListofUnits[cbDeleteIcons.SelectedIndex]).idx, ((Car)ListofUnits[0]).idx);
|
|
LoadImageListUnits();
|
|
PopulateUnitsIcons();
|
|
}
|
|
}
|
|
|
|
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
SM.Debug("Error on delete icons:" + ex.ToString());
|
|
}
|
|
}
|
|
|
|
private void rbPlaces_ToggleStateChanged(object sender, StateChangedEventArgs args)
|
|
{
|
|
if (rbPlaces.IsChecked)
|
|
{
|
|
SM.Debug("Check Place Icons");
|
|
PopulatePlaceIcons();
|
|
}
|
|
}
|
|
|
|
private void rbUnits_ToggleStateChanged(object sender, StateChangedEventArgs args)
|
|
{
|
|
if (rbUnits.IsChecked)
|
|
{
|
|
SM.Debug("Check Unit Icons");
|
|
PopulateUnitsIcons();
|
|
}
|
|
}
|
|
|
|
private void cbDeleteIcons_SelectedIndexChanged(object sender, Telerik.WinControls.UI.Data.PositionChangedEventArgs e)
|
|
{
|
|
try
|
|
{
|
|
if (cbDeleteIcons.SelectedIndex > -1)
|
|
{
|
|
if (rbPlaces.IsChecked) picBoxDelete.Image = imageListPlaces.Images[cbDeleteIcons.SelectedIndex];
|
|
else picBoxDelete.Image = imageListUnits.Images[cbDeleteIcons.SelectedIndex];
|
|
}
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
SM.Debug("Erorr laod picture: " + ex.ToString());
|
|
}
|
|
}
|
|
|
|
private void btAddIcon_Click(object sender, EventArgs e)
|
|
{
|
|
string iconName = tbNewIconName.Text;
|
|
if (!iconName.All(Char.IsLetterOrDigit))
|
|
{
|
|
CustomMessageBox.Show(CustomMessageBoxType.exclamation, MainForm.returnLNGString("onlyNumberOrLetters"), MainForm.returnLNGString("err"));
|
|
return;
|
|
}
|
|
//check if name is combobox
|
|
|
|
if (tbNewIconName.Text.Length > 0)
|
|
{
|
|
//ListofUnits
|
|
if (rbPlaces.IsChecked)
|
|
{
|
|
Boolean elementFind = false;
|
|
foreach (PlaceIcons obj in ListofPlaces)
|
|
if (obj.Placename.ToUpper().CompareTo(tbNewIconName.Text.ToUpper()) == 0)
|
|
{
|
|
elementFind = true;
|
|
break;
|
|
}
|
|
if (elementFind)
|
|
CustomMessageBox.Show(CustomMessageBoxType.exclamation, String.Format(MainForm.returnLNGString("ExistingName"), MainForm.returnLNGString("placelabel"), tbNewIconName.Text), MainForm.returnLNGString("duplicateName"));
|
|
else
|
|
{
|
|
try
|
|
{
|
|
if (bmpIcon != null)
|
|
{
|
|
// save the 32x32 image
|
|
bmpIcon = (Bitmap)picBoxAdd.Image;
|
|
|
|
MemoryStream ms = new MemoryStream();
|
|
bmpIcon.Save(ms, ImageFormat.Png);
|
|
byte[] bitmapData = ms.ToArray();
|
|
DBIcons.Insert_Place_Icons(tbNewIconName.Text, bitmapData);
|
|
CustomMessageBox.Show(CustomMessageBoxType.check, MainForm.returnLNGString("NewplaceADD"), MainForm.returnLNGString("done"));
|
|
LoadImageListPlaces();
|
|
PopulatePlaceIcons();
|
|
}
|
|
else CustomMessageBox.Show(CustomMessageBoxType.exclamation, MainForm.returnLNGString("YouneedtoLoadImage"), MainForm.returnLNGString("err"));
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
SM.Debug("Error add new Icon:"+ex.ToString());
|
|
CustomMessageBox.Show(CustomMessageBoxType.exclamation, MainForm.returnLNGString("dberr"), MainForm.returnLNGString("err"));
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
Boolean elementFind = false;
|
|
foreach (Car obj in ListofUnits)
|
|
if (obj.Name.ToUpper().CompareTo(tbNewIconName.Text.ToUpper()) == 0)
|
|
{
|
|
elementFind = true;
|
|
break;
|
|
}
|
|
if (elementFind)
|
|
CustomMessageBox.Show(CustomMessageBoxType.exclamation, String.Format(MainForm.returnLNGString("ExistingName"), MainForm.returnLNGString("unitlabel"), tbNewIconName.Text), MainForm.returnLNGString("duplicateName"));
|
|
else
|
|
{
|
|
try
|
|
{
|
|
if (bmpIcon != null)
|
|
{
|
|
// save the 32x32 image
|
|
bmpIcon = (Bitmap)picBoxAdd.Image;
|
|
|
|
MemoryStream ms = new MemoryStream();
|
|
bmpIcon.Save(ms, ImageFormat.Png);
|
|
byte[] bitmapData = ms.ToArray();
|
|
DBIcons.Insert_Units_Icons(tbNewIconName.Text, bitmapData);
|
|
CustomMessageBox.Show(CustomMessageBoxType.check, MainForm.returnLNGString("NewuniticonADD"), MainForm.returnLNGString("done"));
|
|
LoadImageListUnits();
|
|
PopulateUnitsIcons();
|
|
}
|
|
else CustomMessageBox.Show(CustomMessageBoxType.exclamation, MainForm.returnLNGString("YouneedtoLoadImage"), MainForm.returnLNGString("err"));
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
SM.Debug("Error add new Icon:" + ex.ToString());
|
|
CustomMessageBox.Show(CustomMessageBoxType.exclamation, MainForm.returnLNGString("dberr"), MainForm.returnLNGString("err"));
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
private void btSaveEmail_Click(object sender, EventArgs e)
|
|
{
|
|
if (SaveEmailServiceSettings())
|
|
{
|
|
CustomMessageBox.Show(CustomMessageBoxType.check, MainForm.returnLNGString("emailindb"), MainForm.returnLNGString("done"));
|
|
((MainForm)this.Parent.Parent).SendRestart();
|
|
|
|
MainForm.HasEmailSettings = cbEmailServiceEnable.Checked;
|
|
}
|
|
}
|
|
|
|
private void ckpollAfterSMS_ToggleStateChanged(object sender, StateChangedEventArgs args)
|
|
{
|
|
if (ckpollAfterSMS.Checked != PollAfterSMS)
|
|
{
|
|
PollAfterSMS = ckpollAfterSMS.Checked;
|
|
if (PollAfterSMS) DB.SetPollAfterSMSSettings(1);
|
|
else DB.SetPollAfterSMSSettings(0);
|
|
}
|
|
}
|
|
|
|
|
|
/// <summary>
|
|
/// Enable or disable the group for email settings when the checkbox is activated or not
|
|
/// </summary>
|
|
private void cbEmailServiceEnable_ToggleStateChanged(object sender, StateChangedEventArgs args)
|
|
{
|
|
if (cbEmailServiceEnable.Checked)
|
|
gbEmailServer.Enabled = true;
|
|
else
|
|
{
|
|
gbEmailServer.Enabled = false;
|
|
MainForm.HasEmailSettings = false;
|
|
}
|
|
|
|
|
|
DB.SetEmailServiceEnable(cbEmailServiceEnable.Checked);
|
|
}
|
|
|
|
|
|
/// <summary>
|
|
/// Enable or disable the Save Email settings button every time the text from a radTextBox
|
|
/// had changed
|
|
/// </summary>
|
|
/// <param name="sender">RadTextBox which had changed its text</param>
|
|
private void email_textboxes_TextChanged(object sender, EventArgs e)
|
|
{
|
|
if (((RadTextBox)sender).Text.Length == 0)
|
|
btSaveEmail.Enabled = false;
|
|
else if ((RadTextBox)sender == tbEmailAddress && !IsValidEmail(tbEmailAddress.Text))
|
|
btSaveEmail.Enabled = false;
|
|
else
|
|
{
|
|
if (tbPopServer.Text.Length > 0 && tbSmtpServer.Text.Length > 0
|
|
&& tbPsw.Text.Length > 0 && IsValidEmail(tbEmailAddress.Text))
|
|
btSaveEmail.Enabled = true;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
/// <summary>
|
|
/// Verify if an email address is a valid email address, in therm of
|
|
/// well written, with '@' and '.' in the wright place
|
|
/// </summary>
|
|
/// <param name="email">Email which needs to be checked</param>
|
|
/// <returns>True if the email is a valid one, or false otherwise</returns>
|
|
bool IsValidEmail(string email)
|
|
{
|
|
bool isEmail = Regex.IsMatch(email, @"\A(?:[a-z0-9!#$%&'*+/=?^_`{|}~-]+(?:\.[a-z0-9!#$%&'*+/=?^_`{|}~-]+)*@(?:[a-z0-9](?:[a-z0-9-]*[a-z0-9])?\.)+[a-z0-9](?:[a-z0-9-]*[a-z0-9])?)\Z", RegexOptions.IgnoreCase);
|
|
return isEmail;
|
|
}
|
|
|
|
|
|
|
|
private void btCheckEmailServer_Click(object sender, EventArgs e)
|
|
{
|
|
// disable the button
|
|
btCheckPopServer.Enabled = false;
|
|
btCheckSmtpServer.Enabled = false;
|
|
//((RadButton)sender).Enabled = false;
|
|
|
|
if (sender is RadButton && (RadButton)sender == btCheckPopServer)
|
|
{
|
|
new Thread(delegate()
|
|
{
|
|
emailServerSSL.CheckPopServerSettings(tbPopServer.Text, (Int32)tbPopPort.Value,
|
|
tbEmailAddress.Text, tbPsw.Text, cbPopSSLEncryption.Checked);
|
|
}).Start();
|
|
|
|
}
|
|
else if (sender is RadButton && (RadButton)sender == btCheckSmtpServer)
|
|
{
|
|
new Thread(delegate()
|
|
{
|
|
emailServerSSL.CheckSmtpServerSettings(tbSmtpServer.Text, (Int32)tbSmtpPort.Value,
|
|
tbEmailAddress.Text, tbPsw.Text, cbSmtpSSLEncryption.Checked);
|
|
}).Start();
|
|
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Bind the icon and the name to the combobox
|
|
/// </summary>
|
|
/// <param name="sender"></param>
|
|
/// <param name="args"></param>
|
|
private void rcbIconThemes_ItemDataBound(object sender, ListItemDataBoundEventArgs args)
|
|
{
|
|
// display the text and image for each item in the comboBox
|
|
DropListItem item = (DropListItem)args.NewItem.DataBoundItem;
|
|
args.NewItem.Text = item.Name;
|
|
args.NewItem.Image = Utils.ScaleImage(item.Image, 16,16);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Execute this method every time the combobox value had changed
|
|
/// </summary>
|
|
/// <param name="sender"></param>
|
|
/// <param name="e"></param>
|
|
private void rcbIconThemes_SelectedIndexChanged(object sender, Telerik.WinControls.UI.Data.PositionChangedEventArgs e)
|
|
{
|
|
DropListItem item = (DropListItem)iconThemesList[e.Position];
|
|
crtIconTheme = SafeMobileLib.IconTheme.GetIconType(item.Prefix);
|
|
SubscriberAndUserManager.MainForm.iconThemeType = crtIconTheme;
|
|
|
|
|
|
int selectedIndex = cbDeleteIcons.SelectedIndex;
|
|
LoadImageListUnits();
|
|
PopulateUnitsIcons();
|
|
|
|
cbDeleteIcons.SelectedIndex = selectedIndex;
|
|
}
|
|
|
|
private void pbHint_MouseEnter(object sender, EventArgs e)
|
|
{
|
|
DisplayToolTip();
|
|
}
|
|
|
|
private void pbHint_MouseLeave(object sender, EventArgs e)
|
|
{
|
|
toolTipHelp.Hide(pbHint);
|
|
}
|
|
|
|
|
|
private void DisplayToolTip()
|
|
{
|
|
String unitsExample = MainForm.returnLNGString("toolTip1") + Environment.NewLine +
|
|
MainForm.returnLNGString("toolTip2");
|
|
toolTipHelp.Show( unitsExample, pbHint, 150000);
|
|
}
|
|
|
|
private async void btnSaveSIPSettings_Click(object sender, EventArgs e)
|
|
{
|
|
btDiscoverSip.Enabled = btTestSip.Enabled = btnSaveSIPSettings.Enabled = false;
|
|
picLoading.Visible = true;
|
|
string natip = txNatIP.Text.Replace(" ", "");
|
|
|
|
string lanip = txLanIP.Text.Replace(" ", "");
|
|
if (!controlGateways.IsValidIP(natip))
|
|
{
|
|
CustomMessageBox.Show(CustomMessageBoxType.exclamation, "Invalid NAT IP", MainForm.returnLNGString("err"));
|
|
return;
|
|
}
|
|
if (!controlGateways.IsValidIP(lanip))
|
|
{
|
|
CustomMessageBox.Show(CustomMessageBoxType.exclamation, "Invalid LAN IP", MainForm.returnLNGString("err"));
|
|
return;
|
|
}
|
|
|
|
if (controlGateways.IsValidIP(natip) || controlGateways.IsValidIP(lanip))
|
|
{
|
|
try
|
|
{
|
|
string response = await Utils.CallWebServerAsync($"http://{txLanIP.Value.ToString().Replace(" ", "")}:{txLanSigPort.Value}/status");
|
|
if (response == "not_available")
|
|
{
|
|
if (Utils.PingHost(lanip))
|
|
{
|
|
picLoading.Visible = false;
|
|
btDiscoverSip.Enabled = btTestSip.Enabled = btnSaveSIPSettings.Enabled = true;
|
|
CustomMessageBox.Show(CustomMessageBoxType.exclamation, "This IP is already used!", MainForm.returnLNGString("err"));
|
|
return;
|
|
}
|
|
}
|
|
var data = new NameValueCollection();
|
|
try
|
|
{
|
|
bool resp = await Utils.PostRequestAsync($"http://{txLanIP.Value.ToString().Replace(" ", "")}:{txLanSigPort.Value}/update-config/" +
|
|
$"port-range/{txUdpStart.Value}/{txUdpEnd.Value}/sip-port/{txLanSipPort.Value}", data);
|
|
|
|
data = new NameValueCollection();
|
|
resp = await Utils.PostRequestAsync($"http://{txLanIP.Value.ToString().Replace(" ", "")}:{txLanSigPort.Value}/database/{MainForm.dbIpforSip}/{MainForm.DBPort}", data);
|
|
}
|
|
catch(Exception ex)
|
|
{
|
|
CustomMessageBox.Show(CustomMessageBoxType.exclamation, MainForm.returnLNGString("postReqError"), MainForm.returnLNGString("err"));
|
|
Utils.WriteLine(ex.ToString(), ConsoleColor.Red);
|
|
}
|
|
DBSettings.updateSettingValue(0, "lanLinxServer", lanip);
|
|
DBSettings.updateSettingValue(0, "natLinxServer", natip);
|
|
DBSettings.updateSettingValue(0, "lanSipPort", txLanSipPort.Value.ToString());
|
|
DBSettings.updateSettingValue(0, "natSipPort", txNatSipPort.Value.ToString());
|
|
DBSettings.updateSettingValue(0, "lanSigPort", txLanSigPort.Value.ToString());
|
|
DBSettings.updateSettingValue(0, "natSigPort", txNatSigPort.Value.ToString());
|
|
DBSettings.updateSettingValue(0, "rtpStart", txUdpStart.Value.ToString());
|
|
DBSettings.updateSettingValue(0, "rtpEnd", txUdpEnd.Value.ToString());
|
|
MainForm.RestartSipLink = $"http://{txLanIP.Value.ToString().Replace(" ", "")}:{txLanSigPort.Value}/restart-sip";
|
|
MainForm.reloadDataLink = $"http://{txLanIP.Value.ToString().Replace(" ", "")}:{txLanSigPort.Value}/reload-data";
|
|
picLoading.Visible = false;
|
|
btDiscoverSip.Enabled = btTestSip.Enabled = btnSaveSIPSettings.Enabled = true;
|
|
CustomMessageBox.Show(CustomMessageBoxType.check, MainForm.returnLNGString("SipSettingsSaved"), MainForm.returnLNGString("done"));
|
|
}
|
|
catch
|
|
{
|
|
CustomMessageBox.Show(CustomMessageBoxType.exclamation, MainForm.returnLNGString("SipSettingsError"), MainForm.returnLNGString("err"));
|
|
}
|
|
}
|
|
picLoading.Visible = false;
|
|
btDiscoverSip.Enabled = btTestSip.Enabled = btnSaveSIPSettings.Enabled = true;
|
|
|
|
}
|
|
|
|
private bool isValidIPAndPort(string input)
|
|
{
|
|
bool ret = false;
|
|
Regex regStr = new Regex(@"^\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}:\d{1,5}$");
|
|
ret = regStr.IsMatch(input);
|
|
return ret;
|
|
}
|
|
|
|
private void tb_KeyPress(object sender, KeyPressEventArgs e)
|
|
{
|
|
if ((e.KeyChar >= '0' && e.KeyChar <= '9') || e.KeyChar == (char)Keys.Back)
|
|
; // ok
|
|
else
|
|
e.Handled = true;
|
|
}
|
|
|
|
private async void btTestSip_Click(object sender, EventArgs e)
|
|
{
|
|
btDiscoverSip.Enabled = btTestSip.Enabled = btnSaveSIPSettings.Enabled = false;
|
|
picLoading.Visible = true;
|
|
string response = await Utils.CallWebServerAsync($"http://{txLanIP.Value.ToString().Replace(" ","")}:{txLanSigPort.Value}/status");
|
|
picLoading.Visible = false;
|
|
btDiscoverSip.Enabled = btTestSip.Enabled = btnSaveSIPSettings.Enabled = true;
|
|
if (response != "not_available")
|
|
{
|
|
CustomMessageBox.Show(CustomMessageBoxType.check, "Web Server response ok!", MainForm.returnLNGString("done"));
|
|
checkdb(response);
|
|
}
|
|
else
|
|
CustomMessageBox.Show(CustomMessageBoxType.exclamation, "Web Server not available!", MainForm.returnLNGString("err"));
|
|
|
|
}
|
|
|
|
private async void btDiscoverSip_Click(object sender, EventArgs e)
|
|
{
|
|
btDiscoverSip.Enabled = btTestSip.Enabled = btnSaveSIPSettings.Enabled = false;
|
|
picLoading.Visible = true;
|
|
//discover
|
|
//1. ip from db for sip server
|
|
Utils.WriteLine($"Testing {txLanIP.Value.ToString().Replace(" ", "")}...");
|
|
string response = await Utils.CallWebServerAsync($"http://{txLanIP.Value.ToString().Replace(" ", "")}:{txLanSigPort.Value}/status");
|
|
if (response == "not_available")
|
|
//2. see Utils.GetWebServerAddress function
|
|
response = await Utils.GetWebServerAddressAsync();
|
|
parseResponse(response);
|
|
picLoading.Visible = false;
|
|
btDiscoverSip.Enabled = btTestSip.Enabled = btnSaveSIPSettings.Enabled = true;
|
|
}
|
|
|
|
private void parseResponse(string response)
|
|
{
|
|
try
|
|
{
|
|
JObject o = JObject.Parse(response);
|
|
string lanIP = o["data"]["network"]["privateIp"].ToString();
|
|
string rtpstart = o["data"]["ports"]["rtpstart"].ToString();
|
|
string rtpend = o["data"]["ports"]["rtpend"].ToString();
|
|
string publicIp = o["data"]["network"]["publicIp"].ToString();
|
|
string sipPort = o["data"]["ports"]["udpbindaddr"].ToString().Split(":".ToCharArray())[1];
|
|
txLanIP.Value = lanIP;
|
|
txNatIP.Value = publicIp;
|
|
txUdpStart.Value = rtpstart;
|
|
txUdpEnd.Value = rtpend;
|
|
txLanSipPort.Value = sipPort;
|
|
if (txNatSipPort.Value.ToString() == "")
|
|
txNatSipPort.Value = sipPort;
|
|
if (txNatSigPort.Value.ToString() == "")
|
|
txNatSigPort.Value = txLanSigPort.Value;
|
|
}
|
|
catch { Utils.WriteLine("Error on parse server response!", ConsoleColor.Red); }
|
|
}
|
|
|
|
private async void checkdb(string response)
|
|
{
|
|
try
|
|
{
|
|
JObject o = JObject.Parse(response);
|
|
string databases = o["data"]["database"].ToString();
|
|
if(databases.IndexOf(MainForm.dbIpforSip) == -1)
|
|
{
|
|
CustomMessageBox.Show(CustomMessageBoxType.exclamation, MainForm.returnLNGString("dbSettChg"), MainForm.returnLNGString("warning"));
|
|
NameValueCollection data = new NameValueCollection();
|
|
bool resp = await Utils.PostRequestAsync($"http://{txLanIP.Value.ToString().Replace(" ", "")}:{txLanSigPort.Value}/database/{MainForm.dbIpforSip}/{MainForm.DBPort}", data);
|
|
}
|
|
}
|
|
catch { Utils.WriteLine("Error on checking database!", ConsoleColor.Red); }
|
|
}
|
|
|
|
private void txLanSipPort_TextChanged(object sender, EventArgs e)
|
|
{
|
|
txNatSipPort.Text = txLanSipPort.Text;
|
|
}
|
|
|
|
private void controlSettings_Load(object sender, EventArgs e)
|
|
{
|
|
btnRefresh.PerformClick();
|
|
btAddIcon.Enabled = (tbNewIconName.Text != "");
|
|
}
|
|
|
|
private void tbNewIconName_KeyPress(object sender, KeyPressEventArgs e)
|
|
{
|
|
if (char.IsLetter(e.KeyChar) || char.IsDigit(e.KeyChar) || e.KeyChar == (char)Keys.Back)
|
|
; // ok
|
|
else
|
|
e.Handled = true;
|
|
}
|
|
|
|
private void tbNewIconName_TextChanged(object sender, EventArgs e)
|
|
{
|
|
btAddIcon.Enabled = (tbNewIconName.Text != "");
|
|
}
|
|
|
|
|
|
#region voice settings
|
|
private void btnResetVoiceSettings_Click(object sender, EventArgs e)
|
|
{
|
|
cbSampleRate.SelectedIndex = cbSampleRate.FindString(defaultSampleRate);
|
|
txtBufferMilliseconds.Value = Convert.ToDecimal(defaultBufferMilliseconds);
|
|
cbBitDepth.SelectedIndex = cbBitDepth.FindString(defaultBitDepth);
|
|
|
|
}
|
|
|
|
private void btnSaveVoiceSettings_Click(object sender, EventArgs e)
|
|
{
|
|
List<sqlResponse> resp = new List<sqlResponse>();
|
|
resp.Add(DBSettings.updateSettingValue(0, "sampleRate", cbSampleRate.SelectedValue.ToString()));
|
|
resp.Add(DBSettings.updateSettingValue(0, "bufferMilliseconds", txtBufferMilliseconds.Value.ToString()));
|
|
resp.Add(DBSettings.updateSettingValue(0, "bitDepth", cbBitDepth.SelectedValue.ToString()));
|
|
if (resp.Contains(sqlResponse.SQLerror))
|
|
CustomMessageBox.Show(CustomMessageBoxType.exclamation, MainForm.returnLNGString("errorSavingSettings"), MainForm.returnLNGString("voiceSettings"));
|
|
else
|
|
CustomMessageBox.Show(CustomMessageBoxType.check, MainForm.returnLNGString("settingsSaveSuccess"), MainForm.returnLNGString("voiceSettings"));
|
|
}
|
|
#endregion
|
|
|
|
|
|
#region excera events
|
|
private void btnSaveExceraSettings_Click(object sender, EventArgs e)
|
|
{
|
|
try
|
|
{
|
|
DBSettings.updateSettingValue(0, "lanLinxServer", tbExceraIP.Value.ToString().Replace(" " ,""));
|
|
DBSettings.updateSettingValue(0, "lanSipPort", tbExceraPort.Value.ToString());
|
|
CustomMessageBox.Show(CustomMessageBoxType.check, "Settings saved.", "SIP Server Settings");
|
|
}
|
|
catch
|
|
{
|
|
CustomMessageBox.Show(CustomMessageBoxType.exclamation, "Error on saving settings.", "SIP Server Settings");
|
|
}
|
|
|
|
}
|
|
|
|
#endregion
|
|
|
|
private void cbEmergency_ToggleStateChanged(object sender, StateChangedEventArgs args)
|
|
{
|
|
if (cbEmergency.Checked)
|
|
{
|
|
DBSettings.updateSettingValue(0, DBsettingsManager.EMERGENCY_ONLY_KEY, "true");
|
|
}
|
|
else
|
|
{
|
|
DBSettings.updateSettingValue(0, DBsettingsManager.EMERGENCY_ONLY_KEY, "false");
|
|
}
|
|
}
|
|
|
|
private Boolean IsGPSCheckboxChecked()
|
|
{
|
|
try
|
|
{
|
|
string EmergencyOnly = DBSettings.getSettingValue(0, DBsettingsManager.EMERGENCY_ONLY_KEY);
|
|
|
|
if (EmergencyOnly.Trim().Equals("false")|| EmergencyOnly.Trim().Equals(""))
|
|
{
|
|
return false;
|
|
}
|
|
else
|
|
{
|
|
return true;
|
|
}
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
Utils.WriteLine("Error GPSCheckboxChecked: " + ex.ToString(), ConsoleColor.Red);
|
|
return false;
|
|
}
|
|
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// used in report form in order to store the imeis and the scIDs of the units and groups
|
|
/// </summary>
|
|
public class DropListItem : RadListDataItem
|
|
{
|
|
public Image Image { get; set; }
|
|
public String Name { get; set; }
|
|
public String Prefix { get; set; }
|
|
public int ID { get; set; }
|
|
|
|
public DropListItem()
|
|
{
|
|
this.Image = null;
|
|
this.Name = "";
|
|
this.Prefix = "";
|
|
this.ID = 0;
|
|
}
|
|
}
|
|
}
|