with
  Ada.Characters.Latin_1,
  Ada.Strings.Unbounded,
  Ada.IO_Exceptions,
  POSIX.IO;
with GNAT.Sockets;
with Open_Process, Close_Process;

procedure Remote_List_Daemon is
   package Unbounded renames Ada.Strings.Unbounded;
   package Latin_1   renames Ada.Characters.Latin_1;
   use type POSIX.POSIX_String;

   function Sanitize (Directory : Unbounded.Unbounded_String)
                     return POSIX.POSIX_String is
      Buffer : POSIX.POSIX_String :=
        POSIX.To_POSIX_String (Unbounded.To_String (Directory));
   begin
      for Index in Buffer'Range loop
         case Buffer (Index) is
            when '0' .. '9' | 'A' .. 'Z' | 'a' .. 'z' | '/' | '-' | '.' | '_' =>
               null;
            when others =>
               return ".";
         end case;
      end loop;
      return Buffer;
   end Sanitize;

   Address   : GNAT.Sockets.Sock_Addr_Type;
   Server    : GNAT.Sockets.Socket_Type;
   Socket    : GNAT.Sockets.Socket_Type;
   Channel   : GNAT.Sockets.Stream_Access;
   Directory : Unbounded.Unbounded_String;
   List      : POSIX.IO.File_Descriptor;
begin
   Address := (Family => GNAT.Sockets.Family_Inet,
               Addr   => GNAT.Sockets.Any_Inet_Addr,
               Port   => 15_000);

   GNAT.Sockets.Create_Socket (Server);
   GNAT.Sockets.Set_Socket_Option (Server,
                                   GNAT.Sockets.Socket_Level,
                                   (GNAT.Sockets.Reuse_Address, True));
   GNAT.Sockets.Bind_Socket (Server, Address);
   GNAT.Sockets.Listen_Socket (Server);
   loop
      GNAT.Sockets.Accept_Socket (Server, Socket, Address);
      Channel := GNAT.Sockets.Stream (Socket);

  Read_Directory_Name:
      declare
         Char : Character;
      begin
         Directory := Unbounded.Null_Unbounded_String;
         loop
            Char := Character'Input (Channel);
            exit when Char = Latin_1.CR;
            exit when Char = Latin_1.LF;
            Unbounded.Append (Source   => Directory,
                              New_Item => Char);
         end loop;
      end Read_Directory_Name;

  Create_List:
      declare
         Sanitized_Directory : POSIX.POSIX_String := Sanitize (Directory);
         Last                : Natural;
      begin
         POSIX.IO.NONSTANDARD_Write
           (File   => POSIX.IO.Standard_Output,
            Buffer => "Showing '" & Sanitized_Directory & "' to " &
                      POSIX.To_POSIX_String (GNAT.Sockets.Image (Address)) &
                      "." & POSIX.LF,
            Last   => Last);

         List := Open_Process
           (Command => "ls -l " & Sanitized_Directory,
            Mode    => POSIX.IO.Read_Only);
      end Create_List;

  Copy_List_Data:
      declare
         Line : POSIX.IO.IO_Buffer (1 .. 1024);
         Last : Natural;
      begin
         loop
            begin
               POSIX.IO.NONSTANDARD_Read (File   => List,
                                          Buffer => Line,
                                          Last   => Last);
               POSIX.IO.IO_Buffer'Write (Channel,
                                         Line (Line'First .. Last));
            exception
               when Ada.IO_Exceptions.End_Error => exit;
               when others                      => raise;
            end;
         end loop;
      end Copy_List_Data;

      Close_Process (List);

      GNAT.Sockets.Close_Socket (Socket);
   end loop;
end Remote_List_Daemon;

