/*
** (c) 1992 Uwe C. Schroeder, Anwendungssysteme , Augsburg, Germany
**
** 
** Permission to use, copy, and modify this software and its
** documentation for non comercial  purpose is hereby granted 
** without fee, provided that
** the above copyright notice appear in all copies and that both that
** copyright notice and this permission notice appear in supporting
** documentation, and that the name of Uwe C. Schroeder not be used in
** advertising or publicity pertaining to distribution of the software without
** specific, written prior permission.  Uwe Schroeder makes no representations
** about the suitability of this software for any purpose.  It is provided
** "as is" without express or implied warranty.
** This software may not be sold or distributed with commercial products
** ( this includes distribution "for users convenience" ) without prior
** written permission by the author.
**
** UWE SCHROEDER DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
** INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
** EVENT SHALL UWE SCHROEDER BE LIABLE FOR ANY SPECIAL, INDIRECT OR
** CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
** DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
** TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
** PERFORMANCE OF THIS SOFTWARE.
**
**
** This is a alpha release, which means, that there are still several
** known bugs.
**
** Please report bugs to:
**
**                     usys@phoenix.abg.sub.org
**
*/


#include <stdio.h>
#include <sys/types.h>
#if 0
#ifdef Linux
#include <sys/termios.h>
#else
#include <sys/termio.h>
#endif
#else
/* This compiles better on SLS */
#ifdef Linux
#include <termios.h>
#else
#include <termio.h>
#endif
#endif
#include <fcntl.h>
#include <sys/ioctl.h>
#include <unistd.h>
#include <dirent.h>
#include <sys/time.h>
#include <setjmp.h>
#include <signal.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#include <errno.h>

#include "vfax.h"
#include "patchlevel.h"

static jmp_buf timeoutbuf;
int debug = 0;
int local = FALSE;
int fd; /* data port, command port */
extern void end_by_sig(); /* signal.c */

int 
sigALRM()
{
  tty_unblock();
  longjmp(timeoutbuf, 1);
}

static void
daemonize()
{
  int s;
  int pid;
  
  if ((pid = fork()) != 0) {
      if (pid < 0)
	perror("start_daemon: fork");
      exit(0);
    }
  if(pid == 0) /* child */
    {
      if( close(0) < 0 
	 || close(1) < 0 
	 || close(2) < 0)
	{
	  perror("close in daemonize");
	  Debug(0,"ERROR: close in daemonize ");
	}
      setpgrp();
    }
  else
    {
      exit(0);
    }
}



