#include "dialer.h"

  typedef struct {
	  ULONG med_Entries;
	  struct ExAllData med_Data[100];
  } MyExAllBuf_t;

MyExAllBuf_t ead1, ead2;

static UBYTE fileNameBuffer[FILENAME_BUF_SIZE];

static const UBYTE EndOfTrans[] =
{
	HSHAKE_EOT, '\r'
};

static int ProcessExAllBuffer(PagerService_t * svc, STRPTR spoolDir, MyExAllBuf_t * edata, ULONG *sentCount)
{
	struct ExAllData *ead;
	int result;

	result = 0;

	if (edata->med_Entries) {
		if (strlen(spoolDir) + 16 > sizeof(fileNameBuffer)) {
			ErrorMsg("spool filename too long.");
			ULog(ph, -1, "spool filename too long.");
			return 5;
		}

		ead = edata->med_Data;

		while (ead && !result) {
			strcpy(fileNameBuffer, spoolDir);
			AddPart(fileNameBuffer, ead->ed_Name, sizeof(fileNameBuffer));

			result = SendSpoolFile(svc, fileNameBuffer);

			if (!result)
				*sentCount += 1;

			ead = ead->ed_Next;
		}
	}

	return result;
}

static const UBYTE WildCards[] = "#[0-9A-Z]";
static UBYTE Pattern[sizeof(WildCards) * 2 + 2];

int DoOneService(STRPTR serviceName, BOOL oneShot)
{
	STRPTR spoolDir;
	BPTR spoolLock;
	struct ExAllControl *eac;
	MyExAllBuf_t *eadata, *ead;
	PagerService_t *svc;
	int more;
	int result;
	ULONG sentCount, totalSentCount;

	totalSentCount = 0;
	result = 5;

	if (svc = FindPagerService(ph, serviceName)) {
		SetLogService(ph, svc->svc_Name);

		/*
		 * we lock on the service's name to insure that concurrent
		 * dialers don't try to call the same service at the same
		 * time.
		 */

		if (LockFile(ph, svc->svc_Name)) {
			if (spoolDir = NameInSpool(ph, svc->svc_Name)) {
				if (spoolLock = Lock(spoolDir, ACCESS_READ)) {
					if (ParsePatternNoCase((STRPTR)WildCards, Pattern, sizeof(Pattern)) >= 0) {
						if (eac = (struct ExAllControl *)AllocDosObject(DOS_EXALLCONTROL, TAG_DONE)) {

							sentCount = 1;	/* so that we enter the
									 * loop the first time */

							result = 0;

							/*
							 * we loop looking
							 * for files until
							 * there are none
							 * more left to send.
							 * this way, if more
							 * files are spooled
							 * for a service
							 * while we are
							 * on-line talking to
							 * it, we'll pick
							 * them up this call
							 * rather than having
							 * to dial in a
							 * second time.
							 */

							while (sentCount && !result) {
								sentCount = 0;

								eac->eac_LastKey = 0;
								eac->eac_Entries = 0;
								eac->eac_MatchString = Pattern;
								eac->eac_MatchFunc = NULL;

								ead1.med_Entries = 0;
								ead2.med_Entries = 0;

								ead = &ead2;	/* next buffer to be
										 * filled */
								eadata = &ead1;	/* buffer to be
										 * processed */

								do {
									more = ExAll(spoolLock, ead->med_Data, sizeof(ead->med_Data) - 200, ED_TYPE, eac);
									if (!more) {
										if (IoErr() != ERROR_NO_MORE_ENTRIES) {
											ErrorMsg("ExAll failed %ld.", IoErr());
											ULog(ph, -1, "ExAll failed %ld.", IoErr());
											result = 10;
											break;
										}
									}

									ead->med_Entries = eac->eac_Entries;

									if (result = ProcessExAllBuffer(svc, spoolDir, eadata, &sentCount)) {
										if (more) {
											ExAllEnd(spoolLock, ead->med_Data, sizeof(ead->med_Data) - 200, ED_TYPE, eac);
											more = 0;
										}
									}
									else {
										if (eadata == &ead1) {
											eadata = &ead2;
											ead = &ead1;
										}
										else {
											eadata = &ead1;
											ead = &ead2;
										}
									}
								} while (more);

								if (!result)
									result = ProcessExAllBuffer(svc, spoolDir, eadata, &sentCount);

								totalSentCount += sentCount;
							}

							FreeDosObject(DOS_EXALLCONTROL, eac);
						}
						else
							ErrorMsg("out of memory!");
					}
					else {
						ErrorMsg("ParsePatternNoCase() failed.");
						ULog(ph, -1, "ParsePatternNoCase() failed.");
					}

					UnLock(spoolLock);
				}
				else {
					ErrorMsg("couldn't lock spool directory.");
					ULog(ph, -1, "couldn't lock spool directory.");
				}

				FreeNameInSpool(spoolDir);
			}
			else
				ErrorMsg("out of memory!");

			UnLockFile(ph, svc->svc_Name);
		}
		else {
			ErrorMsg("service lock failed.");
			ULog(ph, -1, "service lock failed.");
		}

		FreePagerService(svc);
	}
	else if (oneShot) {
		ErrorMsg("couldn't find \"%s\" service.", serviceName);
		ULog(ph, -1, "couldn't find \"%s\" service.", serviceName);
	}

	/*
	 * make sure that we always hang up after processing a service.  if
	 * we can't reopen but are a oneShot call then we don't care about
	 * the error since it doesn't affect us and the cleanup code will
	 * know how to deal with it.  if we're not oneShot, though, a failure
	 * to reopen the device means subsequence services would fail when
	 * trying to connect so we return an error in this case.
	 */

	if (online) {
		SerWrite((STRPTR)EndOfTrans, sizeof(EndOfTrans));

		if (!HangUp() && !oneShot) {
			ErrorMsg("couldn't reopen modem %ld after hangup.", openedModem);
			ULog(ph, -1, "couldn't reopen modem %ld after hangup.", openedModem);
			result = 5;
		}

		ULog(ph, -1, "connection terminated");
	}

	if (totalSentCount)
		ULog(ph, -1, "%ld message%s delivered this call", totalSentCount, totalSentCount == 1 ? "" : "s");

	SetLogService(ph, NULL);

	return result;
}

