~ubuntu-branches/ubuntu/quantal/wvdial/quantal

« back to all changes in this revision

Viewing changes to src/wvdialer.cc

  • Committer: Bazaar Package Importer
  • Author(s): Martin Pitt
  • Date: 2004-10-06 11:05:06 UTC
  • mfrom: (0.1.1 upstream)
  • mto: This revision was merged to the branch mainline in revision 3.
  • Revision ID: james.westby@ubuntu.com-20041006110506-138x19fe4q0iu46e
Tags: 1.54.0-1ubuntu1
postinst: Disable command-line configuration to not disturb installation;
the script just exits early, so the postinst code is not completely lost
(Warty bug #2069)

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
/*
2
 
 * Worldvisions Weaver Software:
3
 
 *   Copyright (C) 1997-2002 Net Integration Technologies, Inc.
4
 
 *
5
 
 * Implementation of the WvDialer smart-dialer class.  
6
 
 *
7
 
 */
8
 
 
9
 
#include "wvdialer.h"
10
 
#include "wvver.h"
11
 
 
12
 
#include <sys/types.h>
13
 
#include <sys/stat.h>
14
 
#include <fcntl.h>
15
 
#include <signal.h>
16
 
#include <termios.h>
17
 
#include <time.h>
18
 
#include <unistd.h>
19
 
#include <ctype.h>
20
 
#include <errno.h>
21
 
#include <assert.h>
22
 
 
23
 
 
24
 
static char *   init_responses[] = {
25
 
        "ok",
26
 
        "error",
27
 
        NULL
28
 
};
29
 
 
30
 
static char *   dial_responses[] = {
31
 
        "connect",
32
 
        "no carrier",
33
 
        "no dialtone",
34
 
        "no dial tone",
35
 
        "busy",
36
 
        "delayed",
37
 
        "error",
38
 
        "voice",
39
 
        "fclass",
40
 
        "no answer",
41
 
        NULL
42
 
};
43
 
 
44
 
static char *   prompt_strings[] = {
45
 
        "}!}",
46
 
        "!}!",
47
 
        NULL
48
 
};
49
 
 
50
 
static int messagetail_pid = 0;
51
 
 
52
 
//**************************************************
53
 
//       WvDialer Public Functions
54
 
//**************************************************
55
 
 
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 )
62
 
{
63
 
    modem                = NULL;
64
 
    ppp_pipe             = NULL;
65
 
    pppd_log             = NULL;
66
 
    been_online          = false;
67
 
    stat                 = Idle;
68
 
    offset               = 0;
69
 
    prompt_tries         = 0;
70
 
    last_rx              = last_execute = 0;
71
 
    prompt_response      = "";
72
 
    auto_reconnect_delay = 0;
73
 
    auto_reconnect_at    = 0;
74
 
    connected_at         = 0;
75
 
    phnum_count = 0;
76
 
    phnum_max = 0;      
77
 
    // tell wvstreams we need our own subtask
78
 
    uses_continue_select = true;
79
 
 
80
 
    sect_list = _sect_list;
81
 
    chat_mode = _chat_mode;
82
 
    
83
 
    log( "WvDial: Internet dialer version " WVDIAL_VER_STRING "\n" );
84
 
 
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 ) {
89
 
            err( WvLog::Warning,
90
 
                 "Warning: section [%s] does not exist in wvdial.conf.\n",
91
 
                 iter );
92
 
        }
93
 
    }
94
 
 
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"];
100
 
        if (entry) {
101
 
            WvString inherits = entry->value;
102
 
            if (cfg[inherits] == NULL)
103
 
                err( WvLog::Warning,  
104
 
                     "Warning: inherited section [%s] does not exist in wvdial.conf\n",
105
 
                     inherits);
106
 
       }
107
 
    }  
108
 
 
109
 
    // Activate the brain and read configuration.
110
 
    brain = new WvDialBrain( this );
111
 
 
112
 
    // init_modem() reads the config options.  It MUST run here!
113
 
    
114
 
    if( !init_modem() )
115
 
    {
116
 
        // init_modem() printed an error
117
 
        stat = ModemError;
118
 
        return;
119
 
    }
120
 
 
121
 
    if (options.provider.len()) {
122
 
        log( WvLog::Notice, "Dialing %s %s.\n",
123
 
                options.provider,
124
 
                options.product);
125
 
    }
