/* GADMIN-PROFTPD - An easy to use GTK+ frontend for the ProFTPD standalone server.
 * Copyright (C) 2001 - 2008 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 <string.h>
#include "widgets.h"
#include "gettext.h"
#include "functions.h"
#include "reread_conf.h"
#include "show_info.h"
#include "apply_user.h"
#include "allocate.h"
#include "populate_users.h"
#include "populate_user_settings.h"
#include "populate_conf_tab.h"

#include "dir_treeview_funcs.h"

extern char global_server_address[1024];
extern char global_server_port[1024];
extern char global_server_type[1024];

extern int activated;

extern int use_ratio;
extern int use_quota;

/* Temporary for option deprecations */
extern char global_version[1024];

/* The current directory beeing added and limited */
//gchar *dir; // ???
extern gchar *homedir;

/* The 18 checkbox values */
gchar *dir_val[19]; // ???

char *user_profile; // ???

extern long num_rows;
extern int row_pos;


/* Fixme mod: group, comment and shell */
void apply_user(struct w *widgets)
{
    /* Change the selected users configuration. */
    /* First delete the user from the conf then add it */
    FILE *fp;
    long conf_size;
    int password_length = 0;
    gchar *info;
    char *old_buffer, *new_buffer, *config, *address_buffer, *port_buffer;
    long profile_size = 0;
    int user_changed = 0;
    int found = 0;
    gchar *UserUsername;
    char *temp_user;

    G_CONST_RETURN gchar *username;
    G_CONST_RETURN gchar *groupname;
    G_CONST_RETURN gchar *comment;
    G_CONST_RETURN gchar *password;
    G_CONST_RETURN gchar *login_from;
    G_CONST_RETURN gchar *max_logins;
    G_CONST_RETURN gchar *br=NULL, *brc=NULL, *fr=NULL, *frc=NULL;

    /* Get the settings from the entries */
    username = gtk_entry_get_text(GTK_ENTRY(widgets->user_set_entry[0]));
    password = gtk_entry_get_text(GTK_ENTRY(widgets->user_set_entry[1]));
    groupname = gtk_entry_get_text(GTK_ENTRY(widgets->user_set_entry[2]));
    comment = gtk_entry_get_text(GTK_ENTRY(widgets->user_set_entry[3]));
    login_from = gtk_entry_get_text(GTK_ENTRY(widgets->user_set_entry[5]));
    max_logins = gtk_entry_get_text(GTK_ENTRY(widgets->user_set_spinbutton[0]));

    /* Ratios */
    if( use_ratio )
    {
	br  = gtk_entry_get_text(GTK_ENTRY(widgets->user_set_spinbutton[1]));
	brc = gtk_entry_get_text(GTK_ENTRY(widgets->user_set_spinbutton[2]));
	fr  = gtk_entry_get_text(GTK_ENTRY(widgets->user_set_spinbutton[3]));
	frc = gtk_entry_get_text(GTK_ENTRY(widgets->user_set_spinbutton[4]));
    }


    if( password!=NULL )
      password_length = strlen(password);

    /* If the user has written a password thats less then MIN_PASS_LEN chars long */
    if( password_length > 0 && password_length < MIN_PASS_LEN )
    {
        info = g_strdup_printf(_("The minimum password length is %d.\n"), MIN_PASS_LEN);
	show_info(info);
	g_free(info);
        return;
    }


    /* Set global num_rows */
    num_rows = 0;
    gtk_tree_model_foreach(GTK_TREE_MODEL(widgets->directory_store), (GtkTreeModelForeachFunc) num_rows_func, widgets);

    /* There must be atleast one directory */
    if( num_rows < 1 )
    {
	info = g_strdup_printf(_("Missing ftp home directory. Scroll down and add one first.\n"));
	show_info(info);
	g_free(info);
	return;    
    }

    /* (Global char) Statics + entries + number of rows (dirlen + APPE STOR STOU etc) */
    profile_size = 16384 + 1400 + (num_rows * 16384);
    /* Allocate the user profile */
    user_profile = allocate(profile_size);


    /* Set the users home dir and its values globally */
    row_pos = 0; /* Only get the home directory */
    gtk_tree_model_foreach(GTK_TREE_MODEL(widgets->directory_store), (GtkTreeModelForeachFunc) dirs_foreach, widgets);

    /* Create the user profile... */

    /* Home directory */
    snprintf(user_profile, 16384, "\n<Anonymous %s>\n", homedir);




    /* Username */    
    strcat(user_profile, "User ");
    strcat(user_profile, username);
    strcat(user_profile, "\n");

    /* Groupname */
    strcat(user_profile, "Group ");
    strcat(user_profile, groupname);
    strcat(user_profile, "\n");

    /* Require password */
    if( ! gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widgets->user_set_checkbutton[1])) )
      strcat(user_profile, "AnonRequirePassword off\n");
    else
      strcat(user_profile, "AnonRequirePassword on\n");

    /* Maximum logins */
    strcat(user_profile, "MaxClients ");
    strcat(user_profile, max_logins);
    strcat(user_profile, " \"");
    strcat(user_profile, "The server is full, hosting %m users");
    strcat(user_profile, "\"\n");

    /* Static Welcome and chdir msgs */
    strcat(user_profile, "DisplayLogin welcome.msg\n");

