/* GAdmin-OpenVPN - An easy to use GTK+ frontend for the openvpn client.
 * Copyright (C) 2008 - 2012 Magnus Loef <magnus-swe@telia.com> 
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
 * See the GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License along
 * with this program; if not, write to the Free Software Foundation, Inc.,
 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
 *
*/



#include <gtk/gtk.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include "widgets.h"
#include "gettext.h"
#include "show_info.h"
#include "functions.h"
#include "apply_client_settings.h"
#include "allocate.h"
#include "commands.h"
#include "populate_client_settings.h"
#include "populate_conf_tab.h"

extern gchar *selected_connection;
extern int activated;

int add_new_connection = 0;


int has_value(gchar *input)
{
    int have_value = 0;

    if( input!=NULL && strlen(input) > 2 )
        have_value = 1;

    return have_value;
}


/* Make firestarter/iptables accept tap+ interfaces */
void add_firestarter_user_pre()
{
    FILE *fp;
    long file_size = 0;
    char *line;
    gchar *conf;
    int have_tap_lines = 0;

    if((fp=fopen(FIRESTARTER_USER_PRE, "r"))==NULL)
    {
        /* Dont show a popup */
        return;
    }
    fseek(fp, 0, SEEK_END);
    file_size = ftell(fp);
    rewind(fp);

    line = allocate(file_size);

    if( file_size > 1 )
    while(fgets(line, file_size, fp)!=NULL)
    {
        if( line==NULL || strlen(line) < 10 || commented(line) )
            continue;

        if( cmplowercase(line, "-a input -i tap+ -j accept") )
            have_tap_lines++;

        if( cmplowercase(line, "-a output -o tap+ -j accept") )
            have_tap_lines++;

        if( cmplowercase(line, "-a forward -i tap+ -j accept") )
            have_tap_lines++;
    }
    fclose(fp);
    free(line);

    /* Dont add the tap+ lines if they already exist */
    if( have_tap_lines >= 3 )
        return;

    /* Append the lines. Does Firestarter allow tap broadcast traffic ? Fix: If it doesnt  */
    conf = g_strdup_printf("$IPT -A INPUT -i tap+ -j ACCEPT\n$IPT -A OUTPUT -o tap+ -j ACCEPT\n$IPT -A FORWARD -i tap+ -j ACCEPT\n");
    if((fp=fopen(FIRESTARTER_USER_PRE, "a"))==NULL)
    {
        /* Show a popup */
        printf("Unable to add firestarter configuration here: %s\n", FIRESTARTER_USER_PRE);
        g_free(conf);
        return;
    }
    fputs(conf, fp);
    fclose(fp);
    g_free(conf);
}


/* Does the connection name exist in the connection treeview */
int connection_exists(struct w *widgets, gchar *name)
{
    GtkTreeSelection *selection;
    gchar *temp_name = NULL;
    GtkTreeIter iter;

    if( widgets->connection_store )
    {
        selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(widgets->connection_treeview));
        if( ! selection )
            return 0;

        if( gtk_tree_model_get_iter_first(GTK_TREE_MODEL(widgets->connection_store), &iter) )
        {
            do {
                    gtk_tree_model_get(GTK_TREE_MODEL(widgets->connection_store), &iter, 0, &temp_name, -1);

	                if( name!=NULL && temp_name!=NULL )
	                {
		                if( strcmp(name, temp_name) == 0 )
		                {
		                    if( temp_name!=NULL )
		                        g_free(temp_name);
		                    return 1;
		                }
	                }
	                if( temp_name!=NULL )
	                  g_free(temp_name);

                }  while(gtk_tree_model_iter_next(GTK_TREE_MODEL(widgets->connection_store), &iter));
         }
    }
    return 0;
}


/* Add a new connection */
void add_connection(struct w *widgets)
{
    add_new_connection = 1;

    apply_client_settings(widgets);

    add_new_connection = 0;
}


