2.5. Cleaning Up Skeleton for the SSHD Configuration

Now you know what can you find in every source file in your YaST module. This part will show you how to clean them up by removing functions and files unneeded for our module and a basic behavior and UI for SSHD Configuration will be set up.

2.5.1. Modifying Source Files

This part will summarize functions and files removed from our YaST module created using the y2tool helper.

2.5.1.1. Changes in the src/ directory:

You can download the changed source files here or you can download them one by one later in this section.

2.5.1.1.1. Files Sshd2.pm and Makefile.am

The file Sshd2.pm has been completely removed from the project and also the appropriate record in the Makefile.am file should be changed to reflect on that change because installing files using the broken Makefile.am would lead into erroneous result.

Original version:

module_DATA =                   \ 
       Sshd.ycp                \ 
       Sshd2.pm

New version:

module_DATA =                   \ 
       Sshd.ycp
2.5.1.1.2. File Sshd.ycp
[Note]Note

This configuration module will provide the basic functional interface with no global variables.

The main reason for a functional interface is that you can simply control your configuration data flow. Global variables are more vulnerable to corruption by other modules.

You had better download the changed file Sshd.ycp here

Here you can see the list of changes in the original file:

Cleaning the source code from unneeded functions:

  • Remove Modified() function (both definitions global boolean Modified...).

  • Remove AbortFunction() function.

  • Remove Abort() function.

  • Remove Export() function.

  • Remove Summary() function.

  • Remove Overview() function.

  • Remove AutoPackages() function.

  • Remove Import() function.

