/************************************************************************
 *    CNet/3 and CNet/4  C language interface routines and examples     *
 *                                                                      *
 *  copyright © 1996 ZenMetal Software ... this code may be freely      *
 *  distributed to and used by registered CNet owners EXCLUSIVELY.      *
 *  Other distribution is in violation of copyright laws.               *
 ************************************************************************/



/************************************************************************
 *                          Function prototypes                         *
 ************************************************************************/
void		CallHost( UBYTE c );
void		ShutDown( char *spawn );
void		GetOut( void );
void		LoadError( void );


/************************************************************************
 *                           Global Variables                           *
 ************************************************************************/
struct MsgPort         *replyp;	/* Some communication details ...	*/
struct CPort           *cport;
struct CMessage        cmess;
struct MainPort        *myp;		/* Pointer to CNet port--ALL info!	*/
struct PortData        *z;
char	                 **bm;
struct Library         *CNetBase = NULL;
struct SignalSemaphore *SEM;



/************************************************************************
 *                             Main routine                             *
 ************************************************************************/
void main( int argc, char **argv )
{
	int zzz=0;
	char text[30];

	Forbid();
	if(argc > 1)
		cport = (struct CPort *)FindPort( argv[1] );
	Permit();

	if( argc<2 || !(cport) ) {
		printf("This is a CNet C program.\n");
		exit(0);
		}

	if( !(replyp = CreatePort( 0,0 )))
		exit(0);

	cmess.cn_Message.mn_ReplyPort   = replyp;
	cmess.cn_Message.mn_Length      = sizeof( struct CMessage );
	cmess.cn_Message.mn_Node.ln_Name= "cstuff";

	// CNet version check
	if( cport->ack != 30 ) {	// change "30" to be compatible with only pre 4.13 systems
		cport->ack = 1;
		LoadError();
		}

//	if( cport->ack != 40 )      // Replace the code above with this
//		if( cport->ack != 30 )   // to support both 3.x and 4.x systems
//			{
//			cport->ack = 1;
//			goto err;
//			}

	cport->ack = 0;

	z    = cport->zp;
	myp  = cport->myp;
	SEM  = myp->SEM;
	bm   = z->bm;

	if( !(CNetBase = OpenLibrary( "cnet.library", 4 )) ) // <- NOTE version 4 - can be changed to 3 to make compatible with older CNet releases!
		LoadError();

/************************************************************************
 *           End of CNet setup - YOUR CUSTOM CODE STARTS HERE           *
 ************************************************************************/

	PutText( "\nu1check bitsu0\n" );
	for(zzz=4;zzz>=0;zzz--)
		{
		switch(zzz)
			{
			case 0:
				sprintf(text, "DOORS CLOSED");
				break;
			case 1:
				sprintf(text, "FILES CLOSED");
				break;
			case 2:
				sprintf(text, "MSGS CLOSED ");
				break;
			case 3:
				sprintf(text, "DOORS CLOSED");
				break;
			case 4:
				sprintf(text, "NO NEW USERS");
				break;
			}
		sprintf(z->ABuffer, "%s: %s\n", text, myp->pc[z->InPort].check & (1<<zzz) ? "TRUE":"FALSE");
		PutA();
		}




	/* exit back to CNet - always call GetOut() to exit back to CNet! */
	GetOut();
}


/**************************************************************************
 *       Routine called if Load error (wrong CNet version, etc,...        *
 **************************************************************************/
void LoadError( void )
{
	DeletePort( replyp );
	exit(0);
}

/************************************************************************
 *                           Generic EXIT code                          *
 ************************************************************************/
void GetOut( void )
{
	ShutDown( NULL );
	DeletePort( replyp );
	exit(0);
}


/**************************************************************************
 *                         another file to run?                           *
 **************************************************************************/
void ShutDown( char *spawn )
{
	/* spawn = full path/file to run */
	if( spawn )
		strcpy( z->CSpawn, spawn );

	CallHost( 0 );
}


void CallHost( UBYTE c )
{
	cmess.command = c;
	PutMsg  ( (struct MsgPort *)cport, (struct Message *)&cmess );
	WaitPort( replyp );
	GetMsg  ( replyp );
}

