/*
 * This file is part of El Cheapo Fax. All modifications relative to the
 * base source are (C) Copyright 1993 by Olaf 'Rhialto' Seibert.
 * All rights reserved. The GNU General Public License applies.
 */
/*
  This file is part of the NetFax system.

  (c) Copyright 1989 by David M. Siegel.
      All rights reserved.

    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.

    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., 675 Mass Ave, Cambridge, MA 02139, USA.
*/

#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <fcntl.h>

#define MAXPATHLEN	128

#include "libfax.h"
#include "seq.h"

char	       *in_qdir = INCOMING_QUEUE;
FaxModem	fm;
int		verbose;
int		immediate;

/*
 * This should also write stuff to the modem.
 */
int
recv_enable(int fd)
{
    /*
     * Make sure nothing is left to read.
     */
    tcflush(fd, TCIFLUSH);
    return 0;
}

static void
print_fdcs_params(FaxModem *f, FILE *fp)
{
    if (FAX_ISSET(f, FAX_F_FDCS)) {
	fprintf(fp, " vr=%s br=%s wd=%s ln=%s",
		t30_vr_string(&f->fdcs_params),
		t30_br_string(&f->fdcs_params),
		t30_wd_string(&f->fdcs_params),
		t30_ln_string(&f->fdcs_params));
      }
}

static int
receive_pages(FaxModem *fmp, char *in_dir, FILE *info_fp)
{
    int page = 0;

    for (;;) {
	time_t start = time(0);
	char file[MAXPATHLEN];
	int fd;

	/*
	 * Tell the modem we are ready to go.
	 */
	switch (faxmodem_start_recv(fmp)) {
	  case RECV_OK:
	    break;
	  case RECV_FAILED:
	    fprintf(info_fp, "  page %d failed\n", page+1);
	    fprintf(info_fp, "\nReceived %d pages succesfully\n", page);
	    return (-1);
	  case RECV_DONE:
	    fprintf(info_fp, "\nReceived %d pages succesfully\n", page);
	    return (page);
	}

	/*
	 * Open the file to hold the G3 data.
	 */
	sprintf(file, "%s%d", in_dir, page++);
	if ((fd = open(file, O_WRONLY|O_CREAT, 0666)) < 0) {
	    log(L_ALERT, "output file open failed: %m");
	    fprintf(info_fp, "  page %d failed\n", page);
	    return (-1);
	}

	/*
	 * Read in the page.
	 */
	if (faxmodem_recv_page(fmp, fd) < 0) {
	    log(L_WARNING, "receive of page failed");
	    fprintf(info_fp, "  page %d failed\n", page);
	    close(fd);
	    return (-1);
	}

	/*
	 * All done with the page.
	 */
	log(L_INFO, "received page %d", page);
	fprintf(info_fp, "  page %d ok", page);
	print_fdcs_params(fmp, info_fp);
	fprintf(info_fp, " time=%d\n", time(0) - start);
	close(fd);
    }
}

/*
 * This function does the bulk of the work for receiving a new
 * fax.  It answers the modem, reads the fax, writes the G3 files,
 * and mails notification.
 */
