#ifdef MACVERSION
	#include <string.h>
	#include <standard.h>
#endif

#ifdef WIN95VERSION
	#include "standard.h"
	//#include <stdlib.h>
#endif

#include "error.h"
#include "memory.h"
#include "ops.h"
#include "dialogs.h"
#include "strings.h"
#include "serialnumber.h"
#include "lang.h"
#include "winsocknetevents.h"
#include "tablestructure.h"
#include "file.h"
#include "launch.h"

#ifndef fltrialsize
	#ifdef PIKE
		#define useSerialNumber 0
	#else
		#define useSerialNumber 0	//9.0b1 JES: Disable serial number check -- now happens in script
	#endif
#else
	#define useSerialNumber 0
#endif


#if useSerialNumber
#pragma message ("************************* Serial Number Check is ON ***********************************")
#else
#pragma message ("************************* Serial Number Check is OFF ***********************************")
#endif


#define snoptions_usefile 512
#define snoptions_multicopycheck 256
#define snoptions_trial 128
#define snoptions_startupcheck 64
#define snoptions_periodiccheck 32
#define snoptions_getfile 16
#define snoptions_connectionlimit 8
#define snoptions_disablescriptdebugger 4
#define snoptions_disableTCPIP 2
#define snoptions_softhard 1
#define snoptions_offset 100


typedef struct serialnumber {

	short d1, d2, d3, d4, d5, d6, p1, p2, p3, p4, v1, v2, c1, c2, c3, c4, o1, o2, o3, o4;
	} tyserialnumber;

typedef struct tyserialnumberinfo {
	boolean useFile;
	boolean getFile;
	boolean trial;
	boolean multiCopyCheck;
	boolean startupCheck;
	boolean periodicCheck;
	boolean connectionLimit;
	boolean disableScriptDebugger;
	boolean disableTCPIP;
	boolean useSoftCheck;
	} tyserialnumberinfo;

tyserialnumberinfo sninfo;

static short asciiCharToB34 (short c) {

	/*
	Base 34 0-9 A-Z less I and 0
	*/
	
	if ((c >= '0') && (c <= '9'))
		return (c - '0');
	
	if ((c >= 'A') && (c <= 'H'))
		return (c - 'A') + 10;

	if ((c >= 'J') && (c <= 'N'))
		return (c - 'A') + 9;
	
	if ((c >= 'P') && (c <= 'Z'))
		return (c - 'A') + 8;
	
	return (-1);
	} /*asciiCharToB34*/

// Reflection is a requirement for the official CRC-32 standard.
// You can create CRCs without it, but they won't conform to the standard.
static unsigned long crcReflect(unsigned long ref, char ch) {
	unsigned long value;
	int i;

	value = 0;

	// Swap bit 0 for bit 7, bit 1 for bit 6, etc.

	for (i = 1; i < (ch + 1); i++) {
		if(ref & 1)
			value |= 1 << (ch - i);
		ref >>= 1;
		}
	return value;
} /*crcReflect*/


static unsigned long * calcCRCTable(unsigned long * crc32table, boolean flReflect) {
	int i, j;
	unsigned long CRC32;
	CRC32 = 79764919;  //This is a standard CRC number.
	if (flReflect) {
		//Code with reflect
	// 256 values representing ASCII character codes.
		for(i = 0; i <= 255; i++) {
			crc32table[i]= crcReflect(i, 8) << 24;
			for (j = 0; j < 8; j++)
				crc32table[i] = (crc32table[i] << 1) ^ (crc32table[i] & (1 << 31) ? CRC32 : 0);
			crc32table[i] = crcReflect(crc32table[i], 32);
			}
		}
	else {
		//Code without reflect
		for (i = 0; i <= 255; i++) {
			crc32table[i] = i;
			for (j = 0; j < 8; j++)
				crc32table[i] = (crc32table[i] >> 1) ^ (crc32table[i] & (1) ? CRC32 : 0);
			}
		}

	return (crc32table);
	} /*calcCRCTable*/

unsigned long crc32table[256];

static long crc (bigstring s, boolean flReflect) {
	//This is a 32 bit complient CRC.  It will return the same results as PKZIP, etc. with flReflect true
	//The code uses reflect as mandated by the standard, but includes code for doing CRC without the reflect.

	unsigned long crcResult;
	int i;
	
	calcCRCTable(crc32table, flReflect);
	crcResult = 0xFFFFFFFF;
	
	for (i = 1; i <= stringlength(s); i++) {
		crcResult = (crcResult >> 8) ^ crc32table[(crcResult & 0xFF) ^ s[i]];
		}
	return (crcResult ^ 0xFFFFFFFF);
	}/*crc*/