126
 
    if (options.homepage.len()) {
127
 
        log( WvLog::Notice, "Homepage of %s: %s\n",
128
 
                options.provider.len() ? (const char *)options.provider : "this provider",
129
 
                options.homepage);
130
 
    }
131
 
 
132
 
    if( options.auto_reconnect && options.idle_seconds > 0) {
133
 
        err( WvLog::Notice,
134
 
            "Idle Seconds = %s, disabling automatic reconnect.\n",
135
 
                                WvString(options.idle_seconds));
136
 
        options.auto_reconnect = false;
137
 
    }
138
 
    
139
 
    pppd_mon.setdnstests (options.dnstest1, options.dnstest2);
140
 
    pppd_mon.setcheckdns (options.check_dns);
141
 
    pppd_mon.setcheckdfr (options.check_dfr);
142
 
}
143
 
 
144
 
WvDialer::~WvDialer()
145
 
/*******************/
146
 
{
147
 
    if( ppp_pipe )
148
 
        delete ppp_pipe;
149
 
    if( pppd_log )
150
 
        delete pppd_log;
151
 
    if( modem )
152
 
        delete modem;
153
 
    if( brain )
154
 
        delete brain;
155
 
}
156
 
 
157
 
bool WvDialer::dial()
158
 
/*******************/
159
 
// Returns false on error, or true to go asynchronous while dialing.
160
 
{
161
 
    if( stat == Online )
162
 
        return( true );
163
 
        
164
 
    if( stat != Idle ) {
165
 
        // (error message has already been printed elsewhere)
166
 
        // err( "Modem is not ready to dial.\n" );
167
 
        return( false );
168
 
    }
169
 
 
170
 
    if( !options.phnum[0] ) {
171
 
        err( "Configuration does not specify a valid phone number.\n" );
172
 
        stat = OtherError;
173
 
    }
174
 
 
175
 
    if( !options.login[0] ) {
176
 
        err( "Configuration does not specify a valid login name.\n" );
177
 
        stat = OtherError;
178
 
    }
179
 
 
180
 
    if( !options.password[0] ) {
181
 
        err( "Configuration does not specify a valid password.\n" );
182
 
        stat = OtherError;
183
 
    }
184
 
    
185
 
    if( stat != Idle )
186
 
        return( false );
187
 
 
188
 
    phnum_max = 0;
189
 
    if( options.phnum1.len() ) 
190
 
    { 
191
 
        phnum_max++;
192
 
        if( options.phnum2.len() ) 
193
 
        { 
194
 
            phnum_max++;
195
 
            if( options.phnum3.len() ) 
196
 
            { 
197
 
                phnum_max++;
198
 
                if( options.phnum4.len() ) 
199
 
                { 
200
 
                    phnum_max++;
201
 
                }
202
 
            }
203
 
        }
204
 
    }
205
 
 
206
 
    // we need to re-init the modem if we were online before.
207
 
    if( been_online && !init_modem() )
208
 
        stat = ModemError;
209
 
    else
210
 
    {
211
 
        stat = Dial;
212
 
        connect_attempts = 1;
213
 
        dial_stat = 0;
214
 
        brain->reset();
215
 
    }
216
 
    
217
 
    return( true );
218
 
}
219
 
 
220
 
void WvDialer::hangup()
221
 
/*********************/
222
 
{
223
 
    if( ppp_pipe ) {
224
 
        delete ppp_pipe;
225
 
        ppp_pipe = NULL;
226
 
    }
227
 
    
228
 
    if( !chat_mode )
229
 
      pppd_watch( 250 );
230
 
    
231
 
    if( stat != Idle ) 
232
 
    {
233
 
        time_t  now;
234
 
        time( &now );
235
 
        log( "Disconnecting at %s", ctime( &now ) );
236
 
        if( modem )
237
 
        {
238
 
            modem->hangup();
239
 
            delete modem;
240
 
            modem = NULL;
241
 
        }
242
 
        stat = Idle;
243
 
    }
244
 
 
245
 
    if (messagetail_pid > 0) 
246
 
    {
247
 
        kill(messagetail_pid, 15);
248
 
        messagetail_pid = 0;
249
 
    }
250
 
}
251
 
 
252
 
bool WvDialer::pre_select( SelectInfo& si )
253
 
/*******************************************/
254
 
{
255
 
    if( isok() && stat != Online && stat != Idle
256
 
               && time( NULL ) - last_execute > 1 )
257
 
    {
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.
262
 
        return( true );
263
 
    } else {
264
 
        return WvStreamClone::pre_select( si );
265
 
    }
266
 
}
267
 
 
268
 
