1 // -*- c++ -*- //////////////////////////////////////////////////////////////// 
   2 // Name:        src/unix/dialup.cpp 
   3 // Purpose:     Network related wxWidgets classes and functions 
   4 // Author:      Karsten Ballüder 
   8 // Copyright:   (c) Karsten Ballüder 
   9 // Licence:     wxWindows licence 
  10 /////////////////////////////////////////////////////////////////////////////// 
  12 // for compilers that support precompilation, includes "wx.h". 
  13 #include "wx/wxprec.h" 
  15 #if wxUSE_DIALUP_MANAGER 
  17 #include "wx/dialup.h" 
  20     #include "wx/string.h" 
  29 #include "wx/filefn.h" 
  31 #include "wx/process.h" 
  32 #include "wx/wxchar.h" 
  39 #define __STRICT_ANSI__ 
  40 #include <sys/socket.h> 
  42 #include <netinet/in.h> 
  43 #include <arpa/inet.h> 
  46 DEFINE_EVENT_TYPE(wxEVT_DIALUP_CONNECTED
) 
  47 DEFINE_EVENT_TYPE(wxEVT_DIALUP_DISCONNECTED
) 
  49 // ---------------------------------------------------------------------------- 
  50 // A class which groups functions dealing with connecting to the network from a 
  51 // workstation using dial-up access to the net. There is at most one instance 
  52 // of this class in the program accessed via GetDialUpManager(). 
  53 // ---------------------------------------------------------------------------- 
  57  * 1. more configurability for Unix: i.e. how to initiate the connection, how 
  58  *    to check for online status, &c. 
  59  * 2. add a "long Dial(long connectionId = -1)" function which asks the user 
  60  *    about which connection to dial (this may be done using native dialogs 
  61  *    under NT, need generic dialogs for all others) and returns the identifier 
  62  *    of the selected connection (it's opaque to the application) - it may be 
  63  *    reused later to dial the same connection later (or use strings instead of 
  65  * 3. add an async version of dialing functions which notify the caller about 
  66  *    the progress (or may be even start another thread to monitor it) 
  67  * 4. the static creation/accessor functions are not MT-safe - but is this 
  68  *    really crucial? I think we may suppose they're always called from the 
  72 class WXDLLEXPORT wxDialUpManagerImpl 
: public wxDialUpManager
 
  75    wxDialUpManagerImpl(); 
  76    virtual ~wxDialUpManagerImpl(); 
  78    /** Could the dialup manager be initialized correctly? If this function 
  79        returns false, no other functions will work neither, so it's a good idea 
  80        to call this function and check its result before calling any other 
  81        wxDialUpManager methods. 
  83    virtual bool IsOk() const 
  86    /** The simplest way to initiate a dial up: this function dials the given 
  87        ISP (exact meaning of the parameter depends on the platform), returns 
  88        true on success or false on failure and logs the appropriate error 
  89        message in the latter case. 
  90        @param nameOfISP optional paramater for dial program 
  91        @param username unused 
  92        @param password unused 
  94    virtual bool Dial(const wxString
& nameOfISP
, 
  95                      const wxString
& WXUNUSED(username
), 
  96                      const wxString
& WXUNUSED(password
), 
  99    // Hang up the currently active dial up connection. 
 100    virtual bool HangUp(); 
 102    // returns true if the computer is connected to the network: under Windows, 
 103    // this just means that a RAS connection exists, under Unix we check that 
 104    // the "well-known host" (as specified by SetWellKnownHost) is reachable 
 105    virtual bool IsOnline() const 
 108          return m_IsOnline 
== Net_Connected
; 
 111    // do we have a constant net connection? 
 112    virtual bool IsAlwaysOnline() const; 
 114    // returns true if (async) dialing is in progress 
 115    virtual bool IsDialing() const 
 116       { return m_DialProcess 
!= NULL
; } 
 118    // cancel dialing the number initiated with Dial(async = true) 
 119    // NB: this won't result in DISCONNECTED event being sent 
 120    virtual bool CancelDialing(); 
 122    size_t GetISPNames(class wxArrayString 
&) const 
 125    // sometimes the built-in logic for determining the online status may fail, 
 126    // so, in general, the user should be allowed to override it. This function 
 127    // allows to forcefully set the online status - whatever our internal 
 128    // algorithm may think about it. 
 129    virtual void SetOnlineStatus(bool isOnline 
= true) 
 130       { m_IsOnline 
= isOnline 
? Net_Connected 
: Net_No
; } 
 132    // set misc wxDialUpManager options 
 133    // -------------------------------- 
 135    // enable automatical checks for the connection status and sending of 
 136    // wxEVT_DIALUP_CONNECTED/wxEVT_DIALUP_DISCONNECTED events. The interval 
 137    // parameter is only for Unix where we do the check manually: under 
 138    // Windows, the notification about the change of connection status is 
 141    // Returns false if couldn't set up automatic check for online status. 
 142    virtual bool EnableAutoCheckOnlineStatus(size_t nSeconds
); 
 144    // disable automatic check for connection status change - notice that the 
 145    // wxEVT_DIALUP_XXX events won't be sent any more neither. 
 146    virtual void DisableAutoCheckOnlineStatus(); 
 148    // under Unix, the value of well-known host is used to check whether we're 
 149    // connected to the internet. It's unused under Windows, but this function 
 150    // is always safe to call. The default value is www.yahoo.com. 
 151    virtual void SetWellKnownHost(const wxString
& hostname
, 
 153    /** Sets the commands to start up the network and to hang up 
 154        again. Used by the Unix implementations only. 
 156    virtual void SetConnectCommand(const wxString 
&command
, const wxString 
&hupcmd
) 
 157       { m_ConnectCommand 
= command
; m_HangUpCommand 
= hupcmd
; } 
 159 //private: -- Sun CC 4.2 objects to using NetConnection enum as the return 
 160 //            type if it is declared private 
 162    // the possible results of testing for Online() status 
 165        Net_Unknown 
= -1,    // we couldn't learn anything 
 166        Net_No
,              // no network connection [currently] 
 167        Net_Connected        
// currently connected 
 170    // the possible net connection types 
 173        NetDevice_None    
= 0x0000,  // no network devices (authoritative) 
 174        NetDevice_Unknown 
= 0x0001,  // test doesn't work on this OS 
 175        NetDevice_Modem   
= 0x0002,  // we have a modem 
 176        NetDevice_LAN     
= 0x0004   //         a network card 
 180    // the current status 
 181    NetConnection m_IsOnline
; 
 183    // the connection we have with the network card 
 184    NetConnection m_connCard
; 
 186    // Can we use ifconfig to list active devices? 
 187    int m_CanUseIfconfig
; 
 189    // The path to ifconfig 
 190    wxString m_IfconfigPath
; 
 192    //  Can we use ping to find hosts? 
 194    // The path to ping program 
 198    wxString m_BeaconHost
; 
 199    // beacon host portnumber for connect: 
 202    // command to connect to network 
 203    wxString m_ConnectCommand
; 
 204    // command to hang up 
 205    wxString m_HangUpCommand
; 
 208    // a timer for regular testing 
 209    class AutoCheckTimer 
*m_timer
; 
 210    friend class AutoCheckTimer
; 
 212    // a wxProcess for dialling in background 
 213    class wxDialProcess 
*m_DialProcess
; 
 214    // pid of dial process 
 216    friend class wxDialProcess
; 
 219    void CheckStatus(bool fromAsync 
= false) const; 
 222    void CheckStatusInternal(); 
 224    // check /proc/net (Linux only) for ppp/eth interfaces, returns the bit 
 225    // mask of NetDeviceType constants 
 228    // check output of ifconfig command for PPP/SLIP/PLIP devices, returns the 
 229    // bit mask of NetDeviceType constants 
 232    // combines the 2 possible checks for determining the connection status 
 233    NetConnection 
CheckConnectAndPing(); 
 236    NetConnection 
CheckPing(); 
 238    // check by connecting to host on given port. 
 239    NetConnection 
CheckConnect(); 
 243 class AutoCheckTimer 
: public wxTimer
 
 246    AutoCheckTimer(wxDialUpManagerImpl 
*dupman
) 
 251    virtual void Notify() 
 253        wxLogTrace(_T("dialup"), wxT("Checking dial up network status.")); 
 255        m_dupman
->CheckStatus(); 
 259    wxDialUpManagerImpl 
*m_dupman
; 
 262 class wxDialProcess 
: public wxProcess
 
 265    wxDialProcess(wxDialUpManagerImpl 
*dupman
) 
 269    void Disconnect() { m_DupMan 
= NULL
; } 
 270    virtual void OnTerminate(int WXUNUSED(pid
), int WXUNUSED(status
)) 
 274             m_DupMan
->m_DialProcess 
= NULL
; 
 275             m_DupMan
->CheckStatus(true); 
 279       wxDialUpManagerImpl 
*m_DupMan
; 
 283 wxDialUpManagerImpl::wxDialUpManagerImpl() 
 286    m_connCard 
= Net_Unknown
; 
 287    m_DialProcess 
= NULL
; 
 289    m_CanUseIfconfig 
= -1; // unknown 
 290    m_CanUsePing 
= -1; // unknown 
 291    m_BeaconHost 
= WXDIALUP_MANAGER_DEFAULT_BEACONHOST
; 
 295    m_ConnectCommand 
= _T("/usr/etc/ppp"); 
 296 #elif defined(__LINUX__) 
 297    // default values for Debian/GNU linux 
 298    m_ConnectCommand 
= _T("pon"); 
 299    m_HangUpCommand 
= _T("poff"); 
 302    wxChar 
* dial 
= wxGetenv(_T("WXDIALUP_DIALCMD")); 
 303    wxChar 
* hup 
= wxGetenv(_T("WXDIALUP_HUPCMD")); 
 304    SetConnectCommand(dial 
? wxString(dial
) : m_ConnectCommand
, 
 305                      hup 
? wxString(hup
) : m_HangUpCommand
); 
 308 wxDialUpManagerImpl::~wxDialUpManagerImpl() 
 310    if(m_timer
) delete m_timer
; 
 313       m_DialProcess
->Disconnect(); 
 314       m_DialProcess
->Detach(); 
 319 wxDialUpManagerImpl::Dial(const wxString 
&isp
, 
 320                           const wxString 
& WXUNUSED(username
), 
 321                           const wxString 
& WXUNUSED(password
), 
 324     if(m_IsOnline 
== Net_Connected
) 
 328     if(m_ConnectCommand
.Find(wxT("%s"))) 
 329         cmd
.Printf(m_ConnectCommand
,m_ISPname
.c_str()); 
 331         cmd 
= m_ConnectCommand
; 
 335         m_DialProcess 
= new wxDialProcess(this); 
 336         m_DialPId 
= (int)wxExecute(cmd
, false, m_DialProcess
); 
 339             delete m_DialProcess
; 
 340             m_DialProcess 
= NULL
; 
 347         return wxExecute(cmd
, /* sync */ true) == 0; 
 350 bool wxDialUpManagerImpl::HangUp() 
 352     if(m_IsOnline 
== Net_No
) 
 356         wxLogError(_("Already dialling ISP.")); 
 360     if(m_HangUpCommand
.Find(wxT("%s"))) 
 361         cmd
.Printf(m_HangUpCommand
,m_ISPname
.c_str(), m_DialProcess
); 
 363         cmd 
= m_HangUpCommand
; 
 364     return wxExecute(cmd
, /* sync */ true) == 0; 
 368 bool wxDialUpManagerImpl::CancelDialing() 
 372    return kill(m_DialPId
, SIGTERM
) > 0; 
 375 bool wxDialUpManagerImpl::EnableAutoCheckOnlineStatus(size_t nSeconds
) 
 377    DisableAutoCheckOnlineStatus(); 
 378    m_timer 
= new AutoCheckTimer(this); 
 379    bool rc 
= m_timer
->Start(nSeconds
*1000); 
 388 void wxDialUpManagerImpl::DisableAutoCheckOnlineStatus() 
 399 void wxDialUpManagerImpl::SetWellKnownHost(const wxString
& hostname
, int portno
) 
 401    if(hostname
.length() == 0) 
 403       m_BeaconHost 
= WXDIALUP_MANAGER_DEFAULT_BEACONHOST
; 
 408    // does hostname contain a port number? 
 409    wxString port 
= hostname
.After(wxT(':')); 
 412       m_BeaconHost 
= hostname
.Before(wxT(':')); 
 413       m_BeaconPort 
= wxAtoi(port
); 
 417       m_BeaconHost 
= hostname
; 
 418       m_BeaconPort 
= portno
; 
 423 void wxDialUpManagerImpl::CheckStatus(bool fromAsync
) const 
 425     // This function calls the CheckStatusInternal() helper function 
 426     // which is OS - specific and then sends the events. 
 428     NetConnection oldIsOnline 
= m_IsOnline
; 
 429     ( /* non-const */ (wxDialUpManagerImpl 
*)this)->CheckStatusInternal(); 
 431     // now send the events as appropriate: i.e. if the status changed and 
 432     // if we're in defined state 
 433     if(m_IsOnline 
!= oldIsOnline
 
 434             && m_IsOnline 
!= Net_Unknown
 
 435             && oldIsOnline 
!= Net_Unknown 
) 
 437         wxDialUpEvent 
event(m_IsOnline 
== Net_Connected
, ! fromAsync
); 
 438         (void)wxTheApp
->ProcessEvent(event
); 
 443    We first try to find out if ppp interface is active. If it is, we assume 
 444    that we're online but don't have a permanent connection (this is false if a 
 445    networked machine uses modem to connect to somewhere else, but we can't do 
 446    anything in this case anyhow). 
 448    If no ppp interface is detected, we check for eth interface. If it is 
 449    found, we check that we can, indeed, connect to an Internet host. The logic 
 450    here is that connection check should be fast enough in this case and we 
 451    don't want to give false positives in a (common) case of a machine on a LAN 
 452    which is not connected to the outside. 
 454    If we didn't find either ppp or eth interfaces, we stop here and decide 
 455    that we're connected. However, if couldn't check for this, we try to ping a 
 456    remote host just in case. 
 458    NB1: Checking for the interface presence can be done in 2 ways 
 459         a) reading /proc/net/dev under Linux 
 460         b) spawning ifconfig under any OS 
 462         The first method is faster but only works under Linux. 
 464    NB2: pinging, actually, means that we first try to connect "manually" to 
 465         a port on remove machine and if it fails, we run ping. 
 468 void wxDialUpManagerImpl::CheckStatusInternal() 
 470     m_IsOnline 
