2
* Worldvisions Weaver Software:
3
* Copyright (C) 1997-2002 Net Integration Technologies, Inc.
5
* Implementation of the WvDialer smart-dialer class.
12
#include <sys/types.h>
24
static char * init_responses[] = {
30
static char * dial_responses[] = {
44
static char * prompt_strings[] = {
50
static int messagetail_pid = 0;
52
//**************************************************
53
// WvDialer Public Functions
54
//**************************************************
56
WvDialer::WvDialer( WvConf &_cfg, WvStringList *_sect_list, bool _chat_mode )
57
/***************************************************************************/
58
: WvStreamClone( (WvStream **)&modem ),
59
cfg(_cfg), log( "WvDial", WvLog::Debug ),
60
err( log.split( WvLog::Error ) ),
61
modemrx( "WvDial Modem", WvLog::Debug )
70
last_rx = last_execute = 0;
72
auto_reconnect_delay = 0;
73
auto_reconnect_at = 0;
77
// tell wvstreams we need our own subtask
78
uses_continue_select = true;
80
sect_list = _sect_list;
81
chat_mode = _chat_mode;
83
log( "WvDial: Internet dialer version " WVDIAL_VER_STRING "\n" );
85
// Ensure all sections in sect_list actually exist, warning if not.
86
WvStringList::Iter iter( *sect_list );
87
for( iter.rewind(); iter.next(); ) {
88
if( cfg[iter] == NULL ) {
90
"Warning: section [%s] does not exist in wvdial.conf.\n",
95
// Ensure all inherited sections exist, warning if not.
96
WvConfigSectionList::Iter iter2 (cfg);
97
for (iter2.rewind(); iter2.next();) {
98
WvConfigSection & sect2 = iter2;
99
WvConfigEntry * entry = sect2["Inherits"];
101
WvString inherits = entry->value;
102
if (cfg[inherits] == NULL)
104
"Warning: inherited section [%s] does not exist in wvdial.conf\n",
109
// Activate the brain and read configuration.
110
brain = new WvDialBrain( this );
112
// init_modem() reads the config options. It MUST run here!
116
// init_modem() printed an error
121
if (options.provider.len()) {
122
log( WvLog::Notice, "Dialing %s %s.\n",
126
if (options.homepage.len()) {
127
log( WvLog::Notice, "Homepage of %s: %s\n",
128
options.provider.len() ? (const char *)options.provider : "this provider",
132
if( options.auto_reconnect && options.idle_seconds > 0) {
134
"Idle Seconds = %s, disabling automatic reconnect.\n",
135
WvString(options.idle_seconds));
136
options.auto_reconnect = false;
139
pppd_mon.setdnstests (options.dnstest1, options.dnstest2);
140
pppd_mon.setcheckdns (options.check_dns);
141
pppd_mon.setcheckdfr (options.check_dfr);
144
WvDialer::~WvDialer()
145
/*******************/
157
bool WvDialer::dial()
158
/*******************/
159
// Returns false on error, or true to go asynchronous while dialing.
165
// (error message has already been printed elsewhere)
166
// err( "Modem is not ready to dial.\n" );
170
if( !options.phnum[0] ) {
171
err( "Configuration does not specify a valid phone number.\n" );
175
if( !options.login[0] ) {
176
err( "Configuration does not specify a valid login name.\n" );
180
if( !options.password[0] ) {
181
err( "Configuration does not specify a valid password.\n" );
189
if( options.phnum1.len() )
192
if( options.phnum2.len() )
195
if( options.phnum3.len() )
198
if( options.phnum4.len() )
206
// we need to re-init the modem if we were online before.
207
if( been_online && !init_modem() )
212
connect_attempts = 1;
220
void WvDialer::hangup()
221
/*********************/
235
log( "Disconnecting at %s", ctime( &now ) );
245
if (messagetail_pid > 0)
247
kill(messagetail_pid, 15);
252
bool WvDialer::pre_select( SelectInfo& si )
253
/*******************************************/
255
if( isok() && stat != Online && stat != Idle
256
&& time( NULL ) - last_execute > 1 )
258
// Pretend we have "data ready," so execute() gets called.
259
// select() already returns true whenever the modem is readable,
260
// but when we are doing a timeout (eg. PreDial1/2) for example,
261
// we need to execute() even if no modem data is incoming.
264
return WvStreamClone::pre_select( si );
268
bool WvDialer::isok() const
269
/*************************/
271
bool b = ( !modem || modem->isok() )
272
&& stat != ModemError && stat != OtherError;
275
err("Returning not ok!!\n" );
280
char * WvDialer::connect_status() const
281
/*************************************/
283
static char msg[ 160 ];
291
strcpy( msg, "Last attempt timed out. Trying again." );
292
else if( dial_stat == 2 )
293
strcpy( msg, "Modem did not connect last attempt. Trying again." );
294
else if( dial_stat == 3 )
295
strcpy( msg, "No dial tone last attempt. Trying again." );
296
else if( dial_stat == 4 )
297
strcpy( msg, "Busy signal on last attempt. Trying again." );
298
else if( dial_stat == 5 )
299
strcpy( msg, "Voice answer on last attempt. Trying again." );
300
else if( dial_stat == 6 )
301
strcpy( msg, "Fax answer on last attempt. Trying again." );
302
else if( dial_stat == 7 )
303
strcpy( msg, "No answer on last attempt. Trying again." );
308
strcpy( msg, "Waiting for a response from Internet Provider." );
311
strcpy( msg, "Waiting for a prompt from Internet Provider." );
313
case AutoReconnectDelay:
314
sprintf( msg, "Next attempt in 00:%02ld:%02ld.",
315
( auto_reconnect_at - time( NULL ) ) / 60,
316
( auto_reconnect_at - time( NULL ) ) % 60 );
325
void WvDialer::pppd_watch( int ms )
326
/*********************************/
328
// see if pppd has a message, analyse it and output to log
330
if( pppd_log != NULL && pppd_log->isok() )
335
while ( (line = pppd_log->getline( ms )) );
337
WvString buffer1(pppd_mon.analyse_line( line ));
340
log("pppd: %s\n",buffer1);
347
void WvDialer::execute()
348
/**********************/
350
WvStreamClone::execute();
352
// the modem object might not exist, if we just disconnected and are
354
if( !modem && !init_modem() )
357
last_execute = time( NULL );
370
// we allow some time after connection for silly servers/modems.
371
if( modem->select( 500 ) ) {
372
// if any data comes in at all, switch to impatient mode.
374
last_rx = time( NULL );
375
} else if( time( NULL ) - last_rx >= 30 ) {
376
// timed out - do what WaitPrompt would do on a timeout.
379
// We prod the server with a CR character every once in a while.
380
// FIXME: Does this cause problems with login prompts?
381
modem->write( "\r", 1 );
388
assert( !chat_mode );
389
// If already online, we only need to make sure pppd is still there.
390
if( ppp_pipe && ppp_pipe->child_exited() ) {
391
int pppd_exit_status = ppp_pipe->exit_status();
392
if( ppp_pipe->child_killed() ) {
393
log( WvLog::Error, "PPP was killed! (signal = %s)\n",
394
ppp_pipe->exit_status() );
397
// we must delete the WvModem object so it can be recreated
398
// later; starting pppd seems to screw up the file descriptor.
403
time_t call_duration = time( NULL ) - connected_at;
405
if( pppd_mon.auth_failed() ) {
406
log("Authentication error.\n"
407
"We failed to authenticate ourselves to the peer.\n"
408
"Maybe bad account or password?\n" );
411
switch (pppd_exit_status) {
412
case 2: msg = "pppd options error"; break;
413
case 3: msg = "No root priv error"; break;
414
case 4: msg = "No ppp module error"; break;
415
case 10: msg = "PPP negotiation failed"; break;
416
case 11: msg = "Peer didn't authenticatie itself"; break;
417
case 12: msg = "Link idle: Idle Seconds reached."; break;
418
case 13: msg = "Connect time limit reached."; break;
419
case 14: msg = "Callback negotiated, call should come back.";
420
case 15: msg = "Lack of LCP echo responses"; break;
421
case 17: msg = "Loopback detected"; break;
422
case 19: msg = "Authentication error.\n"
423
"We failed to authenticate ourselves to the peer.\n"
424
"Maybe bad account or password?";
427
// Note: exit code = %s is parsed by kinternet:
428
log("The PPP daemon has died: %s (exit code = %s)\n",
429
msg, pppd_exit_status);
430
log("man pppd explains pppd error codes in more detail.\n");
431
err(WvLog::Notice, "I guess that's it for now, exiting\n");
432
if (pppd_exit_status == 12 && options.auto_reconnect)
433
err(WvLog::Notice, "Idle parameter is passed to pppd\n"
434
"If you don't want an idle timeout per default,\n"
435
"comment out the idle parameter in /etc/ppp/options\n");
436
if (pppd_exit_status == 15) {
437
log("Provider is overloaded(often the case) or line problem.\n");
439
options.auto_reconnect = false;
442
switch (pppd_exit_status) {
443
case 1: msg = "Fatal pppd error"; break;
444
case 5: msg = "pppd received a signal"; break;
445
case 6: msg = "Serial port lock failed"; break;
446
case 7: msg = "Serial port open failed"; break;
447
case 8: msg = "Connect script failed"; break;
448
case 9: msg = "Pty program error"; break;
449
case 16: msg = "A modem hung up the phone"; break;
450
case 18: msg = "The init script failed"; break;
453
log("The PPP daemon has died: %s (exit code = %s)\n",
454
msg, pppd_exit_status);
455
log("man pppd explains pppd error codes in more detail.\n");
456
log(WvLog::Notice, "Try again and look into /var/log/messages "
457
"and the wvdial and pppd man pages for more information.\n");
459
log(WvLog::Notice, "The PPP daemon has died. (exit code = %s)\n",
463
// check to see if we're supposed to redial automatically soon.
464
if( options.auto_reconnect && isok() ) {
465
if( call_duration >= 45 )
466
// Connection was more than 45 seconds, so reset the
467
// "exponential backup timer".
468
auto_reconnect_delay = 0;
470
// exponentially back up...
471
auto_reconnect_delay *= 2;
472
if( auto_reconnect_delay == 0 )
473
auto_reconnect_delay = 5; // start at 5 seconds
474
if( auto_reconnect_delay > 600 )
475
auto_reconnect_delay = 600; // no longer than 10 minutes
477
auto_reconnect_at = time( NULL ) + auto_reconnect_delay;
479
stat = AutoReconnectDelay;
480
log( WvLog::Notice, "Auto Reconnect will be attempted in %s "
482
auto_reconnect_at - time( NULL ) );
486
case AutoReconnectDelay:
487
// If enough time has passed after ISP disconnected us that we should
489
// We can only get into this state if the Auto Reconnect option is
490
// enabled, so there's no point in checking the option here.
491
if( time( NULL ) >= auto_reconnect_at ) {
506
//**************************************************
507
// WvDialer Private Functions
508
//**************************************************
510
void WvDialer::load_options()
511
/***************************/
515
{ "Modem", &options.modem, NULL, "/dev/modem", 0 },
516
{ "Init1", &options.init1, NULL, "ATZ", 0 },
517
{ "Init2", &options.init2, NULL, "", 0 },
518
{ "Init3", &options.init3, NULL, "", 0 },
519
{ "Init4", &options.init4, NULL, "", 0 },
520
{ "Init5", &options.init5, NULL, "", 0 },
521
{ "Init6", &options.init6, NULL, "", 0 },
522
{ "Init7", &options.init7, NULL, "", 0 },
523
{ "Init8", &options.init8, NULL, "", 0 },
524
{ "Init9", &options.init9, NULL, "", 0 },
525
{ "Phone", &options.phnum, NULL, "", 0 },
526
{ "Phone1", &options.phnum1, NULL, "", 0 },
527
{ "Phone2", &options.phnum2, NULL, "", 0 },
528
{ "Phone3", &options.phnum3, NULL, "", 0 },
529
{ "Phone4", &options.phnum4, NULL, "", 0 },
530
{ "Dial Prefix", &options.dial_prefix, NULL, "", 0 },
531
{ "Area Code", &options.areacode, NULL, "", 0 },
532
{ "Dial Command", &options.dial_cmd, NULL, "ATDT", 0 },
533
{ "Username", &options.login, NULL, "", 0 },
534
{ "Login Prompt", &options.login_prompt, NULL, "", 0 },
535
{ "Password", &options.password, NULL, "", 0 },
536
{ "Password Prompt", &options.pass_prompt, NULL, "", 0 },
537
{ "PPPD Path", &options.where_pppd, NULL, "/usr/sbin/pppd", 0 },
538
{ "PPPD Option", &options.pppd_option, NULL, "", 0 },
539
{ "Force Address", &options.force_addr, NULL, "", 0 },
540
{ "Remote Name", &options.remote, NULL, "*", 0 },
541
{ "Default Reply", &options.default_reply,NULL, "ppp", 0 },
542
{ "Country", &options.country, NULL, "", 0 },
543
{ "Provider", &options.provider, NULL, "", 0 },
544
{ "Product", &options.product, NULL, "", 0 },
545
{ "Homepage", &options.homepage, NULL, "", 0 },
546
{ "DialMessage1", &options.dialmessage1, NULL, "", 0 },
547
{ "DialMessage2", &options.dialmessage2, NULL, "", 0 },
548
{ "DNS Test1", &options.dnstest1, NULL, "www.suse.de", 0 },
549
{ "DNS Test2", &options.dnstest2, NULL, "www.suse.com", 0 },
552
{ "Baud", NULL, &options.baud, "", DEFAULT_BAUD },
553
{ "Carrier Check", NULL, &options.carrier_check, "", true },
554
{ "Stupid Mode", NULL, &options.stupid_mode, "", false },
555
{ "New PPPD", NULL, &options.new_pppd, "", true },
556
{ "Auto Reconnect", NULL, &options.auto_reconnect,"", true },
557
{ "Dial Attempts", NULL, &options.dial_attempts, "", 0 },
558
{ "Abort on Busy", NULL, &options.abort_on_busy, "", false },
559
{ "Abort on No Dialtone", NULL, &options.abort_on_no_dialtone, "", true },
560
{ "Compuserve", NULL, &options.compuserve, "", false },
561
{ "Tonline", NULL, &options.tonline, "", false },
562
{ "Auto DNS", NULL, &options.auto_dns, "", true },
563
{ "Check DNS", NULL, &options.check_dns, "", true },
564
{ "Check Def Route", NULL, &options.check_dfr, "", true },
565
{ "Idle Seconds", NULL, &options.idle_seconds, "", 0 },
566
{ "ISDN", NULL, &options.isdn, "", false },
567
{ "Ask Password", NULL, &options.ask_password, "", false },
569
{ NULL, NULL, NULL, "", 0 }
572
char * d = "Dialer Defaults";
574
for( int i=0; opts[i].name != NULL; i++ ) {
575
if( opts[i].str_member == NULL ) {
576
// it's an int/bool option.
577
*( opts[i].int_member ) =
578
cfg.fuzzy_getint( *sect_list, opts[i].name,
579
cfg.getint( d, opts[i].name, opts[i].int_default ) );
581
// it's a string option.
582
*( opts[i].str_member ) =
583
cfg.fuzzy_get( *sect_list, opts[i].name,
584
cfg.get( d, opts[i].name, opts[i].str_default ) );
585
opts[i].str_member->unique();
589
// Support Init, as well as Init1, to make old WvDial people happy.
590
const char * newopt = cfg.fuzzy_get( *sect_list, "Init",
591
cfg.get( d, "Init", NULL ) );
593
options.init1 = newopt;
594
options.init1.unique();
598
bool WvDialer::init_modem()
599
/*************************/
605
if( !options.modem[0] ) {
606
err( "Configuration does not specify a valid modem device.\n" );
608
return( false ); // if we get this error, we already have a problem.
611
for (count = 0; count < 3; count++)
613
// the buffer is empty.
616
if( modem ) delete modem;
620
int flags = fcntl( STDIN_FILENO, F_GETFL );
621
if( ( flags & O_ACCMODE ) == O_RDWR ) {
622
modem = new WvModemBase( STDIN_FILENO );
624
// The following is needed for diald.
625
// Stdin is not opened for read/write.
626
::close( STDIN_FILENO );
627
if( getenv( "MODEM" ) == NULL ) {
628
err( "stdin not read/write and $MODEM not set\n" );
631
// Try to open device $MODEM.
634
int tty = ::open( getenv( "MODEM" ), flags );
636
err( "can't open %s: %m\n", getenv( "MODEM" ) );
639
modem = new WvModemBase( tty );
642
modem = new WvModem( options.modem, options.baud );
643
if( !modem->isok() ) {
644
err( "Cannot open %s: %s\n", options.modem, modem->errstr() );
648
log( "Initializing modem.\n" );
651
modem->print( "\r\r\r\r\r" );
652
while( modem->select( 100 ) )
655
// Send up to nine init strings, in order.
657
for( init_count=1; init_count<=9; init_count++ ) {
659
switch( init_count ) {
660
case 1: this_str = &options.init1; break;
661
case 2: this_str = &options.init2; break;
662
case 3: this_str = &options.init3; break;
663
case 4: this_str = &options.init4; break;
664
case 5: this_str = &options.init5; break;
665
case 6: this_str = &options.init6; break;
666
case 7: this_str = &options.init7; break;
667
case 8: this_str = &options.init8; break;
670
this_str = &options.init9; break;
673
modem->print( "%s\r", *this_str );
674
log( "Sending: %s\n", *this_str );
676
received = wait_for_modem( init_responses, 5000, true );
679
modem->print( "ATQ0\r" );
680
log( "Sending: ATQ0\n" );
681
received = wait_for_modem( init_responses, 500, true );
682
modem->print( "%s\r", *this_str );
683
log( "Re-Sending: %s\n", *this_str );
684
received = wait_for_modem( init_responses, 5000, true );
687
err( "Modem not responding.\n" );
690
err( "Bad init string.\n" );
695
err( "Bad init string.\n" );
701
// Everything worked fine.
702
log( "Modem initialized.\n" );
705
// allows us to exit the internal loop
710
// we tried 3 times and it didn't work.
714
void WvDialer::async_dial()
715
/*************************/
719
if( stat == PreDial2 ) {
720
// Wait for three seconds and then go to PreDial1.
721
continue_select(3000);
726
if( stat == PreDial1 ) {
727
// Hit enter a few times.
728
for( int i=0; i<3; i++ ) {
729
modem->write( "\r", 1 );
730
continue_select(500);
731
if (!isok() || !modem)
739
// Construct the dial string. We use the dial command, prefix,
740
// area code, and phone number as specified in the config file.
742
switch( phnum_count )
745
this_str = &options.phnum;
748
this_str = &options.phnum1;
751
this_str = &options.phnum2;
754
this_str = &options.phnum3;
758
this_str = &options.phnum4;
762
WvString s( "%s%s%s%s%s\r", options.dial_cmd,
764
!options.dial_prefix ? "" : ",",
768
log( "Sending: %s\n", s );
769
log( "Waiting for carrier.\n" );
774
received = async_wait_for_modem( dial_responses, true );
777
case -1: // nothing -- return control.
778
if( time( NULL ) - last_rx >= 60 ) {
779
log( WvLog::Warning, "Timed out while dialing. Trying again.\n" );
784
//if Attempts in wvdial.conf is 0..dont do anything
785
if(options.dial_attempts != 0){
786
if(check_attempts_exceeded(connect_attempts)){
797
if( options.ask_password ) {
798
err( "Error: dial on demand does not work with option Ask Password = 1\n" );
802
if( getuid() != 0 ) {
803
err( "Hint: if authentication does not work, start wvdial.dod once as user root\n" );
807
papchap.put_secret( options.login, options.password, options.remote );
808
if( getuid() == 0 ) {
809
if( papchap.isok_pap() == false ) {
810
err("Warning: Could not modify %s: %s\n",PAP_SECRETS, strerror(errno));
812
if( papchap.isok_chap() == false ) {
813
err("Warning: Could not modify %s: %s\n",CHAP_SECRETS, strerror(errno));
819
if( options.stupid_mode == true || options.tonline == true ) {
821
log( "Carrier detected. Chatmode finished.\n" );
824
log( "Carrier detected. Starting PPP immediately.\n" );
828
log( "Carrier detected. Waiting for prompt.\n" );
832
case 1: // NO CARRIER
833
log( WvLog::Warning, "No Carrier! Trying again.\n" );
837
continue_select(2000);
839
//if Attempts in wvdial.conf is 0..dont do anything
840
if(options.dial_attempts != 0){
841
if(check_attempts_exceeded(connect_attempts)){
847
case 2: // NO DIALTONE
848
case 3: // NO DIAL TONE
849
if( options.abort_on_no_dialtone == true ) {
850
err( "No dial tone.\n" );
853
log( "No dial tone. Trying again in 5 seconds.\n" );
857
//if Attempts in wvdial.conf is 0..dont do anything
858
if(options.dial_attempts != 0){
859
if(check_attempts_exceeded(connect_attempts)){
866
if( options.abort_on_busy == true ) {
867
err( "The line is busy.\n" );
870
if( phnum_count++ == phnum_max )
872
if( phnum_count == 0 )
873
log( WvLog::Warning, "The line is busy. Trying again.\n" );
875
log( WvLog::Warning, "The line is busy. Trying other number.\n");
879
continue_select(2000);
883
err( "Invalid dial command.\n" );
885
//if Attempts in wvdial.conf is 0..dont do anything
886
if(options.dial_attempts != 0){
887
if(check_attempts_exceeded(connect_attempts)){
893
log( "Voice line detected. Trying again.\n" );
898
//if Attempts in wvdial.conf is 0..dont do anything
899
if(options.dial_attempts != 0){
900
if(check_attempts_exceeded(connect_attempts)){
907
log( "Fax line detected. Trying again.\n" );
911
if(options.dial_attempts != 0){
912
if(check_attempts_exceeded(connect_attempts)){
919
log( WvLog::Warning, "No Answer. Trying again.\n" );
923
if(options.dial_attempts != 0){
924
if(check_attempts_exceeded(connect_attempts)){
928
continue_select(2000);
931
err( "Unknown dial response string.\n" );
937
//This Function checks whether the connection attempts exceeded the Attempts value set in wvdial.conf
939
bool WvDialer::check_attempts_exceeded(int no_of_attempts)
941
if(no_of_attempts > options.dial_attempts){
942
log( WvLog::Warning, "Maximum Attempts Exceeded..Aborting!!\n" );
952
set_echo( int desc, int value )
954
struct termios settings;
956
if( isatty( desc ) != 1 )
959
if( tcgetattr (desc, &settings) < 0 ) {
960
perror ("error in tcgetattr");
965
settings.c_lflag |= ECHO;
967
settings.c_lflag &= ~ECHO;
969
if( tcsetattr (desc, TCSANOW, &settings) < 0 ) {
970
perror ("error in tcgetattr");
978
int WvDialer::ask_password()
979
/**************************/
983
log("Please enter password (or empty password to stop):\n" );
984
// fflush( stdout ); // kinternet needs this - WvLog should do it
987
set_echo( STDOUT_FILENO, 0 );
988
fgets( tmp, 50, stdin );
989
set_echo( STDOUT_FILENO, 1 );
991
if( tmp[ strlen(tmp)-1 ] == '\n' )
992
tmp[ strlen(tmp)-1 ] = '\0';
994
options.password = tmp;
995
options.password.unique();
1001
void WvDialer::start_ppp()
1002
/************************/
1004
if( chat_mode ) exit(0); // pppd is already started...
1006
WvString addr_colon( "%s:", options.force_addr );
1007
WvString speed( options.baud );
1008
WvString idle_seconds( options.idle_seconds );
1010
const char *dev_str = (const char *)options.modem;
1011
if (!(strncmp(options.modem, "/dev/", 5)))
1015
// open a pipe to access the messages of pppd
1016
if( pipe( pppd_msgfd ) == -1 ) {
1017
err("pipe failed: %s\n", strerror(errno) );
1018
exit( EXIT_FAILURE );
1020
pppd_log = new WvStream( pppd_msgfd[0] );
1021
WvString buffer1("%s", pppd_msgfd[1] );
1024
// open a pipe to pass password to pppd
1026
if( options.password != NULL && options.password[0] != '\0' ) {
1027
if( pipe( pppd_passwdfd ) == -1 ) {
1028
err("pipe failed: %s\n", strerror(errno) );
1029
exit( EXIT_FAILURE );
1031
::write( pppd_passwdfd[1], (const char *) options.password, options.password.len() );
1032
::close( pppd_passwdfd[1] );
1033
buffer2.append("%s", pppd_passwdfd[0] );
1036
char const *argv_raw[] = {
1045
"user", options.login,
1046
options.force_addr[0] ? (const char *)addr_colon : "noipdefault",
1047
options.new_pppd && options.auto_dns ? "usepeerdns" : NULL,
1048
options.new_pppd && options.isdn ? "default-asyncmap" : NULL,
1049
options.new_pppd && options.pppd_option[0] ? (const char *) options.pppd_option : NULL,
1051
options.idle_seconds >= 0 ? "idle" : NULL,
1053
options.idle_seconds >= 0 ? (const char *)idle_seconds : NULL,
1055
// !!buffer2 ? "passwordfd" : NULL, !!buffer2 ? (const char *)buffer2 : NULL,
1059
/* Filter out NULL holes in the raw argv list: */
1060
char * argv[sizeof(argv_raw)];
1062
for (unsigned int i = 0; i < sizeof(argv_raw)/sizeof(char *); i++) {
1064
argv[argv_index++] = (char *)argv_raw[i];
1066
argv[argv_index] = NULL;
1068
if( access( options.where_pppd, X_OK ) != 0 ) {
1069
err( "Unable to run %s.\n", options.where_pppd );
1070
err( "Check permissions, or specify a \"PPPD Path\" option "
1071
"in wvdial.conf.\n" );
1075
if (options.dialmessage1.len() || options.dialmessage2.len()) {
1076
log( WvLog::Notice, "\
1077
==========================================================================\n");
1078
log( WvLog::Notice, "> %s\n", options.dialmessage1);
1079
if (options.dialmessage2.len())
1080
log( WvLog::Notice, "> %s\n", options.dialmessage2);
1081
log( WvLog::Notice, "\
1082
==========================================================================\n");
1083
if (options.homepage.len())
1084
log( WvLog::Notice, "Homepage of %s: %s\n",
1085
options.provider.len() ? (const char *)options.provider : "this provider",
1091
log( WvLog::Notice, "Starting pppd at %s", ctime( &now ) );
1094
// unsigned int i = 0;
1095
// WvString pppd_args( "%s", argv[i++] );
1096
// for (; i < sizeof(argv)/sizeof(char *); i++) {
1097
// pppd_args = WvString( "%s %s", pppd_args, argv[i] );
1099
// log("pppd args: %s\n", pppd_args);
1101
// ugly cast however without it the argv list can't be init'd
1102
// Moshe: removed ugly cast, it seems argv can be init'd just fine
1104
ppp_pipe = new WvPipe( argv[0], argv, false, false, false,
1105
modem, modem, modem );
1107
log( WvLog::Notice, "pid of pppd: %s\n", ppp_pipe->getpid() );
1111
connected_at = time( NULL );
1114
void WvDialer::async_waitprompt()
1115
/*******************************/
1118
const char *prompt_response;
1120
if( options.carrier_check == true ) {
1121
if( !modem || !modem->carrier() ) {
1122
err( "Connected, but carrier signal lost! Retrying...\n" );
1128
received = async_wait_for_modem( prompt_strings, false, true );
1129
if( received >= 0 ) {
1130
// We have a PPP sequence!
1131
log( "PPP negotiation detected.\n" );
1133
} else if( received == -1 ) {
1134
// some milliseconds must have passed without receiving anything,
1135
// or async_wait_for_modem() would not have returned yet.
1137
// check to see if we are at a prompt.
1138
// Note: the buffer has been lowered by strlwr() already.
1140
prompt_response = brain->check_prompt( buffer );
1141
if( prompt_response != NULL )
1142
modem->print( "%s\r", prompt_response );
1147
static void strip_parity( char * buf, size_t size )
1148
/*************************************************/
1149
// clear the parity bit on incoming data (to allow 7e1 connections)
1159
int WvDialer::wait_for_modem( char * strs[],
1163
/***********************************************/
1169
const char *ppp_marker = NULL;
1171
while( modem->select( timeout ) ) {
1172
last_rx = time( NULL );
1174
offset += modem->read( buffer + offset, INBUF_SIZE - offset );
1176
// make sure we do not split lines TOO arbitrarily, or the
1177
// logs will look bad.
1178
while( offset < INBUF_SIZE && modem->select( 100 ) )
1179
offset += modem->read( buffer + offset, INBUF_SIZE - offset );
1181
// Make sure there is a NULL on the end of the buffer.
1182
buffer[ offset ] = '\0';
1184
// Now turn all the NULLs in the middle of the buffer to spaces, for
1186
replace_char( buffer + onset, '\0', ' ', offset - onset );
1187
strip_parity( buffer + onset, offset - onset );
1188
replace_char( buffer + onset, '\0', ' ', offset - onset );
1191
modemrx.write( buffer + onset, offset - onset );
1193
strlwr( buffer + onset );
1195
// Now we can search using strstr.
1196
for( result = 0; strs[ result ] != NULL; result++ ) {
1197
len = strlen( strs[ result ] );
1198
soff = strstr( buffer, strs[ result ] );
1200
if( soff && ( !neednewline
1201
|| strchr( soff, '\n' ) || strchr( soff, '\r' ) ) )
1203
memmove( buffer, soff + len,
1204
offset - (int)( soff+len - buffer ) );
1205
offset -= (int)( soff+len - buffer );
1210
if( strs[ result ] == NULL )
1213
// Search the buffer for a valid menu option...
1214
// If guess_menu returns an offset, we zap everything before it in
1215
// the buffer. This prevents finding the same menu option twice.
1216
ppp_marker = brain->guess_menu( buffer );
1217
if (strs != dial_responses) {
1218
if( ppp_marker != NULL )
1219
memset( buffer, ' ', ppp_marker-buffer );
1222
// Looks like we didn't find anything. Is the buffer full yet?
1223
if( offset == INBUF_SIZE ) {
1224
// yes, move the second half to the first half for next time.
1225
memmove( buffer, buffer + INBUF_SIZE/2,
1226
INBUF_SIZE - INBUF_SIZE/2 );
1227
offset = INBUF_SIZE/2;
1234
buffer[ offset ] = 0;
1235
return( result ); // -1 == timeout
1238
int WvDialer::async_wait_for_modem( char * strs[], bool neednl, bool verbose )
1239
/****************************************************************************/
1241
return( wait_for_modem( strs, 10, neednl, verbose ) );
1244
void WvDialer::reset_offset()
1245
/***************************/