/************************************************************************
 *	Routines for dealing with comsat, as used by procmail		*
 *									*
 *	Copyright (c) 1990-1999, S.R. van den Berg, The Netherlands	*
 *	Copyright (c) 1999-2001, Philip Guenther, The United States	*
 *							of America	*
 *	#include "../README"						*
 ************************************************************************/

#ifdef RCS
static /*const*/char rcsid[]=
 "$Id: comsat.c,v 1.4 2001/06/27 17:07:20 guenther Exp $";
#endif

#include "procmail.h"

#ifndef NO_COMSAT

#include "sublib.h"			       /* for strtol() and strlcat() */
#include "robust.h"					     /* for rclose() */
#include "shell.h"					   /* for tmemmove() */
#include "acommon.h"					     /* for ultstr() */
#include "mailfold.h"					     /* for lasttell */
#include "misc.h"
#include "variables.h"
#include "network.h"
#include "comsat.h"

static int csvalid;		     /* is it turned on with a good address? */
static struct sockaddr_in csaddr;
static char*cslastf,*cslgname;

void setlfcs(folder)const char*folder;		/* set lastfolder for comsat */
{ char*new,*old;
  if(strchr(dirsep,*folder))			       /* absolute filename? */
     new=tstrdup(folder);
  else					/* nope; prepend the current maildir */
   { const char*md=tgetenv(maildir);
     size_t len=strlen(md)+2+strlen(folder);
     new=malloc(len);
     strcpy(new,md);
     strlcat(new,MCDIRSEP_,len);
     strlcat(new,folder,len);
   }
  onguard();			     /* protect the change over from signals */
  old=cslastf;
  cslastf=new;
  offguard();
  if(old)
     free(old);
}

void setlgcs(name)const char*name;		   /* set logname for comsat */
{ char*new,*old;
  new=tstrdup(name);
  onguard();			     /* protect the change over from signals */
  old=cslgname;
  cslgname=new;
  offguard();
  if(old)
     free(old);
}

int setcomsat(chp)const char*chp;
{ char*chad;int newvalid; struct sockaddr_in newaddr;
  chad=strchr(chp,SERV_ADDRsep);			     /* @ separator? */
  if(!chad&&!renvint(-1L,chp))
     return csvalid=0;					/* turned off comsat */
  newvalid=1;
  if(chad)
     *chad++='\0';				      /* split the specifier */
  if(!chad||!*chad)						  /* no host */
#ifndef IP_localhost			      /* Is "localhost" preresolved? */
     chad=COMSAThost;					/* nope, use default */
#else /* IP_localhost */
   { static const unsigned char ip_localhost[]=IP_localhost;
     newaddr.sin_family=AF_INET;
     tmemmove(&newaddr.sin_addr,ip_localhost,sizeof ip_localhost);
   }
  else
#endif /* IP_localhost */
   { const struct hostent*host;		      /* what host?  paranoid checks */
     if(!(host=gethostbyname(chad))||!host->h_0addr_list)
      { bbzero(&newaddr.sin_addr,sizeof newaddr.sin_addr);
	newvalid=0;			     /* host can't be found, too bad */
      }
     else
      { newaddr.sin_family=host->h_addrtype;	     /* address number found */
	tmemmove(&newaddr.sin_addr,host->h_0addr_list,host->h_length);
      }
     endhostent();
   }
  if(newvalid)						  /* so far, so good */
   { int s;
     if(!*chp)						       /* no service */
	chp=BIFF_serviceport;				/* new balls please! */
     s=strtol(chp,&chad,10);
     if(chp!=chad)			       /* the service is not numeric */
	newaddr.sin_port=htons((short)s);		    /* network order */
     else
      { const struct servent*serv;
	serv=getservbyname(chp,COMSATprotocol);		   /* so get its no. */
	if(serv)
	   newaddr.sin_port=serv->s_port;
	else
	 { newaddr.sin_port=htons((short)0);		  /* no such service */
	   newvalid=0;
	 }
	endservent();
      }
   }
  onguard();				    /* update the address atomically */
  if(csvalid=newvalid)
     tmemmove(&csaddr,&newaddr,sizeof(newaddr));
  offguard();
  return newvalid;
}

void sendcomsat P((const char*folder))
{ int s;const char*p;
  if(!csvalid||!buf)		  /* is comat on and set to a valid address? */
     return;
  if(!*cslgname||strlen(cslgname)+2>linebuf)	       /* is $LOGNAME bogus? */
     return;
  if(!(p=folder?folder:cslastf))		     /* do we have a folder? */
     return;
  strcpy(buf,cslgname);
  strlcat(buf,"@",linebuf);		     /* start setting up the message */
  if(lasttell>=0)					   /* was it a file? */
   { ultstr(0,(unsigned long)lasttell,buf2);	  /* yep, include the offset */
     strlcat(buf,buf2,linebuf);
   }
  strlcat(buf,COMSATxtrsep,linebuf);			 /* custom seperator */
  strlcat(buf,p,linebuf);			  /* where was it delivered? */
  if((s=socket(AF_INET,SOCK_DGRAM,UDP_protocolno))>=0)
   { sendto(s,buf,strlen(buf),0,(struct sockaddr*)&csaddr,sizeof(csaddr));
     rclose(s);
     yell("Notified comsat:",buf);
   }
}

#else
int comsat_dummy_var;		      /* to prevent insanity in some linkers */
#endif