New and modified functionality:

  • Remove the global keyword from all definitions of variables to make them local-only because we don't want anybody to change our data internally but using the functions.

    Original:

    global boolean modified = false;

    Changed:

    boolean modified = false;
  • Add this

    import "Service";
    import "Popup";

    under other imports in the module. We are using these modules later in the module.

  • Add new variable definition

    integer sl = 1000;

    after the boolean modified... definition. This variable is used for length definition of short sleeps between read and write progress steps.

  • Add new GetModified() function just after the integer sl = 1000; definition:

    /**
     * Returns whether the configuration has been modified.
     */
    global boolean GetModified() {
        return modified;
    }
  • Add new SetModified() function after the GetModified() one:

    /**
     * Sets that the configuration has been modified.
     */
    global void SetModified() {
        modified = true;
    }
  • Modify Abort() function:

    /**
     * Returns a confirmation popup dialog whether user wants to really abort.
     */
    global boolean Abort() {
        return Popup::ReallyAbort(GetModified());
    }
  • Add new PollAbort() function after the Abort() function:

    /**
     * Checks whether an Abort button has been pressed.
     * If so, calls function to confirm the abort call.
     *
     * @return boolean true if abort confirmed
     */
    global boolean PollAbort() {
        if (UI::PollInput() == `abort)
    	return Abort();
    
        return false;
    }
  • Modify Read() function:

    Two useless progress steps were removed. Some texts were changed, e.g., Sshd to SSHD.

    /**
     * Read all SSHD settings
     * @return true on success
     */
    global boolean Read() {
    
        /* SSHD read dialog caption */
        string caption = _("Initializing SSHD Configuration");
    
        integer steps = 2;
    
        Progress::New( caption, " ", steps, [
        /* Progress stage 1/2 */
        _("Read current SSHD configuration"),
        /* Progress stage 2/2 */
        _("Read current SSHD state")
    ], [
        /* Progress step 1/2 */
        _("Reading current SSHD configuration..."),
        /* Progress step 2/2 */
        _("Reading current SSHD state..."),
        /* Progress finished */
        Message::Finished()
    ],
    ""
        );
    
        sleep(sl);
    
        if(PollAbort()) return false;
        Progress::NextStage();
        /* Error message */
        if(false) Report::Error(Message::CannotReadCurrentSettings());
        sleep(sl);
    
        if(PollAbort()) return false;
        Progress::NextStep();
        /* Error message */
        if(false) Report::Error(_("Cannot read current SSHD state."));
        sleep(sl);
    
        if(PollAbort()) return false;
        Progress::NextStage ();
        sleep(sl);
    
        modified = false;
        return true;
    }
  • Modify Write() function:

    Some texts were changed, e.g., Sshd to SSHD. Message::SuSEConfigFailed() is replaced with Message::CannotAdjustService("sshd").

    /**
     * Write all SSHD settings
     * @return true on success
     */
    global boolean Write() {
    
        /* SSHD read dialog caption */
        string caption = _("Saving SSHD Configuration");
    
        integer steps = 2;
        
        Progress::New(caption, " ", steps, [
        /* Progress stage 1/2 */
        _("Write the SSHD settings"),
        /* Progress stage 2/2 */
        _("Adjust the SSHD service")
    ], [
        /* Progress step 1/2 */
        _("Writing the SSHD settings..."),
        /* Progress step 2/2 */
        _("Adjusting the SSHD service..."),
        Message::Finished()
    ],
    ""
        );
    
        sleep(sl);
    
        if(PollAbort()) return false;
        Progress::NextStage();
        /* Error message */
        if(false) Report::Error (_("Cannot write SSHD settings."));
        sleep(sl);
    
        if(PollAbort()) return false;
        Progress::NextStage ();
        /* Error message */
        if(false) Report::Error (Message::CannotAdjustService("sshd"));
        sleep(sl);
    
        Progress::NextStage ();
        sleep(sl);
    
        return true;
    }
2.5.1.1.3. File complex.ycp

You had better download the changed file complex.ycp here

Here is the list of changes in the file:

Removed unneeded functions:

  • Remove Modified() function.

  • Remove ReallyAbort() function.

  • Remove PollAbort() function.

  • Remove SummaryDialog() function.

  • Remove OverviewDialog() function.

2.5.1.1.4. File dialogs.ycp

You had better download the changed file dialogs.ycp here

Here is the list of changes in the file:

Removed unneeded functions:

  • Remove Configure1Dialog() function.

  • Remove Configure2Dialog() function.

Added new functions:

  • Add new ServerConfigurationDialog() function.

    This function creates a dialog using the Wizard module and then handles the user input in the endless loop. After the Abort or Next button is pressed, handler skips outside the loop and returns the ID of the pressed button as the function result.

    /**
     * Server Configuration Dialog
     *
     * @return any dialog result
     */
    any ServerConfigurationDialog() {
    
        /* a dialog caption */
        string caption = _("SSHD Server Configuration");
    
        term contents = `VBox (
            `Left(`Label(_("SSHD TCP Ports"))),
            `Left(
                `VBox (
                    `MinSize( 40, 5,
                        /* A table header */
                        `Table(`id("Port"), `header("Port"), [])
                    ),
                    `HBox (
                        /* a push button */
                        `PushButton(`id("add_port"), _("&Add...")),
                        /* a push button */
                        `PushButton(`id("edit_port"), _("&Edit...")),
                        /* a push button */
                        `PushButton(`id("delete_port"), _("&Delete"))
                    ),
                    `VSpacing(1),
                    `Frame (
                        /* a dialog frame caption */
                        _("Server Features"),
                        `VBox (
                            /* a check box */
                            `Left(`CheckBox(`id("AllowTcpForwarding"), _("Allow &TCP Forwarding"))),
                            /* a check box */
                            `Left(`CheckBox(`id("X11Forwarding"),      _("Allow &X11 Forwarding"))),
                            /* a check box */
                            `Left(`CheckBox(`id("Compression"),        _("Allow &Compression")))
                        )
                    ),
                    `VStretch()
                )
            )
        );
    
        Wizard::SetContentsButtons(caption, contents, HELPS["server_configuration"]:"",
                Label::BackButton(), Label::NextButton());
        Wizard::DisableBackButton();
    
        any ret = nil;
        while(true) {
    
            ret = UI::UserInput();
    
            /* abort? */
            if(ret == `abort) {
                if(Sshd::Abort()) break;
                else continue;
            /* next */
            } else if(ret == `next) {
                break;
            /* unknown */
            } else {
                y2error("unexpected retcode: %1", ret);
                continue;
            }
        }
    
        Wizard::RestoreBackButton();
    
        return ret;
    }

    This dialog defines the the table of TCP Ports connected with Add..., Edit... and Delete buttons. Add... and Edit... button labels are followed by dots because pressing these buttons would open a new small pop-up dialog on the top of the current one. Server Features options are surrounded by a `Frame widget.

     

  • Add new LoginSettingsDialog() function.

    This function creates a dialog using the Wizard module and then handles the user input in the endless loop. After the Abort, Next or Back button is pressed, handler skips outside the loop and returns the ID of the pressed button as the function result.

    /**
     * Login Settings Dialog
     *
     * @return any dialog result
     */
    any LoginSettingsDialog() {
    
        /* a dialog caption */
        string caption = _("SSHD Server Login Settings");
    
        term contents = `VBox(
            `Frame (
                _("General Login Settings"),
                `VBox (
                    /* A check box */
                    `Left(`CheckBox(`id("PrintMotd"),            _("Print &Message of the Day After Login"))),
                    /* A check box */
                    `Left(`CheckBox(`id("PermitRootLogin"),      _("Permi&t Root Login")))
                )
            ),
            `VSpacing(1),
            `Frame (
                _("Authentication Settings"),
                `VBox (
                    /* A text entry */
                    `Left(`TextEntry(`id("MaxAuthTries"),           _("Ma&ximum Authentication Tries"))),
                    /* A check box */
                    `Left(`CheckBox (`id("PasswordAuthentication"), _("Pa&sswordAuthentication"))),
                    /* A check box */
                    `Left(`CheckBox (`id("RSAAuthentication"),      _("RSA Authenti&cation"))),
                    /* A check box */
                    `Left(`CheckBox (`id("PubkeyAuthentication"),   _("Public &Key Authentication")))
                )
            ),
            `VStretch()
        );
    
        Wizard::SetContentsButtons(caption, contents, HELPS["login_settings"]:"",
                Label::BackButton(), Label::NextButton());
        Wizard::SetNextButton(`next, Label::AcceptButton());
    
        any ret = nil;
        while(true) {
    
            ret = UI::UserInput();
    
            /* abort? */
            if(ret == `abort) {
                if(Sshd::Abort()) break;
                else continue;
            /* next */
            } else if(ret == `next) {
                break;
            } else if(ret == `back) {
                break;
            /* unknown */
            } else {
                y2error("unexpected retcode: %1", ret);
                continue;
            }
        }
    
        Wizard::RestoreNextButton();
    
        return ret;
    }

    This simple dialog contains two frames of General Login Settings and Authentication Settings with check boxes.

     

2.5.1.1.5. File helps.ycp

You had better download the changed file helps.ycp here

Here is the list of changes in the file:

  • Remove helps for summary, overview, c1 and c2.

  • Add new helps for server_configuration and login_settings

    /* Server Configuration dialog help */
        "server_configuration" : _("<p><b><big>Server Configuration</big></b><br>
    Configure SSHD here.<br></p>"),
    
        /* Login Settings dialog help */
        "login_settings" : _("<p><b><big>Login Settings</big></b><br>
    Configure SSHD login settings here.<br></p>"),
[Note]Note

Structure of helps is:

map HELPS = $[
       // TRANSLATORS: Comment for translators (this is a help text for...)
       "help_for" : _("Help text marked for translation..."),
       ];
2.5.1.1.6. File sshd.ycp

You had better download the changed file sshd.ycp here

Here is the list of changes in the file:

  • Remove a command line definition.

  • Remove installation proposal support.

This client still runs the workflow via CommandLine module with an empty command line definition just to inform that the command line interface is not available for this module if anyone tries to run it.

2.5.1.1.7. File sshd_auto.ycp

This file has been completely removed from the package and also the appropriate record in the Makefile.am file.

 

2.5.1.1.8. File sshd_proposal.ycp

This file has been completely removed from the package and also the appropriate record in the Makefile.am file.

Makefile.am file should be changed this way.

Original version:

client_DATA =                   \
       sshd.ycp                \
       sshd_auto.ycp   \
       sshd_proposal.ycp

New version:

client_DATA =                   \
       sshd.ycp

 

2.5.1.1.9. File wizards.ycp

You had better download the changed file wizards.ycp here

Here is the list of changes in the file:

  • Remove AddSequence() function.

  • Remove AutoSequence() function.

2.5.1.2. Changes in the testsuite/ directory

Testsuites were designed for checking the global functionality, such as functions of modules, to keep them consistent. They can also help to find out when something else, used by your module, is suddenly changed.

In this tutorial, all testsuites testsuite/tests/Sshd.* have been completely removed. Creating and running testsuites will be later described in another tutorial.

2.5.2. Checking the Progress

We have worked hard to get this project where it is and now we would like to enjoy the current status by running the application.

# Enter the basic directory of the project
cd sshd

# We have changed some Makefiles
make -f Makefile.cvs

# Check the syntax and compile YCP modules
make

# Install the project files to the system
sudo make install

# Run the application in Qt
sudo /sbin/yast2 sshd

# ... or run the application in ncurses
sudo /sbin/yast sshd

Now we can check it out. Dialogs are still not connected with the data, there are no pre-filled values and you still can't save the changed configuration, in spite of these facts, it is still a great success ;)!

See the current status of your module:

[Important]Important

After that, anytime you want to check the current status of changed source code, just run these commands:

# Enter the directory with changed files
cd sshd/src/

# Compile and install files into the system
sudo make install

# Run the application
sudo /sbin/yast2 sshd