/*
** pat_port.c for  in 
** 
** Made by 
** Login   <vianney@epita.fr>
** 
** Started on  Wed Sep  1 06:42:07 1999 
** Last update Thu Oct 28 20:19:46 1999 
*/
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>
#include "pat.h"
#include "pat_port.h"
#include "pat_16.h"

/* converts a string into a port number.
   It uses getservbyname(3) and reverts to atoi(3) if not found.
   Returns the port number */
int			port_from_str(str,proto,resolve)
char			*str;		/* A service name or a number */
char			*proto;		/* Protocol, e.g. "tcp" */
t_boolean		resolve;	/* If FALSE,bypasses getservbyname(3)*/
{
  if (resolve)
    {
      struct servent	*serventry;

      setservent(0);
      if (serventry = getservbyname(str,proto))
	{
	  int		port;
	  
	  port = serventry->s_port;

	  endservent();
	  return (port);
	}
      endservent();
    }
  return (atoi(str));
}

/* converts-and-catenates a port number to a bridled string.
   It uses getservbyport(3) and reverts to long_to_str(3) if not found.
   Returns 0 if OK, might return various errors */
t_status		port_to_str(port,proto,str,max_len,resolve)
int			port;		/* Port number */
char			*proto;		/* Protocol, e.g. "tcp" */
char			*str;		/* Valid string */
int			max_len;	/* Maximum length */
t_boolean		resolve;	/* If FALSE, bypasses getservyport(3)*/
{
  if (resolve)
    {
      struct servent	*serventry;

      setservent(0);
      if (serventry = getservbyport(UNSAFE_HTONS(port),proto))
	{
	  char		*name;
	  
	  name = serventry->s_name;
	  endservent();
	  return (str_cat_str(str,max_len,name));
	}
      endservent();
    }
  return (long_to_str((signed long)port,
		      pat_base,
		      str,
		      max_len));
}

int	port_resolved_chan;

PAT_NAME_GENERIC(port_resolved_pat_name,
		 (VOID_PTR)&port_resolved_chan,
		 "port_resolved")

PAT_EXTRACT_DECL(port_resolved_pat_extract)
{
  t_u16		u16;
  t_status	status;
  char		*proto;

  proto = (char *)(data);
  assert(proto);
  if (len < sizeof (t_u16))
    return (ERR_PAT_TRUNC_FIELD);
  FBCOPY(buf,&u16,sizeof (t_u16));
  u16 = UNSAFE_NTOHS(u16);
  return (port_to_str(u16,
		      proto,
		      str,
		      max_len,
		      pat_resolve));
}

PAT_INSERT_DECL(port_resolved_pat_insert)
{
  t_u16		u16;
  t_status	status;	
  int		port;
  char		*proto;
  
  proto = (char *)(data);
  assert(proto);
  if (len < sizeof (u16))
    return (ERR_PAT_TRUNC_FIELD);
  if ((port = port_from_str(value,
			    proto,
			    TRUE)) != 0)
    return (port);
  u16 = port;
#ifdef NOTDEF
  u16 = UNSAFE_HTONS(u16);
#endif
  FBCOPY(&u16,buf,sizeof (u16));
  return (0);
}

PAT_GET_CHOICES_DECL(port_resolved_pat_get_choices)
{
  struct servent	*serventry;
  char			*proto;
  t_status		status;	

  proto = (char *)(data);
  setservent(0);
  while (serventry = getservent())
    {
      if (!strcmp(proto,serventry->s_proto))
	if ((status = vec_str_add(vec_str,
				  serventry->s_name)) != 0)
	  return (status);
    }
  endservent();
  return (0);
}

t_pat				port_resolved_pat = 
{
  port_resolved_pat_name,	/* t_pat_name_proc		*/
  NULL,				/* t_pat_off_proc		*/
  NULL,				/* t_pat_sub_proc		*/
  NULL,				/* t_pat_sum_proc		*/
  NULL,				/* t_pat_get_field_proc		*/
  NULL,				/* t_pat_set_field_proc		*/
  NULL,				/* t_pat_get_fields_proc	*/
  NULL,				/* t_pat_get_tmpl_proc		*/
  NULL,				/* t_pat_get_tmpl2_proc		*/
  NULL,				/* t_pat_has_opt_proc		*/
  NULL,				/* t_pat_adapt_len_proc		*/
  NULL,				/* t_pat_get_field_pat_proc	*/
  port_resolved_pat_extract,	/* t_pat_extract_proc		*/
  port_resolved_pat_insert,	/* t_pat_insert_proc		*/
  port_resolved_pat_get_choices,/* t_pat_get_choices_proc	*/
};
