📄 xcmain.c
字号:
/* xcmain.c -- main module for XC This file uses 4-character tabstops*/#include <stdio.h>#include <stdlib.h>#include <string.h>#include <sys/types.h>#include <unistd.h>#include <signal.h>#include <ctype.h>#include <setjmp.h>#include <sys/wait.h>#include <getopt.h>#include "xc.h"#define Resume_Not_Allowed 1static pid_t honeychile; /* for fork pid */#if XC_PLUS#if HAVE_RS232FLOWshort rtscts = TRUE; /* RTS/CTS flow control */#endifstatic int sentkill = FALSE; short dosmode = TRUE; /* Translate DOS chars to latin1/vt102 */short delmode = TRUE; /* Map DEL to BS */short auto_zm = TRUE; /* Allow Automagic ZModem downloads */short nowait = FALSE; /* When TRUE this will disable call waiting */short tone = TRUE; /* Flag for pulse or touch tone dialing */char rzcmd[SM_BUFF]; /* Buffer for auto_zmodem command */#endif short autoflag = FALSE, /* Automatic capturing */ cismode = FALSE, /* Automatic response to CIS "ENQ" */ cr_add = TRUE, /* Add cr to nl in B+ uploads */#if HALF_DUPLEX hdplxflag = FALSE, /* Half-duplex mode */#endif nl2cr = TRUE, /* Map nl to cr when transmitting ASCII */ reterm = FALSE, /* Jumping into terminal mode */ eofflag = FALSE; /* Flag to quit a script */static short statflag = FALSE; /* Flag for status display */FILE *tfp;struct termios newmode, oldmode, sigmode; char Msg[SM_BUFF], BS ;static char LK, directory[SM_BUFF], oldshell[SM_BUFF];static const char * const statfmt = "\r\t\t%-8s %25s %s\r\n",#if XC_PLUS version[]="@(#)XC 4.3 JPRadley | xcplus p2 Nov 24, 1996 |",#else version[]="@(#)XC 4.3 JPRadley 11 Sep 1993",#endif * const babble[] = { "\r\nUsage: xc [-l device] [-s file | -t | -p | -w ]", "\t-l device\tUse 'device' as the modem port", "\t-s script\tExecute 'script' immediately", "\t-t\t\tEnter terminal mode immediately",#if XC_PLUS "\t-p\t\tUse pulse dialing instead of tone dialing", "\t-w\t\tDisable call waiting",#endif NULL };jmp_buf erret; /* non-local error return */struct kw { /* Used by command parsing routines */ char *keyword; void (*rtn)();};/* Catch a signal and jump to main. Reset signal and do a longjmp */static RETSIGTYPEcatch(junk)int junk;{ if (! isatty(2)) hangup(), s_exit(junk); S2("XC: Interrupt"); signal(SIGINT,catch); signal(SIGQUIT,catch); longjmp(erret,1);}static voidusage(){ const char * const *ptr; for (ptr = babble; *ptr; ptr++) fprintf(tfp, "%s\r\n", *ptr);}static voids_script(){ getword(); if (word[0] == '\0'){ S1("Script file not specified"); return; } sprintf(ddsname,"%s",word); do_script(ddsname); reterm = TRUE;}static voids_xmodem(){ char d = word[0]; char c = word[1]; char e = word[2]; char oldproto[4]; strcpy(oldproto, protocol); xc_setflow(FALSE); xc_setproto("8N1"); if ( c == 'b' || c == 'y' ) /* ymodem */ { y_flag = TRUE ; if (d == 's') ysend(); else yreceive(e); } else { /* xmodem */ y_flag = FALSE ; getword(); if (word[0] == '\0') S1("Transfer file not specified"); else if (d == 's') /* xmodem */ xsend(c); else xreceive(c); } reterm = TRUE; xc_setflow(flowflag); xc_setproto(oldproto);}voids_cis(){ char oldproto[4]; strcpy(oldproto, protocol); xc_setflow(FALSE); xc_setproto("8N1"); mode(SIGMODE); B_Transfer(); reterm = TRUE; xc_setflow(flowflag); xc_setproto(oldproto);}static voids_term(){ terminal(FALSE); if (cismode != 2) return; cismode = 1; s_cis();}static voids_dial(){ terminal(TRUE); if (cismode != 2) return; cismode = 1; s_cis();}#if XC_PLUS && _POSIX_SOURCE/* send SIGTERM to shell child process */static voidsig_int(int junk){ signal( SIGINT, SIG_IGN ); if( honeychile > 0 ){ kill( -(honeychile), SIGINT); sleep(2); if(kill(honeychile,0) == 0 ){ kill( -(honeychile), SIGTERM); sleep(2); kill( -(honeychile), SIGKILL); } sentkill = TRUE ; }}#endifints_shell(){#if NOSHELL return(0);#else int stat_loc = 0; char c = word[0]; static char *shell = NULL ; RETSIGTYPE (*oldvec)();#if XC_PLUS struct termios savedterm ; tcgetattr(STDIN_FILENO, &savedterm ); sentkill = FALSE ;#endif honeychile = 0 ; if (word[0] == word[1]) strcpy(wptr = word, oldshell); else { getword(); if (*wptr) strcpy(oldshell, wptr); } if (!shell){ shell = getenv("SHELL"); if (!shell) shell = "/bin/sh"; } fputc('\r',tfp), fputc('\n',tfp); mode(OLDMODE); if ( (honeychile = forkem()) == 0 ) { if (c == '$'){ /* Attach modem to stdin, stdout */ setpgid( 0, 0 ); mattach(); } signal(SIGCHLD,SIG_DFL); signal(SIGINT, SIG_DFL ); signal(SIGQUIT,SIG_DFL); if (word[0] == '\0') execl(shell, shell, "-i", NULL ); else execl(shell, shell, "-c", wptr, NULL ); S1("Exec failed!"); exit(2); }#if !XC_PLUS || !_POSIX_SOURCE oldvec = signal(SIGINT,SIG_IGN); wait(&stat_loc); signal(SIGINT,oldvec); strcpy(oldshell, wptr); return(!!stat_loc); #else /*XC_PLUS and _POSIX_SOURCE*/ if( honeychile > 0 ){ if( c == '$' ){#if _POSIX_SOURCE setpgid(honeychile, honeychile);#endif oldvec = signal(SIGINT, sig_int); } else { oldvec = signal(SIGINT, SIG_IGN); } waitpid(honeychile, &stat_loc, 0) ; } else { printf("shell fork() error\n"); exit(1); } signal(SIGINT,oldvec); strcpy(oldshell, wptr); tcsetattr(0, TCSANOW, &savedterm ) ; if( WIFEXITED( stat_loc ) && !WEXITSTATUS( stat_loc ) && !sentkill ) return( 0 ) ; if( sentkill ) { int watch_dog = XC_WATCH_DOG ; fprintf(stderr, "\n\rCaught SIGINT\n\r"); fprintf(stderr, "Purging input buffer . . .\n\r"); /* We use a watch dog so that we don't hang forever if the other end refuses to shut up. This will return control to the user who can take manual action such as sending a string of ^X . */ do{#if _POSIX_SOURCE purge(); sleep(1); #endif watch_dog-- ; } while(watch_dog && readbyte(1) != -1 ) ; if(! watch_dog ) { canit(); fprintf(stderr, BAD_PROGRAM_MSG ); sleep(2); } sendbyte(13); } else { fprintf(stderr, "\n\r\nstatus = %#x return code = %#x\n\r", stat_loc, WEXITSTATUS(stat_loc) ); } sleep(1); return( 1 ) ;#endif /*XC_PLUS*/#endif /*not NOSHELL*/}static const char * const cmdlist[] = { "\tXC Command Summary", "", "\tc|cis\t\tInitiate CIS B+ File Transfer (Upload and Download)", "", "\td|dial\t\tDialing directory", "", "\tx|q|exit|quit\tExit XC", "", "\th|hangup\tHang up the modem", "",#if XC_PLUS "\trx file\t\tXmodem receive file 'file' (binary mode)", "\try \t\tYmodem receive file (binary, file name passed by sender)", "\tryg\t\tYmodem receive file 'G' mode (binary, streaming ymodem)", "\tsx file\t\tXmodem send file 'file' (binary mode 128 byte packets)", "\tso file\t\tXmodem send file 'file' (binary mode 1K byte packets)", "\tsy file\t\tYmodem send file 'file' (binary mode)", "\trt file\t\tXmodem receive file 'file' (obsolete ascii mode)", "\tst file\t\tXmodem send file 'file' (obsolete ascii mode)",#else "\trb file\t\tXMODEM receive file 'file' (binary mode)", "\trt file\t\tXMODEM receive file 'file' (Ascii mode)", "", "\tsb file...\tXMODEM send file 'file' (binary mode)", "\tst file...\tXMODEM send file 'file' (Ascii mode)",#endif "", "\tset\t\tDisplay XC parameters", "\tset kw\t\tDisplay XC parameter for 'kw'", "\tset kw val\tSet XC keyword 'kw' to 'val'", "", "\ts file", "\tscript file\tExecute XC script 'file'", "", "\tt", "\tterm\t\tEnter terminal mode", "",#if !NOSHELL "\t!\t\tExecute a local interactive shell", "\t! cmd\t\tExecute shell command string on the local system", "\t!!\t\tRe-execute the last shell command string", "", "\t$ cmd\t\tShell command with stdin and stdout redirected to modem", "",#endif "\t%p loc [rem]\tPut local file to a UNIX system", "", "\t%t rem [loc]\tTake remote file from a UNIX system", "", "\t?", "\thelp\t\tPrint (this) help text", "\014", /* FORM FEED */ "\tSET Keywords:", "", "\tset\t\t\tDisplay current XC status", "", "\tset auto on|off\t\tSet|Unset automatic capturing", "", "\tset bps value", "\tset baud value\t\tSet Bits/Second to 'value'", "", "\tset cfile name\t\tChange name of capture file", "", "\tset cis on\t\tSet CIS <ENQ> mode (Auto up/download)", "\tset cis off\t\tDo not respond to <ENQ>", "", "\tset cr on|off\t\tSet|Unset Carriage Return Injection mode", "", "\tset xcape char", "\tset escape char\t\tSet the Terminal mode escape character", "",#if HALF_DUPLEX "\tset hdplx on\t\tSet half-duplex mode", "\tset hdplx off\t\tUnset half-duplex mode (use full-duplex)", "",#endif "\tset dir name\tChange current directory", "",#if !XC_PLUS "\tset menu on|off\t\tDo|Don't show mini-menu before XC prompt", "",#endif "\tset nl on|off\t\tSet|Unset newline translation", "", "\tset pfile name\t\tChange name of phonelist file", "", "\tset proto 7E2\t\tSet 7-bit character size, even parity", "\tset proto 7O2\t\tSet 7-bit character size, odd parity", "\tset proto 8N1\t\tSet 8-bit character size, no parity", "", "\tset xon on|off", "\tset xoff on|off\t\tSet|Unset XON/XOFF flow control", "",#if XC_PLUS #if HAVE_RS232FLOW "\tset rtscts on|off\t\tSet/Reset RTS/CTS flow control\n",#endif "\tset del2bs on|off\tmap|unmap Delete character to Backspace", "\tset msdos on|off\ttranslate DOS characters to Linux chars.", "\tset autozm on|off\t\tSet/Reset Automatic ZModem download\n", "\tset zmcmd command\t\tSet command used to invoke ZModem Receive\n", "",#endif "\014", /* FORM FEED */ NULL };voidset_onoff(flag)short *flag;{ char *ptr = xc_strdup(word); uc_word(ptr); getword(); lc_word(word); if (!strcmp(word, "on")) *flag = TRUE; else if (!strcmp(word, "off")) *flag = FALSE; else sprintf(Msg,"Set '%s' value must be 'on' or 'off'",ptr), S, eofflag++; free(ptr);}static voidSET_proto(){ if (statflag){ fprintf(tfp, statfmt, "proto", "Port set to", protocol); return; } getword(); uc_word(word); if (word[0] == '\0') S1("Set proto must be 7E2, 7O2, or 8N1"); else if (!xc_setproto(word)) sprintf(Msg,"Unsupported protocol %s",word), S; eofflag++; if (!scriptflag) sprintf(Msg,"Port set to %s", protocol), S;}static voidSET_dir(){ if (statflag){ fprintf(tfp, statfmt, "dir", "We are in", directory); return; } getword(); strcpy(directory, word); if (chdir(directory)) sprintf(Msg,"Can't move to %s", directory); if (!scriptflag) sprintf(Msg, "%sWe are in %s", CE, directory); S;}static voidSET_cr(){ if (statflag){ fprintf(tfp, statfmt, "cr", "Carriage Return Injection", cr_add ? "ON" : "OFF"); return; } set_onoff(&cr_add); if (!scriptflag) sprintf(Msg,"Carriage Returns %s injected in B+ ASCII uploads", cr_add ? "ARE" : "are NOT"), S;}static voidSET_xcape(){ if (statflag) { fprintf(tfp, statfmt, "xcape", "Terminal Escape Character", unctrl(my_escape)); return; } getword(); if (word[0] == '\0') { show(1,"Set ESCAPE must specify escape character"); eofflag++; return; } my_escape = word[0]; if (!scriptflag) sprintf(Msg,"Terminal mode escape character set to '%s'", unctrl(my_escape)), S;}static voidSET_nl(){ if (statflag){ fprintf(tfp, statfmt, "nl", "Newline Translation", nl2cr ? "ON" : "OFF"); return; } set_onoff(&nl2cr); if (!scriptflag) sprintf(Msg,"Newlines %s changed to Carriage Returns", nl2cr ? "ARE" : "are NOT"), S;}static voidSET_cis(){ if (statflag){ fprintf(tfp, statfmt, "cis", "CIS <ENQ> Auto Download", cismode ? "ON" : "OFF"); return; } set_onoff(&cismode); if (!scriptflag) sprintf(Msg,"CIS <ENQ> Auto Download is %s", cismode ? "ON" : "OFF"), S;}#if XC_PLUSstatic voidSET_del(){ if (statflag) { fprintf(tfp, statfmt, "del2bs", "DEL to BS Translation", delmode ? "ON" : "OFF"); return; } set_onoff(&delmode); if (!scriptflag){ sprintf(Msg,"DEL to Backspace Translation is %s", delmode ? "ON" : "OFF"), S; }}static voidSET_dos(){ if (statflag) { fprintf(tfp, statfmt, "msdos", "Character Translation", dosmode ? "ON" : "OFF" ); return ; } set_onoff(&dosmode); if (!scriptflag) { sprintf(Msg,"DOS Translation is %s", dosmode ? "ON" : "OFF" ), S; }} static voidSET_azm(){ if (statflag) { fprintf(tfp, statfmt, "autozm", "Automatic ZModem Download", auto_zm ? "ON" : "OFF" ); return ; } set_onoff(&auto_zm); if (!scriptflag) { sprintf(Msg,"Automatic ZModem Downloads are %s", auto_zm ? "ON" : "OFF" ), S; } } static void SET_zmcmd()
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -