1/*
2    Copyright (C) 2009-2010 ProFUSION embedded systems
3    Copyright (C) 2009-2010 Samsung Electronics
4
5    This library is free software; you can redistribute it and/or
6    modify it under the terms of the GNU Library General Public
7    License as published by the Free Software Foundation; either
8    version 2 of the License, or (at your option) any later version.
9
10    This library is distributed in the hope that it will be useful,
11    but WITHOUT ANY WARRANTY; without even the implied warranty of
12    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13    Library General Public License for more details.
14
15    You should have received a copy of the GNU Library General Public License
16    along with this library; see the file COPYING.LIB.  If not, write to
17    the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
18    Boston, MA 02110-1301, USA.
19*/
20
21#include "config.h"
22#include "ewk_settings.h"
23
24#include "EWebKit.h"
25#if ENABLE(DATABASE)
26#include "DatabaseTracker.h"
27#endif
28#include "IconDatabase.h"
29#include "Image.h"
30#include "IntSize.h"
31#include "KURL.h"
32#include "MemoryCache.h"
33#include "ewk_private.h"
34
35#include <Eina.h>
36#include <eina_safety_checks.h>
37#include <errno.h>
38#include <string.h>
39#include <sys/stat.h>
40#include <sys/types.h>
41#include <sys/utsname.h>
42#include <unistd.h>
43#include <wtf/text/CString.h>
44#include <wtf/text/StringConcatenate.h>
45
46#if USE(SOUP)
47#include "ResourceHandle.h"
48#include <libsoup/soup.h>
49#endif
50
51#if ENABLE(OFFLINE_WEB_APPLICATIONS)
52#include "appcache/ApplicationCacheStorage.h"
53
54static const char* _ewk_cache_directory_path = 0;
55#endif
56
57static const char* _ewk_default_web_database_path = 0;
58static const char* _ewk_icon_database_path = 0;
59static uint64_t _ewk_default_web_database_quota = 1 * 1024 * 1024;
60
61static WTF::String _ewk_settings_webkit_platform_get()
62{
63    WTF::String ua_platform;
64#if PLATFORM(X11)
65    ua_platform = "X11";
66#else
67    ua_platform = "Unknown";
68#endif
69    return ua_platform;
70}
71
72static WTF::String _ewk_settings_webkit_os_version_get()
73{
74    WTF::String ua_os_version;
75    struct utsname name;
76
77    if (uname(&name) != -1)
78        ua_os_version = WTF::String(name.sysname) + " " + WTF::String(name.machine);
79    else
80        ua_os_version = "Unknown";
81
82    return ua_os_version;
83}
84
85/**
86 * Returns the default quota for Web Database databases. By default
87 * this value is 1MB.
88 *
89 * @return the current default database quota in bytes
90 */
91uint64_t ewk_settings_web_database_default_quota_get(void)
92{
93    return _ewk_default_web_database_quota;
94}
95
96/**
97 * Sets the current path to the directory WebKit will write Web
98 * Database databases.
99 *
100 * @param path the new database directory path
101 */
102void ewk_settings_web_database_path_set(const char *path)
103{
104#if ENABLE(DATABASE)
105    WTF::String corePath = WTF::String::fromUTF8(path);
106    WebCore::DatabaseTracker::tracker().setDatabaseDirectoryPath(corePath);
107    if (!_ewk_default_web_database_path)
108        _ewk_default_web_database_path = eina_stringshare_add(corePath.utf8().data());
109    else
110        eina_stringshare_replace(&_ewk_default_web_database_path, corePath.utf8().data());
111
112#endif
113}
114
115/**
116 * Returns directory path where web database is stored.
117 *
118 * This is guaranteed to be eina_stringshare, so whenever possible
119 * save yourself some cpu cycles and use eina_stringshare_ref()
120 * instead of eina_stringshare_add() or strdup().
121 *
122 * @return database path or @c 0 if none or web database is not supported
123 */
124const char *ewk_settings_web_database_path_get(void)
125{
126#if ENABLE(DATABASE)
127    return _ewk_default_web_database_path;
128#else
129    return 0;
130#endif
131}
132
133/**
134 * Sets directory where to store icon database, opening or closing database.
135 *
136 * @param directory where to store icon database, must be
137 *        write-able, if @c 0 is given, then database is closed
138 *
139 * @return @c EINA_TRUE on success, @c EINA_FALSE on errors
140 */
141Eina_Bool ewk_settings_icon_database_path_set(const char *directory)
142{
143    WebCore::IconDatabase::delayDatabaseCleanup();
144
145    if (directory) {
146        struct stat st;
147
148        if (stat(directory, &st)) {
149            ERR("could not stat(%s): %s", directory, strerror(errno));
150            return EINA_FALSE;
151        }
152
153        if (!S_ISDIR(st.st_mode)) {
154            ERR("not a directory: %s", directory);
155            return EINA_FALSE;
156        }
157
158        if (access(directory, R_OK | W_OK)) {
159            ERR("could not access directory '%s' for read and write: %s",
160                directory, strerror(errno));
161            return EINA_FALSE;
162        }
163
164        WebCore::iconDatabase().setEnabled(true);
165        WebCore::iconDatabase().open(WTF::String::fromUTF8(directory), WebCore::IconDatabase::defaultDatabaseFilename());
166        if (!_ewk_icon_database_path)
167            _ewk_icon_database_path = eina_stringshare_add(directory);
168        else
169            eina_stringshare_replace(&_ewk_icon_database_path, directory);
170    } else {
171        WebCore::iconDatabase().setEnabled(false);
172        WebCore::iconDatabase().close();
173        if (_ewk_icon_database_path) {
174            eina_stringshare_del(_ewk_icon_database_path);
175            _ewk_icon_database_path = 0;
176        }
177    }
178    return EINA_TRUE;
179}
180
181/**
182 * Returns directory path where icon database is stored.
183 *
184 * This is guaranteed to be eina_stringshare, so whenever possible
185 * save yourself some cpu cycles and use eina_stringshare_ref()
186 * instead of eina_stringshare_add() or strdup().
187 *
188 * @return database path or @c 0 if none is set or database is closed
189 */
190const char* ewk_settings_icon_database_path_get(void)
191{
192    if (!WebCore::iconDatabase().isEnabled())
193        return 0;
194    if (!WebCore::iconDatabase().isOpen())
195        return 0;
196
197    return _ewk_icon_database_path;
198}
199
200/**
201 * Removes all known icons from database.
202 *
203 * Database must be opened with ewk_settings_icon_database_path_set()
204 * in order to work.
205 *
206 * @return @c EINA_TRUE on success or @c EINA_FALSE otherwise, like
207 *         closed database.
208 */
209Eina_Bool ewk_settings_icon_database_clear(void)
210{
211    if (!WebCore::iconDatabase().isEnabled())
212        return EINA_FALSE;
213    if (!WebCore::iconDatabase().isOpen())
214        return EINA_FALSE;
215
216    WebCore::iconDatabase().removeAllIcons();
217    return EINA_TRUE;
218}
219
220/**
221 * Queries icon for given URL, returning associated cairo surface.
222 *
223 * @note In order to have this working, one must open icon database
224 *       with ewk_settings_icon_database_path_set().
225 *
226 * @param url which url to query icon
227 *
228 * @return cairo surface if any, or @c 0 on failure
229 */
230cairo_surface_t* ewk_settings_icon_database_icon_surface_get(const char *url)
231{
232    EINA_SAFETY_ON_NULL_RETURN_VAL(url, 0);
233
234    WebCore::KURL kurl(WebCore::KURL(), WTF::String::fromUTF8(url));
235    WebCore::Image *icon = WebCore::iconDatabase().synchronousIconForPageURL(kurl.string(), WebCore::IntSize(16, 16));
236
237    if (!icon) {
238        ERR("no icon for url %s", url);
239        return 0;
240    }
241
242    return icon->nativeImageForCurrentFrame();
243}
244
245/**
246 * Creates Evas_Object of type image representing the given URL.
247 *
248 * This is an utility function that creates an Evas_Object of type
249 * image set to have fill always match object size
250 * (evas_object_image_filled_add()), saving some code to use it from Evas.
251 *
252 * @note In order to have this working, one must open icon database
253 *       with ewk_settings_icon_database_path_set().
254 *
255 * @param url which url to query icon
256 * @param canvas evas instance where to add resulting object
257 *
258 * @return newly allocated Evas_Object instance or @c 0 on
259 *         errors. Delete the object with evas_object_del().
260 */
261Evas_Object* ewk_settings_icon_database_icon_object_add(const char* url, Evas* canvas)
262{
263    EINA_SAFETY_ON_NULL_RETURN_VAL(url, 0);
264    EINA_SAFETY_ON_NULL_RETURN_VAL(canvas, 0);
265
266    WebCore::KURL kurl(WebCore::KURL(), WTF::String::fromUTF8(url));
267    WebCore::Image* icon = WebCore::iconDatabase().synchronousIconForPageURL(kurl.string(), WebCore::IntSize(16, 16));
268    cairo_surface_t* surface;
269
270    if (!icon) {
271        ERR("no icon for url %s", url);
272        return 0;
273    }
274
275    surface = icon->nativeImageForCurrentFrame();
276    return ewk_util_image_from_cairo_surface_add(canvas, surface);
277}
278
279/**
280 * Sets the given proxy URI to network backend.
281 *
282 * @param proxy URI to set
283 */
284void ewk_settings_proxy_uri_set(const char* proxy)
285{
286#if USE(SOUP)
287    SoupSession* session = WebCore::ResourceHandle::defaultSession();
288
289    if (!proxy) {
290        ERR("no proxy uri. remove proxy feature in soup.");
291        soup_session_remove_feature_by_type(session, SOUP_TYPE_PROXY_RESOLVER);
292        return;
293    }
294
295    SoupURI* uri = soup_uri_new(proxy);
296    EINA_SAFETY_ON_NULL_RETURN(uri);
297
298    g_object_set(session, SOUP_SESSION_PROXY_URI, uri, NULL);
299    soup_uri_free(uri);
300#elif USE(CURL)
301    EINA_SAFETY_ON_TRUE_RETURN(1);
302#endif
303}
304
305/**
306 * Gets the proxy URI from the network backend.
307 *
308 * @return current proxy URI or @c 0 if it's not set
309 */
310const char* ewk_settings_proxy_uri_get(void)
311{
312#if USE(SOUP)
313    SoupURI* uri;
314    SoupSession* session = WebCore::ResourceHandle::defaultSession();
315    g_object_get(session, SOUP_SESSION_PROXY_URI, &uri, NULL);
316
317    if (!uri) {
318        ERR("no proxy uri");
319        return 0;
320    }
321
322    WTF::String proxy = soup_uri_to_string(uri, EINA_FALSE);
323    return eina_stringshare_add(proxy.utf8().data());
324#elif USE(CURL)
325    EINA_SAFETY_ON_TRUE_RETURN_VAL(1, 0);
326#endif
327}
328
329/**
330 * Gets status of the memory cache of WebCore.
331 *
332 * @return @c EINA_TRUE if the cache is enabled or @c EINA_FALSE if not
333 */
334Eina_Bool ewk_settings_cache_enable_get(void)
335{
336    WebCore::MemoryCache* cache = WebCore::memoryCache();
337    return !cache->disabled();
338}
339
340/**
341 * Enables/disables the memory cache of WebCore, possibly clearing it.
342 *
343 * Disabling the cache will remove all resources from the cache.
344 * They may still live on if they are referenced by some Web page though.
345 *
346 * @param set @c EINA_TRUE to enable memory cache, @c EINA_FALSE to disable
347 */
348void ewk_settings_cache_enable_set(Eina_Bool set)
349{
350    WebCore::MemoryCache* cache = WebCore::memoryCache();
351    set = !set;
352    if (cache->disabled() != set)
353        cache->setDisabled(set);
354}
355
356/**
357 * Sets capacity of memory cache of WebCore.
358 *
359 * WebCore sets default value of memory cache on 8192 * 1024 bytes.
360 *
361 * @param capacity the maximum number of bytes that the cache should consume overall
362 */
363void ewk_settings_cache_capacity_set(unsigned capacity)
364{
365    WebCore::MemoryCache* cache = WebCore::memoryCache();
366    cache->setCapacities(0, capacity, capacity);
367}
368
369/**
370 * @internal
371 *
372 * Gets the default user agent string.
373 *
374 * @return a pointer to an eina_stringshare containing the user agent string
375 */
376const char* ewk_settings_default_user_agent_get(void)
377{
378    WTF::String ua_version = makeString(String::number(WEBKIT_USER_AGENT_MAJOR_VERSION), '.', String::number(WEBKIT_USER_AGENT_MINOR_VERSION), '+');
379    WTF::String static_ua = makeString("Mozilla/5.0 (", _ewk_settings_webkit_platform_get(), "; ", _ewk_settings_webkit_os_version_get(), ") AppleWebKit/", ua_version) + makeString(" (KHTML, like Gecko) Version/5.0 Safari/", ua_version);
380
381    return eina_stringshare_add(static_ua.utf8().data());
382}
383
384/**
385 * Sets cache directory.
386 *
387 * @param path where to store cache, must be write-able.
388 *
389 * @return @c EINA_TRUE on success, @c EINA_FALSE if path is NULL or offline
390 *         web application is not supported.
391 */
392Eina_Bool ewk_settings_cache_directory_path_set(const char *path)
393{
394#if ENABLE(OFFLINE_WEB_APPLICATIONS)
395    if (!path)
396        return EINA_FALSE;
397
398    WebCore::cacheStorage().setCacheDirectory(WTF::String::fromUTF8(path));
399    if (!_ewk_cache_directory_path)
400        _ewk_cache_directory_path = eina_stringshare_add(path);
401    else
402        eina_stringshare_replace(&_ewk_cache_directory_path, path);
403    return EINA_TRUE;
404#else
405    EINA_SAFETY_ON_TRUE_RETURN_VAL(1, EINA_FALSE);
406#endif
407}
408
409/**
410 * Return cache directory path.
411 *
412 * This is guaranteed to be eina_stringshare, so whenever possible
413 * save yourself some cpu cycles and use eina_stringshare_ref()
414 * instead of eina_stringshare_add() or strdup().
415 *
416 * @return cache directory path.
417 */
418const char *ewk_settings_cache_directory_path_get()
419{
420#if ENABLE(OFFLINE_WEB_APPLICATIONS)
421    return _ewk_cache_directory_path;
422#else
423    EINA_SAFETY_ON_TRUE_RETURN_VAL(1, 0);
424#endif
425}
426