/*
 *  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 Library 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 "util.h"

#ifndef TRUE
#define TRUE 0
#endif

#ifndef FALSE
#define FALSE 1
#endif

#ifndef PASSWD_FILE
#define PASSWD_FILE "/etc/mypasswd"
#endif

int str2int(const char * string) {
/* -----------------------------------------------------------------------------
 * Convert a string to int 
 *
 * @param  const char *, the given string
 * @return int   -1 if the given string do not represent an integer
 * -------------------------------------------------------------------------- */

  int     result = 0;
  int     int_tmp;
  const char * pts = string;

  while (*pts != '\0') {
    int_tmp = *pts - 48;
    if((int_tmp >= 0) && (int_tmp <= 9)) {
      result = 10*result + int_tmp;
    }
    else if (*pts != ' ') {
      return -1;
    }
    pts++;
  }

  return result;

}

char * substring(const char * src, int start, int length) {
/* -----------------------------------------------------------------------------
 * get a substring in a string
 *
 * @param  const char *, source string
 * @param  int, the offset
 * @param  int, the length
 * @return char *, result in a dynamically allocated memory
 *   so the result must be free()
 * -------------------------------------------------------------------------- */

  char *result = (char *)malloc(sizeof(char) * length + 1);

  if (result == NULL) {
    logmsg(LOG_ERR, "substring() : %s", strerror(errno));
    return NULL;
  }

  memcpy(result, &src[start], length);
  result[length] = '\0';
  return result;

}

char * str_replace(const char * strfrom, const char * strby, const char * strin) {
/* -----------------------------------------------------------------------------
 * Replace a string by another string in a string
 *
 * @param  const char *, string to replace
 * @param  const char *, string replacement
 * @param  const char *, source string
 * @return char *, result in a dynamically allocated memory
 *   so the result must be free()
 * -------------------------------------------------------------------------- */

  char *result = NULL, *tmp, *pos;
  char *p = (char *)strin;
  size_t len_from, len_by, len, total_len = 0;

  len_from = strlen(strfrom);
  len_by = strlen(strby);

  while ((pos = strstr(p, strfrom)) != NULL) {
    /* Compute the new length */
    len = (pos - p) + len_by;
    tmp = realloc(result, (total_len + len) * sizeof(char) + 1);
    if (tmp == NULL) {
      logmsg(LOG_ERR, "str_replace() : %s", strerror(errno));
      return NULL;
    }
    result = tmp;

    memcpy(&result[total_len], p, sizeof(char) * (pos - p));
    memcpy(&result[total_len + (pos - p)], strby, sizeof(char) * len_by);

    total_len += len;
    p = pos + len_from;
  }
  if (*p) {
    len = strlen(p);
    tmp = realloc(result, (total_len + len) * sizeof(char) + 1);
    if (tmp == NULL) {
      logmsg(LOG_ERR, "str_replace() : %s", strerror(errno));
      return NULL;
    }
    result = tmp;
    memcpy(&result[total_len], p, sizeof(char) * len);
    total_len += len;
  }
  result[total_len] = '\0';

  if (total_len > 0)
    return result;
  return strdup(strin);
}

char * trim(const char * strin) {
/* -----------------------------------------------------------------------------
 * Trim in the given string
 *
 * @param  const char *
 * @return char *, result in a dynamically allocated memory
 *   so the result must be free()
 * -------------------------------------------------------------------------- */
  char * result = NULL;
  char *pts_start, *pts_end;
  unsigned int left = 0;
  unsigned int right = 0;
  size_t size = strlen(strin);
  const char delimiters[] = " \t\n\r";

  if (size <= 0)
    return NULL;

  pts_start = (char *)strin;
  pts_end = (char *)&strin[size - 1];

  /* Left trim */
  while((*pts_start != '\0') && ((strchr(delimiters, (int)*pts_start)) != NULL)) {
    left++;
    pts_start++;
  }
  /* Right trim */
  while((pts_end != strin) && ((strchr(delimiters, (int)*pts_end)) != NULL)) {
    right++;
    pts_end--;
  }

  result = (char *)malloc((size - left - right) * sizeof(char) + 1);
  if (result == NULL) {
    logmsg(LOG_ERR, "trim() : %s", strerror(errno));
    return NULL;
  }

  memcpy(result, (void *)&strin[left], (size - left - right) * sizeof(char));
  result[size - left - right] = '\0';
  return result;
}

