pcf@galadriel.bt.co.uk (Pete French) (09/15/89)
Since so many of you out there have requested the source to my program for redialing terminals (even though it dont work!) then rather than keep answering mail every 5 minutes I will post it here. Its not very long, or very well written (I wasnt very good at C then) and all the comments have been added recently (i.e. the last few days) so I cant guarantee that they accurately reflect the thinking behind the code when it was written. But for what its worth ... here it is. feel free to play with it as you see fit. If you get it going ... mail me back a copy :-) -Pete. ---------------------------cut here-------------------------------- /* redial - redial a number. Used as "redial <number>". The program immediately logs out the user running it and then attempts to redial him on the given telephone number using a hayes modem. The modem is expected to be 300 baud and connected to tty00. These are - at the present time - hardwired into the program. NOTE : Although this program appears to function correctly when connected to a terminal instead of a modem (i.e. all the correct sequences are sent) it has never been shown to work with an actual modem. This program _DOES_NOT_WORK_ in its current state. Some debugging is therefore necessary (but not much I hope :-) ). It is suggested that this be done by using a terminal to monitor the RS232 line and watch the exchange between the program and the modem. Adapt this code any way you want - you may give it to anyone you like as well (you may eveny give it to anyone you diskile :-) ). -Pete French. */ #include <stdio.h> #include <termio.h> #include <fcntl.h> #include <sys/types.h> #include <utmp.h> #include <string.h> #include <signal.h> extern struct utmp *getutline(); struct utmp *y; struct termio cts; int curpid; char *banner; /* werminate() terminates the program by correctly setting up the utmp entry and then exiting */ werminate(val) int val; { close(0); close(1); close(2); strcpy(y->ut_name,"LOGIN"); strcpy(y->ut_line,"tty00"); strcpy(y->ut_id,"0"); y->ut_type=LOGIN_PROCESS; y->ut_pid=getpid(); pututline(y); exit(val); } main(argc,argv) int argc; char *argv[]; { int rtty,wtty; struct utmp x; signal(SIGALRM,werminate); /* check that we have one argument */ if(argc!=2) { fprintf(stderr,"redial: bad number of arguments\n"); exit(1); } /* fork redial process and kill parent - this logs out the user who is running redial */ banner="Redial from uk.co.bt.kyns\n\r\r"; if(fork()!=0) { kill(getppid(),9); werminate(0); } /* redial process - look for the terminal line in utmp */ strcpy(x.ut_line,ttyname(1)+5); utmpname("/etc/utmp"); if((y=getutline(&x))==0) { fputs("Terminal not found\n",stderr); werminate(1); } /* open the terminal line to the modem - hardwired as TTY0 */ rtty=open("/dev/tty00",O_RDONLY); wtty=open("/dev/tty00",O_WRONLY); /* duplicate onto stdin, stdout and stderr */ dup2(rtty,0); dup2(wtty,1); dup2(wtty,2); /* and then close the originals . We are now connected to /dev/tty00 rather that the original tty */ close(rtty); close(wtty); /* Wait for this process to be inherited by process 1 (since it is now an orphan. Set an alkarm for 60 to terminate the process if we are not inherited */ alarm(60); while(getppid()!=1); alarm(0); /* Dial the number using outdial() and then fork a getty on the line. This process waits for the getty forked process to die (when the user loggs out) and then clears the call by sending ath to the modem */ outdial(argv[1]); if(fork()==0) gettyrun(); wait(&curpid); write(1,"\n\rCall clearing...\n\r",20); close(1); sleep(5); wtty=open("/dev/tty00",O_WRONLY); sleep(5); write(wtty,"+++",3); sleep(5); write(wtty,"ath\n",4); close(wtty); werminate(0); } /* gettyrun() runs a getty process on the modem line to allow logins */ gettyrun() { /* set head of process group. This connects /dev/tty to what we have redirected stdin, stdout and stderr to */ setpgrp(); write(1,banner,strlen(banner)); /* set up the utmp entry and exec a getty process - from here on the system aacts exactly as if a getty had been placed on the line by init */ strcpy(y->ut_name,"LOGIN"); strcpy(y->ut_line,"tty00"); strcpy(y->ut_id,"0"); y->ut_type=LOGIN_PROCESS; y->ut_pid=getpid(); pututline(y); execl("/etc/getty","/etc/getty","tty00","co_300x",(char*)0); } /* outdial() dials the pone number on a hayes modem */ outdial(numb) char *numb; { char expect; int i; /* set up the terminal line to the correct parameters */ cts.c_iflag=BRKINT | ICRNL | IGNCR | IXON; cts.c_oflag=OPOST | ONLCR | TAB3; cts.c_cflag=B300 | CS7 | HUPCL | CREAD | CLOCAL | PARENB; cts.c_lflag=ISIG | ECHOE; cts.c_line=(char)0; cts.c_cc[4]=(char)1; ioctl(1,TCSETA,&cts); /* send the 'at' string and look for a returned AT (out modem returned all strings in capitals ) */ write(1,"at",2); read(0,&expect,1); if(expect!='A') werminate(1); read(0,&expect,1); if(expect!='T') werminate(1); /* All charcters now sent are checked to make sure they are echoed. The string setn is atd<number>r . The r reverses the line when the connection is made so that ORIGINATE can be used at the far end */ write(1,"d",1); read(0,&expect,1); if(expect!='d') werminate(1); i=0; alarm(60); while(numb[i]!='\0') { write(1,&numb[i],1); read(0,&expect,1); if(expect!=numb[i++]) werminate(1); } alarm(0); write(1,"r\n",2); alarm(100); /* wait for the connect message and return . If not then there is a timeout */ scanf("CONNECT"); alarm(0); } -- -Pete French. | British Telecom Research Labs. | "The carefree days are distant now, Martlesham Heath, East Anglia. | I wear my memories like a shroud..." All my own thoughts (of course) | -SIOUXSIE