/*
* Created by SharpDevelop.
* User: jeroen
* Date: 03/14/2013
* Time: 21:44
*
* To change this template use Tools | Options | Coding | Edit Standard Headers.
*/
namespace ComicRackWebViewer
{
using BCR;
using cYo.Projects.ComicRack.Engine.Database;
using cYo.Projects.ComicRack.Viewer;
using Nancy.Hosting.Self;
using System;
using System.Collections.Generic;
using System.Data.SQLite;
using System.IO;
using System.Linq;
using System.Net;
using System.Net.Sockets;
using System.Security.Principal;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;
///
/// MainForm provides the user interface of this plugin.
///
public partial class MainForm : Form
{
private static ManualResetEvent mre = new ManualResetEvent(false);
private static NancyHost host;
private int? actualPort;
private Guid libraryGuid;
private bool cacheSizesInitialized = false;
public MainForm()
{
//
// The InitializeComponent() call is required for Windows Forms designer support.
//
InitializeComponent();
string path = Path.Combine(BCRInstaller.Instance.InstallFolder, "about.html");
webBrowserAbout.Url = new Uri("file://" + path);
textBoxPort.Text = Database.Instance.GlobalSettings.webserver_port.ToString();
actualPort = Database.Instance.GlobalSettings.webserver_port;
textBoxUrlBase.Text = Database.Instance.GlobalSettings.url_base;
string s = "cYo.Projects.ComicRack.Engine.Database.ComicLibraryListItem";
ComicListItem item = Program.Database.ComicLists.GetItems(false).FirstOrDefault((ComicListItem cli) => cli.GetType().ToString() == s);
if (item != null)
{
libraryGuid = item.Id;
}
FillComboHomeList();
FillComboUsers();
SetEnabledState();
}
private string LocalIPAddress()
{
IPHostEntry host;
string localIP = "";
host = Dns.GetHostEntry(Dns.GetHostName());
foreach (IPAddress ip in host.AddressList)
{
if (ip.AddressFamily == AddressFamily.InterNetwork)
{
localIP = ip.ToString();
break;
}
}
return localIP;
}
private void SetEnabledState()
{
if (buttonStart == null)
{
return;
}
buttonStart.Enabled = actualPort.HasValue;
textBoxPort.Enabled = host == null;
textBoxUrlBase.Enabled = host == null;
if (host == null)
{
buttonStart.Text = "Start";
labelStatus.Text = "The web server is not running.";
}
else
{
buttonStart.Text = "Stop";
labelStatus.Text = "The web server is running.\nOpen it on your tablet via http://" + LocalIPAddress() + ":" + textBoxPort.Text + "\nNB: don't forget to allow ComicRack in your firewall.";
}
System.Windows.Input.Mouse.SetCursor(null);
}
public void StartService()
{
textBoxPort.Enabled = false;
textBoxUrlBase.Enabled = false;
System.Windows.Input.Mouse.SetCursor(System.Windows.Input.Cursors.Wait);
Task.Factory.StartNew(() => LoadService());
labelStatus.Text = "Starting";
}
public void LoadService()
{
if (host != null)
{
StopService();
}
try
{
int port = actualPort.Value;
Uri uri = new Uri(String.Format("http://localhost:{0}/", port));
HostConfiguration configuration = new HostConfiguration();
configuration.RewriteLocalhost = true;
host = new NancyHost(new Bootstrapper(), new Uri[] { uri });
host.Start();
this.BeginInvoke(new Action(SetEnabledState));
mre.Reset();
mre.WaitOne();
host.Stop();
}
catch (Exception e)
{
System.Windows.Forms.MessageBox.Show("Error in url binding:\n" + e.ToString());
StopService();
throw;
}
finally
{
host = null;
this.BeginInvoke(new Action(SetEnabledState));
}
}
private static IEnumerable GetLocalIPs()
{
return Dns.GetHostAddresses(Dns.GetHostName()).Where(x => x.AddressFamily == AddressFamily.InterNetwork).Select(x => x.ToString());
}
public void StopService()
{
mre.Set();
}
private bool IsCurrentlyRunningAsAdmin()
{
bool isAdmin = false;
WindowsIdentity currentIdentity = WindowsIdentity.GetCurrent();
if (currentIdentity != null)
{
WindowsPrincipal pricipal = new WindowsPrincipal(currentIdentity);
isAdmin = pricipal.IsInRole(WindowsBuiltInRole.Administrator);
pricipal = null;
}
return isAdmin;
}
///////////////////////////////////////////////////////////////////////
/// WebServer TabPage
void ButtonStartClick(object sender, System.EventArgs e)
{
if (host != null)
{
StopService();
}
else
{
if (IsCurrentlyRunningAsAdmin())
{
Database.Instance.GlobalSettings.webserver_port = actualPort.HasValue ? actualPort.Value : 8080;
Database.Instance.GlobalSettings.url_base = textBoxUrlBase.Text;
Database.Instance.GlobalSettings.Save();
StartService();
}
else
{
System.Windows.Forms.MessageBox.Show("Sorry!, you must be running ComicRack with administrator privileges.");
}
}
}
void TextBoxPortTextChanged(object sender, EventArgs e)
{
if (string.IsNullOrEmpty(textBoxPort.Text))
{
return;
}
int x;
if (int.TryParse(textBoxPort.Text, out x))
{
actualPort = x;
}
else
{
actualPort = null;
}
SetEnabledState();
}
///////////////////////////////////////////////////////////////////////
/// Users TabPage
void FillComboUsers()
{
comboBoxUsers.Items.Clear();
using (SQLiteDataReader reader = Database.Instance.ExecuteReader("SELECT id, username FROM user;"))
{
while (reader.Read())
{
comboBoxUsers.Items.Add(new ComboUserItem(reader.GetString(1), reader.GetInt32(0)));
}
}
if (comboBoxUsers.Items.Count > 0)
comboBoxUsers.SelectedIndex = 0;
}
void FillComboHomeList()
{
comboTreeHomeList.Nodes.Clear();
var nodes = Program.Database.ComicLists.Select(c => c.ToComboTreeNode());
comboTreeHomeList.Nodes.AddRange(nodes);
if (comboTreeHomeList.Nodes.Count > 0)
{
comboTreeHomeList.SelectedNode = comboTreeHomeList.Nodes[0];
}
//Guid id = new Guid(string);
//var list = Program.Database.ComicLists.FindItem(id);
}
void ButtonAddUserClick(object sender, EventArgs e)
{
InputBoxValidation validation = delegate(string val) {
if (val.Length < 4)
return "The username must contain at least 4 characters.";
if (UserDatabase.GetUserId(val) != -1)
return "The username already exists.";
return "";
};
string name = "";
var result = InputBox.Show("Add User", "Enter username (min. 4 characters):", ref name, validation);
if (result == System.Windows.Forms.DialogResult.OK)
{
UserDatabase.AddUser(name, "1234567890");
FillComboUsers();
comboBoxUsers.SelectedIndex = comboBoxUsers.FindString(name);
System.Windows.Forms.MessageBox.Show("User added.\nDon't forget to set a password and choose a home list.", "Add User", MessageBoxButtons.OK, MessageBoxIcon.Information);
ButtonChangePasswordClick(null, null);
}
}
void ButtonRemoveUserClick(object sender, System.EventArgs e)
{
ComboUserItem item = (ComboUserItem)comboBoxUsers.SelectedItem;
if (item == null)
{
return;
}
if (DialogResult.Yes == System.Windows.Forms.MessageBox.Show("Are you sure you want to remove user '"+item.Text+"'?", "Remove user", MessageBoxButtons.YesNo, MessageBoxIcon.Question, MessageBoxDefaultButton.Button2))
{
// remove user
UserDatabase.RemoveUser(item.UserId);
System.Windows.Forms.MessageBox.Show("User removed.", "Remove User", MessageBoxButtons.OK, MessageBoxIcon.Information);
FillComboUsers();
}
}
void ButtonChangePasswordClick(object sender, EventArgs e)
{
ComboUserItem item = (ComboUserItem)comboBoxUsers.SelectedItem;
if (item == null)
{
return;
}
// Password Strength: http://xkcd.com/936/
InputBoxValidation validation = delegate(string val) {
if (val.Length < 8)
return "Password must contain at least 8 characters.";
return "";
};
string password = "";
if (DialogResult.OK == InputBox.Show("Change Password", "Enter a new password (min. 8 characters):", ref password, validation))
{
// change password
UserDatabase.SetPassword(item.UserId, password);
}
}
void ComboTreeHomeListSelectedNodeChanged(object sender, EventArgs e)
{
ComboUserItem item = (ComboUserItem)comboBoxUsers.SelectedItem;
if (item == null)
{
return;
}
if (comboTreeHomeList.SelectedNode != null)
{
string listId = comboTreeHomeList.SelectedNode.Tag.ToString();
Database.Instance.ExecuteNonQuery("UPDATE user_settings SET home_list_id='" + listId + "' WHERE user_id=" + item.UserId + ";");
}
}
void ComboBoxUsersSelectedIndexChanged(object sender, EventArgs e)
{
// Apply values to previously selected user.
// Show values for current user.
ComboUserItem item = (ComboUserItem)comboBoxUsers.SelectedItem;
if (item == null)
{
return;
}
using (SQLiteDataReader reader = Database.Instance.ExecuteReader("SELECT id, username, fullname, home_list_id, use_comicrack_progress FROM user JOIN user_settings ON user.id=user_settings.user_id WHERE user.id = " + item.UserId + " LIMIT 1;"))
{
if (reader.Read())
{
textBoxUsername.Text = reader.GetString(1);
if (!reader.IsDBNull(2))
textBoxFullName.Text = reader.GetString(2);
else
textBoxFullName.Text = "";
Guid listId;
if (!reader.IsDBNull(3))
{
try
{
listId = new Guid(reader.GetString(3));
// Check if list still exists, if not, select Library and update database
var list = Program.Database.ComicLists.FindItem(listId);
if (list == null)
{
listId = libraryGuid;
}
}
catch (Exception ex)
{
// invalid Guid format or reader.GetString(3) failed, just ignore and use main library list...
Console.WriteLine(ex.ToString());
listId = libraryGuid;
}
}
else
{
listId = libraryGuid;
}
checkBoxUseProgressFromComicRack.Checked = (reader.GetInt32(4) != 0);
comboTreeHomeList.SelectedNode = comboTreeHomeList.Nodes.FirstOrDefault((ComboTreeNode ctn) => ctn.Tag.Equals(listId));
}
}
}
void ButtonClearPageCacheClick(object sender, EventArgs e)
{
var cursor = this.Cursor;
this.Cursor = Cursors.WaitCursor;
ImageCache.Instance.ClearPageCache();
UpdateCacheSizes();
this.Cursor = cursor;
}
void TextBoxFullNameValidated(object sender, EventArgs e)
{
ComboUserItem item = (ComboUserItem)comboBoxUsers.SelectedItem;
if (item == null)
{
return;
}
UserDatabase.SetFullName(item.UserId, ((System.Windows.Forms.TextBox)sender).Text);
}
public void UpdateCacheSizes()
{
labelCacheSize.Text = String.Format("Used cache size: Pages {0} MB / Thumbnails {1} MB", (int)(ImageCache.Instance.GetPageCacheSize()/(1024*1024)), (int)(ImageCache.Instance.GetThumbnailsCacheSize()/(1024*1024)));
}
void ButtonClearThumbnailsCacheClick(object sender, EventArgs e)
{
var cursor = this.Cursor;
this.Cursor = Cursors.WaitCursor;
ImageCache.Instance.ClearThumbnailsCache();
UpdateCacheSizes();
this.Cursor = cursor;
}
void TabControlSelectedIndexChanged(object sender, EventArgs e)
{
if (tabControl.SelectedIndex == 2 && !cacheSizesInitialized)
{
cacheSizesInitialized = true;
labelCacheSize.Text = "Calculating cache size....";
var cursor = this.Cursor;
this.Cursor = Cursors.WaitCursor;
UpdateCacheSizes();
this.Cursor = cursor;
}
}
void CheckBoxUseProgressFromComicRackCheckedChanged(object sender, EventArgs e)
{
ComboUserItem item = (ComboUserItem)comboBoxUsers.SelectedItem;
if (item == null)
{
return;
}
Database.Instance.ExecuteNonQuery("UPDATE user_settings SET use_comicrack_progress = " + (checkBoxUseProgressFromComicRack.Checked ? "1" : "0") + " WHERE user_id=" + item.UserId + ";");
}
}
// System.Resources.MissingManifestResourceException: Could not find any resources appropriate for the specified culture or the neutral culture.
// http://stackoverflow.com/questions/2058441/could-not-find-any-resources-appropriate-for-the-specified-culture-or-the-neutra
// To resolve this problem, move all of the other class definitions so that they appear after the form's class definition.
public class ComboUserItem
{
public string Text { get; set; }
public int UserId { get; set; }
public ComboUserItem(string text, int userid)
{
Text = text;
UserId = userid;
}
public override string ToString()
{
return Text;
}
}
public static class ComboTreeNodeExtensions
{
public static ComboTreeNode ToComboTreeNode(this ComicListItem x)
{
ComboTreeNode node = new ComboTreeNode(x.Name);
node.Tag = x.Id;
ComicListItemFolder folderList = x as ComicListItemFolder;
if (folderList != null)
{
node.Nodes.AddRange(folderList.Items.Select(c => c.ToComboTreeNode()));
}
return node;
}
}
}