= Net_Unknown
; 
 472     // first do quick checks to determine what kind of network devices do we 
 474     int netDeviceType 
= CheckProcNet(); 
 475     if ( netDeviceType 
== NetDevice_Unknown 
) 
 477         // nothing found, try ifconfig too 
 478         netDeviceType 
= CheckIfconfig(); 
 481     switch ( netDeviceType 
) 
 484             // no network devices, no connection 
 489             // we still do ping to confirm that we're connected but we only do 
 490             // it once and hope that the purpose of the network card (i.e. 
 491             // whether it used for connecting to the Internet or just to a 
 492             // LAN) won't change during the program lifetime 
 493             if ( m_connCard 
== Net_Unknown 
) 
 495                 m_connCard 
= CheckConnectAndPing(); 
 497             m_IsOnline 
= m_connCard
; 
 500         case NetDevice_Unknown
: 
 501             // try to ping just in case 
 502             m_IsOnline 
= CheckConnectAndPing(); 
 505         case NetDevice_LAN 
+ NetDevice_Modem
: 
 506         case NetDevice_Modem
: 
 507             // assume we're connected 
 508             m_IsOnline 
= Net_Connected
; 
 512             wxFAIL_MSG(_T("Unexpected netDeviceType")); 
 516 bool wxDialUpManagerImpl::IsAlwaysOnline() const 
 518     wxDialUpManagerImpl 