bool WvDialer::isok() const
269
 
/*************************/
270
 
{
271
 
    bool b = ( !modem || modem->isok() )
272
 
        && stat != ModemError && stat != OtherError;
273
 
    /*
274
 
    if (!b)
275
 
        err("Returning not ok!!\n" );
276
 
    */
277
 
    return( b );
278
 
}
279
 
 
280
 
char * WvDialer::connect_status() const
281
 
/*************************************/
282
 
{
283
 
    static char msg[ 160 ];
284
 
 
285
 
    switch( stat ) {
286
 
    case PreDial2:
287
 
    case PreDial1:
288
 
    case Dial:
289
 
    case WaitDial:
290
 
        if( dial_stat == 1 )
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." );
304
 
        else
305
 
            return( NULL );
306
 
        break;
307
 
    case WaitAnything:
308
 
        strcpy( msg, "Waiting for a response from Internet Provider." );
309
 
        break;
310
 
    case WaitPrompt:
311
 
        strcpy( msg, "Waiting for a prompt from Internet Provider." );
312
 
        break;
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 );
317
 
        break;
318
 
    default:
319
 
        return( NULL );
320
 
    }
321
 
    return( msg );
322
 
}
323
 
 
324
 
 
325
 
void WvDialer::pppd_watch( int ms )
326
 
/*********************************/
327
 
{
328
 
  // see if pppd has a message, analyse it and output to log
329
 
  
330
 
    if( pppd_log != NULL && pppd_log->isok() ) 
331
 
    {
332
 
    
333
 
        char *line;
334
 
    
335
 
        while ( (line = pppd_log->getline( ms )) );
336
 
        {
337
 
            WvString buffer1(pppd_mon.analyse_line( line ));
338
 
            if (!!buffer1)
339
 
            {
340
 
                log("pppd: %s\n",buffer1);
341
 
            }
342
 
        }
343
 
    }
344
 
}
345
 
 
346
 
 
347
 
void WvDialer::execute()
348
 
/**********************/
349
 
{
350
 
    WvStreamClone::execute();
351
 
    
352
 
    // the modem object might not exist, if we just disconnected and are
353
 
    // redialing.
354
 
    if( !modem && !init_modem() )
355
 
        return;
356
 
 
357
 
    last_execute = time( NULL );
358
 
    
359
 
    if( !chat_mode )
360
 
      pppd_watch( 100 );
361
 
    
362
 
    switch( stat ) {
363
 
    case Dial:
364
 
    case WaitDial:
365
 
    case PreDial1:
366
 
    case PreDial2:
367
 
        async_dial();
368
 
        break;
369
 
    case WaitAnything:
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.
373
 
            stat = WaitPrompt;
374
 
            last_rx = time( NULL );
375
 
        } else if( time( NULL ) - last_rx >= 30 ) {
376
 
            // timed out - do what WaitPrompt would do on a timeout.
377
 
            stat = WaitPrompt;
378
 
        } else {
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 );
382
 
        }
383
 
        break;
384
 
    case WaitPrompt:
385
 
        async_waitprompt();
386
 
        break;
387
 
    case Online:
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() );
395
 
            }
396
 
 
397
 
            // we must delete the WvModem object so it can be recreated
398
 
            // later; starting pppd seems to screw up the file descriptor.
399
 
            hangup();
400
 
            delete( modem );
401
 
            modem = NULL;
402
 
            
403
 
            time_t call_duration = time( NULL ) - connected_at;
404
 
            
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" );
409
 
            } else {
410
 
                WvString msg = "";
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?";
425
 
                }
426
 
                if (msg.len()) {
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");
438
 
                    }
439
 
                    options.auto_reconnect = false;
440
 
                }
441
 
                msg = "";
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;
451
 
                }
452
 
                if (msg.len()) {
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");
458
 
                } else
459
 
                    log(WvLog::Notice, "The PPP daemon has died. (exit code = %s)\n",
460
 
                        pppd_exit_status);
461
 
            }
462
 
            
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;
469
 
 
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
476
 
 
477
 
                auto_reconnect_at = time( NULL ) + auto_reconnect_delay;
478
 
 
479
 
                stat = AutoReconnectDelay;
480
 
                log( WvLog::Notice, "Auto Reconnect will be attempted in %s "
481
 
                                    "seconds\n", 
482
 
                                        auto_reconnect_at - time( NULL ) );
483
 
            }
