/// <summary> /// Attempts to copy local files from the local filesystem to the selected remote target path /// </summary> /// <param name="files">An array containing full paths to files and or folders to copy</param> /// <param name="target">The target path on the remote system</param> /// <param name="callback">A callback to fire on success or error. On failure the files parameter will be null</param> public void BeginCopyFiles(string[] files, string target, TransferUpdateCallback callback) { if (String.IsNullOrEmpty(m_Session.Username)) { if (m_Login.ShowDialog(SuperPuTTY.MainForm) == System.Windows.Forms.DialogResult.OK) { m_Session.Username = m_Login.Username; m_Session.Password = m_Login.Password; } } // put the copy operation in the background since it could take a long long time m_PscpThread = new Thread(delegate() { Process processCopyToRemote = new Process(); try { processCopyToRemote.EnableRaisingEvents = true; processCopyToRemote.StartInfo.RedirectStandardError = true; processCopyToRemote.StartInfo.RedirectStandardInput = true; processCopyToRemote.StartInfo.RedirectStandardOutput = true; processCopyToRemote.StartInfo.FileName = SuperPuTTY.Settings.PscpExe; processCopyToRemote.StartInfo.CreateNoWindow = true; // process the various options from the session object and convert them into arguments pscp can understand string args = "-r -agent "; // default arguments args += (!String.IsNullOrEmpty(m_Session.PuttySession)) ? "-load \"" + m_Session.PuttySession + "\" " : ""; //args += "-l " + Session.Username + " "; args += (!String.IsNullOrEmpty(m_Session.Password) && m_Session.Password.Length > 0) ? "-pw " + m_Session.Password + " " : ""; args += "-P " + m_Session.Port + " "; args += "\"" + files[0] + "\" "; args += (!String.IsNullOrEmpty(m_Session.Username)) ? m_Session.Username + "@" : ""; args += m_Session.Host + ":" + target; Logger.Log("Args: '{0} {1}'", processCopyToRemote.StartInfo.FileName, args); processCopyToRemote.StartInfo.Arguments = args; processCopyToRemote.StartInfo.UseShellExecute = false; processCopyToRemote.OutputDataReceived += delegate(object sender, DataReceivedEventArgs e) { if (!String.IsNullOrEmpty(e.Data)) { Match match = Regex.Match(e.Data.TrimEnd(), ".*|.*|.*|.*|.*"); if (match.Success) { if (callback != null) { FileTransferStatus status = new FileTransferStatus(); string[] update = e.Data.TrimEnd().Split('|'); status.Filename = update[0].Trim(); status.BytesTransferred = int.Parse(update[1].Replace("kB", "").Trim()); status.TransferRate = float.Parse(update[2].Replace("kB/s", "").Trim()); status.TimeLeft = update[3].Replace("ETA:", "").Trim(); status.PercentComplete = int.Parse(update[4].Replace("%", "").Trim()); //Logger.Log("File Transfer Data: " + e.Data); callback(status.PercentComplete.Equals(100), false, status); } } else { Logger.Log("Unable to parse OutputData: {0}", e.Data.TrimEnd()); } } }; processCopyToRemote.Start(); processCopyToRemote.BeginOutputReadLine(); processCopyToRemote.WaitForExit(); } catch (ThreadAbortException) { if(!processCopyToRemote.HasExited) processCopyToRemote.Kill(); } }); m_PscpThread.IsBackground = true; m_PscpThread.Name = "File Upload"; m_PscpThread.Start(); }
/// <summary> /// Copy files /// </summary> /// <param name="sourceFiles"></param> /// <param name="target"></param> /// <param name="callback"></param> /// <returns></returns> public FileTransferResult CopyFiles(List<BrowserFileInfo> sourceFiles, BrowserFileInfo target, TransferUpdateCallback callback) { lock(this) { /// Known Issues: /// - If a large exe (or other file that the OS will virus scan) is tranfered, the operation will timeout. /// After completion, the OS seems to block on the final write (while scanning). During this time the process looks like it's /// hanging and the timeout logic kicks in. Hacked in "completed" logic into inlineOut/Err handlers but this is awkward FileTransferResult result = new FileTransferResult(); string args = ToArgs(this.Session, this.Session.Password, sourceFiles, target); string argsToLog = ToArgs(this.Session, "XXXXX", sourceFiles, target); ScpLineParser parser = new ScpLineParser(); RunPscp( result, args, argsToLog, (line) => { bool completed = false; if (callback != null) { FileTransferStatus status; if (parser.TryParseTransferStatus(line, out status)) { completed = status.PercentComplete == 100; callback(completed, false, status); } } return completed; }, null, null); return result; } }