/*
 * GProFTPD - A GTK+ frontend for the ProFTPD standalone server.
 * Copyright (C) 2001 - 2006 Magnus Loef (Magnus-swe) <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 2 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., 59 Temple Place, Suite 330, Boston, MA  02111-1307, USA.
 *
 */


#include "../config.h"
#include <gtk/gtk.h>
#include "support.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <time.h>
#include <ctype.h>
#include "widgets.h"
#include "chars_are_digits.h"
#include "allocate.h"
#include "functions.h"
#include "show_info.h"
#include "system_defines.h"
#include "commands.h"

#ifndef _XOPEN_SOURCE
#define _XOPEN_SOURCE
#endif

#if ! defined USE_DARWIN
    #ifndef _CRYPT_H
      #include "crypt.h"
    #endif
#endif


/* Compare strings in lower case */
int cmplowercase(char *buf, char *cmpstring)
{
    char *p, *newbuf;
    int retval = 0;

    if( buf==NULL )
      return retval;

    /* Ignore single newline chars */
    if( strlen(buf) < 2 )
      return retval;

    newbuf = allocate(strlen(buf)+1);
    /* Exists if it cant allocate */
    sprintf(newbuf, "%s", buf);

    for(p = newbuf; *p!='\0'; ++p)
        *p = tolower(*p);

    if( strstr(newbuf, cmpstring) )
      retval = 1;

    free(newbuf);

    return retval;
}


int
user_exists(G_CONST_RETURN gchar *username)
{
    /* Checks if the system user exists */
    FILE *fp;
    long conf_size;
    int x, user_exists = 0;
    char tempname[4096]="";
    char *check_buffer;

    /* Checks if the user exists in passwd */
    if((fp=fopen(GP_PASSWD,"r"))==NULL)
    {
	/* Dont show anything */
    }
    else
      {
	    fseek(fp, 0, SEEK_END);
	    conf_size = ftell(fp);
	    rewind(fp);

	    check_buffer = allocate(conf_size);

	    if( conf_size > 1 )
	    while(fgets(check_buffer, conf_size, fp)!=NULL)
	    {
		for(x=0; check_buffer[x]; x++)
		{
		    if(check_buffer[x]==':')
		    {
			sprintf(tempname, check_buffer);
			tempname[x]='\0';
			if( ! strcmp(username, tempname) )
			{
			    user_exists = 1;
			    break;
			}
		    }
		    if( check_buffer[x]=='\0' || check_buffer[x]=='\n' )
		    break;
		}
	    }
	    free(check_buffer);
      }

    fclose(fp);


    /* Checks if the user exists in shadow */
    if((fp=fopen(GP_SHADOW,"r"))==NULL)
    {
	/* Dont show anything */
    }
    else
      {
	    fseek(fp, 0, SEEK_END);
	    conf_size = ftell(fp);
	    rewind(fp);

	    check_buffer = allocate(conf_size);

	    if( conf_size > 1 )
	    while(fgets(check_buffer, conf_size, fp)!=NULL)
	    {
		for(x=0; check_buffer[x]; x++)
		{
		    if(check_buffer[x]==':')
		    {
			sprintf(tempname, check_buffer);
			tempname[x]='\0';
			if( strstr(username, tempname) 
			&& strlen(username) == strlen(tempname) )
			{
			    user_exists = 1;
			    break;
			}
		    }
		    if( check_buffer[x]=='\0' || check_buffer[x]=='\n' )
		    break;
		}
	    }
	    free(check_buffer);
	    fclose(fp);
      }

    return user_exists;
}


