1/*
2Open Tracker License
3
4Terms and Conditions
5
6Copyright (c) 1991-2000, Be Incorporated. All rights reserved.
7
8Permission is hereby granted, free of charge, to any person obtaining a copy of
9this software and associated documentation files (the "Software"), to deal in
10the Software without restriction, including without limitation the rights to
11use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
12of the Software, and to permit persons to whom the Software is furnished to do
13so, subject to the following conditions:
14
15The above copyright notice and this permission notice applies to all licensees
16and shall be included in all copies or substantial portions of the Software.
17
18THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF TITLE, MERCHANTABILITY,
20FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
21BE INCORPORATED BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
22AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF, OR IN CONNECTION
23WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
24
25Except as contained in this notice, the name of Be Incorporated shall not be
26used in advertising or otherwise to promote the sale, use or other dealings in
27this Software without prior written authorization from Be Incorporated.
28
29Tracker(TM), Be(R), BeOS(R), and BeIA(TM) are trademarks or registered trademarks
30of Be Incorporated in the United States and other countries. Other brand product
31names are registered trademarks or trademarks of their respective holders.
32All rights reserved.
33*/
34
35
36#include "FilePermissionsView.h"
37
38#include <stdio.h>
39#include <stdlib.h>
40
41#include <Beep.h>
42#include <Catalog.h>
43#include <Locale.h>
44
45
46const uint32 kPermissionsChanged = 'prch';
47const uint32 kNewOwnerEntered = 'nwow';
48const uint32 kNewGroupEntered = 'nwgr';
49
50
51#undef B_TRANSLATION_CONTEXT
52#define B_TRANSLATION_CONTEXT "FilePermissionsView"
53
54FilePermissionsView::FilePermissionsView(BRect rect, Model* model)
55	:	BView(rect, "FilePermissionsView", B_FOLLOW_LEFT_RIGHT, B_WILL_DRAW),
56		fModel(model)
57{
58	// Constants for the column labels: "User", "Group" and "Other".
59	const float kColumnLabelMiddle = 77, kColumnLabelTop = 6,
60		kColumnLabelSpacing = 37, kColumnLabelBottom = 20,
61		kColumnLabelWidth = 35, kAttribFontHeight = 10;
62
63	BStringView* strView;
64
65	strView = new BStringView(
66		BRect(kColumnLabelMiddle - kColumnLabelWidth / 2,
67			kColumnLabelTop,
68			kColumnLabelMiddle + kColumnLabelWidth / 2,
69			kColumnLabelBottom),
70		"", B_TRANSLATE("Owner"));
71	AddChild(strView);
72	strView->SetAlignment(B_ALIGN_CENTER);
73	strView->SetFontSize(kAttribFontHeight);
74
75	strView = new BStringView(
76		BRect(kColumnLabelMiddle - kColumnLabelWidth / 2
77				+ kColumnLabelSpacing,
78			kColumnLabelTop,
79			kColumnLabelMiddle + kColumnLabelWidth / 2 + kColumnLabelSpacing,
80			kColumnLabelBottom),
81		"", B_TRANSLATE("Group"));
82	AddChild(strView);
83	strView->SetAlignment(B_ALIGN_CENTER);
84	strView->SetFontSize(kAttribFontHeight);
85
86	strView = new BStringView(
87		BRect(kColumnLabelMiddle - kColumnLabelWidth / 2
88				+ 2 * kColumnLabelSpacing,
89			kColumnLabelTop,
90			kColumnLabelMiddle + kColumnLabelWidth / 2
91				+ 2 * kColumnLabelSpacing,
92			kColumnLabelBottom),
93		"", B_TRANSLATE("Other"));
94	AddChild(strView);
95	strView->SetAlignment(B_ALIGN_CENTER);
96	strView->SetFontSize(kAttribFontHeight);
97
98	// Constants for the row labels: "Read", "Write" and "Execute".
99	const float kRowLabelLeft = 10, kRowLabelTop = kColumnLabelTop + 15,
100		kRowLabelVerticalSpacing = 18, kRowLabelRight = kColumnLabelMiddle
101		- kColumnLabelWidth / 2 - 5, kRowLabelHeight = 14;
102
103	strView = new BStringView(BRect(kRowLabelLeft, kRowLabelTop,
104			kRowLabelRight, kRowLabelTop + kRowLabelHeight),
105		"", B_TRANSLATE("Read"));
106	AddChild(strView);
107	strView->SetAlignment(B_ALIGN_RIGHT);
108	strView->SetFontSize(kAttribFontHeight);
109
110	strView = new BStringView(BRect(kRowLabelLeft, kRowLabelTop
111			+ kRowLabelVerticalSpacing, kRowLabelRight, kRowLabelTop
112			+ kRowLabelVerticalSpacing + kRowLabelHeight),
113		"", B_TRANSLATE("Write"));
114	AddChild(strView);
115	strView->SetAlignment(B_ALIGN_RIGHT);
116	strView->SetFontSize(kAttribFontHeight);
117
118	strView = new BStringView(BRect(kRowLabelLeft, kRowLabelTop
119			+ 2 * kRowLabelVerticalSpacing, kRowLabelRight, kRowLabelTop
120			+ 2 * kRowLabelVerticalSpacing + kRowLabelHeight),
121		"", B_TRANSLATE("Execute"));
122	AddChild(strView);
123	strView->SetAlignment(B_ALIGN_RIGHT);
124	strView->SetFontSize(kAttribFontHeight);
125
126	// Constants for the 3x3 check box array.
127	const float kLeftMargin = kRowLabelRight + 15,
128		kTopMargin = kRowLabelTop - 2,
129		kHorizontalSpacing = kColumnLabelSpacing,
130		kVerticalSpacing = kRowLabelVerticalSpacing,
131		kCheckBoxWidth = 18, kCheckBoxHeight = 18;
132
133	FocusCheckBox** checkBoxArray[3][3] = {
134		{
135			&fReadUserCheckBox,
136			&fReadGroupCheckBox,
137			&fReadOtherCheckBox
138		},
139		{
140			&fWriteUserCheckBox,
141			&fWriteGroupCheckBox,
142			&fWriteOtherCheckBox
143		},
144		{
145			&fExecuteUserCheckBox,
146			&fExecuteGroupCheckBox,
147			&fExecuteOtherCheckBox
148		}
149	};
150
151	for (int32 x = 0; x < 3; x++) {
152		for (int32 y = 0; y < 3; y++) {
153			*checkBoxArray[y][x] =
154				new FocusCheckBox(BRect(kLeftMargin + kHorizontalSpacing * x,
155						kTopMargin + kVerticalSpacing * y,
156						kLeftMargin + kHorizontalSpacing * x + kCheckBoxWidth,
157						kTopMargin + kVerticalSpacing * y + kCheckBoxHeight),
158					"", "", new BMessage(kPermissionsChanged));
159			AddChild(*checkBoxArray[y][x]);
160		}
161	}
162
163	const float kTextControlLeft = 170, kTextControlRight = 270,
164		kTextControlTop = kColumnLabelTop, kTextControlHeight = 14,
165		kTextControlSpacing = 16;
166
167	strView = new BStringView(BRect(kTextControlLeft, kTextControlTop,
168		kTextControlRight, kTextControlTop + kTextControlHeight), "",
169		B_TRANSLATE("Owner"));
170	strView->SetAlignment(B_ALIGN_CENTER);
171	strView->SetFontSize(kAttribFontHeight);
172	AddChild(strView);
173
174	fOwnerTextControl = new BTextControl(
175		BRect(kTextControlLeft,
176			kTextControlTop - 2 + kTextControlSpacing,
177			kTextControlRight,
178			kTextControlTop + kTextControlHeight - 2 + kTextControlSpacing),
179		"", "", "", new BMessage(kNewOwnerEntered));
180	fOwnerTextControl->SetDivider(0);
181	AddChild(fOwnerTextControl);
182
183	strView = new BStringView(BRect(kTextControlLeft,
184			kTextControlTop + 5 + 2 * kTextControlSpacing,
185			kTextControlRight,
186			kTextControlTop + 2 + 2 * kTextControlSpacing
187				+ kTextControlHeight),
188		"", B_TRANSLATE("Group"));
189	strView->SetAlignment(B_ALIGN_CENTER);
190	strView->SetFontSize(kAttribFontHeight);
191	AddChild(strView);
192
193	fGroupTextControl = new BTextControl(BRect(kTextControlLeft,
194			kTextControlTop + 3 * kTextControlSpacing,
195			kTextControlRight,
196			kTextControlTop + 3 * kTextControlSpacing + kTextControlHeight),
197		"", "", "", new BMessage(kNewGroupEntered));
198	fGroupTextControl->SetDivider(0);
199	AddChild(fGroupTextControl);
200
201	SetViewColor(ui_color(B_PANEL_BACKGROUND_COLOR));
202
203	ModelChanged(model);
204}
205
206
207void
208FilePermissionsView::ModelChanged(Model* model)
209{
210	fModel = model;
211
212	bool hideCheckBoxes = false;
213	uid_t nodeOwner = 0;
214	gid_t nodeGroup = 0;
215	mode_t perms = 0;
216
217	if (fModel != NULL) {
218		BNode node(fModel->EntryRef());
219
220		if (node.InitCheck() == B_OK) {
221			if (fReadUserCheckBox->IsHidden()) {
222				fReadUserCheckBox->Show();
223				fReadGroupCheckBox->Show();
224				fReadOtherCheckBox->Show();
225				fWriteUserCheckBox->Show();
226				fWriteGroupCheckBox->Show();
227				fWriteOtherCheckBox->Show();
228				fExecuteUserCheckBox->Show();
229				fExecuteGroupCheckBox->Show();
230				fExecuteOtherCheckBox->Show();
231			}
232
233			if (node.GetPermissions(&perms) == B_OK) {
234				fReadUserCheckBox->SetValue((int32)(perms & S_IRUSR));
235				fReadGroupCheckBox->SetValue((int32)(perms & S_IRGRP));
236				fReadOtherCheckBox->SetValue((int32)(perms & S_IROTH));
237				fWriteUserCheckBox->SetValue((int32)(perms & S_IWUSR));
238				fWriteGroupCheckBox->SetValue((int32)(perms & S_IWGRP));
239				fWriteOtherCheckBox->SetValue((int32)(perms & S_IWOTH));
240				fExecuteUserCheckBox->SetValue((int32)(perms & S_IXUSR));
241				fExecuteGroupCheckBox->SetValue((int32)(perms & S_IXGRP));
242				fExecuteOtherCheckBox->SetValue((int32)(perms & S_IXOTH));
243			} else
244				hideCheckBoxes = true;
245
246			if (node.GetOwner(&nodeOwner) == B_OK) {
247				BString user;
248				if (nodeOwner == 0)
249					if (getenv("USER") != NULL)
250						user << getenv("USER");
251					else
252						user << "root";
253				else
254					user << nodeOwner;
255				fOwnerTextControl->SetText(user.String());
256			} else
257				fOwnerTextControl->SetText(B_TRANSLATE("Unknown"));
258
259			if (node.GetGroup(&nodeGroup) == B_OK) {
260				BString group;
261				if (nodeGroup == 0)
262					if (getenv("GROUP") != NULL)
263						group << getenv("GROUP");
264					else
265						group << "0";
266				else
267					group << nodeGroup;
268				fGroupTextControl->SetText(group.String());
269			} else
270				fGroupTextControl->SetText(B_TRANSLATE("Unknown"));
271
272			// Unless we're root, only allow the owner to transfer the ownership,
273			// i.e. disable text controls if uid:s doesn't match:
274			thread_id thisThread = find_thread(NULL);
275			thread_info threadInfo;
276			get_thread_info(thisThread, &threadInfo);
277			team_info teamInfo;
278			get_team_info(threadInfo.team, &teamInfo);
279			if (teamInfo.uid != 0 && nodeOwner != teamInfo.uid) {
280				fOwnerTextControl->SetEnabled(false);
281				fGroupTextControl->SetEnabled(false);
282			} else {
283				fOwnerTextControl->SetEnabled(true);
284				fGroupTextControl->SetEnabled(true);
285			}
286		} else
287			hideCheckBoxes = true;
288	} else
289		hideCheckBoxes = true;
290
291	if (hideCheckBoxes) {
292		fReadUserCheckBox->Hide();
293		fReadGroupCheckBox->Hide();
294		fReadOtherCheckBox->Hide();
295		fWriteUserCheckBox->Hide();
296		fWriteGroupCheckBox->Hide();
297		fWriteOtherCheckBox->Hide();
298		fExecuteUserCheckBox->Hide();
299		fExecuteGroupCheckBox->Hide();
300		fExecuteOtherCheckBox->Hide();
301	}
302}
303
304
305void
306FilePermissionsView::MessageReceived(BMessage* message)
307{
308	switch(message->what) {
309		case kPermissionsChanged:
310			if (fModel != NULL) {
311				mode_t newPermissions = 0;
312				newPermissions
313					= (mode_t)((fReadUserCheckBox->Value() ? S_IRUSR : 0)
314					| (fReadGroupCheckBox->Value() ? S_IRGRP : 0)
315					| (fReadOtherCheckBox->Value() ? S_IROTH : 0)
316
317					| (fWriteUserCheckBox->Value() ? S_IWUSR : 0)
318					| (fWriteGroupCheckBox->Value() ? S_IWGRP : 0)
319					| (fWriteOtherCheckBox->Value() ? S_IWOTH : 0)
320
321					| (fExecuteUserCheckBox->Value() ? S_IXUSR : 0)
322					| (fExecuteGroupCheckBox->Value() ? S_IXGRP :0)
323					| (fExecuteOtherCheckBox->Value() ? S_IXOTH : 0));
324
325				BNode node(fModel->EntryRef());
326
327				if (node.InitCheck() == B_OK)
328					node.SetPermissions(newPermissions);
329				else {
330					ModelChanged(fModel);
331					beep();
332				}
333			}
334			break;
335
336		case kNewOwnerEntered:
337			if (fModel != NULL) {
338				uid_t owner;
339				if (sscanf(fOwnerTextControl->Text(), "%d", &owner) == 1) {
340					BNode node(fModel->EntryRef());
341					if (node.InitCheck() == B_OK)
342						node.SetOwner(owner);
343					else {
344						ModelChanged(fModel);
345						beep();
346					}
347				} else {
348					ModelChanged(fModel);
349					beep();
350				}
351			}
352			break;
353
354		case kNewGroupEntered:
355			if (fModel != NULL) {
356				gid_t group;
357				if (sscanf(fGroupTextControl->Text(), "%d", &group) == 1) {
358					BNode node(fModel->EntryRef());
359					if (node.InitCheck() == B_OK)
360						node.SetGroup(group);
361					else {
362						ModelChanged(fModel);
363						beep();
364					}
365				} else {
366					ModelChanged(fModel);
367					beep();
368				}
369			}
370			break;
371
372		default:
373			_inherited::MessageReceived(message);
374			break;
375	}
376}
377
378
379void
380FilePermissionsView::AttachedToWindow()
381{
382	fReadUserCheckBox->SetTarget(this);
383	fReadGroupCheckBox->SetTarget(this);
384	fReadOtherCheckBox->SetTarget(this);
385	fWriteUserCheckBox->SetTarget(this);
386	fWriteGroupCheckBox->SetTarget(this);
387	fWriteOtherCheckBox->SetTarget(this);
388	fExecuteUserCheckBox->SetTarget(this);
389	fExecuteGroupCheckBox->SetTarget(this);
390	fExecuteOtherCheckBox->SetTarget(this);
391
392	fOwnerTextControl->SetTarget(this);
393	fGroupTextControl->SetTarget(this);
394}
395