Travis Cross d2edcad66e Merge Phil Zimmermann's libzrtp as a FreeSWITCH library
Thanks to Phil Zimmermann for the code and for the license exception
we needed to include it.

There remains some build system integration work to be done before
this code will build properly in the FreeSWITCH tree.
2012-03-31 23:42:27 +00:00

261 lines
4.6 KiB
C

/*
* Copyright (c) 1995 Colin Plumb. All rights reserved.
* For licensing and other legal details, see the file legal.c.
*
* kbunix.c - Unix keyboard input routines.
*/
/*
* Define NOTERMIO if you don't have the termios stuff
*/
#include "first.h"
#include <fcntl.h>
#include <signal.h>
#include <stdio.h>
#include <stdlib.h> /* For exit() */
#include <sys/types.h>
/* How to get cbreak mode */
#if defined(NOTERMIO)
#include <sgtty.h> /* No termio: Use ioctl() TIOCGETP and TIOCSETP */
#elif defined(SVR2)
#include <termio.h> /* SVR2: Use ioctl() TCGETA and TCSETAF */
#else /* Usual case */
#include <termios.h> /* Posix: use tcgetattr/tcsetattr */
#endif
#ifdef sun /* including ioctl.h and termios.h gives a lot of warnings on sun */
#include <sys/filio.h>
#else
#include <sys/ioctl.h> /* for FIONREAD */
#endif /* sun */
#ifndef FIONREAD
#define FIONREAD TIOCINQ
#endif
#include "posix.h" /* For read(), sleep() */
#include "kb.h"
#if UNITTTEST
#define randEvent(c) (void)c
#else
#include "random.h"
#endif
#include "kludge.h"
/* The structure to hold the keyuboard's state */
#if defined(NOTERMIO)
static struct sgttyb kbState0, kbState1;
#elif defined(SVR2)
static struct termio kbState0, kbState1;
#else
static struct termios kbState0, kbState1;
#endif
#ifndef CBREAK
#define CBREAK RAW
#endif
/* The basic task of getting the terminal into CBREAK mode. */
static void
kbInternalCbreak(int fd)
{
#ifdef NOTERMIO
if (ioctl(fd, TIOCGETP, &kbState0) < 0) {
fprintf (stderr, "\nUnable to get terminal characteristics: ");
perror("ioctl");
exit(1);
}
kbState1 = kbState0;
kbState1.sg_flags |= CBREAK;
kbState1.sg_flags &= ~ECHO;
ioctl(fd, TIOCSETP, &kbState1);
#else /* !NOTERMIO - the usual case */
#ifdef SVR2
if (ioctl(fd, TCGETA, &kbState0) < 0)
#else
if (tcgetattr(fd, &kbState0) < 0)
#endif
{
fprintf (stderr, "\nUnable to get terminal characteristics: ");
perror("ioctl");
exit(1);
}
kbState1 = kbState0;
kbState1.c_cc[VMIN] = 1;
kbState1.c_cc[VTIME] = 0;
kbState1.c_lflag &= ~(ECHO|ICANON);
#ifdef SVR2
ioctl(fd, TCSETAF, &kbState1);
#else
tcsetattr(fd, TCSAFLUSH, &kbState1);
#endif /* not SVR2 */
#endif /* !NOTERMIO */
}
/* Restore the terminal to normal operation */
static void
kbInternalNorm(int fd)
{
#if defined(NOTERMIO)
ioctl(fd, TIOCSETP, &kbState0);
#elif defined(SVR2)
ioctl(fd, TCSETAF, &kbState0);
#else /* Usual case */
tcsetattr (fd, TCSAFLUSH, &kbState0);
#endif
}
/* State variables */
static volatile int kbCbreakFlag = 0;
static int kbFd = -1;
#ifdef SVR2
static int (*savesig)(int);
#else
static void (*savesig)(int);
#endif
/* A wrapper around SIGINT and SIGCONT to restore the terminal modes. */
static void
kbSig1(int sig)
{
if (kbCbreakFlag)
kbInternalNorm(kbFd);
if (sig == SIGINT)
signal(sig, savesig);
else
signal(sig, SIG_DFL);
raise(sig); /* Re-send the signal */
}
static void
kbAddSigs(void);
/* Resume cbreak after SIGCONT */
static void
kbSig2(int sig)
{
(void)sig;
if (kbCbreakFlag)
kbInternalCbreak(kbFd);
else
kbAddSigs();
}
static void
kbAddSigs(void)
{
savesig = signal (SIGINT, kbSig1);
#ifdef SIGTSTP
signal (SIGCONT, kbSig2);
signal (SIGTSTP, kbSig1);
#endif
}
static void
kbRemoveSigs(void)
{
signal (SIGINT, savesig);
#ifdef SIGTSTP
signal (SIGCONT, SIG_DFL);
signal (SIGTSTP, SIG_DFL);
#endif
}
/* Now, at last, the externally callable functions */
void
kbCbreak(void)
{
if (kbFd < 0) {
kbFd = open("/dev/tty", O_RDWR);
if (kbFd < 0) {
fputs("Can't open tty; using stdin\n", stderr);
kbFd = STDIN_FILENO;
}
}
kbAddSigs();
kbCbreakFlag = 1;
kbInternalCbreak(kbFd);
}
void
kbNorm(void)
{
kbInternalNorm(kbFd);
kbCbreakFlag = 0;
kbRemoveSigs();
}
int
kbGet(void)
{
int i;
char c;
i = read(kbFd, &c, 1);
if (i < 1)
return -1;
randEvent(c);
return c;
}
/*
* Flush any pending input. If "thorough" is set, tries to be more
* thorough about it. Ideally, wait for 1 second of quiet, but we
* may do something more primitive.
*
* kbCbreak() has the side effect of flushing the inout queue, so this
* is not too critical.
*/
void
kbFlush(int thorough)
{
if (thorough)
sleep(1);
#if defined(TCIFLUSH)
tcflush(kbFd, TCIFLUSH);
#elif defined(TIOCFLUSH)
#ifndef FREAD
#define FREAD 1 /* The usual value */
#endif
ioctl(kbFd, TIOCFLUSH, FREAD);
#endif
}
#if UNITTEST /* Self-contained test driver */
#include <ctype.h>
int
main(void)
{
int c;
puts("Going to cbreak mode...");
kbCbreak();
puts("In cbreak mode. Please type.");
for (;;) {
c = kbGet();
if (c == '\n' || c == '\r')
break;
printf("c = %d = '%c'\n", c, c);
kbFlush(isupper(c));
}
puts("Returning to normal mode...");
kbNorm();
puts("Done.");
return 0;
}
#endif /* UNITTEST */