extra/src/lib/extra.c

827 lines
19 KiB
C

#ifdef HAVE_CONFIG_H
# include "config.h"
#endif
#include <sys/stat.h>
#include <fcntl.h>
#include "extra.h"
#include "extra_private.h"
static int _extra_init = 0;
static Ecore_Event_Handler *_data;
static Ecore_Event_Handler *_complete;
int _extra_lib_log_dom = -1;
Eina_List *_theme_list = NULL;
Eina_List *_background_list = NULL;
#define sec_strdup(v) v ? eina_strbuf_string_steal(v) : NULL
void _extra_theme_cache_load();
static Eina_Bool extra_request_may_override(Extra_Request *req, Extra_Progress *progress);
#define GEN_FILE_NAME(buf, t) eina_strbuf_append_printf(buf, "%s-%d.edj", t->obj.id, t->obj.version);
//===========
//theme stuff
typedef struct {
Extra_Theme theme;
Extra_Request *preview;
Extra_Request *cache_preview;
Extra_Request *main;
} Extra_Theme_Private;
typedef struct {
Eina_Strbuf *description;
Eina_Strbuf *author;
Eina_Strbuf *name;
Eina_Strbuf *version;
Eina_Strbuf *source;
Eina_Strbuf *id;
} Theme_Object;
static Eina_Bool
_fill_themes(Eina_Strbuf *buf)
{
Theme_Object *obj;
eina_list_free(_theme_list);
_theme_list = NULL;
EXTRA_JSON_TO_LIST_TEMPLATE_INIT(template, Theme_Object,
EXTRA_JSON_STRUCT_FIELD("description", Theme_Object, description, EINA_FALSE),
EXTRA_JSON_STRUCT_FIELD("author", Theme_Object, author, EINA_FALSE),
EXTRA_JSON_STRUCT_FIELD("source", Theme_Object, source, EINA_FALSE),
EXTRA_JSON_STRUCT_FIELD("name", Theme_Object, name, EINA_TRUE),
EXTRA_JSON_STRUCT_FIELD("version", Theme_Object, version, EINA_TRUE),
EXTRA_JSON_STRUCT_FIELD("theme_id", Theme_Object, id, EINA_TRUE)
);
Eina_List *lst = extra_json_to_list(&template, buf);
EINA_LIST_FREE(lst, obj)
{
Extra_Theme_Private *theme;
int versionNumb;
versionNumb = atoi(eina_strbuf_string_get(obj->version));
theme = calloc(1, sizeof(*theme));
theme->theme.obj.id = sec_strdup(obj->id);
theme->theme.obj.name = sec_strdup(obj->name);
theme->theme.obj.author = sec_strdup(obj->author);
theme->theme.description = sec_strdup(obj->description);
theme->theme.obj.source = sec_strdup(obj->source);
theme->theme.obj.version = versionNumb;
_theme_list = eina_list_append(_theme_list, theme);
extra_json_list_part_free(&template, obj);
}
return EINA_TRUE;
}
//================
//background stuff
typedef struct {
Extra_Background background;
Extra_Request *preview;
Extra_Request *cache_preview;
Extra_Request *main;
} Extra_Background_Private;
typedef struct {
Eina_Strbuf *author;
Eina_Strbuf *name;
Eina_Strbuf *source;
Eina_Strbuf *version;
Eina_Strbuf *id;
} Background_Object;
static Eina_Bool
_fill_backgrounds(Eina_Strbuf *buf)
{
Background_Object *obj;
eina_list_free(_background_list);
_background_list = NULL;
EXTRA_JSON_TO_LIST_TEMPLATE_INIT(template, Background_Object,
EXTRA_JSON_STRUCT_FIELD("author", Background_Object, author, EINA_FALSE),
EXTRA_JSON_STRUCT_FIELD("source", Background_Object, source, EINA_FALSE),
EXTRA_JSON_STRUCT_FIELD("name", Background_Object, name, EINA_TRUE),
EXTRA_JSON_STRUCT_FIELD("version", Background_Object, version, EINA_TRUE),
EXTRA_JSON_STRUCT_FIELD("background-id", Background_Object, id, EINA_TRUE),
);
Eina_List *lst = extra_json_to_list(&template, buf);
EINA_LIST_FREE(lst, obj)
{
Extra_Background_Private *background = calloc(1, sizeof(Extra_Background_Private));
int versionNumb;
versionNumb = atoi(eina_strbuf_string_get(obj->version));
background->background.obj.author = sec_strdup(obj->author);
background->background.obj.id = sec_strdup(obj->id);
background->background.obj.name = sec_strdup(obj->name);
background->background.obj.source = sec_strdup(obj->source);
background->background.obj.version = versionNumb;
_background_list = eina_list_append(_background_list, background);
extra_json_list_part_free(&template, obj);
}
return EINA_TRUE;
}
EAPI int
extra_init(void)
{
_extra_init++;
if (_extra_init > 1) return _extra_init;
eina_init();
_extra_lib_log_dom = eina_log_domain_register("extra", EINA_COLOR_CYAN);
if (_extra_lib_log_dom < 0)
{
EINA_LOG_ERR("extra can not create its log domain.");
goto shutdown_eina;
}
//we are putting stuff into <cachedir>/extra/ lets make sure its created
{
Eina_Strbuf *buf;
buf = eina_strbuf_new();
eina_strbuf_append(buf, efreet_cache_home_get());
eina_strbuf_append(buf, "/extra/");
ecore_file_mkdir(eina_strbuf_string_get(buf));
eina_strbuf_free(buf);
}
// Put here your initialization logic of your library
_extra_theme_cache_load();
eina_log_timing(_extra_lib_log_dom, EINA_LOG_STATE_STOP, EINA_LOG_STATE_INIT);
return _extra_init;
shutdown_eina:
eina_shutdown();
_extra_init--;
return _extra_init;
}
EAPI int
extra_shutdown(void)
{
_extra_init--;
if (_extra_init != 0) return _extra_init;
eina_log_timing(_extra_lib_log_dom,
EINA_LOG_STATE_START,
EINA_LOG_STATE_SHUTDOWN);
// Put here your shutdown logic
eina_log_domain_unregister(_extra_lib_log_dom);
_extra_lib_log_dom = -1;
eina_shutdown();
return _extra_init;
}
static Eina_Bool
_url_data_cb(void *data EINA_UNUSED, int type EINA_UNUSED, void *event_info)
{
Ecore_Con_Event_Url_Data *url_data = event_info;
Eina_Strbuf *buf = ecore_con_url_data_get(url_data->url_con);
eina_strbuf_append_n(buf, (char*)url_data->data, url_data->size);
return EINA_TRUE;
}
static char *
_cache_path_get(const char *purpose)
{
char *path;
path = malloc(PATH_MAX * sizeof(char));
sprintf(path, "%s/%s/%s.json", efreet_cache_home_get(), PACKAGE_NAME, purpose);
return path;
}
static void
_cache_content(Eina_Strbuf *content, const char *purpose)
{
char *path;
FILE *cache;
path = _cache_path_get(purpose);
cache = fopen(path, "w+");
if (!cache)
ERR("Failed to open cache.");
else
{
fprintf(cache, "%s", eina_strbuf_string_get(content));
fclose(cache);
}
free(path);
}
typedef struct {
Extra_Progress *progress;
Ecore_Con_Url *themes;
Eina_Strbuf *themes_content;
Ecore_Con_Url *backgrounds;
Eina_Strbuf *background_content;
} Extra_Sync_Request;
static void
_extra_sync_request_end_eval(Extra_Sync_Request *req)
{
if (!req->themes_content || !req->background_content) return;
if (_fill_themes(req->themes_content))
_cache_content(req->themes_content, "themes");
if (_fill_backgrounds(req->background_content))
_cache_content(req->background_content, "backgrounds");
if (req->progress->done_cb)
req->progress->done_cb(req->progress->data);
ecore_event_handler_del(_data);
ecore_event_handler_del(_complete);
}
static Eina_Bool
_url_complete_cb(void *data, int type EINA_UNUSED, void *event_info)
{
Ecore_Con_Event_Url_Complete *complete = event_info;
Extra_Sync_Request *request = data;
if (complete->url_con == request->backgrounds)
{
request->background_content = ecore_con_url_data_get(complete->url_con);
_extra_sync_request_end_eval(request);
}
else if (complete->url_con == request->themes)
{
request->themes_content = ecore_con_url_data_get(complete->url_con);
_extra_sync_request_end_eval(request);
}
return EINA_TRUE;
}
EAPI void
extra_sync(Extra_Progress *progress)
{
Extra_Sync_Request *req;
req = calloc(1, sizeof(Extra_Sync_Request));
req->progress = progress;
req->themes = ecore_con_url_custom_new("http://" HOSTNAME "/v1/themes/", "GET");
ecore_con_url_additional_header_add(req->themes, "Accept", "text/json");
ecore_con_url_data_set(req->themes, eina_strbuf_new());
req->backgrounds = ecore_con_url_custom_new("http://" HOSTNAME "/v1/backgrounds/", "GET");
ecore_con_url_additional_header_add(req->backgrounds, "Accept", "text/json");
ecore_con_url_data_set(req->backgrounds, eina_strbuf_new());
_data = ecore_event_handler_add(ECORE_CON_EVENT_URL_DATA, _url_data_cb, req);
_complete = ecore_event_handler_add(ECORE_CON_EVENT_URL_COMPLETE, _url_complete_cb, req);
ecore_con_url_get(req->backgrounds);
ecore_con_url_get(req->themes);
}
//=========
//Theme Api
EAPI Eina_List *
extra_themes_list(void)
{
return _theme_list;
}
EAPI Extra_Theme *extra_theme_get(const char *id)
{
Extra_Theme *theme;
Eina_List *item;
EINA_LIST_FOREACH(extra_themes_list(), item, theme)
if (!strcmp(id, theme->obj.id))
return theme;
return NULL;
}
EAPI Eina_Bool
extra_theme_installed(Extra_Theme *theme)
{
char *path;
Eina_Bool exists;
EINA_SAFETY_ON_NULL_RETURN_VAL(theme, EINA_FALSE);
path = extra_theme_install_path_get(theme);
exists = ecore_file_exists(path);
free(path);
return exists;
}
EAPI char *
extra_theme_install_path_get(Extra_Theme *theme)
{
Eina_Strbuf *buf;
char *path;
EINA_SAFETY_ON_NULL_RETURN_VAL(theme, NULL);
buf = eina_strbuf_new();
eina_strbuf_append(buf, elm_theme_user_dir_get());
eina_strbuf_append(buf, "/");
GEN_FILE_NAME(buf, theme);
path = eina_strbuf_string_steal(buf);
eina_strbuf_free(buf);
return path;
}
typedef struct {
char *remote;
char *local;
} Extra_Path_Pair;
static Extra_Path_Pair*
_extra_preview_path_pair_gen(const char *resource, Extra_Base_Object *obj)
{
Eina_Strbuf *remote, *local;
Extra_Path_Pair *result;
result = calloc(1, sizeof(Extra_Path_Pair));
remote = eina_strbuf_new();
local = eina_strbuf_new();
eina_strbuf_append_printf(remote, "http://" HOSTNAME "/%s/preview/%s.png", resource, obj->id);
eina_strbuf_append_printf(local, "%s/%s/%s-%s-%d.png", efreet_cache_home_get(), PACKAGE_NAME, resource, obj->id, obj->version);
result->local = eina_strbuf_string_steal(local);
result->remote = eina_strbuf_string_steal(remote);
eina_strbuf_free(remote);
eina_strbuf_free(local);
return result;
}
static void
_extra_path_pair_free(Extra_Path_Pair* pair)
{
free(pair->remote);
free(pair->local);
free(pair);
}
Extra_Progress p = {NULL, NULL, NULL};
EAPI char*
extra_theme_preview_get(Extra_Theme *theme)
{
Extra_Theme_Private *priv = ((Extra_Theme_Private*) theme);
Extra_Path_Pair *pair;
char *local;
//download is in progress do not return the path
if (priv->preview) return NULL;
pair = _extra_preview_path_pair_gen("themes", &theme->obj);
local = pair->local;
if (!ecore_file_exists(local))
{
local = NULL;
}
else
{
if (!priv->cache_preview)
extra_file_cache_download(&p, pair->remote, pair->local, &priv->cache_preview);
}
if (local)
local = strdup(local);
_extra_path_pair_free(pair);
return local;
}
EAPI Extra_Request*
extra_theme_preview_download(Extra_Progress *progress, Extra_Theme *theme)
{
Extra_Theme_Private *priv = ((Extra_Theme_Private*) theme);
Extra_Path_Pair *pair;
if (priv->preview)
{
if (extra_request_may_override(priv->preview, progress))
return priv->preview;
else
return NULL;
}
pair = _extra_preview_path_pair_gen("themes", &theme->obj);
extra_file_download(progress, pair->remote, pair->local, &priv->preview);
_extra_path_pair_free(pair);
return priv->preview;
}
EAPI char *
extra_theme_download_url_get(Extra_Theme *theme)
{
Eina_Strbuf *buf;
char *url;
EINA_SAFETY_ON_NULL_RETURN_VAL(theme, NULL);
buf = eina_strbuf_new();
eina_strbuf_append(buf, "http://" HOSTNAME "/themes/");
eina_strbuf_append_printf(buf, "%s-%d.edj", theme->obj.id, theme->obj.version);
url = eina_strbuf_string_steal(buf);
eina_strbuf_free(buf);
return url;
}
EAPI Extra_Request*
extra_theme_download(Extra_Progress *progress, Extra_Theme *theme)
{
char *path, *urlstr = NULL;
Extra_Theme_Private *priv = ((Extra_Theme_Private*) theme);
EINA_SAFETY_ON_NULL_RETURN_VAL(progress, NULL);
EINA_SAFETY_ON_NULL_RETURN_VAL(theme, NULL);
if (priv->preview)
{
if (extra_request_may_override(priv->preview, progress))
return priv->preview;
else
return NULL;
}
urlstr = extra_theme_download_url_get(theme);
path = extra_theme_install_path_get(theme);
extra_file_download(progress, urlstr, path, &priv->main);
free(urlstr);
free(path);
return priv->main;
}
void
_extra_theme_cache_load()
{
char *cache_path = _cache_path_get("themes");
if (ecore_file_exists(cache_path))
{
Eina_File *cache;
Eina_File_Line *line;
Eina_Iterator *it;
Eina_Strbuf *buf;
INF("Loading themes from cache");
cache = eina_file_open(cache_path, EINA_FALSE);
it = eina_file_map_lines(cache);
buf = eina_strbuf_new();
EINA_ITERATOR_FOREACH(it, line)
{
eina_strbuf_append_length(buf, line->start, line->length);
}
eina_iterator_free(it);
eina_file_close(cache);
_fill_themes(buf);
eina_strbuf_free(buf);
}
else
INF("No theme cache found");
free(cache_path);
}
static Eina_Bool
_enlightenment_restart(void *data EINA_UNUSED)
{
char *cmd = "enlightenment_remote -restart";
ecore_exe_run(cmd, NULL);
return EINA_FALSE;
}
EAPI void
extra_theme_use(Extra_Theme *t)
{
char *path;
EINA_SAFETY_ON_NULL_RETURN(t);
path = extra_theme_install_path_get(t);
elm_theme_set(NULL, path);
elm_config_all_flush();
elm_config_save();
free(path);
ecore_timer_add(3, _enlightenment_restart, NULL);
}
EAPI void
extra_theme_reset(void)
{
elm_theme_set(NULL, "default");
elm_config_all_flush();
elm_config_save();
ecore_timer_add(3, _enlightenment_restart, NULL);
}
EAPI Eina_Bool
extra_theme_default_get(Extra_Theme *t)
{
const char *theme_paths;
char *path, **split;
unsigned int items;
EINA_SAFETY_ON_NULL_RETURN_VAL(t, EINA_FALSE);
if (!extra_theme_installed(t)) return EINA_FALSE;
theme_paths = elm_theme_get(NULL);
path = extra_theme_install_path_get(t);
split = eina_str_split_full(theme_paths, path, -1, &items);
free(split[0]);
free(split);
return (items > 1);
}
EAPI Eina_Bool
extra_theme_installed_old(Extra_Theme *t)
{
Eina_List *n, *files;
char *file;
Eina_Bool b = EINA_FALSE;
Eina_Strbuf *buf;
EINA_SAFETY_ON_NULL_RETURN_VAL(t, EINA_FALSE);
buf = eina_strbuf_new();
files = ecore_file_ls(elm_theme_user_dir_get());
GEN_FILE_NAME(buf, t);
EINA_LIST_FOREACH(files, n, file)
{
if (!strcmp(eina_strbuf_string_get(buf), file))
continue;
if (eina_str_has_prefix(file, t->obj.id) &&
eina_str_has_extension(file, "edj"))
{
b = EINA_TRUE;
break;
}
}
EINA_LIST_FREE(files, file)
free(file);
eina_strbuf_free(buf);
return b;
}
//==============
//background api
EAPI Eina_List*
extra_backgrounds_list(void)
{
return _background_list;
}
EAPI Extra_Background*
extra_background_get(const char *id)
{
Eina_List *n;
Extra_Background *b;
EINA_LIST_FOREACH(_background_list, n, b)
{
if (!strcmp(id, b->obj.id))
return b;
}
return NULL;
}
EAPI char *
extra_background_download_url_get(Extra_Background *background)
{
Eina_Strbuf *buf;
char *url;
EINA_SAFETY_ON_NULL_RETURN_VAL(background, NULL);
buf = eina_strbuf_new();
eina_strbuf_append(buf, "http://" HOSTNAME "/backgrounds/");
eina_strbuf_append_printf(buf, "%s-%d.edj", background->obj.id, background->obj.version);
url = eina_strbuf_string_steal(buf);
eina_strbuf_free(buf);
return url;
}
EAPI char *
extra_background_install_path_get(Extra_Background *background)
{
Eina_Strbuf *buf;
char *path;
EINA_SAFETY_ON_NULL_RETURN_VAL(background, NULL);
buf = eina_strbuf_new();
eina_strbuf_append(buf, eina_environment_home_get());
eina_strbuf_append(buf, "/.e/e/backgrounds/");
eina_strbuf_append_printf(buf, "%s-%d.edj", background->obj.id, background->obj.version);
path = eina_strbuf_string_steal(buf);
eina_strbuf_free(buf);
return path;
}
EAPI Eina_Bool
extra_background_installed(Extra_Background *background)
{
char *path;
Eina_Bool exists;
EINA_SAFETY_ON_NULL_RETURN_VAL(background, EINA_FALSE);
path = extra_background_install_path_get(background);
exists = ecore_file_exists(path);
free(path);
return exists;
}
EAPI Extra_Request*
extra_background_download(Extra_Progress *progress, Extra_Background *background)
{
char *path, *urlstr = NULL;
Extra_Background_Private *priv = ((Extra_Background_Private*) background);
EINA_SAFETY_ON_NULL_RETURN_VAL(progress, NULL);
EINA_SAFETY_ON_NULL_RETURN_VAL(background, NULL);
if (priv->preview)
{
if (extra_request_may_override(priv->preview, progress))
return priv->preview;
else
return NULL;
}
urlstr = extra_background_download_url_get(background);
path = extra_background_install_path_get(background);
extra_file_download(progress, urlstr, path, &priv->main);
free(urlstr);
free(path);
return priv->main;
}
EAPI char*
extra_background_preview_get(Extra_Background *background)
{
Extra_Background_Private *priv = (Extra_Background_Private*) background;
Extra_Path_Pair *pair;
char *local;
if (priv->preview) return NULL;
pair = _extra_preview_path_pair_gen("backgrounds", &background->obj);
local = pair->local;
if (!ecore_file_exists(local))
{
local = NULL;
}
else
{
if (!priv->cache_preview)
{
extra_file_cache_download(&p, pair->remote, pair->local, &priv->cache_preview);
}
}
if (local)
local = strdup(local);
_extra_path_pair_free(pair);
return local;
}
EAPI Extra_Request*
extra_background_preview_download(Extra_Progress *progress, Extra_Background *background)
{
Extra_Background_Private *priv = (Extra_Background_Private*) background;
Extra_Path_Pair *pair;
if (priv->preview)
{
if (extra_request_may_override(priv->preview, progress))
return priv->preview;
else
return NULL;
}
pair = _extra_preview_path_pair_gen("backgrounds", &background->obj);
extra_file_download(progress, pair->remote, pair->local, &priv->preview);
_extra_path_pair_free(pair);
return priv->preview;
}
EAPI void
extra_background_delete(Extra_Background *b)
{
char *path;
path = extra_background_install_path_get(b);
ecore_file_remove(path);
free(path);
}
EAPI void
extra_request_mute(Extra_Request *req)
{
if(!req) return;
req->muted = EINA_TRUE;
req->progress.data = NULL;
req->progress.progress_cb = NULL;
req->progress.done_cb = NULL;
}
static Eina_Bool
extra_request_may_override(Extra_Request *req, Extra_Progress *progress)
{
if (!req->muted) return EINA_FALSE;
memcpy(&req->progress, progress, sizeof(Extra_Progress));
return EINA_TRUE;
}