DataMuseum.dk

Presents historical artifacts from the history of:

Rational R1000/400 Tapes

This is an automatic "excavation" of a thematic subset of
artifacts from Datamuseum.dk's BitArchive.

See our Wiki for more about Rational R1000/400 Tapes

Excavated with: AutoArchaeologist - Free & Open Source Software.


top - download
Index: ┃ B T

⟦9e3d53eda⟧ TextFile

    Length: 35635 (0x8b33)
    Types: TextFile
    Names: »B«

Derivation

└─⟦d10a02448⟧ Bits:30000409 8mm tape, Rational 1000, ENVIRONMENT, D_12_7_3
    └─ ⟦fc9b38f02⟧ »DATA« 
        └─⟦8e9e227a9⟧ 
            └─⟦this⟧ 

TextFile

with Archive;
with Byte_Defs;
with Common;
with Compilation;
with Debug_Tools;
with Directory_Tools;
with Editor;
with Enable_Product_Keymaps;
with File_Transfer;
with Ftp_Defs;
with Ftp_Profile;
with Io;
with Library;
with Log;
with Profile;
with Release;
with Rxi_String;
use Rxi_String;
with String_Utilities;
with Switches;
with Table_Sort_Generic;
with Transport;
with Transport_Defs;
with Transport_Name;

package body Rxi_Install is

------------------------------------------------------------------------------
-- Imported Renames
------------------------------------------------------------------------------

    function "=" (A, B : Ftp_Defs.Status_Code)       return Boolean
        renames Ftp_Defs."=";
    function "=" (A, B : Transport_Defs.Status_Code) return Boolean
        renames Transport_Defs."=";

------------------------------------------------------------------------------
-- Exceptions
------------------------------------------------------------------------------

    I_Am_Confused : exception;
    ----I give up.  Some assumption of the code has changed and the code wasn't
    --  changed to reflect it.

    Quit : exception;
    ----Raised when we want to give up on something.

--\f

    function Hs (Str : String) return Heap_String is
    begin
        return new String'(Str);
    end Hs;