void PutText( char *text )
{
	cmess.arg1 = (ULONG)text;	/* text to print		*/
	CallHost( 1 );
}

void PutA( void )
{
	PutText( z->ABuffer );
}


/**************************************************************************
 *    ENTERLINE FLAGS:                                                    *
 *      1: All capitalized                                                *
 *      2: FILENAME.  Don't allow =":; or asterisk                        *
 *      4: Begin with existing z.InBuffer                                 *
 *      8: Chop leading spaces                                            *
 *     16: Force 1st letter of word caps                                  *
 *     32: Force all others lower case                                    *
 *     64: Numeric input only                                             *
 *    128: Print input box (.)                                            *
 *    256: DO allow MCI                                                   *
 *    512: HANDLES/SPECIAL.  Don't allow ^_`{|}~@                         *
 *   1024: Exit for . or / at beginning of line                           *
 *   2048: Exit for backspace at beginning of line                        *
 *   4096: Do not allow OLM's to appear while editing                     *
 *   8192: Allow Chat break in at this prompt. COMMAND PROMPT.            *
 *  16384: Don't allow SPACE, either                                      *
 *  32768: DON'T ALLOW MOVEMENT                                           *
 *  65536: Don't allow forward slash                                      *
 **************************************************************************/
int EnterLine( UBYTE len, ULONG flags, char *prompt )
{
	cmess.arg1 = (ULONG)len;	/* how many chars max to input	*/
	cmess.arg2 = (ULONG)flags;	/* 1=UpperCase			*/
	cmess.arg3 = (ULONG)prompt;	/* text to print before input	*/
	CallHost( 2 );			/* result is in z->InBuffer	*/
	return( (int)strlen( z->InBuffer ));
}


/**************************************************************************
 *                       Stop until a key is pressed                      *
 **************************************************************************/
char OneKey( void )
{
	CallHost( 3 );
	return( (char)cmess.result );	/* returns key pressed */
}


/**************************************************************************
 *
 **************************************************************************/
void EnterPassword( UBYTE len )
{
	cmess.arg1 = (ULONG)len;	/* max number of characters */
	CallHost( 4 );
}

/**************************************************************************
 *                 Check z->InBuffer for Chat, OLM, etc                   *
 **************************************************************************/
long CommonCommands( void )
{
	CallHost( 5 );
	return( (long)cmess.result );
}


/**************************************************************************
 *
 **************************************************************************/
UBYTE ReadFile( char *path, UBYTE flags )
{
	cmess.arg1 = (ULONG)path;
	cmess.arg2 = (ULONG)flags;          /* 1 = print File Not Found */
	CallHost( 6 );
	return( (UBYTE)cmess.result );      /* returns FALSE if File Not Found */
}

/**************************************************************************
 *        Sets the "Action" or "Where" field for the user's port          *
 *      ** remember to retain and restore the previous z->DOING **        *
 **************************************************************************/
void SetDoing( char *what )
{
	cmess.arg1 = (ULONG)what;
	CallHost( 7 );
}


/**************************************************************************
 *Invokes the CNet editor according to user's preference of line or Visual*
 **************************************************************************/
void CallEditor( short max, short inlines )
{
	cmess.arg1 = (ULONG)max;	/* Maximum number of lines (250)*/
	cmess.arg2 = (ULONG)inlines;	/* TRUE/FALSE use existing _edbuff? */
	CallHost( 8 );
}

/**************************************************************************
 *             Read text file with MCI/graphic interpretation             *
 **************************************************************************/
UBYTE ReadGraphics( char *path, char flags )
{
	cmess.arg1 = (ULONG)path;
	cmess.arg2 = (ULONG)flags;	/* 1 = print File Not Found	*/
	CallHost( 9 );
	return( (UBYTE)cmess.result );		/* FALSE if File Not Found	*/
}

/**************************************************************************
 *  Construct a date in CNet format - like that seen in the port titlebar *
 **************************************************************************/
void MakeDate( struct IsDate *date, char *output )
{
	cmess.arg1 = (ULONG)date;
	cmess.arg2 = (ULONG)output;
	CallHost( 10 );
}


/**************************************************************************
 *                     Load userdata for account "id"                     *
 **************************************************************************/