484
 
        }
485
 
        break;
486
 
    case AutoReconnectDelay:
487
 
        // If enough time has passed after ISP disconnected us that we should
488
 
        // redial, do it...
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 ) {
492
 
            stat = Idle;
493
 
            dial();
494
 
        }
495
 
        break;
496
 
    case Idle:
497
 
    case ModemError:
498
 
    case OtherError:
499
 
    default:
500
 
        drain();
501
 
        break;
502
 
    }
503
 
}
504
 
 
505
 
 
506
 
//**************************************************
507
 
//       WvDialer Private Functions
508
 
//**************************************************
509
 
 
510
 
void WvDialer::load_options()
511
 
/***************************/
512
 
{
513
 
    OptInfo opts[] = {
514
 
    // string options:
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 },
550
 
 
551
 
    // int/bool options
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        },
568
 
 
569
 
        { NULL,              NULL, NULL,                   "", 0            }
570
 
    };
571
 
 
572
 
    char *      d = "Dialer Defaults";
573
 
 
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 ) );
580
 
        } else {
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();
586
 
        }
587
 
    }
588
 
 
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 ) );
592
 
    if( newopt ) {
593
 
        options.init1 = newopt;
594
 
        options.init1.unique();
595
 
    }
596
 
}
597
 
 
598
 
bool WvDialer::init_modem()
599
 
/*************************/
600
 
{
601
 
    int received, count;
602
 
    
603
 
    load_options();
604
 
 
605
 
    if( !options.modem[0] ) {
606
 
        err( "Configuration does not specify a valid modem device.\n" );
607
 
        stat = ModemError;
608
 
        return( false ); // if we get this error, we already have a problem.
609
 
    }
610
 
    
611
 
    for (count = 0; count < 3; count++)
612
 
    {
613
 
        // the buffer is empty.
614
 
        offset = 0;
615
 
    
616
 
        if( modem ) delete modem;
617
 
        
618
 
        // Open the modem...
619
 
        if( chat_mode ) {
620
 
            int flags = fcntl( STDIN_FILENO, F_GETFL );
621
 
            if( ( flags & O_ACCMODE ) == O_RDWR ) {
622
 
                modem = new WvModemBase( STDIN_FILENO );
623
 
            } else {
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" );
629
 
                    exit( 1 );
630
 
                }
631
 
                // Try to open device $MODEM.
632
 
                flags &= !O_ACCMODE;
633
 
                flags |= O_RDWR;
634
 
                int tty = ::open( getenv( "MODEM" ), flags );
635
 
                if( tty == -1 ) {
636
 
                    err( "can't open %s: %m\n", getenv( "MODEM" ) );
637
 
                    exit( 1 );
638
 
                }
639
 
                modem = new WvModemBase( tty );
640
 
            }
641
 
        } else
642
 
            modem = new WvModem( options.modem, options.baud );
643
 
        if( !modem->isok() ) {
644
 
            err( "Cannot open %s: %s\n", options.modem, modem->errstr() );
645
 
            continue;
646
 
        }
647
 
        
648
 
        log( "Initializing modem.\n" );
649
 
        
650
 
        // make modem happy
651
 
        modem->print( "\r\r\r\r\r" );
652
 
        while( modem->select( 100 ) )
653
 
            modem->drain();
654
 
        
655
 
        // Send up to nine init strings, in order.
656
 
        int     init_count;
657
 
        for( init_count=1; init_count<=9; init_count++ ) {
658
 
            WvString *this_str;
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;
668
 
                case 9:
669
 
                default:
670
 
                           this_str = &options.init9;   break;
671
 
            }
672
 
            if( !! *this_str ) {
673
 
                modem->print( "%s\r", *this_str );
674
 
                log( "Sending: %s\n", *this_str );
675
 
                
676
 
                received = wait_for_modem( init_responses, 5000, true );
677
 
                switch( received ) {
678
 
                case -1:
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 );
685
 
                    switch( received ) {
686
 
                        case -1:
687
 
                            err( "Modem not responding.\n" );
688
 
                            return( false );
689
 
                        case 1:
690
 
                            err( "Bad init string.\n" );
691
 
                            return( false );
692
 
                    }
693
 
                    goto end_outer;
694
 
                case 1:
695
 
                    err( "Bad init string.\n" );
696
 
                    goto end_outer;
697
 
                }
698
 
            }
699
 
        }
700
 
 
701
 
        // Everything worked fine.