char * stripcrlf(char * str) {
/* -----------------------------------------------------------------------------
 * Strip CRLR in the given string
 *
 * @param  char *
 * @return char *
 * -------------------------------------------------------------------------- */
  char *pts = str + strlen(str);

  while(pts - str >= 0) {
    if ((*pts == 10) || (*pts == 13))
      *pts = '\0';
    pts--;
  }

  return pts;

}

char * str2upper(const char * strin) {
/* -----------------------------------------------------------------------------
 * Upper case all character in the given string
 *
 * @param  const char *
 * @return char *, result in a dynamically allocated memory
 *   so the result must be free()
 * -------------------------------------------------------------------------- */

  char * result = NULL, * pts;
  result = strdup(strin);
  if (result == NULL) {
    logmsg(LOG_ERR, "str2upper() : strdup error");
    return NULL;
  }
  for (pts = result; *pts; pts++) {
    if ((*pts >= 97)
    && (*pts <= 122))
      *pts -= 32;
  }
  
  return result;
}

char * str2lower(const char * strin) {
/* -----------------------------------------------------------------------------
 * Lower case all character in the given string
 *
 * @param  const char *
 * @return char *, result in a dynamically allocated memory
 *   so the result must be free()
 * -------------------------------------------------------------------------- */

  char * result = NULL, * pts;
  result = strdup(strin);
  if (result == NULL) {
    logmsg(LOG_ERR, "str2upper() : strdup error");
    return NULL;
  }
  for (pts = result; *pts; pts++) {
    if ((*pts >= 65)
    && (*pts <= 90))
      *pts += 32;
  }
  
  return result;
}

char * getlocaltime() {
/* -----------------------------------------------------------------------------
 * Get local datetime in YYY-MM-DD hh:mm:ss format
 *
 * @return char *, result in a statically allocated memory
 * -------------------------------------------------------------------------- */

  static char strtime[20];
  time_t timer = time(NULL);
  struct tm now = *localtime(&timer);

  snprintf(strtime, sizeof(strtime), "%4d-%02d-%02d %02d:%02d:%02d",
          now.tm_year + 1900, now.tm_mon, now.tm_mday,
          now.tm_hour, now.tm_min, now.tm_sec);

  return strtime;

}

char * getdate() {
/* -----------------------------------------------------------------------------
 * Get date in YYYY-MM-DD format
 *
 * @param  int
 * @return char *, result in a statically allocated memory
 * -------------------------------------------------------------------------- */

  static char strtime[11];
  time_t timer = time(NULL);
  struct tm now = *localtime(&timer);

  snprintf(strtime, sizeof(strtime), "%4d-%02d-%02d",
          now.tm_year+1900, now.tm_mon+1, now.tm_mday);

  return strtime;

}

char * gettime() {
/* -----------------------------------------------------------------------------
 * Get time
 *
 * @return char *, result in a statically allocated memory
 * -------------------------------------------------------------------------- */

  static char strtime[11];
  time_t timer = time(NULL);
  struct tm now = *localtime(&timer);

  snprintf(strtime, sizeof(strtime), "%02d:%02d:%02d",
          now.tm_hour, now.tm_min, now.tm_sec);

  return strtime;

}


char * formatdate(int secondes) {
/* -----------------------------------------------------------------------------
 * Format second to date
 *
 * @param  int
 * @return char *, result in a statically allocated memory
 * -------------------------------------------------------------------------- */

  int jour, heure, minute, seconde;
  static char strtime[20];

  jour = secondes / 86400;
  heure = (secondes  - (jour * 86400)) / 3600;
  minute = (secondes - (jour * 86400) - (heure * 3600)) / 60;
  seconde = secondes - (jour * 86400) - (heure * 3600) - (minute * 60);

  snprintf(strtime, sizeof(strtime), "%dj %02dh%02dm%02ds", jour, heure, minute, seconde);

  return strtime;

}

char * addslashes(char * str_in) {
/* -----------------------------------------------------------------------------
 * Addslashes before characters such as ', `, "
 *
 * @param  const char *
 * @return char *, result in a dynamically allocated memory
 *   so the result must be free()
 * -------------------------------------------------------------------------- */

  char *result, *result_realloc, *result_tmp;
  char * pts = str_in;
  int len = strlen(str_in)+1;
  result = (char *)malloc(len);

  if (result == NULL) {
    logmsg(LOG_ERR, "addslashes : malloc error");
    return NULL;
  }

  memset(result, 0, len);

  result_tmp = result;
  /* printf("%s %d %d\n", pts, len, sizeof(char)); */

  while(*pts != '\0') {
    
    switch((int)*pts) {
      case 39: /* ' */
      case 34: /* " */
      case 96: /* ` */
        len++;
        result_realloc = (char *)realloc(result, len);
        if (result_realloc == NULL) {
          logmsg(LOG_ERR, "addslashes : realloc error");
          free(result);
          return NULL;
        }
        result = result_realloc;

        *(result+len-1) = '\0';
        *result_tmp = (char)92;
        result_tmp++;
        break;
    }
    *result_tmp = *pts;
    pts++;
    result_tmp++;
  }
  *result_tmp = '\0';
  /* printf("%s\n", result);
  printf("%s\n", result_tmp);
  printf("len %d, %d, %d, %d\n", len, result_tmp-result, strlen(result), strlen(result_tmp)); */

  return result;

}

#ifdef USE_CRYPT
char * md5(const char * pwd) {
/* -----------------------------------------------------------------------------
 * Crypt a string in a md5 crypt manner
 *
 * @param  const char *, the string to crypt
 * @return char *, the crypt result in a static memory
 * -------------------------------------------------------------------------- */

  char salt[3];
  char des_salt[12];
  char *tmp = NULL;
  memset(&salt, 0, 3);
  memset(&des_salt, 0, 12);

  if (strlen(pwd) < 2) {
    return NULL;
  }
  snprintf(salt, sizeof(salt), "%c%c", *pwd, *(pwd+1));
  tmp = crypt(pwd, salt);
  if (tmp != NULL && strlen(tmp) > 2) {
    snprintf(des_salt, sizeof(des_salt), "$1$%s", tmp + 2);
    des_salt[12] = '\0';
    return (char *)crypt(pwd, des_salt);
  }
  return NULL;
}
#endif

void vsysdaemonlog(const char *pgm, const char * filename, const char * line, va_list ap) {
/* -----------------------------------------------------------------------------
 * Custom log system to a file
 *
 * @param  const char *, program name
 * @param  const char *, file name
 * @param  const char *, printf format
 * @param  va_list, arguments list
 * -------------------------------------------------------------------------- */

  int pid;
  char *msg = NULL, *logline = NULL, *date = NULL, *time = NULL;
  FILE *fd = NULL;

  vasprintf(&msg, line, ap);

  date = getdate();
  time = gettime();
  pid = getpid();

  logline = xstrdup("%s %s %s[%d]: %s", date, time, pgm, pid, msg);
  free(msg);
  msg = NULL;
  if (logline == NULL)
    logmsg(LOG_ERR, "%s at vsysdaemonlog() : Error on xstrdup", pgm);

  fd = fopen(filename, "a");
  if (fd != NULL) {
    
    if (!fwrite((void *)logline, 1, strlen(logline), fd)) {
      logmsg(LOG_ERR, "%s at vsysdaemonlog() : Log failed on %s", pgm, filename);
    }
  }
  else {
    logmsg(LOG_ERR, "%s at vsysdaemonlog() : Open Log file failed on %s", pgm, filename);
  }
  free(logline);
  fclose(fd);

}

