/* Asp Address Search Protocol Client (file: asplib.c)                     */
/* Copyright (C) 1996-2001 Stenio Brunetta                                 */
/*                                                                         */
/*  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., 675 Mass Ave, Cambridge, MA 02139, USA.              */
/*                                                                         */
/*  Author's email address: stenio@brunettaeperin.it                       */

static char rcsid[] = "$Id: asplib.c,v 1.16 2001/01/23 11:20:01 ste Exp $";

#include "asp.h"

void avoid_asplib_rcsid_warning(void){
  rcsid[0] = 0;
}

#ifndef HAVE_GETHOSTNAME
#   ifdef HAVE_UNAME
int gethostname(char* name, size_t len){
  struct utsname buf;

  if(uname(&buf) == -1) return -1;

  strncpy(name, buf.nodename, len);
  return 0;
}
#   else
int gethostname(char* name, size_t len){
  if((name = getenv("HOSTNAME")) == NULL || \
     strcmp(name, "") == 0) return -1;
  return 0;
}
#   endif
#endif

#ifndef HAVE_STRERROR
#   ifdef HAVE_SYS_ERRLIST_DECL
char* strerror(int errnum){
  static char message[32];
  extern char *const sys_errlist[];

  if(errnum > 0 && errnum < sys_nerr)
    return sys_errlist[errnum];
  else{
    if(errnum == 0)
      strcpy(message, "Unknown error");
    else sprintf(message, "Unknown error %d", errnum);
    return message;
  }
}
#   else
char* strerror(int errnum){
  static char message[32];

  sprintf(message, "errno %d", errnum);
  return message;
}
#   endif
#endif

#ifndef HAVE_STRSIGNAL
#   ifdef SYS_SIGLIST_DECLARED
char* strsignal(int errnum){
  static char message[32];

#ifndef NSIG
#define NSIG 32
#endif

  if(errnum > 0 && errnum < NSIG)
    return sys_siglist[errnum];
  else{
    if(errnum == 0)
      strcpy(message, "Unknown signal");
    else sprintf(message, "Unknown signal %d", errnum);
    return message;
  }
}
#   else 
char *strsignal(int sig){
  static char message[32];
  sprintf(message, "signal %d", sig);
  return message;
}
#   endif
#endif

/* Restituisce un puntatore a size caratteri allocato dinamicamente
   con malloc. Stampa la stringa s ed un diagnostico ed esce in caso
   manchi la memoria.
   Usa: prog_name */

void* emalloc(int size, char* s){
  void* p;

  if((p = malloc(size*sizeof(char))) == NULL){
    fprintf(stderr, "%s: %s: virtual memory exausted\n", prog_name, s);
    exit(EXIT_FAILURE);
  }
  return p;
}

/* Controlla se la stringa puntata da sz e` un intero compreso tra min
  e max. In caso affermativo mette l'intero in dest e restituisce 0;
  -1 altrimenti. */

int bound_check(char* sz, int min, int max, int* dest){
  char* endp;
  long l;

  errno = 0;
  l = strtol(sz, &endp, 10);

  if(errno == ERANGE ||		\
     strcmp(endp, "") != 0 ||	\
     l < min || l > max) return -1;

  *dest = l;

  return 0;
}

/* Crea una nuova stringa combinazione della l e della r, interponendo
   il carattere / eliminando eventuali / duplicati. */

char* combine(char* l, char* r){
  char* res;
  int len_l, len_r;

  len_l = strlen(l);
  len_r = strlen(r);
  if(*(l+len_l-1) == '/'){
    if(*r == '/'){
      res = emalloc(len_l+len_r, "combine");
      strcpy(res, l);
      strcpy(res+len_l, r+1);
    }else{
      res = emalloc(len_l+len_r+1, "combine");
      strcpy(res, l);
      strcpy(res+len_l, r);
    }
  }else{
    if(*r == '/'){
      res = emalloc(len_l+len_r+1, "combine");
      strcpy(res, l);
      strcpy(res+len_l, r);
    }else{
      res = emalloc(len_l+len_r+2, "combine");
      strcpy(res, l);
      *(res+len_l) = '/';
      strcpy(res+len_l+1, r);
    }
  }
  return res;
}

/* Restituisce una stringa allocata dinamicamente con malloc in cui
   viene espansa la ~ se c'e`. */

char* tilde_expand(char* sz){
  char *home;
  struct passwd *entry;

  if(*sz == '~'){ /* sz e` del tipo ~... */
    if(*(sz+1) == '\0') /* sz e` solo la ~ */
      if((home = getenv("HOME")) == NULL || strcmp(home, "") == 0){
	fprintf(stderr, "%s: getenv: No home dir set", prog_name);
	exit(EXIT_FAILURE);
      }else return getenv("HOME");
    if(*(sz+1) == '/'){ /* sz e` del tipo ~/... */
      if((home = getenv("HOME")) == NULL || strcmp(home, "") == 0){
	fprintf(stderr, "%s: getenv: No home dir set", prog_name);
	exit(EXIT_FAILURE);
      }
      return combine(home, sz+1);
    }else{ /* sz e` del tipo ~user... */
      char *p, *p1;
      p = strchr(sz, '/');
      if(p != NULL){ /* sz e` del tipo ~user/... */
	p1 = emalloc(p-sz, "tilde_expand");
	strncpy(p1, sz+1, p-sz-1);
	*(p1+(p-sz-1)) = '\0';
	entry = getpwnam(p1);
	free(p1);
	return combine(entry->pw_dir, p+1);
      }else{ /* sz e` del tipo ~user */
	p1 = emalloc(strlen(sz), "tilde_expand");
	strcpy(p1, sz+1);
	entry = getpwnam(p1);
        free(p1);
        return entry->pw_dir;
      }
    }
  }else
    return strcpy(emalloc(strlen(sz)+1, "tilde_expand"), sz);
}

/* Usa: prog_name */
void asp_perror(char* s){
  fprintf(stderr, "%s: ", prog_name);
  perror(s);
  exit(EXIT_FAILURE);
}