*self 
= wxConstCast(this, wxDialUpManagerImpl
); 
 520     int netDeviceType 
= self
->CheckProcNet(); 
 521     if ( netDeviceType 
== NetDevice_Unknown 
) 
 523         // nothing found, try ifconfig too 
 524         netDeviceType 
= self
->CheckIfconfig(); 
 527     if ( netDeviceType 
== NetDevice_Unknown 
) 
 529         // this is the only thing we can do unfortunately... 
 535         // we are only permanently online if we have a network card 
 536         return (netDeviceType 
& NetDevice_LAN
) != 0; 
 540 wxDialUpManagerImpl::NetConnection 
wxDialUpManagerImpl::CheckConnectAndPing() 
 544     // first try connecting - faster 
 545     conn 
= CheckConnect(); 
 546     if ( conn 
== Net_Unknown 
) 
 555 wxDialUpManagerImpl::NetConnection 
wxDialUpManagerImpl::CheckConnect() 
 557    // second method: try to connect to a well known host: 
 558    // This can be used under Win 9x, too! 
 560    struct sockaddr_in  serv_addr
; 
 562    if((hp 
= gethostbyname(m_BeaconHost
.mb_str())) == NULL
) 
 563       return Net_No
; // no DNS no net 
 565    serv_addr
.sin_family 
= hp
->h_addrtype
; 
 566    memcpy(&serv_addr
.sin_addr
,hp
->h_addr
, hp
->h_length
); 
 567    serv_addr
