📄 vmcp.c
字号:
/*----------------------------------------------------------------------*//* vmcp Voice Modem Control Program. *//* A little program to send commands to the modem *//* with special features for voice modems. *//* *//* Version 0.6.1 Jul 14 1999 *//* *//* Author: Niccolo Rigacci <fd131@cleveland.freenet.edu> *//* *//* Copyright (C) 1996-1999 Niccolo Rigacci *//* *//* This program 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 of the License, or *//* (at your option) any later version. *//* *//* This program 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 this program; if not, write to the Free Software *//* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. *//*----------------------------------------------------------------------*/#include <stdio.h>#include <stdlib.h>#include <errno.h>#include <fcntl.h>#include <getopt.h>#include <signal.h>#include <string.h>#include <linux/termios.h>#include <unistd.h>#include <sys/file.h>#include <sys/stat.h>#include <sys/types.h>#include <sys/time.h> /*----------------------------------------------------------------------*//* Macro definitions/*----------------------------------------------------------------------*//* DLE Escape char for voice mode. *//* BREAK_KEY Break key for -k switch. *//* MAX_LEN_FNAME Max len for filename strings. *//* TEMP_DIR Where to put the lock file. *//* DEVS_DIR Where modem devices are. *//* DFLT_DEV Default modem device. *//* DEV_NULL Black-hole file. *//* HDB_LCK_FORMAT Format string for printing PID in HDB lockfile. *//* HDB_LCK_LEN Len of HDB lockfile. */#define TRUE 1#define FALSE 0#define DLE 16#define BREAK_KEY 27#define MAX_LEN_FNAME 255#define TEMP_DIR "/tmp/"#define DEVS_DIR "/dev/"#define DFLT_DEV "ttyS0"#define DEV_NULL "/dev/null"#define HDB_LCK_FORMAT "%10d\n"#define HDB_LCK_LEN 11#define EXIT_OK 0#define EXIT_TIMEOUT 100#define EXIT_KEYPRESS 101#define ERR_MEMORY 150#define ERR_SYNTAX 151#define ERR_DEVICE 152#define ERR_OPEN 153#define ERR_WRITE 154#define ERR_CLOSE 155#define ERR_LOCK 156#define ERR_IOCTL 157#define ERR_LCKFILE 158#define ERR_BAUDRATE 159#define ERR_SIGNAL 200/*----------------------------------------------------------------------*//* Function prototypes/*----------------------------------------------------------------------*/int out_chr(int c);int out_esc(int c);void no_response(int i);void end_on_signal(int i);void fatal(int exit_code);char *strdupcvt(char *str);void safeprint(char *msg, char *str);void port_reset(int fd);/*----------------------------------------------------------------------*//* Global variables/*----------------------------------------------------------------------*/struct termios ts; /* Saved stdin line settings */int debug = FALSE; /* Be verbose */int timeout = 5; /* Seconds to wait */int break_on_key = FALSE; /* Return on keypress */int escaping_dle = FALSE; /* Handle escaping of DLE */int make_lock_file = FALSE; /* Must create lock file */int made_lock_file = FALSE; /* Lock file created */int changed_std_input = FALSE; /* Std input settings changed */int quit_on_eof = FALSE; /* Return on end of input file */int skip_out_string = FALSE; /* Do not output the -W string */FILE *inp_fp; /* Input file pointer */FILE *out_fp; /* Output file pointer */FILE *esc_fp; /* Escape file pointer */unsigned char *lckfname = NULL; /* Name of the lock file */unsigned char *command = NULL; /* Command to send */unsigned char *out_string = NULL; /* String to wait */unsigned char *esc_string = NULL; /* Escape chars to wait */int out_len; /* Len of out_string */int out_pos = 0; /* Index to scan out_string */int ok_exit_code; /* Exit code if OK (0 - 99) */long baud_rate; /* Baud rate of serial line *//*----------------------------------------------------------------------*//* Main program/*----------------------------------------------------------------------*/int main(int argc, char **argv) { int i, c, fd, opt; int eof_inp = TRUE; int finito = FALSE; int reset_port = FALSE; int previous_dle = FALSE; int sent_one_dle = FALSE; unsigned char pid_buf[HDB_LCK_LEN + 1]; unsigned char filename[MAX_LEN_FNAME + 1]; unsigned char *inp_file, *out_file, *esc_file; unsigned char *device; unsigned char buf; struct termios new_ts; fd_set rfds; pid_t pid; /* Set default values for some strings. */ inp_file = out_file = esc_file = DEV_NULL; device = DFLT_DEV; /* Process command line arguments */ while ((opt = getopt(argc, argv, "c:d:eghi:kl:o:qs:t:w:W:x:z:")) != -1) { switch (opt) { case 'e': escaping_dle = TRUE; break; case 'g': debug = TRUE; break; case 'k': break_on_key = TRUE; break; case 'q': quit_on_eof = TRUE; break; case 'c': if ((command = strdupcvt(optarg)) == NULL) fatal(ERR_MEMORY); break; case 'd': if ((device = strdup(optarg)) == NULL) fatal(ERR_MEMORY); break; case 'h': fprintf(stderr, "Voice Modem Control Program\n"); fprintf(stderr, "Usage: %s [OPTION]...\n", argv[0]); fprintf(stderr, "\t-c command\n\t-d device\n\t-e\n\t-g\n\t-h\n"); fprintf(stderr, "\t-i in_file\n\t-k\n\t-l lockfile\n"); fprintf(stderr, "\t-o out_file\n\t-q\n\t-s esc_file\n"); fprintf(stderr, "\t-t sec\n\t-w waitstring\n\t-W skipstring\n"); fprintf(stderr, "\t-x esc_string\n\t-z baudrate\n"); exit(0); break; case 'i': if ((inp_file = strdup(optarg)) == NULL) fatal(ERR_MEMORY); eof_inp = FALSE; break; case 'l': if ((lckfname = strdup(optarg)) == NULL) fatal(ERR_MEMORY); make_lock_file = TRUE; break; case 'o': if ((out_file = strdup(optarg)) == NULL) fatal(ERR_MEMORY); break; case 's': if ((esc_file = strdup(optarg)) == NULL) fatal(ERR_MEMORY); break; case 't': timeout = atoi(optarg); break; case 'W': skip_out_string = TRUE; case 'w': if ((out_string = strdupcvt(optarg)) == NULL) fatal(ERR_MEMORY); out_len = strlen(out_string); break; case 'x': if ((esc_string = strdup(optarg)) == NULL) fatal(ERR_MEMORY); break; case 'z': baud_rate = atol(optarg); reset_port = TRUE; break; default: fprintf(stderr, "Try `vmcp -h' for help.\n"); fatal(ERR_SYNTAX); break; } } /* Set standard input line settings in non-canonical mode: */ /* no line buffering, no echo, no wait. */ if (break_on_key) { /* Get standard input (file descriptor 0) line settings. */ if (ioctl(0, TCGETS, &ts) != 0) fatal(ERR_IOCTL); new_ts = ts; new_ts.c_lflag &= ~ICANON; new_ts.c_lflag &= ~ECHO; new_ts.c_cc[VTIME] = 0; new_ts.c_cc[VMIN] = 0; if (ioctl(0, TCSETS, &new_ts) != 0) fatal(ERR_IOCTL); changed_std_input = TRUE; } /* Set the timeout alarm. */ if (timeout != 0) { signal(SIGALRM, no_response); alarm(timeout); } /* Set some signal handling functions. */ signal(SIGHUP, end_on_signal); signal(SIGINT, end_on_signal); signal(SIGQUIT, end_on_signal); signal(SIGTERM, end_on_signal); /* Open communication file device. */ sprintf(filename, "%s%s", DEVS_DIR, device); if ((fd = open(filename, O_RDWR | O_NONBLOCK)) == -1) fatal(ERR_DEVICE); if (flock(fd, LOCK_EX | LOCK_NB) != 0) fatal(ERR_LOCK); if (reset_port) { if (debug) fprintf(stderr, "Resetting the serial line\n"); port_reset(fd); } /* Create lock file if required. Use HDB lockfile format: */ /* ten byte ASCII decimal number, with a trailing newline. */ if (make_lock_file) { pid = getpid(); sprintf(pid_buf, HDB_LCK_FORMAT, pid); sprintf(filename, "%sTMP..%d", TEMP_DIR, pid); /* Create a temp lock file and write PID to it. */ if ((i = creat(filename, 0644)) == -1) fatal(ERR_LCKFILE); if (write(i, pid_buf, HDB_LCK_LEN) != HDB_LCK_LEN) fatal(ERR_LCKFILE); if (close(i) != 0) fatal(ERR_LCKFILE); /* Change name to the lock file. */ if (link(filename, lckfname) == 0) made_lock_file = TRUE; unlink (filename); if (!made_lock_file) fatal(ERR_LCKFILE); } /* Write command to communication file device. */ /* NOTE: no check is made for EAGAIN error, we */ /* suppose command string to be small enough */ /* to fit entirely in the output buffer. */ if (command != NULL) { /* Just paranoia: US-Robotic requires a pause */ /* of 1 ms before "AT" commands, we do 2 ms. */ if (strncmp(command, "AT", 2) == 0 || strncmp(command, "at", 2) == 0) { struct timeval tv; tv.tv_sec = 0; tv.tv_usec = 2000; select(0, NULL, NULL, NULL, &tv); } if (debug) safeprint("Sending", command); i = strlen(command); if (write(fd, command, i) != i) fatal(ERR_WRITE); } else if (debug && (out_string != NULL)) if (skip_out_string) safeprint("Skipping", out_string); else safeprint("Waiting for", out_string); /* Open input, output and escape files. */ if ((inp_fp = fopen(inp_file, "rb")) == NULL) fatal(ERR_OPEN); if ((out_fp = fopen(out_file, "wb")) == NULL) fatal(ERR_OPEN); if ((esc_fp = fopen(esc_file, "wb")) == NULL) fatal(ERR_OPEN); /* Main loop to send input file to communication device's input */ /* and to capture output to output file. If escaping of DLE */ /* char is enabled, escaped chars are sent to escape file. */ while (!finito) { /* If "-i file" has more characters to send, do one. */ if (!eof_inp) { /* Write a char from "-i file" to device, escape DLE if required. */ if ((c = fgetc(inp_fp)) == EOF) { eof_inp = TRUE; finito = quit_on_eof; } else { buf = (unsigned char)c; if (write(fd, &buf, 1) == 1) { /* No error, check for DLE escaping. */ if (buf == DLE && escaping_dle && !sent_one_dle)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -