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, ¶meter, ¶meterIndex)
174 && parameter.FindString(MDSU_VALUES, &username) == B_OK)
175 fHasUsername = true;
176
177 parameterIndex = 0;
178 if(FindMessageParameter(PPP_PASSWORD_KEY, fSettings, ¶meter, ¶meterIndex)
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, ¶meter, &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, ¶meter);
212
213 index = 0;
214 if(FindMessageParameter(PPP_PASSWORD_KEY, fSettings, ¶meter, &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, ¶meter);
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