/*******************************************************************************
 * Copyright (c) 2002, 2009 QNX Software Systems and others.
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the Eclipse Public License v1.0
 * which accompanies this distribution, and is available at
 * http://www.eclipse.org/legal/epl-v10.html
 *
 * Contributors:
 *     QNX Software Systems - initial API and implementation
 *******************************************************************************/
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/ioctl.h>
#include <fcntl.h>
#include <termios.h>
#include <errno.h>
#include <unistd.h>
#include <stdio.h>
#include <string.h>
#include <grp.h>
#include <termios.h>

#include <stdlib.h>

/**
 * This is taken from R. W. Stevens book.
 * Alain Magloire.
 */

int ptym_open (char *pts_name);
int ptys_open (int fdm, const char * pts_name);

int
openpty(int *amaster, int *aslave, char *name, struct termios *termp, struct winsize *winp)
{
	char line[20];
	line[0]=0;
	*amaster = ptym_open(line);
	if (*amaster < 0)
		return -1;
	*aslave = ptys_open(*amaster, line);
	if (*aslave < 0) {
		close(*amaster);
		return -1;
	}
	if (name)
		strcpy(name, line);
#ifndef TCSAFLUSH
#define TCSAFLUSH TCSETAF
#endif
	if (termp)
		(void) tcsetattr(*aslave, TCSAFLUSH, termp);
#ifdef TIOCSWINSZ
	if (winp)
		(void) ioctl(*aslave, TIOCSWINSZ, (char *)winp);
#endif
	return 0;
}

int
ptym_open(char * pts_name)
{
	char *ptr1, *ptr2;
	int fdm;
	
	strcpy(pts_name, "/dev/ptyXY");
	/* array index: 012345689 (for references in following code) */
	for (ptr1 = "pqrstuvwxyzPQRST"; *ptr1 != 0; ptr1++) {
		pts_name[8] = *ptr1;
		for (ptr2 = "0123456789abcdef"; *ptr2 != 0; ptr2++) {
			pts_name[9] = *ptr2;
			/* try to open master */
			fdm = open(pts_name, O_RDWR);
			if (fdm < 0) {
				if (errno == ENOENT) {/* different from EIO */
					return -1;  /* out of pty devices */
				} else {
					continue;  /* try next pty device */
				}
			}
			pts_name[5] = 't'; /* chage "pty" to "tty" */
			return fdm;   /* got it, return fd of master */
		}
	}
	return -1; /* out of pty devices */
}

int
ptys_open(int fdm, const char * pts_name)
{
	int gid, fds;
	struct group *grptr;

	grptr = getgrnam("tty");
	if (grptr != NULL) {
		gid = grptr->gr_gid;
	} else {
		gid = -1;  /* group tty is not in the group file */
	}

	/* following two functions don't work unless we're root */
	chown(pts_name, getuid(), gid);
	chmod(pts_name, S_IRUSR | S_IWUSR | S_IWGRP);
	fds = open(pts_name, O_RDWR);
	if (fds < 0) {
		close(fdm);
		return -1;
	}
	
#if	defined(TIOCSCTTY)
	/*  TIOCSCTTY is the BSD way to acquire a controlling terminal. */
	if (ioctl(fds, TIOCSCTTY, (char *)0) < 0) {
		// ignore error: this is expected in console-mode
	}
#endif
	
	return fds;
}

void
set_noecho(int fd)
{
	struct termios stermios;
	if (tcgetattr(fd, &stermios) < 0) {
		return ;
	}

	/* turn off echo */
	stermios.c_lflag &= ~(ECHO | ECHOE | ECHOK | ECHONL);
	/* Turn off the NL to CR/NL mapping ou output.  */
	/*stermios.c_oflag &= ~(ONLCR);*/

	stermios.c_iflag |= (IGNCR);

	tcsetattr(fd, TCSANOW, &stermios);
}