702
 
        log( "Modem initialized.\n" );
703
 
        return( true );
704
 
        
705
 
        // allows us to exit the internal loop
706
 
      end_outer:
707
 
        continue;
708
 
    }
709
 
    
710
 
    // we tried 3 times and it didn't work.
711
 
    return( false );
712
 
}
713
 
 
714
 
void WvDialer::async_dial()
715
 
/*************************/
716
 
{
717
 
    int received;
718
 
 
719
 
    if( stat == PreDial2 ) {
720
 
        // Wait for three seconds and then go to PreDial1.
721
 
        continue_select(3000);
722
 
        stat = PreDial1;
723
 
        return;
724
 
    }
725
 
    
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)
732
 
                break;
733
 
        }
734
 
        stat = Dial;
735
 
        return;
736
 
    }
737
 
        
738
 
    if( stat == Dial ) {
739
 
        // Construct the dial string.  We use the dial command, prefix,
740
 
        // area code, and phone number as specified in the config file.
741
 
        WvString *this_str;
742
 
        switch( phnum_count ) 
743
 
        {  
744
 
            case 0:     
745
 
                this_str = &options.phnum;
746
 
                break;
747
 
            case 1:     
748
 
                this_str = &options.phnum1;
749
 
                break;
750
 
            case 2:     
751
 
                this_str = &options.phnum2;     
752
 
                break;
753
 
            case 3:     
754
 
                this_str = &options.phnum3;     
755
 
                break;
756
 
            case 4:
757
 
            default:
758
 
                this_str = &options.phnum4;     
759
 
                break;
760
 
        }
761
 
 
762
 
        WvString s( "%s%s%s%s%s\r", options.dial_cmd,
763
 
                                 options.dial_prefix,
764
 
                                 !options.dial_prefix ? "" : ",",
765
 
                                 options.areacode,
766
 
                                 *this_str );
767
 
        modem->print( s );
768
 
        log( "Sending: %s\n", s );
769
 
        log( "Waiting for carrier.\n" );
770
 
 
771
 
        stat = WaitDial;
772
 
    }
773
 
 
774
 
    received = async_wait_for_modem( dial_responses, true );
775
 
    
776
 
    switch( received ) {
777
 
    case -1:    // nothing -- return control.
778
 
        if( time( NULL ) - last_rx  >= 60 ) {
779
 
            log( WvLog::Warning, "Timed out while dialing.  Trying again.\n" );
780
 
            stat = PreDial1;
781
 
            connect_attempts++;
782
 
            dial_stat = 1;
783
 
            
784
 
            //if Attempts in wvdial.conf is 0..dont do anything
785
 
            if(options.dial_attempts != 0){
786
 
                    if(check_attempts_exceeded(connect_attempts)){
787
 
                            hangup();
788
 
                    }
789
 
            }
790
 
 
791
 
        }
792
 
        return;
793
 
    case 0:     // CONNECT
794
 
 
795
 
        /*
796
 
        if( chat_mode ) {
797
 
          if( options.ask_password ) {
798
 
            err( "Error: dial on demand does not work with option Ask Password = 1\n" );
799
 
            exit( 1 );
800
 
          }
801
 
          
802
 
          if( getuid() != 0 ) {
803
 
            err( "Hint: if authentication does not work, start wvdial.dod once as user root\n" );
804
 
          }
805
 
          
806
 
          WvPapChap papchap;
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));
811
 
            }
812
 
            if( papchap.isok_chap() == false ) {
813
 
              err("Warning: Could not modify %s: %s\n",CHAP_SECRETS, strerror(errno));
814
 
            }
815
 
          }
816
 
        }
817
 
        */
818
 
        
819
 
        if( options.stupid_mode == true || options.tonline == true ) {
820
 
          if( chat_mode ) {
821
 
            log( "Carrier detected.  Chatmode finished.\n" );
822
 
            exit( 0 );
823
 
          } else {
824
 
            log( "Carrier detected.  Starting PPP immediately.\n" );
825
 
            start_ppp();
826
 
          }
827
 
        } else {
828
 
            log( "Carrier detected.  Waiting for prompt.\n" );
829
 
            stat = WaitAnything;
830
 
        }
831
 
        return;
832
 
    case 1:     // NO CARRIER
833
 
        log( WvLog::Warning, "No Carrier!  Trying again.\n" );
834
 
        stat = PreDial1;
835
 
        connect_attempts++;
836
 
        dial_stat = 2;
837
 
        continue_select(2000);
838
 
 
839
 
        //if Attempts in wvdial.conf is 0..dont do anything
840
 
        if(options.dial_attempts != 0){
841
 
                if(check_attempts_exceeded(connect_attempts)){
842
 
                        hangup();
843
 
                }
844
 
        }
845
 
 
846
 
        return;
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" );
851
 
            stat = ModemError;
852
 
        } else {
853
 
            log( "No dial tone.  Trying again in 5 seconds.\n" );
854
 
            stat = PreDial2;
855
 
            connect_attempts++;
856
 
            dial_stat = 3;
857
 
            //if Attempts in wvdial.conf is 0..dont do anything
858
 
            if(options.dial_attempts != 0){
859
 
               if(check_attempts_exceeded(connect_attempts)){
860
 
                       hangup();
861
 
               }
862
 
            }
863
 
        }