static unsigned long genCRC (bigstring s, boolean flReflect) {
	long crcResult;
	crcResult = crc (s, flReflect);
	crcResult = abs (crcResult);
	crcResult = crcResult % 1336336; //this is 34^4
	return (crcResult);
	}/*genCRC*/

static boolean validNumber (tyserialnumber *sn, long base, short baseoffset) {
	
	long sum;
	short digitValue;
	
	sum = 0;
	
	digitValue = asciiCharToB34 (sn->d1);
	if (digitValue == -1)
		return false;
	sum = sum + digitValue;
	
	digitValue = asciiCharToB34 (sn->d2);
	if (digitValue == -1)
		return false;
	sum = sum + (digitValue * base);
	
	digitValue = asciiCharToB34 (sn->d3);
	if (digitValue == -1)
		return false;
	sum = sum + (digitValue * (base * base));
	
	digitValue = asciiCharToB34 (sn->d4);
	if (digitValue == -1)
		return false;
	sum = sum + (digitValue * (base * base * base));
	
	digitValue = asciiCharToB34 (sn->d5);
	if (digitValue == -1)
		return false;
	sum = sum + (digitValue * (base * base * base * base));
	
	digitValue = asciiCharToB34 (sn->d6);
	if (digitValue == -1)
		return false;
	sum = sum + (digitValue * (base * base * base * base * base));
	
	sum = sum - baseoffset;
	if ((sum % 7) != 0)
		return false;
	return true;
	} /*validNumber*/


static boolean compareChecksums (tyserialnumber *sn) {

	long checksum1, checksum2;
	short digitValue;
	
	checksum1 = 0;
	checksum2 = 0;
	
	bundle { //calculate checksum1
	
		digitValue = asciiCharToB34 (sn->d6);
		if (digitValue == -1)
			return (false);
		checksum1 = checksum1 + (digitValue * 9);;
		
		digitValue = asciiCharToB34 (sn->d5);
		if (digitValue == -1)
			return (false);
		checksum1 = checksum1 + (digitValue * 8);;
		
		digitValue = asciiCharToB34 (sn->d4);
		if (digitValue == -1)
			return (false);
		checksum1 = checksum1 + (digitValue * 7);;
		
		digitValue = asciiCharToB34 (sn->d3);
		if (digitValue == -1)
			return (false);
		checksum1 = checksum1 + (digitValue * 6);;
		
		digitValue = asciiCharToB34 (sn->d2);
		if (digitValue == -1)
			return (false);
		checksum1 = checksum1 + (digitValue * 5);;
		
		digitValue = asciiCharToB34 (sn->d1);
		if (digitValue == -1)
			return (false);
		checksum1 = checksum1 + (digitValue * 4);;
		
		digitValue = asciiCharToB34 (sn->p2);
		if (digitValue == -1)
			return (false);
		checksum1 = checksum1 + (digitValue * 3);;
		
		digitValue = asciiCharToB34 (sn->p1);
		if (digitValue == -1)
			return (false);
		checksum1 = checksum1 + (digitValue * 2);;
		
		digitValue = asciiCharToB34 (sn->v1);
		if (digitValue == -1)
			return (false);
		checksum1 = checksum1 + digitValue;;
		
		checksum1 = checksum1 % 1000;
		}
	
	bundle { //calculate checksum2
		if ((sn->c1 < '0') || (sn->c1 > '9'))
			return false;
		checksum2 = checksum2 + (sn->c1 - '0');
		
		if ((sn->c2 < '0') || (sn->c2 > '9'))
			return false;
		checksum2 = checksum2 + ((sn->c2 - '0') * 10);
		
		if ((sn->c3 < '0') || (sn->c3 > '9'))
			return false;
		checksum2 = checksum2 + ((sn->c3 - '0') * 100);
		}
	
	return (checksum1 == checksum2);
	} /*compareChecksums*/