void sysdaemonlog(const char *pgm, const char * filename, const char * line, ...) {
/* -----------------------------------------------------------------------------
 * Custom log system to a file
 *
 * @param  const char *, program name
 * @param  const char *, file name
 * @param  const char *, printf format
 * -------------------------------------------------------------------------- */
  va_list args;
  va_start(args, line);
  vsysdaemonlog(pgm, filename, line, args);
  va_end(args);  
}
  
char * xstrdup(const char * str, ...) {
/* -----------------------------------------------------------------------------
 * Concat strings in a newly allocated memory
 *
 * @param  const char *, printf format
 * @return char *, result in a dynamically allocated memory
 *   so the result must be free()
 * -------------------------------------------------------------------------- */
  va_list ap;
  char *result = NULL;
  va_start(ap, str);
  vasprintf(&result, str, ap);
  va_end(ap);
  return result;
}

int getuidbyname(const char *login) {
/* -----------------------------------------------------------------------------
 * Get the uid number by name
 *
 * @param  const char *, login name
 * @return int or -1 if login is not found
 * -------------------------------------------------------------------------- */
  struct passwd * usrinfo;
  usrinfo = getpwnam(login);
  
  if (usrinfo == NULL) {
    logmsg(LOG_ERR, "getuidbyname() : no such user %s", login);
    return -1;
  }
  return usrinfo->pw_uid;
}

int getgidbyname(const char *group) {
/* -----------------------------------------------------------------------------
 * Get the gid number by name
 *
 * @param  const char *, group name
 * @return int or -1 if group is not found
 * -------------------------------------------------------------------------- */
  struct group * grpinfo;
  grpinfo = getgrnam(group);
  
  if (grpinfo == NULL) {
    logmsg(LOG_ERR, "getgidbyname() : no such group %s", group);
    return -1;
  }
  return grpinfo->gr_gid;
}

char *get_homedir() {
/* -----------------------------------------------------------------------------
 * Get home path
 *
 * @return char *, path in a dynamically allocated memory
 *   so the result must be free()
 * -------------------------------------------------------------------------- */
  char *path = NULL;
  struct passwd * usrinfo;
  usrinfo = getpwuid(getuid());
  
  if ((path = strdup((const char *)usrinfo->pw_dir)) == NULL) {
    logmsg(LOG_ERR, "get_homedir() : strdup error");
  }
  return path;
}
  
char *get_currentdir() {
/* -----------------------------------------------------------------------------
 * Get current path
 *
 * @return char *, path in a dynamically allocated memory
 *   so the result must be free()
 * -------------------------------------------------------------------------- */
  char * path = NULL;
  char * path_tmp = NULL;
  int size = 16;
  
  for(;;) {
    if ((path_tmp = (char *)realloc(path, size)) == NULL) {
      logmsg(LOG_ERR, "get_currentdir() : realloc error");
      break;
    }
    path = path_tmp;
    if (getcwd(path, size) != NULL) {
      break;
    }
    if (errno != ERANGE) {
      break;
    }
    size *= 2;
  }
  return path;
  
}

char * get_dir_cdup(const char *path) {
/* -----------------------------------------------------------------------------
 * Get parent path
 *
 * @param  const char *, directory
 * @return char *, path in a dynamically allocated memory
 *   so the result must be free()
 * -------------------------------------------------------------------------- */
  unsigned int i = 0;
  char *result = NULL;
  unsigned int last_i = strlen(path) - 1;
  
  result = strdup(path);
  if (result == NULL)
    return NULL;
  for (i = last_i; (i >= 0) && (*(result+i) != '/'); i--) {
    *(result+i) = '\0';
  }
  if ((*(result+i) == '/') && (i > 0))
    *(result+i) = '\0';
  return result;
}

unsigned int fexist(const char *path, char type) {
/* -----------------------------------------------------------------------------
 * Check if file exists
 *
 * @param  const char *, port number or name service
 * @param  char, 'd' for a directory, 'f' for a file
 * @return int
 * -------------------------------------------------------------------------- */
  struct stat s;
  int status;
  status = stat (path, &s);
  switch(type) {
  case 'd':
    if (status == 0 && S_ISDIR (s.st_mode))
      return s.st_size;
    break;
  case 'f':
    if (status == 0 && S_ISREG (s.st_mode))
      return s.st_size;
    break;
  }
  return 0;
}