864
 
        return;
865
 
    case 4:     // BUSY
866
 
        if( options.abort_on_busy == true ) {
867
 
            err( "The line is busy.\n" );
868
 
            stat = ModemError;
869
 
        } else {
870
 
           if( phnum_count++ == phnum_max )
871
 
                phnum_count = 0;
872
 
           if( phnum_count == 0 )
873
 
                log( WvLog::Warning, "The line is busy. Trying again.\n" );
874
 
           else
875
 
                log( WvLog::Warning, "The line is busy. Trying other number.\n");
876
 
           stat = PreDial1;
877
 
           connect_attempts++;
878
 
           dial_stat = 4;
879
 
           continue_select(2000);
880
 
        }
881
 
        return;
882
 
    case 5:     // ERROR
883
 
        err( "Invalid dial command.\n" );
884
 
        stat = ModemError;
885
 
        //if Attempts in wvdial.conf is 0..dont do anything
886
 
        if(options.dial_attempts != 0){
887
 
           if(check_attempts_exceeded(connect_attempts)){
888
 
               hangup();
889
 
           }
890
 
        }
891
 
        return;
892
 
    case 6:     // VOICE
893
 
        log( "Voice line detected.  Trying again.\n" );
894
 
        connect_attempts++;
895
 
        dial_stat = 5;
896
 
        stat = PreDial2;
897
 
 
898
 
        //if Attempts in wvdial.conf is 0..dont do anything
899
 
        if(options.dial_attempts != 0){
900
 
                if(check_attempts_exceeded(connect_attempts)){
901
 
                        hangup();
902
 
                }
903
 
        }
904
 
 
905
 
        return;
906
 
    case 7:     // FCLASS
907
 
        log( "Fax line detected.  Trying again.\n" );
908
 
        connect_attempts++;
909
 
        dial_stat = 6;
910
 
        stat = PreDial2;
911
 
        if(options.dial_attempts != 0){
912
 
            if(check_attempts_exceeded(connect_attempts)){
913
 
                hangup();
914
 
            }
915
 
        }
916
 
        return;
917
 
 
918
 
     case 8:    // NO ANSWER
919
 
        log( WvLog::Warning, "No Answer.  Trying again.\n" );
920
 
        stat = PreDial1;
921
 
        connect_attempts++;
922
 
        dial_stat = 7;
923
 
        if(options.dial_attempts != 0){
924
 
            if(check_attempts_exceeded(connect_attempts)){
925
 
                hangup();
926
 
            }
927
 
        }
928
 
        continue_select(2000);
929
 
        return;
930
 
    default:
931
 
        err( "Unknown dial response string.\n" );
932
 
        stat = ModemError;
933
 
        return;
934
 
    }
935
 
}
936
 
 
937
 
//This Function checks whether the connection attempts exceeded the Attempts value set in wvdial.conf
938
 
 
939
 
bool WvDialer::check_attempts_exceeded(int no_of_attempts)
940
 
{
941
 
        if(no_of_attempts > options.dial_attempts){
942
 
                log( WvLog::Warning, "Maximum Attempts Exceeded..Aborting!!\n" );
943
 
                return true;
944
 
        }else{
945
 
                return false;
946
 
        }
947
 
}
948
 
 
949
 
 
950
 
 
951
 
static int
952
 
set_echo( int desc, int value )
953
 
