Updates for mbnntp

This commit is contained in:
Michiel Broek 2004-04-12 11:50:34 +00:00
parent ee0f125f9b
commit 3ddd56e7c5
7 changed files with 261 additions and 453 deletions

View File

@ -3,9 +3,9 @@
include ../Makefile.global include ../Makefile.global
SRCS = mbnntp.c openport.c ttyio.c SRCS = mbnntp.c openport.c ttyio.c auth.c
HDRS = mbnntp.h openport.h ttyio.h HDRS = mbnntp.h openport.h ttyio.h auth.h
OBJS = mbnntp.o openport.o ttyio.o OBJS = mbnntp.o openport.o ttyio.o auth.o
LIBS += ../lib/libmbse.a ../lib/libdbase.a ../lib/libmsgbase.a LIBS += ../lib/libmbse.a ../lib/libdbase.a ../lib/libmsgbase.a
OTHER = Makefile OTHER = Makefile
@ -55,7 +55,8 @@ depend:
# DO NOT DELETE THIS LINE - MAKE DEPEND RELIES ON IT # DO NOT DELETE THIS LINE - MAKE DEPEND RELIES ON IT
# Dependencies generated by make depend # Dependencies generated by make depend
mbnntp.o: ../config.h ../lib/mbselib.h ../lib/users.h ../lib/mbsedb.h openport.h ttyio.h mbnntp.h mbnntp.o: ../config.h ../lib/mbselib.h ../lib/users.h ../lib/mbsedb.h openport.h ttyio.h auth.h mbnntp.h
openport.o: ../config.h ../lib/mbselib.h openport.h openport.o: ../config.h ../lib/mbselib.h openport.h
ttyio.o: ../config.h ../lib/mbselib.h ttyio.h ttyio.o: ../config.h ../lib/mbselib.h ttyio.h
auth.o: ../config.h ../lib/mbselib.h mbnntp.h auth.h
# End of generated dependencies # End of generated dependencies

171
mbnntp/auth.c Normal file
View File

@ -0,0 +1,171 @@
/*****************************************************************************
*
* $Id$
*
*****************************************************************************
* Copyright (C) 1997-2004
*
* Michiel Broek FIDO: 2:280/2802
* Beekmansbos 10
* 1971 BV IJmuiden
* the Netherlands
*
* This file is part of MBSE BBS.
*
* This BBS is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2, or (at your option) any
* later version.
*
* MBSE BBS is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with MBSE BBS; see the file COPYING. If not, write to the Free
* Software Foundation, 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
*****************************************************************************/
#include "../config.h"
#include "../lib/mbselib.h"
#include "../lib/users.h"
#include "mbnntp.h"
#include "auth.h"
int authorized = FALSE; /* Authentication status */
int got_username = FALSE; /* Did we get a username? */
int grecno = 0; /* User record number */
char username[9]; /* Cached username */
extern pid_t mypid;
int check_auth(char *cmd)
{
if (authorized)
return TRUE;
send_nntp("480 Authentication required");
return FALSE;
}
void auth_user(char *cmd)
{
char *p;
p = strtok(cmd, " \0");
p = strtok(NULL, " \0");
p = strtok(NULL, " \0");
if (strlen(p) > 8) {
/*
* Username too long
*/
WriteError("Got a username of %d characters", sizeof(p));
send_nntp("482 Authentication rejected");
return;
}
memset(&username, 0, sizeof(username));
strncpy(username, p, 8);
Syslog('n', "Cache username \"%s\"", printable(username, 0));
send_nntp("381 More authentication information required");
got_username = TRUE;
}
void auth_pass(char *cmd)
{
char *p, *temp;
FILE *fp;
int FoundName = FALSE;
if (! got_username) {
WriteError("Got AUTHINFO PASS before AUTHINFO USER");
send_nntp("482 Authentication rejected");
return;
}
p = strtok(cmd, " \0");
p = strtok(NULL, " \0");
p = strtok(NULL, " \0");
temp = calloc(PATH_MAX, sizeof(char));
sprintf(temp, "%s/etc/users.data", getenv("MBSE_ROOT"));
if ((fp = fopen(temp,"r+")) == NULL) {
/*
* This should not happen
*/
WriteError("$Can't open %s", temp);
send_nntp("482 Authentication rejected");
free(temp);
got_username = FALSE;
return;
}
free(temp);
grecno = 0;
fread(&usrconfighdr, sizeof(usrconfighdr), 1, fp);
while (fread(&usrconfig, usrconfighdr.recsize, 1, fp) == 1) {
if (strcmp(usrconfig.Name, username) == 0) {
FoundName = TRUE;
break;
}
grecno++;
}
if (!FoundName) {
fclose(fp);
Syslog('+', "Unknown user \"%s\", reject", username);
send_nntp("482 Authentication rejected");
got_username = FALSE;
memset(&usrconfig, 0, sizeof(usrconfig));
return;
}
if (strcasecmp(usrconfig.Password, p)) {
Syslog('+', "Password error, reject user \"%s\"", username);
send_nntp("482 Authentication rejected");
fclose(fp);
got_username = FALSE;
memset(&usrconfig, 0, sizeof(usrconfig));
return;
}
/*
* Update user record
*/
usrconfig.tLastLoginDate = time(NULL); /* Login date is current date */
usrconfig.iTotalCalls++; /* Increase calls */
/*
* Update user record.
*/
if (fseek(fp, usrconfighdr.hdrsize + (grecno * usrconfighdr.recsize), 0) != 0) {
WriteError("Can't seek in %s/etc/users.data", getenv("MBSE_ROOT"));
} else {
fwrite(&usrconfig, sizeof(usrconfig), 1, fp);
}
fclose(fp);
/*
* User logged in, tell it to the server. Check if a location is
* set, if Ask User location for new users is off, this field is
* empty but we have to send something to the server.
*/
if (strlen(usrconfig.sLocation))
UserCity(mypid, usrconfig.Name, usrconfig.sLocation);
else
UserCity(mypid, usrconfig.Name, (char *)"N/A");
IsDoing("Logged in");
Syslog('+', "User %s logged in", username);
authorized = TRUE;
got_username = FALSE;
send_nntp("281 Authentication accepted");
}

