/*
 * Drag & drop sample code.
 * Copyright 1992 Atari Corporation
 *
 * global variables used:
 * gl_apid: our AES application id
 *
 * BUGS/CAVEATS:
 * This code is not re-entrant (it uses a static
 * variable for the pipe name and for saving the
 * SIGPIPE signal handler).
 *
 * While doing the drag and drop, the SIGPIPE
 * signal (write on an empty pipe) is ignored
 */
#include <string.h>

#ifdef __MINT__
#include <mint/atarierr.h>
#include <signal.h>
static __Sigfunc	oldpipesig;
#else
#include <atarierr.h>
static long	oldpipesig;
#endif

#include "intern.h"

static char			pipename[] = "u:\\pipe\\dragdrop.aa";


/* Code for originator */


/*
 * ddcreate: create a pipe for doing the drag & drop,
 *           and send an AES message to the receipient
 *           application telling it about the drag & drop
 *           operation.
 *
 * Input Parameters:
 * apid:	AES id of the window owner
 * winid:	target window (0 for background)
 * msx, msy:	mouse X and Y position
 *		(or -1, -1 if a fake drag & drop)
 * kstate:	shift key state at time of event
 *
 * Output Parameters:
 * exts:	A 32 byte buffer into which the
 *		receipient's 8 favorite
 *		extensions will be copied.
 *
 * Returns:
 * A positive file descriptor (of the opened
 * drag & drop pipe) on success.
 * -1 if the receipient doesn't respond or
 *    returns DD_NAK
 * -2 if appl_write fails
 */
int dd_create(int apid, int winid, int msx, int msy, int kstate, char *exts)
{
	int 	fd, i;
	short	msg[8];
	long 	fd_mask;
	char 	c;

	pipename[17] = pipename[18] = 'A';
	fd = -1;
	do 
	{
		pipename[18]++;
		if (pipename[18] > 'Z') 
		{
			pipename[17]++;
			if (pipename[17] > 'Z')
				break;
		}
		/* FA_HIDDEN means "get EOF if nobody has pipe open for reading" */
		fd = (int)Fcreate(pipename, FA_HIDDEN);
	} 
	while (fd == EACCDN);

	if (fd < 0) 
		return fd;

	/* construct and send the AES message */
	msg[0] = AP_DRAGDROP;
	msg[1] = gl_apid;
	msg[2] = 0;
	msg[3] = winid;
	msg[4] = msx;
	msg[5] = msy;
	msg[6] = kstate;
	msg[7] = (pipename[17] << 8) | pipename[18];
	i = appl_write(apid, (int)sizeof(msg), msg);
	if (i == 0) 
	{
		Fclose(fd);
		return -2;
	}

	/* now wait for a response */
	fd_mask = 1L << fd;
	i = Fselect(DD_TIMEOUT, &fd_mask, 0L, 0L);
	if (!i || !fd_mask) 	/* timeout happened */
	{
		Fclose(fd);
		return -1;
	}

	/* read the 1 byte response */
	i = (int)Fread(fd, 1L, &c);
	if (i != 1 || c != DD_OK) 
	{
		Fclose(fd);
		return -1;
	}

	/* now read the "preferred extensions" */
	i = (int)Fread(fd, DD_EXTSIZE, exts);
	if (i != DD_EXTSIZE) 
	{
		Fclose(fd);
		return -1;
	}

#ifdef __MINT__
	oldpipesig = signal(SIGPIPE, SIG_IGN);
#else
	oldpipesig = (long)Psignal(SIGPIPE, SIG_IGN);
#endif
	return fd;
}


/*
 * ddstry: see if the receipient is willing to accept a certain
 *         type of data (as indicated by "ext")
 *
 * Input parameters:
 * fd		file descriptor returned from ddcreate()
 * ext		pointer to the 4 byte file type
 * name		pointer to the name of the data
 * size		number of bytes of data that will be sent
 *
 * Output parameters: none
 *
 * Returns:
 * DD_OK	if the receiver will accept the data
 * DD_EXT	if the receiver doesn't like the data type
 * DD_LEN	if the receiver doesn't like the data size
 * DD_NAK	if the receiver aborts
 */