{
954
 
  struct termios settings;
955
 
  
956
 
  if( isatty( desc ) != 1 )
957
 
    return 0;
958
 
  
959
 
  if( tcgetattr (desc, &settings) < 0 ) {
960
 
    perror ("error in tcgetattr");
961
 
    return 0;
962
 
  }
963
 
  
964
 
  if( value )
965
 
    settings.c_lflag |= ECHO;
966
 
  else
967
 
    settings.c_lflag &= ~ECHO;
968
 
  
969
 
  if( tcsetattr (desc, TCSANOW, &settings) < 0 ) {
970
 
    perror ("error in tcgetattr");
971
 
    return 0;
972
 
  }
973
 
  
974
 
  return 1;
975
 
}
976
 
 
977
 
 
978
 
int WvDialer::ask_password()
979
 
/**************************/
980
 
{
981
 
  char tmp[60];
982
 
  
983
 
  log("Please enter password (or empty password to stop):\n" );
984
 
//  fflush( stdout );           // kinternet needs this - WvLog should do it
985
 
                                // automagically
986
 
  
987
 
  set_echo( STDOUT_FILENO, 0 );
988
 
  fgets( tmp, 50, stdin );
989
 
  set_echo( STDOUT_FILENO, 1 );
990
 
  
991
 
  if( tmp[ strlen(tmp)-1 ] == '\n' )
992
 
    tmp[ strlen(tmp)-1 ] = '\0';
993
 
  
994
 
  options.password = tmp;
995
 
  options.password.unique();
996
 
  
997
 
  return 1;
998
 
}
999
 
 
1000
 
 
1001
 
void WvDialer::start_ppp()
1002
 
/************************/
1003
 
{
1004
 
    if( chat_mode ) exit(0); // pppd is already started...
1005
 
 
1006
 
    WvString    addr_colon( "%s:", options.force_addr );
1007
 
    WvString    speed( options.baud );
1008
 
    WvString    idle_seconds( options.idle_seconds );
1009
 
 
1010
 
    const char *dev_str = (const char *)options.modem;
1011
 
    if (!(strncmp(options.modem, "/dev/", 5)))
1012
 
        dev_str += 5;
1013
 
    
1014
 
    
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 );
1019
 
    }
1020
 
    pppd_log = new WvStream( pppd_msgfd[0] );
1021
 
    WvString buffer1("%s", pppd_msgfd[1] );
1022
 
    
1023
 
    
1024
 
    // open a pipe to pass password to pppd
1025
 
    WvString buffer2;
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 );
1030
 
      }
1031
 
      ::write( pppd_passwdfd[1], (const char *) options.password, options.password.len() );
1032
 
      ::close( pppd_passwdfd[1] );
1033
 
      buffer2.append("%s", pppd_passwdfd[0] );
1034
 
    }
1035
 
    
1036
 
    char const *argv_raw[] = {
1037
 
        options.where_pppd,
1038
 
        speed,
1039
 
        "modem",
1040
 
        "crtscts",
1041
 
        "defaultroute",
1042
 
        "usehostname",
1043
 
        "-detach",
1044
 
        "call", "wvdial",
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,
1050
 
        options.new_pppd &&
1051
 
        options.idle_seconds >= 0 ? "idle"                         : NULL, 
1052
 
        options.new_pppd &&
1053
 
        options.idle_seconds >= 0 ? (const char *)idle_seconds     : NULL, 
1054
 
        "logfd", buffer1,
1055
 
//      !!buffer2 ? "passwordfd" : NULL, !!buffer2 ? (const char *)buffer2 : NULL,
1056
 
        NULL
1057
 
    };
1058
 
    
1059
 
    /* Filter out NULL holes in the raw argv list: */
1060
 
    char * argv[sizeof(argv_raw)];
1061
 
    int argv_index = 0;
1062
 
    for (unsigned int i = 0; i < sizeof(argv_raw)/sizeof(char *); i++) {
1063
 
        if (argv_raw[i])
1064
 
            argv[argv_index++] = (char *)argv_raw[i];
1065
 
    }
1066
 
    argv[argv_index] = NULL;
1067
 
 
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" );
1072
 
        return;
1073
 
    }
1074
 
    
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",
1086
 
                options.homepage);
1087
 
    }
1088
 
 
1089
 
    time_t      now;
1090
 
    time( &now );
1091
 
    log( WvLog::Notice, "Starting pppd at %s", ctime( &now ) );
1092
 
    
1093
 
// sig11 in here:
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] );
1098
 
//    }
1099
 
//    log("pppd args: %s\n", pppd_args);
1100
 
 
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
1103
 
    //        without it.
1104
 
    ppp_pipe = new WvPipe( argv[0], argv, false, false, false,
1105
 
                           modem, modem, modem );
