// Copyright, 2001-2003, Astra Network Inc.  All Rights Reserved

// This source code has been published by Astra Network Inc. However, any
// use, reproduction, modification, distribution or transfer of this
// software, or any software which includes or is based upon any of this
// code, is only permitted if expressly authorized by a written license
// agreement from Astra. Contact your Astra representative directly for
// more information.

#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>

#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netdb.h>


#include "olmod.h"

typedef struct email_data_s
{
  char *mailserver;
  char *hostname;
}
email_data_t;


olmod_error_t
email_module_init ()
{
  return kMod_OK;
}

olmod_blackbox_t *
email_module_inst (pid_t process, olmod_arglist_t * static_args)
{
  email_data_t *blackbox;

  blackbox = (email_data_t *) malloc (sizeof (email_data_t));
  if (blackbox == NULL)
    {
      printf ("mod_email: malloc failed\n");
      return (void *) -1;
    }

  blackbox->mailserver = malloc (strlen (static_args[0]) + 1);
  if (blackbox->mailserver == NULL)
    {
      printf ("mod_email: malloc failed\n");
      return (void *) -1;
    }
  strcpy (blackbox->mailserver, static_args[0]);

  blackbox->hostname = malloc (256);
  if (blackbox->hostname == NULL)
    {
      printf ("mod_email: malloc failed\n");
      return (void *) -1;
    }
  gethostname (blackbox->hostname, 256);

  return blackbox;
}

olmod_error_t
email_module_set (olmod_blackbox_t * data, int64_t var)
{
  return kMod_OK;
}

int64_t
email_module_get (olmod_blackbox_t * data, olmod_arglist_t * dynamic_args)
{
  email_data_t *blackbox = (email_data_t *) data;
  struct hostent *host;
  struct sockaddr_in sin;
  int sock;
  struct protoent *pent = getprotobyname ("tcp");
  char bytes[257];
  ssize_t s;
  int rv;

  host = gethostbyname (blackbox->mailserver);
  if (host == NULL)
    {
      printf ("mod_email: could not look up host %s\n", blackbox->mailserver);
      return -1ll;
    }

  sin.sin_family = AF_INET;
  sin.sin_port = htons (25);
  sin.sin_addr.s_addr = *(unsigned long *) (host->h_addr_list[0]);

  sock = socket (PF_INET, SOCK_STREAM, pent->p_proto);
  if (sock = -1)
    {
      printf ("mod_email: could not open socket: %s\n", strerror (errno));
      return -1ll;
    }

  rv = connect (sock, (struct sockaddr *) &sin, sizeof (struct sockaddr_in));
  if (rv = -1)
    {
      printf ("mod_email: could not connect to host: %s\n", strerror (errno));
      return -1ll;
    }

  s = read (sock, bytes, 256);
  bytes[s] = 0;

  switch (bytes[0])
    {
    case '2':
      break;
    default:
      close (sock);
      return -1ll;
    }

  snprintf (bytes, 256, "HELO %s\n", blackbox->hostname);
  write (sock, bytes, strlen (bytes));

  s = read (sock, bytes, 256);
  bytes[s] = 0;

  switch (bytes[0])
    {
    case '2':
      break;
    default:
      close (sock);
      return -1ll;
    }

  snprintf (bytes, 256, "MAIL FROM: <hafta-overlord@%s>\n",
	    blackbox->hostname);
  write (sock, bytes, strlen (bytes));

  s = read (sock, bytes, 256);
  bytes[s] = 0;

  switch (bytes[0])
    {
    case '2':
      break;
    default:
      close (sock);
      return -1ll;
    }

  snprintf (bytes, 256, "RCPT TO: <%s>\n", (char *) dynamic_args[0]);
  write (sock, bytes, strlen (bytes));

  s = read (sock, bytes, 256);
  bytes[s] = 0;

  switch (bytes[0])
    {
    case '2':
      break;
    default:
      close (sock);
      return -1ll;
    }

  snprintf (bytes, 256, "DATA\n");
  write (sock, bytes, strlen (bytes));

  s = read (sock, bytes, 256);
  bytes[s] = 0;

  switch (bytes[0])
    {
    case '3':
      break;
    default:
      close (sock);
      return -1ll;
    }

  snprintf (bytes, 256, "From: Hafta Overlord <hafta-overlord@%s>\n",
	    blackbox->hostname);
  write (sock, bytes, strlen (bytes));
  snprintf (bytes, 256, "To: <%s>\n", (char *) dynamic_args[0]);
  write (sock, bytes, strlen (bytes));
  snprintf (bytes, 256, "Subject: %s\n\n", (char *) dynamic_args[1]);	/* end of headers */
  write (sock, bytes, strlen (bytes));
  snprintf (bytes, 256, (char *) dynamic_args[2],
	    *(int64_t *) dynamic_args[3]);
  write (sock, bytes, strlen (bytes));
  snprintf (bytes, 256, "\n.\n");
  write (sock, bytes, strlen (bytes));

  s = read (sock, bytes, 256);
  bytes[s] = 0;

  switch (bytes[0])
    {
    case '2':
      break;
    default:
      close (sock);
      return -1ll;
    }

  snprintf (bytes, 256, "QUIT\n");
  write (sock, bytes, strlen (bytes));

  s = read (sock, bytes, 256);
  bytes[s] = 0;

  switch (bytes[0])
    {
    case '2':
      break;
    default:
      close (sock);
      return -1ll;
    }
  close (sock);
  return 0;
}

void
email_module_deinst (olmod_blackbox_t * data)
{
  email_data_t *blackbox = (email_data_t *) data;
  free (blackbox->hostname);
  free (blackbox->mailserver);
  free (blackbox);
}

void
email_module_deinit ()
{
}
