mirror of https://github.com/OpenVPN/openvpn-gui
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
728 lines
19 KiB
728 lines
19 KiB
/* |
|
* OpenVPN-PLAP-Provider |
|
* |
|
* Copyright (C) 2017-2022 Selva Nair <selva.nair@gmail.com> |
|
* |
|
* This program is free software; you can redistribute it and/or modify |
|
* it under the terms of the GNU General Public License as published by |
|
* the Free Software Foundation; either version 2 of the License, or |
|
* (at your option) any later version. |
|
* |
|
* This program is distributed in the hope that it will be useful, |
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|
* GNU General Public License for more details. |
|
* |
|
* You should have received a copy of the GNU General Public License |
|
* along with this program (see the file COPYING included with this |
|
* distribution); if not, write to the Free Software Foundation, Inc., |
|
* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
|
*/ |
|
|
|
#ifdef HAVE_CONFIG_H |
|
#include <config.h> |
|
#endif |
|
|
|
#include "plap_common.h" |
|
#include "plap_connection.h" |
|
#include "plap_dll.h" |
|
#include <assert.h> |
|
#include "resource.h" |
|
#include "localization.h" |
|
#include "openvpn-gui-res.h" |
|
#include "main.h" |
|
#include "misc.h" |
|
|
|
/* A "class" that implements IConnectableCredentialProviderCredential */ |
|
|
|
struct OpenVPNConnection |
|
{ |
|
const IConnectableCredentialProviderCredentialVtbl *lpVtbl; /* base class vtable */ |
|
|
|
/* "private" members */ |
|
ICredentialProviderCredentialEvents *events; /* Passed in by Logon UI for callbacks */ |
|
connection_t *c; /* GUI connection data */ |
|
const wchar_t *display_name; |
|
IQueryContinueWithStatus *qc; /* Passed in by LogonUI for checking status of connect */ |
|
BOOL connect_cancelled; /* we set this true if user cancels the connect operation */ |
|
LONG ref_count; |
|
}; |
|
|
|
#define ICCPC IConnectableCredentialProviderCredential /* shorthand for a long name */ |
|
|
|
#define ISCONNECTED(c) (ConnectionState(c) == state_connected) |
|
#define ISDISCONNECTED(c) (ConnectionState(c) == state_disconnected) |
|
#define ISONHOLD(c) (ConnectionState(c) == state_onhold) |
|
|
|
extern DWORD status_menu_id; |
|
|
|
/* Methods in IConnectableCredentialProviderCredential that we need to define */ |
|
|
|
/* IUnknown */ |
|
static HRESULT WINAPI QueryInterface(ICCPC *this, REFIID riid, void **ppv); |
|
|
|
static ULONG WINAPI AddRef(ICCPC *this); |
|
|
|
static ULONG WINAPI Release(ICCPC *this); |
|
|
|
/* ICredentialProviderCredential */ |
|
static HRESULT WINAPI Advise(ICCPC *this, ICredentialProviderCredentialEvents *e); |
|
|
|
static HRESULT WINAPI UnAdvise(ICCPC *this); |
|
|
|
static HRESULT WINAPI SetSelected(ICCPC *this, BOOL *auto_logon); |
|
|
|
static HRESULT WINAPI SetDeselected(ICCPC *this); |
|
|
|
static HRESULT WINAPI GetFieldState(ICCPC *this, DWORD field, CREDENTIAL_PROVIDER_FIELD_STATE *fs, |
|
CREDENTIAL_PROVIDER_FIELD_INTERACTIVE_STATE *fis); |
|
|
|
static HRESULT WINAPI GetStringValue(ICCPC *this, DWORD index, WCHAR **ws); |
|
|
|
static HRESULT WINAPI GetBitmapValue(ICCPC *this, DWORD field, HBITMAP *bmp); |
|
|
|
static HRESULT WINAPI GetSubmitButtonValue(ICCPC *this, DWORD field, DWORD *adjacent); |
|
|
|
static HRESULT WINAPI SetStringValue(ICCPC *this, DWORD field, const WCHAR *ws); |
|
|
|
static HRESULT WINAPI GetCheckboxValue(ICCPC *this, DWORD field, BOOL *checked, wchar_t **label); |
|
|
|
static HRESULT WINAPI GetComboBoxValueCount(ICCPC *this, DWORD field, DWORD *items, DWORD *selected_item); |
|
|
|
static HRESULT WINAPI GetComboBoxValueAt(ICCPC *this, DWORD field, DWORD item, wchar_t **item_value); |
|
|
|
static HRESULT WINAPI SetCheckboxValue(ICCPC *this, DWORD field, BOOL checked); |
|
|
|
static HRESULT WINAPI SetComboBoxSelectedValue(ICCPC *this, DWORD field, DWORD selected_item); |
|
|
|
static HRESULT WINAPI CommandLinkClicked(ICCPC *this, DWORD field); |
|
|
|
static HRESULT WINAPI GetSerialization(ICCPC *this, |
|
CREDENTIAL_PROVIDER_GET_SERIALIZATION_RESPONSE *response, |
|
CREDENTIAL_PROVIDER_CREDENTIAL_SERIALIZATION *cs, wchar_t **text, |
|
CREDENTIAL_PROVIDER_STATUS_ICON *icon); |
|
|
|
static HRESULT WINAPI ReportResult(ICCPC *this, NTSTATUS status, NTSTATUS substatus, |
|
wchar_t **status_text, CREDENTIAL_PROVIDER_STATUS_ICON *icon); |
|
|
|
/* IConnectableCredentialProviderCredential */ |
|
static HRESULT WINAPI Connect(ICCPC *this, IQueryContinueWithStatus *qc); |
|
|
|
static HRESULT WINAPI Disconnect(ICCPC *this); |
|
|
|
/* use a static table for filling in the methods */ |
|
#define M_(x) .x = x |
|
static const IConnectableCredentialProviderCredentialVtbl iccpc_vtbl = { |
|
M_(QueryInterface), |
|
M_(AddRef), |
|
M_(Release), |
|
M_(Advise), |
|
M_(UnAdvise), |
|
M_(SetSelected), |
|
M_(SetDeselected), |
|
M_(GetFieldState), |
|
M_(GetStringValue), |
|
M_(GetBitmapValue), |
|
M_(GetCheckboxValue), |
|
M_(GetSubmitButtonValue), |
|
M_(GetComboBoxValueCount), |
|
M_(GetComboBoxValueAt), |
|
M_(SetStringValue), |
|
M_(SetCheckboxValue), |
|
M_(SetComboBoxSelectedValue), |
|
M_(CommandLinkClicked), |
|
M_(GetSerialization), |
|
M_(ReportResult), |
|
M_(Connect), |
|
M_(Disconnect), |
|
}; |
|
|
|
/* constructor */ |
|
OpenVPNConnection * |
|
OpenVPNConnection_new() |
|
{ |
|
dmsg(L"Entry"); |
|
|
|
OpenVPNConnection *oc = calloc(sizeof(*oc), 1); |
|
if (oc) |
|
{ |
|
oc->lpVtbl = &iccpc_vtbl; |
|
oc->ref_count = 1; |
|
|
|
dll_addref(); |
|
} |
|
return oc; |
|
} |
|
|
|
/* destructor */ |
|
static void |
|
OpenVPNConnection_free(OpenVPNConnection *oc) |
|
{ |
|
dmsg(L"Entry: profile: <%ls>", oc->display_name); |
|
|
|
free(oc); |
|
dll_release(); |
|
} |
|
|
|
static ULONG WINAPI |
|
AddRef(ICCPC *this) |
|
{ |
|
OpenVPNConnection *oc = (OpenVPNConnection *) this; |
|
|
|
dmsg(L"Connection: ref_count after increment = %lu", oc->ref_count + 1); |
|
return InterlockedIncrement(&oc->ref_count); |
|
} |
|
|
|
static ULONG WINAPI |
|
Release(ICCPC *this) |
|
{ |
|
OpenVPNConnection *oc = (OpenVPNConnection *) this; |
|
|
|
int count = InterlockedDecrement(&oc->ref_count); |
|
dmsg(L"Connection: ref_count after decrement = %lu", count); |
|
if (count == 0) |
|
{ |
|
OpenVPNConnection_free(oc); /* delete self */ |
|
} |
|
return count; |
|
} |
|
|
|
static HRESULT WINAPI |
|
QueryInterface(ICCPC *this, REFIID riid, void **ppv) |
|
{ |
|
HRESULT hr; |
|
|
|
#ifdef DEBUG |
|
debug_print_guid(riid, L"In OVPN Connection QueryInterface with riid = "); |
|
#endif |
|
|
|
if (ppv != NULL) |
|
{ |
|
if (IsEqualIID(riid, &IID_IUnknown) |
|
|| IsEqualIID(riid, &IID_ICredentialProviderCredential) |
|
|| IsEqualIID(riid, &IID_IConnectableCredentialProviderCredential)) |
|
{ |
|
*ppv = this; |
|
ADDREF(this); |
|
hr = S_OK; |
|
} |
|
else |
|
{ |
|
*ppv = NULL; |
|
hr = E_NOINTERFACE; |
|
} |
|
} |
|
else |
|
{ |
|
hr = E_POINTER; |
|
} |
|
return hr; |
|
} |
|
|
|
/* |
|
* LogonUI calls Advise first and the passed in events may be used for |
|
* making callbacks to notify changes asynchronously |
|
*/ |
|
static HRESULT |
|
WINAPI |
|
Advise(ICCPC *this, ICredentialProviderCredentialEvents *e) |
|
{ |
|
HWND hwnd; |
|
|
|
dmsg(L"Entry"); |
|
|
|
OpenVPNConnection *oc = (OpenVPNConnection *) this; |
|
|
|
if (oc->events) |
|
{ |
|
RELEASE(oc->events); |
|
} |
|
oc->events = e; |
|
ADDREF(e); |
|
|
|
if (e |
|
&& e->lpVtbl->OnCreatingWindow(e, &hwnd) == S_OK) |
|
{ |
|
dmsg(L"Setting hwnd"); |
|
SetParentWindow(hwnd); |
|
} |
|
return S_OK; |
|
} |
|
|
|
/* We keep a copy of events pointer in Advise, release it here */ |
|
static HRESULT WINAPI |
|
UnAdvise(ICCPC *this) |
|
{ |
|
dmsg(L"Entry"); |
|
|
|
OpenVPNConnection *oc = (OpenVPNConnection *) this; |
|
|
|
if (oc->events) |
|
{ |
|
RELEASE(oc->events); |
|
} |
|
oc->events = NULL; |
|
return S_OK; |
|
} |
|
|
|
/* |
|
* LogonUI calls this function when our tile is selected |
|
* We do nothing here and let the user choose which profile to connect. |
|
*/ |
|
static HRESULT WINAPI |
|
SetSelected(ICCPC *this, BOOL *auto_logon) |
|
{ |
|
#ifdef DEBUG |
|
OpenVPNConnection *oc = (OpenVPNConnection *) this; |
|
dmsg(L"profile: %ls", oc->display_name); |
|
#else |
|
(void) this; |
|
#endif |
|
|
|
/* setting true here will autoconnect the first entry and Windows will |
|
* autoselect it for the rest of the login session, blocking all other |
|
* entries and other providers, if any. Some commercial products do |
|
* that but its not a good idea, IMO. So we set false here. |
|
*/ |
|
*auto_logon = FALSE; |
|
return S_OK; |
|
} |
|
|
|
static HRESULT WINAPI |
|
SetDeselected(ICCPC *this) |
|
{ |
|
#ifdef DEBUG |
|
OpenVPNConnection *oc = (OpenVPNConnection *) this; |
|
dmsg(L"profile: %ls", oc->display_name); |
|
#else |
|
(void) this; |
|
#endif |
|
|
|
return S_OK; |
|
} |
|
|
|
/* |
|
* Return display states for a particular field of a tile |
|
*/ |
|
static HRESULT WINAPI |
|
GetFieldState(UNUSED ICCPC *this, DWORD field, |
|
CREDENTIAL_PROVIDER_FIELD_STATE *fs, |
|
CREDENTIAL_PROVIDER_FIELD_INTERACTIVE_STATE *fis) |
|
{ |
|
HRESULT hr; |
|
|
|
dmsg(L"field = %lu", field); |
|
|
|
if (field < _countof(field_states)) |
|
{ |
|
if (fs) |
|
{ |
|
*fs = field_states[field]; |
|
} |
|
if (fis) |
|
{ |
|
*fis = (field_desc[field].cpft == CPFT_SUBMIT_BUTTON) ? CPFIS_FOCUSED : CPFIS_NONE; |
|
} |
|
hr = S_OK; |
|
} |
|
else |
|
{ |
|
hr = E_INVALIDARG; |
|
} |
|
return hr; |
|
} |
|
|
|
/* |
|
* Return the string value of the field at the index |
|
*/ |
|
static HRESULT WINAPI |
|
GetStringValue(ICCPC *this, DWORD index, WCHAR **ws) |
|
{ |
|
HRESULT hr = S_OK; |
|
|
|
dmsg(L"index = %lu", index); |
|
|
|
OpenVPNConnection *oc = (OpenVPNConnection *) this; |
|
|
|
const wchar_t *val = L""; |
|
|
|
if (index >= _countof(field_desc)) |
|
{ |
|
return E_INVALIDARG; |
|
} |
|
|
|
/* we have custom field strings only for connection name */ |
|
if (field_desc[index].cpft == CPFT_LARGE_TEXT) |
|
{ |
|
val = oc->display_name; /* connection name */ |
|
} |
|
|
|
/* do not to use malloc here as the client will free using CoTaskMemFree */ |
|
hr = SHStrDupW(val, ws); |
|
if (!SUCCEEDED(hr)) |
|
{ |
|
hr = E_OUTOFMEMORY; |
|
dmsg(L"OOM while copying field_strings[%lu]", index); |
|
} |
|
else |
|
{ |
|
dmsg(L"Returning %ls", *ws); |
|
} |
|
|
|
return hr; |
|
} |
|
|
|
/* |
|
* return the image for the tile at index field |
|
*/ |
|
static HRESULT WINAPI |
|
GetBitmapValue(UNUSED ICCPC *this, DWORD field, HBITMAP *bmp) |
|
{ |
|
HRESULT hr = S_OK; |
|
|
|
dmsg(L"field = %lu ", field); |
|
|
|
if (field_desc[field].cpft == CPFT_TILE_IMAGE && bmp) |
|
{ |
|
HBITMAP tmp = LoadBitmapW(hinst_global, MAKEINTRESOURCE(IDB_TILE_IMAGE)); |
|
if (tmp) |
|
{ |
|
*bmp = tmp; /* The caller takes ownership of this memory */ |
|
dmsg(L"Returning a bitmap for PLAP tile %lu", field); |
|
} |
|
else |
|
{ |
|
hr = HRESULT_FROM_WIN32(GetLastError()); |
|
dmsg(L"LoadBitmap failed with error = 0x%08x", hr); |
|
} |
|
} |
|
else |
|
{ |
|
hr = E_INVALIDARG; |
|
} |
|
|
|
return hr; |
|
} |
|
|
|
/* |
|
* Return the index of the field the button should be placed adjacent to. |
|
*/ |
|
static HRESULT WINAPI |
|
GetSubmitButtonValue(UNUSED ICCPC *this, DWORD field, DWORD *adjacent ) |
|
{ |
|
HRESULT hr; |
|
|
|
dmsg(L"field = %lu", field); |
|
|
|
/* we have defined field ids in order of appearance */ |
|
if (field_desc[field].cpft == CPFT_SUBMIT_BUTTON && field > 0 && adjacent) |
|
{ |
|
*adjacent = field - 1; |
|
hr = S_OK; |
|
} |
|
else |
|
{ |
|
hr = E_INVALIDARG; |
|
} |
|
return hr; |
|
} |
|
|
|
/* |
|
* Set the value of a field which can accept user text input |
|
* This gets called as user types into a field. |
|
*/ |
|
static HRESULT WINAPI |
|
SetStringValue(UNUSED ICCPC *this, UNUSED DWORD field, UNUSED const WCHAR *ws ) |
|
{ |
|
HRESULT hr; |
|
|
|
dmsg(L"field = %lu", field); |
|
|
|
/* We do not allow setting any fields -- at least not yet */ |
|
hr = E_INVALIDARG; |
|
|
|
return hr; |
|
} |
|
|
|
static HRESULT WINAPI |
|
GetCheckboxValue(UNUSED ICCPC *this, UNUSED DWORD field, |
|
UNUSED BOOL *checked, UNUSED wchar_t **label) |
|
{ |
|
dmsg(L"Entry"); |
|
return E_NOTIMPL; |
|
} |
|
|
|
static HRESULT WINAPI |
|
GetComboBoxValueCount(UNUSED ICCPC *this, UNUSED DWORD field, UNUSED DWORD *items, |
|
UNUSED DWORD *selected_item) |
|
{ |
|
dmsg(L"Entry"); |
|
return E_NOTIMPL; |
|
} |
|
|
|
static HRESULT WINAPI |
|
GetComboBoxValueAt(UNUSED ICCPC *this, UNUSED DWORD field, UNUSED DWORD item, |
|
UNUSED wchar_t **item_value) |
|
{ |
|
dmsg(L"Entry"); |
|
return E_NOTIMPL; |
|
} |
|
|
|
static HRESULT WINAPI |
|
SetCheckboxValue(UNUSED ICCPC *this, UNUSED DWORD field, UNUSED BOOL checked) |
|
{ |
|
dmsg(L"Entry"); |
|
return E_NOTIMPL; |
|
} |
|
|
|
static HRESULT WINAPI |
|
SetComboBoxSelectedValue(UNUSED ICCPC *this, UNUSED DWORD field, UNUSED DWORD selected_item) |
|
{ |
|
dmsg(L"Entry"); |
|
return E_NOTIMPL; |
|
} |
|
|
|
static HRESULT WINAPI |
|
CommandLinkClicked(UNUSED ICCPC *this, UNUSED DWORD field) |
|
{ |
|
dmsg(L"Entry"); |
|
return E_NOTIMPL; |
|
} |
|
|
|
/* |
|
* Collect the username and password into a serialized credential for the usage scenario |
|
* This gets called soon after connect -- result returned here influences the status of |
|
* Connect. |
|
* We do not support SSO, so no credentials are serialized. We just indicate whether |
|
* we got correct credentials for the Connect process or not. |
|
*/ |
|
static HRESULT WINAPI |
|
GetSerialization(ICCPC *this, CREDENTIAL_PROVIDER_GET_SERIALIZATION_RESPONSE *response, |
|
UNUSED CREDENTIAL_PROVIDER_CREDENTIAL_SERIALIZATION *cs, wchar_t **text, |
|
CREDENTIAL_PROVIDER_STATUS_ICON *icon) |
|
{ |
|
HRESULT hr = S_OK; |
|
|
|
OpenVPNConnection *oc = (OpenVPNConnection *) this; |
|
dmsg(L"Entry: profile <%ls>", oc->display_name); |
|
|
|
if (oc->connect_cancelled || !ISCONNECTED(oc->c)) |
|
{ |
|
dmsg(L"connect cancelled or failed"); |
|
/* return _NOT_FINISHED response here for the prompt go |
|
* back to the PLAP tiles screen. Unclear the return value |
|
* should be success or not : using S_OK. |
|
*/ |
|
*response = CPGSR_NO_CREDENTIAL_NOT_FINISHED; |
|
|
|
if (text && icon) |
|
{ |
|
if (oc->connect_cancelled) |
|
{ |
|
hr = SHStrDupW(LoadLocalizedString(IDS_NFO_CONN_CANCELLED), text); |
|
} |
|
else |
|
{ |
|
hr = SHStrDupW(LoadLocalizedString(IDS_NFO_CONN_FAILED, oc->display_name), text); |
|
} |
|
|
|
*icon = CPSI_ERROR; |
|
} |
|
} |
|
else |
|
{ |
|
/* Finished but no credentials to pass on to LogonUI */ |
|
*response = CPGSR_NO_CREDENTIAL_FINISHED; |
|
/* return CPGSR_RETURN_NO_CREDENTIAL_FINISHED leads to a loop! */ |
|
if (text && icon) |
|
{ |
|
hr = SHStrDupW(LoadLocalizedString(IDS_NFO_OVPN_STATE_CONNECTED), text); |
|
*icon = CPSI_SUCCESS; |
|
} |
|
} |
|
return hr; |
|
} |
|
|
|
static HRESULT WINAPI |
|
ReportResult(UNUSED ICCPC *this, UNUSED NTSTATUS status, UNUSED NTSTATUS substatus, |
|
UNUSED wchar_t **status_text, UNUSED CREDENTIAL_PROVIDER_STATUS_ICON *icon) |
|
{ |
|
dmsg(L"Entry"); |
|
return E_NOTIMPL; |
|
} |
|
|
|
/* Helper to send status string feedback to events object and qc if available */ |
|
static void |
|
NotifyEvents(OpenVPNConnection *oc, const wchar_t *status) |
|
{ |
|
if (oc->events) |
|
{ |
|
oc->events->lpVtbl->SetFieldString(oc->events, (ICredentialProviderCredential *) oc, |
|
STATUS_FIELD_INDEX, status); |
|
} |
|
if (oc->qc) |
|
{ |
|
oc->qc->lpVtbl->SetStatusMessage(oc->qc, status); |
|
} |
|
} |
|
|
|
static HRESULT WINAPI |
|
ProgressCallback(HWND hwnd, UINT msg, WPARAM wParam, UNUSED LPARAM lParam, LONG_PTR ref_data) |
|
{ |
|
assert(ref_data); |
|
|
|
OpenVPNConnection *oc = (OpenVPNConnection *) ref_data; |
|
connection_t *c = oc->c; |
|
IQueryContinueWithStatus *qc = oc->qc; |
|
|
|
assert(qc); |
|
|
|
HRESULT hr = S_FALSE; |
|
WCHAR status[256] = L""; |
|
|
|
if (msg == TDN_BUTTON_CLICKED && wParam == IDCANCEL) |
|
{ |
|
dmsg(L"wParam=IDCANCEL -- returning S_OK"); |
|
hr = S_OK; /* this will cause the progress dialog to close */ |
|
} |
|
else if (ISCONNECTED(c) || ISDISCONNECTED(c) || (qc->lpVtbl->QueryContinue(qc) != S_OK)) |
|
{ |
|
/* this will trigger IDCANCEL */ |
|
PostMessageW(hwnd, WM_CLOSE, 0, 0); |
|
dmsg(L"profile = %ls, closing progress dialog", oc->display_name); |
|
hr = S_OK; |
|
} |
|
else if (ISONHOLD(c)) /* Try to connect again */ |
|
{ |
|
ConnectHelper(c); |
|
} |
|
else if (!ISCONNECTED(c) && msg == TDN_BUTTON_CLICKED && wParam == status_menu_id) |
|
{ |
|
dmsg(L"wParam = status_menu_id -- showing status window"); |
|
ShowStatusWindow(c, TRUE); |
|
} |
|
else if (!ISCONNECTED(c) && msg == TDN_BUTTON_CLICKED && wParam == IDRETRY) |
|
{ |
|
dmsg(L"wParam = IDRETRY -- closing progress dialog for restart"); |
|
hr = S_OK; |
|
} |
|
|
|
if (msg == TDN_CREATED) |
|
{ |
|
dmsg(L"starting progress bar marquee"); |
|
PostMessageW(hwnd, TDM_SET_PROGRESS_BAR_MARQUEE, 1, 0); |
|
} |
|
|
|
if (msg == TDN_TIMER) |
|
{ |
|
GetConnectionStatusText(c, status, _countof(status)); |
|
NotifyEvents(oc, status); |
|
SendMessageW(hwnd, TDM_UPDATE_ELEMENT_TEXT, TDE_CONTENT, (LPARAM) status); |
|
dmsg(L"Connection status <%ls>", status); |
|
} |
|
|
|
return hr; |
|
} |
|
|
|
static HRESULT WINAPI |
|
Connect(ICCPC *this, IQueryContinueWithStatus *qc) |
|
{ |
|
OpenVPNConnection *oc = (OpenVPNConnection *) this; |
|
wchar_t status[256] = L""; |
|
|
|
dmsg(L"profile: <%ls>", oc->display_name); |
|
|
|
oc->qc = qc; |
|
NotifyEvents(oc, L""); |
|
|
|
again: |
|
oc->connect_cancelled = FALSE; |
|
SetActiveProfile(oc->c); /* This enables UI dialogs to be shown for c */ |
|
|
|
ConnectHelper(oc->c); |
|
|
|
OVPNMsgWait(100, NULL); |
|
|
|
/* if not immediately connected, show a progress dialog with |
|
* service state changes and retry/cancel options. Progress dialog |
|
* returns on error, cancel or when connected. |
|
*/ |
|
if (!ISCONNECTED(oc->c) && !ISDISCONNECTED(oc->c)) |
|
{ |
|
dmsg(L"Runninng progress dialog"); |
|
int res = RunProgressDialog(oc->c, ProgressCallback, (LONG_PTR) oc); |
|
dmsg(L"Out of progress dialog with res = %d", res); |
|
|
|
if (res == IDRETRY && !ISCONNECTED(oc->c)) |
|
{ |
|
LoadLocalizedStringBuf(status, _countof(status), IDS_NFO_STATE_RETRYING); |
|
NotifyEvents(oc, status); |
|
|
|
DisconnectHelper(oc->c); |
|
goto again; |
|
} |
|
else if (res == IDCANCEL && !ISCONNECTED(oc->c) && !ISDISCONNECTED(oc->c)) |
|
{ |
|
LoadLocalizedStringBuf(status, _countof(status), IDS_NFO_STATE_CANCELLING); |
|
NotifyEvents(oc, status); |
|
|
|
DisconnectHelper(oc->c); |
|
oc->connect_cancelled = TRUE; |
|
} |
|
} |
|
|
|
GetConnectionStatusText(oc->c, status, _countof(status)); |
|
NotifyEvents(oc, status); |
|
|
|
ShowStatusWindow(oc->c, FALSE); |
|
oc->qc = NULL; |
|
SetActiveProfile(NULL); |
|
|
|
dmsg(L"Exit with: <%ls>", ISCONNECTED(oc->c) ? L"success" : L"error/cancel"); |
|
|
|
return ISCONNECTED(oc->c) ? S_OK : E_FAIL; |
|
} |
|
|
|
static HRESULT WINAPI |
|
Disconnect(ICCPC *this) |
|
{ |
|
OpenVPNConnection *oc = (OpenVPNConnection *) this; |
|
dmsg(L"profile <%ls>", oc->display_name); |
|
|
|
NotifyEvents(oc, LoadLocalizedString(IDS_NFO_STATE_DISCONNECTING)); |
|
|
|
DisconnectHelper(oc->c); |
|
|
|
NotifyEvents(oc, L""); /* clear status text */ |
|
|
|
return S_OK; |
|
} |
|
|
|
HRESULT WINAPI |
|
OVPNConnection_Initialize(OpenVPNConnection *this, connection_t *conn, const wchar_t *display_name) |
|
{ |
|
HRESULT hr = S_OK; |
|
|
|
this->c = conn; |
|
this->display_name = display_name; |
|
dmsg(L"profile <%ls>", display_name); |
|
|
|
return hr; |
|
} |
|
|
|
/* Copy field descriptor -- caller will free using CoTaskMemFree, alloc using compatible allocator */ |
|
HRESULT |
|
CopyFieldDescriptor(CREDENTIAL_PROVIDER_FIELD_DESCRIPTOR *fd_out, |
|
const CREDENTIAL_PROVIDER_FIELD_DESCRIPTOR *fd_in) |
|
{ |
|
HRESULT hr = S_OK; |
|
|
|
memcpy(fd_out, fd_in, sizeof(CREDENTIAL_PROVIDER_FIELD_DESCRIPTOR)); |
|
/* now copy the label string if present */ |
|
if (fd_in->pszLabel) |
|
{ |
|
hr = SHStrDupW(fd_in->pszLabel, &fd_out->pszLabel); |
|
} |
|
|
|
return hr; |
|
}
|
|
|