main(argc,argv)
     int argc;
     char *argv[];
{
  char tmpfn[512],msgfn[512];
  int msgno = 0, faxno = 0, c,y ;
  int ringcount=1,rcc;
  int be_daemon = FALSE;
  int errflg = FALSE;
  void (*fu)();
  int receive_mode=TRUE;
  int scan_interval = QUEUE_INTERVAL;
  extern char *optarg;
  void *sighand;
  void *sigcarr;
  /* for ipc messages */
  key_t *key;
  int mq; /* message queue */
  FIPM msg;
  FILE *ipc_file;

  fu = signal(SIGALRM,sigALRM);

  /* parse parameters */
  while ((c = getopt(argc, argv, "d:Drli:c:h")) != -1)
    switch (c) {
    case 'd':
      debug = atoi(optarg);
      break;
    case 'D':
      be_daemon = TRUE;
      break;
    case 'l':
      local = TRUE;
      Debug(0,"local mode \n");
      break;
    case 'r':
      receive_mode = FALSE;
      break;
    case 'i':
      scan_interval = atoi(optarg);
      break;
    case 'c':
      ringcount = atoi(optarg);
      break;
    case '?':
    case 'h':
      errflg = TRUE;;
      break;
    }
  if (errflg) usage(argv[0]);

  if (be_daemon)
    daemonize();
  else
    setpgrp();

  sighand = (void(*)())end_by_sig;

  signal(SIGTERM,sighand);
  signal(SIGKILL,sighand);
  signal(SIGQUIT,sighand);
  signal(SIGINT,sighand);
  signal(SIGABRT,sighand);
  

  logto(1,"Have set scan interval to %d seconds",scan_interval);

  /* open IPC file */
  if((ipc_file=fopen(FAX_IPC_FILE,"w+")) == (FILE *)NULL) {
    Debug(0,"FATAL: open ipc_file failed with %d\n",errno);
    exit(errno);
  }


  /* get message queue */
  if((mq = msgget(key,IPC_CREAT | 0666)) < 0) {
    Debug(0,"FATAL: msgget failed with %d\n",errno);
    exit(errno);
  }
  
  if(fwrite(&mq,sizeof(int),1,ipc_file) < 0) {
    Debug(0,"FATAL: fwrite ipcfile failed with %d\n",errno);
    exit(errno);
  }
  fclose(ipc_file);


  fd=open_tty(PORT);
  rcc=0;

  /* force modem to known init stae */
  writecmd("ATZE0");
  getret("OK");

  while(TRUE)
    {
      if(setjmp(timeoutbuf)==0)
	{
	  fu = signal(SIGALRM,sigALRM);
	  alarm(scan_interval);
	  if(msgrcv(mq,&msg,32,0,0|IPC_NOWAIT) < 0) { 
	    if(errno != ENOMSG)
	      Debug(0,"msgrcv failed with errno %d\n",errno);
	  } else {/* hey , there is news */
	    alarm(0);
	    signal(SIGALRM, fu);
	    /* check for call message (has typ 2) */
	    if(msg.mtype == 2) { /* yep, there is a call msg */
	      dial(fd,msg.mtext);
	    } else { /* no call msg */
	      switch(msg.mtext[0]) {
	      case FM_EXIT:
		Debug(2,"Exit due to FM_EXIT message\n");
		close_tty();
		if(unlink(FAX_IPC_FILE)<0)
		  Debug(0,"Error: can't remove file %s\n",FAX_IPC_FILE);
		exit(0);
		break;
	      case FM_RECFAX: /* immediately receive fax */
		Debug(2,"Receive Fax immediately message\n");
		faxno = rfax(faxno);
		continue;
		break;
	      case FM_RELEASE: /* release port */
		Debug(2,"Release port message\n");
		writecmd("ATZ");
		getret("OK");
		close_tty();
		while(msgrcv(mq,&msg,1,0,0&IPC_NOWAIT) < 0 ||
		      msg.mtext[0] != FM_REINIT);
		Debug(2,"Reinit port message\n");
		fd=open_tty(PORT);
		writecmd("ATZE0");
		getret("OK");
		continue;
		break;
	      case FM_PLAYBACK: /* playback all msgs */
		Debug(2,"Playback message - %d messages\n",msgno);
		writecmd("AT+VTS=[933,0,10]");
		getret("OK");
		tty_raw_mode_out(VOICE);
		init_voice();
		init_vspeaker();
		for(y=0;y<msgno;y++)
		  {
		    sprintf(tmpfn,"%s/in%d",VSPOOLDIR,y);
		    Debug(3,"playing msg no %s\r\n",tmpfn);
		    play(tmpfn);
		  }
		/* transmitt end of message signal */
		writecmd("AT+VTS=[933,0,5]");
		getret("OK");
		init_vdef();
		continue;
		break;
	      default:
		Debug(0,"Received illegal message %d",msg.mtext[0]);
		break;
	      }
	    }
	  }
	  /* set up modem */
	  tty_raw_mode_out(VOICE);
	  writecmd("ATZ");
	  getret("OK");
	  if(receive_mode)
	    {
	      Debug(9,"Try to get ring\n");
	      if(local ||(get_bresponse("RING") && ++rcc >= ringcount))
		{
		  alarm(0);
		  signal(SIGALRM, fu);
                  /* set up modem */
		  Debug(5,"got ring\n");
                  tty_raw_mode_out(VOICE);
		  writecmd("ATZ");
		  getret("OK");
                  init_voice();
                  init_vdef();
                  rcc = 0;
                  sprintf(tmpfn,"%s/in%d",VSPOOLDIR,msgno);
                  sprintf(msgfn,"%s/greetmsg.v",MSGDIR);
                  Debug(2,"Greeting %s\r\n",msgfn);
                  play(msgfn);
                  writecmd("AT+VTS=[933,0,3]");
                  getret("OK");
                  switch(recmsg(tmpfn,msgno,faxno)){
		  case FAX:
		    faxno++;
		    break;
		  case VOICE:
                    msgno++;
		    break;
		  }
                  writecmd("AT+VLS=0");
                  getret("OK");
		  continue;
		} /* rings ?? */
	    } /* rec_mode */
	  else
	    sleep(scan_interval+2);
	} /* setjmp */
      else
	{
	  proc_outfile();
	}
    } /* while */
  alarm(0);
  signal(SIGALRM, fu);
  unlink(FAX_IPC_FILE);
  exit(0);
}

int usage(name)
     char *name;
{
  printf("usage: %s [ Ddrlc ] [i val] \n",name);
  printf("where:\n\tD     = run as daemon\n");
  printf("\td val = debug level #\n");
  printf("\tr     = disable answering the line\n");
  printf("\ti val = set scan interval to val\n");
  printf("\tl     = local mode\n");
  printf("\tc val = set no. of rings\n");
  
  exit(0);
}
