From f4a327a0ca93bc48fced863da022648c608d3021 Mon Sep 17 00:00:00 2001 From: Mike Blumenkrantz Date: Fri, 14 Jun 2013 15:36:11 +0100 Subject: [PATCH] add teamwork module see http://e18releasemanager.wordpress.com/2013/06/14/why/ for more info --- ChangeLog | 4 + INSTALL | 378 ++++++++- NEWS | 1 + configure.ac | 2 + src/bin/e_module.c | 1 + src/modules/Makefile.am | 4 + src/modules/Makefile_teamwork.am | 19 + src/modules/teamwork/e-module-teamwork.edj | Bin 0 -> 13926 bytes src/modules/teamwork/e_mod_config.c | 157 ++++ src/modules/teamwork/e_mod_main.c | 207 +++++ src/modules/teamwork/e_mod_main.h | 65 ++ src/modules/teamwork/e_mod_tw.c | 873 +++++++++++++++++++++ src/modules/teamwork/module.desktop.in | 6 + src/modules/teamwork/sha1.c | 146 ++++ src/modules/teamwork/sha1.h | 54 ++ 15 files changed, 1906 insertions(+), 11 deletions(-) create mode 100644 src/modules/Makefile_teamwork.am create mode 100644 src/modules/teamwork/e-module-teamwork.edj create mode 100644 src/modules/teamwork/e_mod_config.c create mode 100644 src/modules/teamwork/e_mod_main.c create mode 100644 src/modules/teamwork/e_mod_main.h create mode 100644 src/modules/teamwork/e_mod_tw.c create mode 100644 src/modules/teamwork/module.desktop.in create mode 100644 src/modules/teamwork/sha1.c create mode 100644 src/modules/teamwork/sha1.h diff --git a/ChangeLog b/ChangeLog index 6881acf09..3e489ea98 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,7 @@ +2013-06-14 Mike Blumenkrantz + + * add teamwork module + 2013-06-13 Mike Blumenkrantz * filemanager dnd operations now show all files when dragging diff --git a/INSTALL b/INSTALL index e55f642b7..a1e89e18a 100644 --- a/INSTALL +++ b/INSTALL @@ -1,14 +1,370 @@ -COMPILING and INSTALLING: +Installation Instructions +************************* -If you got a official release tar archive do: - ./configure - -( otherwise if you got this from enlightenment cvs do: ./autogen.sh ) - -Then to compile: - make +Copyright (C) 1994-1996, 1999-2002, 2004-2011 Free Software Foundation, +Inc. -To install (run this as root, or the user who handles installs): - make install + Copying and distribution of this file, with or without modification, +are permitted in any medium without royalty provided the copyright +notice and this notice are preserved. This file is offered as-is, +without warranty of any kind. + +Basic Installation +================== + + Briefly, the shell commands `./configure; make; make install' should +configure, build, and install this package. The following +more-detailed instructions are generic; see the `README' file for +instructions specific to this package. Some packages provide this +`INSTALL' file but do not implement all of the features documented +below. The lack of an optional feature in a given package is not +necessarily a bug. More recommendations for GNU packages can be found +in *note Makefile Conventions: (standards)Makefile Conventions. + + The `configure' shell script attempts to guess correct values for +various system-dependent variables used during compilation. It uses +those values to create a `Makefile' in each directory of the package. +It may also create one or more `.h' files containing system-dependent +definitions. Finally, it creates a shell script `config.status' that +you can run in the future to recreate the current configuration, and a +file `config.log' containing compiler output (useful mainly for +debugging `configure'). + + It can also use an optional file (typically called `config.cache' +and enabled with `--cache-file=config.cache' or simply `-C') that saves +the results of its tests to speed up reconfiguring. Caching is +disabled by default to prevent problems with accidental use of stale +cache files. + + If you need to do unusual things to compile the package, please try +to figure out how `configure' could check whether to do them, and mail +diffs or instructions to the address given in the `README' so they can +be considered for the next release. If you are using the cache, and at +some point `config.cache' contains results you don't want to keep, you +may remove or edit it. + + The file `configure.ac' (or `configure.in') is used to create +`configure' by a program called `autoconf'. You need `configure.ac' if +you want to change it or regenerate `configure' using a newer version +of `autoconf'. + + The simplest way to compile this package is: + + 1. `cd' to the directory containing the package's source code and type + `./configure' to configure the package for your system. + + Running `configure' might take a while. While running, it prints + some messages telling which features it is checking for. + + 2. Type `make' to compile the package. + + 3. Optionally, type `make check' to run any self-tests that come with + the package, generally using the just-built uninstalled binaries. + + 4. Type `make install' to install the programs and any data files and + documentation. When installing into a prefix owned by root, it is + recommended that the package be configured and built as a regular + user, and only the `make install' phase executed with root + privileges. + + 5. Optionally, type `make installcheck' to repeat any self-tests, but + this time using the binaries in their final installed location. + This target does not install anything. Running this target as a + regular user, particularly if the prior `make install' required + root privileges, verifies that the installation completed + correctly. + + 6. You can remove the program binaries and object files from the + source code directory by typing `make clean'. To also remove the + files that `configure' created (so you can compile the package for + a different kind of computer), type `make distclean'. There is + also a `make maintainer-clean' target, but that is intended mainly + for the package's developers. If you use it, you may have to get + all sorts of other programs in order to regenerate files that came + with the distribution. + + 7. Often, you can also type `make uninstall' to remove the installed + files again. In practice, not all packages have tested that + uninstallation works correctly, even though it is required by the + GNU Coding Standards. + + 8. Some packages, particularly those that use Automake, provide `make + distcheck', which can by used by developers to test that all other + targets like `make install' and `make uninstall' work correctly. + This target is generally not run by end users. + +Compilers and Options +===================== + + Some systems require unusual options for compilation or linking that +the `configure' script does not know about. Run `./configure --help' +for details on some of the pertinent environment variables. + + You can give `configure' initial values for configuration parameters +by setting variables in the command line or in the environment. Here +is an example: + + ./configure CC=c99 CFLAGS=-g LIBS=-lposix + + *Note Defining Variables::, for more details. + +Compiling For Multiple Architectures +==================================== + + You can compile the package for more than one kind of computer at the +same time, by placing the object files for each architecture in their +own directory. To do this, you can use GNU `make'. `cd' to the +directory where you want the object files and executables to go and run +the `configure' script. `configure' automatically checks for the +source code in the directory that `configure' is in and in `..'. This +is known as a "VPATH" build. + + With a non-GNU `make', it is safer to compile the package for one +architecture at a time in the source code directory. After you have +installed the package for one architecture, use `make distclean' before +reconfiguring for another architecture. + + On MacOS X 10.5 and later systems, you can create libraries and +executables that work on multiple system types--known as "fat" or +"universal" binaries--by specifying multiple `-arch' options to the +compiler but only a single `-arch' option to the preprocessor. Like +this: + + ./configure CC="gcc -arch i386 -arch x86_64 -arch ppc -arch ppc64" \ + CXX="g++ -arch i386 -arch x86_64 -arch ppc -arch ppc64" \ + CPP="gcc -E" CXXCPP="g++ -E" + + This is not guaranteed to produce working output in all cases, you +may have to build one architecture at a time and combine the results +using the `lipo' tool if you have problems. + +Installation Names +================== + + By default, `make install' installs the package's commands under +`/usr/local/bin', include files under `/usr/local/include', etc. You +can specify an installation prefix other than `/usr/local' by giving +`configure' the option `--prefix=PREFIX', where PREFIX must be an +absolute file name. + + You can specify separate installation prefixes for +architecture-specific files and architecture-independent files. If you +pass the option `--exec-prefix=PREFIX' to `configure', the package uses +PREFIX as the prefix for installing programs and libraries. +Documentation and other data files still use the regular prefix. + + In addition, if you use an unusual directory layout you can give +options like `--bindir=DIR' to specify different values for particular +kinds of files. Run `configure --help' for a list of the directories +you can set and what kinds of files go in them. In general, the +default for these options is expressed in terms of `${prefix}', so that +specifying just `--prefix' will affect all of the other directory +specifications that were not explicitly provided. + + The most portable way to affect installation locations is to pass the +correct locations to `configure'; however, many packages provide one or +both of the following shortcuts of passing variable assignments to the +`make install' command line to change installation locations without +having to reconfigure or recompile. + + The first method involves providing an override variable for each +affected directory. For example, `make install +prefix=/alternate/directory' will choose an alternate location for all +directory configuration variables that were expressed in terms of +`${prefix}'. Any directories that were specified during `configure', +but not in terms of `${prefix}', must each be overridden at install +time for the entire installation to be relocated. The approach of +makefile variable overrides for each directory variable is required by +the GNU Coding Standards, and ideally causes no recompilation. +However, some platforms have known limitations with the semantics of +shared libraries that end up requiring recompilation when using this +method, particularly noticeable in packages that use GNU Libtool. + + The second method involves providing the `DESTDIR' variable. For +example, `make install DESTDIR=/alternate/directory' will prepend +`/alternate/directory' before all installation names. The approach of +`DESTDIR' overrides is not required by the GNU Coding Standards, and +does not work on platforms that have drive letters. On the other hand, +it does better at avoiding recompilation issues, and works well even +when some directory options were not specified in terms of `${prefix}' +at `configure' time. + +Optional Features +================= + + If the package supports it, you can cause programs to be installed +with an extra prefix or suffix on their names by giving `configure' the +option `--program-prefix=PREFIX' or `--program-suffix=SUFFIX'. + + Some packages pay attention to `--enable-FEATURE' options to +`configure', where FEATURE indicates an optional part of the package. +They may also pay attention to `--with-PACKAGE' options, where PACKAGE +is something like `gnu-as' or `x' (for the X Window System). The +`README' should mention any `--enable-' and `--with-' options that the +package recognizes. + + For packages that use the X Window System, `configure' can usually +find the X include and library files automatically, but if it doesn't, +you can use the `configure' options `--x-includes=DIR' and +`--x-libraries=DIR' to specify their locations. + + Some packages offer the ability to configure how verbose the +execution of `make' will be. For these packages, running `./configure +--enable-silent-rules' sets the default to minimal output, which can be +overridden with `make V=1'; while running `./configure +--disable-silent-rules' sets the default to verbose, which can be +overridden with `make V=0'. + +Particular systems +================== + + On HP-UX, the default C compiler is not ANSI C compatible. If GNU +CC is not installed, it is recommended to use the following options in +order to use an ANSI C compiler: + + ./configure CC="cc -Ae -D_XOPEN_SOURCE=500" + +and if that doesn't work, install pre-built binaries of GCC for HP-UX. + + HP-UX `make' updates targets which have the same time stamps as +their prerequisites, which makes it generally unusable when shipped +generated files such as `configure' are involved. Use GNU `make' +instead. + + On OSF/1 a.k.a. Tru64, some versions of the default C compiler cannot +parse its `' header file. The option `-nodtk' can be used as +a workaround. If GNU CC is not installed, it is therefore recommended +to try + + ./configure CC="cc" + +and if that doesn't work, try + + ./configure CC="cc -nodtk" + + On Solaris, don't put `/usr/ucb' early in your `PATH'. This +directory contains several dysfunctional programs; working variants of +these programs are available in `/usr/bin'. So, if you need `/usr/ucb' +in your `PATH', put it _after_ `/usr/bin'. + + On Haiku, software installed for all users goes in `/boot/common', +not `/usr/local'. It is recommended to use the following options: + + ./configure --prefix=/boot/common + +Specifying the System Type +========================== + + There may be some features `configure' cannot figure out +automatically, but needs to determine by the type of machine the package +will run on. Usually, assuming the package is built to be run on the +_same_ architectures, `configure' can figure that out, but if it prints +a message saying it cannot guess the machine type, give it the +`--build=TYPE' option. TYPE can either be a short name for the system +type, such as `sun4', or a canonical name which has the form: + + CPU-COMPANY-SYSTEM + +where SYSTEM can have one of these forms: + + OS + KERNEL-OS + + See the file `config.sub' for the possible values of each field. If +`config.sub' isn't included in this package, then this package doesn't +need to know the machine type. + + If you are _building_ compiler tools for cross-compiling, you should +use the option `--target=TYPE' to select the type of system they will +produce code for. + + If you want to _use_ a cross compiler, that generates code for a +platform different from the build platform, you should specify the +"host" platform (i.e., that on which the generated programs will +eventually be run) with `--host=TYPE'. + +Sharing Defaults +================ + + If you want to set default values for `configure' scripts to share, +you can create a site shell script called `config.site' that gives +default values for variables like `CC', `cache_file', and `prefix'. +`configure' looks for `PREFIX/share/config.site' if it exists, then +`PREFIX/etc/config.site' if it exists. Or, you can set the +`CONFIG_SITE' environment variable to the location of the site script. +A warning: not all `configure' scripts look for a site script. + +Defining Variables +================== + + Variables not defined in a site shell script can be set in the +environment passed to `configure'. However, some packages may run +configure again during the build, and the customized values of these +variables may be lost. In order to avoid this problem, you should set +them in the `configure' command line, using `VAR=value'. For example: + + ./configure CC=/usr/local2/bin/gcc + +causes the specified `gcc' to be used as the C compiler (unless it is +overridden in the site shell script). + +Unfortunately, this technique does not work for `CONFIG_SHELL' due to +an Autoconf bug. Until the bug is fixed you can use this workaround: + + CONFIG_SHELL=/bin/bash /bin/bash ./configure CONFIG_SHELL=/bin/bash + +`configure' Invocation +====================== + + `configure' recognizes the following options to control how it +operates. + +`--help' +`-h' + Print a summary of all of the options to `configure', and exit. + +`--help=short' +`--help=recursive' + Print a summary of the options unique to this package's + `configure', and exit. The `short' variant lists options used + only in the top level, while the `recursive' variant lists options + also present in any nested packages. + +`--version' +`-V' + Print the version of Autoconf used to generate the `configure' + script, and exit. + +`--cache-file=FILE' + Enable the cache: use and save the results of the tests in FILE, + traditionally `config.cache'. FILE defaults to `/dev/null' to + disable caching. + +`--config-cache' +`-C' + Alias for `--cache-file=config.cache'. + +`--quiet' +`--silent' +`-q' + Do not print messages saying which checks are being made. To + suppress all normal output, redirect it to `/dev/null' (any error + messages will still be shown). + +`--srcdir=DIR' + Look for the package's source code in directory DIR. Usually + `configure' can determine that directory automatically. + +`--prefix=DIR' + Use DIR as the installation prefix. *note Installation Names:: + for more details, including other options available for fine-tuning + the installation locations. + +`--no-create' +`-n' + Run the configure checks, but stop before creating any output + files. + +`configure' also accepts some other, not widely useful, options. Run +`configure --help' for more details. -NOTE: You MUST make install Enlightenment for it to run properly. diff --git a/NEWS b/NEWS index 3c5255998..f62f9bf71 100644 --- a/NEWS +++ b/NEWS @@ -9,6 +9,7 @@ Additions: * bluez4: control bluetoothd daemon * conf_comp: configuration dialogs for composite, like in previous comp module + * teamwork API: * Added action to reset filemanager * Added function to hide all active menus diff --git a/configure.ac b/configure.ac index 2eea45ef0..d4a92411e 100644 --- a/configure.ac +++ b/configure.ac @@ -903,6 +903,7 @@ AC_E_OPTIONAL_MODULE([systray], true) AC_E_OPTIONAL_MODULE([appmenu], true) AC_E_OPTIONAL_MODULE([physics], true, [CHECK_MODULE_PHYSICS]) AC_E_OPTIONAL_MODULE([quickaccess], true) +AC_E_OPTIONAL_MODULE([teamwork], true) AC_E_OPTIONAL_MODULE([shot], true) AC_E_OPTIONAL_MODULE([backlight], true) AC_E_OPTIONAL_MODULE([tasks], true) @@ -1026,6 +1027,7 @@ src/modules/appmenu/module.desktop src/modules/conf_comp/module.desktop src/modules/physics/module.desktop src/modules/quickaccess/module.desktop +src/modules/teamwork/module.desktop src/modules/shot/module.desktop src/modules/backlight/module.desktop src/modules/tasks/module.desktop 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) "syscon", "systray", "tasks", + "teamwork", "temperature", "tiling", "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 include Makefile_quickaccess.am endif +if USE_MODULE_TEAMWORK +include Makefile_teamwork.am +endif + if USE_MODULE_SHOT include Makefile_shot.am endif 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 @@ +teamworkdir = $(MDIR)/teamwork +teamwork_DATA = teamwork/e-module-teamwork.edj \ + teamwork/module.desktop + +EXTRA_DIST += $(teamwork_DATA) + +teamworkpkgdir = $(MDIR)/teamwork/$(MODULE_ARCH) +teamworkpkg_LTLIBRARIES = teamwork/module.la + +teamwork_module_la_SOURCES = teamwork/e_mod_main.c \ + teamwork/e_mod_config.c \ + teamwork/e_mod_main.h \ + teamwork/e_mod_tw.c \ + teamwork/sha1.c \ + teamwork/sha1.h + +.PHONY: teamwork install-teamwork +teamwork: $(teamworkpkg_LTLIBRARIES) $(teamwork_DATA) +install-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 0000000000000000000000000000000000000000..a394dcb853abc3d9139deac3b1c5dc402301840d GIT binary patch literal 13926 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 = tw_config->X + SET(disable_media_fetch); + SET(allowed_media_size); + SET(allowed_media_age); + + SET(mouse_out_delay); + SET(popup_size); + SET(popup_opacity); +#undef SET + return cfdata; +} + +static void +_free_data(E_Config_Dialog *cfd EINA_UNUSED, E_Config_Dialog_Data *cfdata) +{ + tw_mod->cfd = NULL; + free(cfdata); +} + +static int +_basic_check_changed(E_Config_Dialog *cfd EINA_UNUSED, E_Config_Dialog_Data *cfdata) +{ +#define CHECK(X) \ + if (cfdata->X != tw_config->X) return 1 + + CHECK(disable_media_fetch); + if (lround(cfdata->allowed_media_age) != tw_config->allowed_media_age) return 1; + if (lround(cfdata->allowed_media_size) != tw_config->allowed_media_size) return 1; + + if (fabs(cfdata->mouse_out_delay - tw_config->allowed_media_size) > 0.45) return 1; + + if (fabs(cfdata->popup_size - tw_config->popup_size) > 0.9) return 1; + if (fabs(cfdata->popup_opacity - tw_config->popup_opacity) > 0.9) return 1; + +#undef CHECK + return 0; +} + +static Evas_Object * +_basic_create_widgets(E_Config_Dialog *cfd EINA_UNUSED, + Evas *evas, + E_Config_Dialog_Data *cfdata) +{ + Evas_Object *ob, *ol, *otb, *tab; + + tab = e_widget_table_add(evas, 0); + + otb = e_widget_toolbook_add(evas, 48 * e_scale, 48 * e_scale); + + /////////////////////////////////////////// + + ol = e_widget_list_add(evas, 0, 0); + + ob = e_widget_check_add(evas, _("Disable remote media fetching"), &cfdata->disable_media_fetch); + e_widget_list_object_append(ol, ob, 1, 0, 0.5); + + ob = e_widget_label_add(evas, _("Maximum media cache size in RAM")); + e_widget_list_object_append(ol, ob, 1, 1, 0.5); + ob = e_widget_slider_add(evas, 1, 0, _("%4.0f MiB"), 0, 1024, 16, 0, &cfdata->allowed_media_size, NULL, 150); + e_widget_list_object_append(ol, ob, 1, 1, 0.5); + ob = e_widget_label_add(evas, _("Maximum media cache age on disk")); + e_widget_list_object_append(ol, ob, 1, 1, 0.5); + ob = e_widget_slider_add(evas, 1, 0, _("%3.0f Days"), -1, 180, 1, 0, &cfdata->allowed_media_age, NULL, 150); + e_widget_list_object_append(ol, ob, 1, 1, 0.5); + + e_widget_toolbook_page_append(otb, NULL, _("Cache"), ol, 1, 1, 1, 1, 0.5, 0.5); + + /////////////////////////////////////////// + + ol = e_widget_list_add(evas, 0, 0); + + ob = e_widget_label_add(evas, _("Mouse-out hide delay")); + e_widget_list_object_append(ol, ob, 1, 1, 0.5); + ob = e_widget_slider_add(evas, 1, 0, _("%1.1f seconds"), 0, 5, 0.5, 0, &cfdata->mouse_out_delay, NULL, 150); + e_widget_list_object_append(ol, ob, 1, 1, 0.5); + ob = e_widget_label_add(evas, _("Maximum size (Percentage of screens size)")); + e_widget_list_object_append(ol, ob, 1, 1, 0.5); + ob = e_widget_slider_add(evas, 1, 0, _("%3.0f"), 10, 100, 1, 0, &cfdata->popup_size, NULL, 150); + e_widget_list_object_append(ol, ob, 1, 1, 0.5); + ob = e_widget_label_add(evas, _("Opacity")); + e_widget_list_object_append(ol, ob, 1, 1, 0.5); + ob = e_widget_slider_add(evas, 1, 0, _("%3.0f"), 10, 100, 1, 0, &cfdata->popup_opacity, NULL, 150); + e_widget_list_object_append(ol, ob, 1, 1, 0.5); + + e_widget_toolbook_page_append(otb, NULL, _("Popups"), ol, 1, 1, 1, 1, 0.5, 0.5); + + e_widget_toolbook_page_show(otb, 0); + + e_widget_table_object_append(tab, otb, 0, 0, 1, 1, 1, 1, 1, 1); + return tab; +} + + +static int +_basic_apply_data(E_Config_Dialog *cfd EINA_UNUSED, + E_Config_Dialog_Data *cfdata) +{ + +#define SET(X) tw_config->X = cfdata->X + SET(disable_media_fetch); + SET(allowed_media_size); + SET(allowed_media_age); + + SET(mouse_out_delay); + SET(popup_size); + if (fabs(cfdata->popup_opacity - tw_config->popup_opacity) > 0.9) + { + SET(popup_opacity); + tw_popup_opacity_set(); + } + + e_config_save_queue(); + return 1; +} + +EINTERN E_Config_Dialog * +e_int_config_teamwork_module(E_Container *con, const char *params EINA_UNUSED) +{ + E_Config_Dialog *cfd; + E_Config_Dialog_View *v; + char buf[4096]; + + if (tw_mod->cfd) return NULL; + snprintf(buf, sizeof(buf), "%s/e-module-teamwork.edj", e_module_dir_get(tw_mod->module)); + v = E_NEW(E_Config_Dialog_View, 1); + + v->create_cfdata = _create_data; + v->free_cfdata = _free_data; + v->basic.apply_cfdata = _basic_apply_data; + v->basic.create_widgets = _basic_create_widgets; + v->basic.check_changed = _basic_check_changed; + + cfd = e_config_dialog_new(con, _("Teamwork Settings"), + "E", "applications/teamwork", buf, 32, v, tw_mod); + tw_mod->cfd = cfd; + return cfd; +} 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 @@ +#include "e_mod_main.h" +#include "sha1.h" + +EINTERN int _e_teamwork_log_dom = -1; +EINTERN Mod *tw_mod = NULL; +EINTERN Teamwork_Config *tw_config = NULL; + +EAPI E_Module_Api e_modapi = {E_MODULE_API_VERSION, "Teamwork"}; + +static E_Config_DD *conf_edd = NULL; + +static E_Action *e_tw_toggle = NULL; +static const char _act_toggle[] = "tw_toggle"; +static const char _e_tw_name[] = N_("Teamwork"); +static const char _lbl_toggle[] = N_("Toggle Popup Visibility"); + +static const char * +_sha1_to_string(const unsigned char *hashout) +{ + const char hextab[] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' }; + char sha1[41] = {0}; + unsigned int i = 0; + + for (i = 0; i < 20; i++) + { + sha1[2 * i] = hextab[(hashout[i] >> 4) & 0x0f]; + sha1[2 * i + 1] = hextab[hashout[i] & 0x0f]; + } + return eina_stringshare_add(sha1); +} + +const char * +sha1_encode(const unsigned char *data, size_t len) +{ + SHA_CTX2 ctx; + unsigned char hashout[20]; + unsigned char *buf; + + if (EINA_UNLIKELY(len > 65000)) + buf = malloc(len); + else + buf = alloca(len); + EINA_SAFETY_ON_NULL_RETURN_VAL(buf, NULL); + memcpy(buf, data, len); + + SHA1_Init2(&ctx); + SHA1_Update2(&ctx, buf, len); + SHA1_Final2(hashout, &ctx); + if (EINA_UNLIKELY(len > 65000)) free(buf); + return _sha1_to_string(hashout); +} + +////////////////////////////// +static Teamwork_Config * +e_tw_config_new(void) +{ + Teamwork_Config *cf; + + cf = E_NEW(Teamwork_Config, 1); + cf->config_version = MOD_CONFIG_FILE_VERSION; + + cf->allowed_media_size = 10; // 10 megabytes + cf->allowed_media_age = 3; // 3 days + + cf->mouse_out_delay = 0.0; + cf->popup_size = 10.0; + cf->popup_opacity = 90.0; + + return cf; +} + +static E_Config_DD * +e_tw_config_dd_new(void) +{ + conf_edd = E_CONFIG_DD_NEW("Teamwork_Config", Teamwork_Config); + +#undef T +#undef D +#define T Teamwork_Config +#define D conf_edd + E_CONFIG_VAL(D, T, config_version, UINT); + E_CONFIG_VAL(D, T, disable_media_fetch, UCHAR); + E_CONFIG_VAL(D, T, allowed_media_size, LL); + E_CONFIG_VAL(D, T, allowed_media_age, INT); + + E_CONFIG_VAL(D, T, mouse_out_delay, DOUBLE); + E_CONFIG_VAL(D, T, popup_size, DOUBLE); + E_CONFIG_VAL(D, T, popup_opacity, DOUBLE); + return conf_edd; +} +////////////////////////////// +static void +e_tw_act_toggle_cb(E_Object *obj EINA_UNUSED, const char *params EINA_UNUSED) +{ + if (!tw_mod->pop) return; + if (tw_mod->sticky) + tw_hide(NULL); + tw_mod->sticky = !tw_mod->sticky; +} +////////////////////////////// +EAPI void * +e_modapi_init(E_Module *m) +{ + char buf[PATH_MAX]; + E_Configure_Option *co; + + snprintf(buf, sizeof(buf), "%s/e-module-teamwork.edj", e_module_dir_get(m)); + e_configure_registry_category_add("applications", 20, _("Apps"), NULL, + "preferences-applications"); + e_configure_registry_item_add("applications/teamwork", 1, _("Teamwork"), NULL, + buf, e_int_config_teamwork_module); + + tw_mod = E_NEW(Mod, 1); + tw_mod->module = m; + m->data = tw_mod; + conf_edd = e_tw_config_dd_new(); + tw_config = e_config_domain_load("module.teamwork", conf_edd); + if (tw_config) + { + if (!e_util_module_config_check(_("Teamwork"), tw_config->config_version, MOD_CONFIG_FILE_VERSION)) + E_FREE_FUNC(tw_config, free); + } + + if (tw_config) + { + /* sanity checks */ + tw_config->mouse_out_delay = E_CLAMP(tw_config->mouse_out_delay, 0.0, 5.0); + tw_config->popup_size = E_CLAMP(tw_config->popup_size, 10.0, 100.0); + tw_config->popup_opacity = E_CLAMP(tw_config->popup_opacity, 10.0, 100.0); + } + else + tw_config = e_tw_config_new(); + tw_config->config_version = MOD_CONFIG_FILE_VERSION; + + _e_teamwork_log_dom = eina_log_domain_register("teamwork", EINA_COLOR_ORANGE); + eina_log_domain_level_set("teamwork", EINA_LOG_LEVEL_DBG); + + if (!e_tw_init()) + { + e_modapi_shutdown(NULL); + return NULL; + } + e_tw_toggle = e_action_add(_act_toggle); + e_tw_toggle->func.go = e_tw_act_toggle_cb; + e_action_predef_name_set(_e_tw_name, _lbl_toggle, _act_toggle, NULL, NULL, 0); + + e_configure_option_domain_current_set("teamwork"); + + E_CONFIGURE_OPTION_ADD_CUSTOM(co, "teamwork-settings", _("Teamwork settings panel"), _("teamwork"), _("applications")); + co->info = eina_stringshare_add("applications/teamwork"); + E_CONFIGURE_OPTION_ICON(co, buf); + E_CONFIGURE_OPTION_ADD(co, BOOL, disable_media_fetch, tw_config, _("Disable Teamwork remote media fetching"), _("teamwork")); + E_CONFIGURE_OPTION_ADD(co, DOUBLE, allowed_media_size, tw_config, _("Maximum total size of Teamwork media to keep in RAM"), _("teamwork"), _("cache")); + E_CONFIGURE_OPTION_MINMAX_STEP_FMT(co, 0, 1024, 16, _("%4.0f MiB")); + E_CONFIGURE_OPTION_HELP(co, _("This option determines how much memory will be used to cache recent media for faster loading.")); + E_CONFIGURE_OPTION_ADD(co, DOUBLE, allowed_media_age, tw_config, _("Maximum age for a disk-cached Teamwork media item"), _("teamwork"), _("cache")); + E_CONFIGURE_OPTION_MINMAX_STEP_FMT(co, -1, 180, 1, _("%3.0f Days")); + E_CONFIGURE_OPTION_HELP(co, _("This option determines how long media will remain in the disk cache before it is pruned." + "Set to -1 to never delete media, or to 0 to never cache media on disk.")); + + E_CONFIGURE_OPTION_ADD(co, DOUBLE, mouse_out_delay, tw_config, _("Delay before closing a Teamwork popup on mouse-out"), _("teamwork"), _("mouse")); + E_CONFIGURE_OPTION_MINMAX_STEP_FMT(co, 0, 5, 0.5, _("%1.1f seconds")); + E_CONFIGURE_OPTION_ADD(co, DOUBLE, popup_size, tw_config, _("Maximum percentage of screen to use for Teamwork popups"), _("teamwork"), _("screen")); + E_CONFIGURE_OPTION_MINMAX_STEP_FMT(co, 10, 100, 1, _("%3.0f")); + E_CONFIGURE_OPTION_ADD(co, DOUBLE, popup_opacity, tw_config, _("Opacity to use for Teamwork popups"), _("teamwork")); + E_CONFIGURE_OPTION_MINMAX_STEP_FMT(co, 10, 100, 1, _("%3.0f")); + co->funcs[0].none = tw_popup_opacity_set; + + e_configure_option_category_tag_add(_("applications"), _("teamwork")); + e_configure_option_category_tag_add(_("teamwork"), _("teamwork")); + e_configure_option_category_icon_set(_("teamwork"), buf); + + return m; +} + +EAPI int +e_modapi_shutdown(E_Module *m __UNUSED__) +{ + e_tw_shutdown(); + + E_CONFIG_DD_FREE(conf_edd); + eina_log_domain_unregister(_e_teamwork_log_dom); + _e_teamwork_log_dom = -1; + + e_configure_registry_item_del("applications/teamwork"); + e_configure_registry_category_del("applications"); + + e_configure_option_domain_clear("teamwork"); + e_configure_option_category_tag_del(_("teamwork"), _("teamwork")); + e_configure_option_category_tag_del(_("applications"), _("teamwork")); + + e_action_predef_name_del(_e_tw_name, _lbl_toggle); + e_action_del(_act_toggle); + e_tw_toggle = NULL; + + E_FREE(tw_config); + E_FREE(tw_mod); + return 1; +} + +EAPI int +e_modapi_save(E_Module *m __UNUSED__) +{ + e_config_domain_save("module.teamwork", conf_edd, tw_config); + return 1; +} + 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 @@ +#ifndef E_MOD_MAIN_H +#define E_MOD_MAIN_H + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "e.h" + +/* Increment for Major Changes */ +#define MOD_CONFIG_FILE_EPOCH 1 +/* Increment for Minor Changes (ie: user doesn't need a new config) */ +#define MOD_CONFIG_FILE_GENERATION 0 +#define MOD_CONFIG_FILE_VERSION ((MOD_CONFIG_FILE_EPOCH * 1000000) + MOD_CONFIG_FILE_GENERATION) + +typedef struct Teamwork_Config +{ + unsigned int config_version; + + Eina_Bool disable_media_fetch; + long long int allowed_media_size; + int allowed_media_age; + + double mouse_out_delay; + double popup_size; + double popup_opacity; +} Teamwork_Config; + +typedef struct Mod +{ + E_Module *module; + E_Config_Dialog *cfd; + size_t media_size; + Eina_Inlist *media_list; + Eina_Hash *media; + E_Popup *pop; + Eina_Bool sticky : 1; +} Mod; + +extern Teamwork_Config *tw_config; +extern Mod *tw_mod; +extern int _e_teamwork_log_dom; + +EINTERN const char *sha1_encode(const unsigned char *data, size_t len); + +EINTERN int e_tw_init(void); +EINTERN void e_tw_shutdown(void); +EINTERN Eina_Bool tw_hide(void *d EINA_UNUSED); +EINTERN void tw_popup_opacity_set(void); + +EINTERN E_Config_Dialog *e_int_config_teamwork_module(E_Container *con, const char *params EINA_UNUSED); + +EAPI int e_modapi_shutdown(E_Module *m __UNUSED__); +#undef DBG +#undef INF +#undef WRN +#undef ERR +#undef CRIT +#define DBG(...) EINA_LOG_DOM_DBG(_e_teamwork_log_dom, __VA_ARGS__) +#define INF(...) EINA_LOG_DOM_INFO(_e_teamwork_log_dom, __VA_ARGS__) +#define WRN(...) EINA_LOG_DOM_WARN(_e_teamwork_log_dom, __VA_ARGS__) +#define ERR(...) EINA_LOG_DOM_ERR(_e_teamwork_log_dom, __VA_ARGS__) +#define CRIT(...) EINA_LOG_DOM_CRIT(_e_teamwork_log_dom, __VA_ARGS__) + +#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 @@ +#include "e_mod_main.h" + +#define IMAGE_FETCH_TRIES 5 + +typedef struct +{ + const char *sha1; + unsigned long long timestamp; +} Media_Cache; + +typedef struct Media_Cache_List +{ + Eina_List *cache; +} Media_Cache_List; + +typedef struct Media +{ + EINA_INLIST; + Ecore_Con_Url *client; + Eina_Binbuf *buf; + const char *addr; + unsigned long long timestamp; + unsigned int tries; + Eina_Bool dummy : 1; + Eina_Bool valid : 1; + Eina_Bool show : 1; +} Media; + +static Eet_File *media = NULL; +static Eet_File *dummies = NULL; +static Eet_Data_Descriptor *cleaner_edd = NULL; +static Eet_Data_Descriptor *cache_edd = NULL; +static Ecore_Idler *media_cleaner = NULL; +static Eina_List *handlers = NULL; +static Media_Cache_List *tw_cache_list = NULL; + +static Evas_Point last_coords = {0}; + +static Ecore_Timer *tw_hide_timer = NULL; + +static Eldbus_Service_Interface *tw_dbus_iface = NULL; + +typedef enum +{ + TEAMWORK_LINK_TYPE_NONE, + TEAMWORK_LINK_TYPE_LOCAL_FILE, + TEAMWORK_LINK_TYPE_LOCAL_DIRECTORY, + TEAMWORK_LINK_TYPE_REMOTE +} Teamwork_Link_Type; + +typedef enum +{ + TEAMWORK_SIGNAL_LINK_DOWNLOADING, + TEAMWORK_SIGNAL_LINK_PROGRESS, + TEAMWORK_SIGNAL_LINK_COMPLETE, + TEAMWORK_SIGNAL_LINK_INVALID, +} Teamwork_Signal; + +static const Eldbus_Signal tw_signals[] = +{ + [TEAMWORK_SIGNAL_LINK_DOWNLOADING] = {"LinkDownloading", ELDBUS_ARGS({"s", "URI"}, {"u", "Timestamp"}), 0}, + [TEAMWORK_SIGNAL_LINK_PROGRESS] = {"LinkProgress", ELDBUS_ARGS({"s", "URI"}, {"u", "Timestamp"}, {"d", "Percent Completion"}), 0}, + [TEAMWORK_SIGNAL_LINK_COMPLETE] = {"LinkComplete", ELDBUS_ARGS({"s", "URI"}, {"u", "Timestamp"}), 0}, + [TEAMWORK_SIGNAL_LINK_INVALID] = {"LinkInvalid", ELDBUS_ARGS({"s", "URI"}, {"u", "Timestamp"}), 0}, + {} +}; + +static void tw_show(Media *i); +static void tw_show_local_file(const char *uri); +static void tw_show_local_dir(const char *uri); +static int tw_media_add(const char *url, Eina_Binbuf *buf, unsigned long long timestamp); +static void download_media_cleanup(void); +static void tw_dummy_add(const char *url); +static Eina_Bool tw_dummy_check(const char *url); +static void tw_media_ping(const char *url, unsigned long long timestamp); +static Eina_Binbuf *tw_media_get(const char *url, unsigned long long timestamp); +static Eina_Bool tw_idler_start(void); + +static void +dbus_signal_link_complete(Media *i) +{ + unsigned int u = ecore_time_unix_get(); + if (i->show) tw_show(i); + i->show = 0; + eldbus_service_signal_emit(tw_dbus_iface, TEAMWORK_SIGNAL_LINK_COMPLETE, i->addr, u); +} + +static void +dbus_signal_link_invalid(Media *i) +{ + unsigned int u = ecore_time_unix_get(); + eldbus_service_signal_emit(tw_dbus_iface, TEAMWORK_SIGNAL_LINK_INVALID, i->addr, u); +} + +static void +dbus_signal_link_progress(Media *i, double pr) +{ + unsigned int u = ecore_time_unix_get(); + eldbus_service_signal_emit(tw_dbus_iface, TEAMWORK_SIGNAL_LINK_PROGRESS, i->addr, u, pr); +} + +static void +dbus_signal_link_downloading(Media *i) +{ + unsigned int u = ecore_time_unix_get(); + eldbus_service_signal_emit(tw_dbus_iface, TEAMWORK_SIGNAL_LINK_DOWNLOADING, i->addr, u); +} + +static Eina_Bool +download_media_complete(void *data, int type EINA_UNUSED, Ecore_Con_Event_Url_Complete *ev) +{ + Media *i; + + if (data != tw_mod) return ECORE_CALLBACK_RENEW; + i = ecore_con_url_data_get(ev->url_con); + if (!i) return ECORE_CALLBACK_RENEW; + if (!i->valid) return ECORE_CALLBACK_RENEW; + i->timestamp = (unsigned long long)ecore_time_unix_get(); + if (tw_media_add(i->addr, i->buf, i->timestamp) == 1) + tw_mod->media_size += eina_binbuf_length_get(i->buf); + E_FREE_FUNC(i->client, ecore_con_url_free); + dbus_signal_link_complete(i); + download_media_cleanup(); + INF("MEDIA CACHE: %zu bytes", tw_mod->media_size); + return ECORE_CALLBACK_RENEW; +} + +static Eina_Bool +download_media_data(void *data, int type EINA_UNUSED, Ecore_Con_Event_Url_Data *ev) +{ + Media *i; + + if (data != tw_mod) return ECORE_CALLBACK_RENEW; + i = ecore_con_url_data_get(ev->url_con); + if (!i) return ECORE_CALLBACK_RENEW; + if (i->dummy) return ECORE_CALLBACK_RENEW; + if (!i->buf) i->buf = eina_binbuf_new(); + eina_binbuf_append_length(i->buf, ev->data, ev->size); + return ECORE_CALLBACK_RENEW; +} + +static Eina_Bool +download_media_status(void *data, int type EINA_UNUSED, Ecore_Con_Event_Url_Progress *ev) +{ + int status; + const char *h; + Media *i; + const Eina_List *l; + + if (data != tw_mod) return ECORE_CALLBACK_RENEW; + i = ecore_con_url_data_get(ev->url_con); + if (!i) return ECORE_CALLBACK_RENEW; + + if (i->valid) return ECORE_CALLBACK_RENEW; //already checked + status = ecore_con_url_status_code_get(ev->url_con); + if (!status) return ECORE_CALLBACK_RENEW; //not ready yet + DBG("%i code for media: %s", status, i->addr); + if (status != 200) + { + E_FREE_FUNC(i->buf, eina_binbuf_free); + E_FREE_FUNC(i->client, ecore_con_url_free); + if ((status >= 400) || (status <= 300)) goto dummy; + if (++i->tries < IMAGE_FETCH_TRIES) + { + i->client = ecore_con_url_new(i->addr); + ecore_con_url_data_set(i->client, i); + if (!ecore_con_url_get(i->client)) goto dummy; + } + return ECORE_CALLBACK_RENEW; + } + EINA_LIST_FOREACH(ecore_con_url_response_headers_get(ev->url_con), l, h) + { + if (strncasecmp(h, "Content-Type: ", sizeof("Content-Type: ") - 1)) continue; + if (strncasecmp(h + sizeof("Content-Type: ") - 1, "image/", 6)) goto dummy; + } + i->valid = !i->dummy; + if (i->valid) dbus_signal_link_progress(i, ev->down.now / ev->down.total); + + return ECORE_CALLBACK_RENEW; +dummy: + dbus_signal_link_invalid(i); + tw_dummy_add(i->addr); + i->dummy = EINA_TRUE; + E_FREE_FUNC(i->buf, eina_binbuf_free); + E_FREE_FUNC(i->client, ecore_con_url_free); + return ECORE_CALLBACK_RENEW; +} + +static int +download_media_sort_cb(Media *a, Media *b) +{ + long long diff; + diff = a->timestamp - b->timestamp; + if (diff < 0) return -1; + if (!diff) return 0; + return 1; +} + +static Media * +download_media_add(const char *url) +{ + Media *i; + unsigned long long t; + + t = (unsigned long long)ecore_time_unix_get(); + + i = eina_hash_find(tw_mod->media, url); + if (i) + { + if (i->buf) + { + i->timestamp = t; + tw_media_ping(url, i->timestamp); + } + else + { + /* randomly deleted during cache pruning */ + i->buf = tw_media_get(url, t); + tw_mod->media_size += eina_binbuf_length_get(i->buf); + } + tw_mod->media_list = eina_inlist_promote(tw_mod->media_list, EINA_INLIST_GET(i)); + download_media_cleanup(); + return i; + } + if (tw_dummy_check(url)) return NULL; + if (tw_config->disable_media_fetch) return NULL; + i = calloc(1, sizeof(Media)); + i->addr = eina_stringshare_add(url); + i->buf = tw_media_get(url, t); + if (i->buf) + tw_mod->media_size += eina_binbuf_length_get(i->buf); + else + { + i->client = ecore_con_url_new(url); + ecore_con_url_data_set(i->client, i); + ecore_con_url_get(i->client); + dbus_signal_link_downloading(i); + } + eina_hash_direct_add(tw_mod->media, url, i); + tw_mod->media_list = eina_inlist_sorted_insert(tw_mod->media_list, EINA_INLIST_GET(i), (Eina_Compare_Cb)download_media_sort_cb); + return i; +} + +static void +download_media_free(Media *i) +{ + if (!i) return; + tw_mod->media_list = eina_inlist_remove(tw_mod->media_list, EINA_INLIST_GET(i)); + if (i->client) ecore_con_url_free(i->client); + if (i->buf) eina_binbuf_free(i->buf); + eina_stringshare_del(i->addr); + free(i); +} + +static void +download_media_cleanup(void) +{ + Media *i; + Eina_Inlist *l; + + if (tw_config->allowed_media_age) + { + if (tw_config->allowed_media_size < 0) return; + if ((size_t)tw_config->allowed_media_size > (tw_mod->media_size / 1024 / 1024)) return; + } + if (!tw_mod->media_list) return; + l = tw_mod->media_list->last; + while (l) + { + i = EINA_INLIST_CONTAINER_GET(l, Media); + l = l->prev; + if (!i->buf) continue; + /* only free the buffers here where possible to avoid having to deal with multiple list entries */ + if (tw_mod->media_size && (tw_mod->media_size >= eina_binbuf_length_get(i->buf))) + tw_mod->media_size -= eina_binbuf_length_get(i->buf); + E_FREE_FUNC(i->buf, eina_binbuf_free); + if (!tw_config->allowed_media_age) + /* if caching is disabled, just delete */ + eina_hash_del_by_key(tw_mod->media, i->addr); + if ((size_t)tw_config->allowed_media_size > (tw_mod->media_size / 1024 / 1024)) + break; + } +} + +static Teamwork_Link_Type +dbus_link_uri_local_type_get(const char *uri) +{ + size_t len = strlen(uri); + + if (uri[len - 1] == '/') return TEAMWORK_LINK_TYPE_LOCAL_DIRECTORY; + return TEAMWORK_LINK_TYPE_LOCAL_FILE; +} + +static Teamwork_Link_Type +dbus_link_uri_type_get(const char *uri) +{ + if (!uri[0]) return TEAMWORK_LINK_TYPE_NONE; //invalid + if (uri[0] == '/') return dbus_link_uri_local_type_get(uri + 1); //probably a file? + if ((!strncasecmp(uri, "http://", 7)) || (!strncasecmp(uri, "https://", 8))) return TEAMWORK_LINK_TYPE_REMOTE; + if (!strncmp(uri, "file://", 7)) return dbus_link_uri_local_type_get(uri + 7); + WRN("Unknown link type for '%s'", uri); + return TEAMWORK_LINK_TYPE_NONE; +} + +static Eldbus_Message * +dbus_link_detect_cb(const Eldbus_Service_Interface *iface EINA_UNUSED, const Eldbus_Message *msg) +{ + const char *uri; + unsigned int t; + + if (!tw_config->allowed_media_age) goto out; + if (!eldbus_message_arguments_get(msg, "su", &uri, &t)) goto out; + + if (dbus_link_uri_type_get(uri) == TEAMWORK_LINK_TYPE_REMOTE) + download_media_add(uri); +out: + return eldbus_message_method_return_new(msg); +} + +static void +dbus_link_show_helper(const char *uri, Eina_Bool signal_open) +{ + Teamwork_Link_Type type; + + if (tw_mod->pop && (!e_util_strcmp(e_object_data_get(E_OBJECT(tw_mod->pop)), uri))) return; + type = dbus_link_uri_type_get(uri); + switch (type) + { + case TEAMWORK_LINK_TYPE_NONE: break; + case TEAMWORK_LINK_TYPE_LOCAL_DIRECTORY: + if (signal_open) tw_show_local_dir(uri); + break; + case TEAMWORK_LINK_TYPE_LOCAL_FILE: + tw_show_local_file(uri); + break; + case TEAMWORK_LINK_TYPE_REMOTE: + { + Media *i; + + i = eina_hash_find(tw_mod->media, uri); + if (!i) + { + if (tw_dummy_check(uri)) break; + i = download_media_add(uri); + if (i) + { + if (i->buf) tw_show(i); + else if (i->dummy) break; + else i->show = 1; + } + } + else if (!i->dummy) tw_show(i); + break; + } + } +} + +static Eldbus_Message * +dbus_link_show_cb(const Eldbus_Service_Interface *iface EINA_UNUSED, const Eldbus_Message *msg) +{ + const char *uri; + + if (eldbus_message_arguments_get(msg, "s", &uri)) + { + last_coords.x = last_coords.y = -1; + dbus_link_show_helper(uri, 1); + } + return eldbus_message_method_return_new(msg); +} + +static Eldbus_Message * +dbus_link_hide_cb(const Eldbus_Service_Interface *iface EINA_UNUSED, const Eldbus_Message *msg) +{ + const char *uri; + + if (eldbus_message_arguments_get(msg, "s", &uri)) + { + if (tw_mod->pop && (!tw_mod->sticky) && (!e_util_strcmp(e_object_data_get(E_OBJECT(tw_mod->pop)), uri))) + tw_hide(NULL); + } + return eldbus_message_method_return_new(msg); +} + +static Eldbus_Message * +dbus_link_mouse_in_cb(const Eldbus_Service_Interface *iface EINA_UNUSED, const Eldbus_Message *msg) +{ + const char *uri; + unsigned int t; + + if (eldbus_message_arguments_get(msg, "suii", &uri, &t, &last_coords.x, &last_coords.y)) + dbus_link_show_helper(uri, 0); + return eldbus_message_method_return_new(msg); +} + +static Eldbus_Message * +dbus_link_mouse_out_cb(const Eldbus_Service_Interface *iface EINA_UNUSED, const Eldbus_Message *msg) +{ + const char *uri; + unsigned int t; + + if (eldbus_message_arguments_get(msg, "suii", &uri, &t, &last_coords.x, &last_coords.y)) + { + if (tw_mod->pop && (!tw_mod->sticky) && (!e_util_strcmp(e_object_data_get(E_OBJECT(tw_mod->pop)), uri))) + { + if (tw_config->mouse_out_delay) + { + if (tw_hide_timer) ecore_timer_reset(tw_hide_timer); + else tw_hide_timer = ecore_timer_add(tw_config->mouse_out_delay, tw_hide, NULL); + } + else + tw_hide(NULL); + } + } + return eldbus_message_method_return_new(msg); +} + +static Eldbus_Message * +dbus_link_open_cb(const Eldbus_Service_Interface *iface EINA_UNUSED, const Eldbus_Message *msg) +{ + const char *uri; + + if (eldbus_message_arguments_get(msg, "s", &uri)) + { + char *sb; + size_t size = 4096, len = sizeof(E_BINDIR "/enlightenment_open ") - 1; + + sb = malloc(size); + memcpy(sb, E_BINDIR "/enlightenment_open ", len); + sb = e_util_string_append_quoted(sb, &size, &len, uri); + ecore_exe_run(sb, NULL); + free(sb); + } + return eldbus_message_method_return_new(msg); +} + + +static const Eldbus_Method tw_methods[] = { + { "LinkDetect", ELDBUS_ARGS({"s", "URI"}, {"u", "Timestamp"}), NULL, dbus_link_detect_cb }, + { "LinkMouseIn", ELDBUS_ARGS({"s", "URI"}, {"u", "Timestamp"}, {"i", "X Coordinate"}, {"i", "Y Coordinate"}), NULL, dbus_link_mouse_in_cb }, + { "LinkMouseOut", ELDBUS_ARGS({"s", "URI"}, {"u", "Timestamp"}, {"i", "X Coordinate"}, {"i", "Y Coordinate"}), NULL, dbus_link_mouse_out_cb }, + { "LinkShow", ELDBUS_ARGS({"s", "URI"}), NULL, dbus_link_show_cb }, + { "LinkHide", ELDBUS_ARGS({"s", "URI"}), NULL, dbus_link_hide_cb }, + { "LinkOpen", ELDBUS_ARGS({"s", "URI"}), NULL, dbus_link_open_cb }, + { } +}; + +static const Eldbus_Service_Interface_Desc tw_desc = +{ + "org.enlightenment.wm.Teamwork", tw_methods, tw_signals +}; + +static Eet_Data_Descriptor * +media_cache_edd_new(void) +{ + Eet_Data_Descriptor *edd; + Eet_Data_Descriptor_Class eddc; + EET_EINA_FILE_DATA_DESCRIPTOR_CLASS_SET(&eddc, Media_Cache); + edd = eet_data_descriptor_stream_new(&eddc); +#define ADD(name, type) \ + EET_DATA_DESCRIPTOR_ADD_BASIC(edd, Media_Cache, #name, name, EET_T_##type) + + ADD(sha1, INLINED_STRING); + ADD(timestamp, ULONG_LONG); +#undef ADD + return edd; +} + +static int +media_cache_compare(Media_Cache *a, Media_Cache *b) +{ + long long diff; + diff = a->timestamp - b->timestamp; + if (diff < 0) return -1; + if (!diff) return 0; + return 1; +} + +static void +media_cache_add(const char *sha1, unsigned long long timestamp) +{ + Media_Cache *ic; + if (!tw_cache_list) return; + ic = malloc(sizeof(Media_Cache)); + ic->sha1 = eina_stringshare_ref(sha1); + ic->timestamp = timestamp; + tw_cache_list->cache = eina_list_sorted_insert(tw_cache_list->cache, (Eina_Compare_Cb)media_cache_compare, ic); +} + +static void +media_cache_del(const char *sha1) +{ + Eina_List *l, *l2; + Media_Cache *ic; + + if (!tw_cache_list) return; + EINA_LIST_FOREACH_SAFE(tw_cache_list->cache, l, l2, ic) + { + if (ic->sha1 == sha1) continue; + tw_cache_list->cache = eina_list_remove_list(tw_cache_list->cache, l); + return; + } +} + +static void +media_cache_update(const char *sha1, unsigned long long timestamp) +{ + Media_Cache *ic; + Eina_List *l; + + if (!tw_cache_list) return; + EINA_LIST_FOREACH(tw_cache_list->cache, l, ic) + { + if (ic->sha1 != sha1) continue; + ic->timestamp = timestamp; + break; + } + tw_cache_list->cache = eina_list_sort(tw_cache_list->cache, eina_list_count(tw_cache_list->cache), (Eina_Compare_Cb)media_cache_compare); +} + +static Eina_Bool +media_cleaner_cb(void *data EINA_UNUSED) +{ + unsigned long long now; + Media_Cache *ic; + Eina_List *l, *l2; + int cleaned = 0; + if ((!cleaner_edd) || (!cache_edd) || (tw_config->allowed_media_age < 0) || (!tw_cache_list) || (!tw_cache_list->cache)) + { + media_cleaner = NULL; + return EINA_FALSE; + } + + if (tw_config->allowed_media_age) + { + now = (unsigned long long)ecore_time_unix_get(); + now -= tw_config->allowed_media_age * 24 * 60 * 60; + } + else + now = ULONG_LONG_MAX; + EINA_LIST_FOREACH_SAFE(tw_cache_list->cache, l, l2, ic) + { + /* only clean up to 3 entries at a time to ensure responsiveness */ + if (cleaned >= 3) break; + if (ic->timestamp >= now) + { + /* stop the idler for now to avoid pointless spinning */ + ecore_timer_add(24 * 60 * 60, (Ecore_Task_Cb)tw_idler_start, NULL); + media_cleaner = NULL; + return EINA_FALSE; + } + eet_delete(media, ic->sha1); + tw_cache_list->cache = eina_list_remove_list(tw_cache_list->cache, l); + eina_stringshare_del(ic->sha1); + free(ic); + cleaned++; + } + return EINA_TRUE; +} + +static void +tw_dummy_add(const char *url) +{ + if (!dummies) return; + eet_write(dummies, url, "0", 1, 0); + INF("Added new dummy for url %s", url); +} + +static Eina_Bool +tw_dummy_check(const char *url) +{ + char **list; + int lsize; + + if (!dummies) return EINA_FALSE; + list = eet_list(dummies, url, &lsize); + if (lsize) + { + free(list); + return EINA_TRUE; + } + return EINA_FALSE; +} + +static int +tw_media_add(const char *url, Eina_Binbuf *buf, unsigned long long timestamp) +{ + const char *sha1; + int lsize; + char **list; + + if (!media) return -1; + if (!tw_config->allowed_media_age) return 0; //disk caching disabled + + sha1 = sha1_encode(eina_binbuf_string_get(buf), eina_binbuf_length_get(buf)); + INF("Media: %s - %s", url, sha1); + + list = eet_list(media, url, &lsize); + if (lsize) + { + eina_stringshare_del(sha1); + free(list); + return -1; /* should never happen */ + } + list = eet_list(media, sha1, &lsize); + if (lsize) + { + eet_alias(media, url, sha1, 0); + eet_sync(media); + INF("Added new alias for image %s", sha1); + eina_stringshare_del(sha1); + free(list); + return 0; + } + + eet_write(media, sha1, eina_binbuf_string_get(buf), eina_binbuf_length_get(buf), 1); + eet_alias(media, url, sha1, 0); + eet_sync(media); + media_cache_add(sha1, timestamp); + INF("Added new media with length %zu: %s", eina_binbuf_length_get(buf), sha1); + eina_stringshare_del(sha1); + return 1; +} + +void +tw_media_del(const char *url) +{ + const char *alias; + if (!media) return; + alias = eet_alias_get(media, url); + eet_delete(media, alias); + media_cache_del(alias); + eina_stringshare_del(alias); +} + +static Eina_Binbuf * +tw_media_get(const char *url, unsigned long long timestamp) +{ + size_t size; + unsigned char *img; + Eina_Binbuf *buf = NULL; + const char *alias; + char **list; + int lsize; + + if (!media) return NULL; + + list = eet_list(media, url, &lsize); + if (!lsize) return NULL; + free(list); + + img = eet_read(media, url, (int*)&size); + alias = eet_alias_get(media, url); + buf = eina_binbuf_manage_new_length(img, size); + media_cache_update(alias, timestamp); + + eina_stringshare_del(alias); + return buf; +} + +static void +tw_media_ping(const char *url, unsigned long long timestamp) +{ + const char *alias; + + if (!media) return; + + alias = eet_alias_get(media, url); + media_cache_update(alias, timestamp); + + eina_stringshare_del(alias); +} + +static Eina_Bool +tw_idler_start(void) +{ + if (!media) return EINA_FALSE; + media_cleaner = ecore_idler_add((Ecore_Task_Cb)media_cleaner_cb, NULL); + return EINA_FALSE; +} + +static void +tw_popup_del(void *obj) +{ + eina_stringshare_del(e_object_data_get(obj)); +} + +EINTERN void +tw_popup_opacity_set(void) +{ + if (tw_mod->pop && tw_mod->pop->cw) + e_comp_win_opacity_set(tw_mod->pop->cw, lround((double)255 * (tw_config->popup_opacity / 100.))); +} + +static void +tw_show_helper(Evas_Object *o, int w, int h) +{ + int px, py, pw, ph; + double ratio = tw_config->popup_size / 100.; + + E_FREE_FUNC(tw_mod->pop, e_object_del); + tw_mod->sticky = 0; + tw_mod->pop = e_popup_new(e_zone_current_get(e_util_container_current_get()), 0, 0, 1, 1); + e_popup_ignore_events_set(tw_mod->pop, 1); + pw = MIN(w, (ratio * (double)tw_mod->pop->zone->w)); + pw = MIN(pw, tw_mod->pop->zone->w); + if (pw == w) ph = h; + else + ph = lround((double)(pw * h) / ((double)w)); + if (ph > tw_mod->pop->zone->h) + { + ph = tw_mod->pop->zone->h; + pw = lround((double)(ph * w) / ((double)h)); + } + e_widget_preview_size_set(o, pw, ph); + e_widget_preview_vsize_set(o, w, h); + e_popup_layer_set(tw_mod->pop, E_COMP_CANVAS_LAYER_POPUP, 0); + + if ((last_coords.x == last_coords.y) && (last_coords.x == -1)) + { + px = lround(ratio * (double)tw_mod->pop->zone->w) - (pw / 2); + py = lround(ratio * (double)tw_mod->pop->zone->h) - (ph / 2); + if (px + pw > tw_mod->pop->zone->w) + px = tw_mod->pop->zone->w - pw; + if (py + ph > tw_mod->pop->zone->h) + py = tw_mod->pop->zone->h - ph; + } + else + { + /* prefer tooltip left of last_coords */ + px = last_coords.x - pw - 3; + /* if it's offscreen, try right of last_coords */ + if (px < 0) px = last_coords.x + 3; + /* fuck this, stick it right on the last_coords */ + if (px + pw + 3 > tw_mod->pop->zone->w) + px = (last_coords.x / 2) - (pw / 2); + /* give up */ + if (px < 0) px = 0; + + /* prefer tooltip above last_coords */ + py = last_coords.y - ph - 3; + /* if it's offscreen, try below last_coords */ + if (py < 0) py = last_coords.y + 3; + /* fuck this, stick it right on the last_coords */ + if (py + ph + 3 > tw_mod->pop->zone->h) + py = (last_coords.y / 2) - (ph / 2); + /* give up */ + if (py < 0) py = 0; + } + e_popup_move_resize(tw_mod->pop, px, py, pw, ph); + e_popup_content_set(tw_mod->pop, o); + e_popup_show(tw_mod->pop); + tw_popup_opacity_set(); + E_OBJECT_DEL_SET(tw_mod->pop, tw_popup_del); +} + +static void +tw_show(Media *i) +{ + Evas_Object *o, *ic, *prev; + int w, h; + + if (!i->buf) i->buf = tw_media_get(i->addr, ecore_time_unix_get()); + if (!i->buf) return; + prev = e_widget_preview_add(e_util_comp_current_get()->evas, 50, 50); + o = evas_object_image_filled_add(e_widget_preview_evas_get(prev)); + evas_object_image_memfile_set(o, (void*)eina_binbuf_string_get(i->buf), eina_binbuf_length_get(i->buf), NULL, NULL); + evas_object_image_size_get(o, &w, &h); + ic = e_icon_add(e_widget_preview_evas_get(prev)); + e_icon_image_object_set(ic, o); + e_widget_preview_extern_object_set(prev, ic); + tw_show_helper(prev, w, h); + e_object_data_set(E_OBJECT(tw_mod->pop), eina_stringshare_ref(i->addr)); + e_popup_object_add(tw_mod->pop, ic); +} + +static void +tw_show_local_dir(const char *uri) +{ + E_Action *act; + + act = e_action_find("fileman"); + if (act) act->func.go(NULL, uri); +} + +static void +tw_show_local_file(const char *uri) +{ + Evas_Object *o, *prev; + int w, h; + + if (!evas_object_image_extension_can_load_get(uri)) return; + prev = e_widget_preview_add(e_util_comp_current_get()->evas, 50, 50); + o = e_icon_add(e_widget_preview_evas_get(prev)); + e_icon_file_set(o, uri); + e_icon_preload_set(o, 1); + e_icon_size_get(o, &w, &h); + e_widget_preview_extern_object_set(prev, o); + tw_show_helper(prev, w, h); + e_popup_object_add(tw_mod->pop, o); + e_object_data_set(E_OBJECT(tw_mod->pop), eina_stringshare_add(uri)); +} + +EINTERN Eina_Bool +tw_hide(void *d EINA_UNUSED) +{ + E_FREE_FUNC(tw_mod->pop, e_object_del); + last_coords.x = last_coords.y = 0; + E_FREE_FUNC(tw_hide_timer, ecore_timer_del); + download_media_cleanup(); + return EINA_FALSE; +} + +EINTERN int +e_tw_init(void) +{ + char buf[PATH_MAX]; + Eet_Data_Descriptor_Class eddc; + + tw_dbus_iface = e_msgbus_interface_attach(&tw_desc); + + e_user_dir_concat_static(buf, "images/cache.eet"); + media = eet_open(buf, EET_FILE_MODE_READ_WRITE); + if (!media) + { + ERR("Could not open media cache file!"); + return 0; + } + + cache_edd = media_cache_edd_new(); + EET_EINA_FILE_DATA_DESCRIPTOR_CLASS_SET(&eddc, Media_Cache_List); + cleaner_edd = eet_data_descriptor_file_new(&eddc); + EET_DATA_DESCRIPTOR_ADD_LIST(cleaner_edd, Media_Cache_List, "cache", cache, cache_edd); + tw_cache_list = eet_data_read(media, cleaner_edd, "media_cache"); + + e_user_dir_concat_static(buf, "images/dummies.eet"); + dummies = eet_open(buf, EET_FILE_MODE_READ_WRITE); + + E_LIST_HANDLER_APPEND(handlers, ECORE_CON_EVENT_URL_COMPLETE, download_media_complete, tw_mod); + E_LIST_HANDLER_APPEND(handlers, ECORE_CON_EVENT_URL_PROGRESS, download_media_status, tw_mod); + E_LIST_HANDLER_APPEND(handlers, ECORE_CON_EVENT_URL_DATA, download_media_data, tw_mod); + + tw_mod->media = eina_hash_string_superfast_new((Eina_Free_Cb)download_media_free); + return 1; +} + +EINTERN void +e_tw_shutdown(void) +{ + E_FREE_LIST(handlers, ecore_event_handler_del); + if (media) + { + if (tw_cache_list) + { + Media_Cache *ic; + eet_data_write(media, cleaner_edd, "media_cache", tw_cache_list, 1); + EINA_LIST_FREE(tw_cache_list->cache, ic) + { + eina_stringshare_del(ic->sha1); + free(ic); + } + free(tw_cache_list); + } + E_FREE_FUNC(media, eet_close); + } + E_FREE_FUNC(tw_dbus_iface, eldbus_service_interface_unregister); + E_FREE_FUNC(dummies, eet_close); + E_FREE_FUNC(cleaner_edd, eet_data_descriptor_free); + E_FREE_FUNC(cache_edd, eet_data_descriptor_free); + tw_hide(NULL); + last_coords.x = last_coords.y = 0; + eina_hash_free(tw_mod->media); + E_FREE_FUNC(tw_mod->pop, e_object_del); +} 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 @@ +[Desktop Entry] +Type=Link +Name=Teamwork +Icon=e-module-teamwork +Comment=Enlightenment Is A Team Player +X-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 @@ +/* + * The contents of this file are subject to the Mozilla Public + * License Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS + * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or + * implied. See the License for the specific language governing + * rights and limitations under the License. + * + * The Original Code is SHA 180-1 Reference Implementation (Compact version) + * + * The Initial Developer of the Original Code is Paul Kocher of + * Cryptography Research. Portions created by Paul Kocher are + * Copyright (C) 1995-9 by Cryptography Research, Inc. All + * Rights Reserved. + * + * Contributor(s): + * + * Paul Kocher + * + */ + +#include "sha1.h" + +static void shaHashBlock(SHA_CTX2 *ctx); + +void +SHA1_Init2(SHA_CTX2 *ctx) { + int i; + + ctx->lenW = 0; + ctx->sizeHi = ctx->sizeLo = 0; + + /* Initialize H with the magic constants (see FIPS180 for constants) + */ + ctx->H[0] = 0x67452301; + ctx->H[1] = 0xefcdab89; + ctx->H[2] = 0x98badcfe; + ctx->H[3] = 0x10325476; + ctx->H[4] = 0xc3d2e1f0; + + for (i = 0; i < 80; i++) + ctx->W[i] = 0; +} + +void +SHA1_Update2(SHA_CTX2 *ctx, + void *_dataIn, + int len) { + unsigned char *dataIn = _dataIn; + int i; + + /* Read the data into W and process blocks as they get full + */ + for (i = 0; i < len; i++) { + ctx->W[ctx->lenW / 4] <<= 8; + ctx->W[ctx->lenW / 4] |= (unsigned int)dataIn[i]; + if ((++ctx->lenW) % 64 == 0) + { + shaHashBlock(ctx); + ctx->lenW = 0; + } + ctx->sizeLo += 8; + ctx->sizeHi += (ctx->sizeLo < 8); + } +} + +void +SHA1_Final2(unsigned char hashout[20], + SHA_CTX2 *ctx) { + unsigned char pad0x80 = 0x80; + unsigned char pad0x00 = 0x00; + unsigned char padlen[8]; + int i; + + /* Pad with a binary 1 (e.g. 0x80), then zeroes, then length + */ + padlen[0] = (unsigned char)((ctx->sizeHi >> 24) & 255); + padlen[1] = (unsigned char)((ctx->sizeHi >> 16) & 255); + padlen[2] = (unsigned char)((ctx->sizeHi >> 8) & 255); + padlen[3] = (unsigned char)((ctx->sizeHi >> 0) & 255); + padlen[4] = (unsigned char)((ctx->sizeLo >> 24) & 255); + padlen[5] = (unsigned char)((ctx->sizeLo >> 16) & 255); + padlen[6] = (unsigned char)((ctx->sizeLo >> 8) & 255); + padlen[7] = (unsigned char)((ctx->sizeLo >> 0) & 255); + SHA1_Update2(ctx, &pad0x80, 1); + while (ctx->lenW != 56) + SHA1_Update2(ctx, &pad0x00, 1); + SHA1_Update2(ctx, padlen, 8); + + /* Output hash + */ + for (i = 0; i < 20; i++) { + hashout[i] = (unsigned char)(ctx->H[i / 4] >> 24); + ctx->H[i / 4] <<= 8; + } + + /* + * Re-initialize the context (also zeroizes contents) + */ + SHA1_Init2(ctx); +} + +#define SHA_ROT(X, n) (((X) << (n)) | ((X) >> (32 - (n)))) + +static void +shaHashBlock(SHA_CTX2 *ctx) { + int t; + unsigned int A, B, C, D, E, TEMP; + + for (t = 16; t <= 79; t++) + ctx->W[t] = + SHA_ROT(ctx->W[t - 3] ^ ctx->W[t - 8] ^ ctx->W[t - 14] ^ ctx->W[t - 16], 1); + + A = ctx->H[0]; + B = ctx->H[1]; + C = ctx->H[2]; + D = ctx->H[3]; + E = ctx->H[4]; + + for (t = 0; t <= 19; t++) { + TEMP = SHA_ROT(A, 5) + (((C ^ D) & B) ^ D) + E + ctx->W[t] + 0x5a827999; + E = D; D = C; C = SHA_ROT(B, 30); B = A; A = TEMP; + } + for (t = 20; t <= 39; t++) { + TEMP = SHA_ROT(A, 5) + (B ^ C ^ D) + E + ctx->W[t] + 0x6ed9eba1; + E = D; D = C; C = SHA_ROT(B, 30); B = A; A = TEMP; + } + for (t = 40; t <= 59; t++) { + TEMP = SHA_ROT(A, 5) + ((B & C) | (D & (B | C))) + E + ctx->W[t] + 0x8f1bbcdc; + E = D; D = C; C = SHA_ROT(B, 30); B = A; A = TEMP; + } + for (t = 60; t <= 79; t++) { + TEMP = SHA_ROT(A, 5) + (B ^ C ^ D) + E + ctx->W[t] + 0xca62c1d6; + E = D; D = C; C = SHA_ROT(B, 30); B = A; A = TEMP; + } + + ctx->H[0] += A; + ctx->H[1] += B; + ctx->H[2] += C; + ctx->H[3] += D; + ctx->H[4] += E; +} + 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 @@ +/* + * The contents of this file are subject to the Mozilla Public + * License Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS + * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or + * implied. See the License for the specific language governing + * rights and limitations under the License. + * + * The Original Code is SHA 180-1 Header File + * + * The Initial Developer of the Original Code is Paul Kocher of + * Cryptography Research. Portions created by Paul Kocher are + * Copyright (C) 1995-9 by Cryptography Research, Inc. All + * Rights Reserved. + * + * Contributor(s): + * + * Paul Kocher + * + * Alternatively, the contents of this file may be used under the + * terms of the GNU General Public License Version 2 or later (the + * "GPL"), in which case the provisions of the GPL are applicable + * instead of those above. If you wish to allow use of your + * version of this file only under the terms of the GPL and not to + * allow others to use your version of this file under the MPL, + * indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by + * the GPL. If you do not delete the provisions above, a recipient + * may use your version of this file under either the MPL or the + * GPL. + */ + +#ifndef SHA_H +#define SHA_H + +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +typedef struct { + unsigned int H[5]; + unsigned int W[80]; + int lenW; + unsigned int sizeHi,sizeLo; +} SHA_CTX2; + +void SHA1_Init2(SHA_CTX2 *ctx); +void SHA1_Update2(SHA_CTX2 *ctx, void *dataIn, int len); +void SHA1_Final2(unsigned char hashout[20], SHA_CTX2 *ctx); + +#endif