summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorMike Blumenkrantz <m.blumenkran@samsung.com>2013-06-14 15:36:11 +0100
committerMike Blumenkrantz <m.blumenkran@samsung.com>2013-06-14 15:36:11 +0100
commitf4a327a0ca93bc48fced863da022648c608d3021 (patch)
treeef473e7af3999935d2015887c22ec24f8c6d96fc /src
parentc00785634a9f7ab1324c7f5dd3cafff075f36401 (diff)
add teamwork module
see http://e18releasemanager.wordpress.com/2013/06/14/why/ for more info
Diffstat (limited to 'src')
-rw-r--r--src/bin/e_module.c1
-rw-r--r--src/modules/Makefile.am4
-rw-r--r--src/modules/Makefile_teamwork.am19
-rw-r--r--src/modules/teamwork/e-module-teamwork.edjbin0 -> 13926 bytes
-rw-r--r--src/modules/teamwork/e_mod_config.c157
-rw-r--r--src/modules/teamwork/e_mod_main.c207
-rw-r--r--src/modules/teamwork/e_mod_main.h65
-rw-r--r--src/modules/teamwork/e_mod_tw.c873
-rw-r--r--src/modules/teamwork/module.desktop.in6
-rw-r--r--src/modules/teamwork/sha1.c146
-rw-r--r--src/modules/teamwork/sha1.h54
11 files changed, 1532 insertions, 0 deletions
diff --git a/src/bin/e_module.c b/src/bin/e_module.c
index f7af17e33..9de1968e2 100644
--- a/src/bin/e_module.c
+++ b/src/bin/e_module.c
@@ -889,6 +889,7 @@ _e_module_whitelist_check(void)
889 "syscon", 889 "syscon",
890 "systray", 890 "systray",
891 "tasks", 891 "tasks",
892 "teamwork",
892 "temperature", 893 "temperature",
893 "tiling", 894 "tiling",
894 "winlist", 895 "winlist",
diff --git a/src/modules/Makefile.am b/src/modules/Makefile.am
index a2932a44f..2f085bb6d 100644
--- a/src/modules/Makefile.am
+++ b/src/modules/Makefile.am
@@ -207,6 +207,10 @@ if USE_MODULE_QUICKACCESS
207include Makefile_quickaccess.am 207include Makefile_quickaccess.am
208endif 208endif
209 209
210if USE_MODULE_TEAMWORK
211include Makefile_teamwork.am
212endif
213
210if USE_MODULE_SHOT 214if USE_MODULE_SHOT
211include Makefile_shot.am 215include Makefile_shot.am
212endif 216endif
diff --git a/src/modules/Makefile_teamwork.am b/src/modules/Makefile_teamwork.am
new file mode 100644
index 000000000..90029c709
--- /dev/null
+++ b/src/modules/Makefile_teamwork.am
@@ -0,0 +1,19 @@
1teamworkdir = $(MDIR)/teamwork
2teamwork_DATA = teamwork/e-module-teamwork.edj \
3 teamwork/module.desktop
4
5EXTRA_DIST += $(teamwork_DATA)
6
7teamworkpkgdir = $(MDIR)/teamwork/$(MODULE_ARCH)
8teamworkpkg_LTLIBRARIES = teamwork/module.la
9
10teamwork_module_la_SOURCES = teamwork/e_mod_main.c \
11 teamwork/e_mod_config.c \
12 teamwork/e_mod_main.h \
13 teamwork/e_mod_tw.c \
14 teamwork/sha1.c \
15 teamwork/sha1.h
16
17.PHONY: teamwork install-teamwork
18teamwork: $(teamworkpkg_LTLIBRARIES) $(teamwork_DATA)
19install-teamwork: install-teamworkDATA install-teamworkpkgLTLIBRARIES
diff --git a/src/modules/teamwork/e-module-teamwork.edj b/src/modules/teamwork/e-module-teamwork.edj
new file mode 100644
index 000000000..a394dcb85
--- /dev/null
+++ b/src/modules/teamwork/e-module-teamwork.edj
Binary files differ
diff --git a/src/modules/teamwork/e_mod_config.c b/src/modules/teamwork/e_mod_config.c
new file mode 100644
index 000000000..e6e6ea7d4
--- /dev/null
+++ b/src/modules/teamwork/e_mod_config.c
@@ -0,0 +1,157 @@
1#include "e_mod_main.h"
2
3struct _E_Config_Dialog_Data
4{
5 int disable_media_fetch;
6 double allowed_media_size;
7 double allowed_media_age;
8
9 double mouse_out_delay;
10 double popup_size;
11 double popup_opacity;
12};
13
14static void *
15_create_data(E_Config_Dialog *cfd EINA_UNUSED)
16{
17 E_Config_Dialog_Data *cfdata;
18
19 cfdata = E_NEW(E_Config_Dialog_Data, 1);
20#define SET(X) \
21 cfdata->X = tw_config->X
22 SET(disable_media_fetch);
23 SET(allowed_media_size);
24 SET(allowed_media_age);
25
26 SET(mouse_out_delay);
27 SET(popup_size);
28 SET(popup_opacity);
29#undef SET
30 return cfdata;
31}
32
33static void
34_free_data(E_Config_Dialog *cfd EINA_UNUSED, E_Config_Dialog_Data *cfdata)
35{
36 tw_mod->cfd = NULL;
37 free(cfdata);
38}
39
40static int
41_basic_check_changed(E_Config_Dialog *cfd EINA_UNUSED, E_Config_Dialog_Data *cfdata)
42{
43#define CHECK(X) \
44 if (cfdata->X != tw_config->X) return 1
45
46 CHECK(disable_media_fetch);
47 if (lround(cfdata->allowed_media_age) != tw_config->allowed_media_age) return 1;
48 if (lround(cfdata->allowed_media_size) != tw_config->allowed_media_size) return 1;
49
50 if (fabs(cfdata->mouse_out_delay - tw_config->allowed_media_size) > 0.45) return 1;
51
52 if (fabs(cfdata->popup_size - tw_config->popup_size) > 0.9) return 1;
53 if (fabs(cfdata->popup_opacity - tw_config->popup_opacity) > 0.9) return 1;
54
55#undef CHECK
56 return 0;
57}
58
59static Evas_Object *
60_basic_create_widgets(E_Config_Dialog *cfd EINA_UNUSED,
61 Evas *evas,
62 E_Config_Dialog_Data *cfdata)
63{
64 Evas_Object *ob, *ol, *otb, *tab;
65
66 tab = e_widget_table_add(evas, 0);
67
68 otb = e_widget_toolbook_add(evas, 48 * e_scale, 48 * e_scale);
69
70 ///////////////////////////////////////////
71
72 ol = e_widget_list_add(evas, 0, 0);
73
74 ob = e_widget_check_add(evas, _("Disable remote media fetching"), &cfdata->disable_media_fetch);
75 e_widget_list_object_append(ol, ob, 1, 0, 0.5);
76
77 ob = e_widget_label_add(evas, _("Maximum media cache size in RAM"));
78 e_widget_list_object_append(ol, ob, 1, 1, 0.5);
79 ob = e_widget_slider_add(evas, 1, 0, _("%4.0f MiB"), 0, 1024, 16, 0, &cfdata->allowed_media_size, NULL, 150);
80 e_widget_list_object_append(ol, ob, 1, 1, 0.5);
81 ob = e_widget_label_add(evas, _("Maximum media cache age on disk"));
82 e_widget_list_object_append(ol, ob, 1, 1, 0.5);
83 ob = e_widget_slider_add(evas, 1, 0, _("%3.0f Days"), -1, 180, 1, 0, &cfdata->allowed_media_age, NULL, 150);
84 e_widget_list_object_append(ol, ob, 1, 1, 0.5);
85
86 e_widget_toolbook_page_append(otb, NULL, _("Cache"), ol, 1, 1, 1, 1, 0.5, 0.5);
87
88 ///////////////////////////////////////////
89
90 ol = e_widget_list_add(evas, 0, 0);
91
92 ob = e_widget_label_add(evas, _("Mouse-out hide delay"));
93 e_widget_list_object_append(ol, ob, 1, 1, 0.5);
94 ob = e_widget_slider_add(evas, 1, 0, _("%1.1f seconds"), 0, 5, 0.5, 0, &cfdata->mouse_out_delay, NULL, 150);
95 e_widget_list_object_append(ol, ob, 1, 1, 0.5);
96 ob = e_widget_label_add(evas, _("Maximum size (Percentage of screens size)"));
97 e_widget_list_object_append(ol, ob, 1, 1, 0.5);
98 ob = e_widget_slider_add(evas, 1, 0, _("%3.0f"), 10, 100, 1, 0, &cfdata->popup_size, NULL, 150);
99 e_widget_list_object_append(ol, ob, 1, 1, 0.5);
100 ob = e_widget_label_add(evas, _("Opacity"));
101 e_widget_list_object_append(ol, ob, 1, 1, 0.5);
102 ob = e_widget_slider_add(evas, 1, 0, _("%3.0f"), 10, 100, 1, 0, &cfdata->popup_opacity, NULL, 150);
103 e_widget_list_object_append(ol, ob, 1, 1, 0.5);
104
105 e_widget_toolbook_page_append(otb, NULL, _("Popups"), ol, 1, 1, 1, 1, 0.5, 0.5);
106
107 e_widget_toolbook_page_show(otb, 0);
108
109 e_widget_table_object_append(tab, otb, 0, 0, 1, 1, 1, 1, 1, 1);
110 return tab;
111}
112
113
114static int
115_basic_apply_data(E_Config_Dialog *cfd EINA_UNUSED,
116 E_Config_Dialog_Data *cfdata)
117{
118
119#define SET(X) tw_config->X = cfdata->X
120 SET(disable_media_fetch);
121 SET(allowed_media_size);
122 SET(allowed_media_age);
123
124 SET(mouse_out_delay);
125 SET(popup_size);
126 if (fabs(cfdata->popup_opacity - tw_config->popup_opacity) > 0.9)
127 {
128 SET(popup_opacity);
129 tw_popup_opacity_set();
130 }
131
132 e_config_save_queue();
133 return 1;
134}
135
136EINTERN E_Config_Dialog *
137e_int_config_teamwork_module(E_Container *con, const char *params EINA_UNUSED)
138{
139 E_Config_Dialog *cfd;
140 E_Config_Dialog_View *v;
141 char buf[4096];
142
143 if (tw_mod->cfd) return NULL;
144 snprintf(buf, sizeof(buf), "%s/e-module-teamwork.edj", e_module_dir_get(tw_mod->module));
145 v = E_NEW(E_Config_Dialog_View, 1);
146
147 v->create_cfdata = _create_data;
148 v->free_cfdata = _free_data;
149 v->basic.apply_cfdata = _basic_apply_data;
150 v->basic.create_widgets = _basic_create_widgets;
151 v->basic.check_changed = _basic_check_changed;
152
153 cfd = e_config_dialog_new(con, _("Teamwork Settings"),
154 "E", "applications/teamwork", buf, 32, v, tw_mod);
155 tw_mod->cfd = cfd;
156 return cfd;
157}
diff --git a/src/modules/teamwork/e_mod_main.c b/src/modules/teamwork/e_mod_main.c
new file mode 100644
index 000000000..ed9d742cf
--- /dev/null
+++ b/src/modules/teamwork/e_mod_main.c
@@ -0,0 +1,207 @@
1#include "e_mod_main.h"
2#include "sha1.h"
3
4EINTERN int _e_teamwork_log_dom = -1;
5EINTERN Mod *tw_mod = NULL;
6EINTERN Teamwork_Config *tw_config = NULL;
7
8EAPI E_Module_Api e_modapi = {E_MODULE_API_VERSION, "Teamwork"};
9
10static E_Config_DD *conf_edd = NULL;
11
12static E_Action *e_tw_toggle = NULL;
13static const char _act_toggle[] = "tw_toggle";
14static const char _e_tw_name[] = N_("Teamwork");
15static const char _lbl_toggle[] = N_("Toggle Popup Visibility");
16
17static const char *
18_sha1_to_string(const unsigned char *hashout)
19{
20 const char hextab[] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' };
21 char sha1[41] = {0};
22 unsigned int i = 0;
23
24 for (i = 0; i < 20; i++)
25 {
26 sha1[2 * i] = hextab[(hashout[i] >> 4) & 0x0f];
27 sha1[2 * i + 1] = hextab[hashout[i] & 0x0f];
28 }
29 return eina_stringshare_add(sha1);
30}
31
32const char *
33sha1_encode(const unsigned char *data, size_t len)
34{
35 SHA_CTX2 ctx;
36 unsigned char hashout[20];
37 unsigned char *buf;
38
39 if (EINA_UNLIKELY(len > 65000))
40 buf = malloc(len);
41 else
42 buf = alloca(len);
43 EINA_SAFETY_ON_NULL_RETURN_VAL(buf, NULL);
44 memcpy(buf, data, len);
45
46 SHA1_Init2(&ctx);
47 SHA1_Update2(&ctx, buf, len);
48 SHA1_Final2(hashout, &ctx);
49 if (EINA_UNLIKELY(len > 65000)) free(buf);
50 return _sha1_to_string(hashout);
51}
52
53//////////////////////////////
54static Teamwork_Config *
55e_tw_config_new(void)
56{
57 Teamwork_Config *cf;
58
59 cf = E_NEW(Teamwork_Config, 1);
60 cf->config_version = MOD_CONFIG_FILE_VERSION;
61
62 cf->allowed_media_size = 10; // 10 megabytes
63 cf->allowed_media_age = 3; // 3 days
64
65 cf->mouse_out_delay = 0.0;
66 cf->popup_size = 10.0;
67 cf->popup_opacity = 90.0;
68
69 return cf;
70}
71
72static E_Config_DD *
73e_tw_config_dd_new(void)
74{
75 conf_edd = E_CONFIG_DD_NEW("Teamwork_Config", Teamwork_Config);
76
77#undef T
78#undef D
79#define T Teamwork_Config
80#define D conf_edd
81 E_CONFIG_VAL(D, T, config_version, UINT);
82 E_CONFIG_VAL(D, T, disable_media_fetch, UCHAR);
83 E_CONFIG_VAL(D, T, allowed_media_size, LL);
84 E_CONFIG_VAL(D, T, allowed_media_age, INT);
85
86 E_CONFIG_VAL(D, T, mouse_out_delay, DOUBLE);
87 E_CONFIG_VAL(D, T, popup_size, DOUBLE);
88 E_CONFIG_VAL(D, T, popup_opacity, DOUBLE);
89 return conf_edd;
90}
91//////////////////////////////
92static void
93e_tw_act_toggle_cb(E_Object *obj EINA_UNUSED, const char *params EINA_UNUSED)
94{
95 if (!tw_mod->pop) return;
96 if (tw_mod->sticky)
97 tw_hide(NULL);
98 tw_mod->sticky = !tw_mod->sticky;
99}
100//////////////////////////////
101EAPI void *
102e_modapi_init(E_Module *m)
103{
104 char buf[PATH_MAX];
105 E_Configure_Option *co;
106
107 snprintf(buf, sizeof(buf), "%s/e-module-teamwork.edj", e_module_dir_get(m));
108 e_configure_registry_category_add("applications", 20, _("Apps"), NULL,
109 "preferences-applications");
110 e_configure_registry_item_add("applications/teamwork", 1, _("Teamwork"), NULL,
111 buf, e_int_config_teamwork_module);
112
113 tw_mod = E_NEW(Mod, 1);
114 tw_mod->module = m;
115 m->data = tw_mod;
116 conf_edd = e_tw_config_dd_new();
117 tw_config = e_config_domain_load("module.teamwork", conf_edd);
118 if (tw_config)
119 {
120 if (!e_util_module_config_check(_("Teamwork"), tw_config->config_version, MOD_CONFIG_FILE_VERSION))
121 E_FREE_FUNC(tw_config, free);
122 }
123
124 if (tw_config)
125 {
126 /* sanity checks */
127 tw_config->mouse_out_delay = E_CLAMP(tw_config->mouse_out_delay, 0.0, 5.0);
128 tw_config->popup_size = E_CLAMP(tw_config->popup_size, 10.0, 100.0);
129 tw_config->popup_opacity = E_CLAMP(tw_config->popup_opacity, 10.0, 100.0);
130 }
131 else
132 tw_config = e_tw_config_new();
133 tw_config->config_version = MOD_CONFIG_FILE_VERSION;
134
135 _e_teamwork_log_dom = eina_log_domain_register("teamwork", EINA_COLOR_ORANGE);
136 eina_log_domain_level_set("teamwork", EINA_LOG_LEVEL_DBG);
137
138 if (!e_tw_init())
139 {
140 e_modapi_shutdown(NULL);
141 return NULL;
142 }
143 e_tw_toggle = e_action_add(_act_toggle);
144 e_tw_toggle->func.go = e_tw_act_toggle_cb;
145 e_action_predef_name_set(_e_tw_name, _lbl_toggle, _act_toggle, NULL, NULL, 0);
146
147 e_configure_option_domain_current_set("teamwork");
148
149 E_CONFIGURE_OPTION_ADD_CUSTOM(co, "teamwork-settings", _("Teamwork settings panel"), _("teamwork"), _("applications"));
150 co->info = eina_stringshare_add("applications/teamwork");
151 E_CONFIGURE_OPTION_ICON(co, buf);
152 E_CONFIGURE_OPTION_ADD(co, BOOL, disable_media_fetch, tw_config, _("Disable Teamwork remote media fetching"), _("teamwork"));
153 E_CONFIGURE_OPTION_ADD(co, DOUBLE, allowed_media_size, tw_config, _("Maximum total size of Teamwork media to keep in RAM"), _("teamwork"), _("cache"));
154 E_CONFIGURE_OPTION_MINMAX_STEP_FMT(co, 0, 1024, 16, _("%4.0f MiB"));
155 E_CONFIGURE_OPTION_HELP(co, _("This option determines how much memory will be used to cache recent media for faster loading."));
156 E_CONFIGURE_OPTION_ADD(co, DOUBLE, allowed_media_age, tw_config, _("Maximum age for a disk-cached Teamwork media item"), _("teamwork"), _("cache"));
157 E_CONFIGURE_OPTION_MINMAX_STEP_FMT(co, -1, 180, 1, _("%3.0f Days"));
158 E_CONFIGURE_OPTION_HELP(co, _("This option determines how long media will remain in the disk cache before it is pruned.</ps>"
159 "Set to -1 to never delete media, or to 0 to never cache media on disk."));
160
161 E_CONFIGURE_OPTION_ADD(co, DOUBLE, mouse_out_delay, tw_config, _("Delay before closing a Teamwork popup on mouse-out"), _("teamwork"), _("mouse"));
162 E_CONFIGURE_OPTION_MINMAX_STEP_FMT(co, 0, 5, 0.5, _("%1.1f seconds"));
163 E_CONFIGURE_OPTION_ADD(co, DOUBLE, popup_size, tw_config, _("Maximum percentage of screen to use for Teamwork popups"), _("teamwork"), _("screen"));
164 E_CONFIGURE_OPTION_MINMAX_STEP_FMT(co, 10, 100, 1, _("%3.0f"));
165 E_CONFIGURE_OPTION_ADD(co, DOUBLE, popup_opacity, tw_config, _("Opacity to use for Teamwork popups"), _("teamwork"));
166 E_CONFIGURE_OPTION_MINMAX_STEP_FMT(co, 10, 100, 1, _("%3.0f"));
167 co->funcs[0].none = tw_popup_opacity_set;
168
169 e_configure_option_category_tag_add(_("applications"), _("teamwork"));
170 e_configure_option_category_tag_add(_("teamwork"), _("teamwork"));
171 e_configure_option_category_icon_set(_("teamwork"), buf);
172
173 return m;
174}
175
176EAPI int
177e_modapi_shutdown(E_Module *m __UNUSED__)
178{
179 e_tw_shutdown();
180
181 E_CONFIG_DD_FREE(conf_edd);
182 eina_log_domain_unregister(_e_teamwork_log_dom);
183 _e_teamwork_log_dom = -1;
184
185 e_configure_registry_item_del("applications/teamwork");
186 e_configure_registry_category_del("applications");
187
188 e_configure_option_domain_clear("teamwork");
189 e_configure_option_category_tag_del(_("teamwork"), _("teamwork"));
190 e_configure_option_category_tag_del(_("applications"), _("teamwork"));
191
192 e_action_predef_name_del(_e_tw_name, _lbl_toggle);
193 e_action_del(_act_toggle);
194 e_tw_toggle = NULL;
195
196 E_FREE(tw_config);
197 E_FREE(tw_mod);
198 return 1;
199}
200
201EAPI int
202e_modapi_save(E_Module *m __UNUSED__)
203{
204 e_config_domain_save("module.teamwork", conf_edd, tw_config);
205 return 1;
206}
207
diff --git a/src/modules/teamwork/e_mod_main.h b/src/modules/teamwork/e_mod_main.h
new file mode 100644
index 000000000..679447c30
--- /dev/null
+++ b/src/modules/teamwork/e_mod_main.h
@@ -0,0 +1,65 @@
1#ifndef E_MOD_MAIN_H
2#define E_MOD_MAIN_H
3
4#ifdef HAVE_CONFIG_H
5#include "config.h"
6#endif
7
8#include "e.h"
9
10/* Increment for Major Changes */
11#define MOD_CONFIG_FILE_EPOCH 1
12/* Increment for Minor Changes (ie: user doesn't need a new config) */
13#define MOD_CONFIG_FILE_GENERATION 0
14#define MOD_CONFIG_FILE_VERSION ((MOD_CONFIG_FILE_EPOCH * 1000000) + MOD_CONFIG_FILE_GENERATION)
15
16typedef struct Teamwork_Config
17{
18 unsigned int config_version;
19
20 Eina_Bool disable_media_fetch;
21 long long int allowed_media_size;
22 int allowed_media_age;
23
24 double mouse_out_delay;
25 double popup_size;
26 double popup_opacity;
27} Teamwork_Config;
28
29typedef struct Mod
30{
31 E_Module *module;
32 E_Config_Dialog *cfd;
33 size_t media_size;
34 Eina_Inlist *media_list;
35 Eina_Hash *media;
36 E_Popup *pop;
37 Eina_Bool sticky : 1;
38} Mod;
39
40extern Teamwork_Config *tw_config;
41extern Mod *tw_mod;
42extern int _e_teamwork_log_dom;
43
44EINTERN const char *sha1_encode(const unsigned char *data, size_t len);
45
46EINTERN int e_tw_init(void);
47EINTERN void e_tw_shutdown(void);
48EINTERN Eina_Bool tw_hide(void *d EINA_UNUSED);
49EINTERN void tw_popup_opacity_set(void);
50
51EINTERN E_Config_Dialog *e_int_config_teamwork_module(E_Container *con, const char *params EINA_UNUSED);
52
53EAPI int e_modapi_shutdown(E_Module *m __UNUSED__);
54#undef DBG
55#undef INF
56#undef WRN
57#undef ERR
58#undef CRIT
59#define DBG(...) EINA_LOG_DOM_DBG(_e_teamwork_log_dom, __VA_ARGS__)
60#define INF(...) EINA_LOG_DOM_INFO(_e_teamwork_log_dom, __VA_ARGS__)
61#define WRN(...) EINA_LOG_DOM_WARN(_e_teamwork_log_dom, __VA_ARGS__)
62#define ERR(...) EINA_LOG_DOM_ERR(_e_teamwork_log_dom, __VA_ARGS__)
63#define CRIT(...) EINA_LOG_DOM_CRIT(_e_teamwork_log_dom, __VA_ARGS__)
64
65#endif
diff --git a/src/modules/teamwork/e_mod_tw.c b/src/modules/teamwork/e_mod_tw.c
new file mode 100644
index 000000000..e9ca7740e
--- /dev/null
+++ b/src/modules/teamwork/e_mod_tw.c
@@ -0,0 +1,873 @@
1#include "e_mod_main.h"
2
3#define IMAGE_FETCH_TRIES 5
4
5typedef struct
6{
7 const char *sha1;
8 unsigned long long timestamp;
9} Media_Cache;
10
11typedef struct Media_Cache_List
12{
13 Eina_List *cache;
14} Media_Cache_List;
15
16typedef struct Media
17{
18 EINA_INLIST;
19 Ecore_Con_Url *client;
20 Eina_Binbuf *buf;
21 const char *addr;
22 unsigned long long timestamp;
23 unsigned int tries;
24 Eina_Bool dummy : 1;
25 Eina_Bool valid : 1;
26 Eina_Bool show : 1;
27} Media;
28
29static Eet_File *media = NULL;
30static Eet_File *dummies = NULL;
31static Eet_Data_Descriptor *cleaner_edd = NULL;
32static Eet_Data_Descriptor *cache_edd = NULL;
33static Ecore_Idler *media_cleaner = NULL;
34static Eina_List *handlers = NULL;
35static Media_Cache_List *tw_cache_list = NULL;
36
37static Evas_Point last_coords = {0};
38
39static Ecore_Timer *tw_hide_timer = NULL;
40
41static Eldbus_Service_Interface *tw_dbus_iface = NULL;
42
43typedef enum
44{
45 TEAMWORK_LINK_TYPE_NONE,
46 TEAMWORK_LINK_TYPE_LOCAL_FILE,
47 TEAMWORK_LINK_TYPE_LOCAL_DIRECTORY,
48 TEAMWORK_LINK_TYPE_REMOTE
49} Teamwork_Link_Type;
50
51typedef enum
52{
53 TEAMWORK_SIGNAL_LINK_DOWNLOADING,
54 TEAMWORK_SIGNAL_LINK_PROGRESS,
55 TEAMWORK_SIGNAL_LINK_COMPLETE,
56 TEAMWORK_SIGNAL_LINK_INVALID,
57} Teamwork_Signal;
58
59static const Eldbus_Signal tw_signals[] =
60{
61 [TEAMWORK_SIGNAL_LINK_DOWNLOADING] = {"LinkDownloading", ELDBUS_ARGS({"s", "URI"}, {"u", "Timestamp"}), 0},
62 [TEAMWORK_SIGNAL_LINK_PROGRESS] = {"LinkProgress", ELDBUS_ARGS({"s", "URI"}, {"u", "Timestamp"}, {"d", "Percent Completion"}), 0},
63 [TEAMWORK_SIGNAL_LINK_COMPLETE] = {"LinkComplete", ELDBUS_ARGS({"s", "URI"}, {"u", "Timestamp"}), 0},
64 [TEAMWORK_SIGNAL_LINK_INVALID] = {"LinkInvalid", ELDBUS_ARGS({"s", "URI"}, {"u", "Timestamp"}), 0},
65 {}
66};
67
68static void tw_show(Media *i);
69static void tw_show_local_file(const char *uri);
70static void tw_show_local_dir(const char *uri);
71static int tw_media_add(const char *url, Eina_Binbuf *buf, unsigned long long timestamp);
72static void download_media_cleanup(void);
73static void tw_dummy_add(const char *url);
74static Eina_Bool tw_dummy_check(const char *url);
75static void tw_media_ping(const char *url, unsigned long long timestamp);
76static Eina_Binbuf *tw_media_get(const char *url, unsigned long long timestamp);
77static Eina_Bool tw_idler_start(void);
78
79static void
80dbus_signal_link_complete(Media *i)
81{
82 unsigned int u = ecore_time_unix_get();
83 if (i->show) tw_show(i);
84 i->show = 0;
85 eldbus_service_signal_emit(tw_dbus_iface, TEAMWORK_SIGNAL_LINK_COMPLETE, i->addr, u);
86}
87
88static void
89dbus_signal_link_invalid(Media *i)
90{
91 unsigned int u = ecore_time_unix_get();
92 eldbus_service_signal_emit(tw_dbus_iface, TEAMWORK_SIGNAL_LINK_INVALID, i->addr, u);
93}
94
95static void
96dbus_signal_link_progress(Media *i, double pr)
97{
98 unsigned int u = ecore_time_unix_get();
99 eldbus_service_signal_emit(tw_dbus_iface, TEAMWORK_SIGNAL_LINK_PROGRESS, i->addr, u, pr);
100}
101
102static void
103dbus_signal_link_downloading(Media *i)
104{
105 unsigned int u = ecore_time_unix_get();
106 eldbus_service_signal_emit(tw_dbus_iface, TEAMWORK_SIGNAL_LINK_DOWNLOADING, i->addr, u);
107}
108
109static Eina_Bool
110download_media_complete(void *data, int type EINA_UNUSED, Ecore_Con_Event_Url_Complete *ev)
111{
112 Media *i;
113
114 if (data != tw_mod) return ECORE_CALLBACK_RENEW;
115 i = ecore_con_url_data_get(ev->url_con);
116 if (!i) return ECORE_CALLBACK_RENEW;
117 if (!i->valid) return ECORE_CALLBACK_RENEW;
118 i->timestamp = (unsigned long long)ecore_time_unix_get();
119 if (tw_media_add(i->addr, i->buf, i->timestamp) == 1)
120 tw_mod->media_size += eina_binbuf_length_get(i->buf);
121 E_FREE_FUNC(i->client, ecore_con_url_free);
122 dbus_signal_link_complete(i);
123 download_media_cleanup();
124 INF("MEDIA CACHE: %zu bytes", tw_mod->media_size);
125 return ECORE_CALLBACK_RENEW;
126}
127
128static Eina_Bool
129download_media_data(void *data, int type EINA_UNUSED, Ecore_Con_Event_Url_Data *ev)
130{
131 Media *i;
132
133 if (data != tw_mod) return ECORE_CALLBACK_RENEW;
134 i = ecore_con_url_data_get(ev->url_con);
135 if (!i) return ECORE_CALLBACK_RENEW;
136 if (i->dummy) return ECORE_CALLBACK_RENEW;
137 if (!i->buf) i->buf = eina_binbuf_new();
138 eina_binbuf_append_length(i->buf, ev->data, ev->size);
139 return ECORE_CALLBACK_RENEW;
140}
141
142static Eina_Bool
143download_media_status(void *data, int type EINA_UNUSED, Ecore_Con_Event_Url_Progress *ev)
144{
145 int status;
146 const char *h;
147 Media *i;
148 const Eina_List *l;
149
150 if (data != tw_mod) return ECORE_CALLBACK_RENEW;
151 i = ecore_con_url_data_get(ev->url_con);
152 if (!i) return ECORE_CALLBACK_RENEW;
153
154 if (i->valid) return ECORE_CALLBACK_RENEW; //already checked
155 status = ecore_con_url_status_code_get(ev->url_con);
156 if (!status) return ECORE_CALLBACK_RENEW; //not ready yet
157 DBG("%i code for media: %s", status, i->addr);
158 if (status != 200)
159 {
160 E_FREE_FUNC(i->buf, eina_binbuf_free);
161 E_FREE_FUNC(i->client, ecore_con_url_free);
162 if ((status >= 400) || (status <= 300)) goto dummy;
163 if (++i->tries < IMAGE_FETCH_TRIES)
164 {
165 i->client = ecore_con_url_new(i->addr);
166 ecore_con_url_data_set(i->client, i);
167 if (!ecore_con_url_get(i->client)) goto dummy;
168 }
169 return ECORE_CALLBACK_RENEW;
170 }
171 EINA_LIST_FOREACH(ecore_con_url_response_headers_get(ev->url_con), l, h)
172 {
173 if (strncasecmp(h, "Content-Type: ", sizeof("Content-Type: ") - 1)) continue;
174 if (strncasecmp(h + sizeof("Content-Type: ") - 1, "image/", 6)) goto dummy;
175 }
176 i->valid = !i->dummy;
177 if (i->valid) dbus_signal_link_progress(i, ev->down.now / ev->down.total);
178
179 return ECORE_CALLBACK_RENEW;
180dummy:
181 dbus_signal_link_invalid(i);
182 tw_dummy_add(i->addr);
183 i->dummy = EINA_TRUE;
184 E_FREE_FUNC(i->buf, eina_binbuf_free);
185 E_FREE_FUNC(i->client, ecore_con_url_free);
186 return ECORE_CALLBACK_RENEW;
187}
188
189static int
190download_media_sort_cb(Media *a, Media *b)
191{
192 long long diff;
193 diff = a->timestamp - b->timestamp;
194 if (diff < 0) return -1;
195 if (!diff) return 0;
196 return 1;
197}
198
199static Media *
200download_media_add(const char *url)
201{
202 Media *i;
203 unsigned long long t;
204
205 t = (unsigned long long)ecore_time_unix_get();
206
207 i = eina_hash_find(tw_mod->media, url);
208 if (i)
209 {
210 if (i->buf)
211 {
212 i->timestamp = t;
213 tw_media_ping(url, i->timestamp);
214 }
215 else
216 {
217 /* randomly deleted during cache pruning */
218 i->buf = tw_media_get(url, t);
219 tw_mod->media_size += eina_binbuf_length_get(i->buf);
220 }
221 tw_mod->media_list = eina_inlist_promote(tw_mod->media_list, EINA_INLIST_GET(i));
222 download_media_cleanup();
223 return i;
224 }
225 if (tw_dummy_check(url)) return NULL;
226 if (tw_config->disable_media_fetch) return NULL;
227 i = calloc(1, sizeof(Media));
228 i->addr = eina_stringshare_add(url);
229 i->buf = tw_media_get(url, t);
230 if (i->buf)
231 tw_mod->media_size += eina_binbuf_length_get(i->buf);
232 else
233 {
234 i->client = ecore_con_url_new(url);
235 ecore_con_url_data_set(i->client, i);
236 ecore_con_url_get(i->client);
237 dbus_signal_link_downloading(i);
238 }
239 eina_hash_direct_add(tw_mod->media, url, i);
240 tw_mod->media_list = eina_inlist_sorted_insert(tw_mod->media_list, EINA_INLIST_GET(i), (Eina_Compare_Cb)download_media_sort_cb);
241 return i;
242}
243
244static void
245download_media_free(Media *i)
246{
247 if (!i) return;
248 tw_mod->media_list = eina_inlist_remove(tw_mod->media_list, EINA_INLIST_GET(i));
249 if (i->client) ecore_con_url_free(i->client);
250 if (i->buf) eina_binbuf_free(i->buf);
251 eina_stringshare_del(i->addr);
252 free(i);
253}
254
255static void
256download_media_cleanup(void)
257{
258 Media *i;
259 Eina_Inlist *l;
260
261 if (tw_config->allowed_media_age)
262 {
263 if (tw_config->allowed_media_size < 0) return;
264 if ((size_t)tw_config->allowed_media_size > (tw_mod->media_size / 1024 / 1024)) return;
265 }
266 if (!tw_mod->media_list) return;
267 l = tw_mod->media_list->last;
268 while (l)
269 {
270 i = EINA_INLIST_CONTAINER_GET(l, Media);
271 l = l->prev;
272 if (!i->buf) continue;
273 /* only free the buffers here where possible to avoid having to deal with multiple list entries */
274 if (tw_mod->media_size && (tw_mod->media_size >= eina_binbuf_length_get(i->buf)))
275 tw_mod->media_size -= eina_binbuf_length_get(i->buf);
276 E_FREE_FUNC(i->buf, eina_binbuf_free);
277 if (!tw_config->allowed_media_age)
278 /* if caching is disabled, just delete */
279 eina_hash_del_by_key(tw_mod->media, i->addr);
280 if ((size_t)tw_config->allowed_media_size > (tw_mod->media_size / 1024 / 1024))
281 break;
282 }
283}
284
285static Teamwork_Link_Type
286dbus_link_uri_local_type_get(const char *uri)
287{
288 size_t len = strlen(uri);
289
290 if (uri[len - 1] == '/') return TEAMWORK_LINK_TYPE_LOCAL_DIRECTORY;
291 return TEAMWORK_LINK_TYPE_LOCAL_FILE;
292}
293
294static Teamwork_Link_Type
295dbus_link_uri_type_get(const char *uri)
296{
297 if (!uri[0]) return TEAMWORK_LINK_TYPE_NONE; //invalid
298 if (uri[0] == '/') return dbus_link_uri_local_type_get(uri + 1); //probably a file?
299 if ((!strncasecmp(uri, "http://", 7)) || (!strncasecmp(uri, "https://", 8))) return TEAMWORK_LINK_TYPE_REMOTE;
300 if (!strncmp(uri, "file://", 7)) return dbus_link_uri_local_type_get(uri + 7);
301 WRN("Unknown link type for '%s'", uri);
302 return TEAMWORK_LINK_TYPE_NONE;
303}
304
305static Eldbus_Message *
306dbus_link_detect_cb(const Eldbus_Service_Interface *iface EINA_UNUSED, const Eldbus_Message *msg)
307{
308 const char *uri;
309 unsigned int t;
310
311 if (!tw_config->allowed_media_age) goto out;
312 if (!eldbus_message_arguments_get(msg, "su", &uri, &t)) goto out;
313
314 if (dbus_link_uri_type_get(uri) == TEAMWORK_LINK_TYPE_REMOTE)
315 download_media_add(uri);
316out:
317 return eldbus_message_method_return_new(msg);
318}
319
320static void
321dbus_link_show_helper(const char *uri, Eina_Bool signal_open)
322{
323 Teamwork_Link_Type type;
324
325 if (tw_mod->pop && (!e_util_strcmp(e_object_data_get(E_OBJECT(tw_mod->pop)), uri))) return;
326 type = dbus_link_uri_type_get(uri);
327 switch (type)
328 {
329 case TEAMWORK_LINK_TYPE_NONE: break;
330 case TEAMWORK_LINK_TYPE_LOCAL_DIRECTORY:
331 if (signal_open) tw_show_local_dir(uri);
332 break;
333 case TEAMWORK_LINK_TYPE_LOCAL_FILE:
334 tw_show_local_file(uri);
335 break;
336 case TEAMWORK_LINK_TYPE_REMOTE:
337 {
338 Media *i;
339
340 i = eina_hash_find(tw_mod->media, uri);
341 if (!i)
342 {
343 if (tw_dummy_check(uri)) break;
344 i = download_media_add(uri);
345 if (i)
346 {
347 if (i->buf) tw_show(i);
348 else if (i->dummy) break;
349 else i->show = 1;
350 }
351 }
352 else if (!i->dummy) tw_show(i);
353 break;
354 }
355 }
356}
357
358static Eldbus_Message *
359dbus_link_show_cb(const Eldbus_Service_Interface *iface EINA_UNUSED, const Eldbus_Message *msg)
360{
361 const char *uri;
362
363 if (eldbus_message_arguments_get(msg, "s", &uri))
364 {
365 last_coords.x = last_coords.y = -1;
366 dbus_link_show_helper(uri, 1);
367 }
368 return eldbus_message_method_return_new(msg);
369}
370
371static Eldbus_Message *
372dbus_link_hide_cb(const Eldbus_Service_Interface *iface EINA_UNUSED, const Eldbus_Message *msg)
373{
374 const char *uri;
375
376 if (eldbus_message_arguments_get(msg, "s", &uri))
377 {
378 if (tw_mod->pop && (!tw_mod->sticky) && (!e_util_strcmp(e_object_data_get(E_OBJECT(tw_mod->pop)), uri)))
379 tw_hide(NULL);
380 }
381 return eldbus_message_method_return_new(msg);
382}
383
384static Eldbus_Message *
385dbus_link_mouse_in_cb(const Eldbus_Service_Interface *iface EINA_UNUSED, const Eldbus_Message *msg)
386{
387 const char *uri;
388 unsigned int t;
389
390 if (eldbus_message_arguments_get(msg, "suii", &uri, &t, &last_coords.x, &last_coords.y))
391 dbus_link_show_helper(uri, 0);
392 return eldbus_message_method_return_new(msg);
393}
394
395static Eldbus_Message *
396dbus_link_mouse_out_cb(const Eldbus_Service_Interface *iface EINA_UNUSED, const Eldbus_Message *msg)
397{
398 const char *uri;
399 unsigned int t;
400
401 if (eldbus_message_arguments_get(msg, "suii", &uri, &t, &last_coords.x, &last_coords.y))
402 {
403 if (tw_mod->pop && (!tw_mod->sticky) && (!e_util_strcmp(e_object_data_get(E_OBJECT(tw_mod->pop)), uri)))
404 {
405 if (tw_config->mouse_out_delay)
406 {
407 if (tw_hide_timer) ecore_timer_reset(tw_hide_timer);
408 else tw_hide_timer = ecore_timer_add(tw_config->mouse_out_delay, tw_hide, NULL);
409 }
410 else
411 tw_hide(NULL);
412 }
413 }
414 return eldbus_message_method_return_new(msg);
415}
416
417static Eldbus_Message *
418dbus_link_open_cb(const Eldbus_Service_Interface *iface EINA_UNUSED, const Eldbus_Message *msg)
419{
420 const char *uri;
421
422 if (eldbus_message_arguments_get(msg, "s", &uri))
423 {
424 char *sb;
425 size_t size = 4096, len = sizeof(E_BINDIR "/enlightenment_open ") - 1;
426
427 sb = malloc(size);
428 memcpy(sb, E_BINDIR "/enlightenment_open ", len);
429 sb = e_util_string_append_quoted(sb, &size, &len, uri);
430 ecore_exe_run(sb, NULL);
431 free(sb);
432 }
433 return eldbus_message_method_return_new(msg);
434}
435
436
437static const Eldbus_Method tw_methods[] = {
438 { "LinkDetect", ELDBUS_ARGS({"s", "URI"}, {"u", "Timestamp"}), NULL, dbus_link_detect_cb },
439 { "LinkMouseIn", ELDBUS_ARGS({"s", "URI"}, {"u", "Timestamp"}, {"i", "X Coordinate"}, {"i", "Y Coordinate"}), NULL, dbus_link_mouse_in_cb },
440 { "LinkMouseOut", ELDBUS_ARGS({"s", "URI"}, {"u", "Timestamp"}, {"i", "X Coordinate"}, {"i", "Y Coordinate"}), NULL, dbus_link_mouse_out_cb },
441 { "LinkShow", ELDBUS_ARGS({"s", "URI"}), NULL, dbus_link_show_cb },
442 { "LinkHide", ELDBUS_ARGS({"s", "URI"}), NULL, dbus_link_hide_cb },
443 { "LinkOpen", ELDBUS_ARGS({"s", "URI"}), NULL, dbus_link_open_cb },
444 { }
445};
446
447static const Eldbus_Service_Interface_Desc tw_desc =
448{
449 "org.enlightenment.wm.Teamwork", tw_methods, tw_signals
450};
451
452static Eet_Data_Descriptor *
453media_cache_edd_new(void)
454{
455 Eet_Data_Descriptor *edd;
456 Eet_Data_Descriptor_Class eddc;
457 EET_EINA_FILE_DATA_DESCRIPTOR_CLASS_SET(&eddc, Media_Cache);
458 edd = eet_data_descriptor_stream_new(&eddc);
459#define ADD(name, type) \
460 EET_DATA_DESCRIPTOR_ADD_BASIC(edd, Media_Cache, #name, name, EET_T_##type)
461
462 ADD(sha1, INLINED_STRING);
463 ADD(timestamp, ULONG_LONG);
464#undef ADD
465 return edd;
466}
467
468static int
469media_cache_compare(Media_Cache *a, Media_Cache *b)
470{
471 long long diff;
472 diff = a->timestamp - b->timestamp;
473 if (diff < 0) return -1;
474 if (!diff) return 0;
475 return 1;
476}
477
478static void
479media_cache_add(const char *sha1, unsigned long long timestamp)
480{
481 Media_Cache *ic;
482 if (!tw_cache_list) return;
483 ic = malloc(sizeof(Media_Cache));
484 ic->sha1 = eina_stringshare_ref(sha1);
485 ic->timestamp = timestamp;
486 tw_cache_list->cache = eina_list_sorted_insert(tw_cache_list->cache, (Eina_Compare_Cb)media_cache_compare, ic);
487}
488
489static void
490media_cache_del(const char *sha1)
491{
492 Eina_List *l, *l2;
493 Media_Cache *ic;
494
495 if (!tw_cache_list) return;
496 EINA_LIST_FOREACH_SAFE(tw_cache_list->cache, l, l2, ic)
497 {
498 if (ic->sha1 == sha1) continue;
499 tw_cache_list->cache = eina_list_remove_list(tw_cache_list->cache, l);
500 return;
501 }
502}
503
504static void
505media_cache_update(const char *sha1, unsigned long long timestamp)
506{
507 Media_Cache *ic;
508 Eina_List *l;
509
510 if (!tw_cache_list) return;
511 EINA_LIST_FOREACH(tw_cache_list->cache, l, ic)
512 {
513 if (ic->sha1 != sha1) continue;
514 ic->timestamp = timestamp;
515 break;
516 }
517 tw_cache_list->cache = eina_list_sort(tw_cache_list->cache, eina_list_count(tw_cache_list->cache), (Eina_Compare_Cb)media_cache_compare);
518}
519
520static Eina_Bool
521media_cleaner_cb(void *data EINA_UNUSED)
522{
523 unsigned long long now;
524 Media_Cache *ic;
525 Eina_List *l, *l2;
526 int cleaned = 0;
527 if ((!cleaner_edd) || (!cache_edd) || (tw_config->allowed_media_age < 0) || (!tw_cache_list) || (!tw_cache_list->cache))
528 {
529 media_cleaner = NULL;
530 return EINA_FALSE;
531 }
532
533 if (tw_config->allowed_media_age)
534 {
535 now = (unsigned long long)ecore_time_unix_get();
536 now -= tw_config->allowed_media_age * 24 * 60 * 60;
537 }
538 else
539 now = ULONG_LONG_MAX;
540 EINA_LIST_FOREACH_SAFE(tw_cache_list->cache, l, l2, ic)
541 {
542 /* only clean up to 3 entries at a time to ensure responsiveness */
543 if (cleaned >= 3) break;
544 if (ic->timestamp >= now)
545 {
546 /* stop the idler for now to avoid pointless spinning */
547 ecore_timer_add(24 * 60 * 60, (Ecore_Task_Cb)tw_idler_start, NULL);
548 media_cleaner = NULL;
549 return EINA_FALSE;
550 }
551 eet_delete(media, ic->sha1);
552 tw_cache_list->cache = eina_list_remove_list(tw_cache_list->cache, l);
553 eina_stringshare_del(ic->sha1);
554 free(ic);
555 cleaned++;
556 }
557 return EINA_TRUE;
558}
559
560static void
561tw_dummy_add(const char *url)
562{
563 if (!dummies) return;
564 eet_write(dummies, url, "0", 1, 0);
565 INF("Added new dummy for url %s", url);
566}
567
568static Eina_Bool
569tw_dummy_check(const char *url)
570{
571 char **list;
572 int lsize;
573
574 if (!dummies) return EINA_FALSE;
575 list = eet_list(dummies, url, &lsize);
576 if (lsize)
577 {
578 free(list);
579 return EINA_TRUE;
580 }
581 return EINA_FALSE;
582}
583
584static int
585tw_media_add(const char *url, Eina_Binbuf *buf, unsigned long long timestamp)
586{
587 const char *sha1;
588 int lsize;
589 char **list;
590
591 if (!media) return -1;
592 if (!tw_config->allowed_media_age) return 0; //disk caching disabled
593
594 sha1 = sha1_encode(eina_binbuf_string_get(buf), eina_binbuf_length_get(buf));
595 INF("Media: %s - %s", url, sha1);
596
597 list = eet_list(media, url, &lsize);
598 if (lsize)
599 {
600 eina_stringshare_del(sha1);
601 free(list);
602 return -1; /* should never happen */
603 }
604 list = eet_list(media, sha1, &lsize);
605 if (lsize)
606 {
607 eet_alias(media, url, sha1, 0);
608 eet_sync(media);
609 INF("Added new alias for image %s", sha1);
610 eina_stringshare_del(sha1);
611 free(list);
612 return 0;
613 }
614
615 eet_write(media, sha1, eina_binbuf_string_get(buf), eina_binbuf_length_get(buf), 1);
616 eet_alias(media, url, sha1, 0);
617 eet_sync(media);
618 media_cache_add(sha1, timestamp);
619 INF("Added new media with length %zu: %s", eina_binbuf_length_get(buf), sha1);
620 eina_stringshare_del(sha1);
621 return 1;
622}
623
624void
625tw_media_del(const char *url)
626{
627 const char *alias;
628 if (!media) return;
629 alias = eet_alias_get(media, url);
630 eet_delete(media, alias);
631 media_cache_del(alias);
632 eina_stringshare_del(alias);
633}
634
635static Eina_Binbuf *
636tw_media_get(const char *url, unsigned long long timestamp)
637{
638 size_t size;
639 unsigned char *img;
640 Eina_Binbuf *buf = NULL;
641 const char *alias;
642 char **list;
643 int lsize;
644
645 if (!media) return NULL;
646
647 list = eet_list(media, url, &lsize);
648 if (!lsize) return NULL;
649 free(list);
650
651 img = eet_read(media, url, (int*)&size);
652 alias = eet_alias_get(media, url);
653 buf = eina_binbuf_manage_new_length(img, size);
654 media_cache_update(alias, timestamp);
655
656 eina_stringshare_del(alias);
657 return buf;
658}
659
660static void
661tw_media_ping(const char *url, unsigned long long timestamp)
662{
663 const char *alias;
664
665 if (!media) return;
666
667 alias = eet_alias_get(media, url);
668 media_cache_update(alias, timestamp);
669
670 eina_stringshare_del(alias);
671}
672
673static Eina_Bool
674tw_idler_start(void)
675{
676 if (!media) return EINA_FALSE;
677 media_cleaner = ecore_idler_add((Ecore_Task_Cb)media_cleaner_cb, NULL);
678 return EINA_FALSE;
679}
680
681static void
682tw_popup_del(void *obj)
683{
684 eina_stringshare_del(e_object_data_get(obj));
685}
686
687EINTERN void
688tw_popup_opacity_set(void)
689{
690 if (tw_mod->pop && tw_mod->pop->cw)
691 e_comp_win_opacity_set(tw_mod->pop->cw, lround((double)255 * (tw_config->popup_opacity / 100.)));
692}
693
694static void
695tw_show_helper(Evas_Object *o, int w, int h)
696{
697 int px, py, pw, ph;
698 double ratio = tw_config->popup_size / 100.;
699
700 E_FREE_FUNC(tw_mod->pop, e_object_del);
701 tw_mod->sticky = 0;
702 tw_mod->pop = e_popup_new(e_zone_current_get(e_util_container_current_get()), 0, 0, 1, 1);
703 e_popup_ignore_events_set(tw_mod->pop, 1);
704 pw = MIN(w, (ratio * (double)tw_mod->pop->zone->w));
705 pw = MIN(pw, tw_mod->pop->zone->w);
706 if (pw == w) ph = h;
707 else
708 ph = lround((double)(pw * h) / ((double)w));
709 if (ph > tw_mod->pop->zone->h)
710 {
711 ph = tw_mod->pop->zone->h;
712 pw = lround((double)(ph * w) / ((double)h));
713 }
714 e_widget_preview_size_set(o, pw, ph);
715 e_widget_preview_vsize_set(o, w, h);
716 e_popup_layer_set(tw_mod->pop, E_COMP_CANVAS_LAYER_POPUP, 0);
717
718 if ((last_coords.x == last_coords.y) && (last_coords.x == -1))
719 {
720 px = lround(ratio * (double)tw_mod->pop->zone->w) - (pw / 2);
721 py = lround(ratio * (double)tw_mod->pop->zone->h) - (ph / 2);
722 if (px + pw > tw_mod->pop->zone->w)
723 px = tw_mod->pop->zone->w - pw;
724 if (py + ph > tw_mod->pop->zone->h)
725 py = tw_mod->pop->zone->h - ph;
726 }
727 else
728 {
729 /* prefer tooltip left of last_coords */
730 px = last_coords.x - pw - 3;
731 /* if it's offscreen, try right of last_coords */
732 if (px < 0) px = last_coords.x + 3;
733 /* fuck this, stick it right on the last_coords */
734 if (px + pw + 3 > tw_mod->pop->zone->w)
735 px = (last_coords.x / 2) - (pw / 2);
736 /* give up */
737 if (px < 0) px = 0;
738
739 /* prefer tooltip above last_coords */
740 py = last_coords.y - ph - 3;
741 /* if it's offscreen, try below last_coords */
742 if (py < 0) py = last_coords.y + 3;
743 /* fuck this, stick it right on the last_coords */
744 if (py + ph + 3 > tw_mod->pop->zone->h)
745 py = (last_coords.y / 2) - (ph / 2);
746 /* give up */
747 if (py < 0) py = 0;
748 }
749 e_popup_move_resize(tw_mod->pop, px, py, pw, ph);
750 e_popup_content_set(tw_mod->pop, o);
751 e_popup_show(tw_mod->pop);
752 tw_popup_opacity_set();
753 E_OBJECT_DEL_SET(tw_mod->pop, tw_popup_del);
754}
755
756static void
757tw_show(Media *i)
758{
759 Evas_Object *o, *ic, *prev;
760 int w, h;
761
762 if (!i->buf) i->buf = tw_media_get(i->addr, ecore_time_unix_get());
763 if (!i->buf) return;
764 prev = e_widget_preview_add(e_util_comp_current_get()->evas, 50, 50);
765 o = evas_object_image_filled_add(e_widget_preview_evas_get(prev));
766 evas_object_image_memfile_set(o, (void*)eina_binbuf_string_get(i->buf), eina_binbuf_length_get(i->buf), NULL, NULL);
767 evas_object_image_size_get(o, &w, &h);
768 ic = e_icon_add(e_widget_preview_evas_get(prev));
769 e_icon_image_object_set(ic, o);
770 e_widget_preview_extern_object_set(prev, ic);
771 tw_show_helper(prev, w, h);
772 e_object_data_set(E_OBJECT(tw_mod->pop), eina_stringshare_ref(i->addr));
773 e_popup_object_add(tw_mod->pop, ic);
774}
775
776static void
777tw_show_local_dir(const char *uri)
778{
779 E_Action *act;
780
781 act = e_action_find("fileman");
782 if (act) act->func.go(NULL, uri);
783}
784
785static void
786tw_show_local_file(const char *uri)
787{
788 Evas_Object *o, *prev;
789 int w, h;
790
791 if (!evas_object_image_extension_can_load_get(uri)) return;
792 prev = e_widget_preview_add(e_util_comp_current_get()->evas, 50, 50);
793 o = e_icon_add(e_widget_preview_evas_get(prev));
794 e_icon_file_set(o, uri);
795 e_icon_preload_set(o, 1);
796 e_icon_size_get(o, &w, &h);
797 e_widget_preview_extern_object_set(prev, o);
798 tw_show_helper(prev, w, h);
799 e_popup_object_add(tw_mod->pop, o);
800 e_object_data_set(E_OBJECT(tw_mod->pop), eina_stringshare_add(uri));
801}
802
803EINTERN Eina_Bool
804tw_hide(void *d EINA_UNUSED)
805{
806 E_FREE_FUNC(tw_mod->pop, e_object_del);
807 last_coords.x = last_coords.y = 0;
808 E_FREE_FUNC(tw_hide_timer, ecore_timer_del);
809 download_media_cleanup();
810 return EINA_FALSE;
811}
812
813EINTERN int
814e_tw_init(void)
815{
816 char buf[PATH_MAX];
817 Eet_Data_Descriptor_Class eddc;
818
819 tw_dbus_iface = e_msgbus_interface_attach(&tw_desc);
820
821 e_user_dir_concat_static(buf, "images/cache.eet");
822 media = eet_open(buf, EET_FILE_MODE_READ_WRITE);
823 if (!media)
824 {
825 ERR("Could not open media cache file!");
826 return 0;
827 }
828
829 cache_edd = media_cache_edd_new();
830 EET_EINA_FILE_DATA_DESCRIPTOR_CLASS_SET(&eddc, Media_Cache_List);
831 cleaner_edd = eet_data_descriptor_file_new(&eddc);
832 EET_DATA_DESCRIPTOR_ADD_LIST(cleaner_edd, Media_Cache_List, "cache", cache, cache_edd);
833 tw_cache_list = eet_data_read(media, cleaner_edd, "media_cache");
834
835 e_user_dir_concat_static(buf, "images/dummies.eet");
836 dummies = eet_open(buf, EET_FILE_MODE_READ_WRITE);
837
838 E_LIST_HANDLER_APPEND(handlers, ECORE_CON_EVENT_URL_COMPLETE, download_media_complete, tw_mod);
839 E_LIST_HANDLER_APPEND(handlers, ECORE_CON_EVENT_URL_PROGRESS, download_media_status, tw_mod);
840 E_LIST_HANDLER_APPEND(handlers, ECORE_CON_EVENT_URL_DATA, download_media_data, tw_mod);
841
842 tw_mod->media = eina_hash_string_superfast_new((Eina_Free_Cb)download_media_free);
843 return 1;
844}
845
846EINTERN void
847e_tw_shutdown(void)
848{
849 E_FREE_LIST(handlers, ecore_event_handler_del);
850 if (media)
851 {
852 if (tw_cache_list)
853 {
854 Media_Cache *ic;
855 eet_data_write(media, cleaner_edd, "media_cache", tw_cache_list, 1);
856 EINA_LIST_FREE(tw_cache_list->cache, ic)
857 {
858 eina_stringshare_del(ic->sha1);
859 free(ic);
860 }
861 free(tw_cache_list);
862 }
863 E_FREE_FUNC(media, eet_close);
864 }
865 E_FREE_FUNC(tw_dbus_iface, eldbus_service_interface_unregister);
866 E_FREE_FUNC(dummies, eet_close);
867 E_FREE_FUNC(cleaner_edd, eet_data_descriptor_free);
868 E_FREE_FUNC(cache_edd, eet_data_descriptor_free);
869 tw_hide(NULL);
870 last_coords.x = last_coords.y = 0;
871 eina_hash_free(tw_mod->media);
872 E_FREE_FUNC(tw_mod->pop, e_object_del);
873}
diff --git a/src/modules/teamwork/module.desktop.in b/src/modules/teamwork/module.desktop.in
new file mode 100644
index 000000000..80e978197
--- /dev/null
+++ b/src/modules/teamwork/module.desktop.in
@@ -0,0 +1,6 @@
1[Desktop Entry]
2Type=Link
3Name=Teamwork
4Icon=e-module-teamwork
5Comment=Enlightenment Is A Team Player
6X-Enlightenment-ModuleType=core
diff --git a/src/modules/teamwork/sha1.c b/src/modules/teamwork/sha1.c
new file mode 100644
index 000000000..7a53fa712
--- /dev/null
+++ b/src/modules/teamwork/sha1.c
@@ -0,0 +1,146 @@
1/*
2 * The contents of this file are subject to the Mozilla Public
3 * License Version 1.1 (the "License"); you may not use this file
4 * except in compliance with the License. You may obtain a copy of
5 * the License at http://www.mozilla.org/MPL/
6 *
7 * Software distributed under the License is distributed on an "AS
8 * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
9 * implied. See the License for the specific language governing
10 * rights and limitations under the License.
11 *
12 * The Original Code is SHA 180-1 Reference Implementation (Compact version)
13 *
14 * The Initial Developer of the Original Code is Paul Kocher of
15 * Cryptography Research. Portions created by Paul Kocher are
16 * Copyright (C) 1995-9 by Cryptography Research, Inc. All
17 * Rights Reserved.
18 *
19 * Contributor(s):
20 *
21 * Paul Kocher
22 *
23 */
24
25#include "sha1.h"
26
27static void shaHashBlock(SHA_CTX2 *ctx);
28
29void
30SHA1_Init2(SHA_CTX2 *ctx) {
31 int i;
32
33 ctx->lenW = 0;
34 ctx->sizeHi = ctx->sizeLo = 0;
35
36 /* Initialize H with the magic constants (see FIPS180 for constants)
37 */
38 ctx->H[0] = 0x67452301;
39 ctx->H[1] = 0xefcdab89;
40 ctx->H[2] = 0x98badcfe;
41 ctx->H[3] = 0x10325476;
42 ctx->H[4] = 0xc3d2e1f0;
43
44 for (i = 0; i < 80; i++)
45 ctx->W[i] = 0;
46}
47
48void
49SHA1_Update2(SHA_CTX2 *ctx,
50 void *_dataIn,
51 int len) {
52 unsigned char *dataIn = _dataIn;
53 int i;
54
55 /* Read the data into W and process blocks as they get full
56 */
57 for (i = 0; i < len; i++) {
58 ctx->W[ctx->lenW / 4] <<= 8;
59 ctx->W[ctx->lenW / 4] |= (unsigned int)dataIn[i];
60 if ((++ctx->lenW) % 64 == 0)
61 {
62 shaHashBlock(ctx);
63 ctx->lenW = 0;
64 }
65 ctx->sizeLo += 8;
66 ctx->sizeHi += (ctx->sizeLo < 8);
67 }
68}
69
70void
71SHA1_Final2(unsigned char hashout[20],
72 SHA_CTX2 *ctx) {
73 unsigned char pad0x80 = 0x80;
74 unsigned char pad0x00 = 0x00;
75 unsigned char padlen[8];
76 int i;
77
78 /* Pad with a binary 1 (e.g. 0x80), then zeroes, then length
79 */
80 padlen[0] = (unsigned char)((ctx->sizeHi >> 24) & 255);
81 padlen[1] = (unsigned char)((ctx->sizeHi >> 16) & 255);
82 padlen[2] = (unsigned char)((ctx->sizeHi >> 8) & 255);
83 padlen[3] = (unsigned char)((ctx->sizeHi >> 0) & 255);
84 padlen[4] = (unsigned char)((ctx->sizeLo >> 24) & 255);
85 padlen[5] = (unsigned char)((ctx->sizeLo >> 16) & 255);
86 padlen[6] = (unsigned char)((ctx->sizeLo >> 8) & 255);
87 padlen[7] = (unsigned char)((ctx->sizeLo >> 0) & 255);
88 SHA1_Update2(ctx, &pad0x80, 1);
89 while (ctx->lenW != 56)
90 SHA1_Update2(ctx, &pad0x00, 1);
91 SHA1_Update2(ctx, padlen, 8);
92
93 /* Output hash
94 */
95 for (i = 0; i < 20; i++) {
96 hashout[i] = (unsigned char)(ctx->H[i / 4] >> 24);
97 ctx->H[i / 4] <<= 8;
98 }
99
100 /*
101 * Re-initialize the context (also zeroizes contents)
102 */
103 SHA1_Init2(ctx);
104}
105
106#define SHA_ROT(X, n) (((X) << (n)) | ((X) >> (32 - (n))))
107
108static void
109shaHashBlock(SHA_CTX2 *ctx) {
110 int t;
111 unsigned int A, B, C, D, E, TEMP;
112
113 for (t = 16; t <= 79; t++)
114 ctx->W[t] =
115 SHA_ROT(ctx->W[t - 3] ^ ctx->W[t - 8] ^ ctx->W[t - 14] ^ ctx->W[t - 16], 1);
116
117 A = ctx->H[0];
118 B = ctx->H[1];
119 C = ctx->H[2];
120 D = ctx->H[3];
121 E = ctx->H[4];
122
123 for (t = 0; t <= 19; t++) {
124 TEMP = SHA_ROT(A, 5) + (((C ^ D) & B) ^ D) + E + ctx->W[t] + 0x5a827999;
125 E = D; D = C; C = SHA_ROT(B, 30); B = A; A = TEMP;
126 }
127 for (t = 20; t <= 39; t++) {
128 TEMP = SHA_ROT(A, 5) + (B ^ C ^ D) + E + ctx->W[t] + 0x6ed9eba1;
129 E = D; D = C; C = SHA_ROT(B, 30); B = A; A = TEMP;
130 }
131 for (t = 40; t <= 59; t++) {
132 TEMP = SHA_ROT(A, 5) + ((B & C) | (D & (B | C))) + E + ctx->W[t] + 0x8f1bbcdc;
133 E = D; D = C; C = SHA_ROT(B, 30); B = A; A = TEMP;
134 }
135 for (t = 60; t <= 79; t++) {
136 TEMP = SHA_ROT(A, 5) + (B ^ C ^ D) + E + ctx->W[t] + 0xca62c1d6;
137 E = D; D = C; C = SHA_ROT(B, 30); B = A; A = TEMP;
138 }
139
140 ctx->H[0] += A;
141 ctx->H[1] += B;
142 ctx->H[2] += C;
143 ctx->H[3] += D;
144 ctx->H[4] += E;
145}
146
diff --git a/src/modules/teamwork/sha1.h b/src/modules/teamwork/sha1.h
new file mode 100644
index 000000000..6ab295d7e
--- /dev/null
+++ b/src/modules/teamwork/sha1.h
@@ -0,0 +1,54 @@
1/*
2 * The contents of this file are subject to the Mozilla Public
3 * License Version 1.1 (the "License"); you may not use this file
4 * except in compliance with the License. You may obtain a copy of
5 * the License at http://www.mozilla.org/MPL/
6 *
7 * Software distributed under the License is distributed on an "AS
8 * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
9 * implied. See the License for the specific language governing
10 * rights and limitations under the License.
11 *
12 * The Original Code is SHA 180-1 Header File
13 *
14 * The Initial Developer of the Original Code is Paul Kocher of
15 * Cryptography Research. Portions created by Paul Kocher are
16 * Copyright (C) 1995-9 by Cryptography Research, Inc. All
17 * Rights Reserved.
18 *
19 * Contributor(s):
20 *
21 * Paul Kocher
22 *
23 * Alternatively, the contents of this file may be used under the
24 * terms of the GNU General Public License Version 2 or later (the
25 * "GPL"), in which case the provisions of the GPL are applicable
26 * instead of those above. If you wish to allow use of your
27 * version of this file only under the terms of the GPL and not to
28 * allow others to use your version of this file under the MPL,
29 * indicate your decision by deleting the provisions above and
30 * replace them with the notice and other provisions required by
31 * the GPL. If you do not delete the provisions above, a recipient
32 * may use your version of this file under either the MPL or the
33 * GPL.
34 */
35
36#ifndef SHA_H
37#define SHA_H
38
39#ifdef HAVE_CONFIG_H
40# include "config.h"
41#endif
42
43typedef struct {
44 unsigned int H[5];
45 unsigned int W[80];
46 int lenW;
47 unsigned int sizeHi,sizeLo;
48} SHA_CTX2;
49
50void SHA1_Init2(SHA_CTX2 *ctx);
51void SHA1_Update2(SHA_CTX2 *ctx, void *dataIn, int len);
52void SHA1_Final2(unsigned char hashout[20], SHA_CTX2 *ctx);
53
54#endif