شركة التطبيقات المتكاملة لتصميم النظم البرمجية الخاصة

Integrated Applications Programming Company

Skip Navigation LinksHome » Code Library » Ftp

Public general use code classes and xml files that we've compiled and used over the years:

A wrapper class for .NET 2.0 FTP

   1:  using System.Diagnostics;
   2:  using System.Data;
   3:  using System.Collections;
   4:  using Microsoft.VisualBasic;
   5:  using System.Collections.Generic;
   6:  using System;
   7:  using System.Net;
   8:  using System.IO;
   9:  using System.Text.RegularExpressions;
  10:   
  11:  namespace Ia.Cl.Model
  12:  {
  13:      /// <summary publish="true">
  14:      /// A wrapper class for .NET 2.0 FTP
  15:      /// </summary>
  16:      /// </summary>
  17:      /// <remarks> 
  18:      /// This class does not hold open an FTP connection but instead is stateless: for each FTP request it connects, performs the request and disconnects.
  19:      /// </remarks>
  20:      /// 
  21:      /// </summary>
  22:      /// <remarks> 
  23:      /// Copyright � 2001-2015 Jasem Y. Al-Shamlan (info@ia.com.kw), Internet Applications - Kuwait. All Rights Reserved.
  24:      ///
  25:      /// This library is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by
  26:      /// the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
  27:      ///
  28:      /// This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
  29:      /// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
  30:      /// 
  31:      /// You should have received a copy of the GNU General Public License along with this library. If not, see http://www.gnu.org/licenses.
  32:      /// 
  33:      /// Copyright notice: This notice may not be removed or altered from any source distribution.
  34:      /// </remarks>
  35:      public class Ftp
  36:      {
  37:          /// <summary>
  38:          /// Blank constructor
  39:          /// </summary>
  40:          /// </summary>
  41:          /// <remarks> Hostname, username and password must be set manually</remarks>
  42:          public Ftp()
  43:          {
  44:          }
  45:   
  46:          ////////////////////////////////////////////////////////////////////////////
  47:   
  48:          /// <summary>
  49:          /// Constructor just taking the hostname
  50:          /// </summary>
  51:          /// <param name="Hostname">in either ftp://ftp.host.com or ftp.host.com form</param>
  52:          /// </summary>
  53:          /// <remarks> 
  54:          /// </remarks>
  55:          public Ftp(string Hostname)
  56:          {
  57:              _hostname = Hostname;
  58:          }
  59:   
  60:          ////////////////////////////////////////////////////////////////////////////
  61:   
  62:          /// <summary>
  63:          /// Constructor taking hostname, username and password
  64:          /// </summary>
  65:          /// <param name="Hostname">in either ftp://ftp.host.com or ftp.host.com form</param>
  66:          /// <param name="Username">Leave blank to use 'anonymous' but set password to your email</param>
  67:          /// <param name="Password"></param>
  68:          /// </summary>
  69:          /// <remarks> </remarks>
  70:          public Ftp(string Hostname, string Username, string Password)
  71:          {
  72:              _hostname = Hostname;
  73:              _username = Username;
  74:              _password = Password;
  75:          }
  76:   
  77:          ////////////////////////////////////////////////////////////////////////////
  78:   
  79:          /// <summary>
  80:          /// Return a simple directory listing
  81:          /// </summary>
  82:          /// <param name="directory">Directory to list, e.g. /pub</param>
  83:          /// <returns>A list of filenames and directories as a List(of String)</returns>
  84:          /// </summary>
  85:          /// <remarks> For a detailed directory listing, use ListDirectoryDetail</remarks>
  86:          public List<string> ListDirectory(string directory)
  87:          {
  88:              //return a simple list of filenames in directory
  89:              System.Net.FtpWebRequest ftp = GetRequest(GetDirectory(directory));
  90:              //Set request to do simple list
  91:              ftp.Method = System.Net.WebRequestMethods.Ftp.ListDirectory;
  92:   
  93:              string str = GetStringResponse(ftp);
  94:              //replace CRLF to CR, remove last instance
  95:              str = str.Replace("\r\n", "\r").TrimEnd('\r');
  96:              //split the string into a list
  97:              List<string> result = new List<string>();
  98:              result.AddRange(str.Split('\r'));
  99:              return result;
 100:          }
 101:   
 102:          ////////////////////////////////////////////////////////////////////////////
 103:   
 104:          /// <summary>
 105:          /// Return a detailed directory listing
 106:          /// </summary>
 107:          /// <param name="directory">Directory to list, e.g. /pub/etc</param>
 108:          /// <returns>An FtpDirectory object</returns>
 109:          public FtpDirectory ListDirectoryDetail(string directory)
 110:          {
 111:              System.Net.FtpWebRequest ftp = GetRequest(GetDirectory(directory));
 112:              //Set request to do simple list
 113:              ftp.Method = System.Net.WebRequestMethods.Ftp.ListDirectoryDetails;
 114:   
 115:              string str = GetStringResponse(ftp);
 116:              //replace CRLF to CR, remove last instance
 117:              str = str.Replace("\r\n", "\r").TrimEnd('\r');
 118:              //split the string into a list
 119:              return new FtpDirectory(str, _lastDirectory);
 120:          }
 121:   
 122:          ////////////////////////////////////////////////////////////////////////////
 123:   
 124:          /// <summary>
 125:          /// Copy a local file to the FTP server
 126:          /// </summary>
 127:          /// <param name="localFilename">Full path of the local file</param>
 128:          /// <param name="targetFilename">Target filename, if required</param>
 129:          /// <returns></returns>
 130:          /// </summary>
 131:          /// <remarks> If the target filename is blank, the source filename is used
 132:          /// (assumes current directory). Otherwise use a filename to specify a name
 133:          /// or a full path and filename if required.</remarks>
 134:          public bool Upload(string localFilename, string targetFilename)
 135:          {
 136:              //1. check source
 137:              if (!File.Exists(localFilename))
 138:              {
 139:                  throw (new ApplicationException("File " + localFilename + " not found"));
 140:              }
 141:              //copy to FI
 142:              FileInfo fi = new FileInfo(localFilename);
 143:              return Upload(fi, targetFilename);
 144:          }
 145:   
 146:          ////////////////////////////////////////////////////////////////////////////
 147:   
 148:          /// <summary>
 149:          /// Upload a local file to the FTP server
 150:          /// </summary>
 151:          /// <param name="fi">Source file</param>
 152:          /// <param name="targetFilename">Target filename (optional)</param>
 153:          /// <returns></returns>
 154:          public bool Upload(FileInfo fi, string targetFilename)
 155:          {
 156:              //copy the file specified to target file: target file can be full path or just filename (uses current dir)
 157:   
 158:              //1. check target
 159:              string target;
 160:              if (targetFilename.Trim() == "")
 161:              {
 162:                  //Blank target: use source filename & current dir
 163:                  target = this.CurrentDirectory + fi.Name;
 164:              }
 165:              else if (targetFilename.Contains("/"))
 166:              {
 167:                  //If contains / treat as a full path
 168:                  target = AdjustDir(targetFilename);
 169:              }
 170:              else
 171:              {
 172:                  //otherwise treat as filename only, use current directory
 173:                  target = CurrentDirectory + targetFilename;
 174:              }
 175:   
 176:              string URI = Hostname + target;
 177:              //perform copy
 178:              System.Net.FtpWebRequest ftp = GetRequest(URI);
 179:   
 180:              //Set request to upload a file in binary
 181:              ftp.Method = System.Net.WebRequestMethods.Ftp.UploadFile;
 182:              ftp.UseBinary = true;
 183:   
 184:              //Notify FTP of the expected size
 185:              ftp.ContentLength = fi.Length;
 186:   
 187:              //create byte array to store: ensure at least 1 byte!
 188:              const int BufferSize = 2048;
 189:              byte[] content = new byte[BufferSize - 1 + 1];
 190:              int dataRead;
 191:   
 192:              //open file for reading
 193:              using (FileStream fs = fi.OpenRead())
 194:              {
 195:                  //open request to send
 196:                  using (Stream rs = ftp.GetRequestStream())
 197:                  {
 198:                      do
 199:                      {
 200:                          dataRead = fs.Read(content, 0, BufferSize);
 201:                          rs.Write(content, 0, dataRead);
 202:                      } while (!(dataRead < BufferSize));
 203:   
 204:                      //rs.Close();
 205:                  }
 206:              }
 207:   
 208:              ftp = null;
 209:   
 210:              return true;
 211:          }
 212:   
 213:          ////////////////////////////////////////////////////////////////////////////
 214:   
 215:          /// <summary>
 216:          /// Copy a file from FTP server to local
 217:          /// </summary>
 218:          /// <param name="sourceFilename">Target filename, if required</param>
 219:          /// <param name="localFilename">Full path of the local file</param>
 220:          /// <param name="PermitOverwrite"></param>
 221:          /// <returns></returns>
 222:          /// </summary>
 223:          /// <remarks> Target can be blank (use same filename), or just a filename
 224:          /// (assumes current directory) or a full path and filename</remarks>
 225:          public bool Download(string sourceFilename, string localFilename, bool PermitOverwrite)
 226:          {
 227:              //2. determine target file
 228:              FileInfo fi = new FileInfo(localFilename);
 229:              return this.Download(sourceFilename, fi, PermitOverwrite);
 230:          }
 231:   
 232:          ////////////////////////////////////////////////////////////////////////////
 233:   
 234:          /// <summary>
 235:          ///
 236:          /// </summary>
 237:          //Version taking an FtpFileInfo
 238:          public bool Download(FtpFileInfo file, string localFilename, bool PermitOverwrite)
 239:          {
 240:              return this.Download(file.FullName, localFilename, PermitOverwrite);
 241:          }
 242:   
 243:          ////////////////////////////////////////////////////////////////////////////
 244:   
 245:          /// <summary>
 246:          ///
 247:          /// </summary>
 248:          //Another version taking FtpFileInfo and FileInfo
 249:          public bool Download(FtpFileInfo file, FileInfo localFI, bool PermitOverwrite)
 250:          {
 251:              return this.Download(file.FullName, localFI, PermitOverwrite);
 252:          }
 253:   
 254:          ////////////////////////////////////////////////////////////////////////////
 255:   
 256:          /// <summary>
 257:          ///
 258:          /// </summary>
 259:          //Version taking string/FileInfo
 260:          public bool Download(string sourceFilename, FileInfo targetFI, bool PermitOverwrite)
 261:          {
 262:              //1. check target
 263:              if (targetFI.Exists && !(PermitOverwrite))
 264:              {
 265:                  throw (new ApplicationException("Target file already exists"));
 266:              }
 267:   
 268:              //2. check source
 269:              string target;
 270:              if (sourceFilename.Trim() == "")
 271:              {
 272:                  throw (new ApplicationException("File not specified"));
 273:              }
 274:              else if (sourceFilename.Contains("/"))
 275:              {
 276:                  //treat as a full path
 277:                  target = AdjustDir(sourceFilename);
 278:              }
 279:              else
 280:              {
 281:                  //treat as filename only, use current directory
 282:                  target = CurrentDirectory + sourceFilename;
 283:              }
 284:   
 285:              string URI = Hostname + target;
 286:   
 287:              //3. perform copy
 288:              System.Net.FtpWebRequest ftp = GetRequest(URI);
 289:   
 290:              //Set request to download a file in binary mode
 291:              ftp.Method = System.Net.WebRequestMethods.Ftp.DownloadFile;
 292:              ftp.UseBinary = true;
 293:   
 294:              //open request and get response stream
 295:              using (FtpWebResponse response = (FtpWebResponse)ftp.GetResponse())
 296:              {
 297:                  using (Stream responseStream = response.GetResponseStream())
 298:                  {
 299:                      //loop to read & write to file
 300:                      using (FileStream fs = targetFI.OpenWrite())
 301:                      {
 302:                          byte[] buffer = new byte[2048];
 303:                          int read = 0;
 304:                          do
 305:                          {
 306:                              read = responseStream.Read(buffer, 0, buffer.Length);
 307:                              fs.Write(buffer, 0, read);
 308:                          } while (!(read == 0));
 309:   
 310:                          //responseStream.Close();
 311:                          //fs.Flush();
 312:                          //fs.Close();
 313:                      }
 314:   
 315:                      //responseStream.Close();
 316:                  }
 317:   
 318:                  //response.Close();
 319:              }
 320:   
 321:              return true;
 322:          }
 323:   
 324:          ////////////////////////////////////////////////////////////////////////////
 325:   
 326:          /// <summary>
 327:          /// Delete remote file
 328:          /// </summary>
 329:          /// <param name="filename">filename or full path</param>
 330:          /// <returns></returns>
 331:          /// </summary>
 332:          /// <remarks> </remarks>
 333:          public bool FtpDelete(string filename)
 334:          {
 335:              //Determine if file or full path
 336:              string URI = this.Hostname + GetFullPath(filename);
 337:   
 338:              System.Net.FtpWebRequest ftp = GetRequest(URI);
 339:              //Set request to delete
 340:              ftp.Method = System.Net.WebRequestMethods.Ftp.DeleteFile;
 341:              try
 342:              {
 343:                  //get response but ignore it
 344:                  string str = GetStringResponse(ftp);
 345:              }
 346:              catch (Exception)
 347:              {
 348:                  return false;
 349:              }
 350:              return true;
 351:          }
 352:   
 353:          ////////////////////////////////////////////////////////////////////////////
 354:   
 355:          /// <summary>
 356:          /// Determine if file exists on remote FTP site
 357:          /// </summary>
 358:          /// <param name="filename">Filename (for current dir) or full path</param>
 359:          /// <returns></returns>
 360:          /// </summary>
 361:          /// <remarks> Note this only works for files</remarks>
 362:          public bool FtpFileExists(string filename)
 363:          {
 364:              //Try to obtain filesize: if we get error msg containing "550"
 365:              //the file does not exist
 366:              try
 367:              {
 368:                  long size = GetFileSize(filename);
 369:                  return true;
 370:   
 371:              }
 372:              catch (Exception ex)
 373:              {
 374:                  //only handle expected not-found exception
 375:                  if (ex is System.Net.WebException)
 376:                  {
 377:                      //file does not exist/no rights error = 550
 378:                      if (ex.Message.Contains("550"))
 379:                      {
 380:                          //clear
 381:                          return false;
 382:                      }
 383:                      else
 384:                      {
 385:                          throw;
 386:                      }
 387:                  }
 388:                  else
 389:                  {
 390:                      throw;
 391:                  }
 392:              }
 393:          }
 394:   
 395:          ////////////////////////////////////////////////////////////////////////////
 396:   
 397:          /// <summary>
 398:          /// Determine size of remote file
 399:          /// </summary>
 400:          /// <param name="filename"></param>
 401:          /// <returns></returns>
 402:          /// </summary>
 403:          /// <remarks> Throws an exception if file does not exist</remarks>
 404:          public long GetFileSize(string filename)
 405:          {
 406:              string path;
 407:              if (filename.Contains("/"))
 408:              {
 409:                  path = AdjustDir(filename);
 410:              }
 411:              else
 412:              {
 413:                  path = this.CurrentDirectory + filename;
 414:              }
 415:              string URI = this.Hostname + path;
 416:              System.Net.FtpWebRequest ftp = GetRequest(URI);
 417:              //Try to get info on file/dir?
 418:              ftp.Method = System.Net.WebRequestMethods.Ftp.GetFileSize;
 419:              string tmp = this.GetStringResponse(ftp);
 420:              return GetSize(ftp);
 421:          }
 422:   
 423:          ////////////////////////////////////////////////////////////////////////////
 424:   
 425:          /// <summary>
 426:          ///
 427:          /// </summary>
 428:          public bool FtpRename(string sourceFilename, string newName)
 429:          {
 430:              //Does file exist?
 431:              string source = GetFullPath(sourceFilename);
 432:              if (!FtpFileExists(source))
 433:              {
 434:                  throw (new FileNotFoundException("File " + source + " not found"));
 435:              }
 436:   
 437:              //build target name, ensure it does not exist
 438:              string target = GetFullPath(newName);
 439:              if (target == source)
 440:              {
 441:                  throw (new ApplicationException("Source and target are the same"));
 442:              }
 443:              else if (FtpFileExists(target))
 444:              {
 445:                  throw (new ApplicationException("Target file " + target + " already exists"));
 446:              }
 447:   
 448:              //perform rename
 449:              string URI = this.Hostname + source;
 450:   
 451:              System.Net.FtpWebRequest ftp = GetRequest(URI);
 452:              //Set request to delete
 453:              ftp.Method = System.Net.WebRequestMethods.Ftp.Rename;
 454:              ftp.RenameTo = target;
 455:              try
 456:              {
 457:                  //get response but ignore it
 458:                  string str = GetStringResponse(ftp);
 459:              }
 460:              catch (Exception)
 461:              {
 462:                  return false;
 463:              }
 464:              return true;
 465:          }
 466:   
 467:          ////////////////////////////////////////////////////////////////////////////
 468:   
 469:          /// <summary>
 470:          ///
 471:          /// </summary>
 472:          public bool FtpCreateDirectory(string dirpath)
 473:          {
 474:              //perform create
 475:              string URI = this.Hostname + AdjustDir(dirpath);
 476:              System.Net.FtpWebRequest ftp = GetRequest(URI);
 477:              //Set request to MkDir
 478:              ftp.Method = System.Net.WebRequestMethods.Ftp.MakeDirectory;
 479:              try
 480:              {
 481:                  //get response but ignore it
 482:                  string str = GetStringResponse(ftp);
 483:              }
 484:              catch (Exception)
 485:              {
 486:                  return false;
 487:              }
 488:              return true;
 489:          }
 490:   
 491:          ////////////////////////////////////////////////////////////////////////////
 492:   
 493:          /// <summary>
 494:          ///
 495:          /// </summary>
 496:          public bool FtpDeleteDirectory(string dirpath)
 497:          {
 498:              //perform remove
 499:              string URI = this.Hostname + AdjustDir(dirpath);
 500:              System.Net.FtpWebRequest ftp = GetRequest(URI);
 501:              //Set request to RmDir
 502:              ftp.Method = System.Net.WebRequestMethods.Ftp.RemoveDirectory;
 503:              try
 504:              {
 505:                  //get response but ignore it
 506:                  string str = GetStringResponse(ftp);
 507:              }
 508:              catch (Exception)
 509:              {
 510:                  return false;
 511:              }
 512:              return true;
 513:          }
 514:   
 515:          //Get the basic FtpWebRequest object with the
 516:          //common settings and security
 517:   
 518:          ////////////////////////////////////////////////////////////////////////////
 519:   
 520:          /// <summary>
 521:          ///
 522:          /// </summary>
 523:          private FtpWebRequest GetRequest(string URI)
 524:          {
 525:              //create request
 526:              FtpWebRequest result = (FtpWebRequest)FtpWebRequest.Create(URI);
 527:              //Set the login details
 528:              result.Credentials = GetCredentials();
 529:              //Do not keep alive (stateless mode)
 530:              result.KeepAlive = false;
 531:              return result;
 532:          }
 533:   
 534:          ////////////////////////////////////////////////////////////////////////////
 535:   
 536:          /// <summary>
 537:          /// Get the credentials from username/password
 538:          /// </summary>
 539:          private System.Net.ICredentials GetCredentials()
 540:          {
 541:              return new System.Net.NetworkCredential(Username, Password);
 542:          }
 543:   
 544:          ////////////////////////////////////////////////////////////////////////////
 545:   
 546:          /// <summary>
 547:          /// returns a full path using CurrentDirectory for a relative file reference
 548:          /// </summary>
 549:          private string GetFullPath(string file)
 550:          {
 551:              if (file.Contains("/"))
 552:              {
 553:                  return AdjustDir(file);
 554:              }
 555:              else
 556:              {
 557:                  return this.CurrentDirectory + file;
 558:              }
 559:          }
 560:   
 561:          ////////////////////////////////////////////////////////////////////////////
 562:   
 563:          /// <summary>
 564:          /// Amend an FTP path so that it always starts with /
 565:          /// </summary>
 566:          /// <param name="path">Path to adjust</param>
 567:          /// <returns></returns>
 568:          /// </summary>
 569:          /// <remarks> </remarks>
 570:          private string AdjustDir(string path)
 571:          {
 572:              return ((path.StartsWith("/")) ? "" : "/").ToString() + path;
 573:          }
 574:   
 575:          ////////////////////////////////////////////////////////////////////////////
 576:   
 577:          /// <summary>
 578:          ///
 579:          /// </summary>
 580:          private string GetDirectory(string directory)
 581:          {
 582:              string URI;
 583:              if (directory == "")
 584:              {
 585:                  //build from current
 586:                  URI = Hostname + this.CurrentDirectory;
 587:                  _lastDirectory = this.CurrentDirectory;
 588:              }
 589:              else
 590:              {
 591:                  if (!directory.StartsWith("/"))
 592:                  {
 593:                      throw (new ApplicationException("Directory should start with /"));
 594:                  }
 595:                  URI = this.Hostname + directory;
 596:                  _lastDirectory = directory;
 597:              }
 598:              return URI;
 599:          }
 600:   
 601:          //stores last retrieved/set directory
 602:          private string _lastDirectory = "";
 603:   
 604:          ////////////////////////////////////////////////////////////////////////////
 605:   
 606:          /// <summary>
 607:          /// Obtains a response stream as a string
 608:          /// </summary>
 609:          /// <param name="ftp">current FTP request</param>
 610:          /// <returns>String containing response</returns>
 611:          /// </summary>
 612:          /// <remarks> FTP servers typically return strings with CR and
 613:          /// not CRLF. Use respons.Replace(vbCR, vbCRLF) to convert
 614:          /// to an MSDOS string</remarks>
 615:          private string GetStringResponse(FtpWebRequest ftp)
 616:          {
 617:              //Get the result, streaming to a string
 618:              string result = "";
 619:              using (FtpWebResponse response = (FtpWebResponse)ftp.GetResponse())
 620:              {
 621:                  long size = response.ContentLength;
 622:                  using (Stream datastream = response.GetResponseStream())
 623:                  {
 624:                      using (StreamReader sr = new StreamReader(datastream))
 625:                      {
 626:                          result = sr.ReadToEnd();
 627:                          //sr.Close();
 628:                      }
 629:   
 630:                      //datastream.Close();
 631:                  }
 632:   
 633:                  //response.Close();
 634:              }
 635:   
 636:              return result;
 637:          }
 638:   
 639:          ////////////////////////////////////////////////////////////////////////////
 640:   
 641:          /// <summary>
 642:          /// Gets the size of an FTP request
 643:          /// </summary>
 644:          /// <param name="ftp"></param>
 645:          /// <returns></returns>
 646:          /// </summary>
 647:          /// <remarks> </remarks>
 648:          private long GetSize(FtpWebRequest ftp)
 649:          {
 650:              long size;
 651:              using (FtpWebResponse response = (FtpWebResponse)ftp.GetResponse())
 652:              {
 653:                  size = response.ContentLength;
 654:   
 655:                  //response.Close();
 656:              }
 657:   
 658:              return size;
 659:          }
 660:   
 661:          private string _hostname;
 662:   
 663:          ////////////////////////////////////////////////////////////////////////////
 664:   
 665:          /// <summary>
 666:          /// Hostname
 667:          /// </summary>
 668:          /// <value></value>
 669:          /// </summary>
 670:          /// <remarks> Hostname can be in either the full URL format
 671:          /// ftp://ftp.myhost.com or just ftp.myhost.com
 672:          /// </remarks>
 673:          public string Hostname
 674:          {
 675:              get
 676:              {
 677:                  if (_hostname.StartsWith("ftp://"))
 678:                  {
 679:                      return _hostname;
 680:                  }
 681:                  else
 682:                  {
 683:                      return "ftp://" + _hostname;
 684:                  }
 685:              }
 686:              set
 687:              {
 688:                  _hostname = value;
 689:              }
 690:          }
 691:          private string _username;
 692:   
 693:          ////////////////////////////////////////////////////////////////////////////
 694:   
 695:          /// <summary>
 696:          /// Username property
 697:          /// </summary>
 698:          /// <value></value>
 699:          /// </summary>
 700:          /// <remarks> Can be left blank, in which case 'anonymous' is returned</remarks>
 701:          public string Username
 702:          {
 703:              get
 704:              {
 705:                  return (_username == "" ? "anonymous" : _username);
 706:              }
 707:              set
 708:              {
 709:                  _username = value;
 710:              }
 711:          }
 712:          private string _password;
 713:   
 714:          ////////////////////////////////////////////////////////////////////////////
 715:   
 716:          /// <summary>
 717:          ///
 718:          /// </summary>
 719:          public string Password
 720:          {
 721:              get
 722:              {
 723:                  return _password;
 724:              }
 725:              set
 726:              {
 727:                  _password = value;
 728:              }
 729:          }
 730:   
 731:          ////////////////////////////////////////////////////////////////////////////
 732:   
 733:          /// <summary>
 734:          /// The CurrentDirectory value
 735:          /// </summary>
 736:          /// </summary>
 737:          /// <remarks> Defaults to the root '/'</remarks>
 738:          private string _currentDirectory = "/";
 739:   
 740:          ////////////////////////////////////////////////////////////////////////////
 741:   
 742:          /// <summary>
 743:          ///
 744:          /// </summary>
 745:          public string CurrentDirectory
 746:          {
 747:              get
 748:              {
 749:                  //return directory, ensure it ends with /
 750:                  return _currentDirectory + ((_currentDirectory.EndsWith("/")) ? "" : "/").ToString();
 751:              }
 752:              set
 753:              {
 754:                  if (!value.StartsWith("/"))
 755:                  {
 756:                      throw (new ApplicationException("Directory should start with /"));
 757:                  }
 758:                  _currentDirectory = value;
 759:              }
 760:          }
 761:      }
 762:   
 763:      ////////////////////////////////////////////////////////////////////////////
 764:      ////////////////////////////////////////////////////////////////////////////
 765:   
 766:      /// <summary>
 767:      /// Represents a file or directory entry from an FTP listing
 768:      /// </summary>
 769:      /// </summary>
 770:      /// <remarks> 
 771:      /// This class is used to parse the results from a detailed
 772:      /// directory list from FTP. It supports most formats of
 773:      /// </remarks>
 774:      public class FtpFileInfo
 775:      {
 776:   
 777:          //Stores extended info about FTP file
 778:   
 779:          /// <summary/>
 780:          public string FullName
 781:          {
 782:              get
 783:              {
 784:                  return Path + Filename;
 785:              }
 786:          }
 787:   
 788:          /// <summary/>
 789:          public string Filename
 790:          {
 791:              get
 792:              {
 793:                  return _filename;
 794:              }
 795:          }
 796:   
 797:          /// <summary/>
 798:          public string Path
 799:          {
 800:              get
 801:              {
 802:                  return _path;
 803:              }
 804:          }
 805:   
 806:          /// <summary/>
 807:          public DirectoryEntryTypes FileType
 808:          {
 809:              get
 810:              {
 811:                  return _fileType;
 812:              }
 813:          }
 814:   
 815:          /// <summary/>
 816:          public long Size
 817:          {
 818:              get
 819:              {
 820:                  return _size;
 821:              }
 822:          }
 823:   
 824:          /// <summary/>
 825:          public DateTime FileDateTime
 826:          {
 827:              get
 828:              {
 829:                  return _fileDateTime;
 830:              }
 831:          }
 832:   
 833:          /// <summary/>
 834:          public string Permission
 835:          {
 836:              get
 837:              {
 838:                  return _permission;
 839:              }
 840:          }
 841:   
 842:          /// <summary/>
 843:          public string Extension
 844:          {
 845:              get
 846:              {
 847:                  int i = this.Filename.LastIndexOf(".");
 848:                  if (i >= 0 && i < (this.Filename.Length - 1))
 849:                  {
 850:                      return this.Filename.Substring(i + 1);
 851:                  }
 852:                  else
 853:                  {
 854:                      return "";
 855:                  }
 856:              }
 857:          }
 858:   
 859:          /// <summary/>
 860:          public string NameOnly
 861:          {
 862:              get
 863:              {
 864:                  int i = this.Filename.LastIndexOf(".");
 865:                  if (i > 0)
 866:                  {
 867:                      return this.Filename.Substring(0, i);
 868:                  }
 869:                  else
 870:                  {
 871:                      return this.Filename;
 872:                  }
 873:              }
 874:          }
 875:   
 876:          private string _filename;
 877:          private string _path;
 878:          private DirectoryEntryTypes _fileType;
 879:          private long _size;
 880:          private DateTime _fileDateTime;
 881:          private string _permission;
 882:   
 883:          /// <summary>
 884:          /// Identifies entry as either File or Directory
 885:          /// </summary>
 886:          public enum DirectoryEntryTypes
 887:          {
 888:              /// <summary/>
 889:              File,
 890:   
 891:              /// <summary/>
 892:              Directory
 893:          }
 894:   
 895:          /// <summary>
 896:          /// Constructor taking a directory listing line and path
 897:          /// </summary>
 898:          /// <param name="line">The line returned from the detailed directory list</param>
 899:          /// <param name="path">Path of the directory</param>
 900:          /// </summary>
 901:          /// <remarks> </remarks>
 902:          public FtpFileInfo(string line, string path)
 903:          {
 904:              //parse line
 905:              Match m = GetMatchingRegex(line);
 906:              if (m == null)
 907:              {
 908:                  //failed
 909:                  throw (new ApplicationException("Unable to parse line: " + line));
 910:              }
 911:              else
 912:              {
 913:                  _filename = m.Groups["name"].Value;
 914:                  _path = path;
 915:   
 916:                  Int64.TryParse(m.Groups["size"].Value, out _size);
 917:                  //_size = System.Convert.ToInt32(m.Groups["size"].Value);
 918:   
 919:                  _permission = m.Groups["permission"].Value;
 920:                  string _dir = m.Groups["dir"].Value;
 921:                  if (_dir != "" && _dir != "-")
 922:                  {
 923:                      _fileType = DirectoryEntryTypes.Directory;
 924:                  }
 925:                  else
 926:                  {
 927:                      _fileType = DirectoryEntryTypes.File;
 928:                  }
 929:   
 930:                  try
 931:                  {
 932:                      _fileDateTime = DateTime.Parse(m.Groups["timestamp"].Value);
 933:                  }
 934:                  catch (Exception)
 935:                  {
 936:                      _fileDateTime = Convert.ToDateTime(null);
 937:                  }
 938:   
 939:              }
 940:          }
 941:   
 942:          ////////////////////////////////////////////////////////////////////////////
 943:   
 944:          /// <summary>
 945:          ///
 946:          /// </summary>
 947:          private Match GetMatchingRegex(string line)
 948:          {
 949:              Regex rx;
 950:              Match m;
 951:              for (int i = 0; i <= _ParseFormats.Length - 1; i++)
 952:              {
 953:                  rx = new Regex(_ParseFormats[i]);
 954:                  m = rx.Match(line);
 955:                  if (m.Success)
 956:                  {
 957:                      return m;
 958:                  }
 959:              }
 960:              return null;
 961:          }
 962:   
 963:          /// <summary>
 964:          /// List of REGEX formats for different FTP server listing formats
 965:          /// </summary>
 966:          /// </summary>
 967:          /// <remarks> 
 968:          /// The first three are various UNIX/LINUX formats, fourth is for MS FTP
 969:          /// in detailed mode and the last for MS FTP in 'DOS' mode.
 970:          /// I wish VB.NET had support for Const arrays like C# but there you go
 971:          /// </remarks>
 972:          private static string[] _ParseFormats = new string[] { 
 973:              "(?<dir>[\\-d])(?<permission>([\\-r][\\-w][\\-xs]){3})\\s+\\d+\\s+\\w+\\s+\\w+\\s+(?<size>\\d+)\\s+(?<timestamp>\\w+\\s+\\d+\\s+\\d{4})\\s+(?<name>.+)", 
 974:              "(?<dir>[\\-d])(?<permission>([\\-r][\\-w][\\-xs]){3})\\s+\\d+\\s+\\d+\\s+(?<size>\\d+)\\s+(?<timestamp>\\w+\\s+\\d+\\s+\\d{4})\\s+(?<name>.+)", 
 975:              "(?<dir>[\\-d])(?<permission>([\\-r][\\-w][\\-xs]){3})\\s+\\d+\\s+\\d+\\s+(?<size>\\d+)\\s+(?<timestamp>\\w+\\s+\\d+\\s+\\d{1,2}:\\d{2})\\s+(?<name>.+)", 
 976:              "(?<dir>[\\-d])(?<permission>([\\-r][\\-w][\\-xs]){3})\\s+\\d+\\s+\\w+\\s+\\w+\\s+(?<size>\\d+)\\s+(?<timestamp>\\w+\\s+\\d+\\s+\\d{1,2}:\\d{2})\\s+(?<name>.+)", 
 977:              "(?<dir>[\\-d])(?<permission>([\\-r][\\-w][\\-xs]){3})(\\s+)(?<size>(\\d+))(\\s+)(?<ctbit>(\\w+\\s\\w+))(\\s+)(?<size2>(\\d+))\\s+(?<timestamp>\\w+\\s+\\d+\\s+\\d{2}:\\d{2})\\s+(?<name>.+)", 
 978:              "(?<timestamp>\\d{2}\\-\\d{2}\\-\\d{2}\\s+\\d{2}:\\d{2}[Aa|Pp][mM])\\s+(?<dir>\\<\\w+\\>){0,1}(?<size>\\d+){0,1}\\s+(?<name>.+)" };
 979:      }
 980:   
 981:      /// <summary>
 982:      /// Stores a list of files and directories from an FTP result
 983:      /// </summary>
 984:      /// </summary>
 985:      /// <remarks> </remarks>
 986:      public class FtpDirectory : List<FtpFileInfo>
 987:      {
 988:          ////////////////////////////////////////////////////////////////////////////
 989:   
 990:          /// <summary>
 991:          ///
 992:          /// </summary>
 993:          public FtpDirectory()
 994:          {
 995:              //creates a blank directory listing
 996:          }
 997:   
 998:          /// <summary>
 999:          /// Constructor: create list from a (detailed) directory string
1000:          /// </summary>
1001:          /// <param name="dir">directory listing string</param>
1002:          /// <param name="path"></param>
1003:          /// </summary>
1004:          /// <remarks> </remarks>
1005:          public FtpDirectory(string dir, string path)
1006:          {
1007:              foreach (string line in dir.Replace("\n", "").Split(System.Convert.ToChar('\r')))
1008:              {
1009:                  //parse
1010:                  if (line != "")
1011:                  {
1012:                      this.Add(new FtpFileInfo(line, path));
1013:                  }
1014:              }
1015:          }
1016:   
1017:          /// <summary>
1018:          /// Filter out only files from directory listing
1019:          /// </summary>
1020:          /// <param name="ext">optional file extension filter</param>
1021:          /// <returns>FtpDirectory listing</returns>
1022:          public FtpDirectory GetFiles(string ext)
1023:          {
1024:              return this.GetFileOrDir(FtpFileInfo.DirectoryEntryTypes.File, ext);
1025:          }
1026:   
1027:          /// <summary>
1028:          /// Returns a list of only subdirectories
1029:          /// </summary>
1030:          /// <returns>FtpDirectory list</returns>
1031:          /// </summary>
1032:          /// <remarks> </remarks>
1033:          public FtpDirectory GetDirectories()
1034:          {
1035:              return this.GetFileOrDir(FtpFileInfo.DirectoryEntryTypes.Directory, "");
1036:          }
1037:   
1038:          //internal: share use function for GetDirectories/Files
1039:          private FtpDirectory GetFileOrDir(FtpFileInfo.DirectoryEntryTypes type, string ext)
1040:          {
1041:              FtpDirectory result = new FtpDirectory();
1042:              foreach (FtpFileInfo fi in this)
1043:              {
1044:                  if (fi.FileType == type)
1045:                  {
1046:                      if (ext == "")
1047:                      {
1048:                          result.Add(fi);
1049:                      }
1050:                      else if (ext == fi.Extension)
1051:                      {
1052:                          result.Add(fi);
1053:                      }
1054:                  }
1055:              }
1056:              return result;
1057:   
1058:          }
1059:   
1060:          /// <summary/>
1061:          public bool FileExists(string filename)
1062:          {
1063:              foreach (FtpFileInfo ftpfile in this)
1064:              {
1065:                  if (ftpfile.Filename == filename)
1066:                  {
1067:                      return true;
1068:                  }
1069:              }
1070:              return false;
1071:          }
1072:   
1073:          private const char slash = '/';
1074:   
1075:          /// <summary/>
1076:          public static string GetParentDirectory(string dir)
1077:          {
1078:              string tmp = dir.TrimEnd(slash);
1079:              int i = tmp.LastIndexOf(slash);
1080:              if (i > 0)
1081:              {
1082:                  return tmp.Substring(0, i - 1);
1083:              }
1084:              else
1085:              {
1086:                  throw (new ApplicationException("No parent for root"));
1087:              }
1088:          }
1089:      }
1090:  }
1091: