#include <stdlib.h>
#include <stdio.h>
#include <errno.h>
#include <string.h>
#include <unistd.h>
#include <dirent.h>
#include <sys/wait.h>


/* Puffergroesse fuer Mailadresse */
#define MAIL_ADDR_LEN       64

/* Puffergroesse fuer cf / df-Dateiname mit Pfadangabe "spool/" */
#define JOB_FILEPATH_LEN    32


/* Prototyp, Funktion ist in "setstdin.c" implementiert */
int setstdin(char *filename);


/******************************************************************************
 * bexecl: Auftraege lokal verarbeiten; folgende Schritte werden ausgefuehrt: *
 *         - Kindprozess erzeugen                                             *
 *         - Inhalt der df-Datei auf die Standardeingabe umleiten             *
 *         - Das Kommando "/bin/mail" mit den notwendigen Parametern aufrufen *
 *         - Der Vaterprozess wartet nur auf die Terminierung des Kind-       *
 *           prozesses                                                        *
 ******************************************************************************
 * Eingabe: empfaenger: Empfaenger-Mailadresse                                *
 *          dffile:     Name der Datei mit Mailinhalt                         *
 ******************************************************************************/

void bexecl(char *empfaenger, char *dffile)
{
  pid_t pid;

  /* Kindprozess erzeugen, dieser uebernimmt das Versenden der Mail */
  pid = fork();
  if(pid == -1)
  {
    perror("bexecl: fork");
    exit(EXIT_FAILURE);
  }
  else if(pid > 0)
  {
    /* Vater-Prozess, warten bis Kindprozess terminiert */
    wait(NULL);
  }
  else
  {
    /* Kind-Prozess */
    printf("Mail wird lokal an \"%s\" verschickt\n", empfaenger);

    /* Inhalt der Mail-Datei auf Standardeingabekanal umleiten */
    setstdin(dffile);

    /* Mail versenden, dazu "mailx"-Kommando via "exec" aufrufen:
       Erster Parameter fuer "execl" ist das aufzurufende Programm,
       die folgenden Parameter bilden die an das aufgerufene Programm
       uebergebene Parameterliste (argv), wobei der erste Parameter mit
       Index 0 der Programname ist. Es folgen die eigentlichen Parameter
       fuer das Programm: "-s" zeigt an, das als naechster Parameter der
       Betreff folgt; anschliessend wird die Empfaengeradresse angegeben,
       und die Parameterliste mit NULL abgeschlossen */
    execl("/bin/mailx", "mailx", "-s", "Mail-Job", empfaenger, NULL);

    /* exec kehrt im Erfolgsfall nicht zurueck, wenn dieser Programmteil
       ausgefuehrt wird liegt also ein Fehler vor */
    perror("bexecl: execl");
    exit(EXIT_FAILURE);
  }
}


/******************************************************************************
 * bexec: Auftraege verarbeiten:                                              *
 *        Die Empfaengeradresse wird aus der cf-Datei eingelesen und der      *
 *        "bexecl"-Funktion zur lokalen Weiterverarbeitung zusammen mit dem   *
 *        df-Dateinamen uebergeben                                            *
 ******************************************************************************
 * Eingabe: cffile: Name der Datei mit Empfaengeradresse                      *
 *          dffile: Name der Datei mit Mailinhalt                             *
 ******************************************************************************/

void bexec(char *cffile, char *dffile)
{
  FILE *cf_fileptr;
  char  empfaenger[MAIL_ADDR_LEN];


  /* Empfaengeradresse aus cf-Datei einlesen */

  /* cf-Datei oeffnen */
  cf_fileptr = fopen(cffile, "r");
  if(cf_fileptr == NULL)
  {
    perror("bexec: open cffile");
    exit(EXIT_FAILURE);
  }

  /* Adresse einlesen, Datei schliessen */
  fscanf(cf_fileptr, "%s", empfaenger);
  fclose(cf_fileptr);


  /* Auftrag zur lokalen Weiterverarbeitung an "bexecl" uebergeben */
  bexecl(empfaenger, dffile);


  /* Job-Dateien nach Verarbeitung des Auftrags loeschen */
  unlink(cffile);
  unlink(dffile);
}


/******************************************************************************
 * bprocqueue: Auftraege im Spoolverzeichnis abarbeiten, d.h. "spool"-        *
 *             Verzeichnis durchlaufen, cf<nr> und df<nr>-Auftragsdateien an  *
 *             bexec weitergeben                                              *
 ******************************************************************************/

void bprocqueue()
{
  DIR           *dir;
  struct dirent *entry;

  int   ret;
  int   job_num;
  char  cffile[JOB_FILEPATH_LEN];
  char  dffile[JOB_FILEPATH_LEN];


  /* Spool-Verzeichnis oeffnen */
  dir = opendir("spool");
  if(dir == NULL)
  {
    perror("bprocqueue: opendir");
    exit(EXIT_FAILURE);
  }


  /* "spool"-Verzeichnis durchlaufen */
  while(1)
  {
    /* Naechsten Verzeichniseintrag ermitteln
       s.a. Modul "newjob", Funktion "get_next_number" */
    errno = 0;
    entry = readdir(dir);
    if(entry == NULL) /* Fehler? */
    {
      if(errno != 0)
      {
        perror("bprocqueue: readdir");
        exit(EXIT_FAILURE);
      }
      else break; /* Kein Fehler, Verzeichnis ausgelesen */
    }

    if(entry->d_name[0] != 'c') continue; /* Kein c...-Datei */

    if(strlen(entry->d_name) != 6) continue; /* keine cfxxxx-Datei */


    /* Job-Nummer aus Dateiname ermitteln */
    ret = sscanf(entry->d_name, "cf%d", &job_num);
    if(ret != 1) /* Fehler bei der Konvertierng */
    {
       printf("bprocqueue: ungueltige Datei \"%s\" im spool-Verzeichnis\n",  entry->d_name);
       printf("Datei wird ignoriert\n");
       continue; /* Ungueltige Datei ignorieren, mit naechster Datei fortfahren */
    }

    /* Job-Dateinamen aus Job-Nummer generieren */
    sprintf(cffile, "spool/cf%04d", job_num);
    sprintf(dffile, "spool/df%04d", job_num);

    bexec(cffile, dffile);
  }

  closedir(dir);
}
