/* --------------------------------------------------------------- *\

  file  : imonc.c 
  author: f. meyer 
  mail  : frank at fli4l.de
  copyr : copyright (c) 2001 - 2003 by f. meyer

  start : Mon 12 Mai 2003 07:35:16 CEST

  $Id: imonc.c,v 1.7 2003/05/17 17:33:34 bz-akira Exp $

\* --------------------------------------------------------------- */
/* --------------------------------------------------------------- *\
  
  This program is free software; you can redistribute it and/or 
  modify it under the terms of the GNU General Public Licensse 
  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.

\* --------------------------------------------------------------- */
/* --------------------------------------------------------------- *\

  about : small helper to connect to the imond 

\* --------------------------------------------------------------- */
#include <errno.h>
#include <stdio.h>

#include <string.h>
#include <unistd.h>
#include <stdlib.h>
#include <signal.h>

#include <netdb.h>
#include <netinet/in.h>
#include <netinet/tcp.h>
#include <arpa/inet.h>				/* decl of inet_addr()	    */
#include <sys/socket.h>

#include "imonc.h"

/*----------------------------------------------------------------------------
 *  service_connect (host_name, port)
 *  connect to ip=host_name on port=port
 *  returns the fd or '0' if connection failed
 *----------------------------------------------------------------------------
 */
int service_connect (char *	host_name, int	port)
{
    struct sockaddr_in	addr;
    struct hostent *	host_p;
    int			fd;
    int			opt = 1;

    (void) memset ((char *) &addr, 0, sizeof (addr));

    if ((addr.sin_addr.s_addr = inet_addr ((char *) host_name)) == INADDR_NONE)
    {
	host_p = gethostbyname (host_name);

	if (! host_p)
	{
	    fprintf (stderr, "%s: host not found\n", host_name);
	    return (-1);
	}

	(void) memcpy ((char *) (&addr.sin_addr), host_p->h_addr,
			host_p->h_length);
    }

    addr.sin_family  = AF_INET;
    addr.sin_port    = htons ((unsigned short) port);

    if ((fd = socket (AF_INET, SOCK_STREAM, 0)) < 0)
    {						/* open socket		    */
	perror ("socket");
	return (-1);
    }

    (void) setsockopt (fd, IPPROTO_TCP, TCP_NODELAY,
		       (char *) &opt, sizeof (opt));

    if (connect (fd, (struct sockaddr *) &addr, sizeof (addr)) != 0)
    {
	(void) close (fd);
	/* [zeank] being q'n'd
	 * if trying to connect to telmond port don't show an error message
	 */
	if (port != TELMOND_PORT)
		perror (host_name);
	return (-1);
    }

    return (fd);
} /* service_connect (host_name, port) */


/*----------------------------------------------------------------------------
 *  service_disconnect (fd)                 - disconnect from service
 *----------------------------------------------------------------------------
 */
void service_disconnect (int fd)
{
    (void) close (fd);
    return;
} /* service_disconnect (fd) */


/*----------------------------------------------------------------------------
 *  send_command (fd, str)                 - send command str via fd
 *----------------------------------------------------------------------------
 */
void send_command (int	fd, char *str)
{
    char    buf[256];
    int	    len = strlen (str);

    sprintf (buf, "%s\r\n", str);
    write (fd, buf, len + 2);

    return;
} /* send_command (fd, str) */


/*----------------------------------------------------------------------------
 *  get_answer (fd)			- get answer from fd
 *----------------------------------------------------------------------------
 */
char *get_answer (int fd)
{
    static char buf[8192];
    int         len;

    len = read (fd, buf, 8192);

    if (len <= 0)
    {
        return ((char *) NULL);
    }

    while (len > 1 && (buf[len - 1] == '\n' || buf[len - 1] == '\r'))
    {
        buf[len - 1] = '\0';
        len--;
    }

    if (! strncmp (buf, "OK ", 3))                      /* OK xxxx          */
    {
        return (buf + 3);
    }
    else if (len > 2 && ! strcmp (buf + len - 2, "OK"))
    {
        *(buf + len - 2) = '\0';
        return (buf);
    }
    else if (len == 2 && ! strcmp (buf + len - 2, "OK"))
    {
        return (buf);
    }

    return ((char *) NULL);                             /* ERR xxxx         */
} /* get_answer (fd) */