//  Fedora backported all but this!
//    if( strstr(global_version, "1.2.") || strstr(global_version, "1.3.0") ) 
//      strcat(user_profile, "DisplayFirstChdir .msg\n");
//    else
//      strcat(user_profile, "DisplayChdir .msg\n");

    /* Ratio Module (reversed br/fr order in the gui) */
    if( use_ratio )
    {
	strcat(user_profile, "UserRatio ");
	strcat(user_profile, username);
	strcat(user_profile, " ");
	strcat(user_profile, fr);
	strcat(user_profile, " ");
	strcat(user_profile, frc);
	strcat(user_profile, " ");
	strcat(user_profile, br);
	strcat(user_profile, " ");
	strcat(user_profile, brc);
	strcat(user_profile, "\n");
    }

    /* Logins from, if nothing is specified we allow everything */
    if( login_from == NULL || strlen(login_from) < 3 )
    {
	strcat(user_profile, "<Limit LOGIN>\n");
	strcat(user_profile, "Allow from all\nDeny from all\n");
	strcat(user_profile, "</Limit>\n");
    }
    else
      {
	 strcat(user_profile, "<Limit LOGIN>\n");
	 strcat(user_profile, "Allow from ");
	 strcat(user_profile, login_from);
	 strcat(user_profile, "\nDeny from all\n");
	 strcat(user_profile, "</Limit>\n");
      }


    /* Append the Limit CMDs for the home directory */
    append_limit_cmds();

    /* Append all other directories to the user profile */
    row_pos = 1; 
    gtk_tree_model_foreach(GTK_TREE_MODEL(widgets->directory_store), (GtkTreeModelForeachFunc) dirs_foreach, widgets);
    

    /* If not checked, dont show this user in the statistics (picked up by gprostats) */
    if( ! gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widgets->user_set_checkbutton[2])) )
      strcat(user_profile, "#gplockstats\n");

    /* Profile end */
    strcat(user_profile, "</Anonymous>\n");

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

    /* We have the new profile, insert it where the old user was located in the selected server */
    UserUsername = g_strdup_printf("User %s\n", username);

    address_buffer = allocate(8192+15);
    port_buffer = allocate(8192+3);               

    if( strstr((char *)global_server_type, "Virtualhost") )
       sprintf(address_buffer, "<VirtualHost %s>\n", global_server_address);
    else
       sprintf(address_buffer, global_server_address);
     
    sprintf(port_buffer, "Port %s\n", global_server_port);


    /* Make changes for this users settings */
    if((fp=fopen(PROFTPD_CONF, "r"))==NULL)
    {
	free(address_buffer); free(port_buffer);
        return;
    }
    fseek(fp, 0, SEEK_END);
    conf_size = ftell(fp);
    rewind(fp);

    old_buffer = allocate(conf_size+3);
    config = allocate(conf_size+profile_size+3);


    /* If the selected server is a vhost we collect everything up to
       the first vhost with the same name as the selected one */
    if( strstr((char *)global_server_type, "Virtualhost") )
    {
	if( conf_size > 1 )
	while(fgets(old_buffer, conf_size, fp)!=NULL)
	{
	    strcat(config, old_buffer);
	    
	    /* If its the correct address */
	    if( strcmp(old_buffer, address_buffer) == 0 )
	    {
	       while(fgets(old_buffer, conf_size, fp)!=NULL)
	       {
		  strcat(config, old_buffer);
		 
		  /* This server was not the right one */
		  if( strstr(old_buffer, "</VirtualHost>") )
		    break;
		 
		  if( strcmp(old_buffer, port_buffer) == 0 )
		  {
		     found = 1;
	             break;
	          }
	       }
	    }
	    if( found )
	      break;
	}
    }


    /* We have scrolled to the correct VirtualHost or its the default server */

    new_buffer = allocate(8192);

    /* Change the selected users settings */
    if( conf_size > 1 )
    while(fgets(old_buffer, conf_size, fp)!=NULL)
    {
	if( strstr(old_buffer, "<Anonymous ") )
	{
	    /* Save this directory incase its not the correct user */
	    strcat(new_buffer, old_buffer);

	    while(fgets(old_buffer, conf_size, fp)!=NULL)
	    {
		/* This is the correct user in the correct server */
        	if( strstr(old_buffer, UserUsername) 
		&& ! strstr(old_buffer, "AllowUser") 
		&& ! strstr(old_buffer, "DirFakeUser") && ! user_changed )
        	{
		    /* The new profile is added */
		    strcat(config, user_profile);
		    new_buffer[0]='\0';
		    user_changed = 1;

		    /* The old profile is deleted */
		    while(fgets(old_buffer, conf_size, fp)!=NULL)
		    {
			if( strstr(old_buffer, "</Anonymous") )
			  break;

			/* Some more safety breaks */
			if( strstr(old_buffer, "<Anonymous") )
			  break;

			if( strstr(old_buffer, "</VirutalHost") )
			  break;

			if( strstr(old_buffer, "<VirutalHost") )
			  break;
		    }
		}
		else
		  {
		     if( strlen(new_buffer) > 0 )
		     {
		        strcat(config, new_buffer);
		        new_buffer[0]='\0';
		     }
		     strcat(config, old_buffer);
		     break;
		  }
	    }
	}
	else
	  strcat(config, old_buffer);
    }
    free(old_buffer);
    free(new_buffer);
    g_free(UserUsername);
    fclose(fp);


    free(address_buffer); free(port_buffer);
    free(user_profile);


    if( ! user_changed )
    {
	info = g_strdup_printf(_("Error: user not found, couldnt change its settings.\n"));
	show_info(info);
	g_free(info);
	free(config);
        return;
    }


    /* Write the new config with the changed users settings */
    if((fp=fopen(PROFTPD_CONF, "w+"))==NULL) 
    {
	free(config);
        return;
    }
    fputs(config, fp);
    fclose(fp);
    free(config);



    /* Ban or unban the user in ftpusers depending on the selection */
    if( gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widgets->user_set_checkbutton[0])) ) 
    {
	/* Ban the user */
	if( ! is_banned((char *)username) )
	{
	    if((fp=fopen(GP_FTPUSERS, "a"))==NULL) 
	    {
	    }
	    else
	      {
		 fputs("\n", fp);
		 fputs(username, fp);
		 fputs("\n", fp);
		 fclose(fp);
	      }
	}
    }
    else
      {
         /* Remove the user from ftpusers if its there */
         if( is_banned((char *)username) )
	 {
	    if((fp=fopen(GP_FTPUSERS, "r"))==NULL) 
	    {
	    }
	    else
	      {
	         fseek(fp, 0, SEEK_END);
	         conf_size = ftell(fp);
	         rewind(fp);
		 
	         config = allocate(conf_size+4096);        
	         old_buffer = allocate(conf_size+4096);        
		 temp_user = allocate(8192);
		 
		 if( conf_size > 1 )
		 while(fgets(old_buffer, conf_size, fp)!=NULL)
		 {
		    sscanf(old_buffer, "%s", temp_user);
		    if( strcmp(temp_user, username) == 0 )
		    {
			/* Remove it */
		    }
		    else
	    	      strcat(config, old_buffer);
		 }			
		 fclose(fp);
		 free(old_buffer);
		 free(temp_user);

		 if((fp=fopen(GP_FTPUSERS, "w+"))==NULL) 
		 {
		 }
		 else
	           {
		      fputs(config, fp);
		      fclose(fp);
		   }
		 free(config);
	      }
	 }
    }



    /* Change the users password if its >= MIN_PASS_LEN */
    if( password_length >= MIN_PASS_LEN )
    {

	/* Virtual users */
	if( gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widgets->server_set_check_virtual)) )
	{
	    /* Change the virtual users password */
	    if( user_exists(username) )
	    {
		password_virtual_user(username, password);
	    }
	    else
	      printf("Virtual user doesnt exist: %s\n", username);
	}
	else  /* System users */
	{
#ifndef USE_DARWIN
	    if( user_exists(username) )
#elif USE_DARWIN
	    if( niutil_user_exists(username) )
#endif
	    {
#ifndef USE_DARWIN
		password_user(username, password);
#elif USE_DARWIN
		niutil_password_user(username, password);
#endif
    		info = g_strdup_printf(_("\nThe Password was changed.\n"));
    		show_info(info);
    		g_free(info);
	    }
	    else
	    {
		info = g_strdup_printf(_("The password was not changed.\nThe user didnt exist in shadow or passwd.\n"));
    		show_info(info);
    		g_free(info);
	    }
	}
    }


    fix_newlines_in_conf();

    /* Update the userlist */
    populate_users(widgets);

    /* Populate the user settings (it also populates the directories) */
    populate_user_settings(widgets);

    /* Populate the conf tab */    
    populate_conf_tab(widgets);
    
    /* Update the server */
    reread_conf(widgets);
}