int
group_exists(G_CONST_RETURN gchar *groupname)
{
    /* Checks if the system group already exists */
    FILE *fp;
    long conf_size;
    int x, group_exists=0;
    char tempname[4096]="";
    char *check_buffer;

    /* Checks if the group exists in group */
    if((fp=fopen(GP_GROUP,"r"))==NULL)
    {
	/* Dont show anything  */
    }
    else
      {
	    fseek(fp, 0, SEEK_END);
	    conf_size = ftell(fp);
	    rewind(fp);
	    check_buffer = allocate(conf_size);

	    if( conf_size > 1 )
	    while(fgets(check_buffer, conf_size, fp)!=NULL)
	    {
		for(x=0; check_buffer[x]; x++)
		{
		    if(check_buffer[x]==':')
		    {
			sprintf(tempname, check_buffer);
			tempname[x]='\0';
			if( ! strcmp(groupname, tempname) )
			{
			    group_exists = 1;
			    break;
			}
		    }
		    if( check_buffer[x]=='\0' || check_buffer[x]=='\n' )
		    break;
		}
	    }
	    free(check_buffer);
	    fclose(fp);
      }

    /* Checks if the group exists in gshadow */
    if((fp = fopen(GP_GSHADOW,"r"))==NULL)
    {
	/* Dont show anything */
    }
    else
      {
	    fseek(fp, 0, SEEK_END);
	    conf_size = ftell(fp);
	    rewind(fp);
	    check_buffer = allocate(conf_size);

	    if( conf_size > 1 )
	    while(fgets(check_buffer, conf_size, fp)!=NULL)
	    {
		for(x=0; check_buffer[x]; x++)
		{
		    if(check_buffer[x]==':')
		    {
			sprintf(tempname, check_buffer);
			tempname[x]='\0';
			if( strstr(groupname, tempname) && strlen(groupname)==strlen(tempname) )
			{
			    group_exists = 1;
			    break;
			}
		    }
		    if( check_buffer[x]=='\0' || check_buffer[x]=='\n' )
		    break;
		}
	    }
	    free(check_buffer);
	    fclose(fp);
      }

    return group_exists;
}


gchar *get_user_setting(gchar *user, gchar *what)
{
    /* Gets the a specific users setting from passwd */
    FILE *fp;
    long conf_size;
    int x=0, y=0, found_user=0, found_val=0, count=0;
    char *tempname;
    char *check_buffer;
    gchar *groupnumber;
    gchar *retval = NULL;
    gint val_pos = 0;

    /* This is the group number */                        
    if( strstr(what, "group") )
      val_pos = 3;

    if( strstr(what, "comment") )
      val_pos = 4;

    if( strstr(what, "homedir") )
      val_pos = 5;

    if( strstr(what, "shell") )
      val_pos = 6;

    tempname = allocate(4096);
    if((fp=fopen(GP_PASSWD,"r"))==NULL)
    {
        retval = g_strdup_printf(_("User setting not found"));
	free(tempname);
        return retval;
    }
    fseek(fp, 0, SEEK_END);
    conf_size = ftell(fp);
    rewind(fp);
    check_buffer = allocate(conf_size);

    if( conf_size > 1 )
    while(fgets(check_buffer, conf_size, fp)!=NULL)
    {
        for(x=0; check_buffer[x]; x++)
        {
            if(check_buffer[x]==':')
            {
                snprintf(tempname, 4000, "%s", check_buffer);
                tempname[x]='\0';
                if( ! strcmp(user, tempname) )
                {
                    found_user = 1;
                    break;
                }
            }
            if( check_buffer[x]=='\0' || check_buffer[x]=='\n' )
              break;
        }
        if( found_user )
          break;
    }
    fclose(fp);

    /* If the user is found, get the specified section */
    if( found_user )
    for(x=0; check_buffer[x]; x++)
    {
        if( check_buffer[x]=='\0' || check_buffer[x]=='\n' )
          break;
            
        if(check_buffer[x]==':')
        {
            count++;
            /* The val_pos colon is found, beginning of the value to get */
	    if( count == val_pos )
            {
                snprintf(tempname, 4000, "%s", &check_buffer[x+1]);
                break;
            }
        }
    }
    free(check_buffer);

    /* Snip at value end, shell comes last and should be newline terminated */
    if( found_user )
    for(y=0; tempname[y]; y++)
    {
	if( (tempname[y]==':' && y > 0) || (tempname[y]=='\n' && y > 0) )
	{
            tempname[y]='\0';
            /* Atleast one char in the value and max 350 */
            if( strlen(tempname) < 351 && ! strstr(tempname, ":") )
            {
        	/* Convert the groupnumber to groupname */
		if( strstr(what, "group") )
		{
		   groupnumber = g_strdup_printf("%s", tempname);
		   retval = get_group_name(groupnumber);
		   g_free(groupnumber);
		}
		else
                  retval = g_strdup_printf("%s", tempname);

                found_val = 1;
                break;
            }
        }
    }
    free(tempname);

    /* g_free'd after the return */
    if( found_val )
      return retval;

    retval = g_strdup_printf(_("No value has been set"));
    return retval;
}


