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
46#undef B_TRANSLATION_CONTEXT
47#define B_TRANSLATION_CONTEXT "FilePermissionsView"
48
49
50const uint32 kPermissionsChanged = 'prch';
51const uint32 kNewOwnerEntered = 'nwow';
52const uint32 kNewGroupEntered = 'nwgr';
53
54
55class RotatedStringView: public BStringView
56{
57public:
58	RotatedStringView(BRect r, const char* name, const char* label)
59		: BStringView(r, name, label)
60	{
61	}
62
63	void Draw(BRect invalidate)
64	{
65		RotateBy(-M_PI / 5);
66		TranslateBy(0, Bounds().Height() / 3);
67		BStringView::Draw(invalidate);
68	}
69};
70
71
72//	#pragma mark - FilePermissionsView
73
74
75FilePermissionsView::FilePermissionsView(BRect rect, Model* model)
76	:
77	BView(rect, "FilePermissionsView", B_FOLLOW_LEFT_RIGHT, B_WILL_DRAW),
78	fModel(model)
79{
80	SetViewUIColor(B_PANEL_BACKGROUND_COLOR);
81
82	// Constants for the column labels: "User", "Group" and "Other".
83	const float kColumnLabelMiddle = 77, kColumnLabelTop = 0,
84		kColumnLabelSpacing = 37, kColumnLabelBottom = 39,
85		kColumnLabelWidth = 80, kAttribFontHeight = 10;
86
87	BStringView* strView;
88
89	strView = new RotatedStringView(
90		BRect(kColumnLabelMiddle - kColumnLabelWidth / 2,
91			kColumnLabelTop,
92			kColumnLabelMiddle + kColumnLabelWidth / 2,
93			kColumnLabelBottom),
94		"", B_TRANSLATE("Owner"));
95	AddChild(strView);
96	strView->SetFontSize(kAttribFontHeight);
97
98	strView = new RotatedStringView(
99		BRect(kColumnLabelMiddle - kColumnLabelWidth / 2
100				+ kColumnLabelSpacing,
101			kColumnLabelTop,
102			kColumnLabelMiddle + kColumnLabelWidth / 2 + kColumnLabelSpacing,
103			kColumnLabelBottom),
104		"", B_TRANSLATE("Group"));
105	AddChild(strView);
106	strView->SetFontSize(kAttribFontHeight);
107
108	strView = new RotatedStringView(
109		BRect(kColumnLabelMiddle - kColumnLabelWidth / 2
110				+ 2 * kColumnLabelSpacing,
111			kColumnLabelTop,
112			kColumnLabelMiddle + kColumnLabelWidth / 2
113				+ 2 * kColumnLabelSpacing,
114			kColumnLabelBottom),
115		"", B_TRANSLATE("Other"));
116	AddChild(strView);
117	strView->SetFontSize(kAttribFontHeight);
118
119	// Constants for the row labels: "Read", "Write" and "Execute".
120	const float kRowLabelLeft = 10, kRowLabelTop = kColumnLabelBottom + 5,
121		kRowLabelVerticalSpacing = 18, kRowLabelRight = kColumnLabelMiddle
122		- kColumnLabelSpacing / 2 - 5, kRowLabelHeight = 14;
123
124	strView = new BStringView(BRect(kRowLabelLeft, kRowLabelTop,
125			kRowLabelRight, kRowLabelTop + kRowLabelHeight),
126		"", B_TRANSLATE("Read"));
127	AddChild(strView);
128	strView->SetAlignment(B_ALIGN_RIGHT);
129	strView->SetFontSize(kAttribFontHeight);
130
131	strView = new BStringView(BRect(kRowLabelLeft, kRowLabelTop
132			+ kRowLabelVerticalSpacing, kRowLabelRight, kRowLabelTop
133			+ kRowLabelVerticalSpacing + kRowLabelHeight),
134		"", B_TRANSLATE("Write"));
135	AddChild(strView);
136	strView->SetAlignment(B_ALIGN_RIGHT);
137	strView->SetFontSize(kAttribFontHeight);
138
139	strView = new BStringView(BRect(kRowLabelLeft, kRowLabelTop
140			+ 2 * kRowLabelVerticalSpacing, kRowLabelRight, kRowLabelTop
141			+ 2 * kRowLabelVerticalSpacing + kRowLabelHeight),
142		"", B_TRANSLATE("Execute"));
143	AddChild(strView);
144	strView->SetAlignment(B_ALIGN_RIGHT);
145	strView->SetFontSize(kAttribFontHeight);
146
147	// Constants for the 3x3 check box array.
148	const float kLeftMargin = kRowLabelRight + 5,
149		kTopMargin = kRowLabelTop - 2,
150		kHorizontalSpacing = kColumnLabelSpacing,
151		kVerticalSpacing = kRowLabelVerticalSpacing,
152		kCheckBoxWidth = 18, kCheckBoxHeight = 18;
153
154	BCheckBox** checkBoxArray[3][3] = {
155		{
156			&fReadUserCheckBox,
157			&fReadGroupCheckBox,
158			&fReadOtherCheckBox
159		},
160		{
161			&fWriteUserCheckBox,
162			&fWriteGroupCheckBox,
163			&fWriteOtherCheckBox
164		},
165		{
166			&fExecuteUserCheckBox,
167			&fExecuteGroupCheckBox,
168			&fExecuteOtherCheckBox
169		}
170	};
171
172	for (int32 x = 0; x < 3; x++) {
173		for (int32 y = 0; y < 3; y++) {
174			*checkBoxArray[y][x] =
175				new BCheckBox(BRect(kLeftMargin + kHorizontalSpacing * x,
176						kTopMargin + kVerticalSpacing * y,
177						kLeftMargin + kHorizontalSpacing * x + kCheckBoxWidth,
178						kTopMargin + kVerticalSpacing * y + kCheckBoxHeight),
179					"", "", new BMessage(kPermissionsChanged));
180			AddChild(*checkBoxArray[y][x]);
181		}
182	}
183
184	const float kTextControlLeft = 170, kTextControlRight = 270,
185		kTextControlTop = kRowLabelTop - 29,
186		kTextControlHeight = 14, kTextControlSpacing = 16;
187
188	strView = new BStringView(BRect(kTextControlLeft, kTextControlTop,
189		kTextControlRight, kTextControlTop + kTextControlHeight), "",
190		B_TRANSLATE("Owner"));
191	strView->SetAlignment(B_ALIGN_CENTER);
192	strView->SetFontSize(kAttribFontHeight);
193	AddChild(strView);
194
195	fOwnerTextControl = new BTextControl(
196		BRect(kTextControlLeft,
197			kTextControlTop - 2 + kTextControlSpacing,
198			kTextControlRight,
199			kTextControlTop + kTextControlHeight - 2 + kTextControlSpacing),
200		"", "", "", new BMessage(kNewOwnerEntered));
201	fOwnerTextControl->SetDivider(0);
202	AddChild(fOwnerTextControl);
203
204	strView = new BStringView(BRect(kTextControlLeft,
205			kTextControlTop + 11 + 2 * kTextControlSpacing,
206			kTextControlRight,
207			kTextControlTop + 11 + 2 * kTextControlSpacing
208				+ kTextControlHeight),
209		"", B_TRANSLATE("Group"));
210	strView->SetAlignment(B_ALIGN_CENTER);
211	strView->SetFontSize(kAttribFontHeight);
212	AddChild(strView);
213
214	fGroupTextControl = new BTextControl(BRect(kTextControlLeft,
215			kTextControlTop + 10 + 3 * kTextControlSpacing,
216			kTextControlRight,
217			kTextControlTop + 10 + 3 * kTextControlSpacing + kTextControlHeight),
218		"", "", "", new BMessage(kNewGroupEntered));
219	fGroupTextControl->SetDivider(0);
220	AddChild(fGroupTextControl);
221
222	ModelChanged(model);
223}
224
225
226void
227FilePermissionsView::ModelChanged(Model* model)
228{
229	fModel = model;
230
231	bool hideCheckBoxes = false;
232	uid_t nodeOwner = 0;
233	gid_t nodeGroup = 0;
234	mode_t perms = 0;
235
236	if (fModel != NULL) {
237		BNode node(fModel->EntryRef());
238
239		if (node.InitCheck() == B_OK) {
240			if (fReadUserCheckBox->IsHidden()) {
241				fReadUserCheckBox->Show();
242				fReadGroupCheckBox->Show();
243				fReadOtherCheckBox->Show();
244				fWriteUserCheckBox->Show();
245				fWriteGroupCheckBox->Show();
246				fWriteOtherCheckBox->Show();
247				fExecuteUserCheckBox->Show();
248				fExecuteGroupCheckBox->Show();
249				fExecuteOtherCheckBox->Show();
250			}
251
252			if (node.GetPermissions(&perms) == B_OK) {
253				fReadUserCheckBox->SetValue((int32)(perms & S_IRUSR));
254				fReadGroupCheckBox->SetValue((int32)(perms & S_IRGRP));
255				fReadOtherCheckBox->SetValue((int32)(perms & S_IROTH));
256				fWriteUserCheckBox->SetValue((int32)(perms & S_IWUSR));
257				fWriteGroupCheckBox->SetValue((int32)(perms & S_IWGRP));
258				fWriteOtherCheckBox->SetValue((int32)(perms & S_IWOTH));
259				fExecuteUserCheckBox->SetValue((int32)(perms & S_IXUSR));
260				fExecuteGroupCheckBox->SetValue((int32)(perms & S_IXGRP));
261				fExecuteOtherCheckBox->SetValue((int32)(perms & S_IXOTH));
262			} else
263				hideCheckBoxes = true;
264
265			if (node.GetOwner(&nodeOwner) == B_OK) {
266				BString user;
267				if (nodeOwner == 0)
268					if (getenv("USER") != NULL)
269						user << getenv("USER");
270					else
271						user << "root";
272				else
273					user << nodeOwner;
274				fOwnerTextControl->SetText(user.String());
275			} else
276				fOwnerTextControl->SetText(B_TRANSLATE("Unknown"));
277
278			if (node.GetGroup(&nodeGroup) == B_OK) {
279				BString group;
280				if (nodeGroup == 0)
281					if (getenv("GROUP") != NULL)
282						group << getenv("GROUP");
283					else
284						group << "0";
285				else
286					group << nodeGroup;
287				fGroupTextControl->SetText(group.String());
288			} else
289				fGroupTextControl->SetText(B_TRANSLATE("Unknown"));
290
291			// Unless we're root, only allow the owner to transfer the
292			// ownership, i.e. disable text controls if uid:s doesn't match:
293			thread_id thisThread = find_thread(NULL);
294			thread_info threadInfo;
295			get_thread_info(thisThread, &threadInfo);
296			team_info teamInfo;
297			get_team_info(threadInfo.team, &teamInfo);
298			if (teamInfo.uid != 0 && nodeOwner != teamInfo.uid) {
299				fOwnerTextControl->SetEnabled(false);
300				fGroupTextControl->SetEnabled(false);
301			} else {
302				fOwnerTextControl->SetEnabled(true);
303				fGroupTextControl->SetEnabled(true);
304			}
305		} else
306			hideCheckBoxes = true;
307	} else
308		hideCheckBoxes = true;
309
310	if (hideCheckBoxes) {
311		fReadUserCheckBox->Hide();
312		fReadGroupCheckBox->Hide();
313		fReadOtherCheckBox->Hide();
314		fWriteUserCheckBox->Hide();
315		fWriteGroupCheckBox->Hide();
316		fWriteOtherCheckBox->Hide();
317		fExecuteUserCheckBox->Hide();
318		fExecuteGroupCheckBox->Hide();
319		fExecuteOtherCheckBox->Hide();
320	}
321}
322
323
324void
325FilePermissionsView::MessageReceived(BMessage* message)
326{
327	switch(message->what) {
328		case kPermissionsChanged:
329			if (fModel != NULL) {
330				mode_t newPermissions = 0;
331				newPermissions
332					= (mode_t)((fReadUserCheckBox->Value() ? S_IRUSR : 0)
333					| (fReadGroupCheckBox->Value() ? S_IRGRP : 0)
334					| (fReadOtherCheckBox->Value() ? S_IROTH : 0)
335
336					| (fWriteUserCheckBox->Value() ? S_IWUSR : 0)
337					| (fWriteGroupCheckBox->Value() ? S_IWGRP : 0)
338					| (fWriteOtherCheckBox->Value() ? S_IWOTH : 0)
339
340					| (fExecuteUserCheckBox->Value() ? S_IXUSR : 0)
341					| (fExecuteGroupCheckBox->Value() ? S_IXGRP :0)
342					| (fExecuteOtherCheckBox->Value() ? S_IXOTH : 0));
343
344				BNode node(fModel->EntryRef());
345
346				if (node.InitCheck() == B_OK)
347					node.SetPermissions(newPermissions);
348				else {
349					ModelChanged(fModel);
350					beep();
351				}
352			}
353			break;
354
355		case kNewOwnerEntered:
356			if (fModel != NULL) {
357				uid_t owner;
358				if (sscanf(fOwnerTextControl->Text(), "%d", &owner) == 1) {
359					BNode node(fModel->EntryRef());
360					if (node.InitCheck() == B_OK)
361						node.SetOwner(owner);
362					else {
363						ModelChanged(fModel);
364						beep();
365					}
366				} else {
367					ModelChanged(fModel);
368					beep();
369				}
370			}
371			break;
372
373		case kNewGroupEntered:
374			if (fModel != NULL) {
375				gid_t group;
376				if (sscanf(fGroupTextControl->Text(), "%d", &group) == 1) {
377					BNode node(fModel->EntryRef());
378					if (node.InitCheck() == B_OK)
379						node.SetGroup(group);
380					else {
381						ModelChanged(fModel);
382						beep();
383					}
384				} else {
385					ModelChanged(fModel);
386					beep();
387				}
388			}
389			break;
390
391		default:
392			_inherited::MessageReceived(message);
393			break;
394	}
395}
396
397
398void
399FilePermissionsView::AttachedToWindow()
400{
401	fReadUserCheckBox->SetTarget(this);
402	fReadGroupCheckBox->SetTarget(this);
403	fReadOtherCheckBox->SetTarget(this);
404	fWriteUserCheckBox->SetTarget(this);
405	fWriteGroupCheckBox->SetTarget(this);
406	fWriteOtherCheckBox->SetTarget(this);
407	fExecuteUserCheckBox->SetTarget(this);
408	fExecuteGroupCheckBox->SetTarget(this);
409	fExecuteOtherCheckBox->SetTarget(this);
410
411	fOwnerTextControl->SetTarget(this);
412	fGroupTextControl->SetTarget(this);
413}
414