/* Get all extra user added options */
char * get_user_added_options(gchar *openvpn_client_conf)
{
    FILE *fp;
    long file_size = 0;
    char *line;
    char *extra_options = NULL;

    if((fp=fopen(openvpn_client_conf, "r"))==NULL)
    {
        /* Dont show a popup */
        return extra_options;
    }
    fseek(fp, 0, SEEK_END);
    file_size = ftell(fp);
    rewind(fp);

    line = allocate(file_size);
    extra_options = allocate(file_size);
    extra_options[0]='\0';

    if( file_size > 1 )
    while(fgets(line, file_size, fp)!=NULL)
    {
        if( line==NULL || strlen(line) < 10 || commented(line) )
            continue;

        /* Get all options not used in the settings */
        if( cmplowercase(line, "fragment ")
        ||  cmplowercase(line, "tun-mtu ")
        ||  cmplowercase(line, "redirect-gateway ")
        ||  cmplowercase(line, "explicit-exit-notify ")
        ||  cmplowercase(line, "route-delay ")
        ||  cmplowercase(line, "route-method ") )
        {
            strcat(extra_options, line);
        }
    }
    fclose(fp);
    free(line);

    return extra_options;
}


#define MAX_REMOTE_LINES_BUFFER 100000
char *remote_lines_buffer = NULL;
int num_remote_lines = 0;

/* Get remote lines from the gui */
int add_remote_lines_to_buffer(GtkTreeModel *model, GtkTreePath *path,
    	        		  GtkTreeIter *iter, struct w *widgets)
{
    gchar *conf_line=NULL;
    gchar *option1=NULL, *option2=NULL, *option3=NULL;

    gtk_tree_model_get(model, iter, 0, &option1, -1);
    gtk_tree_model_get(model, iter, 1, &option2, -1);
    gtk_tree_model_get(model, iter, 2, &option3, -1);

    /* The last 2 columns (address and port) must be filled in */
    if( option2==NULL || option3==NULL )
    {
    	printf("Missing value for a server.\n");
        if( option1!=NULL )
            g_free(option1);
        if( option2!=NULL )
            g_free(option2);
        if( option3!=NULL )
            g_free(option3);

        return FALSE;
    }

    num_remote_lines++;

    if( option1!=NULL && strlen(option1) > 0 ) /* With a comment */
        conf_line = g_strdup_printf("### %s\nremote %s %s\n", option1, option2, option3);
    else /* Without a standard comment */
        conf_line = g_strdup_printf("### None\nremote %s %s\n", option2, option3);

    /* Add to global remote_lines_buffer */
    if( strlen(conf_line) + strlen(remote_lines_buffer) < MAX_REMOTE_LINES_BUFFER -1 )
        strcat(remote_lines_buffer, conf_line);
        
    if( conf_line!=NULL )
        g_free(conf_line);
    if( option1!=NULL )
        g_free(option1);
    if( option2!=NULL )
        g_free(option2);
    if( option3!=NULL )
        g_free(option3);

    /* Return false to continue iteration */
    return FALSE;
}



