/* UNIX like write program. Kees Lemmens; Juli 1992

   This programs can be used to communicate between two login sessions
   on a multitasking ATARI ST (MINT).
   It behaves just like the UNIX write utility.

   Bugs/remarks:
-  I don't know how to determine the ttyname, so at this moment I use a
   variable TTYNAME defined by GETTY. If not found then ttyname will be
   "console". LOGNAME will be "root" if this variable is not found.
-  Some programs - like tcsh - send a signal TTOU when a foreign process
   attempts to write to their tty. This causes the foreign process to be
   suspended. To avoid this problem the write program has to ignore such
   signals.
-  Because I don't want to rely upon a UTMP file, you can also write to
   devices instead of users by using the -l option.

   Any questions or suggestions about this program can be send to:
   lemmens@dv.twi.tudelft.nl
*/

#include <stdio.h>
#include <fcntl.h>	/* O_WRONLY etc. */
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include "ux_misc.h"
#include <utmp.h>
#include <signal.h>

void set_bell(void)
{	long stack=0;
	char *conterm=(void *)0x484;	/* CON attribs (bell, keyclick) */

	if(Super((void *)1L)==0)
		stack=Super((void *)0L);	/* supervisor mode */
	*conterm |= 4;					/* set bell attribute */
	if(stack) Super((void *)stack);	/* back to user mode  */
}

void fatal(char *txt)
{	fprintf(stderr,"WRITE: %s\n",txt);
	exit(1);
}

void do_write(char *totty)
{	int ttyfp;
	time_t sec;
	char c,warning[250],fulltty[100];
	char *name,*mytty,*endmsg="\r\n<EOT>\r\n";

	set_bell();
	time(&sec);

	if((name  = getenv("LOGNAME")) == NULL)	name  = "root";
	if((mytty = getenv("TTYNAME")) == NULL) mytty = "console";
	
	mk_devnm(fulltty,totty);
	if((ttyfp=open(fulltty,O_WRONLY)) < 0)
		fatal("Can't open tty");

	sprintf(warning,"\7\r\n\tMessage from %s (%s) [ %.19s ] ...\r\n\7",
		name,mytty,ctime(&sec));
	write(ttyfp,warning,strlen(warning));
	puts("\7Write your message (Ctrl-D to stop)\7");
	
	while(read(1,&c,1),c != '\4' && c != '\32')
	{	write(ttyfp,&c,1);
		if(c=='\r')
		{	write(ttyfp,"\n",1);
			putchar('\n');
		}
	}
	write(ttyfp,endmsg,strlen(endmsg));
	close(ttyfp);
}

void usage(void)
{	puts("\nUsage: write [-l <line>] | [<user>]");
	exit(1);
}

void name2tty(char *name,char *totty)
{	extern int utmp_fd;
	int fl=0;
	struct utmp *w;
	
	setutent();
	
	while((w=getutent()) != NULL && !fl)
	{	if(!strncmp(w->ut_name,name,sizeof(w->ut_name)) &&
			w->ut_type == USER_PROCESS)
		{	if(Pkill(w->ut_pid,SIGNULL) == 0) /* process exists ? */
			{	strncpy(totty,w->ut_line,sizeof(w->ut_line));
				fl=1;
			}
			else
			{	w->ut_type=DEAD_PROCESS;
				setutent();		/* rewind and */
				pututline(w);	/* correct UTMP entry */
			}
		}
	}
	endutent();
	if(!fl)
	{	puts("User is not logged on");
		exit(0);
	}	
}

void main(int argc,char *argv[]) 
{	char totty[100];
	int lfl=0;
	
#ifdef MINT /* ignore signal [Attempted write to foreign tty] */
	signal(SIGTTOU,SIG_IGN);
#endif	

	if(argc<2)	usage();
	
	while(--argc>0)			/* parse options */
	{	if(*argv[1]=='-')
		{	switch(*(++argv[1]))
			{	case 'l':	lfl=1;	break;
				default :	usage();
			}
			++argv;
		}
	}	
	if(lfl)	strcpy(totty,argv[1]);
	else	name2tty(argv[1],totty);
	
	do_write(totty);
}