.sin_port 
= htons(m_BeaconPort
); 
 570    if( ( sockfd 
= socket(hp
->h_addrtype
, SOCK_STREAM
, 0)) < 0) 
 572       return Net_Unknown
;  // no info 
 575    if( connect(sockfd
, (struct sockaddr 
*) &serv_addr
, 
 576                sizeof(serv_addr
)) >= 0) 
 579       return Net_Connected
; // we can connect, so we have a network! 
 581    else // failed to connect 
 584        if(errno 
== ENETUNREACH
) 
 585           return Net_No
; // network is unreachable 
 588           return Net_Unknown
; // connect failed, but don't know why 
 594 wxDialUpManagerImpl::CheckProcNet() 
 596     // assume that the test doesn't work 
 597     int netDevice 
= NetDevice_Unknown
; 
 600     if (wxFileExists(_T("/proc/net/route"))) 
 602         // cannot use wxFile::Length because file doesn't support seeking, so 
 603         // use stdio directly 
 604         FILE *f 
= fopen("/proc/net/route", "rt"); 
 607             // now we know that we will find all devices we may have 
 608             netDevice 
= NetDevice_None
; 
 612             while (fgets(output
, 256, f
) != NULL
) 
 614                 if ( strstr(output
, "eth") ) // network card 
 616                     netDevice 
