//
// junkmail.c by Alan Bland  9/25/92
//
// Sample source file for sending mail from a shell command.
//
// Requirements:  SAS/C 5.10b, Xenolink Z.3a
//
// This source file is public domain and may be used for any purpose
// without permission of the author.  The author claims no responsibility
// for the consequences of using this program.
//

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <exec/types.h>
#include <exec/ports.h>
#include <exec/io.h>
#include <exec/semaphores.h>
#include <exec/libraries.h>
#include <dos/dos.h>
#include <proto/dos.h>
#include <proto/exec.h>
#include "xenolink.h"


struct XenolinkBase  *XenolinkBase;

#define MAX_ATTACH 30
#define MAX_RECIPIENTS 500
char *j_from = NULL;
char *j_to[MAX_RECIPIENTS];
short j_next_recipient = 0;
char *j_subject = NULL;
char *j_input = NULL;
char j_private = 0;
char *j_attach[MAX_ATTACH];
short j_next_attach = 0;
short j_base = -1;

int CXBRK(void) { return 0; }
int chkabort(void) { return 0; }

char *readinputfile(char *filename)
{
	char *text;
	char *bp;
	FILE *f;
	struct stat st;

	// get file size and read in the file, converting \n to \r\n (hard newline)
	if (stat(filename, &st) != 0) {
		printf("File '%s' not found\n", filename);
		return NULL;
	}
	// malloc an extra 4K to allow for \n to \r\n expansion
	// SAS/C automatically frees this on exit
	text = calloc(1, st.st_size + 4096);
	if (!text) {
		printf("Can't allocate %d bytes\n", st.st_size + 4096);
		return NULL;
	}

	f = fopen(filename, "r");
	if (!f) {
		printf("Can't open '%s'\n", filename);
		return NULL;
	}
	bp = text;
	while (fgets(bp, 1000, f)) {
		// fgets ends with \n, find it and convert
		while (*bp && *bp != '\n') ++bp;
		if (*bp) {
			*bp++ = '\r';
			*bp++ = '\n';
		}
	}
	fclose(f);
	return text;
}

//
// This function does all the nitty-gritty stuff for sending a message.
//
void xeno_send(char *from, char *to, char *MessageText, char *subject, short base,
	  short private, char *attach[], short num_attach)
{
	struct Msg SaveMsg;
	struct MsgSection *MsgSect;
	struct ManagerSaveMsgCommand SaveCommand;
	struct FidoNetAddress destination;
	int i;

	/* Start with a clean slate. */
	ulibClearMem((void *)&SaveMsg, sizeof(SaveMsg));

	MsgSect = ulibGetMsgSectionInfo(base);
	if (!MsgSect) {
		printf("Base %d is invalid\n", base);
		return;
	}

	SaveMsg.Section = base;
	SaveMsg.Flags.Private = private;
	strncpy(SaveMsg.Subject, subject, SUBJECT_LENGTH);
	strncpy(SaveMsg.From, from, USERNAME_LENGTH);

	// copy recipient name, parsing out the netmail address if specified
	ulibClearMem((void *)&destination, sizeof(destination));
	for (i=0; i<USERNAME_LENGTH; ++i) {
		if (to[i] == '@') {
			destination.Zone = MsgSect->Zone;
			if (ulibParseFidoNetAddress(&to[i+1], &destination)) {
				printf("Fidonet address is invalid\n");
				return;
			}
			SaveMsg.To[i] = 0;
			break;
		}
		SaveMsg.To[i] = to[i];
		if (!to[i]) break;
	}

	/* Date sent */
	ulibStoreTodaysDate(&SaveMsg.DateSent);

	/* Convert JONATHAN FORBES to Jonathan Forbes, etc. */
	ulibNiceName(SaveMsg.To);
	ulibNiceName(SaveMsg.From);

	/* Netmail stuff -- could change this to get aka address for Orig... */
	SaveMsg.OrigZone  = MsgSect->Zone;
	SaveMsg.OrigNet   = MsgSect->Net;
	SaveMsg.OrigNode  = MsgSect->Node;
	SaveMsg.OrigPoint = 0;
	SaveMsg.DestZone  = destination.Zone;
	SaveMsg.DestNet   = destination.Net;
	SaveMsg.DestNode  = destination.Node;
	SaveMsg.DestPoint = destination.Point;

	/* Better make sure destination address was given if this is netmail */
	if (MsgSect->MsgSectionFlags.NetMail && destination.Zone == 0) {
		printf("Destination address required for netmail section\n");
		return;
	}
	
	/* Clear this structure so that no flags or anything else are set */
	ulibClearMem((void *) &SaveCommand, sizeof(struct ManagerSaveMsgCommand));

	SaveCommand.SaveMessage = &SaveMsg;
	SaveCommand.Message     = (void *) MessageText;

	/* Construct Fidonet tag line */
	SaveCommand.Flags.AppendOrigin = 1;
	SaveCommand.Flags.CustomTagLine = 0;
	SaveCommand.Flags.AddWaitingMessage = 1;
	SaveCommand.Flags.AppendNetInfo = 1;
	SaveCommand.SaveType = SAVETYPE_PROGRAM;

	/* If SaveCommand.TextLength equals zero, then MT will perform a    */
	/* strlen() on your text to see how long it is.  If TextLength is   */
	/* nonzero, then MT will use that value of TextLength as the length */
	/* of the message text.  This is simply a minor optimisation if you */
	/* happen to know the length of your message beforehand.            */
	SaveCommand.TextLength       = 0;

	if (num_attach > 0) {
		ulibSetMsgData(&SaveMsg, XMD_FLAGS_FILE_ATTACHED, 1);
	}

	ulibSaveMessage(&SaveCommand);

	// NOTE: we do not update message counts written by the user!

	if (num_attach > 0) {
		char attname[100];
		FILE *wp;
		sprintf(attname, "%s%d.%d.attach", MsgSect->MsgSecDir,
			base, SaveMsg.Number);
		wp = fopen(attname, "w");
		if (wp) {
			for (i=0; i<num_attach; ++i) {
				fprintf(wp, "%s\n", attach[i]);
			}
			fclose(wp);
		}
	}
	printf("ok\n");
}

void usage(void)
{
 printf("\nUsage: junkmail <options>\n\n"
	"Required:\n"
	"  -f user     Name of message author\n"
	"  -t user     Name of message recipient (may be specified more than once)\n"
	"              For netmail recipients, include netmail address as follows:\n"
	"              -t \"The Cyborg@1:104/121.0\"  (all one quoted string)\n"
	"  -s subject  Subject of message\n"
	"  -i file     Input file containing message text\n"
	"  -b number   Number of message base to deposit message\n"
	"\nOptional:\n"
	"  -p          Private (default is public)\n"
	"  -a file     File to attach (may be specified more than once)\n"
	"\n");

 exit(1);
}

void checkarg(char *opt, char *arg)
{
	if (!arg || *arg == '-') {
		printf("%s requires an argument\n", opt);
		usage();
	}
}

void main(int argc, char *argv[])
{
	int i;
	char *text;
    
	// Parse the command line by brute force.
	for (i=1; i<argc; ++i) {
		char *opt;
		char *arg;

		opt = argv[i];
		if (i < argc-1) {
			arg = argv[i+1];
		} else {
			arg = NULL;
		}

		if (strcmp(opt, "-f") == 0) {
			checkarg(opt, arg);
			if (j_from) {
				printf("Too many cooks!\n");
				usage();
			}
			j_from = arg;
			++i;
		}
		else if (strcmp(opt, "-t") == 0) {
			checkarg(opt, arg);
			if (j_next_recipient < MAX_RECIPIENTS) {
				j_to[j_next_recipient++] = arg;
			} else {
				printf("Too many recipients!\n");
				usage();
			}
			++i;
		}
		else if (strcmp(opt, "-s") == 0) {
			checkarg(opt, arg);
			if (j_subject) {
				printf("What's the real subject?\n");
				usage();
			}
			j_subject = arg;
			++i;
		}
		else if (strcmp(opt, "-p") == 0) {
			j_private = 1;
		}
		else if (strcmp(opt, "-a") == 0) {
			FILE *f;
			checkarg(opt, arg);
			f = fopen(arg, "r");
			if (!f) {
				printf("Cannot attach '%s'\n", arg);
				usage();
			}
			fclose(f);
			if (j_next_attach < MAX_ATTACH) {
				j_attach[j_next_attach++] = arg;
			} else {
				printf("Too many file attaches!\n");
				usage();
			}
			++i;
		}
		else if (strcmp(opt, "-i") == 0) {
			checkarg(opt, arg);
			if (j_input) {
				printf("Only one input file, please!\n");
				usage();
			}
			j_input = arg;
			++i;
		}
		else if (strcmp(opt, "-b") == 0) {
			checkarg(opt, arg);
			if (j_base >= 0) {
				printf("Only one message base, please!\n");
				usage();
			}
			j_base = atoi(arg);
			++i;
		}
		else {
			printf("Unrecognized option: %s\n", opt);
			usage();
		}
	}

	if (!j_from || j_next_recipient < 1 || !j_subject || !j_input || j_base < 0) {
		usage();
	}

	if ((text = readinputfile(j_input)) == NULL) {
		usage();
	}

	XenolinkBase = (struct XenolinkBase *) OpenLibrary("xenolink.library", 0);
	if (!XenolinkBase) {
		printf("Where's xenolink.library?\n");
		exit(1);
	}


#if DEBUG
printf("Base: %d\n", j_base);
printf("%s\n", j_private ? "Private" : "Public");
printf("From: %s\n", j_from);
for (i=0; i<j_next_recipient; ++i) printf("  To: %s\n", j_to[i]);
printf("Subj: %s\n", j_subject);
for (i=0; i<j_next_attach; ++i) printf(" Att: %s\n", j_attach[i]);
#endif


	// Send the message to each recipient.
	for (i=0; i<j_next_recipient; ++i) {
		printf("Sending to %s...", j_to[i]);
		xeno_send(j_from, j_to[i], text, j_subject, j_base, j_private,
			  j_attach, j_next_attach);
	}

	CloseLibrary((struct Library *) XenolinkBase);
	exit(0);
}