static long getNumberFromBuffer (Handle hbuffer, long startpos) {
	long res;
	boolean flStart, negative;
	char c;

	flStart = true;
	negative = false;
	res = 0;
	//get number from buffer
	while (true)
		{
		c = (*hbuffer)[startpos++];

		if ((c == ' ') && flStart)
			continue;

		if ((c == '-') && flStart)
			{
			negative = true;

			continue;
			}

		flStart = false;

		if ((c < '0') || (c > '9'))
			break;

		res = (res * 10) + (c - '0');
		}

	if (negative)
		res = res * -1;

	return (res);
	} /*getNumberFromBuffer*/


#ifdef restorestoreNOT

static boolean contactStoreServer (bigstring s, long * daysleft) {

	/*
	1/22/02 dmb: disabled store contact
	*/

	unsigned long stream;
	byte server[] = "\x12" "store.userland.com";
	byte httpRequest1[] = "POST /RPC2 HTTP/1.0\r\nUser-Agent: Frontier/7.0\r\nHost: store.userland.com\r\nContent-Type: text/xml\r\nContent-length: ";
	byte httpRequest2[] = "\r\n\r\n";
	byte httpRequest3[] = "<?xml version=\"1.0\"?>\r\n<methodCall>\r\n\t<methodName>ordersystem.isSerialNumberValid</methodName>\r\n\t<params>\r\n";
	byte httpRequest4[] = "\t\t<param>\r\n\t\t\t<value>";
	byte httpRequest5[] = "</value>\r\n\t\t\t</param>\r\n";
	byte httpRequest8[] = "\t\t</params>\r\n\t</methodCall>\r\n\r\n";

#ifdef PIKE
	byte product[] = "Radio";
#elif defined(ALBERT)
	byte product[] = "Albert";
#else
	byte product[] = "Frontier";
#endif

#ifdef WIN95VERSION
	byte platform[] = "Windows";
#endif

#ifdef MACVERSION
#if TARGET_API_MAC_CARBON == 1
	byte platform[] = "Macintosh OS-X";
#else
	byte platform[] = "Macintosh";
#endif
#endif

	unsigned long bytesPending;
	bigstring httpRequestContentLen;
	bigstring myAddressString;
	bigstring bsversion, bsosversion, bsosextrainfo;
	Handle hpattern = NULL;
	Handle hbuffer = NULL;
	Handle hrequest = NULL;
	char * requestbuffer;
	long headerSize;
	long i, ix, iy, myAddress;
	long totalSize;
	byte contentLengthString[] = "Content-Length: ";
	long contentLength;
	byte methodResponseString[] = "<methodResponse>";
	byte paramsString[] = "<params>";
	byte paramString[] = "<param>";
	byte valueString[] = "<value>";
	byte valueCloseString[] = "</value>";
	byte I4String[] = "<i4>";
	byte I4CloseString[] = "</i4>";
	boolean res = false;
	long len4, len5;

	
	myAddress = 0;
	fwsNetEventMyAddress (&myAddress);
	fwsNetEventAddressDecode (myAddress, myAddressString);

	filegetprogramversion (bsversion);

	getsystemversionstring (bsosversion, bsosextrainfo);

	if (fwsNetEventOpenNameStream (server, 80, &stream))
		{
		//BUILD AND SEND THE xml-rpc REQUEST 
		//Built from httpRequest parts:  
		// 1 + content length + 2 + 3 + 4 + serial number + 5 + 4 + IP Address + 5 + 8
		// 1 + content length + 2 + 3 + 4 + serial number + 5 + 8  -- without second param
		//
		// content length = 3 + 4 + serial number + 5 + 6 + IP Address + 7 + 8

		len4 = strlen (httpRequest4);
		len5 = strlen (httpRequest5);

		bytesPending = strlen (httpRequest3); 
		bytesPending += len4 + stringlength(s) + len5; //param 1 - S/N
		bytesPending += len4 + stringlength(myAddressString) + len5; //param 2 - TCP/IP
		bytesPending += len4 + strlen(product) + len5; //param 3 - Product
		bytesPending += len4 + stringlength(bsversion) + len5; //param 4 - Version
		bytesPending += len4 + strlen(platform) + len5; //param 5 - Platform
		bytesPending += len4 + stringlength(bsosversion) + len5; //param 6 - Platform Version
		bytesPending += len4 + stringlength(bsosextrainfo) + len5; //param 7 - Platform Version Extra Info
		bytesPending += strlen (httpRequest8);

		numbertostring (bytesPending, httpRequestContentLen);

		bytesPending += strlen (httpRequest1) + stringlength (httpRequestContentLen) + strlen (httpRequest2);

		if (newhandle (bytesPending, &hrequest))
			{
			lockhandle (hrequest);
			
			requestbuffer = *hrequest;

			i = strlen (httpRequest1);
			memmove (requestbuffer, httpRequest1, i); 
			requestbuffer += i;

			i = stringlength (httpRequestContentLen);
			memmove (requestbuffer, stringbaseaddress(httpRequestContentLen), i); 
			requestbuffer += i;

			i = strlen (httpRequest2);
			memmove (requestbuffer, httpRequest2, i); 
			requestbuffer += i;

			i = strlen (httpRequest3);
			memmove (requestbuffer, httpRequest3, i); 
			requestbuffer += i;

			//param 1 - S/N
			memmove (requestbuffer, httpRequest4, len4); 
			requestbuffer += len4;

			i = stringlength (s);
			memmove (requestbuffer, stringbaseaddress(s), i); 
			requestbuffer += i;

			memmove (requestbuffer, httpRequest5, len5); 
			requestbuffer += len5;

			//param 2 - TCP/IP
			memmove (requestbuffer, httpRequest4, len4); 
			requestbuffer += len4;

			i = stringlength (myAddressString);
			memmove (requestbuffer, stringbaseaddress(myAddressString), i); 
			requestbuffer += i;

			memmove (requestbuffer, httpRequest5, len5); 
			requestbuffer += len5;

			//param 3 - Product
			memmove (requestbuffer, httpRequest4, len4); 
			requestbuffer += len4;

			i = strlen(product);
			memmove (requestbuffer, product, i); 
			requestbuffer += i;

			memmove (requestbuffer, httpRequest5, len5); 
			requestbuffer += len5;

			//param 4 - Version
			memmove (requestbuffer, httpRequest4, len4); 
			requestbuffer += len4;

			i = stringlength (bsversion);
			memmove (requestbuffer, stringbaseaddress(bsversion), i); 
			requestbuffer += i;

			memmove (requestbuffer, httpRequest5, len5); 
			requestbuffer += len5;

			//param 5 - Platform
			memmove (requestbuffer, httpRequest4, len4); 
			requestbuffer += len4;

			i = strlen(platform);
			memmove (requestbuffer, platform, i); 
			requestbuffer += i;

			memmove (requestbuffer, httpRequest5, len5); 
			requestbuffer += len5;

			//param 6 - Platform Version
			memmove (requestbuffer, httpRequest4, len4); 
			requestbuffer += len4;

			i = stringlength (bsosversion);
			memmove (requestbuffer, stringbaseaddress(bsosversion), i); 
			requestbuffer += i;

			memmove (requestbuffer, httpRequest5, len5); 
			requestbuffer += len5;

			//param 7 - Platform Version Extra Info
			memmove (requestbuffer, httpRequest4, len4); 
			requestbuffer += len4;

			i = stringlength (bsosextrainfo);
			memmove (requestbuffer, stringbaseaddress(bsosextrainfo), i); 
			requestbuffer += i;

			memmove (requestbuffer, httpRequest5, len5); 
			requestbuffer += len5;

			i = strlen (httpRequest8);
			memmove (requestbuffer, httpRequest8, i); 
		
			//
			//we can use a static string sans the serial number portion.
			//this will allow us to not have to have a build XML step
			if (fwsNetEventWriteStream (stream, bytesPending, *hrequest))
				{
				newemptyhandle (&hbuffer);
				newhandle (4, &hpattern);
				(*hpattern)[0] = '\r';
				(*hpattern)[1] = '\n';
				(*hpattern)[2] = '\r';
				(*hpattern)[3] = '\n';
				// Now read
				
				if (fwsNetEventReadStreamUntil (stream, hbuffer, hpattern, 5))
					{
					headerSize = searchhandle (hbuffer, hpattern, 0, gethandlesize (hbuffer));


					//get the content length from the header
					sethandlesize (hpattern, strlen(contentLengthString));
					memmove (*hpattern, contentLengthString, strlen(contentLengthString));

					ix = searchhandle (hbuffer, hpattern, 0, headerSize);
					if (ix > 1)
						{
						ix = ix + strlen(contentLengthString);

						contentLength = getNumberFromBuffer (hbuffer, ix);
				

						totalSize = contentLength + headerSize + 4;

						if (fwsNetEventReadStreamBytes (stream, hbuffer, totalSize, 5))
							{
							sethandlesize (hpattern, strlen(methodResponseString));
							memmove (*hpattern, methodResponseString, strlen(methodResponseString));
							ix = searchhandle (hbuffer, hpattern, headerSize+4, totalSize);

							if (ix != -1)
								{
								ix += strlen(methodResponseString);

								sethandlesize (hpattern, strlen(paramsString));
								memmove (*hpattern, paramsString, strlen(paramsString));
								ix = searchhandle (hbuffer, hpattern, ix, totalSize);

								if (ix != -1)
									{
									ix += strlen(paramsString);

									sethandlesize (hpattern, strlen(paramString));
									memmove (*hpattern, paramString, strlen(paramString));
									ix = searchhandle (hbuffer, hpattern, ix, totalSize);

									if (ix != -1)
										{
										ix += strlen(paramString);

										sethandlesize (hpattern, strlen(valueString));
										memmove (*hpattern, valueString, strlen(valueString));
										ix = searchhandle (hbuffer, hpattern, ix, totalSize);

										if (ix != -1)
											{
											ix += strlen(valueString);

											sethandlesize (hpattern, strlen(I4String));
											memmove (*hpattern, I4String, strlen(I4String));
											ix = searchhandle (hbuffer, hpattern, ix, totalSize);

											if (ix != -1)
												{
												ix += strlen(I4String);

												sethandlesize (hpattern, strlen(I4CloseString));
												memmove (*hpattern, I4CloseString, strlen(I4CloseString));
												iy = searchhandle (hbuffer, hpattern, ix, totalSize);

												if (iy != -1)
													{
													*daysleft = getNumberFromBuffer (hbuffer, ix);

													res = true;
													}
												}
											}
										}
									}
								}
							}
						}
						
					}
				}

			unlockhandle (hrequest);

			disposehandle (hrequest);

			if (hpattern != NULL)
				disposehandle (hpattern);

			if (hbuffer != NULL)
				disposehandle (hbuffer);
			}
		fwsNetEventCloseStream (stream);
		}

	return (res);
	} /*contactStoreServer*/

