xref: /haiku/src/bin/network/ppp_up/ConnectionView.cpp (revision bab64f65bb775dc23060e276f1f1c4498ab7af6c)
1 /*
2  * Copyright 2005, Waldemar Kornewald <wkornew@gmx.net>
3  * Distributed under the terms of the MIT License.
4  */
5 
6 #include "ConnectionView.h"
7 #include "PPPDeskbarReplicant.h"
8 #include <MessageDriverSettingsUtils.h>
9 
10 #include <Application.h>
11 #include <Box.h>
12 #include <Button.h>
13 #include <Deskbar.h>
14 #include <Entry.h>
15 #include <File.h>
16 #include <String.h>
17 #include <StringView.h>
18 #include <TextControl.h>
19 #include <Window.h>
20 
21 #include <PPPInterface.h>
22 #include <settings_tools.h>
23 #include <algorithm>
24 	// for max()
25 
26 using std::max;
27 
28 // GUI constants
29 static const uint32 kDefaultButtonWidth = 80;
30 
31 // message constants
32 static const uint32 kMsgCancel = 'CANC';
33 static const uint32 kMsgConnect = 'CONN';
34 static const uint32 kMsgUpdate = 'MUPD';
35 
36 // labels
37 static const char *kLabelSavePassword = "Save password";
38 static const char *kLabelName = "Username: ";
39 static const char *kLabelPassword = "Password: ";
40 static const char *kLabelConnect = "Connect";
41 static const char *kLabelCancel = "Cancel";
42 static const char *kLabelAuthentication = "Authentication";
43 
44 // connection status strings
45 static const char *kTextConnecting = "Connecting...";
46 static const char *kTextConnectionEstablished = "Connection established.";
47 static const char *kTextNotConnected = "Not connected.";
48 static const char *kTextDeviceUpFailed = "Failed to connect.";
49 static const char *kTextAuthenticating = "Authenticating...";
50 static const char *kTextAuthenticationFailed = "Authentication failed!";
51 static const char *kTextConnectionLost = "Connection lost!";
52 
53 
ConnectionView(BRect rect,const BString & interfaceName)54 ConnectionView::ConnectionView(BRect rect, const BString& interfaceName)
55 	: BView(rect, "ConnectionView", B_FOLLOW_NONE, 0),
56 	fListener(this),
57 	fInterfaceName(interfaceName),
58 	fKeepLabel(false)
59 {
60 	SetViewUIColor(B_PANEL_BACKGROUND_COLOR);
61 
62 	rect = Bounds();
63 	rect.InsetBy(5, 5);
64 	rect.bottom = rect.top
65 		+ 25 // space for topmost control
66 		+ 3 * 20 // size of controls
67 		+ 3 * 5; // space beween controls and bottom of box
68 	BBox *authenticationBox = new BBox(rect, "Authentication");
69 	authenticationBox->SetLabel(kLabelAuthentication);
70 	rect = authenticationBox->Bounds();
71 	rect.InsetBy(10, 20);
72 	rect.bottom = rect.top + 20;
73 	fUsername = new BTextControl(rect, "username", kLabelName, NULL, NULL);
74 	rect.top = rect.bottom + 5;
75 	rect.bottom = rect.top + 20;
76 	fPassword = new BTextControl(rect, "password", kLabelPassword, NULL, NULL);
77 	fPassword->TextView()->HideTyping(true);
78 
79 	// set dividers
80 	float width = max(StringWidth(fUsername->Label()),
81 		StringWidth(fPassword->Label()));
82 	fUsername->SetDivider(width + 5);
83 	fPassword->SetDivider(width + 5);
84 
85 	rect.top = rect.bottom + 5;
86 	rect.bottom = rect.top + 20;
87 	fSavePassword = new BCheckBox(rect, "SavePassword", kLabelSavePassword, NULL);
88 
89 	authenticationBox->AddChild(fUsername);
90 	authenticationBox->AddChild(fPassword);
91 	authenticationBox->AddChild(fSavePassword);
92 	AddChild(authenticationBox);
93 
94 	rect = authenticationBox->Frame();
95 	rect.top = rect.bottom + 10;
96 	rect.bottom = rect.top + 15;
97 	fAttemptView = new BStringView(rect, "AttemptView", "");
98 	AddChild(fAttemptView);
99 
100 	// add status view
101 	rect.top = rect.bottom + 5;
102 	rect.bottom = rect.top + 15;
103 	fStatusView = new BStringView(rect, "StatusView", "");
104 	AddChild(fStatusView);
105 
106 	// add "Connect" and "Cancel" buttons
107 	rect.top = rect.bottom + 10;
108 	rect.bottom = rect.top + 25;
109 	rect.right = rect.left + kDefaultButtonWidth;
110 	fConnectButton = new BButton(rect, "ConnectButton", kLabelConnect,
111 		new BMessage(kMsgConnect));
112 
113 	rect.left = rect.right + 10;
114 	rect.right = rect.left + kDefaultButtonWidth;
115 	fCancelButton = new BButton(rect, "CancelButton", kLabelCancel,
116 		new BMessage(kMsgCancel));
117 
118 	AddChild(fConnectButton);
119 	AddChild(fCancelButton);
120 }
121 
122 
123 void
AttachedToWindow()124 ConnectionView::AttachedToWindow()
125 {
126 	Reload();
127 	fListener.WatchManager();
128 	WatchInterface(fListener.Manager().InterfaceWithName(fInterfaceName.String()));
129 
130 	Window()->SetDefaultButton(fConnectButton);
131 	fConnectButton->SetTarget(this);
132 	fCancelButton->SetTarget(this);
133 }
134 
135 
136 void
MessageReceived(BMessage * message)137 ConnectionView::MessageReceived(BMessage *message)
138 {
139 	switch(message->what) {
140 		case PPP_REPORT_MESSAGE:
141 			HandleReportMessage(message);
142 		break;
143 
144 		case kMsgConnect:
145 			Connect();
146 		break;
147 
148 		case kMsgCancel:
149 			Cancel();
150 		break;
151 
152 		default:
153 			BView::MessageReceived(message);
154 	}
155 }
156 
157 
158 // update authentication UI
159 void
Reload()160 ConnectionView::Reload()
161 {
162 	// load username and password
163 	BString path("ptpnet/");
164 	path << fInterfaceName;
165 	fSettings.MakeEmpty();
166 	ReadMessageDriverSettings(path.String(), &fSettings);
167 
168 	fHasUsername = fHasPassword = false;
169 	BString username, password;
170 
171 	BMessage parameter;
172 	int32 parameterIndex = 0;
173 	if(FindMessageParameter(PPP_USERNAME_KEY, fSettings, &parameter, &parameterIndex)
174 			&& parameter.FindString(MDSU_VALUES, &username) == B_OK)
175 		fHasUsername = true;
176 
177 	parameterIndex = 0;
178 	if(FindMessageParameter(PPP_PASSWORD_KEY, fSettings, &parameter, &parameterIndex)
179 			&& parameter.FindString(MDSU_VALUES, &password) == B_OK)
180 		fHasPassword = true;
181 
182 	fUsername->SetText(username.String());
183 	fPassword->SetText(password.String());
184 	fSavePassword->SetValue(fHasPassword);
185 
186 	fUsername->SetEnabled(fHasUsername);
187 	fPassword->SetEnabled(fHasUsername);
188 	fSavePassword->SetEnabled(fHasUsername);
189 }
190 
191 
192 void
Connect()193 ConnectionView::Connect()
194 {
195 	PPPInterface interface(PPPManager().CreateInterfaceWithName(
196 		fInterfaceName.String()));
197 	interface.SetUsername(Username());
198 	interface.SetPassword(Password());
199 	interface.SetAskBeforeConnecting(false);
200 	interface.Up();
201 
202 	// save settings
203 	if(fHasUsername) {
204 		BMessage parameter;
205 		int32 index = 0;
206 		if(FindMessageParameter(PPP_USERNAME_KEY, fSettings, &parameter, &index))
207 			fSettings.RemoveData(MDSU_PARAMETERS, index);
208 		parameter.MakeEmpty();
209 		parameter.AddString(MDSU_NAME, PPP_USERNAME_KEY);
210 		parameter.AddString(MDSU_VALUES, Username());
211 		fSettings.AddMessage(MDSU_PARAMETERS, &parameter);
212 
213 		index = 0;
214 		if(FindMessageParameter(PPP_PASSWORD_KEY, fSettings, &parameter, &index))
215 			fSettings.RemoveData(MDSU_PARAMETERS, index);
216 		if(DoesSavePassword()) {
217 			parameter.MakeEmpty();
218 			parameter.AddString(MDSU_NAME, PPP_PASSWORD_KEY);
219 			parameter.AddString(MDSU_VALUES, Password());
220 			fSettings.AddMessage(MDSU_PARAMETERS, &parameter);
221 		}
222 
223 		BEntry entry;
224 		if(interface.GetSettingsEntry(&entry) == B_OK) {
225 			BFile file(&entry, B_WRITE_ONLY);
226 			WriteMessageDriverSettings(file, fSettings);
227 		}
228 	}
229 
230 	Reload();
231 }
232 
233 
234 void
Cancel()235 ConnectionView::Cancel()
236 {
237 	PPPInterface interface(fListener.Interface());
238 	bool quit = false;
239 	ppp_interface_info_t info;
240 	if(interface.GetInterfaceInfo(&info) && info.info.phase < PPP_ESTABLISHMENT_PHASE)
241 		quit = true;
242 	interface.Down();
243 	if(quit)
244 		Window()->Quit();
245 }
246 
247 
248 // Clean up before our window quits (called by ConnectionWindow).
249 void
CleanUp()250 ConnectionView::CleanUp()
251 {
252 	fListener.StopWatchingInterface();
253 	fListener.StopWatchingManager();
254 }
255 
256 
257 BString
AttemptString() const258 ConnectionView::AttemptString() const
259 {
260 	PPPInterface interface(fListener.Interface());
261 	ppp_interface_info_t info;
262 	if(!interface.GetInterfaceInfo(&info))
263 		return BString("");
264 	BString attempt;
265 	attempt << "Attempt " << info.info.connectAttempt << " of " <<
266 		info.info.connectRetriesLimit + 1;
267 
268 	return attempt;
269 }
270 
271 
272 void
HandleReportMessage(BMessage * message)273 ConnectionView::HandleReportMessage(BMessage *message)
274 {
275 	ppp_interface_id id;
276 	if(message->FindInt32("interface", reinterpret_cast<int32*>(&id)) != B_OK
277 			|| (fListener.Interface() != PPP_UNDEFINED_INTERFACE_ID
278 				&& id != fListener.Interface()))
279 		return;
280 
281 	int32 type, code;
282 	message->FindInt32("type", &type);
283 	message->FindInt32("code", &code);
284 
285 	if(type == PPP_MANAGER_REPORT && code == PPP_REPORT_INTERFACE_CREATED) {
286 		PPPInterface interface(id);
287 		if(interface.InitCheck() != B_OK || fInterfaceName != interface.Name())
288 			return;
289 
290 		WatchInterface(id);
291 
292 		if(((fHasUsername && !fHasPassword) || fAskBeforeConnecting)
293 				&& Window()->IsHidden())
294 			Window()->Show();
295 	} else if(type == PPP_CONNECTION_REPORT)
296 		UpdateStatus(code);
297 	else if(type == PPP_DESTRUCTION_REPORT)
298 		fListener.StopWatchingInterface();
299 }
300 
301 
302 void
UpdateStatus(int32 code)303 ConnectionView::UpdateStatus(int32 code)
304 {
305 	BString attemptString = AttemptString();
306 	fAttemptView->SetText(attemptString.String());
307 
308 	if(code == PPP_REPORT_UP_SUCCESSFUL) {
309 		fStatusView->SetText(kTextConnectionEstablished);
310 		PPPDeskbarReplicant *item = new PPPDeskbarReplicant(fListener.Interface());
311 		BDeskbar().AddItem(item);
312 		delete item;
313 		Window()->Quit();
314 		return;
315 	}
316 
317 	// maybe the status string must not be changed (codes that set fKeepLabel to false
318 	// should still be handled)
319 	if(fKeepLabel && code != PPP_REPORT_GOING_UP && code != PPP_REPORT_UP_SUCCESSFUL)
320 		return;
321 
322 	if(fListener.InitCheck() != B_OK) {
323 		fStatusView->SetText(kTextConnectionLost);
324 		return;
325 	}
326 
327 	// only errors should set fKeepLabel to true
328 	switch(code) {
329 		case PPP_REPORT_GOING_UP:
330 			fKeepLabel = false;
331 			fStatusView->SetText(kTextConnecting);
332 		break;
333 
334 		case PPP_REPORT_DOWN_SUCCESSFUL:
335 			fStatusView->SetText(kTextNotConnected);
336 		break;
337 
338 		case PPP_REPORT_DEVICE_UP_FAILED:
339 			fKeepLabel = true;
340 			fStatusView->SetText(kTextDeviceUpFailed);
341 		break;
342 
343 		case PPP_REPORT_AUTHENTICATION_REQUESTED:
344 			fStatusView->SetText(kTextAuthenticating);
345 		break;
346 
347 		case PPP_REPORT_AUTHENTICATION_FAILED:
348 			fKeepLabel = true;
349 			fStatusView->SetText(kTextAuthenticationFailed);
350 		break;
351 
352 		case PPP_REPORT_CONNECTION_LOST:
353 			fKeepLabel = true;
354 			fStatusView->SetText(kTextConnectionLost);
355 		break;
356 	}
357 }
358 
359 
360 void
WatchInterface(ppp_interface_id ID)361 ConnectionView::WatchInterface(ppp_interface_id ID)
362 {
363 	fListener.WatchInterface(ID);
364 
365 	// update status
366 	Reload();
367 	PPPInterface interface(fListener.Interface());
368 	ppp_interface_info_t info;
369 	if(!interface.GetInterfaceInfo(&info)) {
370 		UpdateStatus(PPP_REPORT_DOWN_SUCCESSFUL);
371 		fAskBeforeConnecting = false;
372 	} else
373 		fAskBeforeConnecting = info.info.askBeforeConnecting;
374 }
375