1/*
2 * Copyright 2008, François Revol, <revol@free.fr>. All rights reserved.
3 * Distributed under the terms of the MIT License.
4 */
5
6
7#include <Alert.h>
8#include <Catalog.h>
9#include <Screen.h>
10#include <String.h>
11#include <View.h>
12
13#include <stdio.h>
14#include <stdlib.h>
15#include <string.h>
16#include <unistd.h>
17#include <pwd.h>
18
19#include <LaunchRoster.h>
20#include <RosterPrivate.h>
21#include <shadow.h>
22
23#include "multiuser_utils.h"
24
25#include "LoginApp.h"
26#include "LoginWindow.h"
27#include "DesktopWindow.h"
28
29
30#undef B_TRANSLATION_CONTEXT
31#define B_TRANSLATION_CONTEXT "Login App"
32
33const char *kLoginAppSig = "application/x-vnd.Haiku-Login";
34
35
36LoginApp::LoginApp()
37	:
38	BApplication(kLoginAppSig),
39	fEditShelfMode(false),
40	fModalMode(true)
41{
42}
43
44
45LoginApp::~LoginApp()
46{
47}
48
49
50void
51LoginApp::ReadyToRun()
52{
53	BScreen screen;
54
55	if (fEditShelfMode) {
56		BAlert* alert = new BAlert(B_TRANSLATE("Info"), B_TRANSLATE("You can "
57			"customize the desktop shown behind the Login application by "
58			"dropping replicants onto it.\n\n"
59			"When you are finished just quit the application (Cmd-Q)."),
60			B_TRANSLATE("OK"));
61		alert->SetFlags(alert->Flags() | B_CLOSE_ON_ESCAPE);
62		alert->Go(NULL);
63	} else {
64		float sizeDelta = (float)be_plain_font->Size()/12.0f;
65		BRect frame(0, 0, 450 * sizeDelta, 150 * sizeDelta);
66		frame.OffsetBySelf(screen.Frame().Width()/2 - frame.Width()/2,
67			screen.Frame().Height()/2 - frame.Height()/2);
68		fLoginWindow = new LoginWindow(frame);
69		fLoginWindow->Show();
70	}
71
72	fDesktopWindow = new DesktopWindow(screen.Frame(), fEditShelfMode);
73	fDesktopWindow->Show();
74	// TODO: add a shelf with Activity Monitor replicant :)
75}
76
77
78void
79LoginApp::MessageReceived(BMessage *message)
80{
81	bool reboot = false;
82
83	switch (message->what) {
84		case kAttemptLogin:
85			TryLogin(message);
86			// TODO
87			break;
88		case kHaltAction:
89			reboot = false;
90			// FALLTHROUGH
91		case kRebootAction:
92		{
93			BRoster roster;
94			BRoster::Private rosterPrivate(roster);
95			status_t error = rosterPrivate.ShutDown(reboot, false, false);
96			if (error < B_OK) {
97				BString msg(B_TRANSLATE("Error: %1"));
98				msg.ReplaceFirst("%1", strerror(error));
99				BAlert* alert = new BAlert(("Error"), msg.String(),
100					B_TRANSLATE("OK"));
101				alert->SetFlags(alert->Flags() | B_CLOSE_ON_ESCAPE);
102				alert->Go();
103			}
104			break;
105		}
106		case kSuspendAction:
107		{
108			BAlert* alert = new BAlert(B_TRANSLATE("Error"),
109				B_TRANSLATE("Unimplemented"), B_TRANSLATE("OK"));
110			alert->SetFlags(alert->Flags() | B_CLOSE_ON_ESCAPE);
111			alert->Go();
112			break;
113		}
114
115		default:
116			BApplication::MessageReceived(message);
117	}
118}
119
120
121void
122LoginApp::ArgvReceived(int32 argc, char **argv)
123{
124	for (int i = 1; i < argc; i++) {
125		BString arg(argv[i]);
126		//printf("[%d]: %s\n", i, argv[i]);
127		if (arg == "--edit")
128			fEditShelfMode = true;
129		else if (arg == "--nonmodal")
130			fModalMode = false;
131		else /*if (arg == "--help")*/ {
132			printf(B_TRANSLATE("Login application for Haiku\nUsage:\n"));
133			printf("%s [--nonmodal] [--edit]\n", argv[0]);
134			printf(B_TRANSLATE("--nonmodal	Do not make the window modal\n"));
135			printf(B_TRANSLATE("--edit	Launch in shelf editting mode to "
136				"allow customizing the desktop.\n"));
137			// just return to the shell
138			exit((arg == "--help") ? 0 : 1);
139			return;
140		}
141	}
142}
143
144
145void
146LoginApp::TryLogin(BMessage *message)
147{
148	BMessage reply(kLoginBad);
149	status_t status = B_BAD_VALUE;
150
151	const char* login;
152	if (message->FindString("login", &login) == B_OK) {
153		const char* password = message->GetString("password");
154
155		status = ValidateLogin(login, password);
156		if (status == B_OK) {
157			status = BLaunchRoster().StartSession(login);
158			if (status == B_OK)
159				Quit();
160		}
161
162		fprintf(stderr, "ValidateLogin: %s\n", strerror(status));
163	}
164
165	if (status == B_OK) {
166		reply.what = kLoginOk;
167		message->SendReply(&reply);
168	} else {
169		reply.AddInt32("error", status);
170		message->SendReply(&reply);
171	}
172}
173
174
175status_t
176LoginApp::ValidateLogin(const char *login, const char *password)
177{
178	struct passwd *pwd;
179
180	pwd = getpwnam(login);
181	if (pwd == NULL)
182		return ENOENT;
183	if (strcmp(pwd->pw_name, login) != 0)
184		return ENOENT;
185
186	if (verify_password(pwd, getspnam(login), password))
187		return B_OK;
188
189	return B_PERMISSION_DENIED;
190}
191
192
193int
194LoginApp::getpty(char *pty, char *tty)
195{
196	static const char major[] = "pqrs";
197	static const char minor[] = "0123456789abcdef";
198	uint32 i, j;
199	int32 fd = -1;
200
201	for (i = 0; i < sizeof(major); i++)
202	{
203		for (j = 0; j < sizeof(minor); j++)
204		{
205			sprintf(pty, "/dev/pt/%c%c", major[i], minor[j]);
206			sprintf(tty, "/dev/tt/%c%c", major[i], minor[j]);
207			fd = open(pty, O_RDWR|O_NOCTTY);
208			if (fd >= 0)
209			{
210				return fd;
211			}
212		}
213	}
214
215	return fd;
216}
217