/*----------------------------------------------------------------------------
 *  get_lastcall (telmond_port) 	- gets last incoming call from telmond
 *----------------------------------------------------------------------------
 */
char *get_lastcall (char *host_name, int port)
{
    static char buf[8192];
    int		len, td;

    if ((td = service_connect (host_name, port)) <= 0)
	return ((char *) NULL);

    len = read (td, buf, 8192);

    if (len <= 0) 
    {
	service_disconnect (td);
	return ((char *) NULL);
    }
		
    while (len > 1 && (buf[len - 1] == '\n' || buf[len - 1] == '\r'))
    {
	buf[len - 1] = '\0';
	len--;
    }

    service_disconnect (td);
    return (buf);

} /* get_lastcall (telmond_port) */


/* --------------------------------------------------------------- *\
    
\* --------------------------------------------------------------- */
int imonc_user_auth(int fd, const char* pass)
{
  if ( fd > 0 )
  {
    char* a= NULL;
    
    send_command(fd, "pass");
    a= get_answer(fd);

    if ( a )
    {
       switch ( atoi(a) )
       {
         case 1: // userpassword set
           {
             static char buf[128];
             snprintf(buf, 128, "pass %s", pass);
             send_command(fd, buf);
             a= get_answer(fd);

             if ( a && atoi(a) == 3 )
               return 1;

           }
           break;

           
         case 2:    // already authed
         case 3:
         case 4:
           return 1;

       }; // switch
    }
  }
  return 0;
}

int imonc_admin_auth(int fd, const char* pass)
{
  if ( fd > 0 && pass )
  {
    char* a= NULL;
    
    send_command(fd, "pass");
    a= get_answer(fd);

    if ( a )
    {
       switch ( atoi(a) )
       {
         case 1: 
         case 2: 
           {
             static char buf[128];
             snprintf(buf, 128, "pass %s", pass);
             send_command(fd, buf);
             a= get_answer(fd);
             
             if ( a && atoi(a) == 6 )
               return 1;

           }
           break;

         case 4:
           return 1;

       }; // switch
    }
  }
  return 0;
}

int imonc_is_user_mode(int fd)
{
  char* a= NULL;
  send_command(fd, "pass");
  a= get_answer(fd);

  if ( a && atoi(a) & 2 )
    return 1;

  return 0;
}

int imonc_is_admin_mode(int fd)
{
  char* a= NULL;
  send_command(fd, "pass");
  a= get_answer(fd);

  if ( a && atoi(a) & 4 )
    return 1;

  return 0;
}

int imonc_is_pppoe_enabled(int fd)
{
  char* a= NULL;
  send_command(fd, "pppoe");

  a= get_answer(fd);

  if ( a && atoi(a) == 1 )
    return 1;

  return 0;
}


char* imonc_get_channel_time(int fd, int channel, char* buf)
{
  char* a= NULL;

  if ( channel != -1 || ( channel <= 16 && channel > 0 ) )
    return buf;

  switch ( channel )
  {
    case -1: // pppoe
      send_command(fd, "time pppoe");
      break;
      
    default:
      {
        static char b[16];
        snprintf(buf, 16, "time %d", channel);
        send_command(fd, b);
      }
      break;
  };

  a= get_answer(fd);

  if ( a )
  {
    sprintf(buf, "%s", strtok(a, " "));
    return buf;
  }

  return buf;
}

int imonc_get_channel_status(int fd, int channel)
{
  char* a= NULL;

  if ( channel != -1 || ( channel <= 16 && channel > 0 ) )
    return 0;

  switch ( channel )
  {
    case -1: // pppoe
      send_command(fd, "status pppoe");
      break;
      
    default:
      {
        static char buf[16];
        snprintf(buf, 16, "status %d", channel);
        send_command(fd, buf);
      }
      break;
  };

  a= get_answer(fd);

  if ( a && !strcmp(a, "Online"))
  {
    return 1;
  }

  return 0;
}



char* imonc_get_channel_onlinetime(int fd, int channel, char* buf)
{
  char* a= NULL;

  if ( channel != -1 || ( channel <= 16 && channel > 0 ) )
    return buf;

  switch ( channel )
  {
    case -1: // pppoe
      send_command(fd, "online-time pppoe");
      break;
      
    default:
      {
        static char b[16];
        snprintf(buf, 16, "online-time %d", channel);
        send_command(fd, b);
      }
      break;
  };

  a= get_answer(fd);

  if ( a )
  {
    sprintf(buf, "%s", strtok(a, " "));
    return buf;
  }

  return buf;
}

