//
// Text2Mambo - convert HTML to mambo CMS
// Copyright (C) 2009-2011 John Janssen
// http://www.travelisfun.org
//
// This program is free software; you can redistribute it and/or modify
// it any way you want as long as the above copyright statement is maintained.
//
// 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.
//
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Drawing;
using System.Data;
using System.Linq;
using System.Security;
using System.Text;
using System.Windows.Forms;
using System.IO;
using System.Threading;
using System.Diagnostics;
using System.Reflection;
using Microsoft.Win32;
using Text2Mambo.Tools;
using TIFTools;
namespace Text2Mambo.Controls
{
public partial class UCSyncOnline : MyUserControl
{
enum COPYMETHOD
{
CopyAll,
CopySizeDiffers,
CopyTimeDiffers,
CopySizeTimeDiffers
}
enum WORKERSTATUS
{
Start,
TryLogin,
CheckFolders,
CollectFileInfo,
CopyFiles,
Finished
}
private Collection<FileObject> files = new Collection<FileObject>();
private class SynchronizeObject
{
public Collection<String> RemoteFolders = new Collection<string>();
public Collection<FileObject> RemoteFiles = new Collection<FileObject>();
public WORKERSTATUS WorkerStatus = WORKERSTATUS.Start;
public COPYMETHOD CopyMethod = COPYMETHOD.CopyAll;
public Collection<FileObject> LocalFiles;
public String RemoteImportFolder;
public String RemoteImageBaseFolder;
private FTPCredentials credentials = null;
public BackgroundWorker worker = null;
public FTPTools ftpTools = new FTPTools();
public Dictionary<String, Collection<FTPFileInfo>> RemoteFileInfo = new Dictionary<string, Collection<FTPFileInfo>>();
public SynchronizeObject(Collection<FileObject> files)
{
LocalFiles = files;
}
public FTPCredentials Credentials
{
set { credentials = value; }
get { return credentials; }
}
public void AddRemotePath(String folder)
{
folder = folder.Replace('\\', '/');
if (!RemoteFolders.Contains(folder))
RemoteFolders.Add(folder);
}
/// <summary>
/// This is a bastard of a method.
/// It looks if for the corresponding local file a file on the server exist.
/// This file should be in the RemoteFileInfo dictionary
/// So mapping something like:
/// Local remote
/// relative images\2011september\image001.jpg images\2011september\image001.jpg
/// prefix c:\websites\apache\htdocs\mambo ftp.travelisfun.org/htdocs/mambo/images
/// </summary>
/// <param name="fo"></param>
/// <returns></returns>
public FTPFileInfo FindRemoteFile(FileObject fo)
{
// The first is finding the correct dictionary entry, mapping the remote path
Collection<FTPFileInfo> list;
try
{
list = RemoteFileInfo[Path.GetDirectoryName(fo.RemoteFilename)];
String fn = Path.GetFileName(fo.FullFilename);
var ffi = (from a in list where a.Name == fn select a).First();
return ffi;
}
catch
{
return null;
}
}
}
private SynchronizeObject syncObject = null;
public UCSyncOnline()
{
InitializeComponent();
}
/// <summary>
///
/// </summary>
/// <returns></returns>
public override String ToString()
{
return "Sync online";
}
/// <summary>
///
/// </summary>
public override void Closing()
{
base.Closing();
}
private delegate void ClearListDelegate();
public void ClearList()
{
files.Clear();
if (checkedListBox1.InvokeRequired)
this.BeginInvoke(new ClearListDelegate(ClearList), null);
else
checkedListBox1.Items.Clear();
}
private delegate void RefreshListViewDelegate();
private void RefreshListView()
{
if (checkedListBox1.InvokeRequired)
{
this.BeginInvoke(new RefreshListViewDelegate(RefreshListView), null);
}
else
{
checkedListBox1.BeginUpdate();
checkedListBox1.Items.Clear();
foreach (FileObject fo in files)
{
int index = checkedListBox1.Items.Add(fo);
checkedListBox1.SetItemChecked(index, fo.Process);
}
checkedListBox1.EndUpdate();
}
}
/// <summary>
/// Adding a file to the upload file list.
/// </summary>
/// <param name="filename"></param>
/// <param name="type"></param>
public void AddFile(String filename, FileObject.FileType type)
{
foreach (FileObject fo in files)
{
if (fo.Filename == filename)
return;
}
files.Add(new FileObject(filename, type));
RefreshListView();
}
/// <summary>
/// Adding a file to the upload file list.
/// </summary>
/// <param name="filename"></param>
/// <param name="absPath"></param>
/// <param name="type"></param>
public void AddFile(String filename, String absPath, FileObject.FileType type)
{
foreach (FileObject fo in files)
{
if (fo.Filename == filename)
return;
}
files.Add(new FileObject(filename, absPath, type));
RefreshListView();
}
/// <summary>
/// Adding files to the upload file list.
/// </summary>
/// <param name="filenames"></param>
/// <param name="type"></param>
public void AddFiles(String[] filenames, FileObject.FileType type)
{
foreach (String s in filenames)
{
files.Add(new FileObject(s, type));
}
RefreshListView();
}
/// <summary>
///
/// </summary>
private void ReadRegistry()
{
textBoxLocalImageBase.Text = ProgramSettings.GetRegValue(@"SyncOnline\LocalImageBase", MyGenericTools.GetApacheRootPath());
textBoxRemoteImportFolder.Text = ProgramSettings.GetRegValue(@"SyncOnline\ImportFolder", "/htdocs/mambo");
textBoxRemoteImageBase.Text = ProgramSettings.GetRegValue(@"SyncOnline\ImageBase", "/htdocs/mambo/images");
int i = ProgramSettings.GetRegValue(@"SyncOnline\CopySetting", 0);
radioButtonCopyAlways.Checked = (i == 0);
radioButtonCopySizeDiff.Checked = (i == 1);
radioButtonSizeAndTime.Checked = (i == 2);
}
/// <summary>
///
/// </summary>
private void WriteRegistry()
{
ProgramSettings.SetRegValue(@"SyncOnline\LocalImageBase", textBoxLocalImageBase.Text);
ProgramSettings.SetRegValue(@"SyncOnline\ImportFolder", textBoxRemoteImportFolder.Text);
ProgramSettings.SetRegValue(@"SyncOnline\ImageBase", textBoxRemoteImageBase.Text);
int i = 0;
if (radioButtonCopyAlways.Checked)
i = 0;
else if (radioButtonCopySizeDiff.Checked)
i = 1;
else if (radioButtonSizeAndTime.Checked)
i = 2;
ProgramSettings.SetRegValue(@"SyncOnline\CopySetting", i);
}
/// <summary>
///
/// </summary>
/// <param name="Enabled"></param>
private void EnableExportButtons(bool Enabled)
{
buttonSyncOnline.Enabled = Enabled;
}
/// <summary>
///
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void buttonSyncOnline_Click(object sender, EventArgs e)
{
WriteRegistry();
if (backgroundWorker.IsBusy)
{
if (MessageBox.Show("A copy transaction is already running.\x0D\x0A" +
"Should this acion be cancelled?",
"Text2Mambo",
MessageBoxButtons.YesNo,
MessageBoxIcon.Question) == DialogResult.No)
{
return;
}
backgroundWorker.CancelAsync();
while (backgroundWorker.IsBusy)
Thread.Sleep(100);
}
listBoxStatus.Items.Clear();
toolStripStatusLabel1.Text = "Synchronize running";
// Set those fileobject.process property to false if the
// object is not checked in the checkedlistbox.
foreach (Object o in checkedListBox1.Items)
{
FileObject fo = o as FileObject;
if (fo.Process)
{
if (!checkedListBox1.CheckedItems.Contains(o))
fo.Process = false;
}
}
// No determine the full path of each file and fill in the fileinfo.
foreach (FileObject fo in files)
{
if (fo.Process)
{
if (!fo.SetInfo(textBoxLocalImageBase.Text))
{
UpdateStatus("Can't find file: " + fo.FullPath);
fo.Process = false;
}
else
{
UpdateStatus("Added file: " + fo.FullPath);
}
}
}
syncObject = new SynchronizeObject(files);
syncObject.RemoteImportFolder = textBoxRemoteImportFolder.Text;
syncObject.RemoteImageBaseFolder = textBoxRemoteImageBase.Text;
syncObject.Credentials = MainForm.FtpLogin.ftpCredentials;
syncObject.ftpTools.ReportStatus = UpdateStatus;
if (radioButtonCopyAlways.Checked)
syncObject.CopyMethod = COPYMETHOD.CopyAll;
else if (radioButtonCopySizeDiff.Checked)
syncObject.CopyMethod = COPYMETHOD.CopySizeDiffers;
else if (radioButtonSizeAndTime.Checked)
syncObject.CopyMethod = COPYMETHOD.CopySizeTimeDiffers;
backgroundWorker.RunWorkerAsync(syncObject);
}
/// <summary>
///
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void buttonFolderBrowse_Click(object sender, EventArgs e)
{
folderBrowserDlg.RootFolder = Environment.SpecialFolder.Desktop;
folderBrowserDlg.SelectedPath = textBoxLocalImageBase.Text;
if (folderBrowserDlg.ShowDialog() == DialogResult.OK)
{
textBoxLocalImageBase.Text = folderBrowserDlg.SelectedPath;
WriteRegistry();
}
}
private void UpdateStatus(String line)
{
UpdateStatus(line, -1, 0);
}
private delegate void AddStatusDelegate(String line, int maxPos, int curPos);
private void UpdateStatus(String line, int maxPos, int curPos)
{
if (listBoxStatus.InvokeRequired)
{
listBoxStatus.Invoke(new AddStatusDelegate(UpdateStatus), new Object[] { line, maxPos, curPos });
}
else
{
if (maxPos != -1)
{
toolStripStatusLabel2.Text = line;
toolStripProgressBar1.Maximum = maxPos;
toolStripProgressBar1.Value = curPos;
line = String.Format("{0} Done {1}%", line, (curPos * 100) / maxPos);
}
listBoxStatus.SelectedIndex = listBoxStatus.Items.Add(line);
//listBoxStatus.Update();
}
}
/// <summary>
///
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void UCSyncOnline_Load(object sender, EventArgs e)
{
BackColor = ProgramSettings.TabPageBackColor;
ResizeToParent();
ReadRegistry();
webBrowser.AllowNavigation = false;
toolStripStatusLabel1.Text = String.Empty;
toolStripStatusLabel2.Text = String.Empty;
toolTip1.SetToolTip(webBrowser, "Read this help text to understand what this software does, a little bit then.");
toolTip1.SetToolTip(listBoxStatus, "The status of the synchronizing process.");
toolTip1.SetToolTip(textBoxRemoteImageBase, "Remote paths must be written with forward slaces.");
toolTip1.SetToolTip(textBoxRemoteImportFolder, "The folder where the import.php script is located.");
panel1.Left = checkedListBox1.Left + checkedListBox1.Width - 1;
panel1.Top = checkedListBox1.Top;
panel1.Height = checkedListBox1.Height;
listBoxStatus.Top = checkedListBox1.Top + checkedListBox1.Height - 1;
listBoxStatus.Left = checkedListBox1.Left;
listBoxStatus.Width = checkedListBox1.Width + panel1.Width - 1;
SetWebbrowserText();
// If the webbrowser.Visible is set the true in the designer then
// the Load event is not fired correctly.
webBrowser.Visible = true;
}
/// <summary>
///
/// </summary>
private void SetWebbrowserText()
{
webBrowser.SetWebbrowserText(Assembly.GetExecutingAssembly(), "SyncOnline.htm");
if (webBrowser.DocumentText.Length == 0)
{
webBrowser.DocumentText = @"<html><body>Help text is not found.</body></html>";
}
}
/// <summary>
///
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void backgroundWorker_DoWork(object sender, DoWorkEventArgs e)
{
BackgroundWorker worker = sender as BackgroundWorker;
SynchronizeObject syncObj = e.Argument as SynchronizeObject;
syncObj.worker = worker;
syncObj.ftpTools.ReportStatus = UpdateStatus;
WORKERSTATUS[] workerSequence = new WORKERSTATUS[]
{
WORKERSTATUS.Start,
WORKERSTATUS.TryLogin,
WORKERSTATUS.CheckFolders,
WORKERSTATUS.CollectFileInfo,
WORKERSTATUS.CopyFiles,
WORKERSTATUS.Finished
};
int sequenceIndex = 0;
do
{
if (worker.CancellationPending)
{
e.Cancel = true;
}
else
{
switch (workerSequence[sequenceIndex])
{
case WORKERSTATUS.Start:
workerStart(syncObj);
break;
case WORKERSTATUS.TryLogin:
workerLogin(syncObj);
break;
case WORKERSTATUS.CheckFolders:
WorkerCheckFolders(syncObj);
break;
case WORKERSTATUS.CollectFileInfo:
WorkerCollectFileInfo(syncObj);
break;
case WORKERSTATUS.CopyFiles:
WorkerCopyFiles(syncObj);
syncObj.WorkerStatus = WORKERSTATUS.Finished;
break;
}
if (++sequenceIndex >= workerSequence.Length)
break;
}
} while (!e.Cancel && syncObj.WorkerStatus != WORKERSTATUS.Finished);
// delete the Sync object.
syncObj = null;
}
/// <summary>
///
/// </summary>
/// <param name="syncObj"></param>
private void workerStart(SynchronizeObject syncObj)
{
syncObj.WorkerStatus = WORKERSTATUS.TryLogin;
return;
}
/// <summary>
///
/// </summary>
/// <param name="syncObj"></param>
/// <returns></returns>
private bool workerLogin(SynchronizeObject syncObj)
{
UpdateStatus(String.Format("Login in using: {0}, {1}",
syncObj.Credentials.Host, syncObj.Credentials.Username));
try
{
syncObj.ftpTools.ListDirectory(syncObj.Credentials, "/");
}
catch (Exception ex)
{
UpdateStatus("Failed login: " + ex.Message);
syncObj.WorkerStatus = WORKERSTATUS.Finished;
return false;
}
return true;
}
/// <summary>
///
/// </summary>
/// <param name="syncObj"></param>
private void WorkerCheckFolders(SynchronizeObject syncObj)
{
foreach (FileObject fo in syncObj.LocalFiles)
{
if (fo.Type == FileObject.FileType.Configuration)
{
fo.RemoteFilename = Path.Combine(syncObj.RemoteImportFolder, Path.GetFileName(fo.FullFilename));
syncObj.AddRemotePath(syncObj.RemoteImportFolder);
}
else if (fo.Type == FileObject.FileType.ImageFile)
{
String imagePath = MyGenericTools.SpecialCombine(syncObj.RemoteImageBaseFolder, fo.Filename);
imagePath = Path.GetDirectoryName(imagePath);
fo.RemoteFilename = Path.Combine(imagePath, Path.GetFileName(fo.FullFilename));
syncObj.AddRemotePath(imagePath);
}
}
// Create all the folders that are needed.
// No check if they already exists.
foreach (String folder in syncObj.RemoteFolders)
{
try
{
syncObj.ftpTools.MkDir(syncObj.Credentials, folder);
}
catch
{
// do nothing.
}
}
syncObj.WorkerStatus = WORKERSTATUS.CollectFileInfo;
}
/// <summary>
/// Retrieve
/// </summary>
/// <param name="syncObj"></param>
private void WorkerCollectFileInfo(SynchronizeObject syncObj)
{
if (syncObj.CopyMethod == COPYMETHOD.CopyAll)
return;
foreach (String folder in syncObj.RemoteFolders)
{
if (syncObject.worker.CancellationPending)
return;
// retrieve the directionary information fro all the entries in the folder.
syncObj.RemoteFileInfo[folder] = syncObj.ftpTools.GetFolderListInfo(syncObj.Credentials, folder);
}
}
/// <summary>
///
/// </summary>
/// <param name="syncObj"></param>
private void WorkerCopyFiles(SynchronizeObject syncObj)
{
foreach (FileObject fo in syncObj.LocalFiles)
{
if (syncObj.worker.CancellationPending)
return;
if (!fo.Process)
continue;
bool copy = false;
FTPFileInfo remoteFile = syncObj.FindRemoteFile(fo);
if (remoteFile == null) // does the remote file exists?
{
copy = true;
}
else
{
switch (syncObj.CopyMethod)
{
case COPYMETHOD.CopyAll:
copy = true;
break;
case COPYMETHOD.CopySizeDiffers:
copy = (fo.FileSize != remoteFile.Size);
break;
case COPYMETHOD.CopySizeTimeDiffers:
copy = (fo.FileSize != remoteFile.Size || fo.LastWriteTime > remoteFile.FileTime);
break;
case COPYMETHOD.CopyTimeDiffers:
copy = (fo.LastWriteTime > remoteFile.FileTime);
break;
}
}
if (copy)
{
syncObj.ftpTools.UploadFile(syncObj.Credentials, fo.FullFilename, fo.RemoteFilename, fo.FileSize);
}
fo.Process = false;
RefreshListView(); // update the list of files.
}
}
/// <summary>
///
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void backgroundWorker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
if (e.Cancelled)
{
UpdateStatus("Sync online cancelled.");
}
else
{
UpdateStatus("Sync online is finished.");
}
toolStripStatusLabel1.Text = "Synchronize stopped.";
}
/// <summary>
///
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void backgroundWorker_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
}
}
}