]> git.saurik.com Git - wxWidgets.git/blob - src/palmos/dialup.cpp
Nicer and longer fading.
[wxWidgets.git] / src / palmos / dialup.cpp
1 /////////////////////////////////////////////////////////////////////////////
2 // Name: palmos/dialup.cpp
3 // Purpose: Palm OS implementation of network/dialup classes and functions
4 // Author: Vadim Zeitlin
5 // Modified by:
6 // Created: 07.07.99
7 // RCS-ID: $Id$
8 // Copyright: (c) Vadim Zeitlin
9 // Licence: wxWindows licence
10 /////////////////////////////////////////////////////////////////////////////
11
12 // ============================================================================
13 // declarations
14 // ============================================================================
15
16 // ----------------------------------------------------------------------------
17 // headers
18 // ----------------------------------------------------------------------------
19
20 // for compilers that support precompilation, includes "wx.h".
21 #include "wx/wxprec.h"
22
23 #ifdef __BORLANDC__
24 #pragma hdrstop
25 #endif
26
27 #if wxUSE_DIALUP_MANAGER
28
29 #ifndef WX_PRECOMP
30 #include "wx/log.h"
31 #include "wx/intl.h"
32 #include "wx/event.h"
33 #endif
34
35 #include "wx/timer.h"
36 #include "wx/app.h"
37 #include "wx/generic/choicdgg.h"
38
39 #include "wx/dynlib.h"
40 #include "wx/dialup.h"
41
42 DEFINE_EVENT_TYPE(wxEVT_DIALUP_CONNECTED)
43 DEFINE_EVENT_TYPE(wxEVT_DIALUP_DISCONNECTED)
44
45 // This needs to be written using Palm OS Network API calls, but for now this
46 // will do.
47 #if (!defined(__PALMOS__)
48
49 #include <ras.h>
50 #include <raserror.h>
51
52 #include <wininet.h>
53
54 // Not in VC++ 5
55 #ifndef INTERNET_CONNECTION_LAN
56 #define INTERNET_CONNECTION_LAN 2
57 #endif
58 #ifndef INTERNET_CONNECTION_PROXY
59 #define INTERNET_CONNECTION_PROXY 4
60 #endif
61
62 // ----------------------------------------------------------------------------
63 // constants
64 // ----------------------------------------------------------------------------
65
66 // this message is sent by the secondary thread when RAS status changes
67 #define wxWM_RAS_STATUS_CHANGED (WM_USER + 10010)
68 #define wxWM_RAS_DIALING_PROGRESS (WM_USER + 10011)
69
70 // ----------------------------------------------------------------------------
71 // types
72 // ----------------------------------------------------------------------------
73
74 // the signatures of RAS functions: all this is quite heavy, but we must do it
75 // to allow running wxWin programs on machine which don't have RAS installed
76 // (this does exist) - if we link with rasapi32.lib, the program will fail on
77 // startup because of the missing DLL...
78
79 #ifndef UNICODE
80 typedef DWORD (APIENTRY * RASDIAL)( LPRASDIALEXTENSIONS, LPCSTR, LPRASDIALPARAMSA, DWORD, LPVOID, LPHRASCONN );
81 typedef DWORD (APIENTRY * RASENUMCONNECTIONS)( LPRASCONNA, LPDWORD, LPDWORD );
82 typedef DWORD (APIENTRY * RASENUMENTRIES)( LPCSTR, LPCSTR, LPRASENTRYNAMEA, LPDWORD, LPDWORD );
83 typedef DWORD (APIENTRY * RASGETCONNECTSTATUS)( HRASCONN, LPRASCONNSTATUSA );
84 typedef DWORD (APIENTRY * RASGETERRORSTRING)( UINT, LPSTR, DWORD );
85 typedef DWORD (APIENTRY * RASHANGUP)( HRASCONN );
86 typedef DWORD (APIENTRY * RASGETPROJECTIONINFO)( HRASCONN, RASPROJECTION, LPVOID, LPDWORD );
87 typedef DWORD (APIENTRY * RASCREATEPHONEBOOKENTRY)( HWND, LPCSTR );
88 typedef DWORD (APIENTRY * RASEDITPHONEBOOKENTRY)( HWND, LPCSTR, LPCSTR );
89 typedef DWORD (APIENTRY * RASSETENTRYDIALPARAMS)( LPCSTR, LPRASDIALPARAMSA, BOOL );
90 typedef DWORD (APIENTRY * RASGETENTRYDIALPARAMS)( LPCSTR, LPRASDIALPARAMSA, LPBOOL );
91 typedef DWORD (APIENTRY * RASENUMDEVICES)( LPRASDEVINFOA, LPDWORD, LPDWORD );
92 typedef DWORD (APIENTRY * RASGETCOUNTRYINFO)( LPRASCTRYINFOA, LPDWORD );
93 typedef DWORD (APIENTRY * RASGETENTRYPROPERTIES)( LPCSTR, LPCSTR, LPRASENTRYA, LPDWORD, LPBYTE, LPDWORD );
94 typedef DWORD (APIENTRY * RASSETENTRYPROPERTIES)( LPCSTR, LPCSTR, LPRASENTRYA, DWORD, LPBYTE, DWORD );
95 typedef DWORD (APIENTRY * RASRENAMEENTRY)( LPCSTR, LPCSTR, LPCSTR );
96 typedef DWORD (APIENTRY * RASDELETEENTRY)( LPCSTR, LPCSTR );
97 typedef DWORD (APIENTRY * RASVALIDATEENTRYNAME)( LPCSTR, LPCSTR );
98 typedef DWORD (APIENTRY * RASCONNECTIONNOTIFICATION)( HRASCONN, HANDLE, DWORD );
99
100 static const wxChar gs_funcSuffix = _T('A');
101 #else // Unicode
102 typedef DWORD (APIENTRY * RASDIAL)( LPRASDIALEXTENSIONS, LPCWSTR, LPRASDIALPARAMSW, DWORD, LPVOID, LPHRASCONN );
103 typedef DWORD (APIENTRY * RASENUMCONNECTIONS)( LPRASCONNW, LPDWORD, LPDWORD );
104 typedef DWORD (APIENTRY * RASENUMENTRIES)( LPCWSTR, LPCWSTR, LPRASENTRYNAMEW, LPDWORD, LPDWORD );
105 typedef DWORD (APIENTRY * RASGETCONNECTSTATUS)( HRASCONN, LPRASCONNSTATUSW );
106 typedef DWORD (APIENTRY * RASGETERRORSTRING)( UINT, LPWSTR, DWORD );
107 typedef DWORD (APIENTRY * RASHANGUP)( HRASCONN );
108 typedef DWORD (APIENTRY * RASGETPROJECTIONINFO)( HRASCONN, RASPROJECTION, LPVOID, LPDWORD );
109 typedef DWORD (APIENTRY * RASCREATEPHONEBOOKENTRY)( HWND, LPCWSTR );
110 typedef DWORD (APIENTRY * RASEDITPHONEBOOKENTRY)( HWND, LPCWSTR, LPCWSTR );
111 typedef DWORD (APIENTRY * RASSETENTRYDIALPARAMS)( LPCWSTR, LPRASDIALPARAMSW, BOOL );
112 typedef DWORD (APIENTRY * RASGETENTRYDIALPARAMS)( LPCWSTR, LPRASDIALPARAMSW, LPBOOL );
113 typedef DWORD (APIENTRY * RASENUMDEVICES)( LPRASDEVINFOW, LPDWORD, LPDWORD );
114 typedef DWORD (APIENTRY * RASGETCOUNTRYINFO)( LPRASCTRYINFOW, LPDWORD );
115 typedef DWORD (APIENTRY * RASGETENTRYPROPERTIES)( LPCWSTR, LPCWSTR, LPRASENTRYW, LPDWORD, LPBYTE, LPDWORD );
116 typedef DWORD (APIENTRY * RASSETENTRYPROPERTIES)( LPCWSTR, LPCWSTR, LPRASENTRYW, DWORD, LPBYTE, DWORD );
117 typedef DWORD (APIENTRY * RASRENAMEENTRY)( LPCWSTR, LPCWSTR, LPCWSTR );
118 typedef DWORD (APIENTRY * RASDELETEENTRY)( LPCWSTR, LPCWSTR );
119 typedef DWORD (APIENTRY * RASVALIDATEENTRYNAME)( LPCWSTR, LPCWSTR );
120 typedef DWORD (APIENTRY * RASCONNECTIONNOTIFICATION)( HRASCONN, HANDLE, DWORD );
121
122 static const wxChar gs_funcSuffix = _T('W');
123 #endif // ASCII/Unicode
124
125 // structure passed to the secondary thread
126 struct WXDLLEXPORT wxRasThreadData
127 {
128 wxRasThreadData()
129 {
130 hWnd = 0;
131 hEventRas =
132 hEventQuit = 0;
133 dialUpManager = NULL;
134 }
135
136 ~wxRasThreadData()
137 {
138 if ( hWnd )
139 DestroyWindow(hWnd);
140
141 if ( hEventQuit )
142 CloseHandle(hEventQuit);
143
144 if ( hEventRas )
145 CloseHandle(hEventRas);
146 }
147
148 HWND hWnd; // window to send notifications to
149 HANDLE hEventRas, // automatic event which RAS signals when status changes
150 hEventQuit; // manual event which we signal when we terminate
151
152 class WXDLLEXPORT wxDialUpManagerMSW *dialUpManager; // the owner
153 };
154
155 // ----------------------------------------------------------------------------
156 // wxDialUpManager class for MSW
157 // ----------------------------------------------------------------------------
158
159 class WXDLLEXPORT wxDialUpManagerMSW : public wxDialUpManager
160 {
161 public:
162 // ctor & dtor
163 wxDialUpManagerMSW();
164 virtual ~wxDialUpManagerMSW();
165
166 // implement base class pure virtuals
167 virtual bool IsOk() const;
168 virtual size_t GetISPNames(wxArrayString& names) const;
169 virtual bool Dial(const wxString& nameOfISP,
170 const wxString& username,
171 const wxString& password,
172 bool async);
173 virtual bool IsDialing() const;
174 virtual bool CancelDialing();
175 virtual bool HangUp();
176 virtual bool IsAlwaysOnline() const;
177 virtual bool IsOnline() const;
178 virtual void SetOnlineStatus(bool isOnline = TRUE);
179 virtual bool EnableAutoCheckOnlineStatus(size_t nSeconds);
180 virtual void DisableAutoCheckOnlineStatus();
181 virtual void SetWellKnownHost(const wxString& hostname, int port);
182 virtual void SetConnectCommand(const wxString& commandDial,
183 const wxString& commandHangup);
184
185 // for RasTimer
186 void CheckRasStatus();
187
188 // for wxRasStatusWindowProc
189 void OnConnectStatusChange();
190 void OnDialProgress(RASCONNSTATE rasconnstate, DWORD dwError);
191
192 // for wxRasDialFunc
193 static HWND GetRasWindow() { return ms_hwndRas; }
194 static wxDialUpManagerMSW *GetDialer() { return ms_dialer; }
195
196 private:
197 // return the error string for the given RAS error code
198 static wxString GetErrorString(DWORD error);
199
200 // find the (first) handle of the active connection
201 static HRASCONN FindActiveConnection();
202
203 // notify the application about status change
204 void NotifyApp(bool connected, bool fromOurselves = FALSE) const;
205
206 // destroy the thread data and the thread itself
207 void CleanUpThreadData();
208
209 // number of times EnableAutoCheckOnlineStatus() had been called minus the
210 // number of times DisableAutoCheckOnlineStatus() had been called
211 int m_autoCheckLevel;
212
213 // timer used for polling RAS status
214 class WXDLLEXPORT RasTimer : public wxTimer
215 {
216 public:
217 RasTimer(wxDialUpManagerMSW *dialUpManager)
218 { m_dialUpManager = dialUpManager; }
219
220 virtual void Notify() { m_dialUpManager->CheckRasStatus(); }
221
222 private:
223 wxDialUpManagerMSW *m_dialUpManager;
224
225 DECLARE_NO_COPY_CLASS(RasTimer)
226 } m_timerStatusPolling;
227
228 // thread handle for the thread sitting on connection change event
229 HANDLE m_hThread;
230
231 // data used by this thread and our hidden window to send messages between
232 // each other
233 wxRasThreadData *m_data;
234
235 // the handle of rasapi32.dll when it's loaded
236 wxDynamicLibrary m_dllRas;
237
238 // the hidden window we use for passing messages between threads
239 static HWND ms_hwndRas;
240
241 // the handle of the connection we initiated or 0 if none
242 static HRASCONN ms_hRasConnection;
243
244 // the pointers to RAS functions
245 static RASDIAL ms_pfnRasDial;
246 static RASENUMCONNECTIONS ms_pfnRasEnumConnections;
247 static RASENUMENTRIES ms_pfnRasEnumEntries;
248 static RASGETCONNECTSTATUS ms_pfnRasGetConnectStatus;
249 static RASGETERRORSTRING ms_pfnRasGetErrorString;
250 static RASHANGUP ms_pfnRasHangUp;
251 static RASGETPROJECTIONINFO ms_pfnRasGetProjectionInfo;
252 static RASCREATEPHONEBOOKENTRY ms_pfnRasCreatePhonebookEntry;
253 static RASEDITPHONEBOOKENTRY ms_pfnRasEditPhonebookEntry;
254 static RASSETENTRYDIALPARAMS ms_pfnRasSetEntryDialParams;
255 static RASGETENTRYDIALPARAMS ms_pfnRasGetEntryDialParams;
256 static RASENUMDEVICES ms_pfnRasEnumDevices;
257 static RASGETCOUNTRYINFO ms_pfnRasGetCountryInfo;
258 static RASGETENTRYPROPERTIES ms_pfnRasGetEntryProperties;
259 static RASSETENTRYPROPERTIES ms_pfnRasSetEntryProperties;
260 static RASRENAMEENTRY ms_pfnRasRenameEntry;
261 static RASDELETEENTRY ms_pfnRasDeleteEntry;
262 static RASVALIDATEENTRYNAME ms_pfnRasValidateEntryName;
263
264 // this function is not supported by Win95
265 static RASCONNECTIONNOTIFICATION ms_pfnRasConnectionNotification;
266
267 // if this flag is different from -1, it overrides IsOnline()
268 static int ms_userSpecifiedOnlineStatus;
269
270 // this flag tells us if we're online
271 static int ms_isConnected;
272
273 // this flag tells us whether a call to RasDial() is in progress
274 static wxDialUpManagerMSW *ms_dialer;
275
276 DECLARE_NO_COPY_CLASS(wxDialUpManagerMSW)
277 };
278
279 // ----------------------------------------------------------------------------
280 // private functions
281 // ----------------------------------------------------------------------------
282
283 static LRESULT WINAPI wxRasStatusWindowProc(HWND hWnd, UINT message,
284 WPARAM wParam, LPARAM lParam);
285
286 static DWORD wxRasMonitorThread(wxRasThreadData *data);
287
288 static void WINAPI wxRasDialFunc(UINT unMsg,
289 RASCONNSTATE rasconnstate,
290 DWORD dwError);
291
292 // ============================================================================
293 // implementation
294 // ============================================================================
295
296 // ----------------------------------------------------------------------------
297 // init the static variables
298 // ----------------------------------------------------------------------------
299
300 HRASCONN wxDialUpManagerMSW::ms_hRasConnection = 0;
301
302 HWND wxDialUpManagerMSW::ms_hwndRas = 0;
303
304 RASDIAL wxDialUpManagerMSW::ms_pfnRasDial = 0;
305 RASENUMCONNECTIONS wxDialUpManagerMSW::ms_pfnRasEnumConnections = 0;
306 RASENUMENTRIES wxDialUpManagerMSW::ms_pfnRasEnumEntries = 0;
307 RASGETCONNECTSTATUS wxDialUpManagerMSW::ms_pfnRasGetConnectStatus = 0;
308 RASGETERRORSTRING wxDialUpManagerMSW::ms_pfnRasGetErrorString = 0;
309 RASHANGUP wxDialUpManagerMSW::ms_pfnRasHangUp = 0;
310 RASGETPROJECTIONINFO wxDialUpManagerMSW::ms_pfnRasGetProjectionInfo = 0;
311 RASCREATEPHONEBOOKENTRY wxDialUpManagerMSW::ms_pfnRasCreatePhonebookEntry = 0;
312 RASEDITPHONEBOOKENTRY wxDialUpManagerMSW::ms_pfnRasEditPhonebookEntry = 0;
313 RASSETENTRYDIALPARAMS wxDialUpManagerMSW::ms_pfnRasSetEntryDialParams = 0;
314 RASGETENTRYDIALPARAMS wxDialUpManagerMSW::ms_pfnRasGetEntryDialParams = 0;
315 RASENUMDEVICES wxDialUpManagerMSW::ms_pfnRasEnumDevices = 0;
316 RASGETCOUNTRYINFO wxDialUpManagerMSW::ms_pfnRasGetCountryInfo = 0;
317 RASGETENTRYPROPERTIES wxDialUpManagerMSW::ms_pfnRasGetEntryProperties = 0;
318 RASSETENTRYPROPERTIES wxDialUpManagerMSW::ms_pfnRasSetEntryProperties = 0;
319 RASRENAMEENTRY wxDialUpManagerMSW::ms_pfnRasRenameEntry = 0;
320 RASDELETEENTRY wxDialUpManagerMSW::ms_pfnRasDeleteEntry = 0;
321 RASVALIDATEENTRYNAME wxDialUpManagerMSW::ms_pfnRasValidateEntryName = 0;
322 RASCONNECTIONNOTIFICATION wxDialUpManagerMSW::ms_pfnRasConnectionNotification = 0;
323
324 int wxDialUpManagerMSW::ms_userSpecifiedOnlineStatus = -1;
325 int wxDialUpManagerMSW::ms_isConnected = -1;
326 wxDialUpManagerMSW *wxDialUpManagerMSW::ms_dialer = NULL;
327
328 // ----------------------------------------------------------------------------
329 // ctor and dtor: the dynamic linking happens here
330 // ----------------------------------------------------------------------------
331
332 // the static creator function is implemented here
333 wxDialUpManager *wxDialUpManager::Create()
334 {
335 return new wxDialUpManagerMSW;
336 }
337
338 #ifdef __VISUALC__
339 // warning about "'this' : used in base member initializer list" - so what?
340 #pragma warning(disable:4355)
341 #endif // VC++
342
343 wxDialUpManagerMSW::wxDialUpManagerMSW()
344 : m_timerStatusPolling(this),
345 m_dllRas(_T("RASAPI32"))
346 {
347 // initialize our data
348 m_autoCheckLevel = 0;
349 m_hThread = 0;
350 m_data = new wxRasThreadData;
351
352 if ( !m_dllRas.IsLoaded() )
353 {
354 wxLogError(_("Dial up functions are unavailable because the remote access service (RAS) is not installed on this machine. Please install it."));
355 }
356 else if ( !ms_pfnRasDial )
357 {
358 // resolve the functions we need
359
360 // this will contain the name of the function we failed to resolve
361 // if any at the end
362 const char *funcName = NULL;
363
364 // get the function from rasapi32.dll and abort if it's not found
365 #define RESOLVE_RAS_FUNCTION(type, name) \
366 ms_pfn##name = (type)m_dllRas.GetSymbol( wxString(_T(#name)) \
367 + gs_funcSuffix); \
368 if ( !ms_pfn##name ) \
369 { \
370 funcName = #name; \
371 goto exit; \
372 }
373
374 // a variant of above macro which doesn't abort if the function is
375 // not found in the DLL
376 #define RESOLVE_OPTIONAL_RAS_FUNCTION(type, name) \
377 ms_pfn##name = (type)m_dllRas.GetSymbol( wxString(_T(#name)) \
378 + gs_funcSuffix);
379
380 RESOLVE_RAS_FUNCTION(RASDIAL, RasDial);
381 RESOLVE_RAS_FUNCTION(RASENUMCONNECTIONS, RasEnumConnections);
382 RESOLVE_RAS_FUNCTION(RASENUMENTRIES, RasEnumEntries);
383 RESOLVE_RAS_FUNCTION(RASGETCONNECTSTATUS, RasGetConnectStatus);
384 RESOLVE_RAS_FUNCTION(RASGETERRORSTRING, RasGetErrorString);
385 RESOLVE_RAS_FUNCTION(RASHANGUP, RasHangUp);
386 RESOLVE_RAS_FUNCTION(RASGETENTRYDIALPARAMS, RasGetEntryDialParams);
387
388 // suppress error messages about missing (non essential) functions
389 {
390 wxLogNull noLog;
391
392 RESOLVE_OPTIONAL_RAS_FUNCTION(RASGETPROJECTIONINFO, RasGetProjectionInfo);
393 RESOLVE_OPTIONAL_RAS_FUNCTION(RASCREATEPHONEBOOKENTRY, RasCreatePhonebookEntry);
394 RESOLVE_OPTIONAL_RAS_FUNCTION(RASEDITPHONEBOOKENTRY, RasEditPhonebookEntry);
395 RESOLVE_OPTIONAL_RAS_FUNCTION(RASSETENTRYDIALPARAMS, RasSetEntryDialParams);
396 RESOLVE_OPTIONAL_RAS_FUNCTION(RASGETENTRYPROPERTIES, RasGetEntryProperties);
397 RESOLVE_OPTIONAL_RAS_FUNCTION(RASSETENTRYPROPERTIES, RasSetEntryProperties);
398 RESOLVE_OPTIONAL_RAS_FUNCTION(RASRENAMEENTRY, RasRenameEntry);
399 RESOLVE_OPTIONAL_RAS_FUNCTION(RASDELETEENTRY, RasDeleteEntry);
400 RESOLVE_OPTIONAL_RAS_FUNCTION(RASVALIDATEENTRYNAME, RasValidateEntryName);
401 RESOLVE_OPTIONAL_RAS_FUNCTION(RASGETCOUNTRYINFO, RasGetCountryInfo);
402 RESOLVE_OPTIONAL_RAS_FUNCTION(RASENUMDEVICES, RasEnumDevices);
403 RESOLVE_OPTIONAL_RAS_FUNCTION(RASCONNECTIONNOTIFICATION, RasConnectionNotification);
404 }
405
406 // keep your preprocessor name space clean
407 #undef RESOLVE_RAS_FUNCTION
408 #undef RESOLVE_OPTIONAL_RAS_FUNCTION
409
410 exit:
411 if ( funcName )
412 {
413 static const wxChar *msg = wxTRANSLATE(
414 "The version of remote access service (RAS) installed on this machine is too\
415 old, please upgrade (the following required function is missing: %s)."
416 );
417
418 wxLogError(wxGetTranslation(msg), funcName);
419 m_dllRas.Unload();
420 return;
421 }
422 }
423
424 // enable auto check by default
425 EnableAutoCheckOnlineStatus(0);
426 }
427
428 wxDialUpManagerMSW::~wxDialUpManagerMSW()
429 {
430 CleanUpThreadData();
431 }
432
433 // ----------------------------------------------------------------------------
434 // helper functions
435 // ----------------------------------------------------------------------------
436
437 wxString wxDialUpManagerMSW::GetErrorString(DWORD error)
438 {
439 wxChar buffer[512]; // this should be more than enough according to MS docs
440 DWORD dwRet = ms_pfnRasGetErrorString(error, buffer, WXSIZEOF(buffer));
441 switch ( dwRet )
442 {
443 case ERROR_INVALID_PARAMETER:
444 // this was a standard Win32 error probably
445 return wxString(wxSysErrorMsg(error));
446
447 default:
448 {
449 wxLogSysError(dwRet,
450 _("Failed to retrieve text of RAS error message"));
451
452 wxString msg;
453 msg.Printf(_("unknown error (error code %08x)."), error);
454 return msg;
455 }
456
457 case 0:
458 // we want the error message to start from a lower case letter
459 buffer[0] = wxTolower(buffer[0]);
460
461 return wxString(buffer);
462 }
463 }
464
465 HRASCONN wxDialUpManagerMSW::FindActiveConnection()
466 {
467 // enumerate connections
468 DWORD cbBuf = sizeof(RASCONN);
469 LPRASCONN lpRasConn = (LPRASCONN)malloc(cbBuf);
470 if ( !lpRasConn )
471 {
472 // out of memory
473 return 0;
474 }
475
476 lpRasConn->dwSize = sizeof(RASCONN);
477
478 DWORD nConnections = 0;
479 DWORD dwRet = ERROR_BUFFER_TOO_SMALL;
480
481 while ( dwRet == ERROR_BUFFER_TOO_SMALL )
482 {
483 dwRet = ms_pfnRasEnumConnections(lpRasConn, &cbBuf, &nConnections);
484
485 if ( dwRet == ERROR_BUFFER_TOO_SMALL )
486 {
487 LPRASCONN lpRasConnOld = lpRasConn;
488 lpRasConn = (LPRASCONN)realloc(lpRasConn, cbBuf);
489 if ( !lpRasConn )
490 {
491 // out of memory
492 free(lpRasConnOld);
493
494 return 0;
495 }
496 }
497 else if ( dwRet == 0 )
498 {
499 // ok, success
500 break;
501 }
502 else
503 {
504 // an error occured
505 wxLogError(_("Cannot find active dialup connection: %s"),
506 GetErrorString(dwRet).c_str());
507 return 0;
508 }
509 }
510
511 HRASCONN hrasconn;
512
513 switch ( nConnections )
514 {
515 case 0:
516 // no connections
517 hrasconn = 0;
518 break;
519
520 default:
521 // more than 1 connection - we don't know what to do with this
522 // case, so give a warning but continue (taking the first
523 // connection) - the warning is really needed because this function
524 // is used, for example, to select the connection to hang up and so
525 // we may hang up the wrong connection here...
526 wxLogWarning(_("Several active dialup connections found, choosing one randomly."));
527 // fall through
528
529 case 1:
530 // exactly 1 connection, great
531 hrasconn = lpRasConn->hrasconn;
532 }
533
534 free(lpRasConn);
535
536 return hrasconn;
537 }
538
539 void wxDialUpManagerMSW::CleanUpThreadData()
540 {
541 if ( m_hThread )
542 {
543 if ( !SetEvent(m_data->hEventQuit) )
544 {
545 wxLogLastError(_T("SetEvent(RasThreadQuit)"));
546 }
547 else // sent quit request to the background thread
548 {
549 // the thread still needs m_data so we can't free it here, rather
550 // let the thread do it itself
551 m_data = NULL;
552 }
553
554 CloseHandle(m_hThread);
555
556 m_hThread = 0;
557 }
558
559 if ( m_data )
560 {
561 delete m_data;
562 m_data = NULL;
563 }
564 }
565
566 // ----------------------------------------------------------------------------
567 // connection status
568 // ----------------------------------------------------------------------------
569
570 void wxDialUpManagerMSW::CheckRasStatus()
571 {
572 // use int, not bool to compare with -1
573 int isConnected = FindActiveConnection() != 0;
574 if ( isConnected != ms_isConnected )
575 {
576 if ( ms_isConnected != -1 )
577 {
578 // notify the program
579 NotifyApp(isConnected != 0);
580 }
581 // else: it's the first time we're called, just update the flag
582
583 ms_isConnected = isConnected;
584 }
585 }
586
587 void wxDialUpManagerMSW::NotifyApp(bool connected, bool fromOurselves) const
588 {
589 wxDialUpEvent event(connected, fromOurselves);
590 (void)wxTheApp->ProcessEvent(event);
591 }
592
593 // this function is called whenever the status of any RAS connection on this
594 // machine changes by RAS itself
595 void wxDialUpManagerMSW::OnConnectStatusChange()
596 {
597 // we know that status changed, but we don't know whether we're connected
598 // or not - so find it out
599 CheckRasStatus();
600 }
601
602 // this function is called by our callback which we give to RasDial() when
603 // calling it asynchronously
604 void wxDialUpManagerMSW::OnDialProgress(RASCONNSTATE rasconnstate,
605 DWORD dwError)
606 {
607 if ( !GetDialer() )
608 {
609 // this probably means that CancelDialing() was called and we get
610 // "disconnected" notification
611 return;
612 }
613
614 // we're only interested in 2 events: connected and disconnected
615 if ( dwError )
616 {
617 wxLogError(_("Failed to establish dialup connection: %s"),
618 GetErrorString(dwError).c_str());
619
620 // we should still call RasHangUp() if we got a non 0 connection
621 if ( ms_hRasConnection )
622 {
623 ms_pfnRasHangUp(ms_hRasConnection);
624 ms_hRasConnection = 0;
625 }
626
627 ms_dialer = NULL;
628
629 NotifyApp(FALSE /* !connected */, TRUE /* we dialed ourselves */);
630 }
631 else if ( rasconnstate == RASCS_Connected )
632 {
633 ms_isConnected = TRUE;
634 ms_dialer = NULL;
635
636 NotifyApp(TRUE /* connected */, TRUE /* we dialed ourselves */);
637 }
638 }
639
640 // ----------------------------------------------------------------------------
641 // implementation of wxDialUpManager functions
642 // ----------------------------------------------------------------------------
643
644 bool wxDialUpManagerMSW::IsOk() const
645 {
646 return m_dllRas.IsLoaded();
647 }
648
649 size_t wxDialUpManagerMSW::GetISPNames(wxArrayString& names) const
650 {
651 // fetch the entries
652 DWORD size = sizeof(RASENTRYNAME);
653 RASENTRYNAME *rasEntries = (RASENTRYNAME *)malloc(size);
654 rasEntries->dwSize = sizeof(RASENTRYNAME);
655
656 DWORD nEntries;
657 DWORD dwRet;
658 do
659 {
660 dwRet = ms_pfnRasEnumEntries
661 (
662 NULL, // reserved
663 NULL, // default phone book (or all)
664 rasEntries, // [out] buffer for the entries
665 &size, // [in/out] size of the buffer
666 &nEntries // [out] number of entries fetched
667 );
668
669 if ( dwRet == ERROR_BUFFER_TOO_SMALL )
670 {
671 // reallocate the buffer
672 rasEntries = (RASENTRYNAME *)realloc(rasEntries, size);
673 }
674 else if ( dwRet != 0 )
675 {
676 // some other error - abort
677 wxLogError(_("Failed to get ISP names: %s"),
678 GetErrorString(dwRet).c_str());
679
680 free(rasEntries);
681
682 return 0u;
683 }
684 }
685 while ( dwRet != 0 );
686
687 // process them
688 names.Empty();
689 for ( size_t n = 0; n < (size_t)nEntries; n++ )
690 {
691 names.Add(rasEntries[n].szEntryName);
692 }
693
694 free(rasEntries);
695
696 // return the number of entries
697 return names.GetCount();
698 }
699
700 bool wxDialUpManagerMSW::Dial(const wxString& nameOfISP,
701 const wxString& username,
702 const wxString& password,
703 bool async)
704 {
705 // check preconditions
706 wxCHECK_MSG( IsOk(), FALSE, wxT("using uninitialized wxDialUpManager") );
707
708 if ( ms_hRasConnection )
709 {
710 wxFAIL_MSG(wxT("there is already an active connection"));
711
712 return TRUE;
713 }
714
715 // get the default ISP if none given
716 wxString entryName(nameOfISP);
717 if ( !entryName )
718 {
719 wxArrayString names;
720 size_t count = GetISPNames(names);
721 switch ( count )
722 {
723 case 0:
724 // no known ISPs, abort
725 wxLogError(_("Failed to connect: no ISP to dial."));
726
727 return FALSE;
728
729 case 1:
730 // only one ISP, choose it
731 entryName = names[0u];
732 break;
733
734 default:
735 // several ISPs, let the user choose
736 {
737 wxString *strings = new wxString[count];
738 for ( size_t i = 0; i < count; i++ )
739 {
740 strings[i] = names[i];
741 }
742
743 entryName = wxGetSingleChoice
744 (
745 _("Choose ISP to dial"),
746 _("Please choose which ISP do you want to connect to"),
747 count,
748 strings
749 );
750
751 delete [] strings;
752
753 if ( !entryName )
754 {
755 // cancelled by user
756 return FALSE;
757 }
758 }
759 }
760 }
761
762 RASDIALPARAMS rasDialParams;
763 rasDialParams.dwSize = sizeof(rasDialParams);
764 wxStrncpy(rasDialParams.szEntryName, entryName, RAS_MaxEntryName);
765
766 // do we have the username and password?
767 if ( !username || !password )
768 {
769 BOOL gotPassword;
770 DWORD dwRet = ms_pfnRasGetEntryDialParams
771 (
772 NULL, // default phonebook
773 &rasDialParams, // [in/out] the params of this entry
774 &gotPassword // [out] did we get password?
775 );
776
777 if ( dwRet != 0 )
778 {
779 wxLogError(_("Failed to connect: missing username/password."));
780
781 return FALSE;
782 }
783 }
784 else
785 {
786 wxStrncpy(rasDialParams.szUserName, username, UNLEN);
787 wxStrncpy(rasDialParams.szPassword, password, PWLEN);
788 }
789
790 // default values for other fields
791 rasDialParams.szPhoneNumber[0] = '\0';
792 rasDialParams.szCallbackNumber[0] = '\0';
793 rasDialParams.szCallbackNumber[0] = '\0';
794
795 rasDialParams.szDomain[0] = '*';
796 rasDialParams.szDomain[1] = '\0';
797
798 // apparently, this is not really necessary - passing NULL instead of the
799 // phone book has the same effect
800 #if 0
801 wxString phoneBook;
802 if ( wxGetOsVersion() == wxWINDOWS_NT )
803 {
804 // first get the length
805 UINT nLen = ::GetSystemDirectory(NULL, 0);
806 nLen++;
807
808 if ( !::GetSystemDirectory(phoneBook.GetWriteBuf(nLen), nLen) )
809 {
810 wxLogSysError(_("Cannot find the location of address book file"));
811 }
812
813 phoneBook.UngetWriteBuf();
814
815 // this is the default phone book
816 phoneBook << "\\ras\\rasphone.pbk";
817 }
818 #endif // 0
819
820 // TODO may be we should disable auto check while async dialing is in
821 // progress?
822
823 ms_dialer = this;
824
825 DWORD dwRet = ms_pfnRasDial
826 (
827 NULL, // no extended features
828 NULL, // default phone book file (NT only)
829 &rasDialParams,
830 0, // use callback for notifications
831 async ? (void *)wxRasDialFunc // cast needed for gcc 3.1
832 : 0, // no notifications, sync operation
833 &ms_hRasConnection
834 );
835
836 if ( dwRet != 0 )
837 {
838 // can't pass a wxWCharBuffer through ( ... )
839 wxLogError(_("Failed to %s dialup connection: %s"),
840 wxString(async ? _("initiate") : _("establish")).c_str(),
841 GetErrorString(dwRet).c_str());
842
843 // we should still call RasHangUp() if we got a non 0 connection
844 if ( ms_hRasConnection )
845 {
846 ms_pfnRasHangUp(ms_hRasConnection);
847 ms_hRasConnection = 0;
848 }
849
850 ms_dialer = NULL;
851
852 return FALSE;
853 }
854
855 // for async dialing, we're not yet connected
856 if ( !async )
857 {
858 ms_isConnected = TRUE;
859 }
860
861 return TRUE;
862 }
863
864 bool wxDialUpManagerMSW::IsDialing() const
865 {
866 return GetDialer() != NULL;
867 }
868
869 bool wxDialUpManagerMSW::CancelDialing()
870 {
871 if ( !GetDialer() )
872 {
873 // silently ignore
874 return FALSE;
875 }
876
877 wxASSERT_MSG( ms_hRasConnection, wxT("dialing but no connection?") );
878
879 ms_dialer = NULL;
880
881 return HangUp();
882 }
883
884 bool wxDialUpManagerMSW::HangUp()
885 {
886 wxCHECK_MSG( IsOk(), FALSE, wxT("using uninitialized wxDialUpManager") );
887
888 // we may terminate either the connection we initiated or another one which
889 // is active now
890 HRASCONN hRasConn;
891 if ( ms_hRasConnection )
892 {
893 hRasConn = ms_hRasConnection;
894
895 ms_hRasConnection = 0;
896 }
897 else
898 {
899 hRasConn = FindActiveConnection();
900 }
901
902 if ( !hRasConn )
903 {
904 wxLogError(_("Cannot hang up - no active dialup connection."));
905
906 return FALSE;
907 }
908
909 DWORD dwRet = ms_pfnRasHangUp(hRasConn);
910 if ( dwRet != 0 )
911 {
912 wxLogError(_("Failed to terminate the dialup connection: %s"),
913 GetErrorString(dwRet).c_str());
914 }
915
916 ms_isConnected = FALSE;
917
918 return TRUE;
919 }
920
921 bool wxDialUpManagerMSW::IsAlwaysOnline() const
922 {
923 // assume no permanent connection by default
924 bool isAlwaysOnline = FALSE;
925
926 // try to use WinInet functions
927
928 // NB: we could probably use wxDynamicLibrary here just as well,
929 // but we allow multiple instances of wxDialUpManagerMSW so
930 // we might as well use the ref counted version here too.
931
932 wxDynamicLibrary hDll(_T("WININET"));
933 if ( hDll.IsLoaded() )
934 {
935 typedef BOOL (WINAPI *INTERNETGETCONNECTEDSTATE)(LPDWORD, DWORD);
936 INTERNETGETCONNECTEDSTATE pfnInternetGetConnectedState;
937
938 #define RESOLVE_FUNCTION(type, name) \
939 pfn##name = (type)hDll.GetSymbol(_T(#name))
940
941 RESOLVE_FUNCTION(INTERNETGETCONNECTEDSTATE, InternetGetConnectedState);
942
943 if ( pfnInternetGetConnectedState )
944 {
945 DWORD flags = 0;
946 if ( pfnInternetGetConnectedState(&flags, 0 /* reserved */) )
947 {
948 // there is some connection to the net, see of which type
949 isAlwaysOnline = (flags & (INTERNET_CONNECTION_LAN |
950 INTERNET_CONNECTION_PROXY)) != 0;
951 }
952 //else: no Internet connection at all
953 }
954 }
955
956 return isAlwaysOnline;
957 }
958
959 bool wxDialUpManagerMSW::IsOnline() const
960 {
961 wxCHECK_MSG( IsOk(), FALSE, wxT("using uninitialized wxDialUpManager") );
962
963 if ( IsAlwaysOnline() )
964 {
965 // always => now
966 return true;
967 }
968
969 if ( ms_userSpecifiedOnlineStatus != -1 )
970 {
971 // user specified flag overrides our logic
972 return ms_userSpecifiedOnlineStatus != 0;
973 }
974 else
975 {
976 // return TRUE if there is at least one active connection
977 return FindActiveConnection() != 0;
978 }
979 }
980
981 void wxDialUpManagerMSW::SetOnlineStatus(bool isOnline)
982 {
983 wxCHECK_RET( IsOk(), wxT("using uninitialized wxDialUpManager") );
984
985 ms_userSpecifiedOnlineStatus = isOnline;
986 }
987
988 bool wxDialUpManagerMSW::EnableAutoCheckOnlineStatus(size_t nSeconds)
989 {
990 wxCHECK_MSG( IsOk(), FALSE, wxT("using uninitialized wxDialUpManager") );
991
992 if ( m_autoCheckLevel++ )
993 {
994 // already checking
995 return TRUE;
996 }
997
998 bool ok = ms_pfnRasConnectionNotification != 0;
999
1000 if ( ok )
1001 {
1002 // we're running under NT 4.0, Windows 98 or later and can use
1003 // RasConnectionNotification() to be notified by a secondary thread
1004
1005 // first, see if we don't have this thread already running
1006 if ( m_hThread != 0 )
1007 {
1008 if ( ::ResumeThread(m_hThread) != (DWORD)-1 )
1009 return TRUE;
1010
1011 // we're leaving a zombie thread... but what else can we do?
1012 wxLogLastError(wxT("ResumeThread(RasThread)"));
1013
1014 ok = FALSE;
1015 }
1016 }
1017
1018 // create all the stuff we need to be notified about RAS connection
1019 // status change
1020
1021 if ( ok )
1022 {
1023 // first create an event to wait on
1024 m_data->hEventRas = CreateEvent
1025 (
1026 NULL, // security attribute (default)
1027 FALSE, // manual reset (no, it is automatic)
1028 FALSE, // initial state (not signaled)
1029 NULL // name (no)
1030 );
1031 if ( !m_data->hEventRas )
1032 {
1033 wxLogLastError(wxT("CreateEvent(RasStatus)"));
1034
1035 ok = FALSE;
1036 }
1037 }
1038
1039 if ( ok )
1040 {
1041 // create the event we use to quit the thread: using a manual event
1042 // here avoids problems with missing the event if wxDialUpManagerMSW
1043 // is created and destroyed immediately, before wxRasStatusWindowProc
1044 // starts waiting on the event
1045 m_data->hEventQuit = CreateEvent
1046 (
1047 NULL, // default security
1048 TRUE, // manual event
1049 FALSE, // initially non signalled
1050 NULL // nameless
1051 );
1052 if ( !m_data->hEventQuit )
1053 {
1054 wxLogLastError(wxT("CreateEvent(RasThreadQuit)"));
1055
1056 CleanUpThreadData();
1057
1058 ok = FALSE;
1059 }
1060 }
1061
1062 if ( ok && !ms_hwndRas )
1063 {
1064 // create a hidden window to receive notification about connections
1065 // status change
1066 extern const wxChar *wxCanvasClassName;
1067 ms_hwndRas = ::CreateWindow(wxCanvasClassName, NULL,
1068 0, 0, 0, 0,
1069 0, NULL,
1070 (HMENU)NULL, wxGetInstance(), 0);
1071 if ( !ms_hwndRas )
1072 {
1073 wxLogLastError(wxT("CreateWindow(RasHiddenWindow)"));
1074
1075 CleanUpThreadData();
1076
1077 ok = FALSE;
1078 }
1079
1080 // and subclass it
1081 wxSetWindowProc(ms_hwndRas, wxRasStatusWindowProc);
1082 }
1083
1084 m_data->hWnd = ms_hwndRas;
1085
1086 if ( ok )
1087 {
1088 // start the secondary thread
1089 m_data->dialUpManager = this;
1090
1091 DWORD tid;
1092 m_hThread = CreateThread
1093 (
1094 NULL,
1095 0,
1096 (LPTHREAD_START_ROUTINE)wxRasMonitorThread,
1097 (void *)m_data,
1098 0,
1099 &tid
1100 );
1101
1102 if ( !m_hThread )
1103 {
1104 wxLogLastError(wxT("CreateThread(RasStatusThread)"));
1105
1106 CleanUpThreadData();
1107 }
1108 }
1109
1110 if ( ok )
1111 {
1112 // start receiving RAS notifications
1113 DWORD dwRet = ms_pfnRasConnectionNotification
1114 (
1115 (HRASCONN)INVALID_HANDLE_VALUE,
1116 m_data->hEventRas,
1117 3 /* RASCN_Connection | RASCN_Disconnection */
1118 );
1119
1120 if ( dwRet != 0 )
1121 {
1122 wxLogDebug(wxT("RasConnectionNotification() failed: %s"),
1123 GetErrorString(dwRet).c_str());
1124
1125 CleanUpThreadData();
1126 }
1127 else
1128 {
1129 return TRUE;
1130 }
1131 }
1132
1133 // we're running under Windows 95 and have to poll ourselves
1134 // (or, alternatively, the code above for NT/98 failed)
1135 m_timerStatusPolling.Stop();
1136 if ( nSeconds == 0 )
1137 {
1138 // default value
1139 nSeconds = 60;
1140 }
1141 m_timerStatusPolling.Start(nSeconds * 1000);
1142
1143 return TRUE;
1144 }
1145
1146 void wxDialUpManagerMSW::DisableAutoCheckOnlineStatus()
1147 {
1148 wxCHECK_RET( IsOk(), wxT("using uninitialized wxDialUpManager") );
1149
1150 if ( --m_autoCheckLevel )
1151 {
1152 // still checking
1153 return;
1154 }
1155
1156 if ( m_hThread )
1157 {
1158 // we have running secondary thread, it's just enough to suspend it
1159 if ( SuspendThread(m_hThread) == (DWORD)-1 )
1160 {
1161 wxLogLastError(wxT("SuspendThread(RasThread)"));
1162 }
1163 }
1164 else
1165 {
1166 // even simpler - just stop the timer
1167 m_timerStatusPolling.Stop();
1168 }
1169 }
1170
1171 // ----------------------------------------------------------------------------
1172 // stubs which don't do anything in MSW version
1173 // ----------------------------------------------------------------------------
1174
1175 void wxDialUpManagerMSW::SetWellKnownHost(const wxString& WXUNUSED(hostname),
1176 int WXUNUSED(port))
1177 {
1178 wxCHECK_RET( IsOk(), wxT("using uninitialized wxDialUpManager") );
1179
1180 // nothing to do - we don't use this
1181 }
1182
1183 void wxDialUpManagerMSW::SetConnectCommand(const wxString& WXUNUSED(dial),
1184 const wxString& WXUNUSED(hangup))
1185 {
1186 wxCHECK_RET( IsOk(), wxT("using uninitialized wxDialUpManager") );
1187
1188 // nothing to do - we don't use this
1189 }
1190
1191 // ----------------------------------------------------------------------------
1192 // callbacks
1193 // ----------------------------------------------------------------------------
1194
1195 static DWORD wxRasMonitorThread(wxRasThreadData *data)
1196 {
1197 HANDLE handles[2];
1198 handles[0] = data->hEventRas;
1199 handles[1] = data->hEventQuit;
1200
1201 bool cont = TRUE;
1202 while ( cont )
1203 {
1204 DWORD dwRet = WaitForMultipleObjects(2, handles, FALSE, INFINITE);
1205
1206 switch ( dwRet )
1207 {
1208 case WAIT_OBJECT_0:
1209 // RAS connection status changed
1210 SendMessage(data->hWnd, wxWM_RAS_STATUS_CHANGED,
1211 0, (LPARAM)data);
1212 break;
1213
1214 case WAIT_OBJECT_0 + 1:
1215 cont = FALSE;
1216 break;
1217
1218 default:
1219 wxFAIL_MSG( _T("unexpected return of WaitForMultipleObjects()") );
1220 // fall through
1221
1222 case WAIT_FAILED:
1223 #ifdef __WXDEBUG__
1224 // using wxLogLastError() from here is dangerous: we risk to
1225 // deadlock the main thread if wxLog sends output to GUI
1226 DWORD err = GetLastError();
1227 wxMessageOutputDebug().Printf
1228 (
1229 wxT("WaitForMultipleObjects(RasMonitor) failed: 0x%08lx (%s)"),
1230 err,
1231 wxSysErrorMsg(err)
1232 );
1233 #endif // __WXDEBUG__
1234
1235 // no sense in continuing, who knows if the handles we're
1236 // waiting for even exist yet...
1237 return (DWORD)-1;
1238 }
1239 }
1240
1241 // we don't need it any more now and if this thread ran, it is our
1242 // responsability to free the data
1243 delete data;
1244
1245 return 0;
1246 }
1247
1248 static LRESULT APIENTRY wxRasStatusWindowProc(HWND hWnd, UINT message,
1249 WPARAM wParam, LPARAM lParam)
1250 {
1251 switch ( message )
1252 {
1253 case wxWM_RAS_STATUS_CHANGED:
1254 {
1255 wxRasThreadData *data = (wxRasThreadData *)lParam;
1256 data->dialUpManager->OnConnectStatusChange();
1257 }
1258 break;
1259
1260 case wxWM_RAS_DIALING_PROGRESS:
1261 {
1262 wxDialUpManagerMSW *dialMan = wxDialUpManagerMSW::GetDialer();
1263
1264 dialMan->OnDialProgress((RASCONNSTATE)wParam, lParam);
1265 }
1266 break;
1267
1268 default:
1269 return ::DefWindowProc(hWnd, message, wParam, lParam);
1270 }
1271
1272 return 0;
1273 }
1274
1275 static void WINAPI wxRasDialFunc(UINT WXUNUSED(unMsg),
1276 RASCONNSTATE rasconnstate,
1277 DWORD dwError)
1278 {
1279 wxDialUpManagerMSW *dialUpManager = wxDialUpManagerMSW::GetDialer();
1280
1281 wxCHECK_RET( dialUpManager, wxT("who started to dial then?") );
1282
1283 SendMessage(dialUpManager->GetRasWindow(), wxWM_RAS_DIALING_PROGRESS,
1284 rasconnstate, dwError);
1285 }
1286
1287 #endif // __PALMOS__
1288
1289 #endif // wxUSE_DIALUP_MANAGER
1290