void apply_client_settings(struct w *widgets)
{
    /* Change the client configuration and sysinit script. */
    FILE *fp;
    int i = 0;
    gint active_index;
    GtkTreeModel *model;
    gchar *info, *cmd;
    char *extra_options = NULL;
    gchar *sysinit_script_path, *sysinit_start_script;
    gchar *conf_data=NULL, *openvpn_client_conf=NULL;
    gchar *pass_file, *pass_lines;
    gchar *upscript, *upscript_path, *tls_auth_line;
    gchar *firestarter_start, *firestarter_stop;
    gchar *non_firestarter_start, *non_firestarter_stop;
    gchar *share_tunnel_with_lan, *start_at_boot_label;

    /* Entries */
    gchar *connection_name;
    G_CONST_RETURN gchar *user;
    G_CONST_RETURN gchar *pass;
    G_CONST_RETURN gchar *passpath;
    G_CONST_RETURN gchar *mountcmd;
    G_CONST_RETURN gchar *proxy_address;
    /* Cert entries */
    G_CONST_RETURN gchar *cacert;
    G_CONST_RETURN gchar *cert;
    G_CONST_RETURN gchar *key;
    G_CONST_RETURN gchar *takey;
    /* Spin buttons */
    G_CONST_RETURN gchar *log_level;
    G_CONST_RETURN gchar *proxy_port;
    G_CONST_RETURN gchar *mssfix;
    /* Combos */
    gchar *proto=NULL, *device=NULL, *auth_line=NULL;
    gchar *cipher=NULL, *compression=NULL, *proxy_line=NULL;

    if( non_firestarter_stop )
    {
    }

    /* Entries */
    connection_name = g_strdup_printf("%s", gtk_entry_get_text(GTK_ENTRY(widgets->client_set_entry[0])));
    user  = gtk_entry_get_text(GTK_ENTRY(widgets->client_set_entry[1]));
    pass  = gtk_entry_get_text(GTK_ENTRY(widgets->client_set_entry[2]));
    passpath = gtk_entry_get_text(GTK_ENTRY(widgets->client_set_entry[3]));
    mountcmd = gtk_entry_get_text(GTK_ENTRY(widgets->client_set_entry[4]));
    proxy_address = gtk_entry_get_text(GTK_ENTRY(widgets->client_set_entry[5]));
    /* Cert entries */
    cacert = gtk_entry_get_text(GTK_ENTRY(widgets->client_set_entry[6]));
    cert   = gtk_entry_get_text(GTK_ENTRY(widgets->client_set_entry[7]));
    key    = gtk_entry_get_text(GTK_ENTRY(widgets->client_set_entry[8]));
    /* TA.key. Required if TLS-Auth is used on the server. */
    takey  = gtk_entry_get_text(GTK_ENTRY(widgets->client_set_entry[9]));
    /* Spin buttons */
    log_level   = gtk_entry_get_text(GTK_ENTRY(widgets->client_set_spinbutton[0]));
    proxy_port  = gtk_entry_get_text(GTK_ENTRY(widgets->client_set_spinbutton[1]));
    mssfix      = gtk_entry_get_text(GTK_ENTRY(widgets->client_set_spinbutton[2]));

    /* Make sure we have some valid connection settings */
    if( connection_name == NULL || strlen(connection_name) < 3 )
    {
        info = g_strdup_printf("%s", _("The connection name is too short.\n"));
        show_info(info);
        g_free(info);
        return;
    }

    if( strlen(cacert) < 3 || strlen(cert) < 3 || strlen(key) < 3 ) // Ignore TA because its optional.
    {
        info = g_strdup_printf("%s", _("Missing certificate or key setting.\n"));
        show_info(info);
        g_free(info);
        return;
    }

    if( ! add_new_connection )
    {
        if( selected_connection == NULL || strlen(selected_connection) < 3 )
        {
            /* No connection in the connections tab,
               select the one from the connection name entry */
            if( selected_connection!=NULL )
                  g_free(selected_connection);
            selected_connection = g_strdup_printf("%s", connection_name);
        }
    }

    /* Check that the specified connection name is valid. */
    for(i=0; connection_name[i]!='\0'; i++)
    {
        /* Change spaces to "-" chars */
        if( connection_name[i]==' ' )
            connection_name[i]='-';

        if( connection_name[i]=='\n'
        ||  connection_name[i]=='\r'
        ||  connection_name[i]=='\t' )
        {
            printf("The specified connection name contains invalid chars.\n");
            if( connection_name!=NULL )
                g_free(connection_name);
            return;
        }
    }
    if( i < 3 )
    {
        printf("You must select a longer name for this connection.\n");
        if( connection_name!=NULL )
            g_free(connection_name);
        return;
    }

    if( selected_connection != NULL )
    {
        /* Check that the selected connection name is valid. */
        for(i=0; selected_connection[i]!='\0'; i++)
        {
            /* Change spaces to "-" chars */
            if( selected_connection[i]==' ' )
	            selected_connection[i]='-';

            if( selected_connection[i]=='\n'
            ||  selected_connection[i]=='\r'
            ||  selected_connection[i]=='\t' )
            {
	            printf("The connection name contains invalid chars.\n");
	            if( connection_name!=NULL )
                    g_free(connection_name);
	            return;
            }
        }
        if( i < 3 )
        {
            printf("You must select a longer name for this connection.\n");
            if( connection_name!=NULL )
                g_free(connection_name);
            return;
        }
    }

    /* Check that the new connection name doesnt already exist */
    if( add_new_connection )
    {
        if( connection_exists(widgets, connection_name) )
        {
            info = g_strdup_printf("%s",
	            _("A connection with this name already exists. Write a new connection name first.\n"));
            show_info(info);
            g_free(info);
            if( connection_name!=NULL )
                g_free(connection_name);
            return;
        }
    }

    if( ! add_new_connection )
    {
        /* Check if the connection name has changed. If so, move it to the new directory. */
        if( strcmp((char *)selected_connection, (char *)connection_name) !=0 )
        {
            cmd = g_strdup_printf("mv '%s/client/%s' '%s/client/%s'", OPENVPN_SYSCONF_DIR, selected_connection, OPENVPN_SYSCONF_DIR, connection_name);
            if( ! run_command(cmd) )
            {
	            printf("Error: could not run command:\n%s\n", cmd);
	            g_free(cmd);
	            if( connection_name!=NULL )
                    g_free(connection_name);
	            return;
            }
            g_free(cmd);
        }
    }

    /* Set this connection as the globally selected one */
    if( selected_connection!=NULL )
        g_free(selected_connection);
    selected_connection = g_strdup_printf("%s", connection_name);

    if( connection_name!=NULL )
        g_free(connection_name);

    /* Create this connections sysconf directory. */
    cmd = g_strdup_printf("mkdir -p '%s/client/%s'", OPENVPN_SYSCONF_DIR, selected_connection);
    if( ! run_command(cmd) )
    {
        printf("Error: could not run command:\n%s\n", cmd);
        g_free(cmd);
        return;
    }
    g_free(cmd);
    /* Create this connections log directory. */
    cmd = g_strdup_printf("mkdir -p '%s/log/gadmin-openvpn/client/%s'", LOCALSTATEDIR, selected_connection);
    if( ! run_command(cmd) )
    {
        printf("Error: could not run command:\n%s\n", cmd);
        g_free(cmd);
        return;
    }
    g_free(cmd);

    /* Remove all "Connection_selected" lines from all confs */
    remove_all_selected_lines();

    /* Combos... */

    /* Protocol */
    active_index = gtk_combo_box_get_active(GTK_COMBO_BOX(widgets->client_set_combo[0]));
    if( active_index == 0 )
        proto = g_strdup_printf("proto tcp");
    else
        proto = g_strdup_printf("proto udp");

    /* Tap device */
    active_index = gtk_combo_box_get_active(GTK_COMBO_BOX(widgets->client_set_combo[1]));
    if( active_index == 0 )
        device = g_strdup_printf("tap0");
    if( active_index == 1 )
        device = g_strdup_printf("tap1");
    if( active_index == 2 )
        device = g_strdup_printf("tap2");
    if( active_index == 3 )
        device = g_strdup_printf("tap3");

    if( active_index == 4 )
        device = g_strdup_printf("tun0");
    if( active_index == 5 )
        device = g_strdup_printf("tun1");
    if( active_index == 6 )
        device = g_strdup_printf("tun2");
    if( active_index == 7 )
        device = g_strdup_printf("tun3");

    /* Cipher */
    active_index = gtk_combo_box_get_active(GTK_COMBO_BOX(widgets->client_set_combo[2]));
    if( active_index == 0 )
        cipher = g_strdup_printf("cipher BF-CBC\n");       /* BlowFish */
    if( active_index == 1 )
        cipher = g_strdup_printf("cipher AES-128-CBC\n");  /* AES 128 */
    if( active_index == 2 )
        cipher = g_strdup_printf("cipher AES-256-CBC\n");  /* AES 256 */
    if( active_index == 3 )
        cipher = g_strdup_printf("cipher DES-EDE3-CBC\n"); /* Triple-DES */


    /* Setup user authentication if the username entry contains a username. */
    if( user!=NULL && strlen(user) > 0 )
    {
        auth_line = g_strdup_printf("auth-user-pass %s\n", passpath);

        /* Write the username and password to the passfile if the password entry contains a password */
        if( pass!=NULL && strlen(pass) > 3 )
        {
            /* Run the mount command if any. Ignore errors. */
            if( mountcmd!=NULL && strlen(mountcmd) > 7 )
            {	    
	            if( ! run_command((char *)mountcmd) )
	            {
	                // Dont show an error
	            }
            }
            /* Create the passfile directory */
            info = g_strdup_printf("%s", passpath);

            /* Snip a the last '/' from info */
            for(i=strlen(info)-1; info[i]!='\0'; i--)
            if( info[i]=='/' )
            {
	            info[i]='\0';
	            break;
            }
            /* Check password path validity */
            if( strlen(info) < 3 )
            {
	            g_free(info);
	            g_free(auth_line);
	            printf("Passfile path too short\n");
	            return;
            }

            if( ! file_exists(info) )
            {
	            make_dir_chmod(info, "600");
            }
            g_free(info);

            pass_file = g_strdup_printf("%s", passpath);
            if((fp=fopen(pass_file, "w+"))==NULL)
            {
	            info = g_strdup_printf(_("Can not write the password file: \n%s\n"), pass_file);
	            show_info(info);
	            g_free(info);
	            g_free(pass_file);
	            return;
            }
            chmod_file(pass_file, "600");

            pass_lines = g_strdup_printf("%s\n%s\n\n", user, pass);
            fputs(pass_lines, fp);
            fclose(fp);

            info = g_strdup_printf(_("A new username and password has been added.\n"));
            show_info(info);
            g_free(info);

            g_free(pass_file);
            g_free(pass_lines);
        }
    }
    else
      auth_line = g_strdup_printf("\n");


    /* Compression */
    active_index = gtk_combo_box_get_active(GTK_COMBO_BOX(widgets->client_set_combo[3]));
    if( active_index == 0 )
        compression = g_strdup_printf("\n");
    else
        compression = g_strdup_printf("comp-lzo\n");

    /* Chroot is standard */

    /* Make Firestarter accept traffic on Tap interfaces
       if the user-pre firestarter file exists. */
    add_firestarter_user_pre();
    // FIX: Also account for Tun interfaces.

    /* Share connection with LAN */
    active_index = gtk_combo_box_get_active(GTK_COMBO_BOX(widgets->client_set_combo[4]));
    if( active_index == 0 )
    {
        share_tunnel_with_lan = g_strdup_printf("\n");
    }
    else
    {
        share_tunnel_with_lan = g_strconcat(
        IP_FORWARD_CMD_START, "\n",
        NULL);
    }

    /* Firestarter start and stop script parts if used. */
    active_index = gtk_combo_box_get_active(GTK_COMBO_BOX(widgets->client_set_combo[5]));
    if( active_index == 1 )
    {
        firestarter_start = g_strconcat(
        "	# Start Firestarter if its not running.\n",
        "	if [ ! -e /var/lock/subsys/firestarter -o -e /var/lock/firestarter ]; then\n",
        "		", FIRESTARTER_BINARY, " -s\n",
        "	fi\n",
        NULL);

        firestarter_stop = g_strconcat(
        "	# Stop Firestarter if its running.\n",
        "	if [ -e /var/lock/subsys/firestarter -o -e /var/lock/firestarter ]; then\n",
        "    		", FIRESTARTER_BINARY, " -p\n",
        "	fi\n",
        NULL);

        non_firestarter_start = g_strdup_printf("\n");
        non_firestarter_stop  = g_strdup_printf("\n");
    }
    else
    {
        /* Instead of firestarter configuring iptables, we do it. */
        non_firestarter_start = g_strconcat("",
        "	# Run some iptable rules for the VPN-client.\n",
        "	iptables -A INPUT  -i tap+ -j ACCEPT\n",
        "	iptables -A OUTPUT -o tap+ -j ACCEPT\n",
        "	iptables -A FORWARD -i tap+ -j ACCEPT\n",
        NULL);

        /* Dont remove internet sharing and other vital stuff */
        firestarter_start = g_strdup_printf("\n");
        firestarter_stop  = g_strdup_printf("\n");
    }


    /* Start at boot */
    active_index = gtk_combo_box_get_active(GTK_COMBO_BOX(widgets->client_set_combo[6]));
    if( active_index == 0 )
        start_at_boot_label = g_strdup_printf("\n");
    else
        start_at_boot_label = g_strdup_printf("# Client starts at boot\n");

    /* Use proxy. */
    if( proxy_address!=NULL && strlen(proxy_address) > 0 )
        proxy_line = g_strdup_printf("http-proxy-retry\nhttp-proxy %s %s\n", proxy_address, proxy_port);
    else
        proxy_line = g_strdup_printf("\n");


    openvpn_client_conf = g_strdup_printf("%s/client/%s/gadmin-openvpn-client.conf", OPENVPN_SYSCONF_DIR, selected_connection);

    /* Get all extra user added options */
    extra_options = get_user_added_options(openvpn_client_conf);

    /* Get all remote options from the treeview */
    num_remote_lines = 0;
    remote_lines_buffer = allocate(MAX_REMOTE_LINES_BUFFER);
    strcpy(remote_lines_buffer, "\n");
    model = gtk_tree_view_get_model(GTK_TREE_VIEW(widgets->address_treeview));
    gtk_tree_model_foreach(GTK_TREE_MODEL(model),
                    	  (GtkTreeModelForeachFunc) &add_remote_lines_to_buffer, widgets);
    /* Add "remote-random" if more then 1 remote has been added */
    if( num_remote_lines > 1 && strlen(remote_lines_buffer) < MAX_REMOTE_LINES_BUFFER -15 )
        strcat(remote_lines_buffer, "remote-random\n");
    /* Add a last newline to make the conf look nice */
    if( strlen(remote_lines_buffer) < MAX_REMOTE_LINES_BUFFER -2 )
        strcat(remote_lines_buffer, "\n");


    /* Write the openvpn client configuration file:
       /etc/gadmin-openvpn/client/SITE/gadmin-openvpn-client.conf */
    if((fp=fopen(openvpn_client_conf, "w+"))==NULL)
    {
        info = g_strdup_printf(_("Can not write openvpn client configuration here: \n%s\n"), openvpn_client_conf);
        show_info(info);
        g_free(info);
        free(remote_lines_buffer);
        g_free(openvpn_client_conf);
        g_free(proto);
        g_free(device);
        g_free(auth_line);
        g_free(cipher);
        g_free(compression);
        g_free(proxy_line);
        g_free(firestarter_start);
        g_free(firestarter_stop);
        g_free(non_firestarter_start);
        g_free(start_at_boot_label);
        g_free(share_tunnel_with_lan);
        return;
    }

    /* TA.key. Required if TLS-Auth is used on the server. */
    if( takey!=NULL && strlen(takey) > 3 )
    {
        tls_auth_line = g_strdup_printf("tls-auth certs/%s 1\n", takey);
        // client_type = g_strdup_printf("tls-client\n");
    }
    else
    {
        tls_auth_line = g_strdup_printf("\n");
        // client_type = g_strdup_printf("client\n");
    }


    conf_data = g_strconcat("\n",
    "# Connection_name: ", selected_connection, "\n",
    "# Connection_selected\n",
    "client\n",
    remote_lines_buffer,
    proto, "\n",
    "dev ", device, "\n",
    "ca   certs/", cacert,"\n",
    "cert certs/", cert,"\n",
    "key  certs/", key,"\n",
    tls_auth_line,
    auth_line,
    proxy_line,
    cipher,
    compression,
    "chroot ", OPENVPN_SYSCONF_DIR, "/client/", selected_connection, "\n",
    "user ", CLIENT_USER, "\n",
    "group ", CLIENT_GROUP, "\n",
    "persist-key\n",
    "persist-tun\n",
    "log    ", LOCALSTATEDIR, "/log/gadmin-openvpn/client/", selected_connection, "/openvpn-client.log\n",
    "status ", LOCALSTATEDIR, "/log/gadmin-openvpn/client/", selected_connection, "/openvpn-client-status.log\n",
    "verb ", log_level, "\n",
    "mssfix ", mssfix, "\n",
    "mute 20\n",
    "ping 10\n",
    "ping-restart 30\n",
    "allow-pull-fqdn\n",
    "resolv-retry infinite\n",
    "up ", OPENVPN_SYSCONF_DIR, "/client/", selected_connection, "/upscript.sh\n",
    NULL);

    fputs(conf_data, fp);

   /* Puts extra options written in the conf tab */
    if( extra_options != NULL )
    {
        if( strlen(extra_options) > 7 )
        {
            fputs("\n\n", fp);
            fputs(extra_options, fp);
            fputs("\n", fp);
        }    
        free(extra_options);
    }

    fclose(fp);

    g_free(conf_data);
    free(remote_lines_buffer);
    g_free(openvpn_client_conf);
    g_free(proto);
    g_free(device);
    g_free(auth_line);
    g_free(tls_auth_line);
    g_free(proxy_line);
    g_free(cipher);
    g_free(compression);


    /* Write the sysinit script according to the settings */
    sysinit_start_script = g_strconcat(
    "#!/bin/bash\n",
    "#\n",
    "#\n",
    "# chkconfig: 2345 10 30\n",
    "#\n",
    "# processname: gadmin-openvpn-client\n",
    "# description: This shell script takes care of starting and stopping \\n",
    "# gadmin-openvpn-client on chkconfig-based systems.\n",
    "#\n",
    "### BEGIN INIT INFO\n",
    "# Provides: gadmin-openvpn-client\n",
    "# Required-Start: $network\n",
    "# Required-Stop: $network\n",
    "# Default-Start: 2 3 4 5\n",
    "# Default-Stop: 0 1 6\n",
    "# Short-Description: start and stop gadmin-openvpn-client\n",
    "# Description: GAdmin-OpenVPN-Client starts and stops an OpenVPN client in Tap mode.\n",
    "### END INIT INFO\n",
    "\n",
    start_at_boot_label,
    "\n",
    "case \"$1\" in\n",
    "	start)\n",
    "\n",
    "	", firestarter_stop,
    "\n",
    "	modprobe tun\n",
    "	mkdir -p /var/run/openvpn\n",
    "\n",
    "	", mountcmd,
    "\n",
    "	openvpn --daemon --script-security 2 --writepid /var/run/openvpn/openvpn-client.pid \\\n",
    "	--config ", OPENVPN_SYSCONF_DIR, "/client/", selected_connection, "/gadmin-openvpn-client.conf \\\n",
    "	--cd ", OPENVPN_SYSCONF_DIR, "/client/", selected_connection, "\n",
    "\n",
    "	", firestarter_start,
    "	", non_firestarter_start,
    "	", share_tunnel_with_lan,
    "	;;\n",
    "	stop)\n",
    "\n",
    "	killall -9 openvpn &> /dev/null\n",
    "\n",
    "	# Revert any changes made by the push pull DNS and domain settings.\n",
    "	if [ -e /etc/resolv.conf.gadmin.orig ] &&\n",
    "           grep -q \"nameserver\" /etc/resolv.conf.gadmin.orig ; then\n",
    "	   cat /etc/resolv.conf.gadmin.orig > /etc/resolv.conf\n",
    "	fi\n",
    "\n",
    "	;;\n",
    "	*)\n",
    "	echo \"usage gadmin-openvpn-client {start|stop}\"\n",
    "	exit 1\n",
    "	;;\n",
    "esac\n",
    "\n",
    "exit 0\n",
    "\n",
    NULL);

    g_free(firestarter_start);
    g_free(firestarter_stop);
    g_free(non_firestarter_start);
    g_free(start_at_boot_label);
    g_free(share_tunnel_with_lan);


    /* Put the script with the others as: /etc/init.d/gadmin-openvpn-client  */
    sysinit_script_path = g_strdup_printf("%s/gadmin-openvpn-client", SYSINIT_SCRIPTS_DIR);
    if((fp=fopen(sysinit_script_path, "w+"))==NULL)
    {
        info = g_strdup_printf(_("Can not write openvpn client sysinit script here: \n%s\n"), sysinit_script_path);
        show_info(info);
        g_free(info);
        g_free(sysinit_start_script);
        g_free(sysinit_script_path);
        return;
    }
    fputs(sysinit_start_script, fp);
    fclose(fp);

    g_free(sysinit_start_script);

    /* Chmod the script to 755 */
    cmd = g_strdup_printf("chmod 755 %s", sysinit_script_path);
    if( ! run_command(cmd) )
    {
        printf("Show popup, error chmodding sysinit script.\n");
    }
    g_free(cmd);

    g_free(sysinit_script_path);


    /* Write an upscript */
    upscript_path = g_strdup_printf("%s/client/%s/upscript.sh", OPENVPN_SYSCONF_DIR, selected_connection);
    if((fp=fopen(upscript_path, "w+"))==NULL)
    {
        info = g_strdup_printf(_("Can not write the openvpn client upscript here: \n%s\n"), upscript_path);
        show_info(info);
        g_free(info);
        g_free(upscript_path);
        return;
    }
    upscript = g_strconcat(
    "#!/bin/bash\n",
    "### Copy the clients pulled environment and transfer options\n",
    "### such as domain and nameservers to /etc/resolv.conf.\n",
    "### The changes are reverted when gadmin-openvpn-client is deactivated.\n",
    "\n",
    "env > /etc/gadmin-openvpn-client.env || exit 0\n",
    "\n",
    "### Set new search domain and DNS-addresses first in the conf if any.\n",
    "\n",
    "grep \"dhcp-option DNS\" /etc/gadmin-openvpn-client.env || exit 0\n",
    "cat /etc/resolv.conf > /etc/resolv.conf.gadmin.orig || exit 0\n",
    "echo > /etc/resolv.conf\n",
    "\n",
    "grep \"dhcp-option DOMAIN\" /etc/gadmin-openvpn-client.env | awk '{print \"search \" $3}' >> /etc/resolv.conf ; \\\n",
    "grep \"dhcp-option DNS\"    /etc/gadmin-openvpn-client.env | awk '{print \"nameserver \" $3}' >> /etc/resolv.conf\n",
    "grep \"nameserver\" /etc/resolv.conf.gadmin.orig >> /etc/resolv.conf\n",
    "echo \"GAdmin-OpenVPN-Client: Updated resolv.conf with pushed DNS name servers.\"\n",
    "\n",
    NULL);
    fputs(upscript, fp);
    fclose(fp);
    g_free(upscript);

    /* Chmod the script to 755 */
    cmd = g_strdup_printf("chmod 755 %s", upscript_path);
    if( ! run_command(cmd) )
    {
        printf("Show popup, error chmodding the upscript.\n");
    }
    g_free(cmd);
    g_free(upscript_path);


    /* Populate the client settings */
    populate_connections(widgets);

    populate_client_settings(widgets);

    /* Populate the configuration tab */
    populate_conf_tab(widgets);
}

