File Coverage

blib/lib/Ivrs.pm
Criterion Covered Total %
statement 25 656 3.8
branch 0 382 0.0
condition 0 93 0.0
subroutine 11 55 20.0
pod 0 48 0.0
total 36 1234 2.9


line stmt bran cond sub pod time code
1             #Perl module to implement a full functional Interactive Voice Response
2             #System using standard voice modem. I have *taken* some codes from
3             #SerialPort.pm for serial port access, with due respect to Bill Birthisel.
4              
5              
6             package SerialJunk;
7             # this is the linux path. Need to determine location on other OSs
8 1     1   960 use vars qw($ioctl_ok);
  1         2  
  1         107  
9             eval { require 'asm/termios.ph'; };
10             if ($@) {
11             $ioctl_ok = 0;
12             ## print "error message: $@\n"; ## DEBUG ##
13             }
14             else {
15             $ioctl_ok = 1;
16             }
17              
18             package Ivrs;
19 1     1   1208 use POSIX qw(:termios_h);
  1         11444  
  1         8  
20 1     1   2968 use IO::Handle;
  1         8547  
  1         378  
21              
22 1         300 use vars qw($bitset $bitclear $rtsout $dtrout $getstat $incount $outcount
23 1     1   10 $txdone);
  1         1  
24             if ($SerialJunk::ioctl_ok) {
25             $bitset = &SerialJunk::TIOCMBIS;
26             $bitclear = &SerialJunk::TIOCMBIC;
27             $getstat = &SerialJunk::TIOCMGET;
28             $incount = &SerialJunk::TIOCINQ;
29             $outcount = &SerialJunk::TIOCOUTQ;
30             $txdone = &SerialJunk::TIOCSERGETLSR;
31             $rtsout = pack('L', &SerialJunk::TIOCM_RTS);
32             $dtrout = pack('L', &SerialJunk::TIOCM_DTR);
33             }
34             else {
35             $bitset = 0;
36             $bitclear = 0;
37             $statget = 0;
38             $incount = 0;
39             $outcount = 0;
40             $txdone = 0;
41             $rtsout = pack('L', 0);
42             $dtrout = pack('L', 0);
43             }
44              
45              
46             sub TIOCM_LE1 {
47 0 0   0 0 0 if (defined &SerialJunk::TIOCSER_TEMT) { return &SerialJunk::TIOCSER_TEMT; }
  0         0  
48 0 0       0 if (defined &SerialJunk::TIOCM_LE) { return &SerialJunk::TIOCM_LE; }
  0         0  
49 0         0 0;
50             }
51              
52 1     1   6 use Carp;
  1         1  
  1         65  
53 1     1   7 use strict;
  1         1  
  1         35  
54              
55 1     1   4 use vars qw($VERSION @ISA @EXPORT @EXPORT_OK %EXPORT_TAGS);
  1         1  
  1         8967  
