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 <algorithm>
39#include <stdio.h>
40#include <stdlib.h>
41
42#include <Beep.h>
43#include <Catalog.h>
44#include <LayoutBuilder.h>
45#include <Locale.h>
46
47
48#undef B_TRANSLATION_CONTEXT
49#define B_TRANSLATION_CONTEXT "FilePermissionsView"
50
51
52const uint32 kPermissionsChanged = 'prch';
53const uint32 kNewOwnerEntered = 'nwow';
54const uint32 kNewGroupEntered = 'nwgr';
55
56
57class RotatedStringView: public BStringView
58{
59public:
60	RotatedStringView(const char* name, const char* label)
61		: BStringView(name, label)
62	{
63		BFont currentFont;
64		GetFont(&currentFont);
65
66		currentFont.SetRotation(57);
67		SetFont(&currentFont);
68
69		// Get the dimension of the bounding box of the string, taking care
70		// of the orientation
71		const char* stringArray[1];
72		stringArray[0] = label;
73		BRect rectArray[1];
74		escapement_delta delta = { 0.0, 0.0 };
75		currentFont.GetBoundingBoxesForStrings(stringArray, 1, B_SCREEN_METRIC,
76			&delta, rectArray);
77
78		// Adjust the size to avoid partial drawing of first and last chars
79		// due to the orientation
80		fExplicitSize = BSize(rectArray[0].Width(), rectArray[0].Height()
81			+ currentFont.Size() / 2);
82
83		SetExplicitSize(fExplicitSize);
84	}
85
86	void Draw(BRect invalidate)
87	{
88		BFont currentFont;
89		GetFont(&currentFont);
90
91		// Small adjustment to draw in the calculated area
92		TranslateBy(currentFont.Size() / 1.9 + 1, 0);
93
94		BStringView::Draw(invalidate);
95	}
96
97	BSize ExplicitSize()
98	{
99		return fExplicitSize;
100	}
101
102private:
103	BSize fExplicitSize;
104};
105
106
107//	#pragma mark - FilePermissionsView
108
109
110FilePermissionsView::FilePermissionsView(BRect rect, Model* model)
111	:
112	BView(rect, B_TRANSLATE("Permissions"), B_FOLLOW_LEFT_RIGHT, B_WILL_DRAW),
113	fModel(model)
114{
115	SetViewUIColor(B_PANEL_BACKGROUND_COLOR);
116
117	RotatedStringView* ownerRightLabel = new RotatedStringView("",
118		B_TRANSLATE("Owner"));
119	RotatedStringView* groupRightLabel = new RotatedStringView("",
120		B_TRANSLATE("Group"));
121	RotatedStringView* otherRightLabel = new RotatedStringView("",
122		B_TRANSLATE("Other"));
123
124	// Get the largest inclined area of the three
125	BSize ownerRightLabelSize, groupRightLabelSize, maxSize;
126
127	ownerRightLabelSize = ownerRightLabel->ExplicitSize();
128	groupRightLabelSize = groupRightLabel->ExplicitSize();
129
130	maxSize.width = std::max(ownerRightLabelSize.width,
131		groupRightLabelSize.width);
132	maxSize.width = std::max(maxSize.width,
133		otherRightLabel->ExplicitSize().width);
134
135	maxSize.height = std::max(ownerRightLabel->ExplicitSize().height,
136		groupRightLabel->ExplicitSize().height);
137	maxSize.height = std::max(maxSize.height,
138		otherRightLabel->ExplicitSize().height);
139
140
141	// Set all the component with this size
142	ownerRightLabel->SetExplicitSize(maxSize);
143	groupRightLabel->SetExplicitSize(maxSize);
144	otherRightLabel->SetExplicitSize(maxSize);
145
146	BStringView* readLabel = new BStringView("", B_TRANSLATE("Read"));
147	readLabel->SetAlignment(B_ALIGN_RIGHT);
148
149	BStringView* writeLabel = new BStringView("", B_TRANSLATE("Write"));
150	writeLabel->SetAlignment(B_ALIGN_RIGHT);
151
152	BStringView* executeLabel = new BStringView("", B_TRANSLATE("Execute"));
153	executeLabel->SetAlignment(B_ALIGN_RIGHT);
154
155	// Creating checkbox
156	fReadUserCheckBox = new BCheckBox("", "",
157		new BMessage(kPermissionsChanged));
158	fReadGroupCheckBox = new BCheckBox("", "",
159		new BMessage(kPermissionsChanged));
160	fReadOtherCheckBox = new BCheckBox("", "",
161		new BMessage(kPermissionsChanged));
162
163	fWriteUserCheckBox = new BCheckBox("", "",
164		new BMessage(kPermissionsChanged));
165	fWriteGroupCheckBox = new BCheckBox("", "",
166		new BMessage(kPermissionsChanged));
167	fWriteOtherCheckBox = new BCheckBox("", "",
168		new BMessage(kPermissionsChanged));
169
170	fExecuteUserCheckBox = new BCheckBox("", "",
171		new BMessage(kPermissionsChanged));
172	fExecuteGroupCheckBox = new BCheckBox("", "",
173		new BMessage(kPermissionsChanged));
174	fExecuteOtherCheckBox = new BCheckBox("", "",
175		new BMessage(kPermissionsChanged));
176
177	fOwnerTextControl = new BTextControl("", B_TRANSLATE("Owner"), "",
178		new BMessage(kNewOwnerEntered));
179	fGroupTextControl = new BTextControl("", B_TRANSLATE("Group"), "",
180		new BMessage(kNewGroupEntered));
181
182	BGroupLayout* groupLayout = new BGroupLayout(B_VERTICAL);
183
184	SetLayout(groupLayout);
185
186	BLayoutBuilder::Group<>(groupLayout)
187		.AddGroup(B_HORIZONTAL, B_USE_DEFAULT_SPACING, 0.0f)
188			.SetInsets(B_USE_DEFAULT_SPACING)
189			.AddGrid(B_USE_SMALL_SPACING, B_USE_SMALL_SPACING)
190				.Add(ownerRightLabel, 1, 0)
191				.Add(groupRightLabel, 2, 0)
192				.Add(otherRightLabel, 3, 0)
193				.Add(readLabel, 0, 1)
194				.Add(writeLabel, 0, 2)
195				.Add(executeLabel, 0, 3)
196				.Add(fReadUserCheckBox, 1, 1)
197				.Add(fReadGroupCheckBox, 2, 1)
198				.Add(fReadOtherCheckBox, 3, 1)
199				.Add(fWriteUserCheckBox, 1, 2)
200				.Add(fWriteGroupCheckBox, 2, 2)
201				.Add(fWriteOtherCheckBox, 3, 2)
202				.Add(fExecuteUserCheckBox, 1, 3)
203				.Add(fExecuteGroupCheckBox, 2, 3)
204				.Add(fExecuteOtherCheckBox, 3, 3)
205				.AddGlue(0, 4)
206			.End()
207			.AddGrid(B_USE_SMALL_SPACING, B_USE_SMALL_SPACING)
208				.AddGlue(0, 0)
209				.AddTextControl(fOwnerTextControl, 0, 1)
210				.AddTextControl(fGroupTextControl, 0, 2)
211			.End()
212			.AddGlue()
213		.End()
214		.AddGlue();
215
216	ModelChanged(model);
217}
218
219
220void
221FilePermissionsView::ModelChanged(Model* model)
222{
223	fModel = model;
224
225	bool hideCheckBoxes = false;
226	uid_t nodeOwner = 0;
227	gid_t nodeGroup = 0;
228	mode_t perms = 0;
229
230	if (fModel != NULL) {
231		BNode node(fModel->EntryRef());
232
233		if (node.InitCheck() == B_OK) {
234			if (fReadUserCheckBox->IsHidden()) {
235				fReadUserCheckBox->Show();
236				fReadGroupCheckBox->Show();
237				fReadOtherCheckBox->Show();
238				fWriteUserCheckBox->Show();
239				fWriteGroupCheckBox->Show();
240				fWriteOtherCheckBox->Show();
241				fExecuteUserCheckBox->Show();
242				fExecuteGroupCheckBox->Show();
243				fExecuteOtherCheckBox->Show();
244			}
245
246			if (node.GetPermissions(&perms) == B_OK) {
247				fReadUserCheckBox->SetValue((int32)(perms & S_IRUSR));
248				fReadGroupCheckBox->SetValue((int32)(perms & S_IRGRP));
249				fReadOtherCheckBox->SetValue((int32)(perms & S_IROTH));
250				fWriteUserCheckBox->SetValue((int32)(perms & S_IWUSR));
251				fWriteGroupCheckBox->SetValue((int32)(perms & S_IWGRP));
252				fWriteOtherCheckBox->SetValue((int32)(perms & S_IWOTH));
253				fExecuteUserCheckBox->SetValue((int32)(perms & S_IXUSR));
254				fExecuteGroupCheckBox->SetValue((int32)(perms & S_IXGRP));
255				fExecuteOtherCheckBox->SetValue((int32)(perms & S_IXOTH));
256			} else
257				hideCheckBoxes = true;
258
259			if (node.GetOwner(&nodeOwner) == B_OK) {
260				BString user;
261				if (nodeOwner == 0)
262					if (getenv("USER") != NULL)
263						user << getenv("USER");
264					else
265						user << "root";
266				else
267					user << nodeOwner;
268				fOwnerTextControl->SetText(user.String());
269			} else
270				fOwnerTextControl->SetText(B_TRANSLATE("Unknown"));
271
272			if (node.GetGroup(&nodeGroup) == B_OK) {
273				BString group;
274				if (nodeGroup == 0)
275					if (getenv("GROUP") != NULL)
276						group << getenv("GROUP");
277					else
278						group << "0";
279				else
280					group << nodeGroup;
281				fGroupTextControl->SetText(group.String());
282			} else
283				fGroupTextControl->SetText(B_TRANSLATE("Unknown"));
284
285			// Unless we're root, only allow the owner to transfer the
286			// ownership, i.e. disable text controls if uid:s doesn't match:
287			thread_id thisThread = find_thread(NULL);
288			thread_info threadInfo;
289			get_thread_info(thisThread, &threadInfo);
290			team_info teamInfo;
291			get_team_info(threadInfo.team, &teamInfo);
292			if (teamInfo.uid != 0 && nodeOwner != teamInfo.uid) {
293				fOwnerTextControl->SetEnabled(false);
294				fGroupTextControl->SetEnabled(false);
295			} else {
296				fOwnerTextControl->SetEnabled(true);
297				fGroupTextControl->SetEnabled(true);
298			}
299		} else
300			hideCheckBoxes = true;
301	} else
302		hideCheckBoxes = true;
303
304	if (hideCheckBoxes) {
305		fReadUserCheckBox->Hide();
306		fReadGroupCheckBox->Hide();
307		fReadOtherCheckBox->Hide();
308		fWriteUserCheckBox->Hide();
309		fWriteGroupCheckBox->Hide();
310		fWriteOtherCheckBox->Hide();
311		fExecuteUserCheckBox->Hide();
312		fExecuteGroupCheckBox->Hide();
313		fExecuteOtherCheckBox->Hide();
314	}
315}
316
317
318void
319FilePermissionsView::MessageReceived(BMessage* message)
320{
321	switch(message->what) {
322		case kPermissionsChanged:
323			if (fModel != NULL) {
324				mode_t newPermissions = 0;
325				newPermissions
326					= (mode_t)((fReadUserCheckBox->Value() ? S_IRUSR : 0)
327					| (fReadGroupCheckBox->Value() ? S_IRGRP : 0)
328					| (fReadOtherCheckBox->Value() ? S_IROTH : 0)
329
330					| (fWriteUserCheckBox->Value() ? S_IWUSR : 0)
331					| (fWriteGroupCheckBox->Value() ? S_IWGRP : 0)
332					| (fWriteOtherCheckBox->Value() ? S_IWOTH : 0)
333
334					| (fExecuteUserCheckBox->Value() ? S_IXUSR : 0)
335					| (fExecuteGroupCheckBox->Value() ? S_IXGRP :0)
336					| (fExecuteOtherCheckBox->Value() ? S_IXOTH : 0));
337
338				BNode node(fModel->EntryRef());
339
340				if (node.InitCheck() == B_OK)
341					node.SetPermissions(newPermissions);
342				else {
343					ModelChanged(fModel);
344					beep();
345				}
346			}
347			break;
348
349		case kNewOwnerEntered:
350			if (fModel != NULL) {
351				uid_t owner;
352				if (sscanf(fOwnerTextControl->Text(), "%d", &owner) == 1) {
353					BNode node(fModel->EntryRef());
354					if (node.InitCheck() == B_OK)
355						node.SetOwner(owner);
356					else {
357						ModelChanged(fModel);
358						beep();
359					}
360				} else {
361					ModelChanged(fModel);
362					beep();
363				}
364			}
365			break;
366
367		case kNewGroupEntered:
368			if (fModel != NULL) {
369				gid_t group;
370				if (sscanf(fGroupTextControl->Text(), "%d", &group) == 1) {
371					BNode node(fModel->EntryRef());
372					if (node.InitCheck() == B_OK)
373						node.SetGroup(group);
374					else {
375						ModelChanged(fModel);
376						beep();
377					}
378				} else {
379					ModelChanged(fModel);
380					beep();
381				}
382			}
383			break;
384
385		default:
386			_inherited::MessageReceived(message);
387			break;
388	}
389}
390
391
392void
393FilePermissionsView::AttachedToWindow()
394{
395	fReadUserCheckBox->SetTarget(this);
396	fReadGroupCheckBox->SetTarget(this);
397	fReadOtherCheckBox->SetTarget(this);
398	fWriteUserCheckBox->SetTarget(this);
399	fWriteGroupCheckBox->SetTarget(this);
400	fWriteOtherCheckBox->SetTarget(this);
401	fExecuteUserCheckBox->SetTarget(this);
402	fExecuteGroupCheckBox->SetTarget(this);
403	fExecuteOtherCheckBox->SetTarget(this);
404
405	fOwnerTextControl->SetTarget(this);
406	fGroupTextControl->SetTarget(this);
407}
408