#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/select.h>
#include <signal.h>
#include <sys/types.h>
#include <sys/time.h>
#include <sys/wait.h>
#include "antibadmail.h"
#include "s.h"

/*
 * Return zero if the recipient address RCPT surely does NOT exist
 * return 1: RCPT exists maybe
 *        2: Failed to connect to qserver
 *	 <0: other error
 */
int rq(char *rcpt, char *argv[])
{
  int p2c[2], c2p[2], status;
  pid_t pid;
  fd_set fds;
  static STR buf = {0};
  int nread, buflen=sizeof buf;
  if (-1 == pipe(p2c) || -1 == pipe(c2p)) {
    fprintf(stderr, "PIPE error\n");
    return -2;
  }
  if ((pid=fork()) == -1) {
    fprintf(stderr, "Cannot fork(1).\n");
    return -3;
  } else if (pid != 0) {
    /* grand parent */
    close(p2c[1]);
    close(p2c[0]);
    close(c2p[1]);
    close(c2p[0]);
  } else {
    /* child */
    pid_t cpid;
    if ((cpid=fork()) == -1) {
      fprintf(stderr, "Cannot fork(2)\n");
      return -4;
    } else {
      if (cpid != 0) {
        /* parent of child */
        int rc=1, trial=1;
        close(p2c[0]);
        close(c2p[1]);
        write(p2c[1], rcpt, strlen(rcpt));
        close(p2c[1]);
        while (trial-- > 0) {
          struct timeval timeout = {RQ_TIMEOUT > 2 ? RQ_TIMEOUT-1 : 1, 0};
          FD_ZERO(&fds);
          FD_SET(c2p[0], &fds);
          nread = select(32, &fds, 0, 0, &timeout);
          if (nread < 0) {
            rc = -5;
            break;
          }
          if (FD_ISSET(c2p[0], &fds)) {
            int nb, ch, len=0;
            do {
              nb = read(c2p[0], &ch, 1);
              if (!strop(&buf, "addch", ch)) return -7;
              FD_ZERO(&fds);
              FD_SET(c2p[0], &fds);
            } while (nb>0 && ch != '\n'
                     && 0 < select(32, &fds, 0, 0, 0));
            fprintf(stderr, "GET: %s\n", buf.s);
            if (!strncmp("NG", buf.s, 2))
              rc = 0;           /* Not existent */
            else if (!strncmp("OK", buf.s, 2))
              rc = 1;           /* Maybe OK */
          } else {
            pid_t pg = getpgid(cpid);
            fprintf(stderr, "Error: TIMEOUT(cpid=%d, pgrp=%d)\n", cpid, pg);
            killpg(pg, SIGINT);
            rc = 2;
          }
        }
        wait(&status);
        fprintf(stderr, "EXIT:%d, im=%d\n", rc, getpid());
        exit(rc);
      } else {
        close(p2c[1]);
        close(c2p[0]);
        /* child of child */
        close(0);
        dup(p2c[0]);
        close(p2c[0]);              /* p2c[0] turns to stdin */

        close(1);
        dup(c2p[1]);
        close(c2p[1]);              /* c2p[1] turns to stdout */
        execvp(argv[0], argv);
        /* If failed, return error string. */
        printf("rq exec [%s] failed\n", argv[0]);
        exit(-6);
      }
    }
  }
  waitpid(pid, &status, 0);
  if (WIFEXITED(status))
      return WEXITSTATUS(status);
  return -1;
}

int rq_nonexistent(char *rcpt, char *cmd)
{
  char *argv[3] = {cmd, cmd, NULL};
  return rq(rcpt, argv);
}

#ifdef RQ_TEST
int main(int argc, char *argv[])
{
  if (argc > 2)
    return rq(argv[1], 2+argv);
  else
    fprintf(stderr, "Usage: %s rcpt path-to-rq IP-addr-of-rqserver\n", argv[0]);
  return 0;
}
#endif
