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 "TrashWatcher.h"
37
38#include <string.h>
39
40#include <Debug.h>
41#include <Directory.h>
42#include <NodeMonitor.h>
43#include <Path.h>
44#include <Volume.h>
45#include <VolumeRoster.h>
46
47#include "Attributes.h"
48#include "Bitmaps.h"
49#include "FSUtils.h"
50#include "Tracker.h"
51
52
53//	 #pragma mark - BTrashWatcher
54
55
56BTrashWatcher::BTrashWatcher()
57	:
58	BLooper("TrashWatcher", B_LOW_PRIORITY),
59	fTrashNodeList(20, true)
60{
61	FSCreateTrashDirs();
62	WatchTrashDirs();
63	fTrashFull = CheckTrashDirs();
64	UpdateTrashIcons();
65
66	// watch volumes
67	TTracker::WatchNode(0, B_WATCH_MOUNT, this);
68}
69
70
71BTrashWatcher::~BTrashWatcher()
72{
73	stop_watching(this);
74}
75
76
77bool
78BTrashWatcher::IsTrashNode(const node_ref* testNode) const
79{
80	int32 count = fTrashNodeList.CountItems();
81	for (int32 index = 0; index < count; index++) {
82		node_ref* nref = fTrashNodeList.ItemAt(index);
83		if (nref->node == testNode->node && nref->device == testNode->device)
84			return true;
85	}
86
87	return false;
88}
89
90
91void
92BTrashWatcher::MessageReceived(BMessage* message)
93{
94	if (message->what != B_NODE_MONITOR) {
95		_inherited::MessageReceived(message);
96		return;
97	}
98
99	switch (message->FindInt32("opcode")) {
100		case B_ENTRY_CREATED:
101			if (!fTrashFull) {
102				fTrashFull = true;
103				UpdateTrashIcons();
104			}
105			break;
106
107		case B_ENTRY_MOVED:
108		{
109			// allow code to fall through if move is from/to trash
110			// but do nothing for moves in the same directory
111			ino_t toDir;
112			ino_t fromDir;
113			message->FindInt64("from directory", &fromDir);
114			message->FindInt64("to directory", &toDir);
115			if (fromDir == toDir)
116				break;
117		}
118		// fall-through
119		case B_DEVICE_UNMOUNTED:
120		case B_ENTRY_REMOVED:
121		{
122			bool full = CheckTrashDirs();
123			if (fTrashFull != full) {
124				fTrashFull = full;
125				UpdateTrashIcons();
126			}
127			break;
128		}
129		// We should handle DEVICE_UNMOUNTED here too to remove trash
130
131		case B_DEVICE_MOUNTED:
132		{
133			dev_t device;
134			BDirectory trashDir;
135			if (message->FindInt32("new device", &device) == B_OK
136				&& FSGetTrashDir(&trashDir, device) == B_OK) {
137				node_ref trashNode;
138				trashDir.GetNodeRef(&trashNode);
139				TTracker::WatchNode(&trashNode, B_WATCH_DIRECTORY, this);
140				fTrashNodeList.AddItem(new node_ref(trashNode));
141
142				// Check if the new volume has anything trashed.
143				if (CheckTrashDirs() && !fTrashFull) {
144					fTrashFull = true;
145					UpdateTrashIcons();
146				}
147			}
148			break;
149		}
150	}
151}
152
153
154void
155BTrashWatcher::UpdateTrashIcons()
156{
157	BVolumeRoster roster;
158	BVolume volume;
159	roster.Rewind();
160
161	BDirectory trashDir;
162	while (roster.GetNextVolume(&volume) == B_OK) {
163		if (FSGetTrashDir(&trashDir, volume.Device()) == B_OK) {
164			// pull out the icons for the current trash state from resources
165			// and apply them onto the trash directory node
166			size_t vectorSize = 0;
167			const void* vectorData = GetTrackerResources()->LoadResource(
168				B_VECTOR_ICON_TYPE,
169				fTrashFull ? R_TrashFullIcon : R_TrashIcon, &vectorSize);
170
171			if (vectorData) {
172				trashDir.WriteAttr(kAttrIcon, B_VECTOR_ICON_TYPE, 0,
173					vectorData, vectorSize);
174			} else
175				TRESPASS();
176		}
177	}
178}
179
180
181void
182BTrashWatcher::WatchTrashDirs()
183{
184	BVolumeRoster volRoster;
185	volRoster.Rewind();
186	BVolume	volume;
187	while (volRoster.GetNextVolume(&volume) == B_OK) {
188		if (volume.IsReadOnly() || !volume.IsPersistent())
189			continue;
190
191		BDirectory trashDir;
192		if (FSGetTrashDir(&trashDir, volume.Device()) == B_OK) {
193			node_ref trash_node;
194			trashDir.GetNodeRef(&trash_node);
195			watch_node(&trash_node, B_WATCH_DIRECTORY, this);
196			fTrashNodeList.AddItem(new node_ref(trash_node));
197		}
198	}
199}
200
201
202bool
203BTrashWatcher::CheckTrashDirs()
204{
205	BVolumeRoster volRoster;
206	volRoster.Rewind();
207	BVolume	volume;
208	while (volRoster.GetNextVolume(&volume) == B_OK) {
209		if (volume.IsReadOnly() || !volume.IsPersistent())
210			continue;
211
212		BDirectory trashDir;
213		FSGetTrashDir(&trashDir, volume.Device());
214		trashDir.Rewind();
215		BEntry entry;
216		if (trashDir.GetNextEntry(&entry) == B_OK)
217			return true;
218	}
219
220	return false;
221}
222