56             $VERSION = '0.24';
57              
58             require Exporter;
59              
60             @ISA = qw(Exporter);
61             @EXPORT= qw();
62             @EXPORT_OK= qw();
63             %EXPORT_TAGS = (STAT => [qw( MS_CTS_ON MS_DSR_ON
64             MS_RING_ON MS_RLSD_ON
65             ST_BLOCK ST_INPUT
66             ST_OUTPUT ST_ERROR )],
67              
68             PARAM => [qw( LONGsize SHORTsize OS_Error
69             nocarp yes_true )]);
70              
71             Exporter::export_ok_tags('STAT', 'PARAM');
72              
73             $EXPORT_TAGS{ALL} = \@EXPORT_OK;
74              
75             # Linux-specific constant for Hardware Handshaking
76 0     0 0 0 sub CRTSCTS { 020000000000 }
77              
78             # Linux-specific Baud-Rates
79 1     1 0 6 sub B57600 { 0010001 }
80 1     1 0 4 sub B115200 { 0010002 }
81 1     1 0 1065 sub B230400 { 0010003 }
82 1     1 0 12 sub B460800 { 0010004 }
83              
84             my %bauds = (
85             9600 => B9600,
86             19200 => B19200,
87             38400 => B38400,
88             # These are Linux-specific
89             57600 => B57600,
90             115200 => B115200,
91             230400 => B230400,
92             460800 => B460800,
93             );
94              
95              
96             my %c_cc_fields = (
97             VEOF => &POSIX::VEOF,
98             VEOL => &POSIX::VEOL,
99             VERASE => &POSIX::VERASE,
100             VINTR => &POSIX::VINTR,
101             VKILL => &POSIX::VKILL,
102             VQUIT => &POSIX::VQUIT,
103             VSUSP => &POSIX::VSUSP,
104             VSTART => &POSIX::VSTART,
105             VSTOP => &POSIX::VSTOP,
106             VMIN => &POSIX::VMIN,
107             VTIME => &POSIX::VTIME,
108             );
109             #Default directories and filenames. You may specify $vdir from your
110             #programme
111             my $vdir="sfiles";
112             my $logfile="/var/log/Ivrs_Log";
113             my $tmpmsg="/tmp/tmpmsg";
114              
115              
116             #These headers are required for recorded files only.
117             #my $rmdhdr="";
118             # For Rockwell chip set modem
119             my $rmdhdr="RMD1Rockwell".pack("C20",0,0,0,0,0,0,0,0,0,4,28,32,4,0,0,0,0,0,0,0);
120             # For US Robotics modem
121             #my $rmdhdr="RMD1US Robotics".pack("C17",0,0,0,0,0,0,8,31,64,1,0,0,0,0,0,0,0);
122              
123             my $Babble = 1; #Set to 0 if you do not want lots of garbage in Log File.
124             my $testactive = 0; # test mode active
125             my @Yes_resp = (
126             "YES", "Y",
127             "ON",
128             "TRUE", "T",
129             "1"
130             );
131              
132             my @binary_opt = ( 0, 1 );
133             my @byte_opt = (0, 255);
134              
135             ## my $null=[];
136             my $null=0;
137             my $zero=0;
138              
139 0     0 0   sub nocarp { return $testactive }
140              
141             sub yes_true {
142 0     0 0   my $choice = uc shift;
143 0           my $ans = 0;
144 0 0         foreach (@Yes_resp) { $ans = 1 if ( $choice eq $_ ) }
  0            
145 0           return $ans;
146             }
147              
148             sub new {
149 0     0 0   my $proto = shift;
150 0   0       my $class = ref($proto) || $proto;
151 0           my $self = {};
152 0           my $ok = 0; # API return value
153              
154 0           my $item = 0;
155 0           $self->{NAME} = shift;
156 0 0         open (LOG, ">>$logfile.$self->{NAME}")||die"Log file failed";
157 0           print LOG "\n-----------Access Log file for IVRS-----------\n";
158 0           print LOG `date`;
159 0           $self->{NAME}="/dev/".$self->{NAME} ;
160 0           my $tmpdir=shift;
161 0 0         $vdir=$tmpdir if $tmpdir ne "";
162 0           my $quiet = shift;
163 0 0 0       unless ($quiet or ($bitset && $bitclear && $rtsout && $dtrout) ) {
      0        
      0        
      0        
164 0 0         nocarp or warn "disabling ioctl methods - constants not found\n";
165             }
166              
167 0           my $lockfile = shift;
168 0 0         if ($lockfile) {
169 0           $self->{LOCK} = $lockfile;
170 0           my $lockf = POSIX::open($self->{LOCK},
171             &POSIX::O_WRONLY |
172             &POSIX::O_CREAT |
173             &POSIX::O_NOCTTY |
174             &POSIX::O_EXCL);
175 0 0         unless (defined $lockf) {
176 0 0         unless ($quiet) {
177 0 0         nocarp or carp "can't open lockfile: $self->{LOCK}\n";
178             }
179 0 0         return 0 if ($quiet);
180 0           return;
181             }
182 0           my $pid = "$$\n";
183 0           $ok = POSIX::write($lockf, $pid, length $pid);
184 0           my $ok2 = POSIX::close($lockf);
185 0 0 0       return unless ($ok && (defined $ok2));
186 0           sleep 2; # wild guess for Version 0.05
187             }
188             else {
189 0           $self->{LOCK} = "";
190             }
191              
192 0           $self->{FD}= POSIX::open($self->{NAME},
193             &POSIX::O_RDWR |
194             &POSIX::O_NOCTTY |
195             &POSIX::O_NONBLOCK);
196              
197 0 0         unless (defined $self->{FD}) { $self->{FD} = -1; }
  0            
198 0 0         unless ($self->{FD} >= 1) {
199 0 0         unless ($quiet) {
200 0 0         nocarp or carp "can't open device: $self->{NAME}\n";
201             }
202 0           $self->{FD} = -1;
203 0 0         if ($self->{LOCK}) {
204 0           $ok = unlink $self->{LOCK};
205 0 0 0       unless ($ok or $quiet) {
206 0 0         nocarp or carp "can't remove lockfile: $self->{LOCK}\n";
207             }
208 0           $self->{LOCK} = "";
209             }
210 0 0         return 0 if ($quiet);
211 0           return;
212             }
213              
214 0           $self->{TERMIOS} = POSIX::Termios->new();
215              
216             # a handle object for ioctls: read-only ok
217 0           $self->{HANDLE} = new_from_fd IO::Handle ($self->{FD}, "r");
218            
219             # get the current attributes
220 0           $ok = $self->{TERMIOS}->getattr($self->{FD});
221              
222 0 0         unless ( $ok ) {
223 0           carp "can't getattr";
224 0           undef $self;
225 0           return undef;
226             }
227              
228             # save the original values
229 0           $self->{"_CFLAG"} = $self->{TERMIOS}->getcflag();
230 0           $self->{"_IFLAG"} = $self->{TERMIOS}->getiflag();
231 0           $self->{"_ISPEED"} = $self->{TERMIOS}->getispeed();
232 0           $self->{"_LFLAG"} = $self->{TERMIOS}->getlflag();
233 0           $self->{"_OFLAG"} = $self->{TERMIOS}->getoflag();
234 0           $self->{"_OSPEED"} = $self->{TERMIOS}->getospeed();
235              
236 0           foreach $item (keys %c_cc_fields) {
237 0           $self->{"_$item"} = $self->{TERMIOS}->getcc($c_cc_fields{$item});
238             }
239              
240             # copy the original values into "current" values
241 0           foreach $item (keys %c_cc_fields) {
242 0           $self->{"C_$item"} = $self->{"_$item"};
243             }
244              
245 0           $self->{"C_CFLAG"} = $self->{"_CFLAG"};
246 0           $self->{"C_IFLAG"} = $self->{"_IFLAG"};
247 0           $self->{"C_ISPEED"} = $self->{"_ISPEED"};
248 0           $self->{"C_LFLAG"} = $self->{"_LFLAG"};
249 0           $self->{"C_OFLAG"} = $self->{"_OFLAG"};
250 0           $self->{"C_OSPEED"} = $self->{"_OSPEED"};
251              
252             # Finally, default to "raw" mode for this package
253 0           $self->{"C_IFLAG"} &= ~(IGNBRK|BRKINT|PARMRK|ISTRIP|INLCR|IGNCR|ICRNL|IXON);
254 0           $self->{"C_OFLAG"} &= ~OPOST;
255 0           $self->{"C_LFLAG"} &= ~(ECHO|ECHONL|ICANON|ISIG|IEXTEN);
256 0           $self->{"C_CFLAG"} &= ~(CSIZE|PARENB);
257 0           $self->{"C_CFLAG"} |= (CS8|CLOCAL);
258 0           &write_settings($self);
259              
260 0           $self->{ALIAS} = $self->{NAME}; # so "\\.\+++" can be changed
261 0           print LOG "Port $self->{NAME} opened by IVRS\n";
262 0           bless ($self, $class);
263 0           return $self;
264             }
265              
266             sub write_settings {
267 0     0 0   my $self = shift;
268 0           my $item;
269              
270             # put current values into Termios structure
271 0           $self->{TERMIOS}->setcflag($self->{"C_CFLAG"});
272 0           $self->{TERMIOS}->setiflag($self->{"C_IFLAG"});
273 0           $self->{TERMIOS}->setispeed($self->{"C_ISPEED"});
274 0           $self->{TERMIOS}->setlflag($self->{"C_LFLAG"});
275 0           $self->{TERMIOS}->setoflag($self->{"C_OFLAG"});
276 0           $self->{TERMIOS}->setospeed($self->{"C_OSPEED"});
277              
278 0           foreach $item (keys %c_cc_fields) {
279 0           $self->{TERMIOS}->setcc($c_cc_fields{$item}, $self->{"C_$item"});
280             }
281              
282 0           $self->{TERMIOS}->setattr($self->{FD}, &POSIX::TCSANOW);
283              
284 0 0         if ($Babble) {
285             # print "writing settings to $self->{ALIAS}\n";
286             }
287 0           1;
288             }
289              
290             sub readport {
291 0 0   0 0   return undef unless (@_ == 2);
292 0           my $self = shift;
293 0           my $wanted = shift;
294 0           my $result = "";
295 0           my $ok = 0;
296 0 0         return unless ($wanted > 0);
297              
298 0           my $done = 0;
299 0           my $count_in = 0;
300 0           my $string_in = "";
301 0           my $in2 = "";
302 0           my $bufsize = 255; # VMIN max (declared as char)
303              
304 0           while ($done < $wanted) {
305 0           my $size = $wanted - $done;
306 0 0         if ($size > $bufsize) { $size = $bufsize; }
  0            
307 0           ($count_in, $string_in) = $self->read_vmin($size);
308 0 0         if ($count_in) {
    0          
309 0           $in2 .= $string_in;
310 0           $done += $count_in;
311             }
312             elsif ($done) {
313 0           last;
314             }
315             else {
316 0 0         return if (!defined $count_in);
317 0           last;
318             }
319             }
320 0           return ($done, $in2);
321             }
322              
323             sub read_vmin {
324 0 0   0 0   return undef unless (@_ == 2);
325 0           my $self = shift;
326 0           my $wanted = shift;
327 0           my $result = "";
328 0           my $ok = 0;
329 0 0         return unless ($wanted > 0);
330              
331 0 0         if ($self->{"C_VMIN"} != $wanted) {
332 0           $self->{"C_VMIN"} = $wanted;
333 0           write_settings($self);
334             }
335 0           my $rin = "";
336 0           vec($rin, $self->{FD}, 1) = 1;
337 0           my $ein = $rin;
338 0           my $tin = $self->{RCONST} + ($wanted * $self->{RTOT});
339 0           my $rout;
340             my $wout;
341 0           my $eout;
342 0           my $tout;
343 0           my $ready = select($rout=$rin, $wout=undef, $eout=$ein, $tout=$tin);
344              
345 0           my $got = POSIX::read ($self->{FD}, $result, $wanted);
346              
347 0 0         unless (defined $got) {
348             ## $got = -1; ## DEBUG
349 0 0         return (0,"") if (&POSIX::EAGAIN == ($ok = POSIX::errno()));
350 0 0 0       return (0,"") if (!$ready and (0 == $ok));
351             # at least Solaris acts like eof() in this case
352 0           carp "Error #$ok in Device::SerialPort::read";
353 0           return;
354             }
355              
356 0 0         print "read_vmin=$got, ready=$ready, result=..$result..\n" if ($Babble);
357 0           return ($got, $result);
358             }
359              
360             sub input {
361 0 0   0 0   return undef unless (@_ == 1);
362 0           my $self = shift;
363 0           my $ok = 0;
364 0           my $result = "";
365 0           my $wanted = 255;
366              
367 0 0 0       if (nocarp && $self->{"_T_INPUT"}) {
368 0           $result = $self->{"_T_INPUT"};
369 0           $self->{"_T_INPUT"} = "";
370 0           return $result;
371             }
372              
373 0 0         if ( $self->{"C_VMIN"} ) {
374 0           $self->{"C_VMIN"} = 0;
375 0           write_settings($self);
376             }
377              
378 0           my $got = POSIX::read ($self->{FD}, $result, $wanted);
379              
380 0 0         unless (defined $got) { $got = -1; }
  0            
381 0 0         if ($got == -1) {
382 0 0         return "" if (&POSIX::EAGAIN == ($ok = POSIX::errno()));
383 0 0         return "" if (0 == $ok); # at least Solaris acts like eof()
384 0           carp "Error #$ok in Device::SerialPort::input"
385             }
386 0           return $result;
387             }
388              
389             sub write {
390 0 0   0 0   return undef unless (@_ == 2);
391 0           my $self = shift;
392 0           my $wbuf = shift;
393 0           my $ok;
394              
395 0 0         return 0 if ($wbuf eq "");
396 0           my $lbuf = length ($wbuf);
397 0           my $written = POSIX::write ($self->{FD}, $wbuf, $lbuf);
398              
399 0           return $written;
400             }
401              
402             sub write_drain {
403 0     0 0   my $self = shift;
404 0 0         return if (@_);
405 0 0         return 1 if (defined POSIX::tcdrain($self->{FD}));
406 0           return;
407             }
408              
409             sub purge_all {
410 0     0 0   my $self = shift;
411 0 0         return if (@_);
412 0 0         return 1 if (defined POSIX::tcflush($self->{FD}, TCIOFLUSH));
413 0           return;
414             }
415              
416             sub dtr_active {
417 0 0   0 0   return unless (@_ == 2);
418 0 0 0       return unless ($bitset && $bitclear && $dtrout);
      0        
419 0           my $self = shift;
420 0           my $onoff = shift;
421             # returns ioctl result
422 0 0         if ($onoff) {
423 0           ioctl($self->{HANDLE}, $bitset, $dtrout);
424             }
425             else {
426 0           ioctl($self->{HANDLE}, $bitclear, $dtrout);
427             }
428             }
429              
430             sub rts_active {
431 0 0   0 0   return unless (@_ == 2);
432 0 0 0       return unless ($bitset && $bitclear && $rtsout);
      0        
433 0           my $self = shift;
434 0           my $onoff = shift;
435             # returns ioctl result
436 0 0         if ($onoff) {
437 0           ioctl($self->{HANDLE}, $bitset, $rtsout);
438             }
439             else {
440 0           ioctl($self->{HANDLE}, $bitclear, $rtsout);
441             }
442             }
443              
444             sub pulse_break_on {
445 0 0   0 0   return unless (@_ == 2);
446 0           my $self = shift;
447 0           my $delay = (shift)/1000;
448 0           my $length = 0;
449 0           my $ok = POSIX::tcsendbreak($self->{FD}, $length);
450 0 0         warn "could not pulse break on" unless ($ok);
451 0           select (undef, undef, undef, $delay);
452 0           return $ok;
453             }
454              
455             sub pulse_rts_on {
456 0 0   0 0   return unless (@_ == 2);
457 0 0 0       return unless ($bitset && $bitclear && $rtsout);
      0        
458 0           my $self = shift;
459 0           my $delay = (shift)/1000;
460 0 0         $self->rts_active(1) or warn "could not pulse rts on";
461             ## print "rts on\n"; ## DEBUG
462 0           select (undef, undef, undef, $delay);
463 0 0         $self->rts_active(0) or warn "could not restore from rts on";
464             ## print "rts_off\n"; ## DEBUG
465 0           select (undef, undef, undef, $delay);
466 0           1;
467             }
468              
469             sub pulse_dtr_on {
470 0 0   0 0   return unless (@_ == 2);
471 0 0 0       return unless ($bitset && $bitclear && $dtrout);
      0        
472 0           my $self = shift;
473 0           my $delay = (shift)/1000;
474 0 0         $self->dtr_active(1) or warn "could not pulse dtr on";
475             ## print "dtr on\n"; ## DEBUG
476 0           select (undef, undef, undef, $delay);
477 0 0         $self->dtr_active(0) or warn "could not restore from dtr on";
478             ## print "dtr_off\n"; ## DEBUG
479 0           select (undef, undef, undef, $delay);
480 0           1;
481             }
482              
483             sub pulse_rts_off {
484 0 0   0 0   return unless (@_ == 2);
485 0 0 0       return unless ($bitset && $bitclear && $rtsout);
      0        
486 0           my $self = shift;
487 0           my $delay = (shift)/1000;
488 0 0         $self->rts_active(0) or warn "could not pulse rts off";
489             ## print "rts off\n"; ## DEBUG
490 0           select (undef, undef, undef, $delay);
491 0 0         $self->rts_active(1) or warn "could not restore from rts off";
492             ## print "rts on\n"; ## DEBUG
493 0           select (undef, undef, undef, $delay);
494 0           1;
495             }
496              
497             sub pulse_dtr_off {
498 0 0   0 0   return unless (@_ == 2);
499 0 0 0       return unless ($bitset && $bitclear && $dtrout);
      0        
500 0           my $self = shift;
501 0           my $delay = (shift)/1000;
502 0 0         $self->dtr_active(0) or warn "could not pulse dtr off";
503             ## print "dtr off\n"; ## DEBUG
504 0           select (undef, undef, undef, $delay);
505 0 0         $self->dtr_active(1) or warn "could not restore from dtr off";
506             ## print "dtr on\n"; ## DEBUG
507 0           select (undef, undef, undef, $delay);
508 0           1;
509             }
510             sub baudrate {
511 0     0 0   my $self = shift;
512 0           my $item = 0;
513              
514 0 0         if (@_) {
515 0 0         if (defined $bauds{$_[0]}) {
516 0           $self->{"C_OSPEED"} = $bauds{$_[0]};
517 0           $self->{"C_ISPEED"} = $bauds{$_[0]};
518 0           write_settings($self);
519             }
520             else {
521 0 0 0       if ($self->{U_MSG} or $Babble) {
522 0           carp "Can't set baudrate on $self->{ALIAS}";
523             }
524 0           return undef;
525             }
526             }
527 0 0         if (wantarray) { return (keys %bauds); }
  0            
528 0           foreach $item (keys %bauds) {
529 0 0         return $item if ($bauds{$item} == $self->{"C_OSPEED"});
530             }
531 0           return undef;
532             }
533             sub parity_enable {
534 0     0 0   my $self = shift;
535 0 0         if (@_) {
536 0 0         if ( yes_true( shift ) ) {
537 0           $self->{"C_IFLAG"} |= PARMRK;
538 0           $self->{"C_CFLAG"} |= PARENB;
539             } else {
540 0           $self->{"C_IFLAG"} &= ~PARMRK;
541 0           $self->{"C_CFLAG"} &= ~PARENB;
542             }
543 0           write_settings($self);
544             }
545 0 0         return wantarray ? @binary_opt : ($self->{"C_CFLAG"} & PARENB);
546             }
547              
548             sub parity {
549 0     0 0   my $self = shift;
550 0 0         if (@_) {
551 0 0         if ( $_[0] eq "none" ) {
    0          
    0          
552 0           $self->{"C_IFLAG"} &= ~INPCK;
553 0           $self->{"C_CFLAG"} &= ~PARENB;
554             }
555             elsif ( $_[0] eq "odd" ) {
556 0           $self->{"C_IFLAG"} |= INPCK;
557 0           $self->{"C_CFLAG"} |= (PARENB|PARODD);
558             }
559             elsif ( $_[0] eq "even" ) {
560 0           $self->{"C_IFLAG"} |= INPCK;
561 0           $self->{"C_CFLAG"} |= PARENB;
562 0           $self->{"C_CFLAG"} &= ~PARODD;
563             }
564             else {
565 0 0 0       if ($self->{U_MSG} or $Babble) {
566 0           carp "Can't set parity on $self->{ALIAS}";
567             }
568 0           return;
569             }
570 0           write_settings($self);
571             }
572 0 0         if (wantarray) { return ("none", "odd", "even"); }
  0            
573 0 0         return "none" unless ($self->{"C_IFLAG"} & INPCK);
574 0           my $mask = (PARENB|PARODD);
575 0 0         return "odd" if ($mask == ($self->{"C_CFLAG"} & $mask));
576 0           $mask = (PARENB);
577 0 0         return "even" if ($mask == ($self->{"C_CFLAG"} & $mask));
578 0           return "none";
579             }
580              
581             sub databits {
582 0     0 0   my $self = shift;
583 0 0         if (@_) {
584 0 0         if ( $_[0] == 8 ) {
    0          
    0          
    0          
585 0           $self->{"C_CFLAG"} &= ~CSIZE;
586 0           $self->{"C_CFLAG"} |= CS8;
587             }
588             elsif ( $_[0] == 7 ) {
589 0           $self->{"C_CFLAG"} &= ~CSIZE;
590 0           $self->{"C_CFLAG"} |= CS7;
591             }
592             elsif ( $_[0] == 6 ) {
593 0           $self->{"C_CFLAG"} &= ~CSIZE;
594 0           $self->{"C_CFLAG"} |= CS6;
595             }
596             elsif ( $_[0] == 5 ) {
597 0           $self->{"C_CFLAG"} &= ~CSIZE;
598 0           $self->{"C_CFLAG"} |= CS5;
599             }
600             else {
601 0 0 0       if ($self->{U_MSG} or $Babble) {
602 0           carp "Can't set databits on $self->{ALIAS}";
603             }
604 0           return;
605             }
606 0           write_settings($self);
607             }
608 0 0         if (wantarray) { return (5, 6, 7, 8); }
  0            
609 0           my $mask = ($self->{"C_CFLAG"} & CSIZE);
610 0 0         return 8 if ($mask == CS8);
611 0 0         return 7 if ($mask == CS7);
612 0 0         return 6 if ($mask == CS6);
613 0           return 5;
614             }
615              
616             sub stopbits {
617 0     0 0   my $self = shift;
618 0 0         if (@_) {
619 0 0         if ( $_[0] == 2 ) {
    0          
620 0           $self->{"C_CFLAG"} |= CSTOPB;
621             }
622             elsif ( $_[0] == 1 ) {
623 0           $self->{"C_CFLAG"} &= ~CSTOPB;
624             }
625             else {
626 0 0 0       if ($self->{U_MSG} or $Babble) {
627 0           carp "Can't set stopbits on $self->{ALIAS}";
628             }
629 0           return;
630             }
631 0           write_settings($self);
632             }
633 0 0         if (wantarray) { return (1, 2); }
  0            
634 0 0         return 2 if ($self->{"C_CFLAG"} & CSTOPB);
635 0           return 1;
636             }
637            
638             sub handshake {
639 0     0 0   my $self = shift;
640            
641 0 0         if (@_) {
642 0 0         if ( $_[0] eq "none" ) {
    0          
    0          
643 0           $self->{"C_IFLAG"} &= ~(IXON | IXOFF);
644 0           $self->{"C_CFLAG"} &= ~CRTSCTS;
645             }
646             elsif ( $_[0] eq "xoff" ) {
647 0           $self->{"C_IFLAG"} |= (IXON | IXOFF);
648 0           $self->{"C_CFLAG"} &= ~CRTSCTS;
649             }
650             elsif ( $_[0] eq "rts" ) {
651 0           $self->{"C_IFLAG"} &= ~(IXON | IXOFF);
652 0           $self->{"C_CFLAG"} |= CRTSCTS;
653             }
654             else {
655 0 0 0       if ($self->{U_MSG} or $Babble) {
656 0           carp "Can't set handshake on $self->{ALIAS}";
657             }
658 0           return;
659             }
660 0           write_settings($self);
661             }
662 0 0         if (wantarray) { return ("none", "xoff", "rts"); }
  0            
663 0           my $mask = (IXON|IXOFF);
664 0 0         return "xoff" if ($mask == ($self->{"C_IFLAG"} & $mask));
665 0 0         return "rts" if ($self->{"C_CFLAG"} & CRTSCTS);
666 0           return "none";
667             }
668              
669             sub buffers {
670 0     0 0   my $self = shift;
671 0 0         if (@_) { return unless (@_ == 2); }
  0 0          
672 0 0         return wantarray ? (4096, 4096) : 1;
673             }
674              
675             sub pclose {
676 0     0 0   my $self = shift;
677 0           my $ok = undef;
678 0           my $item;
679              
680 0 0         return unless (defined $self->{NAME});
681              
682 0 0         if ($Babble) {
683 0           carp "Closing $self " . $self->{ALIAS};
684             }
685 0 0         if ($self->{FD}) {
686 0           purge_all ($self);
687              
688             # copy the original values into "current" values
689 0           foreach $item (keys %c_cc_fields) {
690 0           $self->{"C_$item"} = $self->{"_$item"};
691             }
692              
693 0           $self->{"C_CFLAG"} = $self->{"_CFLAG"};
694 0           $self->{"C_IFLAG"} = $self->{"_IFLAG"};
695 0           $self->{"C_ISPEED"} = $self->{"_ISPEED"};
696 0           $self->{"C_LFLAG"} = $self->{"_LFLAG"};
697 0           $self->{"C_OFLAG"} = $self->{"_OFLAG"};
698 0           $self->{"C_OSPEED"} = $self->{"_OSPEED"};
699            
700 0           write_settings($self);
701              
702 0           $ok = POSIX::close($self->{FD});
703             # also closes $self->{HANDLE}
704              
705 0           $self->{FD} = undef;
706             }
707 0 0         if ($self->{LOCK}) {
708 0 0         unless ( unlink $self->{LOCK} ) {
709 0 0         nocarp or carp "can't remove lockfile: $self->{LOCK}\n";
710             }
711 0           $self->{LOCK} = "";
712             }
713 0           $self->{NAME} = undef;
714 0           $self->{ALIAS} = undef;
715 0           close (LOG);
716 0 0         return unless ($ok);
717             # exit 0;
718             }
719              
720             #My routines starts from here, Not a very tight code, but it works!!
721             #
722             #---------------------------------------------------------------------#
723             sub initmodem {
724 0     0 0   my $self=shift;
725 0 0         $self->pulse_dtr_on(500)||return undef;
726 0 0         $self->pulse_dtr_off(500)||return undef;
727 0 0         $self->atcomm("ATZ","OK") ||return undef;
728 0 0         $self->atcomm("AT&C1&D2&K3M2L3","OK")||return undef;
729 0 0         $self->atcomm("AT#CLS=8","OK")||return undef;
730             #These are some of the Rockwell specific commands, enable them if your
731             #Modem does not work.
732             # $self->atcomm("AT","OK")||return undef;
733             # $self->atcomm("AT#VBS=4","OK")||return undef;
734             # $self->atcomm("AT#VSP=2","OK")||return undef;
735             # $self->atcomm("AT#VTD=3F,3F,3F","OK")||return undef;
736             # $self->atcomm("AT#VSR=7200","OK")||return undef;
737             # $self->atcomm("AT#VSD=1","OK")||return undef;
738             # $self->atcomm("AT#BDR=0","OK")||return undef;
739              
740             #These are some of the USRobotic specific commands, enable them if your
741             #Modem does not work.
742             # $self->atcomm("AT#VTM=0","OK")||return undef;
743             # $self->atcomm("AT#VSR=8000","OK")||return undef;
744             # $self->atcomm("AT#VGT=255","OK")||return undef;
745              
746             #Do not comment out these!!
747 0 0         $self->atcomm("AT#VLS=2","VCON")||return undef;
748 0 0         $self->atcomm("ATL3","OK")||return undef;
749 0           unlink("$tmpmsg");
750 0           print LOG "Port Configured for Voice \n";
751             }
752              
753             sub setport {
754 0     0 0   my $self=shift;
755 0           my $baud=shift;
756 0           my $parity=shift;
757 0           my $data=shift;
758 0           my $stop=shift;
759 0           my $hand=shift;
760 0           my $buff=shift;
761 0 0         $self->baudrate($baud)||return undef;
762 0 0         $self->parity($parity)||return undef;
763 0 0         $self->databits($data)||return undef;
764 0 0         $self->stopbits($stop)||return undef;
765 0 0         $self->handshake($hand)||return undef;
766             #$self->buffers($buff,$buff)||return undef;
767 0 0         $self->buffers(0,0)||return undef;
768 0           $self->write_settings;
769 0           print LOG "Port Configuration changed\n";
770 0           return 1;
771             }
772            
773             sub waitring {
774 0     0 0   my $self=shift;
775 0           my $callid="";
776 0           print LOG "Waiting for ring from ",`date`;
777 0 0         $self->atcomm("AT#VLS=0","OK")||return undef;
778 0 0         $self->atcomm("AT#CLS=8","OK")||return undef;
779 0           while (!($self->input=~/[RING]/)){sleep 1;}
  0            
780 0           $callid=$self->input;
781 0 0         $self->atcomm("ATA","")||return undef;
782 0 0         $self->atcomm("AT#VLS=2","VCON")||return undef;
783 0 0         $self->atcomm("AT#VTX","CONNECT")||return undef;
784 0           print LOG "Call from <$callid> received at ",`date`;
785 0           return $callid;
786             }
787              
788             sub dialout
789             {
790             #This is experimental only. Most of the modem fail to detect ring back,
791             #and pick up, even before the receiver is lifted by called number.
792 0     0 0   my $self=shift;
793 0           my $telno = shift;
794 0           my $ddelay=shift;
795 0           my $cstring ="ATX1DT".$telno;
796 0           $self->atcomm("ATZ","OK");
797             # $self->atcomm("AT#VRA=45","OK");
798             # $self->atcomm("AT#VRN=250","OK");
799 0           $self->atcomm("AT#VLS=0","OK");
800 0           $self->atcomm("AT#CLS=8","OK");
801 0           $self->atcomm("AT","OK");
802 0           $self->atcomm($cstring,"VCON",$ddelay);
803 0           sleep 5;
804             # $self->atcomm("AT#VLS=2","OK")||return undef;
805 0 0         $self->atcomm("AT#VTX","CONNECT")||return undef;
806 0 0         print LOG "Dialing $telno \n" if $Babble;
807              
808             }
809              
810             sub callxfer
811             {
812              
813             #This is experimental only. Most of the modem fail to detect ring back,
814             #and pick up, even before the receiver is lifted by called number.
815              
816 0     0 0   my $self=shift;
817 0           my $telno = shift;
818 0           $self->atcomm("\020\003\020\003","VCON");
819 0           my $cstring ="ATX1DT".$telno;
820 0           $self->atcomm("AT#VLS=0","OK");
821 0           $self->atcomm("AT#CLS=8","OK");
822 0           $self->atcomm("ATDP1","");
823 0           $self->atcomm($cstring,"OK","20");
824 0 0         $self->atcomm("ATH","OK")||return undef;
825 0 0         print LOG "Transfered to $telno \n" if $Babble;
826             }
827              
828             sub atcomm {
829 0     0 0   my $self=shift;
830 0           my $atstr=shift;
831 0           my $waitfor=shift;
832 0           my $dialdelay=shift;
833 0           my $oltime=time;
834 0           my $mdtime=5;
835 0 0         $mdtime=$dialdelay if ($dialdelay);
836 0           my $getstr="";
837             #$atstr=$atstr."AT\r";
838 0           $self->write("$atstr\r");
839 0           while (!($getstr=~/$waitfor/)) {
840 0           $getstr=$getstr.$self->input;
841 0 0 0       if (((time - $oltime)>$mdtime)||($getstr=~/[b]/)) {
842 0           print LOG "Modem failed to reply <$atstr> \n";
843             #$self->pclose ;
844 0           return undef;
845             }
846             }
847             #return $getstr;
848 0 0         print LOG "Modem->$getstr" if $Babble;
849 0           return 1;
850             }
851              
852             sub faxmode {
853 0     0 0   my $self=shift;
854 0           $self->atcomm("\020\003\020\003","VCON");
855 0           $self->atcomm("AT#BDR=0","OK");
856 0           $self->atcomm("AT#CLS=0","OK");
857 0           $self->atcomm("AT+FCLASS=1","OK");
858 0 0         print LOG "Fax mode set \n" if $Babble;
859             }
860              
861             sub playfile {
862 0     0 0   my $self=shift;
863 0           my $pfile=shift;
864 0           my $playfile="";
865 0 0         $pfile="" if !($pfile);
866 0           $playfile=$pfile;
867 0 0         $playfile="$vdir/$pfile" if (substr($pfile,0,1) ne "/");
868 0 0         $playfile=$tmpmsg if ($pfile eq "");
869 0 0         if (!(-e $playfile)) {
870 0           print LOG "play->File $playfile not found\n";
871 0           return undef;
872             }
873 0 0         print LOG "play->The play file is $playfile \n" if $Babble;
874 0           my $ndtmf=shift;
875 0 0         $ndtmf=0 if !($ndtmf);
876 0           my $rdtmf="";
877 0           my $dtmf="";
878 0           my $tmp;
879 0           my $dtcount =0;
880 0           open (FH1,$playfile);
881 0           $self->write($rmdhdr);
882 0           $self->write_drain;
883 0           while (!eof(FH1)) {
884 0           read FH1,$tmp,1000;
885 0           $self->write($tmp);
886 0           $self->write_drain;
887 0           $dtmf=$self->input;
888 0 0 0       last if ($dtmf=~/[0-9]/) && ($ndtmf !=0);
889 0 0         if ($dtmf=~/[b]/) {
890 0           print LOG "Call->User hanged up before call was finished\n";
891 0           return undef;
892             }
893             }
894 0 0         unlink("$tmpmsg") if $playfile eq "$tmpmsg";
895 0 0         if ($ndtmf == 0) {
896 0 0         $self->atcomm("\020\030\020\003","VCON") ||return undef;
897 0 0         $self->atcomm("AT#VTX","CONNECT")||return undef;
898 0           return 1;
899             }
900 0 0         if ($ndtmf==1) {
901 0 0         $self->atcomm("\020\030\020\003","VCON") ||return undef;
902 0 0         $self->atcomm("AT#VTX","CONNECT")||return undef;
903 0 0         return join('', split(/\W/,$dtmf)) if $dtmf;
904 0           return " ";
905             }
906 0           $rdtmf=$dtmf;
907 0 0         $self->atcomm("\020\030\020\003","VCON") ||return undef;
908 0 0         $self->atcomm("AT#VTX","CONNECT")||return undef;
909 0           open (FH1,"$vdir/tsil15");
910 0           while (!eof(FH1)) {
911 0           read FH1,$tmp,1000;
912 0           $self->write($tmp);
913 0           $self->write_drain;
914 0           $dtmf=$self->input;
915 0 0         $rdtmf=$rdtmf.$dtmf if ($dtmf=~/[0-9]/);
916 0 0         if ($dtmf=~/[b]/) {
917 0           print LOG "Call->User hanged up before call was finished\n";
918 0           return undef;
919             }
920 0 0 0       last if (length($rdtmf)==$ndtmf*2) or ($dtmf=~/[#\*]/);
921             }
922 0 0         $self->atcomm("\020\030\020\003","VCON") ||return undef;
923 0 0         $self->atcomm("AT#VTX","CONNECT")||return undef;
924 0 0         return " " if !($rdtmf=~/[0-9]/);
925 0           return join('', split(/\W/, $rdtmf));
926             }
927              
928             sub recfile {
929 0     0 0   my $self=shift;
930 0           my $recfile = shift;
931 0           my $ttime=shift;
932 0           $self->atcomm("\020\003\020\003","VCON");
933 0 0         $self->atcomm("AT#VRX","CONNECT")||return undef;
934 0           open (FH1,">$recfile");
935 0           print FH1 $rmdhdr;
936 0           my $otimer=time;
937 0           while ((time-$otimer)<$ttime) {
938 0           print FH1 $self->input;
939             }
940 0           close FH1;
941 0 0         if ($self->input=~/[b]/) {
942 0           print LOG "Call->User hanged up before call was finished\n";
943 0           return undef;
944             }
945 0           print LOG "Message file $recfile recorded\n";
946 0 0         $self->atcomm("\020\030\020\003","VCON")||return undef;
947 0 0         $self->atcomm("AT#VTX","CONNECT")||return undef;
948 0           return 1;
949             }
950              
951             sub addmsg {
952 0     0 0   my $self=shift;
953 0           my $playfile=shift;
954 0           my $self1=shift;
955 0           my $tmp="";
956 0           open (FHO, ">>$tmpmsg");
957 0           open (FHI, "<$vdir/$playfile");
958 0           while (!eof(FHI)) {
959 0           read FHI,$tmp,1000;
960 0           print FHO $tmp;
961             }
962 0           close (FHI);
963 0           close (FHO);
964 0 0         print LOG "Msg->$playfile added\n" if $Babble;
965             }
966              
967             sub addval {
968 0     0 0   my $self=shift;
969 0           my $num1=shift;
970 0           my $num2;
971             my $num3;
972 0           $num1="0".$num1 while (length($num1) ne 9);
973 0           $num2=substr($num1,0,2);
974 0           $self->addint1($num2,"crore");
975 0           $num2=substr($num1,2,2);
976 0           $self->addint1($num2,"lack");
977 0           $num2=substr($num1,4,2);
978 0           $self->addint1($num2,"thousand");
979 0           $num2=substr($num1,6,1);
980 0 0         $self->addmsg($num2) if ($num2 != 0);
981 0 0         $self->addmsg("hundred") if ($num2 != 0);
982 0           $num2=substr($num1,7,2);
983 0           $self->addint1($num2,"sil0");
984 0           return ;
985             }
986              
987             sub addint1 {
988 0     0 0   my $self=shift;
989 0           my $num2=shift;
990 0           my $unit=shift;
991 0           my $num3;
992 0 0 0       if (($num2<21)&&($num2>0)) {
993 0           $num2=int($num2);
994 0           $self->addmsg($num2);
995             }
996 0 0         if ($num2>20) {
997 0           $num3=10*substr($num2,0,1);
998 0           $self->addmsg($num3);
999 0           $num3=substr($num2,1,1);
1000 0 0         $self->addmsg($num3) if ($num3 !=0);
1001             }
1002 0 0         $self->addmsg($unit) if ($num2 != 0);
1003 0           return;
1004             }
1005              
1006             sub addmil {
1007 0     0 0   my $self=shift;
1008 0           my $num1=shift;
1009 0           my $num2;
1010             my $num3;
1011 0           $num1="0".$num1 while (length($num1) ne 9);
1012 0           $num2=substr($num1,0,3);
1013 0           $self->addint2($num2,"crore");
1014 0           $num2=substr($num1,3,3);
1015 0           $self->addint2($num2,"thousand");
1016 0           $num2=substr($num1,6,3);
1017 0           $self->addint2($num2,"sil0");
1018 0           return ;
1019             }
1020              
1021             sub addint2 {
1022 0     0 0   my $self=shift;
1023 0           my $num2=shift;
1024 0           my $unit=shift;
1025 0           my $num3=0;
1026 0           $num3=substr($num2,0,1);
1027 0 0         $self->addmsg($num3) if ($num3 != 0);
1028 0 0         $self->addmsg("hundred") if ($num3 != 0);
1029 0           $num2=substr($num2,1,2);
1030 0 0 0       if (($num2<21)&&($num2>0)) {
1031 0           $num2=int($num2);
1032 0           $self->addmsg($num2);
1033             }
1034 0 0         if ($num2>20) {
1035 0           $num3=10*substr($num2,0,1);
1036 0           $self->addmsg($num3);
1037 0           $num3=substr($num2,1,1);
1038 0 0         $self->addmsg($num3) if ($num3 !=0);
1039             }
1040 0 0         $self->addmsg($unit) if ($num2 != 0);
1041 0           return;
1042             }
1043              
1044             sub addtxt {
1045 0     0 0   my $self = shift;
1046 0           my $pstr = shift;
1047 0           my $i=0;
1048 0           my $pchr="";
1049 0           while ($i!=length($pstr)) {
1050 0           $pchr=lc(substr($pstr,$i,1));
1051 0           $self->addmsg($pchr);
1052 0           $i++;
1053             }
1054             }
1055              
1056             sub addate {
1057 0     0 0   my $self=shift;
1058 0           my $num1=shift;
1059 0           my $num2="";
1060 0           $num2=substr($num1,0,2);
1061 0           $self->addval($num2);
1062 0           $num2=substr($num1,2,2);
1063             #$num2=abs($num2);
1064 0           $num2="m$num2";
1065 0           $self->addmsg($num2);
1066 0           $num2=substr($num1,4,4);
1067             #$num2=substr($num1,2,2) if (substr($num1,0,2) eq 19);
1068 0           $self->addval($num2);
1069 0           return;
1070             }
1071              
1072              
1073             sub closep {
1074 0     0 0   my $self=shift;
1075 0           unlink ("$tmpmsg");
1076 0           unlink ("$tmpmsg.1");
1077 0           unlink ("$tmpmsg.2");
1078 0           $self->atcomm("\020\030\020\003","VCON");
1079 0           $self->atcomm("ATH","OK");
1080 0           $self->atcomm("ATZ","OK");
1081 0           $self->pclose
1082             }
1083              
1084              
1085             1;
1086             __END__