📄 console.c
字号:
/* console.c -- Console interface for Intercom Copyright (C) 2001-2003 Shane Wegner This file is part of Intercom. Intercom is free software; you can redistribute it and/or modify it under the terms of version 2 of the GNU General Public License as published by the Free Software Foundation. Intercom 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 version 2 of the GNU General Public License along with Intercom; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA To contact the author, please send email to shane@cm.nu. *//* $Id: console.c,v 1.65 2003/02/13 20:22:49 shane Exp $ */ /* AIX requires this to be the first thing in the file. */#ifdef _AIX #pragma alloca#endif#ifdef HAVE_CONFIG_H#include "config.h"#endif#include <stdio.h>#include <stdlib.h>#include <unistd.h>#include <string.h>#include <assert.h>#include <errno.h>#include <time.h>#ifdef HAVE_GETOPT_H#include <getopt.h>#else#include "subst/getopt.h"#endif#include <fcntl.h>#include <sys/types.h>#include <sys/wait.h>#if defined(HAVE_SYS_SOUNDCARD_H)#include <sys/soundcard.h>#elif defined(HAVE_MACHINE_SOUNDCARD_H)#include <machine/soundcard.h>#else#include <soundcard.h>#endif#include <sys/ioctl.h>#include <sys/socket.h>#include <netinet/in.h>#include <arpa/inet.h>#ifdef HAVE_LIBREADLINE#ifdef HAVE_READLINE_READLINE_H#include <readline/readline.h>#else#include <readline.h>#endif#endif#ifdef HAVE_LIBHISTORY#ifdef HAVE_READLINE_HISTORY_H#include <readline/history.h>#else#include <history.h>#endif#endif#ifdef USE_CRYPTO#include <openssl/sha.h>#endif#include "intercom.h"#include "protocol.h"#include "console.h"#include "userdefs.h"#include "hooks.h"#include "iwordexp.h"#ifdef USE_CRYPTO#include "crypto.h"#endif#ifdef USE_GETTEXT#include <libintl.h>#define _(String) gettext(String)#define gettext_noop(String) (String)#define N_(String) gettext_noop(String)#else#define _(String) (String)#define N_(String) (String)#endifstruct console_cmd {const char *cmd;char *desc;void (*func)(int, char **);};struct alias {char *cmd;char *newcmd;struct alias *next;};static struct alias *alias_list = NULL;#ifndef HAVE_LIBREADLINEstatic int console_active = 0;#endif#ifdef HAVE_LIBHISTORYchar *historyfile = NULL;#endifstatic void cmd_alias(int ARGC, char **ARGV){static const struct option long_options[]={{"help", no_argument, NULL, 'h'},{"unalias", no_argument, NULL, 'u'},{"verbose", no_argument, NULL, 'v'},{NULL, 0, NULL, 0}};int o, verbose = 0, unalias = 0, all = 0;struct alias *ap, *next, *prev = NULL;optind = 0;while ((o = getopt_long(ARGC, ARGV, "ahuv", long_options, (int *)0)) != EOF) {switch(o) {case 'a':all = 1;break;case 'h':printf(_("Usage: %s [options] [<alias>] {<command>]\n\n""Valid options:\n""-a, --all\tWhen used with -u, removes all aliases""-h, --help\tDisplay this help information\n""-u, --unalias\tRemove an alias\n""-v, --verbose\tPrint alias with value when creating an alias\n\n""If <command> is omited, the alias is printed with it\'s command.\n""If <alias> is omited, all aliases and their values will be printed.\n\n"),ARGV[0]);return;case 'u':unalias = 1;break;case 'v':verbose = 1;break;default:fprintf(stderr, _("Try '%s --help' for a usage summary.\n"), ARGV[0]);return;}}if (unalias) {if (!all && (ARGC - optind) == 0) {fprintf(stderr, _("%s: Nothing to unalias.\n"), ARGV[0]);return;} else if ((ARGC - optind) > 1) {fprintf(stderr, _("%s: Too many command-line options specified.\n"), ARGV[0]);return;}for (ap = alias_list; ap != NULL; ap = next) {next = ap->next;if (all || !strcmp(ap->cmd, ARGV[optind])) {if (prev == NULL)alias_list = ap->next;elseprev->next = ap->next;if (verbose)printf(_("Alias '%s' removed.\n"), ap->cmd);free(ap->cmd);free(ap->newcmd);free(ap);if (!all)break;} elseprev = ap;}return;} /* endif unalias */if (!(ARGC - optind)) {fputs(_("Currently defined aliases:\n"), stdout);for (ap = alias_list; ap != NULL; ap = ap->next)printf("'%s' = '%s'\n", ap->cmd, ap->newcmd);putchar('\n');} else if ((ARGC - optind) == 1) {for (ap = alias_list; ap != NULL; ap = ap->next)if (!strcmp(ap->cmd, ARGV[optind])) {printf(_("'%s' aliases '%s'\n"), ap->cmd, ap->newcmd);break;}} else {for (ap = alias_list; ap != NULL; ap = ap->next) {if (!strcmp(ap->cmd, ARGV[optind])) {if (verbose)fprintf(stderr, _("Alias '%s' already defined.\n"), ap->cmd);return;}}if (alias_list != NULL) {for (ap = alias_list; ap->next != NULL; ap = ap->next);ap->next = malloc(sizeof(struct alias));ap = ap->next;} else {ap = malloc(sizeof(struct alias));alias_list = ap;}ap->cmd = strdup(ARGV[optind]);ap->newcmd = strdup(ARGV[optind+1]);ap->next = NULL;if (verbose)printf(_("'%s' aliases '%s'\n"), ap->cmd, ap->newcmd);}}void cmd_answer(int ARGC, char **ARGV){const struct option long_options[] = {{"compression", required_argument, NULL, 'c'},{"rate", required_argument, NULL, 'r'},{"help", no_argument, NULL, 'h'},{NULL, 0, NULL, 0}};int o, i;struct pkt_callresponse callpkt;struct pkt_audiostart audiopkt;struct sockaddr_in r_address;callpkt.aparams.compression = call.rcv_aparams.compression;callpkt.aparams.rate = call.rcv_aparams.rate;callpkt.aparams.bitwidth = call.rcv_aparams.bitwidth;callpkt.responsecode = CALLRESPONSE_ACCEPT;optind = 0;while ((o = getopt_long(ARGC, ARGV, "c:hr:", long_options, (int *)0)) != EOF) {switch(o) {case 'c':if ((i = int_compression(optarg)) == -1) {fprintf(stderr, _("%s: Compression format %s is invalid or unsupported.\n"),ARGV[0], optarg);return;} elsecallpkt.aparams.compression = i;break;case 'h':printf(_("Usage: %s [options]\n\n""Valid options:\n""-c, --compression\tSet audio compression format\n""-r, --rate\t\tSet audio sample rate\n""-h, --help\t\tDisplay this help information\n""\n"), ARGV[0]);return;case 'r':callpkt.aparams.rate = atoi(optarg);break;default:fprintf(stderr, _("Try '%s --help' for a usage summary.\n"), ARGV[0]);return;}}if ((ARGC - optind)) {fprintf(stderr, _("%s: Too many arguments on command-line.\n"), ARGV[0]);return;} else if (!TEST_BIT(call.state, CALL_STATE_WFRANSWER)) {fprintf(stderr, _("%s: No incoming call is pending at this time.\n"), ARGV[0]);return;}memcpy(&call.snd_aparams, &callpkt.aparams, sizeof(callpkt.aparams));#ifdef USE_CRYPTOif (call.cryptinfo.type != CALL_CRYPT_NONE) {char *pass;char clr_challenge[128];char challenge_sha1[20];size_t try_nr, l;pass = opt_get_str("crypt_passphrase");if (*pass) {cr_set_key(pass);cr_decrypt(call.cryptinfo.challenge, 128, clr_challenge, &l);SHA1(clr_challenge, 128, challenge_sha1);if (!memcmp(challenge_sha1, call.cryptinfo.challenge_sha1, 20)) {puts(_("Default passphrase is good."));goto goodpass;}}for (try_nr = 1; try_nr <= 3; try_nr++) {pass = getpass(_("Enter passphrase for encrypted call: "));cr_set_key(pass);cr_decrypt(call.cryptinfo.challenge, 128, clr_challenge, &l);SHA1(clr_challenge, 128, challenge_sha1);if (!memcmp(challenge_sha1, call.cryptinfo.challenge_sha1, 20))goto goodpass;printf(_("%s: Incorrect passphrase (try %d)\n"),ARGV[0], try_nr);}fprintf(stderr, _("%s: Closing connection.\n"), ARGV[0]);closecall();}goodpass:#endiffputs(_("Answering call.\n"), stdout);queuepacket(&call.cssq, PKT_TYPE_CALLRESPONSE, (char *)&callpkt, sizeof(callpkt));hk_trigger(hk_call_connect);CLEAR_BIT(call.state, CALL_STATE_WFRANSWER);SET_BIT(call.state, CALL_STATE_INCALL);call.connstats.start_time = time(NULL);if ((call.dsock = setup_udpsock(&r_address)) == -1) {closecall();return;}if (*opt_get_str("snd_play_device")) {if ((call.pdsp = dsp_setup(opt_get_str("snd_play_device"),(opt_get_int("snd_singleopen")) ? O_RDWR : O_WRONLY, &call.rcv_aparams)) == -1)return;if (ioctl(call.pdsp, SNDCTL_DSP_GETBLKSIZE, &call.pdsp_blksize) == -1) {perror("ioctl(SND_DSP_GETBLKSIZE)");return;}call.pdsp_buff = malloc(call.pdsp_blksize);iob_setminbytes(&call.pdspq, call.pdsp_blksize * 4);}audiopkt.dport = r_address.sin_port;queuepacket(&call.cssq, PKT_TYPE_AUDIOSTART, (char *)&audiopkt, sizeof(audiopkt));SET_BIT(call.state, CALL_STATE_AUDIORCV);}void cmd_call(int ARGC, char **ARGV){const struct option long_options[] = {{"compression", required_argument, NULL, 'c'},#ifdef USE_CRYPTO{"encrypt", optional_argument, NULL, 'e'},#endif{"port", required_argument, NULL, 'p'},{"rate", required_argument, NULL, 'r'},{"user", required_argument, NULL, 'u'},{"help", no_argument, NULL, 'h'},{NULL, 0, NULL, 0}};int o, i;struct pkt_call callpkt;struct pkt_hello hellopkt;struct sockaddr_in r_address;int port = opt_get_int("port");callpkt.cryptinfo.type = CALL_CRYPT_NONE;callpkt.aparams.compression = int_compression(opt_get_str("snd_compression"));callpkt.aparams.rate = opt_get_int("snd_rate");callpkt.aparams.bitwidth = opt_get_int("snd_bitwidth");hellopkt.proto_version = INTERCOM_PROTOCOL_VERSION;strcpy(hellopkt.username, opt_get_str("username"));strcpy(hellopkt.clientname, "Intercom " VERSION);optind = 0;while ((o = getopt_long(ARGC, ARGV, "c:e::hp:r:u:", long_options, (int *)0)) != EOF) {switch(o) {case 'c':if ((i = int_compression(optarg)) == -1) {fprintf(stderr, _("%s: Compression format %s is invalid or unsupported.\n"),ARGV[0], optarg);return;} elsecallpkt.aparams.compression = i;break;case 'e': {#ifndef USE_CRYPTOfprintf(stderr,_("%s: error: -e switch used but crypto has been disabled in this build\n"), ARGV[0]);return;#elseint t;if (optarg == NULL)t = cr_type_fromstr(opt_get_str("crypt_method"));elset = cr_type_fromstr(optarg);if (t == -1) {fprintf(stderr, _("%s: Invalid or unsupported encryption method.\n"),ARGV[0]);return;} elsecallpkt.cryptinfo.type = t;#endif}break;case 'h':printf(_("Usage: %s [options] host\n\n""Valid options:\n""-c, --compression\tSet audio compression format\n""-e, --encrypt\tEncrypt audio data optionally a crypt method can be specified\n""-p, --port\t\tConnect on specified port\n""-r, --rate\t\tSet audio sample rate\n""-u, --user\t\tSpecifies the username to send\n""-h, --help\t\tDisplay this help information\n""\n"), ARGV[0]);return;case 'p':port = atoi(optarg);break;case 'r':callpkt.aparams.rate = atoi(optarg);break;case 'u':strncpy(hellopkt.username, optarg, 128);break;default:fprintf(stderr, _("Try '%s --help' for a usage summary.\n"), ARGV[0]);return;}}if ((ARGC - optind) != 1) {fprintf(stderr, _("%s: No hostname specified.\n"), ARGV[0]);return;} else if ((ARGC - optind) > 1) {fprintf(stderr, _("%s: Too many options on command-line.\n"), ARGV[0]);return;} else if (TEST_BIT(call.state, CALL_STATE_CONNECTED)) {fprintf(stderr, _("%s: Another call is already active.\n"), ARGV[0]);return;}printf(_("%s: Placing call to '%s'.\n"), ARGV[0], ARGV[optind]);if ((call.csock = do_connect(ARGV[optind], port, &r_address)) == -1)return;memcpy(&call.r_address, &r_address, sizeof(r_address));icsetenv("remote_hostip", inet_ntoa(r_address.sin_addr));if (opt_get_int("reverse_lookup")) {if ((call.r_hostent = gethostbyaddr((char *)&r_address.sin_addr, sizeof(r_address.sin_addr), AF_INET)) == NULL)call.r_hostent = gethostbyname(inet_ntoa(r_address.sin_addr));icsetenv("remote_hostname", call.r_hostent->h_name);} elsecall.r_hostent = gethostbyname(inet_ntoa(r_address.sin_addr));memcpy(&call.snd_aparams, &callpkt.aparams, sizeof(callpkt.aparams));queuepacket(&call.cssq, PKT_TYPE_HELLO, (char *)&hellopkt, sizeof(hellopkt));#ifdef USE_CRYPTOif (callpkt.cryptinfo.type != CALL_CRYPT_NONE) {char *pass, *pass2;char challenge[128];int i;size_t os;pass2 = opt_get_str("crypt_passphrase");if (!*pass2) {pass = getpass(_("Enter encryption passphrase: "));pass = strdup(pass);pass2 = getpass(_("Confirm passphrase: "));if (strcmp(pass, pass2)) {fprintf(stderr, _("%s: passphrases do not match, aborting.\n"), ARGV[0]);free(pass);close(call.csock);call.csock = -1;return;}free(pass);}for (i = 0; i < 128; i++)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -