xref: /haiku/src/kits/tracker/infowindow/FilePermissionsView.cpp (revision 9e54316c528c34ee76f4d0d21150ceadd031c4de)
1 /*
2 Open Tracker License
3 
4 Terms and Conditions
5 
6 Copyright (c) 1991-2000, Be Incorporated. All rights reserved.
7 
8 Permission is hereby granted, free of charge, to any person obtaining a copy of
9 this software and associated documentation files (the "Software"), to deal in
10 the Software without restriction, including without limitation the rights to
11 use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
12 of the Software, and to permit persons to whom the Software is furnished to do
13 so, subject to the following conditions:
14 
15 The above copyright notice and this permission notice applies to all licensees
16 and shall be included in all copies or substantial portions of the Software.
17 
18 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF TITLE, MERCHANTABILITY,
20 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
21 BE INCORPORATED BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
22 AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF, OR IN CONNECTION
23 WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
24 
25 Except as contained in this notice, the name of Be Incorporated shall not be
26 used in advertising or otherwise to promote the sale, use or other dealings in
27 this Software without prior written authorization from Be Incorporated.
28 
29 Tracker(TM), Be(R), BeOS(R), and BeIA(TM) are trademarks or registered trademarks
30 of Be Incorporated in the United States and other countries. Other brand product
31 names are registered trademarks or trademarks of their respective holders.
32 All 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 
50 const uint32 kPermissionsChanged = 'prch';
51 const uint32 kNewOwnerEntered = 'nwow';
52 const uint32 kNewGroupEntered = 'nwgr';
53 
54 
55 class RotatedStringView: public BStringView
56 {
57 public:
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 
75 FilePermissionsView::FilePermissionsView(BRect rect, Model* model)
76 	:
77 	BView(rect, B_TRANSLATE("Permissions"), 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 
226 void
227 FilePermissionsView::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 
324 void
325 FilePermissionsView::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 
398 void
399 FilePermissionsView::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