/* Peek into a user's actions on the bbs.
 * This allows you to follow all stuff, and also
 * send messages and initiate chats...
 * (C) 1994, Johan. K. Reinalda, WG7J
 */
#include "global.h"
#ifdef LOOKSESSION
#include "ctype.h"
#include "commands.h"
#include "session.h"
#include "smtp.h"
#include "usock.h"
#include "mailbox.h"
  
#if !defined(_lint)
static char rcsid[] OPTIONAL = "$Id: look.c,v 1.18 2001/05/06 16:32:56 brian Exp $";
#endif

static void look_input (int unused,void *p1,void *p2);
extern int sockblock (int s,int value);
  
struct look {
	struct session *sp;     /* our look session */
	int user;               /* socket we look at */
};
  

int
dolook(int argc OPTIONAL, char *argv[],void *p OPTIONAL)
{
struct look lk;
struct usock *up;
int chat;
char *cp;
char const *cp2;
char name[20];
char buf[MBXLINE];
int i, block;
  
	/* Check if this comes from console - WG7J*/
	if (Curproc->input != Command->input)
		return 0;
  
#ifdef MAILBOX
	/* Find the user ! */
	lk.user = atoi (argv[1]);  /* store socket #, or illegal # if callsign */
	for (i = 0; i < NUMMBX; i++)	{
		if (Mbox[i] == NULLMBX)
			continue;
		if (!stricmp (Mbox[i]->name, argv[1]))
			break;
		if (lk.user && Mbox[i]->user == lk.user)
			break;
	}
	if (i != NUMMBX) {
		lk.user = Mbox[i]->user;
		strncpy (name, Mbox[i]->name, 20);
	} else {
#endif
		lk.user = atoi (argv[1]);
		sprintf (name, "socket %d", lk.user);
#ifdef MAILBOX
	}
#endif
  
	if ((up = itop (lk.user)) == NULLUSOCK)	{
		tputs ("User socket error!\n");
		return 0;
	}
	if (up->look)	{
		tprintf ("Already looking at %s\n", argv[1]);
		return 0;
	}
	if (lk.user == Curproc->input || lk.user == Curproc->output)	{
		tputs ("Can not look at myself!\n");
		return 0;
	}
	/* Now everything seems okay ! Get a session */
	if ((lk.sp = newsession (name, LOOK, 1)) == NULLSESSION)	{
		tputs (TooManySessions);
		return 0;
	}
  
	up->look = Curproc;     /* Tell the socket to echo data to this process ! */
	chat = 0;
	block = sockblock (Curproc->input, SOCK_NORXBLOCK);
  
	tprintf ("%s session %d looking at %s\n", Sestypes[lk.sp->type], lk.sp->index, argv[1]);
  
	/* Process whatever's typed on the terminal */
	memset (buf, 0, MBXLINE);   /* Clear the input buffer */
	while (nb_recvline (Curproc->input, (unsigned char *) buf, sizeof(buf) - 1) >= 0) {
		if (itop (lk.user) == NULLUSOCK)
			break;
		if (buf[0] == '/')	{
			cp = skipnonwhite (buf);
			cp = skipwhite (cp);
			/* process commands */
			switch (tolower (buf[1])) {
				case 'h':
				case '?':
#ifdef MAILBOX
					tputs ("<Cmds>: /c-chat /i-insert /m-msg /q-quit\n");
#else
					tputs ("<Cmds>: /q-quit\n");
#endif
					break;
#ifdef MAILBOX
				case 'm':   /* Send a message to the user */
					if (i == NUMMBX)          /* Not a mailbox user */
						break;
#if 0
					cp = &buf[2];
					if (buf[2] == ' ')
						cp = &buf[3];
#endif
					usprintf (lk.user, "<sysop>: %s", cp);
					break;
				case 'c':   /* Initiate chat mode */
					if (chat || i == NUMMBX)
						/* Already in 'chat' mode or not a mailbox user */
						break;
					(void) usputs (lk.user, "*** SYSOP Initiated CHAT.\n");
					up->look = NULL;    /* Disable echoing in socket layer */
					/* Now we need to redirect the network input
					 * from the user's bbs process to the chat process
					 */
					lk.sp->proc1 = newproc ("CHAT Server", 1024, look_input, 0,
						(void *)&lk, NULL, 0);
					chat = 1;
					break;
#endif
				case 'i':
#if 0
					cp = skipnonwhite (buf);
					cp = skipwhite (cp);
#endif
					up->insertptr = up->insertbuf = strdup (cp);
					(void) usputs (lk.user, cp);
					break;
				case 'b':
				case 'e':
				case 'q':   /* quit chat mode, or look mode */
#ifdef MAILBOX
					if (!chat)
						goto done;

					lk.sp->proc1 = NULLPROC;
					up->look = Curproc; /* Enable echoing in socket layer */
					(void) usputs (lk.user, "*** BACK in mailbox\n");
					kpause (500);
					kwait (NULL);	/* wait for the death of look_input */
					chat = 0;
#else
					goto done;
#endif
					break;
				default:
					break;
			}
		}
#ifdef MAILBOX
		else if (chat)
			usprintf (lk.user, "<sysop>: %s", buf);
#endif
  
		usflush (lk.user);
		usflush (Curproc->output);
		memset (buf, 0, MBXLINE);   /* Clear the input buffer */
	}	
done:
	(void) sockblock (Curproc->input, block);
	/* A 'close' command was given, or user disconnected.
	 * Notify the user, kill the receiver input task and wait for a response
	 * from the user before freeing the session.
	 */
	cp2 = sockerr (lk.sp->input);
	tprintf ("\n%s session %u closed: %s\n", Sestypes[lk.sp->type], lk.sp->index,
		(cp2 != NULLCHAR) ? cp2 : "EOF");
  
	if ((up = itop (lk.user)) != NULLUSOCK)   /* Make sure socket is still there */
		up->look = NULL;
#ifdef MAILBOX
	if (lk.sp->proc1 != NULLPROC) {
		/* kill the receive process */
		lk.sp->proc1 = NULLPROC;
		if (up) {
			(void) usputs (lk.user, "*** BACK in mailbox\n");
			usflush (lk.user);
		}
	}
#endif
	(void) keywait (NULLCHAR, 1);
	freesession (lk.sp);
	return 0;
}

  
#ifdef MAILBOX
/* Task that read the user's input socket (that formerly went to the socket
 * process), and sends it to the look session !
 */