|= NetDevice_LAN
; 
 618                 else if (strstr(output
,"ppp")   // ppp 
 619                         || strstr(output
,"sl")  // slip 
 620                         || strstr(output
,"pl")) // plip 
 622                     netDevice 
|= NetDevice_Modem
; 
 636 wxDialUpManagerImpl::CheckIfconfig() 
 639     m_CanUseIfconfig 
= 0; 
 642     // assume that the test doesn't work 
 643     int netDevice 
= NetDevice_Unknown
; 
 645     // first time check for ifconfig location 
 646     if ( m_CanUseIfconfig 
== -1 ) // unknown 
 648         static const wxChar 
*ifconfigLocations
[] = 
 650             _T("/sbin"),         // Linux, FreeBSD, Darwin 
 651             _T("/usr/sbin"),     // SunOS, Solaris, AIX, HP-UX 
 652             _T("/usr/etc"),      // IRIX 
 656         for ( size_t n 
= 0; n 
< WXSIZEOF(ifconfigLocations
); n
++ ) 
 658             wxString 
path(ifconfigLocations
[n
]); 
 659             path 
<< _T("/ifconfig"); 
 661             if ( wxFileExists(path
) ) 
 663                 m_IfconfigPath 
= path
; 
 669     if ( m_CanUseIfconfig 
!= 0 ) // unknown or yes 
 671         wxLogNull ln
; // suppress all error messages 
 673         wxASSERT_MSG( m_IfconfigPath
.length(), 
 674                       _T("can't use ifconfig if it wasn't found") ); 
 676         wxString tmpfile 
= wxGetTempFileName( wxT("_wxdialuptest") ); 
 677         wxString cmd 
= wxT("/bin/sh -c \'"); 
 678         cmd 
<< m_IfconfigPath
; 
 679 #if defined(__AIX__) || \ 
 680     defined(__OSF__) || \ 
 681     defined(__SOLARIS__) || defined (__SUNOS__) 
 682         // need to add -a flag 
 684 #elif defined(__LINUX__) || defined(__SGI__) 
 685         // nothing to be added to ifconfig 
 686 #elif defined(__FREEBSD__) || defined(__DARWIN__) 
 689 #elif defined(__HPUX__) 
 690         // VZ: a wild guess (but without it, ifconfig fails completely) 
 693         #if defined(__GNUG__) 
 694             #warning "No ifconfig information for this OS." 
 696             #pragma warning "No ifconfig information for this OS." 
 699         m_CanUseIfconfig 
= 0; 
 702        cmd 