#endif


static boolean isValidSerialNumber1 (bigstring s) {

	/*
	1/22/02 dmb: disabled store contact
	
	2002-10-13 AR: ifdef'd out variable declaration for daysleft
	to eliminate a compiler warning about an unused variable
	*/

	long base = 34;	
	tyserialnumber sn;
	#ifdef restorestoreNOT
		long daysleft;
	#endif
	
	
	if (stringlength(s) != 14)
		return false;
	
	if (s[5] != '-')
		return false;
	
	if (s[10] != '-')
		return false;
	
	sn.d1 = s[7];
	sn.d2 = s[4];
	sn.d3 = s[14];
	sn.d4 = s[8];
	sn.d5 = s[3];
	sn.d6 = s[13];
	sn.p1 = s[2];
	sn.p2 = s[1];
	sn.v1 = s[11];
	sn.c1 = s[6];
	sn.c2 = s[12];
	sn.c3 = s[9];
	
	if (!validNumber(&sn, base, 3))
		return false;
	
	if (compareChecksums(&sn)) {

		#ifdef restorestoreNOT
			contactStoreServer (s, &daysleft);
		#endif

		return true;
		}

	return false;
	} /*isValidSerialNumber1*/


#define str_maxTcpConnections "\x11" "maxTcpConnections"

