/* * axconv.c - A simple AX.25 convers client - version 1.3 * * Copyright (C) 1997 Tomi Manninen, OH2BNS, . * * Compile with: gcc -Wall -O6 -o axconv axconv.c * * * Axconv is a simple AX.25 convers client intended to be launched * from ax25d. It connects to the conversd system specified and * optionally logs in with the user and channel specified. It does * the necessary end-of-line conversions and also buffers the traffic * in order to optimise the AX.25 channel usage slightly. * * Usage: axconv [-c ] [-l] [-n ] [-p ] [-t ] * [] * * Options: * -c The channel to log into. Defaults * to nothing. Only valid if name is * also specified. * * -l Use LF as end-of-line instead of CR. * * -n Use when logging in to the * convers server. If omitted, no * automatic logging in is done. * * -p Maximum frame length for the client * connection. Defaults to 256. * * -t After seconds of inactivity * from the client and convers server the * connection is closed. Defaults to * 0 ie. no timeout. * * * 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 #include #include #include #include #include #include #include #include #include #include #include #define BUFFERSIZE 4096 #define FLUSHTIMEOUT 500000L /* 0.5 sec */ static char eol = '\r'; static char *usage_string = "Usage: axconv [-c ] [-l] [-n ] [-p ] [-t ] []"; #define PERROR(s) fprintf(stderr, "%s: %s%c", (s), strerror(errno), eol) static void alarm_handler(int sig) { printf("*** Inactivity timeout%c", eol); exit(0); } /* * Convert to */ static int convert_eol_crlf(char *inbuf, char *outbuf, int len) { int i = 0; while (len-- > 0) { if (*inbuf == eol) { outbuf[i++] = '\r'; outbuf[i++] = '\n'; } else outbuf[i++] = *inbuf; inbuf++; } return i; } /* * Convert , or a plain to a eol */ static int convert_crlf_eol(char *inbuf, char *outbuf, int len) { int i = 0; while (len-- > 0) { if (*inbuf == '\r' && (inbuf[1] == '\n' || inbuf[1] == '\0')) { /* * or */ outbuf[i++] = eol; inbuf++; len--; } else if (*inbuf == '\n') { /* * */ outbuf[i++] = eol; } else outbuf[i++] = *inbuf; inbuf++; } return i; } int main(int argc, char **argv) { char inbuf[BUFFERSIZE], outbuf[BUFFERSIZE]; char *buf; char *name = NULL, *channel = NULL; int paclen = 256, timeout = 0, len, fd; FILE *fp; fd_set fdset; struct timeval tv; struct sockaddr_in sin; struct hostent *hp; struct servent *sp; signal(SIGALRM, alarm_handler); while ((len = getopt(argc, argv, "c:ln:p:t:")) != -1) { switch (len) { case 'n': name = optarg; break; case 'l': eol = '\n'; break; case 'c': channel = optarg; break; case 'p': paclen = atoi(optarg); break; case 't': timeout = atoi(optarg); break; case ':': case '?': fprintf(stderr, "%s%c", usage_string, eol); return 1; } } if (optind == argc) { fprintf(stderr, "%s%c", usage_string, eol); return 1; } if (paclen < 1) { fprintf(stderr, "Invalid paclen: %d%c", paclen, eol); return 1; } if ((buf = malloc(paclen)) == NULL) { PERROR("axconv: malloc"); return 1; } setvbuf(stdout, buf, _IOFBF, paclen); if ((fd = socket(AF_INET, SOCK_STREAM, 0)) < 0) { PERROR("axconv: socket"); return 1; } if ((hp = gethostbyname(argv[optind])) == NULL) { fprintf(stderr, "Unknown host %s%c", argv[optind], eol); close(fd); return 1; } sin.sin_family = AF_INET; sin.sin_addr.s_addr = ((struct in_addr *)(hp->h_addr))->s_addr; sin.sin_port = htons(3600); if (optind == argc - 2) { sp = getservbyname(argv[optind + 1], "tcp"); if (sp != NULL) sin.sin_port = sp->s_port; else sin.sin_port = htons(atoi(argv[optind + 1])); if (ntohs(sin.sin_port) == 0) { fprintf(stderr, "Unknown service %s%c", argv[optind + 1], eol); return 1; } } printf("*** Connecting to %s, port %d%c", hp->h_name, ntohs(sin.sin_port), eol); fflush(stdout); len = sizeof(struct sockaddr_in); if (connect(fd, (struct sockaddr *) &sin, len) == -1) { PERROR("axconv: connect"); return 1; } if ((fp = fdopen(fd, "w+")) == NULL) { PERROR("axconv: fdopen"); return 1; } if (fcntl(STDIN_FILENO, F_SETFL, O_NONBLOCK) == -1) { PERROR("axconv: fcntl"); exit(1); } if (fcntl(fd, F_SETFL, O_NONBLOCK) == -1) { PERROR("axconv: fcntl"); exit(1); } if (name != NULL) { printf("*** Logging in as %s", name); if (channel != NULL) printf(", channel %s", channel); fputc(eol, stdout); fprintf(fp, "/n %s %s\r\n", name, channel ? channel : ""); fflush(stdout); fflush(fp); } alarm(timeout); while (1) { FD_ZERO(&fdset); FD_SET(STDIN_FILENO, &fdset); FD_SET(fd, &fdset); tv.tv_sec = 0; tv.tv_usec = FLUSHTIMEOUT; len = select(fd + 1, &fdset, 0, 0, &tv); if (len == -1) { PERROR("axconv: select"); return 1; } if (len == 0) { fflush(stdout); fflush(fp); } if (FD_ISSET(STDIN_FILENO, &fdset)) { alarm(timeout); len = read(STDIN_FILENO, inbuf, BUFFERSIZE); if (len < 0 && errno != EAGAIN) { PERROR("axconv: read"); break; } if (len == 0) break; len = convert_eol_crlf(inbuf, outbuf, len); fwrite(outbuf, 1, len, fp); } if (FD_ISSET(fd, &fdset)) { alarm(timeout); len = read(fd, inbuf, BUFFERSIZE); if (len < 0 && errno != EAGAIN) { PERROR("axconv: read"); break; } if (len == 0) break; len = convert_crlf_eol(inbuf, outbuf, len); fwrite(outbuf, 1, len, stdout); } } printf("*** Disconnected from %s%c", hp->h_name, eol); fflush(stdout); fclose(fp); free(buf); return 0; }