struct ExAllData eaBuf[100];

int DoAllServices(void)
{
	STRPTR spoolDir;
	BPTR spoolLock;
	struct ExAllControl *eac;
	struct ExAllData *exdata, fakeExdata;
	int more;
	PagerService_t *svc;
	int result;

	result = 10;

	fakeExdata.ed_Next = NULL;

	if (spoolDir = NameInSpool(ph, NULL)) {
		if (spoolLock = Lock(spoolDir, ACCESS_READ)) {
			if (eac = (struct ExAllControl *)AllocDosObject(DOS_EXALLCONTROL, TAG_DONE)) {
				eac->eac_LastKey = 0;
				eac->eac_Entries = 0;
				eac->eac_MatchString = NULL;
				eac->eac_MatchFunc = NULL;

				result = 0;

				do {
					more = ExAll(spoolLock, eaBuf, sizeof(eaBuf) - 200, ED_TYPE, eac);
					if (!more) {
						if (IoErr() != ERROR_NO_MORE_ENTRIES) {
							ErrorMsg("ExAll failed %ld.", IoErr());
							ULog(ph, -1, "ExAll failed %ld.", IoErr());
							result = 10;
							break;
						}
					}

					if (eac->eac_Entries) {
						exdata = eaBuf;

						while (exdata) {
							if (exdata->ed_Type > 0)
								if (svc = FindPagerService(ph, exdata->ed_Name)) {
									if (result = DoOneService(svc->svc_Name, FALSE)) {
										if (more) {
											ExAllEnd(spoolLock, eaBuf, sizeof(eaBuf) - 200, ED_TYPE, eac);
											more = 0;
										}

										exdata = &fakeExdata;
									}

									FreePagerService(svc);
								}

							exdata = exdata->ed_Next;
						}
					}
				} while (more);

				FreeDosObject(DOS_EXALLCONTROL, eac);
			}
			else
				ErrorMsg("out of memory!");

			UnLock(spoolLock);
		}
		else {
			ErrorMsg("couldn't lock spool directory.");
			ULog(ph, -1, "couldn't lock spool directory.");
		}

		FreeNameInSpool(spoolDir);
	}
	else
		ErrorMsg("out of memory!");

	return result;
}
