#!/bin/sh -- # A comment mentioning perl, to prevent perl from looping. Indented to work with bash. eval 'exec perl -S $0 ${1+"$@"}' if 0; $Program = &basename($0); # initialize default values $Debug = 0; #$Debug = 1; $Dialstring = ''; $Init = ''; $Finish = ''; $Reset = ''; $Baud = ''; $Pause = 1; $Hook = ''; $Listall = 0; $Remote_Pipe = 0; $Pty_Only = 0; $Verbose = 0; $Display_Only = ''; $Input_File = ''; $List_Modems_Only = 0; $READERR = '__READ_MODEM_ERROR__'; select(STDERR); $| = 1; select(STDOUT); $| = 1; ################################################################### # Log the cmd line usage: { my $logfile = "/var/tmp/autodial.$ENV{USER}"; my $now = scalar(localtime); if ( -w "$logfile" && open(LOG, ">> $logfile") ) { print LOG "$now $0 " . join(' ', @ARGV) . "\n"; close LOG; } } ################################################################### # set the "central" Modem_Host (usually haystack server) # and other host related things. if ( $ENV{MODEM_HOST} eq '' ) { $Modem_Host = 'haystack'; } else { $Modem_Host = $ENV{MODEM_HOST}; } $ENV{MODEM_HOST} = $Modem_Host; chop($This_Host = `hostname`); $This_Host =~ s/\..*$//; if ( $ARGV[0] eq '-local' ) { $Modem_Host = $This_Host; $ARGV[0] = '-list'; # XXX really? } if ( $This_Host ne $Modem_Host ) { $Xon = "xon $Modem_Host"; } else { $Xon = ''; } ################################################################### # a map to minimal usually supported speeds: %Speed_Map = qw( 2.4 2400 4.8 4800 9.6 9600 14.4 19200 28.8 38400 57.6s 57600 57.6 76800 57.6f 115200 vfast1 230400 vfast2 460800 ); ################################################################## # Process the list of modems: if ( $ENV{MODEM_LIST} eq '' ) { $Modem_File = ''; if ( -r "$ENV{'HOME'}/.modems" ) { $Modem_File = "$ENV{'HOME'}/.modems"; } elsif ( -r "/home/runge/.modems" ) { $Modem_File = "/home/runge/.modems"; } if ( open(MODEMS, "<$Modem_File") ) { my ($str, $host, $line, $numb, $speed, $init, $max, $note); my ($bps, $cnt); while () { next if /^\s*#/; next if /^\s*$/; $str = &trim($_); ($host, $line, $number, $speed, $init, $max, $note) = split(/\s*,\s*/, $str, 7); $cnt = $Modems{$host}{count}++; $cnt = 0 if $cnt eq ''; if ( $Speed_Map{$speed} ) { $bps = $Speed_Map{$speed}; } else { $bps = 'unknown'; } $init = 'ATZ' unless $init; $Modems{$host}{$cnt}{line} = $line; my $note2 = $note; $note2 =~ s/\s+/_/g; $Modems{$host}{$cnt}{info} = "$host $number $speed $bps $init NOTE:$note2"; $Modems{$host}{$line}{bps} = $bps; $Modems{$host}{$line}{all} = $str; $Modems{$host}{$line}{note} = $note; $Modems{$host}{$line}{init} = $init; $Modems{$host}{$line}{max} = $max; # print STDERR "Max: $Modems{$host}{$line}{max}\n"; } close(MODEMS); } else { # hardwire them then... my $host = $Modem_Host; my $dev = 'ttyS0'; $Modems{$host}{count} = 0; $Modems{$host}{0}{line} = $dev; $Modems{$host}{0}{info} = 'haystack 472-5913 28.8 ATZ'; $Modems{$host}{$dev}{max} = 60; } } else { my $cnt = 0; my $line; my $host = $Modem_Host; foreach $line (split(/,/, $ENV{MODEM_LIST})) { next if $line =~ /^\s+$/; $Modems{$host}{$cnt++} = $line; } } ################################################################## # Decide issues about grabbing the X selection: $Do_Selection = 0; if ( $ARGV[0] eq '-sel') { shift; $Do_Selection = 1; } $Do_Selection = 1 if $Program eq 'dialsel'; if ( $Do_Selection && $ENV{DIAL_SELECTION} eq '' ) { $ENV{DIAL_SELECTION} = 1; my $number = ''; $number = `selection.tcl 2>/dev/null`; $number =~ s/\n/ /g; $number =~ s/^\s*//; $number =~ s/\s*$//; $number = &url2phone_number($number); $number =~ s/[<\(\[]//g; $number =~ s/[>\)\]]/-/g; $number =~ s/\s+/-/g; $number =~ s/\.+/-/g; $number =~ s/[-]+/-/g; $number =~ s/^-//; $number =~ s/-$//; my $test = $number; $test =~ s/\D//g; if ( length($test) < 7 ) { print STDERR "Converting letters to numbers $number -> "; $number = &convert_letters($number); print STDERR "$number\n"; } if ( $number =~ /^[\-\d]+$/ ) { if ( $ARGV[0] eq '-D' || $Display_Only ) { system("people -scrub '$number'"); exit 0; } my $tmp = $number; system("$Xon xterm -geometry 60x20+400+400 -e people -add_timeout 10 -add \"$number\" &"); $tmp =~ s/-//g; if ( length($tmp) == 10 ) { $number = "1-$number"; } if ( length($tmp) >= 7 ) { chop($number = `people -scrub '$number'`); } my $args = join(' ', @ARGV); print STDERR "$0 -X $args -n $number &\n"; system("$0 -X $args -n $number &"); exit 0; } else { print STDERR "Bad selected number: $number\n"; exit 1; } } ################################################################## # decide whether to launch the xterm. $Do_Xterm = 0; $Xterm_Opts = "-name autodial -title autodial -geometry 80x35+100+100 -bg gainsboro -fg black -xrm 'XTerm*VT100*translations: #override : string(\"\\n\")'"; $Xprompt = 'tkquery -warp -space -nocancel "%MSG"'; if ( $ARGV[0] =~ /^-x$/ ) { $Do_Xterm = 1; shift; } elsif ( $ARGV[0] =~ /^-X$/ ) { $Do_Xterm = 2; shift; } elsif ( $ARGV[0] =~ /^-Xwait$/ ) { $Do_Xterm = 2; $Do_Xterm_nobg = 1; shift; } elsif ( $ARGV[0] =~ /^-display$/ ) { $Do_Xterm = 2; shift; $ENV{DISPLAY} = shift; } elsif ( $0 =~ /^x/ ) { $Do_Xterm = 1; } ################################################################## # record the calling arguments $Args = ''; foreach my $arg (@ARGV) { # try to quote args properly. if ( $arg =~ /\s/ || $arg eq '#' ) { $Args .= " \"$arg\""; } else { $Args .= " $arg"; } } if ( $ENV{AUTODIAL_MODEM} ne '' ) { $Args = "-l $ENV{AUTODIAL_MODEM} $Args"; } if ( $Do_Xterm && $ENV{AUTODIAL_XTERM} eq '' ) { $ENV{AUTODIAL_XTERM} = $Do_Xterm; if ( $Do_Xterm == 2 || $Do_Xterm == 3 ) { $Xterm_Opts = " -iconic $Xterm_Opts" } if ( $This_Host ne $Modem_Host ) { chop($This_Display = `disp -h`); if ( $This_Display eq '' ) { $This_Display = $ENV{DISPLAY}; } if ( $This_Display =~ /^:[\d\.]+$/ ) { $This_Display = "$This_Host$This_Display"; } &msg("rsh $Modem_Host $Program -display $This_Display $Args &\n") if $ENV{DEBUG}; system("rsh $Modem_Host $Program -display $This_Display $Args &"); } else { &msg("xterm +ls +wf $Xterm_Opts -e $0 $Args &\n") if $ENV{DEBUG}; if ( $Do_Xterm_nobg ) { system("xterm +ls +wf $Xterm_Opts -e $0 $Args"); } else { system("xterm +ls +wf $Xterm_Opts -e $0 $Args &"); } } exit 0; } ################################################################## $TTY0 = $Modems{$Modem_Host}{0}{line}; $Usage = <<"END"; $Program: Uses a modem to automatically a number (or sequence of numbers) It then passes control over to you. (i.e. you pick up the phone and then the modem hangs up). Usage: $Program Options: -n Add dialing digits to dial sequence. -s Add sleep time to dial sequence. "," -w Add a wait for silence event to dial sequence. "\@" -t Add a wait for dialtone event to dial sequence. "W" -e Add a string to be eval'ed to dial sequence (hack). -F Read the number to dial from -d Use instead of stuff from -n,-s,-w -b Set baudrate to -l Use modem at /dev/ ($TTY0) -i Init strings for modem. Separate cmds with "|" sign. Or use the "%" instead. -f Finish strings for modem. Separate cmds with "|" sign. This is after user response, but BEFORE ATH. ($Finish) -r Reset strings for modem. Separate cmds with "|" sign. This is AFTER ATH. ($Reset) "%" may be used as separation char instead of "|" -pty Start the remote modem in a pty and then exit. (use -l host:device) -x Launch in an xterm. -X As -x, plus additional X-window prompts. -display Set DISPLAY to , implies -X. Each of -x, -X, -display MUST be the first option on the cmdline. -L, -list List available modems on modem host. -listall List available modems on all hosts. -local List available modems on local machine. (must be first arg) -v Verbose extra info (must come first) -hook Hook to run a command after the connection. -p Pause and prompt before exiting. -np Do not pause. -debug Turn on debug output. -D Display scrubbed number and exit. -DD Print dialstring and exit. Notes: Here is an example: $Program -n 18887862786 -s 8 -w -n 123456789 where "123456789" is a secret code that needs to be entered. The "modemese" dialstring created out of this would be: ATDT18887862786,,,,\@123456789 The list of modems is in the file: $Modem_File. This program should be used as a interface to that file. with the -L, -list, -listall, -local, and -v switches. programs that might be needed: people, selection.tcl, tkquery, disp stty, xon, rsh, xterm, xwit, whoami, id, hostname END ####################################################################### # (finally) read command line args LOOP: while (@ARGV) { $_ = shift; CASE: { /^-n$/ && (push(@Dial_Items, "NUM:" . shift), last CASE); /^-s$/ && (push(@Dial_Items, "SLEEP:" . shift), last CASE); /^-e$/ && (push(@Dial_Items, "EVAL:" . shift), last CASE); /^-w$/ && (push(@Dial_Items, "WAIT:"), last CASE); /^-t$/ && (push(@Dial_Items, "TONE:"), last CASE); /^-d$/ && ($Dialstring = shift, last CASE); /^-display$/ && ($ENV{DISPLAY} = shift, last CASE); /^-b$/ && ($Baud = shift, last CASE); /^-p$/ && ($Pause = 1, last CASE); /^-np$/ && ($Pause = 0, last CASE); /^-v$/ && ($Verbose = 1, last CASE); /^-pty$/ && ($Pty_Only = 1, last CASE); /^-l$/ && ($Line = shift, last CASE); /^-i$/ && ($Init = shift, last CASE); /^-f$/ && ($Finish = shift, last CASE); /^-r$/ && ($Reset = shift, last CASE); /^-F$/ && ($Input_File = shift, last CASE); /^-debug$/ && ($Debug = 1, last CASE); /^-D$/ && ($Display_Only = 1, last CASE); /^-DD$/ && ($Debug = 2, last CASE); /^-hook$/ && ($Hook = shift, last CASE); /^(-L|-list)$/ && ($List_Modems_Only = 1, last CASE); /^-default$/ && ($Modem_Host = $This_Host, $List_Modems_Only = 2, last CASE); /^-listall$/ && ($List_Modems_Only = 1, $Listall = 1, $Verbose = 1, last CASE); /^-(-.*)$/ && (unshift(@ARGV, $1), last CASE); /^-h/ && ((&help), exit 0, last CASE); if ( /^-(..+)$/ ) { # split bundled switches: my ($y, $x) = ($1, ''); foreach $x (reverse(split(//, $y))) { unshift(@ARGV,"-$x") }; last CASE; } /^-/ && ((print "Invalid arg: $_\n", &help()), exit 1, last CASE); unshift(@ARGV,$_); last LOOP; } } if ( $Input_File && -f $Input_File ) { if ( open(INPUT, "<$Input_File") ) { # http://rd.yahoo.com/yp/phonebooth/?http://phonebooth.yahoo.com/?dto=6038801428 # http://rd.yahoo.com/whitepages/idt/?http://call.click2talk.net2phone.com/cgi-bin/c2tdial.cgi?name=John+Ruth+Runge&number=(603)878-2690&key=KD8757FG&orig=yahoops&img=yahoo&ext=x.n2p my ($numb); while () { chomp($numb = $_); next if $numb =~ /^\s*$/; # clean it up: $numb =~ s/^\s*//; # url is first one: $numb =~ s/\s.*$//; # $numb =~ s/^[^\?]*\?//; # first or last "?" ? $numb =~ s/^.*\?//; # last $numb =~ s/[\(\)-]//g; if ( $numb =~ /(dto|number)=(\d+)/ ) { $numb = $2; } else { my $best; foreach my $part (split(/\D+/, $numb)) { my $lp = length($part); my $lb = length($best); # FIXME if ( 7 <= $lp && $lp <= 11 ) { # good part if ( 7 <= $lb && $lb <= 11 ) { ; # but good best } else { $best = $part; } } else { if ( 7 <= $lb && $lb <= 11 ) { ; # but good best } else { $best = $part; } } # print STDERR "$part best=$best\n"; } if ( $best ne '' ) { $numb = $best; } } if ( $numb ne '' ) { last; } } close(INPUT); if ( $numb ne '' ) { chomp($numb = `people -scrub '$numb'`); push(@Dial_Items, "NUM:" . $numb); } elsif (! @Dial_Items) { die "No dial items!\n"; } } } if ( $Display_Only ) { if ( ! $Dialstring ) { $Dialstring = join(' ', @Dial_Items); $Dialstring =~ s/[a-z:]//g; } system("people -scrub '$Dialstring'"); exit $?; } if ( $List_Modems_Only ) { &list_modems(); exit 0; } ####################################################################### # determine modem device file if ( $Line ne '' ) { if ( $Line =~ /^\d+$/ ) { # handle -l 1 (line #1 or dev #) convenience: if ( $Modems{$Modem_Host}{$Line}{line} ne '' ) { $Line = $Modems{$Modem_Host}{$Line}{line}; } else { $Line = "/dev/cua$Line"; } } $Line =~ s,^/dev/,,; $Tty = $Line; } elsif ( $ARGV[0] ne '' ) { $Tty = $ARGV[0]; } elsif ( $ENV{AUTODIAL_MODEM} ne '' ) { $Tty = $ENV{AUTODIAL_MODEM}; } else { $Tty = $TTY0; } ####################################################################### # for other than network modem we must be on Modem_Host... if ( ! $Pty_Only && $This_Host ne $Modem_Host ) { # environment passing is lost here: &msg("rsh $Modem_Host $Program $Args\n") if $ENV{DEBUG}; exec "rsh $Modem_Host $Program $Args"; exit 1; } ####################################################################### # handle "network modem" hack (pty glued to "rsh host cu -l ...") if ( $Tty =~ /:/ ) { # it is like: somehost:ttyDEV my $tty_save = $Tty; ($Remote_Host, $Tty) = split(/:/, $Tty, 2); $Remote_Pipe = 1; if ( $Tty !~ m,/, ) { $Tty = "/dev/$Tty"; } $Remote_Tty = $Tty; my $line0 = &basename($Tty); if ( $Modems{$Remote_Host}{$line0} ) { $Host_LU = $Remote_Host; $Line_LU = $line0; } else { $Host_LU = $Modem_Host; # will be modemhost $Line_LU = $tty_save; $Line_LU =~ s,/dev/,,g; # will be somehost:DEV } my $speed = ''; if ( $Modems{$Host_LU}{$Line_LU}{bps} ne '' ) { $speed = "-s $Modems{$Host_LU}{$Line_LU}{bps}"; } &msg("\nRunning: ptyexec rsh $Remote_Host \"cu $speed -E '' -l $Remote_Tty\"\n"); my $out = `ptyexec -d rsh $Remote_Host "cu $speed -E '' -l $Remote_Tty"`; if ( $out =~ /SLAVE:\s*(\S+)/ ) { # N.B. $Tty is overwritten with the local pseudo terminal: $Tty = $1; $Pty = $Tty; $Pty =~ s/tty/pty/; &msg("Found slave: $Tty\n"); &msg("$out\n"); print STDOUT $Tty; sleep 2; &msg(`ls -l $Pty $Tty`); } else { die "No slave: $out\n"; } } else { if ( $Tty !~ m,^/, ) { $Tty = "/dev/$Tty"; } $Host_LU = $Modem_Host; $Line_LU = &basename($Tty); } if ( $Pty_Only ) { if ( ! $Remote_Pipe ) { &msg("SLAVE: $Tty\n"); } exit 0; } ####################################################################### # Now know line & etc, tell user &msg("\nUsing line: $Tty\n"); &msg("Date: " . `date`); &msg("PID: $$\n"); &msg("Host Lookup: $Host_LU\n"); &msg("Line Lookup: $Line_LU\n\n"); ####################################################################### # Work out lock files { my $tty_base = &basename($Tty); # we have symlink /var/spool/uucp to /var/lock. $Lock_File1 = "/var/spool/uucp/LCK..$tty_base"; $Lock_File2 = $Lock_File1; if ( $tty_base =~ /cua/ ) { $Lock_File2 =~ s/LCK\.\.cua/LCK..ttyS/; } elsif ( $tty_base =~ /ttyS/ ) { $Lock_File2 =~ s/LCK\.\.ttyS/LCK..cua/; } } if ( -f $Lock_File1 ) { &check_lock($Lock_File1); } if ( -f $Lock_File2 ) { &check_lock($Lock_File2); } if ( $Remote_Pipe ) { &msg("\nSkipping lockfile usage: $Lock_File1\n"); } elsif ( open(LCK, ">$Lock_File1") ) { my $tmp = sprintf("%*d\n", 10, $$); $tmp = pack(I, $$); my $user = $ENV{USER}; if ( ! $user ) { chop($user = `whoami`); } if ( ! $user ) { chop($user = `id -nu`); } if ( ! $user ) { $user = 'unknown'; } print LCK "$tmp $Program $user\n"; close(LCK); } else { &msg("\nCannot open lockfile: $Lock_File1\n"); &beep_and_map(); sleep 5; &Exit(1); } if ( $Remote_Pipe ) { $Set_Lock_File = ''; } else { if ( -f $Lock_File1 ) { $Set_Lock_File = $Lock_File1; } else { &msg("\nCannot open lockfile: $Lock_File1\n"); &beep_and_map(); sleep 5; &Exit(1); } &msg("\nLockfile: $Set_Lock_File\n"); } ####################################################################### # Set signal handlers: $SIG{HUP} = 'Exit'; $SIG{INT} = 'Exit'; $SIG{TERM} = 'Exit'; &msg("\n"); ####################################################################### # create dialing string "ATDT..." out of our little language { $Waittime = 0; my $numbers = ''; if ( $Dialstring eq '' ) { foreach my $item (@Dial_Items) { if ( $item =~ /NUM:/ ) { # should convert_letters be called here? $Dialstring .= " $' "; $numbers .= " $' "; } elsif ( $item =~ /EVAL:\s*/ ) { my $evalcmd = $'; eval "\$tmp .= $evalcmd"; $tmp =~ s/\n//g; &msg("Evaluated: $evalcmd -> $tmp\n"); $Dialstring .= ' ' . $tmp . ' '; } elsif ( $item =~ /SLEEP:\s*(\d+)/ ) { my $sleep = int((1.0+$1)/2); # two seconds per comma. $Waittime += $sleep; $Dialstring .= " "; $Dialstring .= "," x $sleep; $Dialstring .= " "; } elsif ( $item =~ /WAIT:/ ) { $Dialstring .= ' @ '; $Waittime += 5; } elsif ( $item =~ /TONE:/ ) { $Dialstring .= ' W '; $Waittime += 3; } else { &msg("Huh? $item\n"); &beep_and_map(); &pause("exit"); &Exit(1); } } } if ( $numbers ne '' ) { $numbers =~ s/^\s*//g; $numbers =~ s/\s*$//g; $numbers .= ": $Program"; print STDERR "]0;${numbers}"; } } if ( $Dialstring !~ /;\s*$/ ) { $Dialstring .= " ; "; # add trailing ";" to get back modem cmd mode } if ( $Dialstring !~ /^\s*atd/i ) { $Dialstring = " ATDT " . $Dialstring; # need ATDT at start } $Dialstring_raw = $Dialstring; $Dialstring_raw =~ s/ATDT//ig; $Dialstring_raw =~ s/[\s-]//g; &msg("Dialstring is: $Dialstring\n"); $Dialstring =~ s/\s//g; # remove spaces if ( $Debug == 2 ) { &msg("Dialstring is: $Dialstring\n"); &pause("exit"); &Exit(0); } ####################################################################### # open the modem device $Set_Init = 0; REOPEN: if ( $Baud eq '' && $Modems{$Host_LU}{$Line_LU}{bps} ne '' ) { $Baud = $Modems{$Host_LU}{$Line_LU}{bps}; &msg("\nSet baud to $Baud bps\n"); } if ( $Baud <= 19200 ) { if ( $Modems{$Host_LU}{$Line_LU}{note} eq '' || $Modems{$Host_LU}{$Line_LU}{note} =~ /\b(dead)\b/i ) { my $n = 2; &msg("\nNote said: $Modems{$Host_LU}{$Line_LU}{note}. sleep $n\n"); sleep $n; } } &msg("\nOpening $Tty ...\n\n"); if ( $Modems{$Host_LU}{$Line_LU}{note} =~ /sysopen/ ) { use IO::File; &msg("sysopen(MODEM, $Tty, O_RDWR|O_NONBLOCK)...\n"); if (! sysopen(MODEM, $Tty, O_RDWR|O_NONBLOCK) ) { &msg("cannot sysopen: $Tty: $!\n"); &beep_and_map(); &pause("exit"); &Exit(1); } &msg("opened $Tty OK\n"); &nap(0.1); select(MODEM); $| = 1; select(STDERR); } else { if (! open(MODEM, "+>$Tty") ) { &msg("cannot open: $Tty: $!\n"); &beep_and_map(); &pause("exit"); &Exit(1); } &msg("opened $Tty OK\n"); &nap(0.1); select(MODEM); $| = 1; select(STDERR); # use /bin/stty to initialize it to no echo and raw mode &msg("\nstty $Baud -echo raw <$Tty >$Tty ... "); system("stty $Baud -echo raw <$Tty >$Tty"); &msg("done\n"); &nap(0.2); } &bitsetup(); ####################################################################### # send the initialization strings to the modem $char = "\\|"; $char = '%' if $Init !~ /$char/; if ( ! $Set_Init ) { $Set_Init = 1; my $str; if ( $Init eq '' && $Modems{$Host_LU}{$Line_LU}{init} ne '' ) { $str = $Modems{$Host_LU}{$Line_LU}{init}; $str =~ s/\;/$char/g; # $Init = "$str$char$Init"; $Init = "$str"; } $Init = "AT${char}" x 1 . $Init; $str = $Init; $str =~ s/$char/, /g; print "\nINIT: $str\n\n"; } &writemodem("\r"); &nap(0.1); foreach my $ini (split(/$char/, $Init)) { next if $ini =~ /^\s*$/; &msg("INIT: $ini\n") if $Debug; &writemodem("$ini\r"); my $ret = &readmodem(5); if ( $ret ne $READERR && $ret ne '' && $ret !~ /OK/ ) { # wait a bit for slow modems... my $sleep = 3.0; &msg("(INIT: sleeping for $sleep seconds in case modem is just slow...)\n") if $Debug; &nap($sleep); $ret .= &readmodem(5); } if ( $ret eq $READERR || $ret !~ /OK/ ) { close(MODEM); print STDERR "PROBLEM: ret=$ret\n"; $Retry_Count++; if ( $Retry_Count > 5 ) { &Exit(1); } else { &msg("RETRY: $Retry_Count\n"); print STDERR "\n"; &nap(0.5); goto REOPEN; } } else { &msg("\nGOT_OK: $ret\n\n") if $Debug; } } ####################################################################### # dial the place &nap(0.2); &writemodem("AT\r"); &readmodem(); $max_write = $Modems{$Host_LU}{$Line_LU}{max}; &msg("max_write: $max_write\n") if $Debug; if ( $max_write ne '' && $max_write > 0 && length($Dialstring_raw) + 2 > $max_write ) { # Handle icky case of long dialstring that must be broken up: $old_modem = 1; &msg("WARNING: old modem, splitting up dialstring into $max_write chars or smaller pieces\n\n"); # 32 should be enough and this cuts # sun_audix on a "," TODO: cleanup. #my $stride = $max_write - 8; #$stride = 32 if $stride > 32; my $stride = $max_write - 4; $stride = 36 if $stride > 36; my $ds = $Dialstring_raw; my ($dt, @pieces, $piece, $lil_dial, $n, $cnt); $ds =~ s/;+$//; while ($ds ne '') { $dt = substr($ds, 0, $stride); &msg("piece: $dt\n"); push(@pieces, $dt); $ds = substr($ds, $stride); } &msg("\nTurning off dial tone requirement: ATX3\n"); &writemodem("ATX3\r"); &nap(0.25); &readmodem(); $cnt = 0; foreach $piece (@pieces) { # We are likely so screwed up on our @'s we just # hardwire each one to 6 seconds. TODO: cleanup $piece =~ s/\@/,,,/g; if ( $cnt == 0 ) { # 2 secs for initial dialtone: $lil_dial = "ATDT,$piece;"; } else { $lil_dial = "ATDT$piece;"; } $n = length($lil_dial) - 2; &msg("DIALING PIECE: $lil_dial ($n)\n"); &writemodem("$lil_dial\r"); &nap(0.25); &msg("\[$cnt]\n"); if ( ++$cnt < @pieces ) { $ds = ''; while ($ds !~ /OK/ ) { &msg("readmodem...\n"); $ds .= &readmodem(); } &msg("\nGOT\[$cnt]: $ds\n"); } } } else { &msg("DIALING: $Dialstring\n\n"); &writemodem("$Dialstring\r"); } &nap($Waittime); ####################################################################### # read modem output waiting for "OK" to appear # todo: check for BUSY and other errors $recv = ''; $read_cnt = 0; while (1) { $recv .= &readmodem(); &nap(0.5); last if $old_modem; # risk it... &msg("\nrecv: $recv\n") if $Debug; last if $recv =~ /OK/; last if $read_cnt++ > 20; } ####################################################################### # tell the guy to pick up the phone, then we hangup... #print "*** Now would be a good time to pick up the phone if you haven't already!\n"; #print "*** After picking it up, press to have the modem hangup ===> "; if ( $ENV{AUTODIAL_XTERM} == 2 ) { print "*** Pick up the phone, and then Click on the OK widget "; } else { print "*** Pick up the phone, and then press "; } print ""; &nap(0.35); print ""; &nap(0.35); print ""; $x = ''; if ( $ENV{AUTODIAL_XTERM} == 2 ) { $x = &pause("--Pick up the phone", 1); } else { $x = ; } if ( $Hook ne '' ) { # run the connected hook program (e.g. show the user some info). &msg("\nRunning: $Hook\n"); system("$Hook"); &msg("\n"); } ####################################################################### # send the modem finishing strings $char = "\\|"; $char = '%' if $Finish !~ /$char/; foreach my $fini (split(/$char/, $Finish)) { next if $fini eq ''; &msg("finishing string: $fini\n"); &writemodem("$fini\r"); sleep 1; &readmodem(); } ####################################################################### # hangup &msg("\nHanging up modem $Tty ...\n\n"); &msg("\nATH:\n") if $Debug; &writemodem("ATH\r"); &readmodem(); ####################################################################### # send the modem reset strings $char = "\\|"; $char = '%' if $Reset !~ /$char/; foreach my $rese (split(/$char/, $Reset)) { next if $rese eq ''; &msg("RESET: $rese\n") if $Debug; &writemodem("$rese\r"); &readmodem(); sleep 1; } close(MODEM); ####################################################################### # clean up lock files if ( $Set_Lock_File ) { unlink($Set_Lock_File); # done in &Exit() too. } if ( $ENV{AUTODIAL_XTERM} == 2 ) { &msg("sleeping...\n"); sleep 2; my $sleep = 20; if ( $ENV{'AUTODIAL_SLEEP'} ) { $sleep = $ENV{'AUTODIAL_SLEEP'}; } &Exit(0, $sleep); } else { sleep 3 unless $Pause; &pause("exit"); } ####################################################################### # done. &Exit(0); ####################### Subroutines ################################### sub Exit { my ($n, $sleep) = @_; if ( $Set_Lock_File && -f $Set_Lock_File ) { unlink($Set_Lock_File); &msg("\n$Program: unlinked: $Set_Lock_File\n"); sleep 1; $sleep = 1; } &msg("\n$Program: Exiting with \"$n\"\n"); $sleep += 5 if $Debug; if ( $sleep ne '' ) { &msg("(sleep=$sleep)\n"); sleep $sleep; } exit $n; } sub list_modems { foreach my $flag (0,1) { foreach my $host (keys(%Modems)) { if ( $flag == 0 && $host ne $Modem_Host ) { next; } elsif ( $flag == 1 && $host eq $Modem_Host ) { next; } foreach $i ( 0 .. $Modems{$host}{count} - 1 ) { if ( ! $Listall && $host ne $Modem_Host ) { if ( $Modems{$host}{$i}{line} !~ /:/ ) { next; } } if ( $Verbose ) { print STDOUT "$Modems{$host}{$i}{line} $Modems{$host}{$i}{info}\n"; } else { print STDOUT "$Modems{$host}{$i}{line}\n"; } return if $List_Modems_Only == 2; } } } } sub beep_and_map { if ( $ENV{AUTODIAL_XTERM} ne '' ) { # map, i.e. uniconify the xterm: system("xwit"); } print STDERR ""; sleep 1; print STDERR ""; } sub check_lock { my ($lckfile) = @_; return if $Remote_Pipe; if ( ! -f $lckfile ) { return; } my ($buf, $pid); if ( open(LCK, "$lckfile") ) { read(LCK, $buf, 64); close(LCK); if ( $buf =~ /^\s+(\d+)\n$/ ) { # e.g. " 1235\n" $pid = $1; } elsif ( length($buf) == 4 ) { # e.g. "BBBB" (B = byte) $pid = unpack(I, $buf); } else { &msg("Cannot read lockfile: $lckfile\n"); &beep_and_map(); sleep 5; &Exit(1); } if ( -d "/proc/$pid" ) { &msg("Process $pid still running. Lockfile: $lckfile\n"); &beep_and_map(); sleep 5; &Exit(1); } &msg("Process $pid not running. Removing stale lockfile: $lckfile\n\n"); unlink($lckfile); } else { &msg("Cannot read lockfile: $lckfile\n"); &beep_and_map(); sleep 5; &Exit(1); } } sub url2phone_number { # some url's have phone numbers embedded in them. # apply some heuristics to extract the number: my ($x) = @_; $x =~ s/\n/ /g; $x =~ s/^\s*//; $x =~ s/\s*$//; my ($y, $t, $best); if ( $x =~ m,http:,i ) { $x =~ s,^.*/,,; $x =~ s,^.*\?,,; $best = ''; foreach $y (split(/&/, $x)) { $y =~ s/^[^=]*=//; $y =~ s/%([a-f\d][a-f\d])/pack("C", hex($1))/eig; next if $y =~ /[a-z]/i; $y =~ s/\s//g; $y =~ s/\+//g; $t = $y; $t =~ s/\D//g; next if length($t) < 7; next if length($t) > 11; if ( $y =~ /^([-\d\(\)]+)$/ ) { if ( $best ne '' ) { if ( $best =~ /\(/ && $y !~ /\(/ ) { next; } } $best = $y; } } $x = $best if $best ne ''; } return $x; } sub convert_letters { # This is like on the phone pad ABC is 2, etc.. my ($x) = @_; $x =~ s/[ABC]/2/ig; $x =~ s/[DEF]/3/ig; $x =~ s/[GHI]/4/ig; $x =~ s/[JKL]/5/ig; $x =~ s/[MNO]/6/ig; $x =~ s/[PQRS]/7/ig; $x =~ s/[TUV]/8/ig; $x =~ s/[WXYZ]/9/ig; return $x; } sub pause { # wrapper to pause the program possibly waiting for a response my ($str,$mode) = @_; my $x; $mode = $Pause unless $mode; $str = "continue" unless $str; if ( $str =~ /^--/ ) { $str = $' } else { if ( $ENV{AUTODIAL_XTERM} == 2 ) { $str = "Click OK to $str"; } else { $str = "press to $str "; } } if ( $mode ) { if ( $ENV{AUTODIAL_XTERM} == 2 ) { $str =~ s/"/'/g; my $xpr = $Xprompt; $xpr =~ s/%MSG/$str/g; chop($x = `$xpr`); } else { &msg("\n$str "); chop($x = ); } } return $x; } sub ready_to_read { # see if modem is read to be read from my ($timeout) = @_; my $nf; &msg("ready_to_read-0\n") if $Debug; if ( $timeout ne '' ) { $nf = select($ROUT=$RIN, undef, undef, $timeout); } else { $nf = select($ROUT=$RIN, undef, undef, undef); } &msg("ready_to_read-1\n") if $Debug; return ($nf, $ROUT); } sub nap { # sleep a floating point amount of time my ($t) = @_; &msg("nap: $t\n") if $Debug; select(undef,undef,undef, $t); } sub bitsetup { # initialize the bit vectors for select() $RIN = $WIN = $EIN = ''; # N.B. global bitvectors vec($RIN,fileno(MODEM),1) = 1; vec($WIN,fileno(MODEM),1) = 1; $EIN = $RIN | $WIN; my $mydebug = 0; if ( $mydebug ) { print "r: ", bitview($RIN), "\n"; print "w: ", bitview($WIN), "\n"; print "e: ", bitview($EIN), "\n"; } } sub bitview { # debugging sub to print out bit vectors my ($vec) = @_; my $bits = unpack("b*", $vec); return $bits; } sub msg { # stderr wrapper print STDERR @_; } sub readmodem { # read a block from the modem. No more than 1024 bytes. my ($times) = @_; my ($nf, $ok, $cnt, $timo, $rchk, $read, $n); my $sleep = 0.4; my $sleep_got = 0.2; $rchk = ''; &msg("readmodem-IN\n") if $Debug; $nf = 0; $ok = 0; $cnt = 0; while (! $nf ) { &nap($sleep); if ( $times > 0 ) { $timo = $times * $sleep; last if $cnt++ > $times; } else { $timo = ''; } &msg("readmodem-cnt=$cnt\n") if $Debug; ($nf, $rchk) = &ready_to_read($timo); $ok++ if $nf; } if ( ! $ok ) { &msg("readmodem-error\n") if $Debug; return $READERR; } else { &nap($sleep_got); } &msg("readmodem-sysread\n") if $Debug; $n = sysread(MODEM ,$read, 256); print STDOUT "$read\n"; # print data read to the terminal &msg("readmodem-OUT <$nf/$n>\n") if $Debug; return $read; } sub writemodem { # write a string to the modem. # note that \r must be supplied by caller. my ($data) = @_; my $tmp = $data; my $putc = 0; my $c; $tmp =~ s/[\n\r]*$//; &msg("writemodem-0\t<$tmp>\n") if $Debug; if ( $putc && length($data) > 16 ) { # this is no longer used. &msg("len: " . length($data)); foreach $c (split(//, $data)) { syswrite(MODEM ,$c, length($c)); &nap(0.05); } } else { syswrite(MODEM ,$data, length($data)); } &msg("writemodem-1\n") if $Debug; &nap(0.1); } sub help { if (open(MORE, "|more")) { print MORE $Usage; close(MORE); } else { print STDOUT $Usage; } } sub trim { # remove leading and trailing whitespace my ($x) = @_; $x =~ s/^\s*//; $x =~ s/\s*$//; return $x; } sub basename { # Like basename(1), returns basename of a path. my ($x) = @_; $x =~ s,/+$,,; # remove trailing /'s if ( $x =~ m,/([^/]+)$, ) { # check if matches / $x = $1; # grab stuff after the last / } $x = '.' if $x eq ''; # evidently input was null. return $x; } sub dirname { # Like dirname(1), returns dirname of a path. my ($x) = @_; $x =~ s,/+$,,; # remove trailing /'s $x =~ s,/+,/,g; # change multiple /'s to single / if ( $x =~ m,/([^/]+)$, ) { # check if matches / $x = $`; # grab stuff before / $x = '/' if $x eq ''; # is root if null. } else { # it was a bare word without / $x = '.'; } $x = '.' if $x eq ''; # never return null string return $x; } __END__