--\f

    function Release_From_Here return String is
        Rel  : constant String := Release.Info.R1000_Release;
        Wrk  : constant String := Release.Info.R1000_Working;
        Here : constant String := Directory_Tools.Naming.Full_Name
                                     (Directory_Tools.Naming.Resolution ("$"));
    begin
        if Here'Length >= Rel'Length - 1 and then  
           Here (Here'First .. Here'First + Rel'Length - 2) =
              String_Utilities.Upper_Case (Rel (Rel'First .. Rel'Last - 1)) then
            ----Doing a normal install.
            return Rel;
        elsif Here'Length >= Wrk'Length - 1 and then  
              Here (Here'First .. Here'First + Wrk'Length - 2) =
                 String_Utilities.Upper_Case
                    (Wrk (Wrk'First .. Wrk'Last - 1)) then
            ----Doing a test install from development area
            return Release.Info.R1000_Working;
        else
            Log.Put_Line ("Please connect to: ", Profile.Error_Msg);
            Log.Put_Line ("  " & Rel, Profile.Error_Msg);
            Log.Put_Line ("  or to:", Profile.Error_Msg);
            Log.Put_Line ("  " & Wrk, Profile.Error_Msg);
            Log.Put_Line ("  and try this command again.", Profile.Error_Msg);
            Log.Put_Line ("Cannot run this command from " & Here,
                          Profile.Exception_Msg);
            raise I_Am_Confused;
        end if;
    end Release_From_Here;

--\f

    function Ada_Files_Generate (Keyboard           : Terminal_Type;  
                                 Suppress_Rxi_Files : Boolean) return String is
------------------------------------------------------------------------------
-- Returns the name(s) of the files in the Editor_Data area to
-- compile/transfer for this Keyboard type.
------------------------------------------------------------------------------
        Base : constant String :=
           Release.Supported_Keyboards (Keyboard).Name.all & "_@";
    begin

        if Suppress_Rxi_Files then
            return Base;
        else
            return "[" & Base & ",RXI_@]";
        end if;

    end Ada_Files_Generate;

--\f

    procedure Machine_Editor_Data_Files
                 (Keyboard           : Terminal_Type;  
                  Suppress_Rxi_Files : Boolean := False;  
                  Overrides          : String  := "foo=>FALSE,bar=>true") is
------------------------------------------------------------------------------
--  Keyboard            - Specifies the RXI-based terminal type being installed.
--  Suppress_Rxi_Files  - Specifies TRUE if the RXI files are not to be
--          included in the installation; perhaps they are already there.
------------------------------------------------------------------------------
        Ada_Files : constant String := Ada_Files_Generate (Keyboard,  
                                                           Suppress_Rxi_Files);
        Body_Files : constant String := Ada_Files & "'Body";
        Non_Body_Files : constant String := Ada_Files & "['c(File),'Spec]";

        Med         : constant String := "!Machine.Editor_Data.";
        Tt_Filename : constant String := Med & "Terminal_Types";
        Tr_Filename : constant String := Med & "Terminal_Recognition";
        Tt_File     : Io.File_Type;
        Tr_File     : Io.File_Type;
    begin

----Say Hello.

        Log.Put_Line ("[Install.Machine_Editor_Data_Files(" &
                      Terminal_Type'Image (Keyboard) & "," &
                      Boolean'Image (Suppress_Rxi_Files) & ")]",
                      Profile.Auxiliary_Msg, Profile.Verbose);
        Log.Put_Line (Release_From_Here,
                      Profile.Auxiliary_Msg, Profile.Verbose);

----Try to open the TT file for append.  Errors probably indicate non-existence.

        Log.Put_Line ("Modify the " & Tt_Filename,
                      Profile.Auxiliary_Msg, Profile.Verbose);
        begin
            Io.Append (Tt_File, Tt_Filename);
        exception
            when Io.Name_Error =>

----Try to create the presumably non-existent file.  We give up on errors.

                begin
                    Io.Create (Tt_File, Io.Out_File, Tt_Filename);
                exception
                    when others =>
                        Log.Put_Line  
                           ("Unexpected exception creating " &
                            Tt_Filename & ":" &  
                            Debug_Tools.Get_Exception_Name (True, True),  
                            Profile.Error_Msg,  
                            Profile.Verbose);
                        return;
                end;

----Other errors cause us to give up.

            when others =>
                Log.Put_Line ("Unexpected exception opening " &
                              Tt_Filename & ":" &  
                              Debug_Tools.Get_Exception_Name (True, True),  
                              Profile.Error_Msg,  
                              Profile.Verbose);
                return;
        end;

----Install our one-liner describing the terminal type.

        Io.Put (Tt_File, Release.Supported_Keyboards (Keyboard).Name.all);
        Io.Put (Tt_File, " XRTERM ");
        Io.Put (Tt_File, Release.Supported_Keyboards (Keyboard).Lines);
        Io.Put (Tt_File, ' ');
        Io.Put (Tt_File, Release.Supported_Keyboards (Keyboard).Columns);
        Io.New_Line (Tt_File);

----Add any extra information that may be required.

        if Release.Supported_Keyboards (Keyboard).Tt_Extra /= null then
            Io.Put_Line (Tt_File,
                         Release.Supported_Keyboards (Keyboard).Tt_Extra.all);
        end if;

----Close the file.

        Io.Close (Tt_File);

----Try to open the TR file for append.  Errors probably indicate non-existence.

        Log.Put_Line ("Modify the " & Tr_Filename,
                      Profile.Auxiliary_Msg, Profile.Verbose);
        begin
            Io.Append (Tr_File, Tr_Filename);
        exception
            when Io.Name_Error =>

----Try to create the presumably non-existent file.  We give up on errors.

                begin
                    Io.Create (Tr_File, Io.Out_File, Tr_Filename);
                exception
                    when others =>
                        Log.Put_Line  
                           ("Unexpected exception creating " &
                            Tr_Filename & ":" &  
                            Debug_Tools.Get_Exception_Name (True, True),  
                            Profile.Error_Msg,  
                            Profile.Verbose);
                        return;
                end;

----Other errors cause us to give up.

            when others =>
                Log.Put_Line ("Unexpected exception opening " &
                              Tr_Filename & ":" &  
                              Debug_Tools.Get_Exception_Name (True, True),  
                              Profile.Error_Msg,  
                              Profile.Verbose);
                return;
        end;

----Install the one-liner and close the file.

        declare
            Id : constant String :=
               Natural'Image
                  (Release.Supported_Keyboards (Keyboard).Id * 8 + 2);
            ----Id # as a string with a leading space because it is positive.
            Id_No : constant String := Id (Id'First + 1 .. Id'Last);
            ----Id # as a string with no leading space.
        begin
            Io.Put (Tr_File, Release.Supported_Keyboards (Keyboard).Name.all);
            Io.Put (Tr_File, " " & Ascii.Esc & "[?1;");
            Io.Put (Tr_File, Id_No);
            Io.Put (Tr_File, 'c');
            Io.New_Line (Tr_File);
        end;
        Io.Close (Tr_File);

----Make sure that any 'Body's that we may be overwriting in !Machine.
--  Editor_Data are in the Source state so that we don't waste time promoting
--  the 'Body's twice.  (Once in the Archive.Copy step and once in the
--  Enable_Product_Keymaps step.)

        Log.Put_Line ("Install the keymap files.",  
                      Profile.Auxiliary_Msg, Profile.Verbose);
        begin
            ----See if any of the objects exist.
            Library.Resolve (Name_Of  => "!Machine.Editor_Data." & Body_Files,
                             Response => "<Quiet> Raise_Error");
            ----Demote existing objects.
            Compilation.Demote (Unit => "!Machine.Editor_Data." & Body_Files,
                                Goal => Compilation.Source,
                                Limit => "<ALL_WORLDS>",
                                Effort_Only => False,
                                Response => "<Verbose> Persevere");
        exception
            ----None of the objects exist.
            when Library.Error =>
                null;
        end;

----Use Archive.Copy to create/replace the !Machine.Editor_Data files and to
--  guarantee that they end up Source (if new) or Installed/Coded (if replacing
--  old ones that were Installed/Coded).

        Archive.Copy (Objects    => Release_From_Here & "Editor_Data." &  
                                       Non_Body_Files,
                      Use_Prefix => "!Machine.Editor_Data",
                      For_Prefix => Release_From_Here & "Editor_Data",
                      Options    => "ALL_OBJECTS,REPLACE,REMAKE",
                      Response   => "<Verbose> Raise_Error");
        Archive.Copy (Objects    => Release_From_Here & "Editor_Data." &  
                                       Body_Files,
                      Use_Prefix => "!Machine.Editor_Data",
                      For_Prefix => Release_From_Here & "Editor_Data",
                      Options    => "ALL_OBJECTS,SOURCE",
                      Response   => "<Verbose> Raise_Error");

----Copy the Enable_Product_Keymaps procedure if it is newer than any existing
--  such procedure.
--  Since this Copy operation is copying a Load_Proc, and since we run the
--  Code-Generator in other steps of this procedure, and since there is a bug
--  in pre-Delta-3 Environments, we will run this Copy as a separate task
--  as a work-around for the bug.

        declare
            Library : constant String := "!Machine.Editor_Data";
            Switch_File : constant String := Library & ".Library_Switches";
            Assoc : constant String := Switches.Associated (Library => Library);
            task Bug_Fix is
            end Bug_Fix;
            task body Bug_Fix is
            begin
                if Assoc = "" or else  
                   Assoc (Assoc'First .. Assoc'First - 1 + Library'Length) /=
                      Library then
                    Switches.Create (File => Switch_File, Category => 'L');
                    Switches.Associate (File    => Switch_File,  
                                        Library => Library);
                    Switches.Set
                       (Spec => "R1000_Cg.Retain_Delta1_Compatibility := False",  
                        File => Switch_File);
                else
                    Switches.Set
                       (Spec => "R1000_Cg.Retain_Delta1_Compatibility := False",  
                        File => Assoc);
                end if;

                Archive.Copy (Objects    => Release_From_Here & "Editor_Data" &
                                               ".Enable_Product_Keymaps",
                              Use_Prefix => "!Machine.Editor_Data",
                              For_Prefix => Release_From_Here & "Editor_Data",
                              Options    => "CHANGED_OBJECTS,REPLACE,REMAKE",
                              Response   => "<Verbose> Raise_Error");

            end Bug_Fix;
        begin
            null;   -- Wait for task to complete.
        end;

----Turn on/off any product bindings and put the Editor_Data at least in
--  the installed state.

        Log.Put_Line ("Enable product keys in keymaps.",  
                      Profile.Auxiliary_Msg, Profile.Verbose);
        Enable_Product_Keymaps (Keymap => "!Machine.Editor_Data." & Body_Files,
                                Response => "<Verbose> Raise_Error",
                                Overrides => Overrides);

----All Done.

        Log.Put_Line ("[end of Install.Machine_Editor_Data_Files(" &
                      Terminal_Type'Image (Keyboard) & "," &
                      Boolean'Image (Suppress_Rxi_Files) & ")]",
                      Profile.Auxiliary_Msg, Profile.Verbose);

    end Machine_Editor_Data_Files;

--\f

    function Get_Host_Id (Name : String) return Transport_Defs.Host_Id is
------------------------------------------------------------------------------
--  Name        - Specifies the name of some remote host
-- Returns the Host_Id of this host or else returns an empty Host_Id if the
-- name isn't known.
------------------------------------------------------------------------------
    begin
        return Transport_Name.Host_To_Host_Id (Name);
    exception
        when Transport_Name.Undefined =>
            return (1 .. 0 => 0);
    end Get_Host_Id;

--\f

    procedure Status_Ok (Status : Transport_Defs.Status_Code) is
------------------------------------------------------------------------------
--  Status  - Specifies a status to check
-- Complains and raises Quit if the Status != Ok.
------------------------------------------------------------------------------
    begin

        if Status /= Transport_Defs.Ok then
            Log.Put_Line ("Error in Rxi_Install: " &
                          Transport_Defs.Image (Status),  
                          Profile.Error_Msg,  
                          Profile.Verbose);
            raise Quit;
        end if;

    end Status_Ok;

--\f

    procedure Status_Ok (Status : Ftp_Defs.Status_Code) is
------------------------------------------------------------------------------
--  Status  - Specifies a status to check
-- Complains and raises Quit if the Status != Successful
------------------------------------------------------------------------------
    begin
        if Status /= Ftp_Defs.Successful then
            Log.Put_Line ("Error in Rxi_Install: " &
                          Ftp_Defs.Status_Code'Image (Status),  
                          Profile.Error_Msg,  
                          Profile.Verbose);
            raise Quit;
        end if;
    end Status_Ok;

--\f

    procedure Response (Connection : File_Transfer.Connect_Id) is
------------------------------------------------------------------------------
--  Conection   - Specifies the connection to check
-- Called to read any and all Response text that has been received from the
-- On_Machine host in response to any FTP command.  The response text is
-- send to the Log.
------------------------------------------------------------------------------
        Str : String (1 .. 1000);
        Len : Natural;
    begin

        while not File_Transfer.End_Of_Response (Connection) loop
            File_Transfer.Read_Response (Connection, Str, Len);
            Log.Put_Line ("Ftp: " & Str (1 .. Len),  
                          Profile.Note_Msg,  
                          Profile.Verbose);
        end loop;

    end Response;

--\f

    function Natural_Image (Val : Natural) return String is
------------------------------------------------------------------------------
--  Val - Specifies the value
-- Turn a natural into a string with no leading blanks.
------------------------------------------------------------------------------
        Str : constant String := Natural'Image (Val);
    begin
        return Str (Str'First + 1 .. Str'Last);
    end Natural_Image;

--\f

    function Duration_Image (Time : Duration) return String is
------------------------------------------------------------------------------
--  Time    - Specifies the duration
-- Ada doesn't give us a nice way to turn a Fixed quantity into a string so
-- we must hack one up.
------------------------------------------------------------------------------
        Val    : Integer := Integer (Time * Duration (1000.0));
        Valsub : Natural := (abs Val) rem 1000;
    begin
        if Valsub < 10 then
            return Natural_Image (Val / 1000) & ".00" & Natural_Image (Valsub);
        elsif Valsub < 100 then
            return Natural_Image (Val / 1000) & ".0" & Natural_Image (Valsub);
        else
            return Natural_Image (Val / 1000) & "." & Natural_Image (Valsub);
        end if;
    end Duration_Image;

--\f

    procedure Store (Connection : File_Transfer.Connect_Id;  
                     Local      : String;  
                     Remote     : String) is
------------------------------------------------------------------------------
--  Conection   - Specifies the connection to use
--  Local       - Specifies the name of an existing local object
--  Remote      - Specifies the name of a remote object to be created/written
-- Called to perform (and check) the transfer of one file from the R1000 to
-- the On_Machine host.
------------------------------------------------------------------------------
        Ftp_Status : Ftp_Defs.Status_Code;
    begin

----Inform the log of the impending transfer.

        Log.Put_Line
           ("--------------------------------------------------------",
            Profile.Note_Msg,  
            Profile.Verbose);
        Log.Put_Line ("Transfer: " & Local & " => " & Remote,  
                      Profile.Note_Msg,  
                      Profile.Verbose);

----Set up a new socket connection for the actual transfer.

        File_Transfer.Send_Data_Port (Connection,  
                                      Transport_Defs.Null_Host_Id,  
                                      Transport_Defs.Null_Socket_Id);
        Response (Connection);
        File_Transfer.Command_Status (Connection, Ftp_Status);
        Status_Ok (Ftp_Status);

----Begin the transfer and wait for it to end.

        File_Transfer.Start_Store (Connection,  
                                   Local_Filename  => Local,
                                   Remote_Filename => Remote,  
                                   Append          => False);
        Response (Connection);
        File_Transfer.Command_Status (Connection, Ftp_Status);
        if Ftp_Status /= Ftp_Defs.Transfer_Complete then
            Status_Ok (Ftp_Status);
        end if;

----Inform the log of a successful transfer.

        Log.Put_Line  
           ("Done, bytes: " &  
            Natural_Image (File_Transfer.Last_Transfer_Length (Connection)) &
            ", seconds: " &  
            Duration_Image (File_Transfer.Last_Transfer_Time (Connection)),  
            Profile.Note_Msg,  
            Profile.Verbose);

        Log.Put_Line ("--------------------------------------------------",
                      Profile.Note_Msg,  
                      Profile.Verbose);
    end Store;

--\f

    procedure Disconnect (Connection : in out File_Transfer.Connect_Id) is
------------------------------------------------------------------------------
--  Connection  - Specifies the connection to destroy
-- Called (at any time, in any state) when we must get rid of a connection.
-- We try to do it nicely but we are prepared to ignore any errors and to
-- simply drop the connection at the worst.
------------------------------------------------------------------------------
        Ftp_Status : Ftp_Defs.Status_Code;
    begin

----If the Connection isn't "open" (really means allocated) then we have nothing
--  to do.

        if not File_Transfer.Is_Open (Connection) then
            return;
        end if;

----If there is an actual connection then we must try to Quit out of it.

        if File_Transfer.Is_Connected (Connection) then
            begin
                begin
                    File_Transfer.Send_Quit (Connection);
                    Response (Connection);
                    File_Transfer.Command_Status (Connection, Ftp_Status);
                    Status_Ok (Ftp_Status);

----If the Quit fails then report that but also continue.

                exception
                    when others =>
                        Log.Put_Line
                           ("Unexpected exception during File_Transfer.Send_Quit:" &  
                            Debug_Tools.Get_Exception_Name (True, True),
                            Profile.Error_Msg,  
                            Profile.Verbose);
                end;

----Try to disconnect from the remote server.

                File_Transfer.Disconnect (Connection);
            exception
                when others =>
                    Log.Put_Line
                       ("Unexpected exception during File_Transfer.Disconnect:" &  
                        Debug_Tools.Get_Exception_Name (True, True),  
                        Profile.Error_Msg,  
                        Profile.Verbose);
            end;
        end if;

----Finally we close (deallocate) the socket.

        File_Transfer.Close (Connection);

    end Disconnect;

--\f

    function R1000_Form (Old_Namelc : String) return String is
------------------------------------------------------------------------------
--  Old_Namelc  - Specifies a name usable by some OS other than the R1000
--
-- Called to convert a non-R1000 name into a name the R1000 can handle.
-- We return the converted name.  Typically we just convert "strange"
-- characters into underscores ("_").  When this is a problem; at the
-- beginning of a name, the end of a name, or next to another "_"; we use
-- a semi-random letter; actually "A", "B", or "C".
------------------------------------------------------------------------------
        Old_Name : constant String := String_Utilities.Upper_Case (Old_Namelc);
        New_Name : String (1 .. Old_Name'Length + 2);
        Oldi     : Natural         := Old_Name'First;
        Newi     : Natural         := New_Name'First;
    begin

----See if the name begins with an underscore.  Prepend an A if necessary.

        if Old_Name (Oldi) not in 'A' .. 'Z' and then  
           Old_Name (Oldi) not in '0' .. '9' then
            New_Name (Newi) := 'A';
            Newi            := Newi + 1;
        end if;

----Convert all non-letters to underscores.  If this would lead to having
--  two underscores adjacent then convert every 2nd underscore to a B.

        while Oldi <= Old_Name'Last loop
            if Old_Name (Oldi) not in 'A' .. 'Z' and then  
               Old_Name (Oldi) not in '0' .. '9' then
                if New_Name (Newi - 1) = '_' then
                    New_Name (Newi) := 'B';
                else
                    New_Name (Newi) := '_';
                end if;
            else
                New_Name (Newi) := Old_Name (Oldi);
            end if;  
            Newi := Newi + 1;
            Oldi := Oldi + 1;
        end loop;

----See if the name ends in an underscore.  Append a C if necessary.

        if New_Name (Newi - 1) not in 'A' .. 'Z' and then  
           New_Name (Newi - 1) not in '0' .. '9' then
            New_Name (Newi) := 'C';
            return New_Name (New_Name'First .. Newi);
        else
            return New_Name (New_Name'First .. Newi - 1);
        end if;

    end R1000_Form;

--\f

    procedure Workstation_Files
                 (Keyboard             : Terminal_Type;
                  On_Machine           : String := Ftp_Profile.Remote_Machine;
                  Username             : String := Ftp_Profile.Username;
                  Password             : String := Ftp_Profile.Password;
                  Account              : String := Ftp_Profile.Account;
                  Rxi_Source_Directory : String :=
                     ">/src/x/mit/clients/rxi<") is
------------------------------------------------------------------------------
--  Keyboard            - Specifies the RXI-based terminal type being installed.
--  On_Machine          - Specifies the name of the workstation
--  Username            - Specifies a username valid on the workstation
--  Password            - Specifies the password for the username
--  Account             - Specifies the account to use on the workstation
--  Rxi_Source_Directory- Specifies the directory to contain the RXI C source
--                          code
------------------------------------------------------------------------------
        Connection : File_Transfer.Connect_Id;
        Td_Status : Transport_Defs.Status_Code;
        Ftp_Status : Ftp_Defs.Status_Code;
        Host_Id : constant Transport_Defs.Host_Id := Get_Host_Id (On_Machine);
        Ascii_Mode : Boolean;

----All of the RXI files will be located in this directory on the R1000.

        Local_Dir : constant String :=
           Release_From_Here  
               & '.'  
               & Release.Supported_Keyboards (Keyboard).R1000_Dir.all  
               & '.';

----Names for recognition.h

        Recog_H : constant Release.File_Info :=
           Release.Recognition_File (Keyboard);

        R1000_Recog_H : constant String :=
           Local_Dir  
               & R1000_Form (Release.Supported_Keyboards (Keyboard).Name.all  
                             & Recog_H.Master_File.all);

        Ws_Recog_H : constant String :=
           Recog_H.Install_File.all (Recog_H.Install_File'First + 1 ..  
                                        Recog_H.Install_File'Last) & "h";

        Ttws_Recog_H : constant String :=
           Release.Supported_Keyboards (Keyboard).Name.all  
               & Recog_H.Install_File.all & "h";

        procedure Tcp_Port_Numbers_Bug_Workaround is
            ----HP has a silly bug that we have to get-around.
            --  Assign port numbers until port numbers reach at least 1024.
            --  The R1000 assigns successive numbers starting at around 511.
            --  HP and apparently some others cannot accept any number less
            --  than 1024.  Silly bug.
            C      : Transport.Connection_Id;
            Status : Transport_Defs.Status_Code;
            Done   : Boolean := False;
        begin
            while not Done loop
                Transport.Open (C, Status, "TCP/IP");
                exit when Transport_Defs."/=" (Status, Transport_Defs.Ok);
                declare
                    Port : constant Transport_Defs.Socket_Id :=
                       Transport.Local_Socket (C);
                begin
                    Done := Byte_Defs.">=" (Port (Port'First), 4);
                end;
                Transport.Close (C);
            end loop;
        end Tcp_Port_Numbers_Bug_Workaround;

    begin

----Make sure that the On_Machine host is known to the R1000.

        Log.Put_Line ("[Rxi_Install.Workstation_Files(" &
                      Terminal_Type'Image (Keyboard) & ',' & On_Machine & ',' &
                      Username & ',' & Rxi_Source_Directory & ")]",
                      Profile.Auxiliary_Msg, Profile.Verbose);
        Log.Put_Line (Release_From_Here,
                      Profile.Auxiliary_Msg, Profile.Verbose);
        if Host_Id'Length = 0 then
            Log.Put_Line
               ("Host name [" & On_Machine &
                "] is not in the Transport_Name_Map (Host name undefined).",
                Profile.Error_Msg,  
                Profile.Verbose);
            return;
        end if;

----Try to get a socket for our use.

        Log.Put_Line ("Get network socket.", Profile.Note_Msg, Profile.Verbose);
        Tcp_Port_Numbers_Bug_Workaround;
        File_Transfer.Open (Connection, Td_Status);
        Status_Ok (Td_Status);

----Try to call up the On_Machine and see if it will talk to us at all.

        Log.Put_Line ("Connect to " & On_Machine,
                      Profile.Note_Msg, Profile.Verbose);
        File_Transfer.Connect (Connection, Host_Id);
        Response (Connection);
        File_Transfer.Command_Status (Connection, Ftp_Status);
        Status_Ok (Ftp_Status);

----Try to log in as the Username/Password that was given to us.

        Log.Put_Line ("Send username.", Profile.Note_Msg, Profile.Verbose);
        File_Transfer.Send_Username (Connection, Username);
        Response (Connection);
        File_Transfer.Command_Status (Connection, Ftp_Status);
        if Ftp_Status = Ftp_Defs.Not_Logged_In then
            Log.Put_Line ("Username " & Username &
                          " invalid on workstation " & On_Machine,
                          Profile.Error_Msg,  
                          Profile.Verbose);
            raise Quit;
        elsif Ftp_Status = Ftp_Defs.Need_Password then
            Log.Put_Line ("Send password.", Profile.Note_Msg, Profile.Verbose);
            File_Transfer.Send_Password (Connection, Password);
            Response (Connection);
            File_Transfer.Command_Status (Connection, Ftp_Status);
        end if;
        if Ftp_Status = Ftp_Defs.Not_Logged_In then
            Log.Put_Line ("Password invalid for username " &
                          Username & " on workstation " & On_Machine,
                          Profile.Error_Msg,  
                          Profile.Verbose);
            raise Quit;
        end if;
        Status_Ok (Ftp_Status);

----Set the account for the logged-in job On_Machine.

        if Account /= "" and then  
           Account /= " " then
            Log.Put_Line ("Send account.", Profile.Note_Msg, Profile.Verbose);
            File_Transfer.Send_Account (Connection, Account);
            Response (Connection);
            File_Transfer.Command_Status (Connection, Ftp_Status);
            if Ftp_Status /= Ftp_Defs.Command_Not_Implemented then
                Status_Ok (Ftp_Status);
            end if;
        end if;

----Connect to the Rxi_Source_Directory.

        Log.Put_Line ("Connect to " & Rxi_Source_Directory,
                      Profile.Note_Msg, Profile.Verbose);
        File_Transfer.Send_Cwd (Connection, Rxi_Source_Directory);
        Response (Connection);
        File_Transfer.Command_Status (Connection, Ftp_Status);
        Status_Ok (Ftp_Status);

----We will be working in Stream mode, sending Ascii data, and working in
--  units of Files.  These should work on all FTP implementations.

        Log.Put_Line ("Set transfer modes (Stream,Ascii,File).",
                      Profile.Note_Msg, Profile.Verbose);
        File_Transfer.Set_Mode (Connection, Ftp_Defs.Stream);
        Response (Connection);
        File_Transfer.Command_Status (Connection, Ftp_Status);
        Status_Ok (Ftp_Status);

        Ascii_Mode := True;
        File_Transfer.Set_Type (Connection, Ftp_Defs.Ascii);
        Response (Connection);
        File_Transfer.Command_Status (Connection, Ftp_Status);
        Status_Ok (Ftp_Status);

        File_Transfer.Set_Structure (Connection, Ftp_Defs.File);
        Response (Connection);
        File_Transfer.Command_Status (Connection, Ftp_Status);
        Status_Ok (Ftp_Status);

----Send all of the various files.

        for I in 1 .. Release.Install_Length (Keyboard) loop
            case Release.Install (Keyboard, I).File_Type is
                when Release.Text =>
                    if not Ascii_Mode then
                        Log.Put_Line
                           ("Set transmission modes (Stream,Ascii,File).",
                            Profile.Note_Msg, Profile.Verbose);
                        Ascii_Mode := True;
                        File_Transfer.Set_Type (Connection, Ftp_Defs.Ascii);
                        Response (Connection);
                        File_Transfer.Command_Status (Connection, Ftp_Status);
                        Status_Ok (Ftp_Status);
                    end if;
                    Store (Connection,  
                           Local_Dir & R1000_Form
                                          (Release.Install (Keyboard, I).
                                           Master_File.all),  
                           Release.Install (Keyboard, I).Install_File.all);
                when Release.Binary =>
                    if Ascii_Mode then
                        Log.Put_Line
                           ("Set transmission modes (Stream,Image,File).",
                            Profile.Note_Msg, Profile.Verbose);
                        Ascii_Mode := False;
                        File_Transfer.Set_Type (Connection, Ftp_Defs.Image);
                        Response (Connection);
                        File_Transfer.Command_Status (Connection, Ftp_Status);
                        Status_Ok (Ftp_Status);
                    end if;
                    Store (Connection,  
                           Local_Dir & R1000_Form
                                          (Release.Install (Keyboard, I).
                                           Master_File.all),  
                           Release.Install (Keyboard, I).Install_File.all);
            end case;
        end loop;
        if not Ascii_Mode then
            Log.Put_Line ("Set transmission modes (Stream,Ascii,File).",
                          Profile.Note_Msg, Profile.Verbose);
            Ascii_Mode := True;
            File_Transfer.Set_Type (Connection, Ftp_Defs.Ascii);
            Response (Connection);
            File_Transfer.Command_Status (Connection, Ftp_Status);
            Status_Ok (Ftp_Status);
        end if;
        Store (Connection, R1000_Recog_H, Ws_Recog_H);
        Store (Connection, R1000_Recog_H, Ttws_Recog_H);

----We are all done; say "bye", disconnect, and free up the socket.

        Log.Put_Line ("Disconnect.", Profile.Note_Msg, Profile.Verbose);
        Disconnect (Connection);
        Log.Put_Line ("[end of Rxi_Install.Workstation_Files(" &
                      Terminal_Type'Image (Keyboard) & ',' & On_Machine & ',' &
                      Username & ',' & Rxi_Source_Directory & ")]",
                      Profile.Auxiliary_Msg, Profile.Verbose);

    exception

----When we Quit we simply disconnect; error messages have already gone out.

        when Quit =>
            Disconnect (Connection);
            raise Library.Error;

----Anything else is simply unexpected.

        when others =>
            Log.Put_Line ("Unexpected exception during Rxi_Install script:" &  
                          Debug_Tools.Get_Exception_Name (True, True),  
                          Profile.Error_Msg,  
                          Profile.Verbose);
            Disconnect (Connection);

    end Workstation_Files;

--\f

end Rxi_Install;