UBYTE ReadAccount( short id, struct UserData *user )
{
	cmess.arg1 = (ULONG)id;
	cmess.arg2 = (ULONG)user;
	CallHost( 11 );
	return( (UBYTE)cmess.result );
}

/**************************************************************************
 *           Saves an account after editing/changing attributes           *
 **************************************************************************/
UBYTE SaveAccount( struct UserData *user, short id )
{
	cmess.arg1 = (ULONG)user;
	cmess.arg2 = (ULONG)id;
	CallHost( 12 );
	return( (UBYTE)cmess.result );
}

/**************************************************************************
 *         add charge amount "a" to charge schedule number "n"            *
 **************************************************************************/
UBYTE AddCharge( short n, short a )
{
	cmess.arg1 = (ULONG)n;
	cmess.arg2 = (ULONG)a;
	CallHost( 13 );
	return( (UBYTE)cmess.result );
}

/**************************************************************************
 *
 **************************************************************************/
UBYTE CheckBalance( short n, short a )
{
	cmess.arg1 = (ULONG)n;
	cmess.arg2 = (ULONG)a;
	CallHost( 14 );
	return( (UBYTE)cmess.result );
}

/***************************************************************************
 * Get text from user.  Results are placed in z.GBuffer[] array of strings *
 * note that there are 16 lines MAX and each line may hold up to 80        *
 * characters                                                              *
 ***************************************************************************/
int EnterText( char firstchar, short maxchars, short perline, short maxlines )
{
	cmess.arg1 = (ULONG)firstchar;
	cmess.arg2 = (ULONG)maxchars;
	cmess.arg3 = (ULONG)perline;
	cmess.arg4 = (ULONG)maxlines;
	CallHost( 15 );
	return( (int)cmess.result );
}

/**************************************************************************
 *
 **************************************************************************/
long ConferenceWait( short a )
{
	cmess.arg1 = (ULONG) a;
	CallHost( 16 );
	return( (long)cmess.result );
}


/****************************************************************************
 * Update the current time, load the user's bbstext translation, charges    *
 * If the user has little time remaining, print "you have xx minutes left", *
 * force Events to be checked for pending event execution..                 *
 ****************************************************************************/
void CheckChanges( void )
{
	CallHost( 17 );
}


/**************************************************************************
 *      Converts a CNet access/range string to a packed LONG value        *
 **************************************************************************/
long ConvertAccess( char *s )
{
	cmess.arg1 = (ULONG)s;
	CallHost( 18 );
	return( (long)cmess.result );
}


/**************************************************************************
 * return the number of bytes free on device specified by s               *
 * if q==0, the result is displayed to the user by GetFree()              *
 **************************************************************************/
long GetFree( char *s, UBYTE q )
{
	cmess.arg1 = (ULONG)s;
	cmess.arg2 = (ULONG)q;
	CallHost( 19 );
	return( (long)cmess.result );
}

/**************************************************************************
 *    Find an account based on account number, Handle or real name        *
 *    This is the same routine that, if the user is not found, pops up    *
 *    the mini-userlist for user choice.                                  *
 **************************************************************************/
short FindAccount( char *a, struct UserData *b )
{
	cmess.arg1 = (ULONG)a;
	cmess.arg2 = (ULONG)b;
	CallHost( 20 );
	return( (short)cmess.result );
}


/**************************************************************************
 *  Forces CNet to flush/check it's buffers and parse/update the keyboard *
 *  buffers                                                               *
 **************************************************************************/
void CheckFlowControl( void )
{
	CallHost( 21 );
}

/**************************************************************************
 * list the contents of a directory (the user will be prompted for        *
 * directory name).                                                       *
 *                                                                        *
 * options: a = allow selection of files to user's select list            *
 *                                                                        *
 *          b = 1: select and download immediately                        *
 *              2: allow wildcard pattern                                 *
 *                                                                        *
 *          c = list files newer than the date specified by c             *
 *              c is a properly filled out Cnet IsDate structure          *
 **************************************************************************/
long ListDir( UBYTE a, UBYTE b, struct IsDate *c )
{
	cmess.arg1 = (ULONG)a;
	cmess.arg2 = (ULONG)b;
	cmess.arg3 = (ULONG)c;
	CallHost( 22 );
	return( (long)cmess.result );
}