static boolean isValidSerialNumber2 (bigstring s) {

	/*
	1/22/02 dmb: disabled store contact

	2002-10-13 AR: ifdef'd out variable declaration for msg1 and bsDaysLeft
	to eliminate a compiler warning about an unused variable
	*/

	long base = 34;
	long daysleft = 0;
	bigstring s2, bsversion;
	#ifdef restorestoreNOT
		bigstring msg1, bsDaysLeft;
	#endif
	long majorVersion;
	tyserialnumber sn;
	short P1idx, P2idx, P3idx, P4idx;
	short D1idx, D2idx, D3idx, D4idx, D5idx, D6idx;
	short O1idx, O2idx, O3idx, O4idx;
	short C1idx, C2idx, C3idx, C4idx, V1idx, V2idx;
	long crcResult1, crcResult2, options;


	P1idx = 1;
	P2idx = 2;
	P3idx = 3;
	P4idx = 24;
	D1idx = 18;
	D2idx = 13;
	D3idx = 9;
	D4idx = 11;
	D5idx = 23;
	D6idx = 4;
	V1idx = 6;
	V2idx = 17;
	O1idx = 22;
	O2idx = 19;
	O3idx = 14;
	O4idx = 8;
	C1idx = 12;
	C2idx = 7;
	C3idx = 21;
	C4idx = 16;
		
	if (stringlength(s) != 24)
		return false;
	
	if (s[5] != '-')
		return false;
	
	if (s[10] != '-')
		return false;
	
	if (s[15] != '-')
		return false;
	
	if (s[20] != '-')
		return false;
	
	sn.d1 = s[D1idx];
	sn.d2 = s[D2idx];
	sn.d3 = s[D3idx];
	sn.d4 = s[D4idx];
	sn.d5 = s[D5idx];
	sn.d6 = s[D6idx];
	sn.p1 = s[P1idx];
	sn.p2 = s[P2idx];
	sn.p3 = s[P3idx];
	sn.p4 = s[P4idx];
	sn.v1 = s[V1idx];
	sn.v2 = s[V2idx];
	sn.c1 = s[C1idx];
	sn.c2 = s[C2idx];
	sn.c3 = s[C3idx];
	sn.c4 = s[C4idx];
	sn.o1 = s[O1idx];
	sn.o2 = s[O2idx];
	sn.o3 = s[O3idx];
	sn.o4 = s[O4idx];
	
	if (!validNumber(&sn, base, 5))
		return false;

	copystring (s, s2);
	
	s2[C1idx] = '-';
	s2[C2idx] = '-';
	s2[C3idx] = '-';
	s2[C4idx] = '-';

	crcResult1 = genCRC (s2, true);
	crcResult2 = (asciiCharToB34(sn.c4) * 34*34*34) + (asciiCharToB34(sn.c3) * 34*34) + (asciiCharToB34(sn.c2) * 34) + asciiCharToB34(sn.c1);

	if (crcResult1 != crcResult2)
		return false;

	//Here are some of the specific checks
	options = (asciiCharToB34(sn.o1) * 34) + asciiCharToB34(sn.o2) - snoptions_offset;

	sninfo.useFile = (options & snoptions_usefile) == snoptions_usefile;
	sninfo.getFile = (options & snoptions_getfile) == snoptions_getfile;
	sninfo.trial = (options & snoptions_trial) == snoptions_trial;
	sninfo.multiCopyCheck = (options & snoptions_multicopycheck) == snoptions_multicopycheck;
	sninfo.startupCheck = (options & snoptions_startupcheck) == snoptions_startupcheck;
	sninfo.periodicCheck = (options & snoptions_periodiccheck) == snoptions_periodiccheck;
	sninfo.connectionLimit = (options & snoptions_connectionlimit) == snoptions_connectionlimit;
	sninfo.disableScriptDebugger = (options & snoptions_disablescriptdebugger) == snoptions_disablescriptdebugger;
	sninfo.disableTCPIP = (options & snoptions_disableTCPIP) == snoptions_disableTCPIP;
	sninfo.useSoftCheck = (options & snoptions_softhard) == snoptions_softhard;

	if (sninfo.connectionLimit) {
		maxconnections = asciiCharToB34(sn.o3);
		langassignlongvalue (environmenttable, str_maxTcpConnections, maxconnections); /*7.0b37 PBS: max TCP connections*/
		}		

	if (sninfo.disableTCPIP) {
		maxconnections = 0;
		langassignlongvalue (environmenttable, str_maxTcpConnections, maxconnections); /*7.0b37 PBS: max TCP connections*/
		}		

		
	//product ID checks

	if (sn.p2 != 'U')
		{			/* Normal checks not needed on UserLand Universal License */

		//Frontier or Radio (serial numbers will NOT work cross product)

#ifdef PIKE
		if (sn.p1 != 'R')	/* PIKE is Radio.  All Radio serial numbers will start with R */
			return (false);
#else
		if (sn.p1 != 'F')	/* Otherwise we are building Frontier, serial numbers start with F */
			return (false);
#endif

		//Platform Check	New serial number will NOT work cross platform, they have to be reassigned.

#ifdef WIN95VERSION
		if (sn.p3 != 'W')
			return (false);
#endif

#ifdef MACVERSION
#if TARGET_API_MAC_CARBON == 1
		if (sn.p3 != 'X')
			return (false);
#else
		if (sn.p3 != 'M')
			return (false);
#endif
#endif

		//Version number check
		filegetprogramversion (bsversion);
		if (stringtonumber (bsversion, &majorVersion))
			if (asciiCharToB34(sn.v1) != majorVersion)	//require SN update on Major Version Change
				return (false);
		}


#ifdef restorestoreNOT

	if (! sninfo.disableTCPIP) {
		if (contactStoreServer (s, &daysleft)) {
			if (daysleft == -5)		//Allows us to force a serial number bad!
				return (false);

			if (daysleft == -2)	{	//The serial number was not found
				if (sninfo.trial)
					return (false);
				}
			
			if (daysleft == 0) {
				if (sninfo.trial)
					{
					//Trial Expired
					alertdialog ("\x1F" "This Trial version has expired.");
					return (false);
					}
				if (!sninfo.useSoftCheck)
					{
					//Subscription expired
					alertdialog ("\x1E" "Your subscription has expired.");
					}
				}
			else {
				if (sninfo.trial) {
					copyctopstring ("This is a Trial Version.  There are ^0 days left in your trial.", msg1);
					numbertostring (daysleft, bsDaysLeft);
					parsedialogstring (msg1, bsDaysLeft, nil, nil, nil, msg1);
					alertdialog (msg1);
					return (true);
					}
				}
			}
		else {
			//contact failed
			//if trial go no-no
			if (sninfo.trial) {
				alertdialog ("\x52" "Trial version could not launch because it could not contact the validation server.");
				return (false);
				}
			}
		}

#endif

	return true;
	} /*isValidSerialNumber2*/