static int
handle_incoming_fax(FaxModem *fmp)
{
    time_t start = time(0);
    char in_dir[MAXPATHLEN];
    char seq_file[MAXPATHLEN];
    char info_file[MAXPATHLEN];
    FILE *info_fp;
    int seq;
    int rc;

    log(L_INFO, "handling an incoming fax");

    if (faxmodem_answer(fmp) < 0) {
	log(L_NOTICE, "can't anwser the phone");
	faxmodem_hangup(fmp);
	return (-1);
    }

    sprintf(seq_file, "%s%s", in_qdir, SEQ_FILE);
    if ((seq = seq_next(seq_file)) < 0) {
	log(L_ALERT, "can't get incoming sequence number: %m");
	faxmodem_hangup(fmp);
	return (-1);
    }

    sprintf(in_dir, "%s%d/", in_qdir, seq);
    if (mkdir(in_dir, 0755) < 0) {
	log(L_ALERT, "can't make incoming directory: %m");
	faxmodem_hangup(fmp);
	return (-1);
    }

    sprintf(info_file, "%sLOG", in_dir);
    if ((info_fp = fopen(info_file, "w+")) == NULL) {
	log(L_ALERT, "can't make info file: %m");
	faxmodem_hangup(fmp);
	return (-1);
    }

    /*
     * Print the header for the info file.
     */
    fprintf(info_fp, "Reception of fax %d started at %s", seq, ctime(&start));
    faxmodem_print_id_strings(fmp, info_fp);
    fprintf(info_fp, "\n");

    /*
     * Receive the pages.
     */
    rc = receive_pages(fmp, in_dir, info_fp);
    fprintf(info_fp, "\nTotal connect time was %d seconds.\n",
	    time(0) - start);

    /*
     * All done.
     */
    faxmodem_hangup(fmp);
    fclose(info_fp);
    return (rc);
}

/* ARGSUSED */
static int
recv_handler(FaxModem *fm)
{
    log(L_INFO, "the phone is (probably) ringing");

    handle_incoming_fax(fm);

    /*
     * Resync resync the modem, just in case.
     */
    if (faxmodem_sync(fm, FAXMODEM_SYNC_TRIES) < 0)
      log(L_EMERG, "can't resync to the modem");

    /*
     * All done!
     */
    return (0);
}

void
cleanup(void)
{
    if (fm.fd >= 0)
	faxmodem_close(&fm);
}

/*
 * Setup for incoming faxes.  Basically, we read from the serial
 * device If any data arrives on the fd, we know
 * we have an incoming fax, and we handle the call.
 */
int
init_for_recv(char *fax_device)
{
    if (faxmodem_open(&fm, fax_device) >= 0) {
	char c;
	int rc;

	atexit(cleanup);
	recv_enable(fm.fd);

	if (!FAX_ISSET(&fm, FAX_F_FCON)) {
	    if (faxmodem_sync(&fm, FAXMODEM_SYNC_TRIES) < 0) {
		log(L_EMERG, "can't sync to the modem");
		return -1;
	    }
	}
	for (;;) {
	    if (immediate) {
		rc = immediate;
		immediate = -1;     /* receive only one fax */
	    } else
		rc = tread(fm.fd, &c, 1, 60*60);   /* 1 hour timeout */
	    if (rc > 0)
		recv_handler(&fm);
	    else if (rc < 0)
		break;
	}
	faxmodem_close(&fm);
	fm.fd = -1;
	immediate = 0;
    }
}

int
main(int argc, char **argv)
{
    int 	    c;
    extern char    *optarg;
    extern int	    optind;
    extern int	    getopt(int, char **, char *);
    int 	    errflg = 0;
    char	   *fax_device = FAX_DEVICE;

    log_set_level(LOG_WARNING);

    while ((c = getopt(argc, argv, "d:l:vf:i")) != -1) {
	switch (c) {
	case 'd':
	    in_qdir = optarg;
	    break;
	case 'l':
	    log_set_level(atoi(optarg));
	    break;
	case 'v':
	    verbose = TRUE;
	    break;
	case 'f':
	    fax_device = optarg;
	    break;
	case 'i':
	    immediate++;
	    if (immediate == 2) {
		fm.flags |= FAX_F_FCON;   /* Don't ATZ/ATA */
	    }
	    break;
	case '?':
	    errflg++;
	    break;
	}
    }

    if (errflg || optind > argc) {
	fprintf(stderr,
"Usage: %s -d queuedir/ -f faxdevice -l loglevel -v -i\n", argv[0]);
	exit(EXIT_FAILURE);
    }

    return init_for_recv(fax_device) >= 0? EXIT_SUCCESS: EXIT_FAILURE;
}
