vfs: check userland buffers before reading them.
[haiku.git] / src / apps / people / PeopleApp.cpp
blobc1e14424b6ed42c42b1e438acace13b40e401f66
1 /*
2 * Copyright 2005-2010, Haiku, Inc. All rights reserved.
3 * Distributed under the terms of the MIT license.
5 * Authors:
6 * Robert Polic
7 * Axel Dörfler, axeld@pinc-software.de
8 * Stephan Aßmus <superstippi@gmx.de>
10 * Copyright 1999, Be Incorporated. All Rights Reserved.
11 * This file may be used under the terms of the Be Sample Code License.
15 #include "PeopleApp.h"
17 #include <Alert.h>
18 #include <AutoDeleter.h>
19 #include <Bitmap.h>
20 #include <Catalog.h>
21 #include <Directory.h>
22 #include <FindDirectory.h>
23 #include <fs_index.h>
24 #include <Locale.h>
25 #include <Path.h>
26 #include <Roster.h>
27 #include <Screen.h>
28 #include <Volume.h>
29 #include <VolumeRoster.h>
31 #include "PersonWindow.h"
32 #include "PersonIcons.h"
34 #include <string.h>
37 #undef B_TRANSLATION_CONTEXT
38 #define B_TRANSLATION_CONTEXT "People"
41 struct DefaultAttribute {
42 const char* attribute;
43 int32 width;
44 const char* name;
47 // TODO: Add flags in attribute info message to find these.
48 static const char* kNameAttribute = "META:name";
49 static const char* kCategoryAttribute = "META:group";
51 struct DefaultAttribute sDefaultAttributes[] = {
52 { kNameAttribute, 120, B_TRANSLATE("Contact name") },
53 { "META:nickname", 120, B_TRANSLATE("Nickname") },
54 { "META:company", 120, B_TRANSLATE("Company") },
55 { "META:address", 120, B_TRANSLATE("Address") },
56 { "META:city", 90, B_TRANSLATE("City") },
57 { "META:state", 50, B_TRANSLATE("State") },
58 { "META:zip", 50, B_TRANSLATE("Zip") },
59 { "META:country", 120, B_TRANSLATE("Country") },
60 { "META:hphone", 90, B_TRANSLATE("Home phone") },
61 { "META:wphone", 90, B_TRANSLATE("Work phone") },
62 { "META:fax", 90, B_TRANSLATE("Fax") },
63 { "META:email", 120, B_TRANSLATE("E-mail") },
64 { "META:url", 120, B_TRANSLATE("URL") },
65 { kCategoryAttribute, 120, B_TRANSLATE("Group") },
66 { NULL, 0, NULL }
70 TPeopleApp::TPeopleApp()
72 BApplication(APP_SIG),
73 fWindowCount(0),
74 fAttributes(20, true)
76 B_TRANSLATE_MARK_SYSTEM_NAME_VOID("People");
78 fPosition.Set(6, TITLE_BAR_HEIGHT, 6 + WIND_WIDTH,
79 TITLE_BAR_HEIGHT + WIND_HEIGHT);
80 BPoint pos = fPosition.LeftTop();
82 BPath path;
83 find_directory(B_USER_SETTINGS_DIRECTORY, &path, true);
85 BDirectory dir(path.Path());
86 BEntry entry;
87 if (dir.FindEntry("People_data", &entry) == B_OK) {
88 fPrefs = new BFile(&entry, B_READ_WRITE);
89 if (fPrefs->InitCheck() == B_NO_ERROR) {
90 fPrefs->Read(&pos, sizeof(BPoint));
91 if (BScreen(B_MAIN_SCREEN_ID).Frame().Contains(pos))
92 fPosition.OffsetTo(pos);
94 } else {
95 fPrefs = new BFile();
96 if (dir.CreateFile("People_data", fPrefs) != B_OK) {
97 delete fPrefs;
98 fPrefs = NULL;
102 // Read attributes from person mime type. If it does not exist,
103 // or if it contains no attribute definitions, install a "clean"
104 // person mime type from the hard-coded default attributes.
106 bool valid = false;
107 BMimeType mime(B_PERSON_MIMETYPE);
108 if (mime.IsInstalled()) {
109 BMessage info;
110 if (mime.GetAttrInfo(&info) == B_NO_ERROR) {
111 int32 index = 0;
112 while (true) {
113 int32 type;
114 if (info.FindInt32("attr:type", index, &type) != B_OK)
115 break;
116 bool editable;
117 if (info.FindBool("attr:editable", index, &editable) != B_OK)
118 break;
120 // TODO: Support other types besides string attributes.
121 if (type != B_STRING_TYPE || !editable)
122 break;
124 Attribute* attribute = new Attribute();
125 ObjectDeleter<Attribute> deleter(attribute);
126 if (info.FindString("attr:public_name", index,
127 &attribute->name) != B_OK) {
128 break;
130 if (info.FindString("attr:name", index,
131 &attribute->attribute) != B_OK) {
132 break;
135 if (!fAttributes.AddItem(attribute))
136 break;
138 deleter.Detach();
139 index++;
142 if (fAttributes.CountItems() == 0) {
143 valid = false;
144 mime.Delete();
145 } else
146 valid = true;
148 if (!valid) {
149 mime.Install();
150 mime.SetShortDescription(B_TRANSLATE_CONTEXT("Person",
151 "Short mimetype description"));
152 mime.SetLongDescription(B_TRANSLATE_CONTEXT(
153 "Contact information for a person.",
154 "Long mimetype description"));
155 mime.SetIcon(kPersonIcon, sizeof(kPersonIcon));
156 mime.SetPreferredApp(APP_SIG);
158 // add default person fields to meta-mime type
159 BMessage fields;
160 for (int32 i = 0; sDefaultAttributes[i].attribute; i++) {
161 fields.AddString("attr:public_name", sDefaultAttributes[i].name);
162 fields.AddString("attr:name", sDefaultAttributes[i].attribute);
163 fields.AddInt32("attr:type", B_STRING_TYPE);
164 fields.AddBool("attr:viewable", true);
165 fields.AddBool("attr:editable", true);
166 fields.AddInt32("attr:width", sDefaultAttributes[i].width);
167 fields.AddInt32("attr:alignment", B_ALIGN_LEFT);
168 fields.AddBool("attr:extra", false);
170 // Add the default attribute to the attribute list, too.
171 Attribute* attribute = new Attribute();
172 attribute->name = sDefaultAttributes[i].name;
173 attribute->attribute = sDefaultAttributes[i].attribute;
174 if (!fAttributes.AddItem(attribute))
175 delete attribute;
178 mime.SetAttrInfo(&fields);
181 // create indices on all volumes for the found attributes.
183 int32 count = fAttributes.CountItems();
184 BVolumeRoster volumeRoster;
185 BVolume volume;
186 while (volumeRoster.GetNextVolume(&volume) == B_OK) {
187 for (int32 i = 0; i < count; i++) {
188 Attribute* attribute = fAttributes.ItemAt(i);
189 fs_create_index(volume.Device(), attribute->attribute,
190 B_STRING_TYPE, 0);
197 TPeopleApp::~TPeopleApp()
199 delete fPrefs;
203 void
204 TPeopleApp::ArgvReceived(int32 argc, char** argv)
206 BMessage message(B_REFS_RECEIVED);
208 for (int32 i = 1; i < argc; i++) {
209 BEntry entry(argv[i]);
210 entry_ref ref;
211 if (entry.Exists() && entry.GetRef(&ref) == B_OK)
212 message.AddRef("refs", &ref);
215 RefsReceived(&message);
219 void
220 TPeopleApp::MessageReceived(BMessage* message)
222 switch (message->what) {
223 case M_NEW:
224 case B_SILENT_RELAUNCH:
225 _NewWindow();
226 break;
228 case M_WINDOW_QUITS:
229 _SavePreferences(message);
230 fWindowCount--;
231 if (fWindowCount < 1)
232 PostMessage(B_QUIT_REQUESTED);
233 break;
235 case M_CONFIGURE_ATTRIBUTES:
237 const char* arguments[] = { "-type", B_PERSON_MIMETYPE, 0 };
238 status_t ret = be_roster->Launch(
239 "application/x-vnd.Haiku-FileTypes",
240 sizeof(arguments) / sizeof(const char*) - 1,
241 const_cast<char**>(arguments));
242 if (ret != B_OK && ret != B_ALREADY_RUNNING) {
243 BString errorMsg(B_TRANSLATE("Launching the FileTypes "
244 "preflet to configure Person attributes has failed."
245 "\n\nError: "));
246 errorMsg << strerror(ret);
247 BAlert* alert = new BAlert(B_TRANSLATE("Error"),
248 errorMsg.String(), B_TRANSLATE("OK"), NULL, NULL,
249 B_WIDTH_AS_USUAL, B_STOP_ALERT);
250 alert->SetFlags(alert->Flags() | B_CLOSE_ON_ESCAPE);
251 alert->Go(NULL);
253 break;
256 default:
257 BApplication::MessageReceived(message);
262 void
263 TPeopleApp::RefsReceived(BMessage* message)
265 int32 index = 0;
266 while (message->HasRef("refs", index)) {
267 entry_ref ref;
268 message->FindRef("refs", index++, &ref);
270 PersonWindow* window = _FindWindow(ref);
271 if (window != NULL)
272 window->Activate(true);
273 else {
274 BFile file(&ref, B_READ_ONLY);
275 if (file.InitCheck() == B_OK)
276 _NewWindow(&ref);
282 void
283 TPeopleApp::ReadyToRun()
285 if (fWindowCount < 1)
286 _NewWindow();
290 // #pragma mark -
293 PersonWindow*
294 TPeopleApp::_NewWindow(entry_ref* ref)
296 PersonWindow* window = new PersonWindow(fPosition,
297 B_TRANSLATE("New person"), kNameAttribute,
298 kCategoryAttribute, ref);
300 _AddAttributes(window);
302 window->Show();
304 fWindowCount++;
306 // Offset the position for the next window which will be opened and
307 // reset it if it would open outside the screen bounds.
308 fPosition.OffsetBy(20, 20);
309 BScreen screen(window);
310 if (fPosition.bottom > screen.Frame().bottom)
311 fPosition.OffsetTo(fPosition.left, TITLE_BAR_HEIGHT);
312 if (fPosition.right > screen.Frame().right)
313 fPosition.OffsetTo(6, fPosition.top);
315 return window;
319 void
320 TPeopleApp::_AddAttributes(PersonWindow* window) const
322 int32 count = fAttributes.CountItems();
323 for (int32 i = 0; i < count; i++) {
324 Attribute* attribute = fAttributes.ItemAt(i);
325 const char* label = attribute->name;
326 if (attribute->attribute == kNameAttribute)
327 label = B_TRANSLATE("Name");
329 window->AddAttribute(label, attribute->attribute);
334 PersonWindow*
335 TPeopleApp::_FindWindow(const entry_ref& ref) const
337 for (int32 i = 0; BWindow* window = WindowAt(i); i++) {
338 PersonWindow* personWindow = dynamic_cast<PersonWindow*>(window);
339 if (personWindow == NULL)
340 continue;
341 if (personWindow->RefersPersonFile(ref))
342 return personWindow;
344 return NULL;
348 void
349 TPeopleApp::_SavePreferences(BMessage* message) const
351 BRect frame;
352 if (message->FindRect("frame", &frame) != B_OK)
353 return;
355 BPoint leftTop = frame.LeftTop();
357 if (fPrefs != NULL) {
358 fPrefs->Seek(0, 0);
359 fPrefs->Write(&leftTop, sizeof(BPoint));