using System.Net; using System.Text; using FluentFTP; using HeyRed.Mime; namespace Shoko; [Protocol("ftp")] [Protocol("ftps")] class FtpProtoHandler : ProtoHandler { public FtpProtoHandler(Uri url) { URL = url; } public override void Load() { var file = URL.AbsolutePath; var conn = new FtpClient { Host = URL.Host, Port = URL.Port }; if (URL.UserInfo.Length > 0) { var userinfo = URL.UserInfo.Split(":",2); var user = userinfo[0]; var pass = userinfo.Length > 1 ? userinfo[1] : ""; conn.Credentials = new NetworkCredential(user, pass); } if(URL.Scheme == "ftps") { conn.Config.EncryptionMode = FtpEncryptionMode.Explicit; conn.Config.ValidateAnyCertificate = true; } conn.Config.LogToConsole = true; conn.Config.LogHost = true; conn.Config.LogUserName = true; conn.Config.LogPassword = true; conn.Connect(); MediaType = "text/plain"; // TODO: magic numbers Status = "OK"; var info = conn.GetObjectInfo(file); if(info is not null) { switch(info.Type) { case FtpObjectType.File: //Content = conn.OpenRead(file); if(conn.DownloadBytes(out byte[] bytes, info.FullName)) { Content = new MemoryStream(bytes); MediaType = MimeGuesser.GuessMimeType(Content); } break; case FtpObjectType.Directory: MediaType = "text/gemini"; var entries = conn.GetListing(info.FullName); var str = "# "+file+"\r\n"; foreach(var entry in entries) { var path = entry.Name; if(entry.Type == FtpObjectType.Directory) path += "/"; var target = new Uri(URL, path).ToString(); if(entry.Type == FtpObjectType.Link) target = new Uri(URL, info.LinkTarget).ToString(); str += string.Format("=>{0} {1}\r\n", target, path); } Content = new MemoryStream(Encoding.UTF8.GetBytes(str)); break; case FtpObjectType.Link: MediaType = "text/gemini"; Content = new MemoryStream(Encoding.UTF8.GetBytes("=>"+new Uri(URL, info.LinkTarget).ToString())); break; } } else { if(conn.DirectoryExists(file)) { MediaType = "text/gemini"; var entries = conn.GetListing(file); var str = "# "+file+"\r\n"; foreach(var entry in entries) { var path = entry.Name; if(entry.Type == FtpObjectType.Directory) path += "/"; str += string.Format("=>{0} {1}\r\n", new Uri(URL, path).ToString(), path); } Content = new MemoryStream(Encoding.UTF8.GetBytes(str)); } else { Content = new MemoryStream(Encoding.UTF8.GetBytes("file not found")); Status = "not found"; } } Loaded = true; } public override void Render() { } }