10
mbnntp/auth.h Normal file
View File

@ -0,0 +1,10 @@
#ifndef _MBAUTH_H
#define _MBAUTH_H
/* $Id$ */
int check_auth(char *); /* Check user is authorized */
void auth_user(char *); /* Auth username */
void auth_pass(char *); /* Auth password */
#endif

View File

@ -34,17 +34,17 @@
#include "../lib/mbsedb.h" #include "../lib/mbsedb.h"
#include "openport.h" #include "openport.h"
#include "ttyio.h" #include "ttyio.h"
#include "auth.h"
#include "mbnntp.h" #include "mbnntp.h"
time_t t_start; time_t t_start;
time_t t_end; time_t t_end;
char *envptr = NULL; char *envptr = NULL;
struct sockaddr_in peeraddr; struct sockaddr_in peeraddr;
pid_t mypid;
extern char *ttystat[]; extern char *ttystat[];
extern int authorized;
void send_nntp(const char *, ...);
void die(int onsig) void die(int onsig)
@ -87,7 +87,7 @@ int main(int argc, char *argv[])
envptr = xstrcat(envptr, pw->pw_dir); envptr = xstrcat(envptr, pw->pw_dir);
putenv(envptr); putenv(envptr);
} }
mypid = getpid();
/* /*
* Read the global configuration data, registrate connection * Read the global configuration data, registrate connection
@ -97,11 +97,13 @@ int main(int argc, char *argv[])
InitUser(); InitUser();
InitFidonet(); InitFidonet();
umask(002); umask(002);
memset(&usrconfig, 0, sizeof(usrconfig));
t_start = time(NULL); t_start = time(NULL);
InitClient(pw->pw_name, (char *)"mbnntp", CFG.location, CFG.logfile, InitClient(pw->pw_name, (char *)"mbnntp", CFG.location, CFG.logfile,
CFG.util_loglevel, CFG.error_log, CFG.mgrlog, CFG.debuglog); CFG.util_loglevel, CFG.error_log, CFG.mgrlog, CFG.debuglog);
Syslog(' ', "MBNNTP v%s", VERSION); Syslog(' ', "MBNNTP v%s", VERSION);
IsDoing("Loging in");
/* /*
* Catch all the signals we can, and ignore the rest. * Catch all the signals we can, and ignore the rest.
@ -123,7 +125,7 @@ int main(int argc, char *argv[])
Syslog('s', "TCP connection: len=%d, family=%hd, port=%hu, addr=%s", Syslog('s', "TCP connection: len=%d, family=%hd, port=%hu, addr=%s",
addrlen,peeraddr.sin_family, peeraddr.sin_port, inet_ntoa(peeraddr.sin_addr)); addrlen,peeraddr.sin_family, peeraddr.sin_port, inet_ntoa(peeraddr.sin_addr));
Syslog('+', "Incoming connection from %s", inet_ntoa(peeraddr.sin_addr)); Syslog('+', "Incoming connection from %s", inet_ntoa(peeraddr.sin_addr));
send_nntp("200 Welcome to MBNNTP v%s (posting may or may not be allowed, try your luck)", VERSION); send_nntp("200 MBNNTP v%s server ready -- no posting allowed", VERSION);
nntp(); nntp();
} }
} }
@ -136,6 +138,46 @@ int main(int argc, char *argv[])
/*
* Get command from the client.
* return < 0: error
* return >= 0: size of buffer
*/
int get_nntp(char *buf, int max)
{
int c, len;
len = 0;
memset(buf, 0, sizeof(buf));
while (TRUE) {
c = tty_getc(180);
if (c <= 0) {
if (c == -2) {
/*
* Timeout
*/
send_nntp("400 Service discontinued");
}
Syslog('+', "Receiver status %s", ttystat[- c]);
return c;
}
if ((c == '\r') || (c == '\n'))
return len;
else {
buf[len] = c;
len++;
buf[len] = '\0';
}
if (len >= max) {
WriteError("Input buffer full");
return len;
}
}
return 0; /* Not reached */
}
void send_nntp(const char *format, ...) void send_nntp(const char *format, ...)
{ {
char *out; char *out;
@ -155,7 +197,7 @@ void send_nntp(const char *format, ...)
void command_list(void) void command_list(char *cmd)
{ {
send_nntp("215 List of newsgroups follows"); send_nntp("215 List of newsgroups follows");
@ -167,36 +209,14 @@ void command_list(void)
void nntp(void) void nntp(void)
{ {
char buf[4096]; char buf[4096];
int len, c; int len;
while (TRUE) { while (TRUE) {
len = 0;
memset(&buf, 0, sizeof(buf)); len = get_nntp(buf, sizeof(buf) -1);
while (TRUE) { if (len < 0)
c = tty_getc(180); return;
if (c <= 0) { if (len == 0)
if (c == -2) {
/*
* Timeout
*/
send_nntp("500 Timeout");
}
Syslog('+', "Receiver status %s", ttystat[- c]);
return;
}
if ((c == '\r') || (c == '\n'))
break;
else {
buf[len] = c;
len++;
buf[len] = '\0';
}
if (len == sizeof(buf)) {
WriteError("Input buffer full");
break;
}
}
if (strlen(buf) == 0)
continue; continue;
/* /*
@ -206,8 +226,13 @@ void nntp(void)
if (strncasecmp(buf, "QUIT", 4) == 0) { if (strncasecmp(buf, "QUIT", 4) == 0) {
send_nntp("205 Goodbye\r\n"); send_nntp("205 Goodbye\r\n");
return; return;
} else if (strncasecmp(buf, "AUTHINFO USER", 13) == 0) {
auth_user(buf);
} else if (strncasecmp(buf, "AUTHINFO PASS", 13) == 0) {
auth_pass(buf);
} else if (strncasecmp(buf, "LIST", 4) == 0) { } else if (strncasecmp(buf, "LIST", 4) == 0) {
command_list(); if (check_auth(buf))
command_list(buf);
} else if (strncasecmp(buf, "IHAVE", 5) == 0) { } else if (strncasecmp(buf, "IHAVE", 5) == 0) {
send_nntp("435 Article not wanted - do not send it"); send_nntp("435 Article not wanted - do not send it");
} else if (strncasecmp(buf, "NEWGROUPS", 9) == 0) { } else if (strncasecmp(buf, "NEWGROUPS", 9) == 0) {
@ -217,11 +242,23 @@ void nntp(void)
send_nntp("230 Warning: NEWNEWS not implemented, returning empty list"); send_nntp("230 Warning: NEWNEWS not implemented, returning empty list");
send_nntp("."); send_nntp(".");
} else if (strncasecmp(buf, "SLAVE", 5) == 0) { } else if (strncasecmp(buf, "SLAVE", 5) == 0) {
send_nntp("202 Slave status noted (but ignored)"); send_nntp("202 Slave status noted");
} else if (strncasecmp(buf, "MODE READER", 11) == 0) {
if (authorized)
send_nntp("200 Server ready, posting allowed");
else
send_nntp("201 Server ready, no posting allowed");
} else if (strncasecmp(buf, "HELP", 4) == 0) { } else if (strncasecmp(buf, "HELP", 4) == 0) {
send_nntp("100 Help text follows"); send_nntp("100 Help text follows");
send_nntp("Recognized commands:"); send_nntp("Recognized commands:");
send_nntp("");
send_nntp("AUTHINFO");
send_nntp("IHAVE (not implemented, messages are always rejected)");
send_nntp("LIST");
send_nntp("NEWGROUPS (not implemented, always returns an empty list)");
send_nntp("NEWNEWS (not implemented, always returns an empty list)");
send_nntp("QUIT"); send_nntp("QUIT");
send_nntp("SLAVE (has no effect)");
send_nntp(""); send_nntp("");
send_nntp("MBNNTP supports most of RFC-977 and also has support for AUTHINFO and"); send_nntp("MBNNTP supports most of RFC-977 and also has support for AUTHINFO and");
send_nntp("limited XOVER support (RFC-2980)"); send_nntp("limited XOVER support (RFC-2980)");

View File

@ -3,6 +3,8 @@
/* $Id$ */ /* $Id$ */
void send_nntp(const char *, ...);
int get_nntp(char *, int);
void nntp(void); void nntp(void);
#endif #endif

View File

@ -55,101 +55,6 @@ char *ttystat[]= {(char *)"Ok",
(char *)"Empty", (char *)"Empty",
(char *)"UnCompress"}; (char *)"UnCompress"};
int tty_resettimer(int tno);
void tty_resettimers(void);
int tty_settimer(int,int);
int tty_expired(int);
int tty_running(int);
#define RESETTIMER(x) tty_resettimer(x)
#define RESETTIMERS() tty_resettimers()
#define SETTIMER(x,y) tty_settimer(x,y)
#define EXPIRED(x) tty_expired(x)
#define RUNNING(x) tty_running(x)
/*
* timer functions
*/
int tty_resettimer(int tno)
{
if (tno >= NUMTIMERS) {
errno = EINVAL;
WriteError("ttyio: invalid timer No for resettimer(%d)", tno);
return -1;
}
timer[tno] = (time_t) 0;
return 0;
}
void tty_resettimers(void)
{
int i;
for (i = 0; i < NUMTIMERS; i++)
timer[i] = (time_t)0;
}
int tty_settimer(int tno, int interval)
{
if (tno >= NUMTIMERS) {
errno = EINVAL;
WriteError("ttyio: invalid timer No for settimer(%d)", tno);
return -1;
}
timer[tno]=time((time_t*)NULL)+interval;
return 0;
}
int tty_expired(int tno)
{
time_t now;
if (tno >= NUMTIMERS) {
errno = EINVAL;
WriteError("ttyio: invalid timer No for expired(%d)", tno);
return -1;
}
/*
* Check if timer is running
*/
if (timer[tno] == (time_t) 0)
return 0;
now = time(NULL);
return (now >= timer[tno]);
}
int tty_running(int tno)
{
if (tno > NUMTIMERS) {
errno = EINVAL;
WriteError("ttyio: invalid timer for tty_running(%d)", tno);
return -1;
}
/*
* check if timer is running
*/
if (timer[tno] == (time_t) 0)
return 0;
else
return 1;
}
/* /*
@ -264,141 +169,6 @@ int tty_write(char *buf, int size)
/* public r/w functions */
/*
* Check if there is data available on stdin.
*/
int tty_check(void)
{
int rc;
// try to read available (timeout = 0) data if we have no data in
// our buffer
if (!left) {
rc = tty_read(buffer, TT_BUFSIZ, 0);
if (rc > 0) {
left = rc;
}
}
return (left > 0);
}
int tty_putcheck(int size)
{
fd_set set;
struct timeval timeout;
/*
* Initialize the file descriptor set.
*/
FD_ZERO(&set);
FD_SET(1, &set);
/*
* Initialize the timeout data structure.
*/
timeout.tv_sec = 0;
timeout.tv_usec = 0;
/*
* `select' returns 0 if timeout, 1 if input available, -1 if error.
*/
return select(FD_SETSIZE, NULL, &set, NULL, &timeout);
}
int tty_waitputget(int tot)
{
int i, rc;
time_t timeout, now;
fd_set readfds, writefds, exceptfds;
struct timeval seltimer;
tty_status=0;
now = time(NULL);
timeout=(time_t)300; /* maximum of 5 minutes */
for (i = 0; i < NUMTIMERS; i++) {
if (timer[i]) {
if (now >= timer[i]) {
tty_status = STAT_TIMEOUT;
WriteError("tty_waitputget: timer %d already expired, return",i);
return -tty_status;
} else {
if (timeout > (timer[i]-now))
timeout = timer[i]-now;
}
}
}
if ((tot != -1) && (timeout > tot))
timeout=tot;
Syslog('t', "tty_waitputget: timeout=%d",timeout);
/*
* Initialize the file descriptor set.
*/
FD_ZERO(&readfds);
FD_ZERO(&writefds);
FD_ZERO(&exceptfds);
FD_SET(0, &readfds);
FD_SET(1, &writefds);
FD_SET(0, &exceptfds);
FD_SET(1, &exceptfds);
/*
* Initialize the timeout data structure.
*/
seltimer.tv_sec = timeout;
seltimer.tv_usec = 0;
/*
* `select' returns 0 if timeout, 1 if input available, -1 if error.
*/
rc = select(FD_SETSIZE, &readfds, &writefds, &exceptfds, &seltimer);
if (rc < 0) {
if (hanged_up) {
tty_status=STAT_HANGUP;
WriteError("tty_waitputget: hanged_up flag");
} else {
WriteError("$tty_waitputget: select failed");
tty_status=STAT_ERROR;
}
} else if (rc == 0) {
tty_status=STAT_TIMEOUT;
} else {
/* rc > 0 */
if ((FD_ISSET(0,&exceptfds)) || (FD_ISSET(1,&exceptfds))) {
WriteError("$tty_waitputget: exeption error");
tty_status=STAT_ERROR;
}
}
if (tty_status) {
Syslog('t', "tty_waitputget: return after select status %s",ttystat[tty_status]);
return -tty_status;
}
rc = 0;
if (FD_ISSET(0,&readfds))
rc |= 1;
if (FD_ISSET(1,&writefds))
rc |= 2;
return rc;
}
void tty_flushin(void) void tty_flushin(void)
{ {
tcflush(0, TCIFLUSH); tcflush(0, TCIFLUSH);
@ -412,27 +182,6 @@ void tty_flushout(void)
} }
int tty_ungetc(int c)
{
if (next == buffer) {
if (left >= TT_BUFSIZ) {
return -1;
}
next = buffer + TT_BUFSIZ - left;
memcpy(next, buffer, left);
}
next--;
*next = c;
left++;
return 0;
}
int tty_getc(int tot) int tty_getc(int tot)
{ {
if (!left) { if (!left) {
@ -450,138 +199,9 @@ int tty_getc(int tot)
} }
int tty_get(char *buf, int size, int tot)
{
int result=0;
if (left >= size) {
memcpy(buf,next,size);
next += size;
left -= size;
return 0;
}
if (left > 0) {
memcpy(buf,next,left);
buf += left;
next += left;
size -= left;
left=0;
}
while ((result=tty_read(buf,size,tot)) > 0) {
buf += result;
size -= result;
}
return result;
}
int tty_putc(int c)
{
char buf = c;
return tty_write(&buf,1);
}
int tty_put(char *buf, int size) int tty_put(char *buf, int size)
{ {
return tty_write(buf,size); return tty_write(buf,size);
} }
int tty_putget(char **obuf, int *osize, char **ibuf, int *isize)
{
time_t timeout, now;
int i, rc;
fd_set readfds, writefds, exceptfds;
struct timeval seltimer;
tty_status = 0;
now = time(NULL);
timeout = (time_t)300; /* maximum of 5 minutes */
for (i = 0; i < NUMTIMERS; i++) {
if (timer[i]) {
if (now >= timer[i]) {
tty_status = STAT_TIMEOUT;
WriteError("tty_putget: timer %d already expired, return",i);
return -tty_status;
} else {
if (timeout > (timer[i]-now))
timeout=timer[i]-now;
}
}
}
Syslog('t', "tty_putget: timeout=%d",timeout);
FD_ZERO(&readfds);
FD_ZERO(&writefds);
FD_ZERO(&exceptfds);
FD_SET(0,&readfds);
FD_SET(1,&writefds);
FD_SET(0,&exceptfds);
FD_SET(1,&exceptfds);
seltimer.tv_sec=timeout;
seltimer.tv_usec=0;
rc=select(2,&readfds,&writefds,&exceptfds,&seltimer);
if (rc < 0) {
if (hanged_up) {
tty_status=STAT_HANGUP;
WriteError("tty_putget: hanged_up flag");
} else {
WriteError("$tty_putget: select failed");
tty_status=STAT_ERROR;
}
} else if (rc == 0) {
tty_status=STAT_TIMEOUT;
} else {
/* rc > 0 */
if ((FD_ISSET(0,&exceptfds)) || (FD_ISSET(1,&exceptfds))) {
WriteError("$tty_putget: exeption error");
tty_status=STAT_ERROR;
}
}
if (tty_status) {
Syslog('t', "tty_putget: return after select status %s",ttystat[tty_status]);
return -tty_status;
}
if (FD_ISSET(0,&readfds) && *isize) {
rc = read(0, *ibuf, *isize);
if (rc < 0) {
WriteError("$tty_putget: read failed");
tty_status=STAT_ERROR;
} else {
(*ibuf)+=rc;
(*isize)-=rc;
}
}
if (FD_ISSET(1,&writefds) && *osize) {
rc=write(1, *obuf, *osize);
if (rc < 0) {
WriteError("$tty_putget: write failed");
tty_status=STAT_ERROR;
} else {
(*obuf)+=rc;
(*osize)-=rc;
}
}
if (tty_status)
return -tty_status;
else
return ((*isize == 0) | ((*osize == 0) << 1));
}

View File

@ -3,28 +3,11 @@
/* $Id$ */ /* $Id$ */
#define TIMERNO_BRAIN 0 /* BRAIN timerno */
#define TIMERNO_RX 1 /* Receiver timerno */
#define TIMERNO_TX 2 /* Transmitter timerno */
#define RESETTIMER(x) tty_resettimer(x)
#define RESETTIMERS() tty_resettimers()
#define SETTIMER(x,y) tty_settimer(x,y)
#define EXPIRED(x) tty_expired(x)
#define RUNNING(x) tty_running(x)
#define TCHECK() tty_check()
#define PUTCHECK(x) tty_putcheck(x)
#define WAITPUTGET(x) tty_waitputget(x)
#define FLUSHOUT() tty_flushout() #define FLUSHOUT() tty_flushout()
#define FLUSHIN() tty_flushin() #define FLUSHIN() tty_flushin()
#define PUTCHAR(x) tty_putc(x)
#define PUT(x,y) tty_put(x,y) #define PUT(x,y) tty_put(x,y)
#define PUTSTR(x) tty_put(x,strlen(x)) #define PUTSTR(x) tty_put(x,strlen(x))
#define GETCHAR(x) tty_getc(x) #define GETCHAR(x) tty_getc(x)
#define UNGETCHAR(x) tty_ungetc(x)
#define GET(x,y,z) tty_get(x,y,z)
#define PUTGET(a,b,x,y) tty_putget(a,b,x,y)
#define STATUS tty_status #define STATUS tty_status
#define STAT_SUCCESS 0 #define STAT_SUCCESS 0
@ -42,27 +25,11 @@
#define HANGUP (-STAT_HANGUP) #define HANGUP (-STAT_HANGUP)
#define EMPTY (-STAT_EMPTY) #define EMPTY (-STAT_EMPTY)
#define GET_COMPLETE(x) (x & 1)
#define PUT_COMPLETE(x) (x & 2)
extern int tty_status; extern int tty_status;
extern int tty_resettimer(int tno);
extern void tty_resettimers(void);
extern int tty_settimer(int,int);
extern int tty_expired(int);
extern int tty_running(int);
extern int tty_check(void);
extern int tty_waitputget(int);
extern int tty_ungetc(int);
extern int tty_getc(int); extern int tty_getc(int);
extern int tty_get(char*,int,int);
extern int tty_putcheck(int);
extern int tty_putc(int);
extern int tty_put(char*,int); extern int tty_put(char*,int);
extern int tty_putget(char**,int*,char**,int*);
extern void tty_flushout(void); extern void tty_flushout(void);
extern void tty_flushin(void); extern void tty_flushin(void);
extern void sendbrk(void);
#endif #endif