/// <summary> /// Constructor for the class. Instantiates the class and initialises its properties. /// </summary> /// <param name="location">String: The location of the file to download.</param> public Download(string location) { // We know the hash of the location of the file we have to get. // First step is to get the product name. We're also going to need the location we're downloading to. _product = DbConnect.GetProductNameFromLocationHash(location); // Could-Have: Let users choose download location _target = Properties.Settings.Default.DownloadDirectory; if (String.IsNullOrEmpty(_target)) { string homePath = (Environment.OSVersion.Platform == PlatformID.Unix || Environment.OSVersion.Platform == PlatformID.MacOSX) ? Environment.GetEnvironmentVariable("HOME") : Environment.ExpandEnvironmentVariables("%HOMEDRIVE%%HOMEPATH%"); Properties.Settings.Default.DownloadDirectory = _target = Path.Combine(homePath, @"\Downloads\Donatello\"); Properties.Settings.Default.Save(); } // If the target directory doesn't exist, we should create it. if (!Directory.Exists(_target)) { Directory.CreateDirectory(_target); } // Finally we need to find out where we're downloading the file from, and get it. int locs = DbConnect.CountLocations(); int decodedLocation = -1; // Iterate through each location in the database until you find the location_id that matches the hash we've got. // TODO: Isn't there a method in DBConnect that does the same thing? for (int i = 1; i < locs + 1; i++) { if (DbConnect.CalculateMD5(i.ToString()) == location) { decodedLocation = i; } } if (decodedLocation == -1) { throw new NullReferenceException(); } // Pass the location_id to the database to get the actual location of the file we're after. string secretLoc = DbConnect.GetLocation(decodedLocation); _location = new Uri(@"ftp://kieranajp.co.uk/donatello/" + secretLoc + @"/" + secretLoc + ".file"); // Could-Have: Dynamic file types Notification n = new Notification("Download started!", false); // We're going to need to multithread this now. _bw = new BackgroundWorker { WorkerReportsProgress = true }; _bw.DoWork += GetFile; _bw.ProgressChanged += Progress; _bw.RunWorkerCompleted += Complete; _bw.RunWorkerAsync(); }
/// <summary> /// Constructor for this class. /// Initialises and displays the form. /// Checks if valid user credentials are stored for automatic login. If so, closes this form and opens an instance of Listener. /// Else, shows the login panel. /// </summary> public Dashboard() { InitializeComponent(); this.Visible = false; if (Properties.Settings.Default.LastUsername != "*****@*****.**" && DbConnect.CheckLogin(Properties.Settings.Default.LastUsername, Properties.Settings.Default.LastPassword)) { Account acc = DbConnect.GetAccount(Properties.Settings.Default.LastUsername); Notification n = new Notification("Welcome, " + acc.Name + "!", false); this.Hide(); DbConnect.SetClient(Properties.Settings.Default.LastUsername); Listener li = new Listener(); li.ShowDialog(); } else { this.Visible = true; pnl_Login.Show(); } }
private void Notify(string txt) { if (this.InvokeRequired) { this.Invoke(new NotifyDelegate(this.Notify), txt); } else { Notification n = new Notification(txt, false); } }
/// <summary> /// Attempts to log in using the input credentials. If successful, hides this form and creates an instance of Listener. /// </summary> /// <param name="sender"></param> /// <param name="e"></param> private void btn_Login_Click(object sender, EventArgs e) { if (String.IsNullOrEmpty(emailBox.Text) || String.IsNullOrEmpty(passBox.Text) || emailBox.Text == "*****@*****.**") { MessageBox.Show("You must fill in all fields!", "Error", MessageBoxButtons.OK, MessageBoxIcon.Warning); } else if (DbConnect.Login(emailBox.Text, passBox.Text)) { DbConnect.SetClient(emailBox.Text); WindowState = FormWindowState.Minimized; Properties.Settings.Default.LastUsername = emailBox.Text; Properties.Settings.Default.LastPassword = DbConnect.GetPassHash(emailBox.Text); Properties.Settings.Default.Save(); Notification n = new Notification("Welcome to Donatello, ", false); Listener li = new Listener(); li.Show(); this.Hide(); } else { MessageBox.Show("Incorrect username or password!"); } }
/// <summary> /// ProcessChanged event of the BackgroundWorker /// Displays a notification every 10% of the download. /// (Note user feedback is minimal since the program is designed to be used while the user is away from their computer). /// </summary> /// <param name="sender"></param> /// <param name="e"></param> private void Progress(object sender, ProgressChangedEventArgs e) { if (e.ProgressPercentage % 10 == 0) { Notification n = new Notification("Download of " + _product + ": " + e.ProgressPercentage + "%", false); } }
/// <summary> /// Initialises and runs FTP to get a file or its size. /// </summary> /// <param name="download">Boolean: True to download the file, false to merely get its size.</param> /// <returns>Long: If getting the filesize, the filesize in bytes. /// If downloading the file, a returncode signifying the download's success or failure.</returns> private long FTPGet(bool download) { FtpWebRequest req = (FtpWebRequest)WebRequest.Create(_location); req.UsePassive = true; req.UseBinary = true; req.Credentials = new NetworkCredential("*****@*****.**", "eijonu"); if (download) { int returnCode = 0; req.KeepAlive = false; req.Method = WebRequestMethods.Ftp.DownloadFile; FtpWebResponse response = (FtpWebResponse)req.GetResponse(); Stream responseStream = response.GetResponseStream(); string newFileName = CleanFileName(_product); string path = Path.Combine(_target, String.Concat(newFileName, ".file")); if (File.Exists(path)) { string bak = "_backup"; if (File.Exists(path + bak)) { File.Delete(path + bak); } File.Move(path, path + bak); } try { using (FileStream writeStream = File.Create(path)) { Byte[] buffer = new Byte[2048]; int bytesRead = responseStream.Read(buffer, 0, 2048); while (bytesRead > 0) { writeStream.Write(buffer, 0, bytesRead); bytesRead = responseStream.Read(buffer, 0, 2048); } } } catch { Notification n = new Notification("Error downloading " + _product, true); returnCode = -1; } finally { response.Close(); } return returnCode; } else { req.KeepAlive = true; req.Method = WebRequestMethods.Ftp.GetFileSize; long fileSize = (long)req.GetResponse().ContentLength; return fileSize; } }
/// <summary> /// The RunWorkerCompleted event of the BackgroundWorker. Runs when the BackgroundWorker has finished. /// MD5 checksums the download and proclaims it complete or displays an error as appropriate. /// </summary> /// <param name="sender"></param> /// <param name="e"></param> private void Complete(object sender, RunWorkerCompletedEventArgs e) { if (e.Error != null) { // Why could there be an error? Probably wouldn't be. } if (!CheckMD5(Path.Combine(_target, String.Concat(CleanFileName(_product), ".file")), _product)) { Notification n = new Notification("Error: Checksum of " + _product + " failed :(", true); // Could-Have: More graceful dealing with this (redownloading that product perhaps) // Problem is, trying to do that simply could end up with a huge memory leak (millions of recursive threads, sort of fork bomb) } else { Notification n = new Notification("Download complete!", true); // The downlad's complete! } }
/// <summary> /// The RunWorkerCompleted event of the BackgroundWorker. Runs when the BackgroundWorker has finished. /// MD5 checksums the download and proclaims it complete or displays an error as appropriate. /// </summary> /// <param name="sender"></param> /// <param name="e"></param> private void Complete(object sender, RunWorkerCompletedEventArgs e) { if (e.Error != null) { // TODO: Why could there be an error? } else { if (!CheckMD5(Path.Combine(_target, String.Concat(CleanFileName(_product), ".file")), _product)) { Notification n = new Notification("Error: Checksum of " + _product + " failed :(", true); // TODO: Work out how to deal with this } else { Notification n = new Notification("Download complete!", false); // The downlad's complete! } } }