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

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