1/*
2 * Copyright 2002-2014, Haiku, Inc. All Rights Reserved.
3 * Distributed under the terms of the MIT License.
4 *
5 * Authors:
6 *		Tyler Dauwalder
7 *		Rene Gollent, rene@gollent.com.
8 *		Michael Lotz, mmlr@mlotz.ch
9 *		Jonas Sundstr��m, jonas@kirilla.com
10 *		Ingo Weinhold, ingo_weinhold@gmx.de
11 */
12
13
14#include <mime/MimeInfoUpdater.h>
15
16#include <stdlib.h>
17
18#include <AppFileInfo.h>
19#include <Bitmap.h>
20#include <File.h>
21#include <fs_attr.h>
22#include <MimeType.h>
23#include <String.h>
24
25#include <AutoLocker.h>
26#include <mime/Database.h>
27#include <mime/database_support.h>
28
29
30static const char *kAppFlagsAttribute = "BEOS:APP_FLAGS";
31
32
33static status_t
34update_icon(BAppFileInfo &appFileInfoRead, BAppFileInfo &appFileInfoWrite,
35	const char *type, BBitmap &icon, icon_size iconSize)
36{
37	status_t err = appFileInfoRead.GetIconForType(type, &icon, iconSize);
38	if (err == B_OK)
39		err = appFileInfoWrite.SetIconForType(type, &icon, iconSize, false);
40	else if (err == B_ENTRY_NOT_FOUND)
41		err = appFileInfoWrite.SetIconForType(type, NULL, iconSize, false);
42	return err;
43}
44
45
46static status_t
47update_icon(BAppFileInfo &appFileInfoRead, BAppFileInfo &appFileInfoWrite,
48	const char *type)
49{
50	uint8* data = NULL;
51	size_t size = 0;
52
53	status_t err = appFileInfoRead.GetIconForType(type, &data, &size);
54	if (err == B_OK)
55		err = appFileInfoWrite.SetIconForType(type, data, size, false);
56	else if (err == B_ENTRY_NOT_FOUND)
57		err = appFileInfoWrite.SetIconForType(type, NULL, size, false);
58
59	free(data);
60
61	return err;
62}
63
64
65static bool
66is_shared_object_mime_type(const BString &type)
67{
68	return type.ICompare(B_APP_MIME_TYPE) == 0;
69}
70
71
72namespace BPrivate {
73namespace Storage {
74namespace Mime {
75
76
77MimeInfoUpdater::MimeInfoUpdater(Database* database,
78	DatabaseLocker* databaseLocker, int32 force)
79	:
80	MimeEntryProcessor(database, databaseLocker, force)
81{
82}
83
84
85MimeInfoUpdater::~MimeInfoUpdater()
86{
87}
88
89
90status_t
91MimeInfoUpdater::Do(const entry_ref& entry, bool* _entryIsDir)
92{
93	bool updateType = false;
94	bool updateAppInfo = false;
95	BNode node;
96
97	status_t err = node.SetTo(&entry);
98	if (!err && _entryIsDir)
99		*_entryIsDir = node.IsDirectory();
100	if (!err) {
101		// If not forced, only update if the entry has no file type attribute
102		attr_info info;
103		if (fForce == B_UPDATE_MIME_INFO_FORCE_UPDATE_ALL
104			|| node.GetAttrInfo(kFileTypeAttr, &info) == B_ENTRY_NOT_FOUND) {
105			updateType = true;
106		}
107		updateAppInfo = (updateType
108			|| fForce == B_UPDATE_MIME_INFO_FORCE_KEEP_TYPE);
109	}
110
111	// guess the MIME type
112	BString type;
113	if (!err && (updateType || updateAppInfo)) {
114		AutoLocker<DatabaseLocker> databaseLocker(fDatabaseLocker);
115		err = fDatabase->GuessMimeType(&entry, &type);
116	}
117
118	// update the MIME type
119	if (!err && updateType) {
120		ssize_t len = type.Length() + 1;
121		ssize_t bytes = node.WriteAttr(kFileTypeAttr, kFileTypeType, 0, type,
122			len);
123		if (bytes < B_OK)
124			err = bytes;
125		else
126			err = (bytes != len ? (status_t)B_FILE_ERROR : (status_t)B_OK);
127	}
128
129	// update the app file info attributes, if this is a shared object
130	BFile file;
131	BAppFileInfo appFileInfoRead;
132	BAppFileInfo appFileInfoWrite;
133	if (!err && updateAppInfo && node.IsFile()
134		&& is_shared_object_mime_type(type)
135		&& (err = file.SetTo(&entry, B_READ_WRITE)) == B_OK
136		&& (err = appFileInfoRead.SetTo(&file)) == B_OK
137		&& (err = appFileInfoWrite.SetTo(&file)) == B_OK) {
138
139		// we read from resources and write to attributes
140		appFileInfoRead.SetInfoLocation(B_USE_RESOURCES);
141		appFileInfoWrite.SetInfoLocation(B_USE_ATTRIBUTES);
142
143		// signature
144		char signature[B_MIME_TYPE_LENGTH];
145		err = appFileInfoRead.GetSignature(signature);
146		if (err == B_OK)
147			err = appFileInfoWrite.SetSignature(signature);
148		else if (err == B_ENTRY_NOT_FOUND)
149			err = appFileInfoWrite.SetSignature(NULL);
150		if (err != B_OK)
151			return err;
152
153		// catalog entry
154		char catalogEntry[B_MIME_TYPE_LENGTH * 3];
155		err = appFileInfoRead.GetCatalogEntry(catalogEntry);
156		if (err == B_OK)
157			err = appFileInfoWrite.SetCatalogEntry(catalogEntry);
158		else if (err == B_ENTRY_NOT_FOUND)
159			err = appFileInfoWrite.SetCatalogEntry(NULL);
160		if (err != B_OK)
161			return err;
162
163		// app flags
164		uint32 appFlags;
165		err = appFileInfoRead.GetAppFlags(&appFlags);
166		if (err == B_OK) {
167			err = appFileInfoWrite.SetAppFlags(appFlags);
168		} else if (err == B_ENTRY_NOT_FOUND) {
169			file.RemoveAttr(kAppFlagsAttribute);
170			err = B_OK;
171		}
172		if (err != B_OK)
173			return err;
174
175		// supported types
176		BMessage supportedTypes;
177		bool hasSupportedTypes = false;
178		err = appFileInfoRead.GetSupportedTypes(&supportedTypes);
179		if (err == B_OK) {
180			err = appFileInfoWrite.SetSupportedTypes(&supportedTypes, false,
181				false);
182			hasSupportedTypes = true;
183		} else if (err == B_ENTRY_NOT_FOUND)
184			err = appFileInfoWrite.SetSupportedTypes(NULL, false, false);
185		if (err != B_OK)
186			return err;
187
188		// vector icon
189		err = update_icon(appFileInfoRead, appFileInfoWrite, NULL);
190		if (err != B_OK)
191			return err;
192
193		// small icon
194		BBitmap smallIcon(BRect(0, 0, 15, 15), B_BITMAP_NO_SERVER_LINK,
195			B_CMAP8);
196		if (smallIcon.InitCheck() != B_OK)
197			return smallIcon.InitCheck();
198		err = update_icon(appFileInfoRead, appFileInfoWrite, NULL, smallIcon,
199			B_MINI_ICON);
200		if (err != B_OK)
201			return err;
202
203		// large icon
204		BBitmap largeIcon(BRect(0, 0, 31, 31), B_BITMAP_NO_SERVER_LINK,
205			B_CMAP8);
206		if (largeIcon.InitCheck() != B_OK)
207			return largeIcon.InitCheck();
208		err = update_icon(appFileInfoRead, appFileInfoWrite, NULL, largeIcon,
209			B_LARGE_ICON);
210		if (err != B_OK)
211			return err;
212
213		// version infos
214		const version_kind versionKinds[]
215			= {B_APP_VERSION_KIND, B_SYSTEM_VERSION_KIND};
216		for (int i = 0; i < 2; i++) {
217			version_kind kind = versionKinds[i];
218			version_info versionInfo;
219			err = appFileInfoRead.GetVersionInfo(&versionInfo, kind);
220			if (err == B_OK)
221				err = appFileInfoWrite.SetVersionInfo(&versionInfo, kind);
222			else if (err == B_ENTRY_NOT_FOUND)
223				err = appFileInfoWrite.SetVersionInfo(NULL, kind);
224			if (err != B_OK)
225				return err;
226		}
227
228		// icons for supported types
229		if (hasSupportedTypes) {
230			const char *supportedType;
231			for (int32 i = 0;
232				 supportedTypes.FindString("types", i, &supportedType) == B_OK;
233				 i++) {
234				// vector icon
235				err = update_icon(appFileInfoRead, appFileInfoWrite,
236					supportedType);
237				if (err != B_OK)
238					return err;
239
240				// small icon
241				err = update_icon(appFileInfoRead, appFileInfoWrite,
242					supportedType, smallIcon, B_MINI_ICON);
243				if (err != B_OK)
244					return err;
245
246				// large icon
247				err = update_icon(appFileInfoRead, appFileInfoWrite,
248					supportedType, largeIcon, B_LARGE_ICON);
249				if (err != B_OK)
250					return err;
251			}
252		}
253	}
254
255	return err;
256}
257
258
259} // namespace Mime
260} // namespace Storage
261} // namespace BPrivate
262