int imonc_get_channel_rate(int fd, int channel, int* down_rate, int* up_rate)
{
  char* a= NULL;

  if ( channel != -1 || ( channel <= 16 && channel > 0 ) )
    return 0;

  switch ( channel )
  {
    case -1: // pppoe
      send_command(fd, "rate pppoe");
      break;
      
    default:
      {
        static char buf[16];
        snprintf(buf, 16, "rate %d", channel);
        send_command(fd, buf);
      }
      break;
  };

  a= get_answer(fd);

  if ( a )
  {
    *down_rate= atoi(strtok(a, " "));
		*up_rate=   atoi(strtok(NULL, " "));

    return 1;
  }

  return 0;
}

int imonc_dial_channel(int fd, int channel)
{
  char* a= NULL;

  if ( channel != -1 || ( channel <= 16 && channel > 0 ) )
    return 0;

  switch ( channel )
  {
    case -1: // pppoe
      send_command(fd, "dial");
      break;
      
    default:
      {
        static char buf[16];
        snprintf(buf, 16, "dial");
        send_command(fd, buf);
      }
      break;
  };

  a= get_answer(fd);

  if ( a )
  {
    return 1;
  }
  
  return 0;
}

int imonc_hangup_channel(int fd, int channel)
{
char* a= NULL;

  if ( channel != -1 || ( channel <= 16 && channel > 0 ) )
    return 0;

  switch ( channel )
  {
    case -1: // pppoe
      send_command(fd, "hangup pppoe");
      break;
      
    default:
      {
        static char buf[16];
        snprintf(buf, 16, "hangup %d", channel);
        send_command(fd, buf);
      }
      break;
  };

  a= get_answer(fd);

  if ( a )
  {
    return 1;
  }
  
  return 0;

}

int imonc_get_cpuload(int fd)
{
  char* a;
  
  send_command(fd, "cpu");
  a= get_answer(fd);

  if ( a  )
    return atoi(strtok(a, " "));

  return -1;
}

int imonc_get_uptime(int fd)
{
  char* a;
  
  send_command(fd, "uptime");
  a= get_answer(fd);

  if ( a  )
    return atoi(strtok(a, " "));

  return -1;
}










char* imonchelp_get_bytes_string(unsigned int bytes, char* buf)
{
  if ( buf )
  {
    static float flobytes;

    // TODO optimize
    if ( bytes >= GIGABYTES ) 
    {
       flobytes= bytes * INV_GIGABYTES;
       sprintf (buf, "%.1fG", flobytes);
       return buf;
    }

    if ( bytes >= MEGABYTES ) 
    {
       flobytes= bytes * INV_MEGABYTES;
       sprintf (buf, "%.1fM", flobytes);
       return buf;
    }

    if ( bytes >= KILOBYTES ) 
    {
       flobytes = bytes * INV_KILOBYTES;
       sprintf (buf, "%.1fK", flobytes);
       return buf;
    } 

    sprintf (buf, "%lu", (ulong) bytes);

  }
  return buf;
}



char* imonchelp_get_uptime_string(unsigned int uptime, char* buf)
{
  if ( buf )
  {
    static int d;
    static int h;
    static int m;
    static int s;

    // TODO: optimize a bit 
    d= uptime / SECS_PER_DAY;
    h= (uptime % SECS_PER_DAY) / SECS_PER_HOUR;
    m= ((uptime % SECS_PER_DAY) % SECS_PER_HOUR) / SECS_PER_MINUTE;
    s= ((uptime % SECS_PER_DAY) % SECS_PER_HOUR) % SECS_PER_MINUTE;
    
    if (d > 0)
      sprintf (buf , "%d days %d", d, h);
    else 
      sprintf (buf, "%d", h);

    if (m < 10)
      sprintf (buf, "%s:0%d", buf, m);
    else 
      sprintf (buf, "%s:%2d", buf, m);

    if (s < 10)
      sprintf (buf, "%s:0%d", buf, s);
    else 
      sprintf (buf, "%s:%2d", buf, s);

  }
  return buf;
}
