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 26using std::max; 27 28// GUI constants 29static const uint32 kDefaultButtonWidth = 80; 30 31// message constants 32static const uint32 kMsgCancel = 'CANC'; 33static const uint32 kMsgConnect = 'CONN'; 34static const uint32 kMsgUpdate = 'MUPD'; 35 36// labels 37static const char *kLabelSavePassword = "Save password"; 38static const char *kLabelName = "Username: "; 39static const char *kLabelPassword = "Password: "; 40static const char *kLabelConnect = "Connect"; 41static const char *kLabelCancel = "Cancel"; 42static const char *kLabelAuthentication = "Authentication"; 43 44// connection status strings 45static const char *kTextConnecting = "Connecting..."; 46static const char *kTextConnectionEstablished = "Connection established."; 47static const char *kTextNotConnected = "Not connected."; 48static const char *kTextDeviceUpFailed = "Failed to connect."; 49static const char *kTextAuthenticating = "Authenticating..."; 50static const char *kTextAuthenticationFailed = "Authentication failed!"; 51static const char *kTextConnectionLost = "Connection lost!"; 52 53 54ConnectionView::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 123void 124ConnectionView::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 136void 137ConnectionView::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 159void 160ConnectionView::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 192void 193ConnectionView::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 234void 235ConnectionView::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). 249void 250ConnectionView::CleanUp() 251{ 252 fListener.StopWatchingInterface(); 253 fListener.StopWatchingManager(); 254} 255 256 257BString 258ConnectionView::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 272void 273ConnectionView::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 302void 303ConnectionView::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 360void 361ConnectionView::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