int dd_stry(int fd, char *ext, char *name, long size)
{
	short	hdrlen, i;
	char 	c;

	/* 4 bytes for extension, 4 bytes for size, 1 byte for
	 * trailing 0
	 */
	hdrlen = 9 + strlen(name);
	i = Fwrite(fd, 2L, &hdrlen);

	/* now send the header */
	if (i != 2) 
		return DD_NAK;
	i = Fwrite(fd, 4L, ext);
	i += Fwrite(fd, 4L, &size);
	i += Fwrite(fd, (long)strlen(name)+1, name);
	if (i != hdrlen) 
		return DD_NAK;

	/* wait for a reply */
	i = Fread(fd, 1L, &c);
	if (i != 1) 
		return DD_NAK;
	return c;
}


/* Code for either receipient or originator */


/*
 * ddclose: close a drag & drop operation
 */
void	dd_close(int fd)
{
#ifdef __MINT__
	(void)signal(SIGPIPE, oldpipesig);
#else
	Psignal(SIGPIPE, (void *)oldpipesig);
#endif
	(void)Fclose(fd);
}



/* Code for receipient */


/*
 * ddopen: open a drag & drop pipe
 *
 * Input Parameters:
 * ddnam:	the pipe's name (from the last word of
 *		the AES message)
 * preferext:	a list of DD_NUMEXTS 4 byte extensions we understand
 *		these should be listed in order of preference
 *		if we like fewer than DD_NUMEXTS extensions, the
 *		list should be padded with 0s
 *
 * Output Parameters: none
 *
 * Returns:
 * A (positive) file handle for the drag & drop pipe, on success
 * -1 if the drag & drop is aborted
 * A negative error number if an error occurs while opening the
 * pipe.
 */
int	dd_open(int ddnam, char *preferext)
{
	int 	fd;
	char	outbuf[DD_EXTSIZE+1];

	pipename[18] = ddnam & 0x00ff;
	pipename[17] = (ddnam & 0xff00) >> 8;

	fd = (int)Fopen(pipename, 2);
	if (fd < 0) return fd;

	outbuf[0] = DD_OK;
	strncpy(outbuf+1, preferext, DD_EXTSIZE);

#ifdef __MINT__
	oldpipesig = signal(SIGPIPE, SIG_IGN);
#else
	oldpipesig = (long)Psignal(SIGPIPE, SIG_IGN);
#endif

	if (Fwrite(fd, (long)DD_EXTSIZE+1, outbuf) != DD_EXTSIZE+1) 
	{
		dd_close(fd);
		return -1;
	}

	return fd;
}


/*
 * ddrtry: get the next header from the drag & drop originator
 *
 * Input Parameters:
 * fd:		the pipe handle returned from ddopen()
 *
 * Output Parameters:
 * name:	a pointer to the name of the drag & drop item
 *		(note: this area must be at least DD_NAMEMAX bytes long)
 * whichext:	a pointer to the 4 byte extension
 * size:	a pointer to the size of the data
 *
 * Returns:
 * TRUE on success
 * FALSE if the originator aborts the transfer
 *
 * Note: it is the caller's responsibility to actually
 * send the DD_OK byte to start the transfer, or to
 * send a DD_NAK, DD_EXT, or DD_LEN reply with ddreply().
 */
int dd_rtry(int fd, char *name, char *whichext, long *size)
{
	short	hdrlen;
	int 	i;
	char 	buf[80];

	i = (int)Fread(fd, 2L, &hdrlen);
	if (i != 2) 
		return FALSE;
	if (hdrlen < 9) 	/* this should never happen */
		return FALSE;
	i = (int)Fread(fd, 4L, whichext);
	if (i != 4) 
		return FALSE;
	whichext[4] = 0;
	i = (int)Fread(fd, 4L, size);
	if (i != 4) 
		return FALSE;
	hdrlen -= 8;
	if (hdrlen > DD_NAMEMAX)
		i = DD_NAMEMAX;
	else
		i = hdrlen;
	if (Fread(fd, (long)i, name) != i) 
		return FALSE;
	hdrlen -= i;

	/* skip any extra header */
	while (hdrlen > 80) 
	{
		Fread(fd, 80L, buf);
		hdrlen -= 80;
	}
	if (hdrlen > 0)
		Fread(fd, (long)hdrlen, buf);

	return TRUE;
}


/*
 * ddreply: send a 1 byte reply to the drag & drop originator
 *
 * Input Parameters:
 * fd:		file handle returned from ddopen()
 * ack:		byte to send (e.g. DD_OK)
 *
 * Output Parameters:
 * none
 *
 * Returns: TRUE on success, FALSE on failure
 * in the latter case the file descriptor is closed
 */
int dd_reply(int fd, int ack)
{
	char c = ack;

	if (Fwrite(fd, 1L, &c) == 1L) 
		return TRUE;
	else
		Fclose(fd);
	return FALSE;
}
