/*****************************************************************************

  POPular -- A POP3 server and proxy for large mail systems

  $Id: util.c,v 1.35 2001/04/30 15:14:14 sqrt Exp $

  http://www.remote.org/jochen/mail/popular/

******************************************************************************

  Copyright (C) 1999-2001  Jochen Topf <jochen@remote.org>

  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

*****************************************************************************/

#if HAVE_CONFIG_H
# include <config.h>
#endif

#include "popular.h"


#if 0
/*****************************************************************************

  lock_shmem()

  type is F_RDLCK or F_WRLCK

  Lock shared memory mapped file.
  This is currently not used! See documentation.

*****************************************************************************/
int
lock_shmem(int fd, int type)
{
  struct flock fl;
  fl.l_type   = type;
  fl.l_whence = SEEK_SET;
  fl.l_start  = 0;
  fl.l_len    = 0;
  while (fcntl(fd, F_SETLKW, &fl) == -1) {
    if (errno != EINTR) return -1;
  }
  return 0;
}


/*****************************************************************************

  unlock_shmem()

  Unlock shared memory mapped file.
  This is currently not used! See documentation.

*****************************************************************************/
int
unlock_shmem(int fd)
{
  struct flock fl;
  fl.l_type   = F_UNLCK;
  fl.l_whence = SEEK_SET;
  fl.l_start  = 0;
  fl.l_len    = 0;
  while (fcntl(fd, F_SETLKW, &fl) == -1) {
    if (errno != EINTR) return -1;
  }
  return 0;
}
#endif


/*****************************************************************************

  get_int(string, min, max, overflow, error, empty)

  Get integer from <string>. Returns <overflow> if value is not between <min>
  and <max>, <error> if there are additional chars in the <string> and <empty>
  if the <string> was NULL or the empty string.

*****************************************************************************/
int
get_int(const char *string, int min, int max, int overflow, int error, int empty)
{
  char *tptr;
  long value;

  if ((!string) || (string[0] == '\0')) return empty;

  value = strtol(string, &tptr, 10);
  if (tptr[0] != '\0') return error;

  if ((value < min) || (value > max)) return overflow;

  return (int)value;
}


/*****************************************************************************

  timedesc2sec()

*****************************************************************************/
int
timedesc2sec(char *desc, int min, int max)
{
  char *tptr=desc;
  long value;
  int sec=0;

  errno = 0;
  while (1) {
    if (*tptr == '-') return -1;
    value = strtol(tptr, &tptr, 10);
    if (errno && errno != EINVAL) return -1;
    switch (*tptr) {
      case 'd':
    	sec += value*60*60*24;
	tptr++;
	break;
      case 'h':
    	sec += value*60*60;
	tptr++;
	break;
      case 'm':
    	sec += value*60;
	tptr++;
	break;
      case 's':
    	sec += value;
	tptr++;
	break;
      case '\0':
    	sec += value;
        if (sec < min || sec > max) return -1;
	return sec;
      default:
	return -1;
    }
  }

  return -1;
}


/*****************************************************************************

  sec2timedesc()

*****************************************************************************/
char *
sec2timedesc(int s)
{
  static char buf[MAXBUF];
  int d, h, m;
  int r=0;

  if (s < 0) return NULL;

  d = s / (60*60*24); s -= d*60*60*24;
  h = s / (60*60);    s -= h*60*60;
  m = s / (60);       s -= m*60;

  if (d)    r += snprintf(buf+r, sizeof(buf), "%dd", d);
  if (h)    r += snprintf(buf+r, sizeof(buf), "%dh", h);
  if (m)    r += snprintf(buf+r, sizeof(buf), "%dm", m);
  if (s || r==0) snprintf(buf+r, sizeof(buf), "%ds", s);

  return buf;
}


/*****************************************************************************

  sec2prettytime()

*****************************************************************************/
char *
sec2prettytime(int s)
{
  static char buf[MAXBUF];
  int d, h, m;

  if (s < 0) return NULL;

  d = s / (60*60*24); s -= d*60*60*24;
  h = s / (60*60);    s -= h*60*60;
  m = s / (60);       s -= m*60;

  snprintf(buf, sizeof(buf), "%3d:%02d:%02d:%02d", d, h, m, s);
  return buf;
}


/*****************************************************************************

  get_port()

*****************************************************************************/
int
get_port(const char *s)
{
  struct servent *se = getservbyname(s, "tcp");
  if (se != NULL) return ntohs(se->s_port);

  return get_int(s, 1, 65535, -1, -1, -1);
}


