home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Atari FTP
/
ATARI_FTP_0693.zip
/
ATARI_FTP_0693
/
Mint
/
Mgr
/
mgrterm.zoo
/
mgrterm.c
next >
Wrap
C/C++ Source or Header
|
1991-04-04
|
19KB
|
929 lines
/*
* mgrterm - a terminal emulator for MiNT/mgr
* term loop based on a very simple term emu by
* david@doe.utoronto.ca (David Megginson)
*
* ++jrb bammi@cadence.com
*/
/*
* Menus:
*
* Main Menu Baud Dial FlowControl
* --------- ---- ---- -----------
* Suspend 19200 ph#1 None
* Baud => 9600 .. Rts/Cts
* Dial => 2400 Xon/Xoff
* ToggleDuplex 1200 .. Both
* FlowControl => 300 ph#n
* StuffTermcap
* Shell
* Status
* =============
* Quit
*
*/
/* Whitepages
* the whitepages file may either be specified
* - on the command line
* - via the WHITEPAGES environment variable
* - otherwise the default below is used if it exists
* - if no white pages exits, the menu entry will contain a dummy.
* The dial pull right menu is paged, 15 entries/page.
*
* The whitepages files can contain
* - comments lines - begining with '#'
* - blank lines
* - entries
* a whitepages entry is for the form (max length of an entry == 132)
* name : [baud] : [dial string]
*
* the name is the key. only enough characters to make the search
* unambigious need be specified. imbedded blanks are significant.
* leading and trailing one are ignored. case is significant.
*
* if no baud is specified, then the present baud rate is not changed,
* otherwise the baud rate is set when the entry is chosen. leading and
* trailing blanks are ignored. if the baud specified is invalid, the dial
* is aborted.
*
* if a dial string is specified, it is sent to the modem with interpretation.
* leading blanks are ignored. tailing ones are significant. the dial string
* is interpreted as follows:
* \n, \r, \\ send newline, carriage return and backslash respectively.
* \nnn send octal char nnn
* \s<number> sleep for <number> seconds
* \t<number> set char wait timeout to <number> seconds (default 10 seconds)
* \w<char> wait until char, all chars occuring in the mean while
* are skipped. Abort dial on timeout. the char maybe
* specified in its octal form \nnn (\r etc not recognized).
*
* examples:
* unix direct login : 19200 : \w:bammi\r\w:mypasswd\r
* # switch to 19200 baud, wait for ':' send string "bammi\r" wait for ':'
* # send string "mypasswd\r". use default char wait timeout period.
* unix dialup : 2400 : atdt5551212\w:bammi\r\w:mypasswd\r
* compuserve : 2400 : atdt5551515\w2\w4\w0\w0\r\w:CIS\r\w:71515,111\r\w:xxx\r
* timbaktu :: atdt1timbaktu\r
* # use current baud rate
* 2400 : 2400 :
* # just change baud rate
*
*/
#include <stddef.h>
#include <stdlib.h>
#include <osbind.h>
#include <mintbind.h>
#include <string.h>
#include <setjmp.h>
#include <signal.h>
#include <unistd.h>
#include <fcntl.h>
#include <term.h>
#include "proto.h"
#ifndef Bconmap
#define Bconmap(dev) (short)trap_14_ww((short)(0x2c), (short)(dev))
#endif
#define Bconws(s) Boutput(2, (s))
#define CTRL(x) ((x) & 0x1f)
#define ESCAPE 0x001D /* CTRL-] */
#define QUIT 0x0080 /* <UNDO> */
#define MAXWAIT 20000L /* Maximum number of failed attempts */
/* to read a character before we */
/* start snoozing */
#define MIDIDEV 3 /* bios midi dev id */
int mgr = 1; /* mgr not pure MiNT */
int half = 0; /* doing half duplex */
int rsdev = 1; /* serial line */
char *phones = NULL; /* whitepages file */
char *default_phones = "d:/etc/white";
int baud; /* current baud rate */
int flow = 0; /* current flow */
int olddev = 0x2c;
typedef struct {
char *name;
char *baud;
char *number;
} WHITEPAGE;
WHITEPAGE *whitepages = 0; /* white pages entries */
int main(int argc, const char **argv)
{
unsigned long counter = 0;
unsigned short c;
extern char *optarg;
extern int optind, opterr;
while((c = getopt(argc, argv, "P:")) != -1)
{
switch(c)
{
case 'P':
rsdev = atoi(optarg);
if(rsdev != MIDIDEV)
olddev = Bconmap(rsdev);
break;
case '?':
Bconws((char *)(argv[0])); Bconws(" [-P serial device] [whitepages file]\r\n");
exit(1);
}
}
if(optind < argc)
phones = (char *)(argv[optind]);
init();
do{
/* We haven't found any activity yet */
counter++;
/* Check for a character from the modem */
if( Bconstat(rsdev) ) {
counter = 0;
c = ((int)Bconin(rsdev)) & 0x7f;
Bconout(2,c);
}
/* Check for a character from the cons */
if( Bconstat(2) ) {
counter = 0;
c = ((int)Bconin(2)) & 0x00FF;
if( c == QUIT )
do_quit();
else if( (c &= 0x7f) == ESCAPE )
do_escape();
else
{
Bconout(rsdev,c);
if(half)
Bconout(2, c);
}
}
/* Don't soak up CPU time if there is */
/* nothing going on! */
if( counter >= MAXWAIT )
Syield();
} while( 1 );
return 0;
}
struct {
int id;
char *str;
} men[] = {
{1, "\005\
Suspend \005\
BaudRate ==>\005\
DialNumber ==>\005\
ToggleDuplex \005\
FlowControl ==>\005\
StuffTermcap \005\
ShellCommand \005\
PrintStatus \005\
-----------------\005\
Quit \005\
\035z\005\
\035b\005\
\035d\005\
\035h\005\
\035f\005\
\035t\005\
\035!\005\
\035s\005\
\005\
\035q\005" },
{ 2, "\005\
19200 \005\
9600 \005\
4800 \005\
3600 \005\
2400 \005\
2000 \005\
1800 \005\
1200 \005\
600 \005\
300 \005\
200 \005\
150 \005\
134 \005\
110 \005\
75 \005\
50 \005\
19200\r\005\
9600\r\005\
4800\r\005\
3600\r\005\
2400\r\005\
2000\r\005\
1800\r\005\
1200\r\005\
600\r\005\
300\r\005\
200\r\005\
150\r\005\
134\r\005\
110\r\005\
75\r\005\
50\r\005" },
{3, "\005\
None \005\
Rts/Cts \005\
Xon/Xoff \005\
Both \005\
n\r\005\
r\r\005\
x\r\005\
b\r\005" },
{0, (char *)0 }}, default_dial =
{ 4, "\005\
none \005\
ATH\r\005" };
int ndialmenus; /* number of dial sub menus menus */
int ndial; /* number of whitepages entries */
int lastm; /* last menu before dial menus(or first dial menu) */
_IOREC *iorec_p, save_iorec;
char myrsbuf[16384];
char linebuf[132];
void init(void)
{
char *getenv(const char *);
char *s = getenv("TERM");
if(s)
mgr = !strcmp(s, "mgr");
else
mgr = 1; /* no TERM -- assume mgr */
iorec_p = (_IOREC *)Iorec((rsdev == MIDIDEV)? 2 : 0);
save_iorec = *iorec_p;
iorec_p->ibuf = myrsbuf;
iorec_p->ibufsiz = sizeof(myrsbuf);
iorec_p->ibuflow = sizeof(myrsbuf) >> 3;
iorec_p->ibufhi = (sizeof(myrsbuf) >> 2) * 3;
iorec_p->ibufhd = iorec_p->ibuftl = 0;
if(rsdev != MIDIDEV)
{
baud = Rsconf(-2, -1, -1, -1, -1, -1);
Rsconf(-1, 0, -1, -1, -1, -1);
}
else
{
baud = 16;
flow = 0;
}
if(!phones)
phones = getenv("WHITEPAGES");
if(!phones)
phones = default_phones;
if(access(phones, R_OK))
phones = NULL;
if(phones) read_whitepages(phones);
if( mgr )
{
m_setup(M_FLUSH|M_DEBUG);
m_push(P_FLAGS|P_MENU);
m_setmode(M_BACKGROUND);
download_menus();
}
}
void do_quit(void)
{
int i;
*iorec_p = save_iorec;
Bconws("\r\n");
if( mgr )
{
m_nomenu();
for(i = ndialmenus+lastm-1; i > lastm; i--)
{
m_unpagemenu(i-1);
}
m_unlinkmenu(1, 2);
m_unlinkmenu(1, 4);
m_unlinkmenu(1, 1);
for(i = lastm; i < ndialmenus+lastm; i++)
m_clearmenu(i);
for(i = 0; men[i].id; i++)
m_clearmenu(men[i].id);
m_pop();
}
if((rsdev != MIDIDEV) && (olddev != 0x2c))
(void)Bconmap(olddev);
exit(0);
}
void download_menus(void)
{
int i, j, k, l, len;
for(i = 0; men[i].id; i++)
{
m_loadmenu(men[i].id, men[i].str);
lastm = men[i].id;
}
m_linkmenu(1, 1, 2, 0);
m_linkmenu(1, 4, 3, 0);
i = ++lastm;
if(whitepages)
{
for(j = 0; (j < ndial) && (whitepages[j].name); j += 15)
{
#if 0
printf("Downloading %d\n", i);
#endif
fprintf(m_termout,"%c%d,", m_escchar, i);
for(len = 0, k = j; (k < (j+15)) && whitepages[k].name; k++)
len += (((int)strlen(whitepages[k].name)) + 1) * 2 + 1;
fprintf(m_termout, "%d%c", len+1, E_MENU);
strcpy(linebuf, "\005");
for(l = 0; l < 2; l++)
{
for(k = j; (k < (j+15)) && whitepages[k].name; k++)
{
strcat(linebuf, whitepages[k].name);
if(l == 0)
strcat(linebuf, "\005");
else
strcat(linebuf, "\r\005");
fprintf(m_termout, "%s", linebuf);
strcpy(linebuf, "");
}
}
fflush(m_termout);
#if 0
printf("Done Downloading %d(%d)\n", i, len+1);
#endif
if(i != lastm)
{
m_pagemenu(i-1, i);
#if 0
printf("Page %d to %d\n", i, i-1);
#endif
}
i++;
if(!(whitepages[k].name)) break;
}
ndialmenus = i - lastm;
}
else
{
m_loadmenu(lastm, default_dial.str);
ndialmenus = 1;
}
m_linkmenu(1, 2, lastm, 0);
m_selectmenu(1);
#if 0
printf("%d dial menus\n", ndialmenus);
#endif
}
char *prompt = "\r\nenter one of z b d h f t ! s q or ? for help: ";
char *help = "\r\n\n\
\tz\t\tto suspend\r\n\
\tb speed\t\tto set baud rate\r\n\
\td num\t\tto dial number\r\n\
\th\t\tto toggle duplex\r\n\
\tf nrxb\t\tto set flow control\r\n\
\tt\t\tto stuff termcap\r\n\
\t! cmd\t\tto execute cmd\r\n\
\ts\t\tto print status\r\n\
\tq\t\tto quit\r\n\
or <return> to cancel\r\n\n";
#define EECHO(c) if(!mgr) Bconout(2, (c))
void do_escape(void)
{
int c, done = 0;
while(!done)
{
if(!mgr)
Bconws(prompt);
c = Bconin(2) & 0x7f;
EECHO(c);
done = 1;
switch(c)
{
case '?':
Bconws(help);
done = 0;
break;
case '!':
do_shell();
break;
case 'b': case 'B':
do_baud();
break;
case 'q': case 'Q':
do_quit();
break;
case 'z': case 'Z': case '\032': /* ctl-z */
do_stop();
break;
case '\r':
Bconout(2, '\n');
break;
case '\n':
Bconout(2, '\r');
break;
case 'd': case 'D':
do_dial();
break;
case 'h': case 'H':
do_duplex();
break;
case 'f': case 'F':
do_flow();
break;
case 't': case 'T':
do_termcap();
break;
case 's': case 'S':
do_status();
break;
default:
done = 0;
}
}
}
char *getline(int echo)
{
char *l = linebuf;
int c;
while(! rindex("\n\r", (c = Bconin(2) &0x7f)) )
{
switch(c)
{
case '\b': case '\177':
if(echo) Bconws("\b \b");
break;
case CTRL('U'):
if(echo)
while(l-- != linebuf) Bconws("\b \b");
l = linebuf;
break;
default:
*l++ = c;
if(echo) Bconout(2, c);
}
}
if(echo)
Bconws("\r\n");
*l = '\0';
l = linebuf;
while((*l == ' ') || (*l == '\t')) l++;
return l;
}
void do_shell(void)
{
char *s;
if(mgr)
{
m_nomenu();
Bconws("\r\ncmd: ");
}
s = getline(1);
if(!(*s))
goto ret;
system(s);
Bconws("\r\nhit <return> to continue");
(void)getline(1);
ret:
if( mgr )
{
m_selectmenu(1);
}
}
struct {
char *string;
int value;
} bauds[] = {
{ "19200", 0 },
{ "9600", 1 },
{ "4800", 2 },
{ "3600", 3 },
{ "2400", 4 },
{ "2000", 5 },
{ "1800", 6 },
{ "1200", 7 },
{ "600", 8 },
{ "300", 9 },
{ "200", 10 },
{ "150", 11 },
{ "134", 12 },
{ "110", 13 },
{ "75", 14 },
{ "50", 15 },
{ "MidiBaud", 16},
{ (char *)0, -1}
};
void do_baud(void)
{
char *s;
while(1)
{
s = getline(!mgr);
if(!(*s))
return;
if(set_baud(s))
Bconws("Unknown baud rate, enter again or <return> to cancel: ");
else
return;
}
}
int set_baud(char *s)
{
int i;
for(i = 0; bauds[i].string; i++)
{
if(strcmp(s, bauds[i].string) == 0)
{
if(rsdev != MIDIDEV)
{
Rsconf(bauds[i].value, -1, -1, -1, -1, -1);
baud = bauds[i].value;
}
return 0;
}
}
return 1;
}
#include <signal.h>
void do_stop(void)
{
unsigned long omask;
if(mgr)
{
m_nomenu();
}
Bconws("\r\n");
omask = Psigsetmask(0L);
(void) Pkill(0, SIGTSTP);
(void) Psigsetmask(omask);
if( mgr )
{
m_selectmenu(1);
}
}
void do_duplex(void)
{
half = !half;
}
struct {
char c;
char *string;
} flows[] = {
{ 'n', "none" },
{ 'r', "Rts/Cts" },
{ 'x', "Xon/Xoff" },
{ 'b', "both" },
{ '\377', (char *)0 }
};
void do_flow(void)
{
int i, c;
if(!mgr)
{
Bconws("\r\nn(none) r(rts/cts) x(xon/xoff) or b(both): ");
}
while(1)
{
c = *(getline(!mgr));
if(c == '\0')
return;
for (i = 0; flows[i].c != '\377'; i++)
{
if(flows[i].c == c)
{
if(rsdev != MIDIDEV)
{
Rsconf(-1, i, -1, -1, -1, -1);
flow = i;
}
return;
}
}
Bconws("Unknown flow type, enter again or <return> to cancel: ");
}
}
char *atermcap = "\
atari|st52|Atari ST without al dl:\\\r\
:am:bl=^G:bs:cd=\\EJ:ce=\\EK:cl=\\EE:cm=\\EY%+ %+ :co#80:\\\r\
:do=^J:eo:ho=\\EH:is=\\Eq\\EE\\Ee\\Ev:it#8:le=^H:li#25:ll=\\EY9!:\\\r\
:me=\\Eq:mr=\\Ep:nd=\\EC:rc=\\Ek:sc=\\Ej:se=\\Eq:so=\\Ep:ta=^I:\\\r\
:ti=\\Eq\\Ev\\Ee:up=\\EA:ve=\\Ee:vi=\\Ef:";
void do_termcap(void)
{
char *termcap = (mgr)? get_termcap() : atermcap;
if(termcap)
{
Boutput(rsdev, "setenv TERMCAP '");
Boutput(rsdev, termcap);
Boutput(rsdev,"'\r");
}
}
void do_status(void)
{
Bconws("\r\nMgrterm $Revision: 1.2 $\r\n");
Bconws("\tBaud rate: "); Bconws(bauds[baud].string);
Bconws("\r\n\tFlow type: "); Bconws(flows[flow].string);
Bconws("\r\n\tSerial dev: "); Bconout(2, (rsdev+'0'));
Bconws("\r\n\tWhitepages: "); Bconws((phones)? phones:"none"); Bconws("\r\n");
}
void Boutput(int dev, char *s)
{
for( ; *s ; s++)
Bconout(dev, *s);
}
/* dialing stuff */
void do_dial(void)
{
char *s = getline(!mgr);
int i;
size_t len;
if((!(*s)) || (!whitepages))
return;
len = strlen(s);
for(i = 0; whitepages[i].name; i++)
{
if(!strncmp(whitepages[i].name, s, len))
{
if((*(whitepages[i].baud)) &&
strcmp(bauds[baud].string, whitepages[i].baud))
{
if(set_baud(whitepages[i].baud))
{
Bconws("\r\nInvalid baud rate ");Bconws(whitepages[i].baud);
Bconws(" for "); Bconws(whitepages[i].name);
Bconws(" dial aborted\r\n");
return;
}
Bconout(rsdev, '\r');
}
send_dial(whitepages[i].number);
return;
}
}
Bconws("\r\n"); Bconws(s); Bconws(": unlisted in whitepages\r\n");
}
#if __STDC__
char * strdup(const char *s);
#else
extern char *strdup();
#endif
void read_whitepages(char *file)
{
int pass, n = 0, i = 0;
FILE *fp = fopen(file, "r");
char *s, *p, *q, *r, *next;
if(!fp)
{
Bconws("\r\nCant find "); Bconws(file);
Bconws(" Continuing without it\r\n");
return;
}
for(pass = 0; pass < 2; pass++)
{
do {
do {
if((s = fgets(linebuf, sizeof(linebuf), fp)) == NULL)
break;
while((*s == ' ') || (*s == '\t')) s++;
} while((*s == '#') || (*s == '\n') || (*s == '\r'));
if(s == NULL)
{
if(pass == 0)
{
if((whitepages = (WHITEPAGE *)malloc((n+1) * sizeof(WHITEPAGE))) == NULL)
{
goto nomem;
}
fseek(fp, 0L, SEEK_SET);
bzero(whitepages, (n+1) * sizeof(WHITEPAGE));
}
break;
}
if(pass == 0)
{
n++;
continue;
}
s[(strlen(s) - 1)] = '\0';
p = s;
q = index(p, ':');
if((!q) || (q == p))
{
Invalid:
Bconws("Invalid entry: "); Bconws(s);
Bconws("\r\n Continuing without it\r\n");
if(whitepages[i].name) free(whitepages[i].name);
whitepages[i].name = NULL;
continue;
}
next = q+1;
for(--q; ((*q == ' ') || (*q == '\t')); --q) ;
*++q = '\0';
if(!(r = strdup(p)))
goto nomem;
whitepages[i].name = r;
p = next;
while((*p == ' ') || (*p == '\t')) p++;
q = index(p, ':');
if(!q) goto Invalid;
next = q+1;
if(q == p)
*q = '\0';
else
{
for(--q; ((*q == ' ') || (*q == '\t')); --q) ;
*++q = '\0';
}
if(!(r = strdup(p)))
goto nomem;
whitepages[i].baud = r;
p = next;
while((*p == ' ') || (*p == '\t')) p++;
if(!(r = strdup(p)))
goto nomem;
whitepages[i].number = r;
i++;
} while(1);
}
if(i == 0)
{
if(whitepages)
free(whitepages);
whitepages == NULL;
ndial = 0;
goto closeup;
}
if(i != n)
whitepages = realloc(whitepages, sizeof(WHITEPAGE)*(i+1));
if(!whitepages) goto nomem;
ndial = i; /* # of whitepages entries */
closeup:
fclose(fp);
#if 0
printf("Found %d entries\n", ndial);
for(i = 0; i < ndial; i++)
printf("%s %s %s\n", whitepages[i].name, whitepages[i].baud,
whitepages[i].number);
#endif
return;
nomem:
fclose(fp);
if(whitepages)
{
for(i = 0; whitepages[i].name; i++)
{
free(whitepages[i].name);
if(whitepages[i].baud) free(whitepages[i].baud);
if(whitepages[i].number) free(whitepages[i].number);
}
free(whitepages);
}
whitepages = NULL;
ndial = 0;
Bconws("\r\nNot enough memory for whitepages, continuing without them\r\n");
return;
}
#define isnumber(c) (((c) >= '0') && ((c) <= '9'))
int timeout = 10; /* char wait timeout */
void send_dial(char *s)
{
char c;
for(; (c = *s) ; s++)
{
if(c != '\\')
{
Bconout(rsdev, c);
if(half) Bconout(2, c);
continue;
}
switch((c = *++s))
{
case 'r':
Bconout(rsdev, '\r'); if(half) Bconout(2, '\r'); break;
case 'n':
Bconout(rsdev, '\n'); if(half) Bconout(2, '\n'); break;
case '\\':
Bconout(rsdev, '\\'); if(half) Bconout(2, '\\'); break;
case 's':
sleep(getnum(&s, 10)); break;
case 't':
timeout = getnum(&s, 10); if(timeout == 0) timeout = 10; break;
case 'w':
if((c = *++s) == '\\') c = getnum(&s, 8);
if(await_char(c))
{
Bconws("\r\nCharacter wait time out\r\n");
return;
}
break;
default:
if(isnumber(c))
{
unsigned char n = 0;
int i = 0;
do {
n = (n << 3) | (c - '0');
c = *++s;
i++;
} while(isnumber(c) && (i < 3));
--s;
Bconout(rsdev, n); if(half) Bconout(2, n);
}
else
{
Bconws("\r\nIllegal dial string escape, skipped\r\n");
if(!(*s)) return;
}
}
}
}
int getnum(char **stringp, int base)
{
char *s = *stringp;
int n = 0;
for(++s; isnumber(*s); s++)
{
n = n * base + (*s - '0');
}
*stringp = --s;
return (n < 0)? 0 : n;
}
jmp_buf alrm_buf;
void alrm(void)
{
Psigreturn();
longjmp(alrm_buf, -1);
}
int await_char(int ch)
{
int c;
void (*save)(void) = signal(SIGALRM, alrm);
if(setjmp(alrm_buf))
{
(void)signal(SIGALRM, save);
return 1;
}
alarm(timeout);
while((c = Bconin(rsdev) & 0x7f) != ch)
Bconout(2, c);
alarm(0);
Bconout(2, c);
(void)signal(SIGALRM, save);
return 0;
}