gchar *get_group_name(gchar *groupnr)
{
    /* Gets the system group name from the system group number */
    FILE *fp;
    long conf_size;
    int x=0, y=0, found_group_number=0;
    int count=0,  found_group_name=0;
    char *line, *temp;
    gchar *retval = NULL;
    gint val_pos = 0;

    /* position of the group number (name is always first) */
    val_pos = 2;

    temp = allocate(4096);    
    if((fp=fopen(GP_GROUP,"r"))==NULL)
    {
	retval = g_strdup_printf(_("Group file not found"));
	free(temp);
	return retval;
    }
    fseek(fp, 0, SEEK_END);
    conf_size = ftell(fp);
    rewind(fp);

    line = allocate(conf_size+1);

    if( conf_size > 1 )
    while(fgets(line, conf_size, fp)!=NULL)
    {
	count = 0;

	for(x=0; line[x]!='\0'; x++)
	{
	    if( line[x]==':' )
	      count++;
		      
	    if( count == val_pos )
	      break;
	}

	snprintf(temp, 4000, "%s", &line[x+1]);

	/* Snip an extra ":" at the end */			
	for(y=strlen(temp)-1; temp[y]; y--)
	{
	    if( temp[y]==':' )
	    {
	        temp[y]='\0';
		break;
	    }
	}
			
	if( ! strcmp(groupnr, temp) )
	{
	    found_group_number = 1;
	    break;
	}

    }
    fclose(fp);


    count = 0;

    /* Get the name of this group */
    if( found_group_number )
    for(y=strlen(line)-1; line[y]!='\0'; y--)
    {
	if( line[y]==':' && x < 4000 )
	  count++;
	
	if( count == 3 )
	{
	    found_group_name = 1;
	    snprintf(temp, y+1, "%s", line);
	    break;
	}
    }
    free(line);

    /* g_free'd after the return */    
    if( found_group_name )
    {
	retval = g_strdup_printf("%s", temp);
	free(temp);
        return retval;
    }

    free(temp);
    retval = g_strdup_printf(_("Group name not found"));

    return retval;
}


void
password_user(G_CONST_RETURN gchar *username, G_CONST_RETURN gchar *password)
{
    FILE *fp;
    char *user_pass, *encrypted_pass;

    if( ! user_exists(username) )
    {
//	sprintf(info_buffer, _("User: %s could not be found in passwd or shadow.\n"), username);
//	strcat(info_buffer, _("The password was not changed.\n"));
//    	info_window=create_info_window();
//    	gtk_widget_show(info_window);
	return;
    }

    user_pass = allocate(8192);

    /* Crypt returns a pointer to a static buffer do not free it */
    encrypted_pass = encrypt_password(password);

    if( encrypted_pass == NULL )
    {
	/* Using unencrypted passwords */
	printf("Crypt error: using the chpass(wd) program instead\n");

#if defined USE_LINUX
	sprintf(user_pass, "echo %s:%s | chpasswd", username, password);
#endif


#if defined USE_OPENBSD || USE_NETBSD || USE_FREEBSD
	sprintf(user_pass, "echo %s:%s | chpass", username, password);
#endif


#if defined USE_DARWIN
	/* Someone who knows what can be used .. niutil lines ? */
	printf("Darwin functions are defined in osx_functions, this is a bug\n");
	sprintf(user_pass, "echo passwd/username %s:%s", username, password);
#endif

    }
    else
      {
	/* Using encrypted passwords */

#if defined USE_LINUX
	sprintf(user_pass, "usermod -p '%s' %s", encrypted_pass, username);
#endif

#if defined USE_OPENSBD || USE_NETBSD || USE_FREEBSD || USE_AIX || USE_HPUX
	sprintf(user_pass, "pw usermod -p '%s' %s", encrypted_pass, username);
#endif

#if defined USE_DARWIN
	sprintf(user_pass, "echo manually change the password: passwd/username '%s' %s", encrypted_pass, username);
#endif

      }	


    /* Now we have the correct password changing string, change it */
    if((fp=popen(user_pass,"w"))==NULL)
    {
        perror("popen");
//	sprintf(info_buffer, _("Error changing password for user: %s\n"), username);
//    	info_window=create_info_window();
//    	gtk_widget_show(info_window);
    }
    else
      pclose(fp);

#if defined USE_DARWIN
    printf("Send me a mail describing your systems way of changing a users password\n");
    printf("Then i can fix it.\n");
#endif

    free(user_pass);
}


