/* login.cx - log ports in and out */

/* this is an #included file !!!! */

/*
**	8/18/86, Tim Holloway
**
**	Description: These routines are designed to ensure that a user does
**	not find a message port, only to have it disappear before all
**	messages have been transmitted to the destination port.  To that end,
**	the sender must log in to the the destination port, send all messages
**	and then log out.  The first byte of each message indicates log
**	status.  If the receiver changes it to LOGOUT, the sender has been
**	forced off the port and should send no further messages (including
**	logout).
**
**	Caveats: The login ID for the sender is determined by the reply
**	port address of the initial login.  You should either use the
**	same message template for all further communications, or 'clone'
**	the message.  That's the way Amiga EXEC I/O structures are handled,
**	too!
**
**	Miscellaneous: A special data structure called a PORTPAIR is
**	used in order to keep the sending and reply ports together.
**	The PORTPAIR is initialized by LogInPort, and should not be
**	modified by the user.
*/

enum portid {OUTPORT, INPORT};
/* #define OUTPORT 0 / #define INPORT 1 ... if your compiler can't enum */

typedef struct MsgPort *PORT_ADDRESS;
typedef PORT_ADDRESS PORTPAIR[2];

extern PORT_ADDRESS 	CreatePort(char *, int);	/* prototypes */
extern PORT_ADDRESS	FindPort (char *);
extern VOID 		DeletePort (PORT_ADDRESS);


/*
**	Log in a message port.  Assures that receiver will not delete port
**	out from under us!  Creates a reply port. and initializes a portpair -
**	i.e. array containing the addresses of the outbound and reply ports.
*/

BOOL
LogInPort (port_name, ports, log_message)
char *port_name;
PORTPAIR ports;
SPOOLmsg  *log_message;
{
	REGISTER PORT_ADDRESS mpin, mpout;

/*
   Note - we build a reply port FIRST, even though we may not be able to
   use it, simply because we don't want to do any more work while Forbidden
   than absolutely neccessary.  I refuse to feel guilty about the xxx
   microseconds of work wasted if the login failed.  Better that than
   playing ping-pong with Forbids and Permits.  Two Permits for one Forbid
   was bad enough!
*/

	mpin = ports[INPORT] = CreatePort (NULL, 0);	/* reply port */
	if (mpin == NULL)
	{
		error ("Wasn't able to create the reply port.");
		return FALSE;
	}

	Forbid();	/* forbid other tasks from pre-empting */

/* printf ("Reply port is at %lx.\nFind port..", mpin); */

	mpout = ports[OUTPORT]	= FindPort(port_name);
	if (mpout != NULL)
	{
		log_message->log_status = LOG_IN;
		log_message->minfo.mn_ReplyPort = mpin;
		PutMsg (mpout, log_message);

/* printf ("message sent.  Waiting.\n"); */

		(void) WaitPort(mpin);

/* printf ("operation complete.\n"); */

	Permit();	/* */
		(void) GetMsg (mpin);
		return ((BOOL) (log_message->log_status != LOG_OUT));
	}

	Permit();	/* back to the multitasking world! */
	DeletePort (mpin);
	return FALSE;
}

/* disconnect port pair and clean up */

static VOID
LogOutPort(ports, log_message)
PORTPAIR ports;
SPOOLmsg  *log_message;
{

/* printf ("log out ports\n"); */
	if (log_message->log_status != LOG_OUT)
	{
	    log_message->log_status = LOG_OUT;
	    log_message->minfo.mn_ReplyPort = ports[INPORT];
	    PutMsg (ports[OUTPORT], log_message);
	    (VOID) WaitPort (ports[INPORT]);
	    (VOID) GetMsg (ports[INPORT]);
	}

	if (ports[INPORT] != NULL)
	    DeletePort (ports[INPORT]);	/* get rid of port we allocated */
}
