// https://developer.apple.com/library/mac/documentation/networking/Reference/AFP_Reference/Reference/reference.html#//apple_ref/c/func/FPOpenDir void T2(object state) { Thread.CurrentThread.CurrentUICulture = CultureInfo.InvariantCulture; Encoding enc = Encoding.GetEncoding(932); ManualResetEvent evExit = new ManualResetEvent(false); try { using (TcpClient tcp = (TcpClient)state) { NetworkStream st = tcp.GetStream(); StreamWriter wr = new StreamWriter(st, Encoding.UTF8); StreamReader rr = new StreamReader(st, Encoding.UTF8, false); ConDyn cd = new ConDyn(cc); String syst = ""; using (MyDSI3 comm = new MyDSI3(afp)) { TransmitRes res = comm.Transmit(new DSIGetStatus()); if (res.pack.IsResponse && res.pack.ErrorCode == 0) { GetSrvrInfoPack pack = new GetSrvrInfoPack(res.br); if (pack.AFPVersionsList.Contains("AFP2.2")) { } if (pack.AFPVersionsList.Contains("AFPX03")) { cd.AFP30 = true; } if (pack.AFPVersionsList.Contains("AFP3.1")) { cd.AFP31 = true; } syst += " Server: " + pack.ServerName + "\n"; syst += " AFPVer:"; foreach (String ver in pack.AFPVersionsList) syst += " <" + ver + ">"; syst += "\n"; syst += " UAM:"; foreach (String ver in pack.UAMsList) syst += " <" + ver + ">"; } else { Ut.WriteRes(wr, 500, "AFP server failed: " + new DSIException(res.pack.ErrorCode, res.pack)); return; } } String U = String.Empty; String P = String.Empty; IDir root = new DisconnetedRoot(); IDir pwd = root; DataConn dc = new DataConn(); Int64 ftpRest = 0; IEnt rnfr = null; using (MyDSI3 comm = new MyDSI3(afp)) { Ticker ti = new Ticker(comm, evExit); Ut.WriteRes(wr, 220, "FTP4AFP in UTF-8"); while (true) { try { String row = rr.ReadLine(); if (row == null) break; Match M; M = Regex.Match(row, "^QUIT", RegexOptions.Singleline | RegexOptions.IgnoreCase); if (M.Success) { Ut.WriteRes(wr, 221, "Goodbye!"); break; } M = Regex.Match(row, "^USER\\s+(?<a>.+)\\s*$", RegexOptions.Singleline | RegexOptions.IgnoreCase); if (M.Success) { U = M.Groups["a"].Value; Ut.WriteRes(wr, 331, "Proceed to password."); continue; } M = Regex.Match(row, "^PASS\\s+(?<a>.+)\\s*$", RegexOptions.Singleline | RegexOptions.IgnoreCase); if (M.Success) { P = M.Groups["a"].Value; Uta a = new Uta(); root = pwd = a.Login(comm, cd, U, P); Ut.WriteRes(wr, 230, "User logged in, proceed."); continue; } M = Regex.Match(row, "^SYST", RegexOptions.Singleline | RegexOptions.IgnoreCase); if (M.Success) { Ut.WriteRes(wr, 215, typeof(AFPServ).AssemblyQualifiedName + "\n" + Environment.OSVersion + "\n" + "\n" + syst); continue; } M = Regex.Match(row, "^(XPWD|PWD)", RegexOptions.Singleline | RegexOptions.IgnoreCase); if (M.Success) { MLoc m = MLoc.Ut.Get(pwd); Ut.WriteRes(wr, 257, "\"" + m.UnixPath + "\" is current directory."); continue; } M = Regex.Match(row, "^TYPE\\s+(?<a>A|I)\\s*$", RegexOptions.Singleline | RegexOptions.IgnoreCase); if (M.Success) { String mode = M.Groups["a"].Value.ToUpperInvariant(); if (mode == "I") dc.TypeI(); if (mode == "A") dc.TypeA(); Ut.WriteRes(wr, 200, "Ok."); continue; } M = Regex.Match(row, "^PASV", RegexOptions.Singleline | RegexOptions.IgnoreCase); if (M.Success) { dc.Pasv(tcp.Client.LocalEndPoint); Ut.WriteRes(wr, 227, "Entering Passive Mode (" + dc.GetPasv() + ")"); continue; } M = Regex.Match(row, "^PORT\\s+(?<a>\\d+,\\d+,\\d+,\\d+,\\d+,\\d+)\\s*$", RegexOptions.Singleline | RegexOptions.IgnoreCase); if (M.Success) { dc.Port(M.Groups["a"].Value); Ut.WriteRes(wr, 200, "PORT command successful."); continue; } M = Regex.Match(row, "^LIST(\\s+(?<a>.+))?\\s*$", RegexOptions.Singleline | RegexOptions.IgnoreCase); if (M.Success) { String cwd = M.Groups["a"].Value; try { IDir newwd = (cwd.Length == 0) ? pwd : TravUt.Cwd(pwd, cwd); StringWriter ww = new StringWriter(); foreach (IEnt o in newwd.GetEnts()) { bool isDir = o is IDir; ww.WriteLine("{0}rw-r--r-- 1 0 0 {1,10} {2,-12} {3}" , isDir ? "d" : "-" , isDir ? "0" : o.Size.ToString() , DUt.Format(o.Mt) , o.Name ); } // http://blog.livedoor.jp/kumagai_nori/archives/51660940.html // http://ash.jp/net/ftp_command.htm // http://www.atmarkit.co.jp/ait/articles/0307/11/news001.html // http://www.atmarkit.co.jp/fnetwork/rensai/netpro10/ftp-responsecode.html // http://maruo.dyndns.org:81/hidesoft/hidesoft_2/x17565.html // http://www.nsftools.com/tips/MSFTP.htm#dir Ut.WriteRes(wr, 150, "Opening " + dc.Mode + " mode data connection for LIST"); dc.SendData(wr.Encoding.GetBytes(ww.ToString())); Ut.WriteRes(wr, 226, "Transfer complete"); continue; } catch (EntNotFoundException err) { Ut.WriteRes(wr, 501, err.Message); continue; } } M = Regex.Match(row, "^MLSD(\\s+(?<a>.+))?\\s*$", RegexOptions.Singleline | RegexOptions.IgnoreCase); if (M.Success) { String cwd = M.Groups["a"].Value; try { IDir newwd = (cwd.Length == 0) ? pwd : TravUt.Cwd(pwd, cwd); StringWriter ww = new StringWriter(); foreach (IEnt o in newwd.GetEnts()) { bool isDir = o is IDir; ww.WriteLine("modify={0};perm={1};size={2};type={3}; {4}" , o.Mt.HasValue ? String.Format("{0:yyyy}{0:MM}{0:dd}{0:HH}{0:mm}{0:ss}", o.Mt.Value) : "" , isDir ? "cdelmp" : "dlrw" , Math.Max(o.Size, 0) , isDir ? "dir" : "file" , o.Name ); } Ut.WriteRes(wr, 150, "Opening " + dc.Mode + " mode data connection for MLSD"); dc.SendData(wr.Encoding.GetBytes(ww.ToString())); Ut.WriteRes(wr, 226, "Transfer complete"); continue; } catch (EntNotFoundException err) { Ut.WriteRes(wr, 501, err.Message); continue; } } M = Regex.Match(row, "^CWD\\s+(?<a>.+)\\s*$", RegexOptions.Singleline | RegexOptions.IgnoreCase); if (M.Success) { String cwd = M.Groups["a"].Value; try { IDir newwd = TravUt.Cwd(pwd, cwd); pwd = newwd; Ut.WriteRes(wr, 250, "Directory successfully changed."); continue; } catch (EntNotFoundException err) { Ut.WriteRes(wr, 550, err.Message); continue; } } M = Regex.Match(row, "^CDUP", RegexOptions.Singleline | RegexOptions.IgnoreCase); if (M.Success) { IDir newwd = pwd.ParentDir; if (newwd == null) { Ut.WriteRes(wr, 250, "We are already at root directory."); continue; } else { pwd = newwd; Ut.WriteRes(wr, 250, "Directory successfully changed."); continue; } } M = Regex.Match(row, "^OPTS\\s+UTF8\\s+ON\\s*$", RegexOptions.Singleline | RegexOptions.IgnoreCase); if (M.Success) { Ut.WriteRes(wr, 200, "It is in UTF8 mode."); wr = new StreamWriter(st, Encoding.UTF8); rr = new StreamReader(st, Encoding.UTF8, false); continue; } M = Regex.Match(row, "^OPTS\\s+UTF8\\s+OFF\\s*$", RegexOptions.Singleline | RegexOptions.IgnoreCase); if (M.Success) { Ut.WriteRes(wr, 200, "It is in " + enc.BodyName + " mode."); wr = new StreamWriter(st, enc); rr = new StreamReader(st, enc, false); continue; } M = Regex.Match(row, "^OPTS\\s+FORKMODE\\s+(?<a>\\d+)\\s*$", RegexOptions.Singleline | RegexOptions.IgnoreCase); if (M.Success) { int i = int.Parse(M.Groups["a"].Value); cd.ForkMode = i; Ut.WriteRes(wr, 200, "It is in fork mode " + i + "."); continue; } M = Regex.Match(row, "^FEAT", RegexOptions.Singleline | RegexOptions.IgnoreCase); if (M.Success) { Ut.WriteRes(wr, 211, "Features:| UTF8| MLST modify*;perm*;size*;type*;| FORKMODE| END".Replace("|", "\n")); continue; } M = Regex.Match(row, "^RETR\\s+(?<a>.+)\\s*$", RegexOptions.Singleline | RegexOptions.IgnoreCase); if (M.Success) { String cwd = M.Groups["a"].Value; try { IEnt source = TravUt.Find(pwd, cwd, false); if (source is ICanDL) { using (Stream si = ((ICanDL)source).OpenRead()) { Ut.WriteRes(wr, 150, "Opening " + dc.Mode + " mode data connection for " + cwd); si.Position = ftpRest; dc.SendSt(si); } } else { Ut.WriteRes(wr, 550, "We can't get \"" + cwd + "\"."); continue; } ftpRest = 0; Ut.WriteRes(wr, 226, "Transfer complete"); continue; } catch (EntNotFoundException err) { Ut.WriteRes(wr, 550, err.Message); continue; } } M = Regex.Match(row, "^STOR\\s+(?<a>.+)\\s*$", RegexOptions.Singleline | RegexOptions.IgnoreCase); if (M.Success) { String cwd = M.Groups["a"].Value; try { using (Stream os = TravUt.Createf(pwd, cwd, cd)) { Ut.WriteRes(wr, 150, "Opening " + dc.Mode + " mode data connection for " + cwd); os.SetLength(ftpRest); os.Position = ftpRest; dc.RecvSt(os); } ftpRest = 0; Ut.WriteRes(wr, 226, "Transfer complete"); continue; } catch (EntNotFoundException err) { Ut.WriteRes(wr, 550, err.Message); continue; } } M = Regex.Match(row, "^APPE\\s+(?<a>.+)\\s*$", RegexOptions.Singleline | RegexOptions.IgnoreCase); if (M.Success) { String cwd = M.Groups["a"].Value; try { using (Stream os = TravUt.Createf(pwd, cwd, cd)) { Ut.WriteRes(wr, 150, "Opening " + dc.Mode + " mode data connection for " + cwd); os.Seek(0, SeekOrigin.End); dc.RecvSt(os); } Ut.WriteRes(wr, 226, "Transfer complete"); continue; } catch (EntNotFoundException err) { Ut.WriteRes(wr, 550, err.Message); continue; } } M = Regex.Match(row, "^MKD\\s+(?<a>.+)\\s*$", RegexOptions.Singleline | RegexOptions.IgnoreCase); if (M.Success) { String cwd = M.Groups["a"].Value; try { TravUt.CreateDir(pwd, cwd); Ut.WriteRes(wr, 250, "\"" + cwd + "\" created successfully."); continue; } catch (EntNotFoundException err) { Ut.WriteRes(wr, 550, "\"" + cwd + "\": Unable to create directory. \n" + err.Message); continue; } } M = Regex.Match(row, "^RMD\\s+(?<a>.+)\\s*$", RegexOptions.Singleline | RegexOptions.IgnoreCase); if (M.Success) { String cwd = M.Groups["a"].Value; try { TravUt.RMDir(pwd, cwd); Ut.WriteRes(wr, 250, "\"" + cwd + "\" removed successfully."); continue; } catch (EntNotFoundException err) { Ut.WriteRes(wr, 550, "\"" + cwd + "\": Unable to remove directory. \n" + err.Message); continue; } } M = Regex.Match(row, "^DELE\\s+(?<a>.+)\\s*$", RegexOptions.Singleline | RegexOptions.IgnoreCase); if (M.Success) { String cwd = M.Groups["a"].Value; try { TravUt.Dele(pwd, cwd, cd); Ut.WriteRes(wr, 250, "\"" + cwd + "\" removed successfully."); continue; } catch (EntNotFoundException err) { Ut.WriteRes(wr, 550, "\"" + cwd + "\": Unable to remove directory. \n" + err.Message); continue; } } M = Regex.Match(row, "^REST\\s+(?<a>\\d+)\\s*$", RegexOptions.Singleline | RegexOptions.IgnoreCase); if (M.Success) { ftpRest = Int64.Parse(M.Groups["a"].Value); Ut.WriteRes(wr, 200, "Ok."); continue; } M = Regex.Match(row, "^RNFR\\s+(?<a>.+)\\s*$", RegexOptions.Singleline | RegexOptions.IgnoreCase); if (M.Success) { String cwd = M.Groups["a"].Value; try { rnfr = TravUt.Find(pwd, cwd, false); Ut.WriteRes(wr, 350, "The file exists, continue with RNTO."); continue; } catch (EntNotFoundException err) { Ut.WriteRes(wr, 550, err.Message); continue; } } M = Regex.Match(row, "^RNTO\\s+(?<a>.+)\\s*$", RegexOptions.Singleline | RegexOptions.IgnoreCase); if (M.Success) { String cwd = M.Groups["a"].Value; try { MLoc mfrm = MLoc.Ut.Get(rnfr); String fpfrm = mfrm.UnixPath; MLoc m = MLoc.Ut.Get(pwd); String fp2 = UtPLoc.Getfp(m.UnixPath, cwd, cd); PLoc p1 = new PLoc(fpfrm); PLoc p2 = new PLoc(fp2); if (!p1.volume.Equals(p2.volume)) throw new ApplicationException("We have different volumes."); if (!p1.dir.Equals(p2.dir)) { MLoc m2 = new MLoc(); m2.VolID = mfrm.VolID; m2.DirID = mfrm.DirID; m2.MacVol = mfrm.MacVol; m2.MacPath = p2.dir.Replace("/", "\0"); Utcmd.Move(comm, mfrm, m2, p2.fname); } else { Utcmd.Rename(comm, mfrm, p2.fname); } Ut.WriteRes(wr, 200, "Ok."); continue; } catch (EntNotFoundException err) { Ut.WriteRes(wr, 550, err.Message); continue; } } Ut.WriteRes(wr, 500, "NotImpl Error."); } catch (Exception err) { if (tcp.Connected) { try { Ut.WriteRes(wr, 500, err.ToString()); } catch (IOException) { } } else break; } } } tcp.Close(); } } finally { evExit.Set(); } }
public static void Move(MyDSI3 comm, MLoc mfrm, MLoc m2, String nam) { TransmitRes res1 = comm.Transmit(new DSICommand().WithRequestPayload(new FPMoveAndRename() .WithVolumeID(mfrm.VolID) .WithSourceDirectoryID(mfrm.DirID) .WithSourcePath(mfrm.RawPath) .WithDestDirectoryID(m2.DirID) .WithDestPath(m2.RawPath) .WithNewName(nam) )); if (res1.pack.IsResponse && res1.pack.ErrorCode == 0) { } else { throw new DSIException(res1.pack.ErrorCode, res1.pack); } }
public static IEnumerable<IEnt> GetEnts310(MLoc m, MyDSI3 comm, ConDyn cd, IDir self) { for (uint x = 0; ; ) { TransmitRes res1 = comm.Transmit(new DSICommand().WithRequestPayload(new FPEnumerateExt2() .WithPath(m.RawPath) .WithStartIndex(Convert.ToUInt32(1U + x)) .WithVolumeID(m.VolID) .WithDirectoryID(m.DirID) .WithFileBitmap(AfpFileBitmap.ExtDataForkLength | AfpFileBitmap.ExtResourceForkLength | AfpFileBitmap.LongName | AfpFileBitmap.NodeID | AfpFileBitmap.ModificationDate) .WithDirectoryBitmap(AfpDirectoryBitmap.NodeID | AfpDirectoryBitmap.LongName | AfpDirectoryBitmap.ModificationDate) )); if (res1.pack.ErrorCode == -5018) break; if (res1.pack.IsResponse && res1.pack.ErrorCode == 0) { } else { throw new DSIException(res1.pack.ErrorCode, res1.pack); } EnumerateExtPack pack = new EnumerateExtPack(res1.br); foreach (FileParameters ent in pack.Ents) { if (ent.IsDirectory) { yield return new MacDir(ent, comm, cd, self); } else { yield return new MacEnt(ent, Forkty.Data, comm, cd, self); if (cd.EnumRes && ((Utfs.ResFork(ent) > 0) || !cd.IfAvail)) yield return new MacEnt(ent, Forkty.Res, comm, cd, self); if (cd.EnumFi) yield return new MacEnt(ent, Forkty.Finder, comm, cd, self); } } if (pack.ActualCount == 0) break; x += pack.ActualCount; } }
public static IEnumerable<IEnt> GetEnts(MLoc m, MyDSI3 comm, ConDyn cd, IDir self) { if (cd.AFP31) return GetEnts310(m, comm, cd, self); if (cd.AFP30) return GetEnts300(m, comm, cd, self); return GetEnts220(m, comm, cd, self); }
public static MLoc GetVol(MacVol vol) { MLoc m = new MLoc(); vol.OpenIt(); m.MacPath = ""; m.MacVol = vol.RealName; m.VolID = vol.VolID; m.DirID = vol.DirID; return m; }
public static MLoc Get(IEnt p) { MLoc m = new MLoc(); m.MacPath = String.Empty; m.MacVol = String.Empty; while (p != null) { if (p is MacRoot) break; if (p is MacVol) { MacVol vol = (MacVol)p; vol.OpenIt(); m.VolID = vol.VolID; m.DirID = vol.DirID; m.MacVol = p.RealName; } else { m.MacPath = ((String)(p.RealName + ":" + m.MacPath)).TrimEnd(':'); } p = p.ParentDir; } return m; }
public MacFiSt(MyDSI3 comm, byte[] fi, MLoc m, bool write) { this.comm = comm; this.fi = fi; this.m = m; this.write = write; this.open = true; this.pos = 0; }