char *encrypt_password(G_CONST_RETURN gchar *password)
{
    /* Make an encrypted password using the MD5 algoritm */
    int i=0, where=0, randlen=8; /* The max MD5 random stringsize is 8 */
    char *rnd_string;
    char salt[13]=""; /* The total salt length is 12 */

    /* 64 chars */
    char *arr[]={"A","B","C","D","E","F","G","H","I","J","K",
		 "L","M","N","O","P","Q","R","S","T","U","V",
		 "W","X","Y","Z","a","b","c","d","e","f","g",
		 "h","i","j","k","l","m","n","o","p","q","r",
		 "s","t","u","v","w","x","y","z","0","1","2",
		 "3","4","5","6","7","8","9",".","/"};
    
    srand((unsigned)time(NULL));

    rnd_string = allocate(9);
    
    while( i < randlen )
    {
	where=rand()%64;
	strcat(rnd_string, arr[where]);
	i++;
    }

#if defined HAVE_CRYPT
    /* For this to work it must have linked with -lcrypt */
    sprintf(salt, "$1$%s$", rnd_string);
#else
    /* We cant use MD5 salting and the salt can only be 2 chars */
    sprintf(salt, "%s", &rnd_string[6]);
#endif

    free(rnd_string);

    return crypt(password, salt);
}


int is_banned(char *user)
{
    /* Is this user banned */
    FILE *fp;
    char *old_buffer, *user_buffer;
    int ret=0, i=0;
    long conf_size;

    if((fp=fopen(GP_FTPUSERS, "r"))==NULL)
    {
	/* if there is no ftpusers the user isnt banned */
        return 0;
    }
    fseek(fp, 0, SEEK_END);
    conf_size=ftell(fp);
    rewind(fp);
    user_buffer = allocate(8192);
    old_buffer = allocate(conf_size);

    if( conf_size > 1 )
    while(fgets(old_buffer, conf_size, fp)!=NULL)
    {
	if( strstr(old_buffer, user) )
	{
	    sscanf(old_buffer, "%s", user_buffer);
	    for(i=0; user_buffer[i]!='\0'; i++)
	    {
		if( user_buffer[i]=='\n' || user_buffer[i]=='\r' )
		  user_buffer[i]='\0';
	    }
	    if( ! strcmp(user_buffer, user) )
	    {
		ret = 1;
		break;
	    }
	}
    }
    free(old_buffer);
    free(user_buffer);
    fclose(fp);

    return ret;
}


void make_dir_chmod(gchar *directory, char perm[128])
{
    gchar *command;
    
    command = g_strdup_printf("mkdir -p %s && chmod %s %s", directory, perm, directory);
    if( ! run_command(command) )
      printf("Error running command: %s\n", command);    

    g_free(command);
}


