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 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 SetViewColor(ui_color(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 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 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 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 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 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 250 ConnectionView::CleanUp() 251 { 252 fListener.StopWatchingInterface(); 253 fListener.StopWatchingManager(); 254 } 255 256 257 BString 258 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 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 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 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