char * file_exists (const char *directory, const char *filename) {
/* -----------------------------------------------------------------------------
 * Check if file exists in a directory
 *
 * @param  const char *, directory
 * @param  const char *, file name
 * @return char *, the full path in a dynamically allocated memory
 *   so the result must be free()
 * -------------------------------------------------------------------------- */
  
  char *full_filename = NULL;
  struct stat s;
  int status;
  size_t len = strlen(directory) + 1 + strlen(filename) + 1;

  full_filename = (char *) malloc(sizeof(char) * len);
  if (full_filename == NULL) {
    logmsg(LOG_ERR, "file_exists() : malloc error");
    return NULL;
  }

  strlcpy(full_filename, directory, sizeof(char) * len);
  strlcat(full_filename, "/", sizeof(char) * len);
  strlcat(full_filename, filename, sizeof(char) * len);

  status = stat (full_filename, &s);
  if (status == 0 && S_ISREG (s.st_mode))
    return full_filename;
  free (full_filename);
  return NULL;
}

int init_perl_script(const char *path, int pipes[2]) {
/* -----------------------------------------------------------------------------
 * Init a perl script with the associated pipe descriptor to write and read
 *
 * @param  const char *, perl script path
 * @param  int[2], that will contains 2 descriptors
 * @return int, 1 for parent process
 * -------------------------------------------------------------------------- */
  
  int tube1[2];
  int tube2[2];
  char *argv[3];
  int i;
    
  if ((pipe(tube1) != 0) || (pipe(tube2) != 0))
    return 0;
   
  switch(fork()) {
  case -1: /* Erreur fork */
    close(tube1[0]);
    close(tube1[1]);
    close(tube2[0]);
    close(tube2[1]);
    exit(-1);
    break;
  case 0 : /* Processus enfant */
    signal(SIGHUP, SIG_IGN);
  
    close(tube1[1]);  /* Fermeture tube1 entrée ECRITURE  */
    close(tube2[0]);  /* Fermeture tube2 sortie LECTURE */
    dup2(tube1[0], STDIN_FILENO);
    close(tube1[0]);
    dup2(tube2[1], STDOUT_FILENO);
    close(tube2[1]);
  
    /* On ferme tous les descripteurs sauf STDOUT et STDIN */
    for(i = 2; i < OPEN_MAX; i++)
      close(i);
    
    argv[0] = "/usr/bin/perl";
    argv[1] = (char *)path;
    argv[2] = NULL;
  
    execv("/usr/bin/perl", argv);
    return 0;
    break;
  default :
  /* Processus père lisant dans la socket */    
    close(tube1[0]);  /* Fermeture tube1 sortie LECTURE */
    close(tube2[1]);  /* Fermeture tube2 entrée ECRITURE */
    /*tubes[0] = tube2[0];*/  /* Tube de lecture */
    /*tubes[1] = tube1[1];*/  /* Tube d'écriture */
    
    pipes[1] = tube1[1];
    pipes[0] = tube2[0];
    
    signal(SIGCHLD, SIG_IGN);
    break;
  }
  
  return 1;
}

int process_daemon() {
/* -----------------------------------------------------------------------------
 * Daemonize a process
 
 * @return int, 1 for parent process, 0 for child process
 * -------------------------------------------------------------------------- */
  
  int i = 0;
  /* Processus Démon */
  switch (fork ()) {
  case -1: /* Erreur fork */
    logmsg(LOG_ERR, "process_daemon() : %s (%d) : Fork Error", strerror(errno), errno);

    return errno;
    break;
  case 0: /* Processus enfant = démon: */

    chdir("/");
    setsid();
    /* Fermeture de tous les descripteurs */
    for (i = 0; i < _POSIX_OPEN_MAX; i++)
      close(i);
    break;
  default: /* Processus Parent */
    return 1;
  }
  
  return 0;

}


syntax highlighted by Code2HTML, v. 0.9.1