int
fix_newlines_in_conf()
{
    /* Strip all newlines between directives */
    /* * then add newlines before <Anonymous and <VirtualHost */
    FILE *fp;
    char *old_buffer, *new_buffer;
    long conf_size, allocate_extra=0;

    /* First remove any newlines first on all lines in the config */
    /* And see how many new chars we will be adding */
    if((fp=fopen(PROFTPD_CONF, "r"))==NULL)
    {
       printf("Error reading %s for adding newlines\n", PROFTPD_CONF);
       return 0;
    }
    fseek(fp, 0, SEEK_END);
    conf_size=ftell(fp);
    rewind(fp);

    old_buffer = allocate(conf_size+1024);
    if( old_buffer==NULL )
    {
        printf("Cant allocate enough memory for newlines\n");
        fclose(fp);
	return 0;
    }

    new_buffer = allocate(conf_size+1024);
    if( new_buffer==NULL )
    {
        printf("Cant allocate enough memory for newlines\n");
        fclose(fp);
	free(old_buffer);
	return 0;
    }

    if( conf_size > 1 )
    while(fgets(old_buffer, conf_size, fp)!=NULL)
    {
	if( old_buffer[0]=='\n' || old_buffer[0]=='\r' )
	{
	  /* Dont collect these lines */
	}
	else
	  strcat(new_buffer, old_buffer);	  	  

	if( strstr(old_buffer, "<Anonymous") || strstr(old_buffer, "<VirtualHost") )
	  allocate_extra++;
    }
    fclose(fp);
    free(old_buffer);
    strcat(new_buffer, "\n");

    /* Write the newline stripped conf */
    if((fp=fopen(PROFTPD_CONF, "w+"))==NULL)
    {
       printf("Error reading %s for adding newlines\n", PROFTPD_CONF);
       free(new_buffer);
       return 0;
    }
    fputs(new_buffer, fp);
    fclose(fp);
    free(new_buffer);

    /* Add the newlines */
    if((fp=fopen(PROFTPD_CONF, "r"))==NULL)
    {
       printf("Error reading %s for adding newlines\n", PROFTPD_CONF);
       return 0;
    }
    fseek(fp, 0, SEEK_END);
    conf_size=ftell(fp);
    rewind(fp);

    old_buffer = allocate(conf_size+1024);
    if( old_buffer==NULL )
    {
        printf("Cant allocate enough memory for newlines\n");
        fclose(fp);
	return 0;
    }

    new_buffer = allocate(conf_size+1024+allocate_extra);
    if( new_buffer==NULL )
    {
        printf("Cant allocate enough memory for newlines\n");
        fclose(fp);
	free(old_buffer);
	return 0;
    }

    if( conf_size > 1 )
    while(fgets(old_buffer, conf_size, fp)!=NULL)
    {
	if( strstr(old_buffer, "<Anonymous") || strstr(old_buffer, "<VirtualHost") )
	{
	    strcat(new_buffer, "\n");
	    strcat(new_buffer, old_buffer);
	}
	else
	  strcat(new_buffer, old_buffer);
    }
    fclose(fp);
    free(old_buffer);

    /* Write the newline added conf */
    if((fp=fopen(PROFTPD_CONF, "w+"))==NULL)
    {
       printf("Error reading %s for adding newlines\n", PROFTPD_CONF);
       free(new_buffer);
       return 0;
    }
    fputs(new_buffer, fp);
    fclose(fp);
    free(new_buffer);

    return 1;
}

void randomize_username(struct w *widgets)
{
    int len;
    char *rnd_string;
    gchar *info;
    gchar *utf8=NULL;
    G_CONST_RETURN gchar *default_username_length;

    default_username_length = gtk_entry_get_text(GTK_ENTRY(widgets->server_set_spinbutton[7]));

    if( chars_are_digits((char *)default_username_length) )
    {
	if( strlen((char *)default_username_length) < 4 )
	  len = atoi((char *)default_username_length);
	else
	  {
	     info = g_strdup_printf(_("Max randomize username length is 999\n"));
	     show_info(info);
	     g_free(info);
	     return;
	  }
    }
    else
      {
	 info = g_strdup_printf(_("Randomize username length can only contain digits\n"));
	 show_info(info);
	 g_free(info);
         return;
      }
      
    rnd_string = random_string(len);

    /* Insert the randomized username in the username entry */    
    utf8 = g_locale_to_utf8(rnd_string, strlen(rnd_string), NULL, NULL, NULL);
    gtk_entry_set_text(GTK_ENTRY(widgets->user_set_entry[0]), utf8);

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

    free(rnd_string);
}