/*****************************************************************************

  sep_args()

*****************************************************************************/
int
sep_args(char *string, char **argv, int maxlen)
{
  typedef enum {
    sasWhitespace,
    sasArg,
    sasString
  } sep_args_state_t;
  sep_args_state_t state = sasWhitespace;
  char *p;
  int n=0;

  for (p=string; *p != '\0'; p++) {
    if (! isprint((int)*p)) return -1;		/* parse error (! isprint) */
    switch (state) {
      case sasWhitespace:
        if (isspace((int)*p)) {
          *p = '\0';
        } else if (*p == '"') {
          *p = '\0';
          if (n >= maxlen) return -2;		/* too many arguments */
          argv[n++] = p+1;
          state = sasString;
        } else {
          if (n >= maxlen) return -2;		/* too many arguments */
          argv[n++] = p;
          state = sasArg;
        }
        break;
      case sasArg:
        if (isspace((int)*p)) {
          *p = '\0';
          state = sasWhitespace;
        } else if (*p == '"') {
          return -1;				/* parse error (" in arg) */
        }
        break;
      case sasString:
        if (*p == '"') {
          *p = '\0';
          state = sasWhitespace;
        }
        break;
      default:
        return -3;				/* should never be here */
    }
  }
  if (state == sasString) return -1;		/* parse error (unmatched ") */
  return n;
}


/*****************************************************************************

  valid_id()

*****************************************************************************/
int
valid_id(const char *s)
{
  const char *p;
  if (!s || *s == '\0') return 0;
  for (p=s; *p != '\0'; p++) {
    if (! (isalnum((int)*p) || *p == '.' || *p == '_' || *p == '-')) return 0;
  }
  return 1;
}


/*****************************************************************************

  print_ip(const struct sockaddr_in *sin, char *buf))

  Puts the ASCII (dotted quad) representation of the IP address in <sin>
  into <buf>. <buf> must be preallocated with at least 16 bytes or NULL. If
  <buf> is NULL an internal static buffer is used.

  print_ip returns <buf> or a pointer to the static buffer.

  If the IP address ist INADDR_ANY the string "ANY" ist returned.

*****************************************************************************/
char *
print_ip(const struct sockaddr_in *sin, char *buf)
{
  static char sbuf[16];
  if (! buf) buf = sbuf;

  if (sin->sin_addr.s_addr == htonl(INADDR_ANY)) {
    (void) strlcpy(buf, "ANY", sizeof(sbuf));
  } else {
    (void) strlcpy(buf, inet_ntoa(sin->sin_addr), sizeof(sbuf));
  }

  return buf;
}


/*****************************************************************************

  get_load()

  Returns current system load as long integer or -1 if the load couldn't be
  determined. This reads /proc/loadavg to find the load.

*****************************************************************************/
long
get_load()
{
#ifdef LOADAVG_FILE
  char buf[20];
  int fd = open(LOADAVG_FILE, O_RDONLY);
  if (fd < 0) return -1;
  if (read(fd, buf, sizeof(buf)) <= 0) return -1;
  close(fd);

  buf[sizeof(buf)-1] = '\0';

  /* this will automatically read everything in front of the first . and
     ignore the rest (the digits after the decimal dot and the other
     numbers in the file) */
  return strtol(buf, (char **)NULL, 10);
#else
  return -1;
#endif
}


/*****************************************************************************

  touch()

*****************************************************************************/
int
touch(const char *dir, const char *file)
{
  char buf[MAXBUF];
  int fd;

  strlcpy(buf, dir, sizeof(buf));
  strlcat(buf, "/", sizeof(buf));
  strlcat(buf, file, sizeof(buf));

  fd = open(buf, O_CREAT|O_WRONLY, 0644);
  if (fd < 0) return -1;

  close(fd);

  return 0;
}


/*****************************************************************************

  search_string()

*****************************************************************************/
char *
search_string(char *s, char *t, int len)
{
  int i;
  int l = strlen(t);

  for (i=0; i <= len-l; i++) {
    if ((s[i] == t[0]) && (!strncmp(s+i+1, t+1, l-1))) return s+i;
  }
  return NULL;
}


/*****************************************************************************

  rel_select()

  reliable select

*****************************************************************************/
int
rel_select(fd_set *readset, int sec, int usec)
{
  int r;
  struct timeval timeout;
  fd_set setcopy;

  do {
    timeout.tv_sec  = sec;
    timeout.tv_usec = usec;
    memcpy(&setcopy, readset, sizeof(fd_set));
    r = select(FD_SETSIZE, &setcopy, (fd_set *)0, (fd_set *) 0, &timeout);
  } while (r < 0 && errno==EINTR);

  memcpy(readset, &setcopy, sizeof(fd_set));
  return r;
}


/*****************************************************************************

  rel_write()

  reliable write

*****************************************************************************/
ssize_t
rel_write(int fd, const char *buf, size_t count)
{
  ssize_t len;
  int offset=0;

  while ((len = write(fd, buf+offset, count-offset))) {
    if ((len < 0) && (errno != EINTR)) return -1;
    if (len == count-offset) return count;
    if (len > 0) offset += len;
  }
  return 0;
}


/** THE END *****************************************************************/


syntax highlighted by Code2HTML, v. 0.9.1