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