void randomize_password(struct w *widgets)
{
    char *rnd_string;
    int len;
    gchar *info;
    gchar *utf8=NULL;
    G_CONST_RETURN gchar *default_password_length;

    default_password_length = gtk_entry_get_text(GTK_ENTRY(widgets->server_set_spinbutton[8]));

    if( chars_are_digits((char *)default_password_length) )
    {
	if( strlen((char *)default_password_length) < 4 )
	  len = atoi((char *)default_password_length);
	else
	  {
	     info = g_strdup_printf(_("Max randomize password length is 999\n"));
	     show_info(info);
	     g_free(info);
	     return;
	  }
    }
    else
      {
	 info = g_strdup_printf(_("Randomize password length can only contain digits\n"));
	 show_info(info);
	 g_free(info);
         return;
      }
      
    rnd_string = random_string(len);

    /* Insert the randomized password in the password entry */    
    utf8 = g_locale_to_utf8(rnd_string, strlen(rnd_string), NULL, NULL, NULL);
    gtk_entry_set_text(GTK_ENTRY(widgets->user_set_entry[1]), utf8);

    if( utf8!=NULL )
      g_free(utf8);
    
    free(rnd_string);
}


char *random_string(int len)
{
    /* Returns a randomized string in upper or lower case 
     * depending on what is selected */
    char *rnd_string;
    gchar *info;
    int upper_case = 0;
    int where = 0;
    int i = 0;

    if( len > 256 )
    {
	info = g_strdup_printf(_("Randomize length too long, changed it to 256.\n"));
	show_info(info);
	g_free(info);
	len = 256;
    }

    /* 256 is the max allowed */
    rnd_string = allocate(300);

    /* Uppercase array 106 chars */
    char *u_arr[]={"A","B","C","D","E","F","G","H","I",
	    	   "J","K","L","M","N","O","P","Q","R",
	           "S","T","U","V","W","X","Y","Z",
    	           "a","b","c","d","e","f","g","h","i",
	           "j","k","l","m","n","o","p","q","r",
	           "s","t","u","v","w","x","y","z",
    	           "1","2","3","4","5","6","7","8","9",
	           "1","2","3","4","5","6","7","8","9",
	           "1","2","3","4","5","6","7","8","9",
	           "1","2","3","4","5","6","7","8","9",
	           "1","2","3","4","5","6","7","8","9",
	           "1","2","3","4","5","6","7","8","9"};

    /* Lowercase array 53 chars */
    char *l_arr[]={"a","b","c","d","e","f","g","h","i",
                   "j","k","l","m","n","o","p","q","r",
	           "s","t","u","v","w","x","y","z",
                   "1","2","3","4","5","6","7","8","9",
                   "1","2","3","4","5","6","7","8","9",
	           "1","2","3","4","5","6","7","8","9"};


    /* Give "deep thought" some time to come up with the number "42" :) */
    usleep(300000);

    /* Make the first random nondigit */
    srand((unsigned)time(NULL));
    while(1)
    {
	if( upper_case )
	{
	    where = rand() % 106;
    	  
	    if( u_arr[where]!="0" && u_arr[where]!="1" && u_arr[where]!="2" && u_arr[where]!="3" && u_arr[where]!="4"
	    &&  u_arr[where]!="5" && u_arr[where]!="6" && u_arr[where]!="7" && u_arr[where]!="8" && u_arr[where]!="9" )
	    {
		strcpy(rnd_string, u_arr[where]);
                break;
	    }
	}
	
	if( ! upper_case )
	{
	    where = rand() % 53;

            if( l_arr[where]!="0" && l_arr[where]!="1" && l_arr[where]!="2" && l_arr[where]!="3" && l_arr[where]!="4"
	    &&  l_arr[where]!="5" && l_arr[where]!="6" && l_arr[where]!="7" && l_arr[where]!="8" && l_arr[where]!="9" )
	    {
		strcpy(rnd_string, l_arr[where]);
    	        break;
	    }
	}
    }

    where = 0;
    i = 1;

    usleep(300000);
    srand((unsigned)time(NULL));

    while( i < len )
    {
	if( upper_case )
	{
	    where = rand() % 106;
       	    strcat(rnd_string, u_arr[where]);
	}
	if( ! upper_case )
	{
	    where = rand() % 53;
       	    strcat(rnd_string, l_arr[where]);
	}
	i++;
    }

    return rnd_string;
}


void
exec_ssl(char *command, char descr[128])
{
    FILE *fp;
    if((fp=popen(command, "r"))==NULL)    
    {
	perror("popen");
	printf("Error description: %s\n", descr);
	printf("Error command: %s\n", command);
	return;
    }
    pclose(fp);
}


syntax highlighted by Code2HTML, v. 0.9.1