/**************************************************************************
 * Read the next base/udbase message                                      *
 **************************************************************************/
UBYTE Rnext( void )
{
	CallHost( 24 );
	return( (UBYTE)cmess.result );
}

/***************************************************************************
 * Parse the contents of z->InBuffer into z->pitems.  Parses up to numargs *
 * items                                                                   *
 ***************************************************************************/
void ParseCommandLine( UBYTE numargs )
{
	cmess.arg1 = (ULONG)numargs;
	CallHost( 25 );
}


/**************************************************************************
 *  Takes the contents of z->InBuffer and searches for a matching command *
 *  in menu "num" of BBSMENU.                                             *
 **************************************************************************/
short FindCommand( short num )
{
	cmess.arg1 = (ULONG) num;
	CallHost( 26 );
	return( (short)cmess.result );
}

/**************************************************************************
 * Open the filename specified by a, seek to position b in the file       *
 * and display the contents of the file from point b to EOF               *
 **************************************************************************/
void ReadMessagePoint( char *a, long b )
{
	cmess.arg1 = (ULONG) a;
	cmess.arg2 = (ULONG) b;
	CallHost( 27 );
}

/**************************************************************************
 * Use the CNet editor to edit the file specified by "file"               *
 **************************************************************************/
void EditMessage( char *file )
{
	cmess.arg1 = (ULONG) file;
	CallHost( 28 );
}

/***************************************************************************
 * Load the text from the file-handle given and insert it into the current *
 * port's editor file                                                      *
 ***************************************************************************/
void LoadText( BPTR fh )
{
	cmess.arg1 = (ULONG) fh;
	CallHost( 29 );
}


/**************************************************************************
 *	1000000 mics = 1 second                                                *
 **************************************************************************/
char WaitForInput( long mics )
{
	cmess.arg1 = (ULONG) mics;
	CallHost( 31 );
	return( (char)cmess.result );
}


/**************************************************************************
 *                       Select and download a file.                      *
 *                                                                        *
 * file  = full path/filename                                             *
 *                                                                        *
 * flags = 0 -> select without immediate download                         *
 *       = 1 -> select and download immediately                           *
 *                                                                        *
 * flag values below are new for v4.11                                    *
 *                                                                        *
 *       = 2 -> delete file after downloading/no immediate download       *
 *       = 3 -> delete file after downloading/download immediate.         *
 **************************************************************************/
UBYTE SelectAndDownload( char *file, UBYTE flags )
{
	cmess.arg1 = (ULONG)file;
	cmess.arg2 = (ULONG)flags;
	CallHost( 39 );
	return( (UBYTE)cmess.result );
}


/**************************************************************************
 * file: the ".vde" filename, without the ".vde"!                         *
 * data: pointer to the structure you are going to edit                   *
 * size: structure length in bytes                                        *
 *                                                                        *
 * returns: TRUE  if structure has been changed                           *
 *          FALSE otherwise                                               *
 **************************************************************************/
short VisualDataEditor( char *file, void *data, long size )
{
	cmess.arg1 = (ULONG)file;
	cmess.arg2 = (ULONG)data;
	cmess.arg3 = (ULONG)size;
	CallHost( 40 );
	return( (short)cmess.result );
}

/**************************************************************************
 * In preparation for an ExtUpload, this function                         *
 * sets the minimum number of free bytes to maintain on the	drive.        *
 **************************************************************************/
void ExtSetMinFree( long free )
{
	cmess.arg1 = (ULONG)free;
	CallHost( 42 );
}


/**************************************************************************
 * In preparation for an ExtDownload or an ExtUpload, this function       *
 * sets the protocol to be used.  If you send NULL, it will allow the     *
 * user to choose his OWN protocol.                                       *
 *                                                                        *
 * Otherwise, you may select 'a' to be the first letter of a valid        *
 * system protocol (from BBSPROTO file), such as 'x', 'z', etc.           *
 *                                                                        *
 * TRUE will be returned if a protocol is selected and ready, FALSE       *
 * if there is a problem.                                                 *
 **************************************************************************/
