diff --git a/Duplicati/Library/Backend/FTP/FTPBackend.cs b/Duplicati/Library/Backend/FTP/FTPBackend.cs index 19b951db1..51a59dc1a 100644 --- a/Duplicati/Library/Backend/FTP/FTPBackend.cs +++ b/Duplicati/Library/Backend/FTP/FTPBackend.cs @@ -144,18 +144,28 @@ namespace Duplicati.Library.Backend req.Method = System.Net.WebRequestMethods.Ftp.ListDirectoryDetails; req.UseBinary = false; - List lst = new List(); - using (System.Net.WebResponse resp = req.GetResponse()) - using (System.IO.Stream rs = resp.GetResponseStream()) - using (System.IO.StreamReader sr = new System.IO.StreamReader(rs)) - while(sr.Peek() >= 0) - { - FileEntry f = ParseLine(sr.ReadLine()); - if (f != null) - lst.Add(f); - } + try + { + List lst = new List(); + using (System.Net.WebResponse resp = req.GetResponse()) + using (System.IO.Stream rs = resp.GetResponseStream()) + using (System.IO.StreamReader sr = new System.IO.StreamReader(rs)) + while (sr.Peek() >= 0) + { + FileEntry f = ParseLine(sr.ReadLine()); + if (f != null) + lst.Add(f); + } - return lst; + return lst; + } + catch (System.Net.WebException wex) + { + if (wex.Response as System.Net.FtpWebResponse != null && (wex.Response as System.Net.FtpWebResponse).StatusCode == System.Net.FtpStatusCode.ActionNotTakenFileUnavailable) + throw new Backend.FolderMissingException(string.Format(Strings.FTPBackend.MissingFolderError, req.RequestUri.PathAndQuery, wex.Message), wex); + else + throw; + } } public void Put(string remotename, System.IO.Stream input) @@ -251,7 +261,14 @@ namespace Duplicati.Library.Backend return req; } - + public void CreateFolder() + { + System.Net.FtpWebRequest req = CreateRequest(""); + req.Method = System.Net.WebRequestMethods.Ftp.MakeDirectory; + req.KeepAlive = false; + using (req.GetResponse()) + { } + } #region IBackendGUI Members diff --git a/Duplicati/Library/Backend/FTP/FTPUI.cs b/Duplicati/Library/Backend/FTP/FTPUI.cs index 5600cf8af..b4cc6fcc8 100644 --- a/Duplicati/Library/Backend/FTP/FTPUI.cs +++ b/Duplicati/Library/Backend/FTP/FTPUI.cs @@ -201,11 +201,26 @@ namespace Duplicati.Library.Backend MessageBox.Show(this, Backend.CommonStrings.ConnectionSuccess, Application.ProductName, MessageBoxButtons.OK, MessageBoxIcon.Information); m_hasTested = true; } + catch (Backend.FolderMissingException) + { + switch (MessageBox.Show(this, Strings.FTPUI.CreateMissingFolderQuestion, Application.ProductName, MessageBoxButtons.YesNoCancel, MessageBoxIcon.Question)) + { + case DialogResult.Yes: + CreateFolderButton.PerformClick(); + TestConnection.PerformClick(); + return; + default: + return; + } + } catch (Exception ex) { MessageBox.Show(this, string.Format(Backend.CommonStrings.ConnectionFailure, ex.Message), Application.ProductName, MessageBoxButtons.OK, MessageBoxIcon.Error); } - this.Cursor = c; + finally + { + this.Cursor = c; + } } } @@ -246,23 +261,28 @@ namespace Duplicati.Library.Backend { if (ValidateForm()) { + Cursor c = this.Cursor; try { - string url = "ftp://" + Servername.Text + ":" + Port.Value.ToString() + "/" + Path.Text; - System.Net.FtpWebRequest req = (System.Net.FtpWebRequest)System.Net.FtpWebRequest.Create(url); - req.Credentials = new System.Net.NetworkCredential(Username.Text, Password.Text); - req.Method = System.Net.WebRequestMethods.Ftp.MakeDirectory; - req.KeepAlive = false; - using (req.GetResponse()) - { } + this.Cursor = Cursors.WaitCursor; + SaveSettings(); + + Dictionary options = new Dictionary(); + string hostname = GetConfiguration(m_options, options); + FTP f = new FTP(hostname, options); + f.CreateFolder(); MessageBox.Show(this, Backend.CommonStrings.FolderCreated, Application.ProductName, MessageBoxButtons.OK, MessageBoxIcon.Information); } - catch(Exception ex) + catch (Exception ex) { MessageBox.Show(this, string.Format(Backend.CommonStrings.ConnectionFailure, ex.Message), Application.ProductName, MessageBoxButtons.OK, MessageBoxIcon.Error); } + finally + { + this.Cursor = c; + } } } diff --git a/Duplicati/Library/Backend/FTP/Strings/FTPBackend.Designer.cs b/Duplicati/Library/Backend/FTP/Strings/FTPBackend.Designer.cs index 084cf3bfe..6c45eac15 100644 --- a/Duplicati/Library/Backend/FTP/Strings/FTPBackend.Designer.cs +++ b/Duplicati/Library/Backend/FTP/Strings/FTPBackend.Designer.cs @@ -1,7 +1,7 @@ //------------------------------------------------------------------------------ // // This code was generated by a tool. -// Runtime Version:2.0.50727.3053 +// Runtime Version:2.0.50727.4927 // // Changes to this file may cause incorrect behavior and will be lost if // the code is regenerated. @@ -167,5 +167,14 @@ namespace Duplicati.Library.Backend.Strings { return ResourceManager.GetString("DisplayName", resourceCulture); } } + + /// + /// Looks up a localized string similar to The folder {0} was not found, message: {1}. + /// + internal static string MissingFolderError { + get { + return ResourceManager.GetString("MissingFolderError", resourceCulture); + } + } } } diff --git a/Duplicati/Library/Backend/FTP/Strings/FTPBackend.resx b/Duplicati/Library/Backend/FTP/Strings/FTPBackend.resx index f144e4eef..8e8e39eb7 100644 --- a/Duplicati/Library/Backend/FTP/Strings/FTPBackend.resx +++ b/Duplicati/Library/Backend/FTP/Strings/FTPBackend.resx @@ -153,4 +153,7 @@ FTP based + + The folder {0} was not found, message: {1} + \ No newline at end of file diff --git a/Duplicati/Library/Backend/FTP/Strings/FTPUI.Designer.cs b/Duplicati/Library/Backend/FTP/Strings/FTPUI.Designer.cs index 15fc8c830..cc6b2519e 100644 --- a/Duplicati/Library/Backend/FTP/Strings/FTPUI.Designer.cs +++ b/Duplicati/Library/Backend/FTP/Strings/FTPUI.Designer.cs @@ -1,7 +1,7 @@ //------------------------------------------------------------------------------ // // This code was generated by a tool. -// Runtime Version:2.0.50727.3053 +// Runtime Version:2.0.50727.4927 // // Changes to this file may cause incorrect behavior and will be lost if // the code is regenerated. @@ -60,6 +60,15 @@ namespace Duplicati.Library.Backend.Strings { } } + /// + /// Looks up a localized string similar to The folder does not exist, do you want to create it?. + /// + internal static string CreateMissingFolderQuestion { + get { + return ResourceManager.GetString("CreateMissingFolderQuestion", resourceCulture); + } + } + /// /// Looks up a localized string similar to On this page you can select where to store the backup data.. /// diff --git a/Duplicati/Library/Backend/FTP/Strings/FTPUI.resx b/Duplicati/Library/Backend/FTP/Strings/FTPUI.resx index 498c95b8d..3f4c718c7 100644 --- a/Duplicati/Library/Backend/FTP/Strings/FTPUI.resx +++ b/Duplicati/Library/Backend/FTP/Strings/FTPUI.resx @@ -117,6 +117,9 @@ System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + The folder does not exist, do you want to create it? + On this page you can select where to store the backup data. diff --git a/Duplicati/Library/Backend/WEBDAV/Strings/WEBDAV.Designer.cs b/Duplicati/Library/Backend/WEBDAV/Strings/WEBDAV.Designer.cs index cded2ee48..4e56513ca 100644 --- a/Duplicati/Library/Backend/WEBDAV/Strings/WEBDAV.Designer.cs +++ b/Duplicati/Library/Backend/WEBDAV/Strings/WEBDAV.Designer.cs @@ -1,7 +1,7 @@ //------------------------------------------------------------------------------ // // This code was generated by a tool. -// Runtime Version:2.0.50727.3082 +// Runtime Version:2.0.50727.4927 // // Changes to this file may cause incorrect behavior and will be lost if // the code is regenerated. @@ -149,5 +149,14 @@ namespace Duplicati.Library.Backend.Strings { return ResourceManager.GetString("DisplayName", resourceCulture); } } + + /// + /// Looks up a localized string similar to The folder {0} was not found, message: {1}. + /// + internal static string MissingFolderError { + get { + return ResourceManager.GetString("MissingFolderError", resourceCulture); + } + } } } diff --git a/Duplicati/Library/Backend/WEBDAV/Strings/WEBDAV.resx b/Duplicati/Library/Backend/WEBDAV/Strings/WEBDAV.resx index c4860c305..1d305295c 100644 --- a/Duplicati/Library/Backend/WEBDAV/Strings/WEBDAV.resx +++ b/Duplicati/Library/Backend/WEBDAV/Strings/WEBDAV.resx @@ -147,4 +147,7 @@ WEBDAV based + + The folder {0} was not found, message: {1} + \ No newline at end of file diff --git a/Duplicati/Library/Backend/WEBDAV/Strings/WebDAVUI.Designer.cs b/Duplicati/Library/Backend/WEBDAV/Strings/WebDAVUI.Designer.cs index f2ac41c8d..ddd3ead48 100644 --- a/Duplicati/Library/Backend/WEBDAV/Strings/WebDAVUI.Designer.cs +++ b/Duplicati/Library/Backend/WEBDAV/Strings/WebDAVUI.Designer.cs @@ -1,7 +1,7 @@ //------------------------------------------------------------------------------ // // This code was generated by a tool. -// Runtime Version:2.0.50727.3053 +// Runtime Version:2.0.50727.4927 // // Changes to this file may cause incorrect behavior and will be lost if // the code is regenerated. @@ -60,6 +60,15 @@ namespace Duplicati.Library.Backend.Strings { } } + /// + /// Looks up a localized string similar to The folder does not exist, do you want to create it?. + /// + internal static string CreateMissingFolderQuestion { + get { + return ResourceManager.GetString("CreateMissingFolderQuestion", resourceCulture); + } + } + /// /// Looks up a localized string similar to On this page you can select where to store the backup data.. /// diff --git a/Duplicati/Library/Backend/WEBDAV/Strings/WebDAVUI.resx b/Duplicati/Library/Backend/WEBDAV/Strings/WebDAVUI.resx index 498c95b8d..3f4c718c7 100644 --- a/Duplicati/Library/Backend/WEBDAV/Strings/WebDAVUI.resx +++ b/Duplicati/Library/Backend/WEBDAV/Strings/WebDAVUI.resx @@ -117,6 +117,9 @@ System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + The folder does not exist, do you want to create it? + On this page you can select where to store the backup data. diff --git a/Duplicati/Library/Backend/WEBDAV/WEBDAV.cs b/Duplicati/Library/Backend/WEBDAV/WEBDAV.cs index 96950b678..32cf1c7fe 100644 --- a/Duplicati/Library/Backend/WEBDAV/WEBDAV.cs +++ b/Duplicati/Library/Backend/WEBDAV/WEBDAV.cs @@ -108,74 +108,85 @@ namespace Duplicati.Library.Backend using (System.IO.Stream s = req.GetRequestStream()) s.Write(PROPFIND, 0, PROPFIND.Length); - System.Xml.XmlDocument doc = new System.Xml.XmlDocument(); - using (System.Net.HttpWebResponse resp = (System.Net.HttpWebResponse)req.GetResponse()) - { - int code = (int)resp.StatusCode; - if (code < 200 || code >= 300) //For some reason Mono does not throw this automatically - throw new System.Net.WebException(resp.StatusDescription, null, System.Net.WebExceptionStatus.ProtocolError, resp); - - doc.Load(resp.GetResponseStream()); - } - - System.Xml.XmlNamespaceManager nm = new System.Xml.XmlNamespaceManager(doc.NameTable); - nm.AddNamespace("D", "DAV:"); - - List files = new List(); - - foreach (System.Xml.XmlNode n in doc.SelectNodes("D:multistatus/D:response/D:href", nm)) + try { - string name = System.Web.HttpUtility.UrlDecode(n.InnerText); - - string cmp_path; - - if (name.StartsWith(m_url)) - cmp_path = m_url; - else if (name.StartsWith(m_rawurl)) - cmp_path = m_rawurl; - else if (name.StartsWith(m_path)) - cmp_path = m_path; - else - continue; - - if (name.Length <= cmp_path.Length) - continue; - - name = name.Substring(cmp_path.Length); - - long size = 0; - DateTime lastAccess = new DateTime(); - DateTime lastModified = new DateTime(); - bool isCollection = false; - - System.Xml.XmlNode stat = n.ParentNode.SelectSingleNode("D:propstat/D:prop", nm); - if (stat != null) + System.Xml.XmlDocument doc = new System.Xml.XmlDocument(); + using (System.Net.HttpWebResponse resp = (System.Net.HttpWebResponse)req.GetResponse()) { - System.Xml.XmlNode s = stat.SelectSingleNode("D:getcontentlength", nm); - if (s != null) - size = long.Parse(s.InnerText); - s = stat.SelectSingleNode("D:getlastmodified", nm); - if (s != null) - try - { - //Not important if this succeeds - lastAccess = lastModified = DateTime.Parse(s.InnerText, System.Globalization.CultureInfo.InvariantCulture); - } - catch { } + int code = (int)resp.StatusCode; + if (code < 200 || code >= 300) //For some reason Mono does not throw this automatically + throw new System.Net.WebException(resp.StatusDescription, null, System.Net.WebExceptionStatus.ProtocolError, resp); - s = stat.SelectSingleNode("D:iscollection", nm); - if (s != null) - isCollection = s.InnerText.Trim() == "1"; - else - isCollection = (stat.SelectSingleNode("D:resourcetype/D:collection", nm) != null); + doc.Load(resp.GetResponseStream()); } - FileEntry fe = new FileEntry(name, size, lastAccess, lastModified); - fe.IsFolder = isCollection; - files.Add(fe); + System.Xml.XmlNamespaceManager nm = new System.Xml.XmlNamespaceManager(doc.NameTable); + nm.AddNamespace("D", "DAV:"); + + List files = new List(); + + foreach (System.Xml.XmlNode n in doc.SelectNodes("D:multistatus/D:response/D:href", nm)) + { + string name = System.Web.HttpUtility.UrlDecode(n.InnerText); + + string cmp_path; + + if (name.StartsWith(m_url)) + cmp_path = m_url; + else if (name.StartsWith(m_rawurl)) + cmp_path = m_rawurl; + else if (name.StartsWith(m_path)) + cmp_path = m_path; + else + continue; + + if (name.Length <= cmp_path.Length) + continue; + + name = name.Substring(cmp_path.Length); + + long size = 0; + DateTime lastAccess = new DateTime(); + DateTime lastModified = new DateTime(); + bool isCollection = false; + + System.Xml.XmlNode stat = n.ParentNode.SelectSingleNode("D:propstat/D:prop", nm); + if (stat != null) + { + System.Xml.XmlNode s = stat.SelectSingleNode("D:getcontentlength", nm); + if (s != null) + size = long.Parse(s.InnerText); + s = stat.SelectSingleNode("D:getlastmodified", nm); + if (s != null) + try + { + //Not important if this succeeds + lastAccess = lastModified = DateTime.Parse(s.InnerText, System.Globalization.CultureInfo.InvariantCulture); + } + catch { } + + s = stat.SelectSingleNode("D:iscollection", nm); + if (s != null) + isCollection = s.InnerText.Trim() == "1"; + else + isCollection = (stat.SelectSingleNode("D:resourcetype/D:collection", nm) != null); + } + + FileEntry fe = new FileEntry(name, size, lastAccess, lastModified); + fe.IsFolder = isCollection; + files.Add(fe); + } + + return files; + } + catch (System.Net.WebException wex) + { + if (wex.Response as System.Net.HttpWebResponse != null && (wex.Response as System.Net.HttpWebResponse).StatusCode == System.Net.HttpStatusCode.NotFound) + throw new Backend.FolderMissingException(string.Format(Strings.WEBDAV.MissingFolderError, m_path, wex.Message), wex); + else + throw; } - return files; } public void Put(string remotename, string filename) diff --git a/Duplicati/Library/Backend/WEBDAV/WebDAVUI.cs b/Duplicati/Library/Backend/WEBDAV/WebDAVUI.cs index 3313f9f44..0365a7f0d 100644 --- a/Duplicati/Library/Backend/WEBDAV/WebDAVUI.cs +++ b/Duplicati/Library/Backend/WEBDAV/WebDAVUI.cs @@ -215,6 +215,18 @@ namespace Duplicati.Library.Backend MessageBox.Show(this, Backend.CommonStrings.ConnectionSuccess, Application.ProductName, MessageBoxButtons.OK, MessageBoxIcon.Information); m_hasTested = true; } + catch (Backend.FolderMissingException) + { + switch (MessageBox.Show(this, Strings.WebDAVUI.CreateMissingFolderQuestion, Application.ProductName, MessageBoxButtons.YesNoCancel, MessageBoxIcon.Question)) + { + case DialogResult.Yes: + CreateFolderButton.PerformClick(); + TestConnection.PerformClick(); + return; + default: + return; + } + } catch (Exception ex) { MessageBox.Show(this, string.Format(Backend.CommonStrings.ConnectionFailure, ex.Message), Application.ProductName, MessageBoxButtons.OK, MessageBoxIcon.Error);