1/* 2 * Copyright 2008, François Revol, <revol@free.fr>. All rights reserved. 3 * Distributed under the terms of the MIT License. 4 */ 5#include <Catalog.h> 6#include <ScrollView.h> 7#include <String.h> 8#include <Window.h> 9#ifdef __HAIKU__ 10#include <Layout.h> 11#endif 12 13#include <pwd.h> 14 15#include "LoginApp.h" 16#include "LoginView.h" 17 18#undef B_TRANSLATION_CONTEXT 19#define B_TRANSLATION_CONTEXT "Login View" 20 21#define LW 120 22#define CSEP 15 23#define BH 20 24#define BW 60 25 26class PwdItem : public BStringItem { 27public: 28 PwdItem(struct passwd *pwd, uint32 level = 0, 29 bool expanded = true) 30 : BStringItem("", level, expanded) 31 { 32 if (pwd) { 33 BString name(pwd->pw_gecos); 34 // TODO: truncate at first ; 35 fLogin = pwd->pw_name; 36 SetText(name.String()); 37 } 38 }; 39 virtual ~PwdItem() {}; 40 const char* Login() const { return fLogin.String(); }; 41private: 42 BString fLogin; 43}; 44 45 46LoginView::LoginView(BRect frame) 47 : BView(frame, "LoginView", B_FOLLOW_ALL, B_PULSE_NEEDED) 48{ 49 // TODO: when I don't need to test in BeOS anymore, 50 // rewrite to use layout engine. 51 SetViewColor(ui_color(B_PANEL_BACKGROUND_COLOR)); 52 SetLowColor(ViewColor()); 53 BRect r; 54 r.Set(CSEP, CSEP, LW, Bounds().Height() - 3 * CSEP - BH); 55 fUserList = new BListView(r, "users"); 56 BScrollView *sv = new BScrollView("userssv", fUserList, 57 B_FOLLOW_LEFT | B_FOLLOW_TOP, 0, false, true); 58 AddChild(sv); 59 fUserList->SetSelectionMessage(new BMessage(kUserSelected)); 60 fUserList->SetInvocationMessage(new BMessage(kUserInvoked)); 61 62 r.Set(LW + 30, Bounds().top + CSEP, 63 Bounds().right - CSEP, Bounds().top + CSEP + CSEP); 64 fLoginControl = new BTextControl(r, "login", B_TRANSLATE("Login:"), "", 65 new BMessage(kLoginEdited)); 66 AddChild(fLoginControl); 67 68 r.OffsetBySelf(0, CSEP + CSEP); 69 fPasswordControl = new BTextControl(r, "password", 70 B_TRANSLATE("Password:"), "", new BMessage(kPasswordEdited)); 71 fPasswordControl->TextView()->HideTyping(true); 72 AddChild(fPasswordControl); 73 74 r.OffsetBySelf(0, CSEP + CSEP); 75 fHidePasswordCheckBox = new BCheckBox(r, "hidepw", 76 B_TRANSLATE("Hide password"), new BMessage(kHidePassword)); 77 fHidePasswordCheckBox->SetValue(1); 78 AddChild(fHidePasswordCheckBox); 79 80 // buttons 81 float buttonWidth = BW; //(Bounds().Width() - 4 * CSEP) / 3; 82 BRect buttonRect(0, Bounds().bottom - BH, 83 buttonWidth, Bounds().bottom); 84 buttonRect.OffsetBySelf(CSEP, -CSEP); 85 86 fHaltButton = new BButton(buttonRect, "halt", B_TRANSLATE("Halt"), 87 new BMessage(kHaltAction)); 88 AddChild(fHaltButton); 89 90 buttonRect.OffsetBySelf(CSEP + buttonWidth, 0); 91 fRebootButton = new BButton(buttonRect, "reboot", B_TRANSLATE("Reboot"), 92 new BMessage(kRebootAction)); 93 AddChild(fRebootButton); 94 95 BRect infoRect(buttonRect); 96 infoRect.OffsetBySelf(buttonWidth + CSEP, 0); 97 98 buttonRect.OffsetToSelf(Bounds().Width() - CSEP - buttonWidth, 99 Bounds().Height() - CSEP - BH); 100 fLoginButton = new BButton(buttonRect, "ok", B_TRANSLATE("OK"), 101 new BMessage(kAttemptLogin)); 102 AddChild(fLoginButton); 103 104 infoRect.right = buttonRect.left - CSEP + 5; 105 BString info; 106 //info << hostname; 107 fInfoView = new BStringView(infoRect, "info", info.String()); 108 AddChild(fInfoView); 109} 110 111 112LoginView::~LoginView() 113{ 114} 115 116void 117LoginView::AttachedToWindow() 118{ 119 fUserList->SetTarget(this); 120 fLoginControl->SetTarget(this); 121 fPasswordControl->SetTarget(this); 122 fHidePasswordCheckBox->SetTarget(this); 123 fHaltButton->SetTarget(be_app_messenger); 124 fRebootButton->SetTarget(be_app_messenger); 125 fLoginButton->SetTarget(this); 126 Window()->SetDefaultButton(fLoginButton); 127 //fLoginControl->MakeFocus(); 128 fUserList->MakeFocus(); 129 // populate user list 130 BMessenger(this).SendMessage(kAddNextUser); 131} 132 133 134void 135LoginView::MessageReceived(BMessage *message) 136{ 137 switch (message->what) { 138 case kSetProgress: 139 break; 140 case kAddNextUser: 141 AddNextUser(); 142 break; 143 case kUserSelected: 144 { 145 int32 selection = fUserList->CurrentSelection(); 146 if (selection > -1) { 147 PwdItem *item = dynamic_cast<PwdItem *>( 148 fUserList->ItemAt(selection)); 149 if (item) 150 fLoginControl->SetText(item->Login()); 151 } 152 break; 153 } 154 case kUserInvoked: 155 fPasswordControl->MakeFocus(); 156 break; 157 case kLoginEdited: 158 break; 159 case kHidePassword: 160 fPasswordControl->TextView()->HideTyping( 161 fHidePasswordCheckBox->Value()); 162 break; 163 case kAttemptLogin: 164 { 165 // if no pass specified and we were selecting the user, 166 // give a chance to enter the password 167 // else we might want to enter an empty password. 168 if (strlen(fPasswordControl->Text()) < 1 169 && (fUserList->IsFocus() || fLoginControl->IsFocus())) { 170 fPasswordControl->MakeFocus(); 171 break; 172 } 173 BMessage *m = new BMessage(kAttemptLogin); 174 m->AddString("login", fLoginControl->Text()); 175 m->AddString("password", fPasswordControl->Text()); 176 be_app->PostMessage(m, NULL, this); 177 break; 178 } 179 case kLoginBad: 180 fPasswordControl->SetText(""); 181 EnableControls(false); 182 fInfoView->SetText(B_TRANSLATE("Invalid login!")); 183 if (Window()) { 184 BPoint savedPos = Window()->Frame().LeftTop(); 185 for (int i = 0; i < 10; i++) { 186 BPoint p(savedPos); 187 p.x += (i%2) ? 10 : -10; 188 Window()->MoveTo(p); 189 Window()->UpdateIfNeeded(); 190 snooze(30000); 191 } 192 Window()->MoveTo(savedPos); 193 } 194 EnableControls(true); 195 break; 196 case kLoginOk: 197 // XXX: quit ? 198 if (Window()) { 199 Window()->Hide(); 200 } 201 break; 202 default: 203 message->PrintToStream(); 204 BView::MessageReceived(message); 205 } 206} 207 208 209void 210LoginView::Pulse() 211{ 212 BString info; 213 time_t now = time(NULL); 214 struct tm *t = localtime(&now); 215 // TODO: use strftime and locale settings 216 info << asctime(t); 217 info.RemoveSet("\r\n"); 218 fInfoView->SetText(info.String()); 219} 220 221 222void 223LoginView::AddNextUser() 224{ 225 struct passwd *pwd; 226 if (fUserList->CountItems() < 1) 227 setpwent(); 228 229 pwd = getpwent(); 230 231 if (pwd && pwd->pw_shell && 232 strcmp(pwd->pw_shell, "false") && 233 strcmp(pwd->pw_shell, "true") && 234 strcmp(pwd->pw_shell, "/bin/false") && 235 strcmp(pwd->pw_shell, "/bin/true")) { 236 // not disabled 237 PwdItem *item = new PwdItem(pwd); 238 fUserList->AddItem(item); 239 } 240 if (pwd) 241 BMessenger(this).SendMessage(kAddNextUser); 242 else 243 endpwent(); 244} 245 246 247void 248LoginView::EnableControls(bool enable) 249{ 250 int32 i; 251 for (i = 0; i < fUserList->CountItems(); i++) { 252 fUserList->ItemAt(i)->SetEnabled(enable); 253 } 254 fLoginControl->SetEnabled(enable); 255 fPasswordControl->SetEnabled(enable); 256 fHidePasswordCheckBox->SetEnabled(enable); 257 fHaltButton->SetEnabled(enable); 258 fRebootButton->SetEnabled(enable); 259 fLoginButton->SetEnabled(enable); 260} 261 262