UBYTE ExtSetProtocol( char a )
{
	cmess.arg1 = (ULONG)a;
	CallHost( 43 );
	return( (UBYTE)cmess.result );
}



/**************************************************************************
 * This routine allows the user to download the SINGLE file specified     *
 * by the FULL PATH 'args'.                                               *
 *                                                                        *
 *	Currently, NULL is always returned.                                    *
 **************************************************************************/
char *ExtDownload( char *args )
{
	cmess.arg1 = (ULONG)args;
	CallHost( 44 );
	return( (char *)cmess.result );
}


/**************************************************************************
 * This routine allows the user to upload the file specified by           *
 * 'args'.  The path for uploading will be taken from the path            *
 * in 'args'.  If you do NOT specify a path, the file(s) will             *
 * appear in the user's HOME directory.                                   *
 *                                                                        *
 * Note that with batch protocols like ZMODEM, the filename(s) are        *
 * taken from the header packet information, and may NOT be the           *
 * same as what you have requested the user upload.  For this reason,     *
 * you should have uploads occur in a TEMP directory, and search that     *
 * directory yourself for new files.                                      *
 *                                                                        *
 * Currently, NULL is always returned.                                    *
 **************************************************************************/
char *ExtUpload( char *args )
{
	cmess.arg1 = (ULONG)args;
	CallHost( 45 );
	return( (char *)cmess.result );
}


/**************************************************************************
 * compare two strings and return result                                  *
 *                                                                        *
 * result: 0 if equal                                                     *
 *        >0 if s is alphabetically "higher" than t                       *
 *        <0 if t is alphabetically "higher" than s                       *
 **************************************************************************/
short compstra( char *s, char *t )
{
	for( ; tolower(*s) == tolower(*t); s++, t++)
		if( !*s ) return 0;

	return (short)( tolower(*s)-tolower(*t) );
}


/**************************************************************************
 * Print the prompt string passed as "a" and return the user's            *
 * YES or NO equivalent result.  1=YES, 2=NO                              *
 **************************************************************************/
UBYTE PutQ( char *a )
{
	PutText( a );
	return (UBYTE)(z->MCIcreg[0][0]=='1') ;
}

/**************************************************************************
 * Isn't it obvious enough? ;-)
 **************************************************************************/
void DoReturn( void )
{
	PutText("\n");
}

/**************************************************************************
 * Create the editor filename used for the current port and place it      *
 * in the string array passed as "path"                                   *
 **************************************************************************/
void MakeEd( char *path )
{
	sprintf( path, "%s_edbuff%d", myp->gc.ZIPpath, z->InPort );
}


/**************************************************************************
 * Delete the editor file                                                 *
 **************************************************************************/
void DeleteEd( void )
{
	char	filename[80];

	MakeEd    ( filename ) ;
	DeleteFile( filename ) ;
}

/**************************************************************************
 * Open the file used for the editor and return the filehandle (BPTR)     *
 **************************************************************************/
BPTR OpenEd( long mode )
{
	char	filename[80];

	MakeEd( filename );

	return Open( filename, mode );
}

/**************************************************************************
 * insert the contents of the file belonging to filehandle "fp" into      *
 * the current port's editor file                                         *
 **************************************************************************/
void PrepEditor( BPTR fp )
{
	BPTR	kp;
	char	buff[100];

	if( fp ) {
		if( kp = OpenEd( MODE_NEWFILE ) ) {
			while( FGets( fp, buff, 82 ) && buff[0]!=26 )
			       FPuts( kp, buff     ) ;

			Close( kp );
		}
	}
	else	DeleteEd();
}

/**************************************************************************
 * Save the contents of the current port's editor file into the file      *
 * belonging to filehandle "fp"                                           *
 **************************************************************************/
void SaveEditor( BPTR fp, UBYTE eof )
{
	BPTR	kp;
	char	buff[100];

	if( kp = OpenEd( MODE_OLDFILE ) ) {
		while( FGets( kp, buff, 82 ) && buff[0]!=26 )
		       FPuts( fp, buff     ) ;

		Close( kp );

		DeleteEd();
	}

	if( eof ) FPuts( fp, "\032\n" );
}
