vfs: check userland buffers before reading them.
[haiku.git] / src / apps / mail / QueryList.cpp
blob59d56246165fc19f090e7eddc5819568a3e3fd29
1 /*
2 * Copyright 2015, Axel Dörfler, axeld@pinc-software.de.
3 * Distributed under the terms of the MIT License.
4 */
7 #include "QueryList.h"
9 #include <Autolock.h>
10 #include <Debug.h>
11 #include <NodeMonitor.h>
12 #include <VolumeRoster.h>
15 static BLooper* sQueryLooper = NULL;
16 static pthread_once_t sInitOnce = PTHREAD_ONCE_INIT;
19 static void
20 initQueryLooper()
22 sQueryLooper = new BLooper("query looper");
23 sQueryLooper->Run();
27 // #pragma mark - QueryListener
30 QueryListener::~QueryListener()
35 // #pragma mark - QueryList
38 QueryList::QueryList()
40 fQuit(false),
41 fListeners(5, true)
46 QueryList::~QueryList()
48 fQuit = true;
50 ThreadVector::const_iterator threadIterator = fFetchThreads.begin();
51 for (; threadIterator != fFetchThreads.end(); threadIterator++) {
52 wait_for_thread(*threadIterator, NULL);
55 QueryVector::iterator queryIterator = fQueries.begin();
56 for (; queryIterator != fQueries.end(); queryIterator++) {
57 delete *queryIterator;
62 status_t
63 QueryList::Init(const char* predicate, BVolume* specificVolume)
65 if (sQueryLooper == NULL)
66 pthread_once(&sInitOnce, &initQueryLooper);
68 if (Looper() != NULL)
69 debugger("Init() called twice!");
71 sQueryLooper->Lock();
72 sQueryLooper->AddHandler(this);
73 sQueryLooper->Unlock();
75 if (specificVolume == NULL) {
76 BVolumeRoster roster;
77 BVolume volume;
79 while (roster.GetNextVolume(&volume) == B_OK) {
80 if (volume.KnowsQuery() && volume.KnowsAttr() && volume.KnowsMime())
81 _AddVolume(volume, predicate);
83 } else
84 _AddVolume(*specificVolume, predicate);
86 return B_OK;
90 void
91 QueryList::AddListener(QueryListener* listener)
93 BAutolock locker(this);
95 // Add all entries that were already retrieved
96 RefMap::const_iterator iterator = fRefs.begin();
97 for (; iterator != fRefs.end(); iterator++) {
98 listener->EntryCreated(*this, iterator->second, iterator->first.node);
101 fListeners.AddItem(listener);
105 void
106 QueryList::RemoveListener(QueryListener* listener)
108 BAutolock locker(this);
109 fListeners.RemoveItem(listener, false);
113 void
114 QueryList::MessageReceived(BMessage* message)
116 switch (message->what) {
117 case B_QUERY_UPDATE:
119 int32 opcode = message->GetInt32("opcode", -1);
120 int64 directory = message->GetInt64("directory", -1);
121 int32 device = message->GetInt32("device", -1);
122 int64 node = message->GetInt64("node", -1);
124 if (opcode == B_ENTRY_CREATED) {
125 const char* name = message->GetString("name");
126 if (name != NULL) {
127 entry_ref ref(device, directory, name);
128 _AddEntry(ref, node);
130 } else if (opcode == B_ENTRY_REMOVED) {
131 node_ref nodeRef(device, node);
132 _RemoveEntry(nodeRef);
134 break;
137 default:
138 BHandler::MessageReceived(message);
139 break;
144 void
145 QueryList::_AddEntry(const entry_ref& ref, ino_t node)
147 BAutolock locker(this);
149 // TODO: catch bad_alloc
150 fRefs.insert(std::make_pair(node_ref(ref.device, node), ref));
152 _NotifyEntryCreated(ref, node);
156 void
157 QueryList::_RemoveEntry(const node_ref& nodeRef)
159 BAutolock locker(this);
160 RefMap::iterator found = fRefs.find(nodeRef);
161 if (found != fRefs.end())
162 _NotifyEntryRemoved(nodeRef);
166 void
167 QueryList::_NotifyEntryCreated(const entry_ref& ref, ino_t node)
169 ASSERT(IsLocked());
171 int32 count = fListeners.CountItems();
172 for (int32 index = 0; index < count; index++) {
173 fListeners.ItemAt(index)->EntryCreated(*this, ref, node);
178 void
179 QueryList::_NotifyEntryRemoved(const node_ref& nodeRef)
181 ASSERT(IsLocked());
183 int32 count = fListeners.CountItems();
184 for (int32 index = 0; index < count; index++) {
185 fListeners.ItemAt(index)->EntryRemoved(*this, nodeRef);
190 void
191 QueryList::_AddVolume(BVolume& volume, const char* predicate)
193 BQuery* query = new BQuery();
194 if (query->SetVolume(&volume) != B_OK
195 || query->SetPredicate(predicate) != B_OK
196 || query->SetTarget(this) != B_OK) {
197 delete query;
200 // TODO: catch bad_alloc
201 fQueries.push_back(query);
202 Lock();
203 fQueryQueue.push_back(query);
204 Unlock();
206 thread_id thread = spawn_thread(_FetchQuery, "query fetcher",
207 B_NORMAL_PRIORITY, this);
208 if (thread >= B_OK) {
209 resume_thread(thread);
211 fFetchThreads.push_back(thread);
216 /*static*/ status_t
217 QueryList::_FetchQuery(void* self)
219 return static_cast<QueryList*>(self)->_FetchQuery();
223 status_t
224 QueryList::_FetchQuery()
226 RefMap map;
228 BAutolock locker(this);
229 BQuery* query = fQueryQueue.back();
230 fQueryQueue.pop_back();
231 locker.Unlock();
233 query->Fetch();
235 entry_ref ref;
236 while (!fQuit && query->GetNextRef(&ref) == B_OK) {
237 BEntry entry(&ref);
238 node_ref nodeRef;
239 if (entry.GetNodeRef(&nodeRef) == B_OK)
240 map.insert(std::make_pair(nodeRef, ref));
242 if (fQuit)
243 return B_INTERRUPTED;
245 locker.Lock();
247 RefMap::const_iterator iterator = map.begin();
248 for (; iterator != map.end(); iterator++) {
249 _AddEntry(iterator->second, iterator->first.node);
252 return B_OK;