<< wxT(" >") << tmpfile 
<<  wxT('\''); 
 703         /* I tried to add an option to wxExecute() to not close stdout, 
 704            so we could let ifconfig write directly to the tmpfile, but 
 705            this does not work. That should be faster, as it doesn´t call 
 706            the shell first. I have no idea why. :-(  (KB) */ 
 707         if ( wxExecute(cmd
,true /* sync */) == 0 ) 
 709             m_CanUseIfconfig 
= 1; 
 711             if( file
.Open(tmpfile
) ) 
 714                 if ( file
.ReadAll(&output
) ) 
 716                     // FIXME shouldn't we grep for "^ppp"? (VZ) 
 718                     bool hasModem 
= false, 
 721 #if defined(__SOLARIS__) || defined (__SUNOS__) 
 722                     // dialup device under SunOS/Solaris 
 723                     hasModem 
= strstr(output
.fn_str(),"ipdptp") != (char *)NULL
; 
 724                     hasLAN 
= strstr(output
.fn_str(), "hme") != (char *)NULL
; 
 725 #elif defined(__LINUX__) || defined (__FREEBSD__) 
 726                     hasModem 
= strstr(output
.fn_str(),"ppp")    // ppp 
 727                         || strstr(output
.fn_str(),"sl")  // slip 
 728                         || strstr(output
.fn_str(),"pl"); // plip 
 729                     hasLAN 
= strstr(output
.fn_str(), "eth") != NULL
; 
 730 #elif defined(__SGI__)  // IRIX 
 731                     hasModem 
= strstr(output
.fn_str(), "ppp") != NULL
; // PPP 
 732 #elif defined(__HPUX__) 
 733                     // if could run ifconfig on interface, then it exists 
 737                     netDevice 
= NetDevice_None
; 
 739                         netDevice 
|= NetDevice_Modem
; 
 741                         netDevice 
|= NetDevice_LAN
; 
 743                 //else: error reading the file 
 745             //else: error opening the file 
 747         else // could not run ifconfig correctly 
 749             m_CanUseIfconfig 
= 0; // don´t try again 
 752         (void) wxRemoveFile(tmpfile
); 
 759 wxDialUpManagerImpl::NetConnection 
wxDialUpManagerImpl::CheckPing() 
 761     // First time check for ping location. We only use the variant 
 762     // which does not take arguments, a la GNU. 
 763     if(m_CanUsePing 
== -1) // unknown 
 766         if (wxFileExists( wxT("SYS$SYSTEM:TCPIP$PING.EXE") )) 
 767             m_PingPath 
= wxT("$SYS$SYSTEM:TCPIP$PING"); 
 768 #elif defined(__AIX__) 
 769         m_PingPath 
= _T("/etc/ping"); 
 770 #elif defined(__SGI__) 
 771         m_PingPath 
= _T("/usr/etc/ping"); 
 773         if (wxFileExists( wxT("/bin/ping") )) 
 774             m_PingPath 
= wxT("/bin/ping"); 
 775         else if (wxFileExists( wxT("/usr/sbin/ping") )) 
 776             m_PingPath 
= wxT("/usr/sbin/ping"); 
 786        // we didn't find ping 
 790     wxLogNull ln
; // suppress all error messages 
 791     wxASSERT(m_PingPath
.length()); 
 793     cmd 
<< m_PingPath 
<< wxT(' '); 
 794 #if defined(__SOLARIS__) || defined (__SUNOS__) 
 795     // nothing to add to ping command 
 796 #elif defined(__AIX__) || \ 
 797       defined (__BSD__) || \ 
 798       defined(__LINUX__) || \ 
 799       defined(__OSF__) || \ 
 800       defined(__SGI__) || \ 
 802     cmd 
<< wxT("-c 1 "); // only ping once 
 803 #elif defined(__HPUX__) 
 804     cmd 
<< wxT("64 1 "); // only ping once (need also specify the packet size) 
 806     #if defined(__GNUG__) 
 807         #warning "No Ping information for this OS." 
 809         #pragma warning "No Ping information for this OS." 
 816     if(wxExecute(cmd
, true /* sync */) == 0) 
 817         return Net_Connected
; 
 823 wxDialUpManager 
*wxDialUpManager::Create() 
 825    return new wxDialUpManagerImpl
; 
 828 #endif // wxUSE_DIALUP_MANAGER