//
// 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.Net;
using System.Threading;
using System.Windows.Forms;
using System.IO;
using System.Collections.ObjectModel;
using Microsoft.Win32;
using System.Security.AccessControl;
namespace Text2Mambo.Tools
{
/// <summary>
///
/// </summary>
public class FTPFileInfo
{
public enum FTPPREMISSION
{
None = 0,
Read = 1,
Write = 2,
Execute = 4
};
/// drwxr-xr-x 3 2019902 15000 4096 May 17 09:05 var
public String Attributes;
public int LinkCount;
public String Owner;
public String Group;
public long Size;
public DateTime FileTime;
public String Name;
public String Path;
public FTPFileInfo()
{
}
public FTPFileInfo(String str, String path)
{
ParseString(str, path);
}
public override string ToString()
{
return String.Format("{0}\t{1}\t{2}", Name, Size.ToString(), FileTime.ToString());
}
public bool ParseString(String str, String path)
{
this.Path = path;
String[] elements = str.Split(new char[] { ' ' }, StringSplitOptions.RemoveEmptyEntries);
if (elements.Length >= 9)
{
Attributes = elements[0];
LinkCount = int.Parse(elements[1]);
Owner = elements[2];
Group = elements[3];
Size = long.Parse(elements[4]);
elements[5] = elements[5].ToLower();
int month = 0, day;
if (elements[5] == "jan") month = 0;
else if (elements[5] == "feb") month = 1;
else if (elements[5] == "mar") month = 2;
else if (elements[5] == "apr") month = 3;
else if (elements[5] == "may") month = 4;
else if (elements[5] == "jun") month = 5;
else if (elements[5] == "jul") month = 6;
else if (elements[5] == "aug") month = 7;
else if (elements[5] == "sep") month = 8;
else if (elements[5] == "oct") month = 9;
else if (elements[5] == "nov") month = 10;
else if (elements[5] == "dec") month = 11;
day = int.Parse(elements[6]);
if (elements[7].IndexOf(':') == -1)
{
FileTime = new DateTime(int.Parse(elements[7]), month, day);
}
else
{
int hour = int.Parse(elements[7].Substring(0, 2));
int min = int.Parse(elements[7].Substring(3, 2));
FileTime = new DateTime(DateTime.Now.Year, month, day, hour, min, 0);
}
Name = elements[8];
return true;
}
Name = String.Empty; // reset valid
return false;
}
public bool IsValid
{
get { return !String.IsNullOrEmpty(Name); }
}
public bool IsDirectory
{
get
{
if (Attributes.Length > 0)
return Attributes[0] == 'd';
return false;
}
}
private FTPPREMISSION permission(int pos)
{
FTPPREMISSION p = FTPPREMISSION.None;
if (Attributes[pos] == 'r') p |= FTPPREMISSION.Read;
if (Attributes[pos] == 'w') p |= FTPPREMISSION.Write;
if (Attributes[pos] == 'x') p |= FTPPREMISSION.Execute;
return p;
}
public FTPPREMISSION PermissionOwner
{
get { return permission(1); }
}
public FTPPREMISSION PermissionGroup
{
get { return permission(4); }
}
public FTPPREMISSION PermissionAll
{
get { return permission(7); }
}
}
/// <summary>
///
/// </summary>
public sealed class FTPCredentials
{
public String Username;
public String Password;
public String Host;
public String Port;
public String Name
{
get { return MakeName(Host, Username, Port); }
}
static public String MakeName(String host, String username, String port)
{
return String.Format("{0}_{1}_{2}", host.ToLower(), username.ToLower(), port.ToLower());
}
public override string ToString()
{
return Name;
}
private String FormatString()
{
return String.Format("username={0};password={1};host={2};port={3}",
Username.Replace(';', ':'),
Password.Replace(';', ':'),
Host.Replace(';', ':'),
Port.Replace(';', ':'));
}
public void Store()
{
ProgramSettings.SetRegValue(@"FTPLogin\" + Name, FormatString());
}
public void Load(String regkey)
{
String str = ProgramSettings.GetRegValue(@"FTPLogin\" + regkey, "");
ParseString(str);
}
/// <summary>
///
/// </summary>
/// <param name="str"></param>
/// <returns></returns>
public bool ParseString(String str)
{
if (String.IsNullOrEmpty(str))
return false;
String[] elements = str.Split(new char[] { ';' });
foreach (String s in elements)
{
if (s.IndexOf('=') == -1)
continue;
String name = s.Substring(0, s.IndexOf('=')).ToLower();
if (name == "username")
Username = s.Substring(s.IndexOf('=') + 1);
else if (name == "password")
Password = s.Substring(s.IndexOf('=') + 1);
else if (name == "host")
Host = s.Substring(s.IndexOf('=') + 1);
else if (name == "port")
Port = s.Substring(s.IndexOf('=') + 1);
}
return true;
}
}
/// <summary>
/// List of stored FTP Login credentials.
/// </summary>
public sealed class FTPCredentialList : Collection<FTPCredentials>
{
private String RegKey = ProgramSettings.RegistryPath + @"\FTPLogin";
public FTPCredentialList()
{
Readregistry();
}
/// <summary>
///
/// </summary>
public void Readregistry()
{
base.Clear();
try
{
RegistryKey key = Registry.CurrentUser.OpenSubKey(RegKey,
RegistryKeyPermissionCheck.ReadSubTree,
RegistryRights.ReadPermissions | RegistryRights.QueryValues);
if (key != null)
{
foreach (String t in key.GetValueNames())
{
FTPCredentials c = new FTPCredentials();
c.Load(t);
base.Add(c);
}
key.Close();
}
}
catch { }
}
public void WriteRegistry()
{
try
{
RegistryKey key = Registry.CurrentUser.CreateSubKey(RegKey,
RegistryKeyPermissionCheck.ReadWriteSubTree);
if (key != null)
{
foreach (FTPCredentials c in base.Items)
c.Store();
key.Close();
}
}
catch
{
// MessageBox.Show(ex.Message, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
}
}
/// <summary>
///
/// </summary>
/// <param name="c"></param>
new public void Add(FTPCredentials c)
{
FTPCredentials remove = null;
foreach (FTPCredentials i in Items)
{
if (i.Name == c.Name)
{
remove = i;
break;
}
}
if (remove != null)
Items.Remove(remove);
Items.Insert(0, c);
while (base.Count > 15)
base.RemoveAt(15);
}
}
/// <summary>
///
/// </summary>
public class FTPTools
{
public delegate void ReportStatusDelegate(String line, int maxPos, int curPos);
private ReportStatusDelegate reportStatus = null;
private FtpWebRequest webRequest;
private FtpWebResponse webResponse;
private String ftpRequestUri = String.Empty;
/// <summary>
/// Cleanup.
/// </summary>
public void Close()
{
// do nothing for the moment.
}
/// <summary>
/// Set the report callback
/// </summary>
public ReportStatusDelegate ReportStatus
{
set { reportStatus = value; }
}
/// <summary>
///
/// </summary>
/// <param name="line"></param>
/// <param name="curPos"></param>
/// <param name="maxPos"></param>
private void UpdateStatus(String line, int maxPos, int curPos)
{
if (reportStatus != null)
reportStatus(line, maxPos, curPos);
}
/// <summary>
///
/// </summary>
/// <param name="cred"></param>
/// <param name="method"></param>
/// <param name="uri"></param>
/// <returns></returns>
private FtpWebRequest SetWebRequest(FTPCredentials cred, String method, String uri)
{
FtpWebRequest request;
request = (FtpWebRequest)WebRequest.Create(uri);
request.Method = method;
request.KeepAlive = false;
request.UseBinary = true;
request.Credentials = new NetworkCredential(cred.Username, cred.Password);
request.Proxy = null;
return request;
}
/// <summary>
/// drwxr-xr-x 3 2019902 15000 4096 Jul 22 11:18 .Archived
/// -rwxr-xr-x 1 2019902 15000 3 Feb 1 2011 .membership
/// drwxr-xr-x 11 2019902 15000 4096 Jun 11 05:38 htdocs
/// drwxr-xr-x 2 2019902 15000 4096 Oct 4 22:06 phpsessions
/// drwxr-xr-x 2 2019902 15000 8192 Oct 6 01:16 stats
/// drwxr-xr-x 3 2019902 15000 4096 May 17 09:05 var
/// </summary>
/// <param name="text"></param>
/// <param name="folder"></param>
/// <returns></returns>
private Collection<FTPFileInfo> ParseDirListing(String text, String folder)
{
Collection<FTPFileInfo> info = new Collection<FTPFileInfo>();
text = text.Replace("\r\n", "\n");
text = text.Replace("\n\r", "\n");
String[] lines = text.Split(new Char[] { '\n' }, StringSplitOptions.RemoveEmptyEntries);
foreach (String line in lines)
{
if (line.Length > 0)
{
//String[] elements = line.Split(new char[] { ' ' });
FTPFileInfo i = new FTPFileInfo(line, folder);
if (i.IsValid)
info.Add(i);
}
}
return info;
}
/// <summary>
/// Retrieves a list FTPFileInfo objects describing the entries in the folder.
/// </summary>
/// <param name="cred"></param>
/// <param name="folder"></param>
/// <returns></returns>
public Collection<FTPFileInfo> GetFolderListInfo(FTPCredentials cred, String folder)
{
try
{
ftpRequestUri = "ftp://" + cred.Host + folder;
webRequest = SetWebRequest(cred, WebRequestMethods.Ftp.ListDirectoryDetails, ftpRequestUri);
webResponse = (FtpWebResponse)webRequest.GetResponse();
if (!String.IsNullOrEmpty(webResponse.WelcomeMessage))
UpdateStatus(webResponse.WelcomeMessage, -1, 0);
Stream requestStream = webResponse.GetResponseStream();
if (requestStream.CanRead)
{
StreamReader reader = new StreamReader(requestStream);
String text = reader.ReadToEnd();
webResponse.Close();
return ParseDirListing(text, folder);
}
}
finally
{
if (webResponse != null)
webResponse.Close();
webResponse = null;
}
return null;
}
/// <summary>
///
/// </summary>
/// <param name="cred"></param>
/// <param name="folder"></param>
/// <returns></returns>
public String[] ListDirectory(FTPCredentials cred, String folder)
{
try
{
ftpRequestUri = "ftp://" + cred.Host + folder;
webRequest = SetWebRequest(cred, WebRequestMethods.Ftp.ListDirectory, ftpRequestUri);
webResponse = (FtpWebResponse)webRequest.GetResponse();
Stream requestStream = webResponse.GetResponseStream();
if (requestStream.CanRead)
{
StreamReader reader = new StreamReader(requestStream);
String[] list = reader.ReadToEnd().Split(new String[] { "\r\n" }, StringSplitOptions.RemoveEmptyEntries);
for (int i = 0; i < list.Length; i++)
{
if (list[i].IndexOf('/') != -1)
list[i] = folder + list[i].Substring(list[i].IndexOf('/'));
else
list[i] = folder + list[i];
}
return list;
}
}
catch (Exception ex)
{
UpdateStatus("ListDirectory failed: " + ex.Message, -1, 0);
}
finally
{
if (webResponse != null)
webResponse.Close();
webResponse = null;
}
return null;
}
/// <summary>
///
/// </summary>
/// <param name="cred"></param>
/// <param name="filename"></param>
/// <returns>Returns DateTime.MinValue on error.</returns>
public DateTime GetLastModified(FTPCredentials cred, String filename)
{
try
{
ftpRequestUri = "ftp://" + cred.Host + filename;
webRequest = (FtpWebRequest)WebRequest.Create(ftpRequestUri);
webRequest.Method = WebRequestMethods.Ftp.GetDateTimestamp;
webRequest.KeepAlive = false;
webRequest.UseBinary = true;
webRequest.Credentials = new NetworkCredential(cred.Username, cred.Password);
webRequest.Proxy = null;
webResponse = (FtpWebResponse)webRequest.GetResponse();
UpdateStatus(webResponse.LastModified.ToString(), -1, 0);
DateTime dt = webResponse.LastModified;
return dt;
}
catch
{
return DateTime.MinValue;
}
finally
{
if (webResponse != null)
webResponse.Close();
webResponse = null;
}
}
/// <summary>
///
/// </summary>
/// <param name="cred">Login credentials and server name</param>
/// <param name="folder">["ftp://" + cred.host + folder] should be the full path</param>
/// <returns></returns>
public bool MkDir(FTPCredentials cred, String folder)
{
try
{
ftpRequestUri = "ftp://" + cred.Host + folder;
webRequest = SetWebRequest(cred, WebRequestMethods.Ftp.MakeDirectory, ftpRequestUri);
webResponse = (FtpWebResponse)webRequest.GetResponse();
UpdateStatus(String.Format("MkDir status: {0}", webResponse.StatusDescription), -1, 0);
return true;
}
catch
{
return false;
}
finally
{
if (webResponse != null)
webResponse.Close();
webResponse = null;
}
}
/// <summary>
///
/// </summary>
/// <param name="cred">Login credentials and server name</param>
/// <param name="localFile">Full path to local file.</param>
/// <param name="remoteFile">Relative path, from root, of remote file.</param>
/// <param name="size"></param>
/// <returns></returns>
public bool UploadFile(FTPCredentials cred, String localFile, String remoteFile, long size)
{
FileStream fileStream = null;
String filename = String.Format("Written to {0}:", Path.GetFileName(localFile));
try
{
ftpRequestUri = "ftp://" + cred.Host + remoteFile;
webRequest = SetWebRequest(cred, WebRequestMethods.Ftp.UploadFile, ftpRequestUri);
fileStream = File.OpenRead(localFile);
Stream requestStream = webRequest.GetRequestStream();
const int bufferLength = 2048;
byte[] buffer = new byte[bufferLength];
int count = 0;
int readBytes = 0;
do
{
readBytes = fileStream.Read(buffer, 0, bufferLength);
requestStream.Write(buffer, 0, readBytes);
count += readBytes;
UpdateStatus(filename, (int)size, count);
} while (readBytes != 0);
//UpdateStatus(String.Format("Writing {0} bytes to the stream.", count), (int)size, count);
requestStream.Close();
return true;
}
catch (Exception ex)
{
UpdateStatus("Error wih FTP: " + ex.Message, -1, 0);
return false;
}
finally
{
if (webResponse != null)
webResponse.Close();
webResponse = null;
if (fileStream != null)
fileStream.Close();
fileStream = null;
}
}
}
/// <summary>
///
/// </summary>
public sealed class FTPState : IDisposable
{
private ManualResetEvent wait;
private FtpWebRequest request;
private string fileName;
private Exception operationException = null;
private bool disposed = false;
string status;
public FTPState()
{
wait = new ManualResetEvent(false);
}
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
public void Dispose(bool disposing)
{
// Check to see if Dispose has already been called.
if (!this.disposed)
{
// If disposing equals true, dispose all managed
// and unmanaged resources.
if (disposing)
{
// Dispose managed resources.
wait.Close();
wait = null;
}
// Call the appropriate methods to clean up unmanaged resources here.
// If disposing is false, only the following code is executed.
// Note disposing has been done.
disposed = true;
}
}
public ManualResetEvent OperationComplete
{
get { return wait; }
}
public FtpWebRequest Request
{
get { return request; }
set { request = value; }
}
public string FileName
{
get { return fileName; }
set { fileName = value; }
}
public Exception OperationException
{
get { return operationException; }
set { operationException = value; }
}
public string StatusDescription
{
get { return status; }
set { status = value; }
}
}
/// <summary>
/// AsynchronousFtpUpLoader class
/// </summary>
public static class AsynchronousFtpUpLoader
{
/// <summary>
/// Command line arguments are two strings:
/// 1. The url that is the name of the file being uploaded to the server.
/// 2. The name of the file on the local machine.
/// </summary>
/// <param name="source"></param>
/// <param name="destination"></param>
/// <param name="password"></param>
/// <param name="username"></param>
public static void CopyFile(String source, String destination, String username, String password)
{
try
{
// Create a Uri instance with the specified URI string.
// If the URI is not correctly formed, the Uri constructor
// will throw an exception.
ManualResetEvent waitObject;
Uri target = new Uri(destination);
FTPState state = new FTPState();
state.Request = (FtpWebRequest)WebRequest.Create(target);
state.Request.Method = WebRequestMethods.Ftp.UploadFile;
// This example uses anonymous logon.
// The request is anonymous by default; the credential does not have to be specified.
// The example specifies the credential only to
// control how actions are logged on the server.
state.Request.Credentials = new NetworkCredential(username, password);
// Store the request in the object that we pass into the
// asynchronous operations.
state.FileName = source;
// Get the event to wait on.
waitObject = state.OperationComplete;
// Asynchronously get the stream for the file contents.
state.Request.BeginGetRequestStream(new AsyncCallback(EndGetStreamCallback), state);
// Block the current thread until all operations are complete.
if (waitObject.SafeWaitHandle != null && !waitObject.SafeWaitHandle.IsClosed)
waitObject.WaitOne();
// The operations either completed or threw an exception.
if (state.OperationException != null)
{
throw state.OperationException;
}
else
{
Console.WriteLine("The operation completed - {0}", state.StatusDescription);
}
state.Dispose();
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
}
/// <summary>
///
/// </summary>
/// <param name="ar"></param>
private static void EndGetStreamCallback(IAsyncResult ar)
{
FTPState state = (FTPState)ar.AsyncState;
Stream requestStream = null;
FileStream stream = null;
// End the asynchronous call to get the request stream.
try
{
requestStream = state.Request.EndGetRequestStream(ar);
// Copy the file contents to the request stream.
const int bufferLength = 2048;
byte[] buffer = new byte[bufferLength];
int count = 0;
int readBytes = 0;
stream = File.OpenRead(state.FileName);
do
{
readBytes = stream.Read(buffer, 0, bufferLength);
requestStream.Write(buffer, 0, readBytes);
count += readBytes;
} while (readBytes != 0);
Console.WriteLine("Writing {0} bytes to the stream.", count);
// IMPORTANT: Close the request stream before sending the request.
requestStream.Close();
// Asynchronously get the response to the upload request.
state.Request.BeginGetResponse(new AsyncCallback(EndGetResponseCallback), state);
}
// Return exceptions to the main application thread.
catch (Exception e)
{
Console.WriteLine("Could not get the request stream.");
state.OperationException = e;
state.OperationComplete.Set();
return;
}
finally
{
if (stream != null)
stream.Dispose();
state.Dispose();
}
}
/// <summary>
/// The EndGetResponseCallback method completes a call to BeginGetResponse.
/// </summary>
/// <param name="ar"></param>
private static void EndGetResponseCallback(IAsyncResult ar)
{
FTPState state = (FTPState)ar.AsyncState;
FtpWebResponse response = null;
try
{
response = (FtpWebResponse)state.Request.EndGetResponse(ar);
response.Close();
state.StatusDescription = response.StatusDescription;
// Signal the main application thread that
// the operation is complete.
state.OperationComplete.Set();
}
// Return exceptions to the main application thread.
catch (Exception e)
{
Console.WriteLine("Error getting response.");
state.OperationException = e;
state.OperationComplete.Set();
}
}
}
}