static void
look_input(unused,p1,p2)
int unused OPTIONAL;
void *p1;
void *p2 OPTIONAL;
{
struct session *sp;
struct usock *up;
int user,c;
int block;
int done = 0;

	sp = ((struct look *)p1)->sp;
	user = ((struct look *)p1)->user;

	if ((up = itop (user)) == NULLUSOCK) {
		/* Make sure our parent doesn't try to kill us after we exit */
		sp->proc1 = NULLPROC;
		return;
	}

	/* Suspend the process that owns the socket */
	suspend (up->owner);

	/* Get current blocking mode and set to non-block */
	block = sockblock (user, SOCK_NORXBLOCK);

	/* Process input on the users socket connection */
	while (!done)	{
		while ((c = recvchar (user)) == EOF)	{
			if (errno != EWOULDBLOCK || sp->proc1 == NULLPROC)	{
				done = 1;
				break;
			}
			kpause (500);
		}
		if (!done)
			tputc ((unsigned char)c);
	}
	if (sp->proc1 != NULLPROC)
		tputs ("*** Remote user disconnected!\n");

	/* Reset to original blocking mode */
	(void) sockblock (user, block);

	/* Make sure our parent doesn't try to kill us after we exit */
	sp->proc1 = NULLPROC;

	/* Alert the parent, in case the chat was terminated by losing the
	 * user connection. This in effect will close the look session
	 */
	alert (sp->proc, ENOTCONN);

	/* Resume the process that owns the socket */
	resume (up->owner);
}
#endif /* MAILBOX */
  
#endif /* LOOKSESSION */