boolean isvalidserialnumber (bigstring bsserialnumber) {

	/*
	12/3/01 7.1b34 dmb: new public function, wrapping repeated compilation case
	*/

#if 0 //def PIKE
		if (isValidSerialNumber2 (bsserialnumber))
			return (true);
#else
		if (isValidSerialNumber1 (bsserialnumber))  //allow old serial numbers
			return (true);

		if (isValidSerialNumber2 (bsserialnumber))
			return (true);
#endif

	return (false);
	} /*isvalidserialnumber*/


boolean validateserialnumber (void) {

	/*
	5.1b23 dmb: loop until we have a valid serial number, or the callback to 
	get a new one fails.
	
	5.1.1 dmb: don't accept "trial" serial number

	6.1b8 AR: If the serial number is invalid, inform the user
	*/
	
#if useSerialNumber
	// FCW0-7105-7A2A-902A-PH07  // sample only
	
	byte bspref [] = "\x17" "user.prefs.serialNumber";
	byte bsgetit [] = "\x20" "Please enter your serial number:";

#ifdef PIKE
	byte bsinvalid [] = "\x3D" "Can't launch Radio because \"^0\" is not a valid serial number.";
#elif defined(ALBERT)
	byte bsinvalid [] = "\x3E" "Can't launch Albert because \"^0\" is not a valid serial number.";
#else
	byte bsinvalid [] = "\x40" "Can't launch Frontier because \"^0\" is not a valid serial number.";
#endif

	bigstring bsserialnumber;
	bigstring bsscript;
	bigstring bsresult;
	bigstring bstemp;
	
	if (langrunstringnoerror (bspref, bsserialnumber)) {
		
		if (isvalidserialnumber (bsserialnumber))
			return (true);
		}
	else
		setemptystring (bsserialnumber);
	
	while (true) {
		
		activateapplication (nil); /*8.0b49 PBS: bring app to front*/

		if (!askdialog (bsgetit, bsserialnumber))
			return (false);
		
		allupper (bsserialnumber);
		
		/*
		if (equalstrings (bsserialnumber, "\x05" "TRIAL"))
			break;
		*/
		
		if (isvalidserialnumber (bsserialnumber))
			break;

		parsedialogstring (bsinvalid, bsserialnumber, nil, nil, nil, bstemp);

		if (!alertdialog (bstemp))
			return (false);
		}
	
	copystring (bspref, bsscript);

	pushstring ("\x02" "=\"", bsscript);
	pushstring (bsserialnumber, bsscript);
	pushchar ('"', bsscript);

	langrunstring (bsscript, bsresult);
	
	#endif
	
	return (true);
	} /*validateserialnumber*/