1106
 
 
1107
 
    log( WvLog::Notice, "pid of pppd: %s\n", ppp_pipe->getpid() );
1108
 
 
1109
 
    stat         = Online;
1110
 
    been_online  = true;
1111
 
    connected_at = time( NULL );
1112
 
}
1113
 
 
1114
 
void WvDialer::async_waitprompt()
1115
 
/*******************************/
1116
 
{
1117
 
    int         received;
1118
 
    const char *prompt_response;
1119
 
 
1120
 
    if( options.carrier_check == true ) {
1121
 
        if( !modem || !modem->carrier() ) {
1122
 
            err( "Connected, but carrier signal lost!  Retrying...\n" );
1123
 
            stat = PreDial2;
1124
 
            return;
1125
 
        }
1126
 
    }
1127
 
 
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" );
1132
 
        start_ppp();
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.
1136
 
        
1137
 
        // check to see if we are at a prompt.
1138
 
        // Note: the buffer has been lowered by strlwr() already.
1139
 
 
1140
 
        prompt_response = brain->check_prompt( buffer );
1141
 
        if( prompt_response != NULL )
1142
 
            modem->print( "%s\r", prompt_response );
1143
 
    }
1144
 
}
1145
 
 
1146
 
 
1147
 
static void strip_parity( char * buf, size_t size )
1148
 
/*************************************************/
1149
 
// clear the parity bit on incoming data (to allow 7e1 connections)
1150
 
{
1151
 
    while( size-- > 0 )
1152
 
    {
1153
 
        *buf = *buf & 0x7f;
1154
 
        buf++;
1155
 
    }
1156
 
}
1157
 
 
1158
 
 
1159
 
int WvDialer::wait_for_modem( char *    strs[], 
1160
 
                              int       timeout, 
1161
 
                              bool      neednewline,
1162
 
                              bool      verbose )
1163
 
/***********************************************/
1164
 
{
1165
 
    off_t       onset;
1166
 
    char *      soff;
1167
 
    int         result = -1;
1168
 
    int         len;
1169
 
    const char *ppp_marker = NULL;
1170
 
 
1171
 
    while( modem->select( timeout ) ) {
1172
 
        last_rx = time( NULL );
1173
 
        onset = offset;
1174
 
        offset += modem->read( buffer + offset, INBUF_SIZE - offset );
1175
 
        
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 );
1180
 
 
1181
 
        // Make sure there is a NULL on the end of the buffer.
1182
 
        buffer[ offset ] = '\0';
1183
 
 
1184
 
        // Now turn all the NULLs in the middle of the buffer to spaces, for
1185
 
        // easier parsing.
1186
 
        replace_char( buffer + onset, '\0', ' ', offset - onset );
1187
 
        strip_parity( buffer + onset, offset - onset );
1188
 
        replace_char( buffer + onset, '\0', ' ', offset - onset );
1189
 
 
1190
 
        if( verbose )
1191
 
            modemrx.write( buffer + onset, offset - onset );
1192
 
 
1193
 
        strlwr( buffer + onset );
1194
 
 
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 ] );
1199
 
            
1200
 
            if( soff && ( !neednewline 
1201
 
                         || strchr( soff, '\n' ) || strchr( soff, '\r' ) ) )
1202
 
            {
1203
 
                memmove( buffer, soff + len,
1204
 
                         offset - (int)( soff+len - buffer ) );
1205
 
                offset -= (int)( soff+len - buffer );
1206
 
                break;
1207
 
            }
1208
 
        }
1209
 
        
1210
 
        if( strs[ result ] == NULL )
1211
 
            result = -1;
1212
 
 
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 );
1220
 
        }
1221
 
        
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;
1228
 
        }
1229
 
        
1230
 
        if( result != -1 )
1231
 
            break;
1232
 
    }
1233
 
    
1234
 
    buffer[ offset ] = 0;
1235
 
    return( result ); // -1 == timeout
1236
 
}
1237
 
 
1238
 
int WvDialer::async_wait_for_modem( char * strs[], bool neednl, bool verbose )
1239
 
/****************************************************************************/
1240
 
{
1241
 
    return( wait_for_modem( strs, 10, neednl, verbose ) );
1242
 
}
1243
 
 
1244
 
void WvDialer::reset_offset()
1245
 
/***************************/
1246
 
{
1247
 
    offset = 0;
1248
 
    buffer[0] = '\0';
1249
 
}