diff --git a/legacy/efreet/configure.in b/legacy/efreet/configure.in index 24aa414f91..75ee660785 100644 --- a/legacy/efreet/configure.in +++ b/legacy/efreet/configure.in @@ -1,6 +1,6 @@ rm -f config.cache -AC_INIT(efreet, 0.5.0.043, enlightenment-devel@lists.sourceforge.net) +AC_INIT(efreet, 0.5.0.044, enlightenment-devel@lists.sourceforge.net) AC_PREREQ(2.52) AC_CONFIG_SRCDIR(configure.in) AC_CANONICAL_BUILD @@ -69,6 +69,7 @@ AC_OUTPUT([ efreet.spec efreet.pc efreet-mime.pc +efreet-trash.pc Makefile src/Makefile src/lib/Makefile diff --git a/legacy/efreet/doc/head.html b/legacy/efreet/doc/head.html index 1e8e96095c..0be9c2d7ff 100644 --- a/legacy/efreet/doc/head.html +++ b/legacy/efreet/doc/head.html @@ -23,6 +23,7 @@ + diff --git a/legacy/efreet/efreet-trash.pc.in b/legacy/efreet/efreet-trash.pc.in new file mode 100644 index 0000000000..343e90e1ee --- /dev/null +++ b/legacy/efreet/efreet-trash.pc.in @@ -0,0 +1,11 @@ +prefix=@prefix@ +exec_prefix=@exec_prefix@ +libdir=@libdir@ +includedir=@includedir@ + +Name: efreet-trash +Description: Freedesktop Shared Trash implementation for the EFL +Requires: @requirements@ +Version: @VERSION@ +Libs: -L${libdir} -lefreet_trash +Cflags: -I${includedir}/efreet diff --git a/legacy/efreet/src/lib/Efreet_Trash.h b/legacy/efreet/src/lib/Efreet_Trash.h new file mode 100644 index 0000000000..115f459e5e --- /dev/null +++ b/legacy/efreet/src/lib/Efreet_Trash.h @@ -0,0 +1,82 @@ +/* vim: set sw=4 ts=4 sts=4 et: */ +#ifndef EFREET_TRASH_H +#define EFREET_TRASH_H + +/** + * @file efreet_trash.h + * @brief Contains the methods used to support the FDO trash specification. + * @addtogroup Efreet_Trash Efreet_Trash: The XDG Trash Specification + * Some better explanation here... + * @{ + */ + +#ifdef EAPI +#undef EAPI +#endif +#ifdef _MSC_VER +# ifdef BUILDING_DLL +# define EAPI __declspec(dllexport) +# else +# define EAPI __declspec(dllimport) +# endif +#else +# ifdef __GNUC__ +# if __GNUC__ >= 4 +# define EAPI __attribute__ ((visibility("default"))) +# else +# define EAPI +# endif +# else +# define EAPI +# endif +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @{ + */ + +/** + * Efreet_Uri + */ +typedef struct Efreet_Uri Efreet_Uri; + +/** + * Efreet_Uri + * @brief Contains a simple rappresentation of an uri. The string don't have + * special chars escaped. + */ +struct Efreet_Uri +{ + const char *protocol; /**< The name of the host if any, or NULL */ + const char *hostname; /**< The name of the host if any, or NULL */ + const char *path; /**< The full file path whitout protocol nor host*/ +}; + + +EAPI const char *efreet_uri_escape(Efreet_Uri *uri); +EAPI Efreet_Uri *efreet_uri_parse(const char *val); +EAPI void efreet_uri_free(Efreet_Uri *uri); + +EAPI int efreet_trash_init(void); +EAPI void efreet_trash_shutdown(void); + +EAPI const char *efreet_trash_dir_get(void); +EAPI int efreet_trash_delete_uri(Efreet_Uri *uri, int force_delete); +EAPI Ecore_List *efreet_trash_ls(void); +EAPI int efreet_trash_is_empty(void); +EAPI int efreet_trash_empty_trash(void); + + +/** + * @} + */ + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/legacy/efreet/src/lib/Makefile.am b/legacy/efreet/src/lib/Makefile.am index a39f4786b5..1812e48823 100644 --- a/legacy/efreet/src/lib/Makefile.am +++ b/legacy/efreet/src/lib/Makefile.am @@ -6,7 +6,7 @@ AM_CPPFLAGS = \ -I$(top_srcdir) \ @ECORE_CFLAGS@ -lib_LTLIBRARIES = libefreet.la libefreet_mime.la +lib_LTLIBRARIES = libefreet.la libefreet_mime.la libefreet_trash.la EFREETHEADERS = \ Efreet.h \ @@ -43,10 +43,23 @@ $(EFREETMIMEHEADERS) libefreet_mime_la_SOURCES = \ $(EFREETMIMESOURCES) + +EFREETTRASHHEADERS = \ +Efreet_Trash.h + +EFREETTRASHSOURCES = \ +efreet_trash.c \ +$(EFREETTRASHHEADERS) + +libefreet_trash_la_SOURCES = \ +$(EFREETTRASHSOURCES) + + installed_headersdir = $(prefix)/include/efreet -installed_headers_DATA = $(EFREETHEADERS) $(EFREETMIMEHEADERS) +installed_headers_DATA = $(EFREETHEADERS) $(EFREETMIMEHEADERS) $(EFREETTRASHHEADERS) libefreet_la_LIBADD = @ECORE_LIBS@ libefreet_la_LDFLAGS = -version-info @version_info@ libefreet_mime_la_LIBADD = @ECORE_LIBS@ libefreet.la +libefreet_trash_la_LIBADD = @ECORE_LIBS@ libefreet.la diff --git a/legacy/efreet/src/lib/efreet_trash.c b/legacy/efreet/src/lib/efreet_trash.c new file mode 100644 index 0000000000..5c7b6199bc --- /dev/null +++ b/legacy/efreet/src/lib/efreet_trash.c @@ -0,0 +1,316 @@ +/* vim: set sw=4 ts=4 sts=4 et: */ +#include +#include +#include "Efreet.h" +#include "Efreet_Trash.h" +#include "efreet_private.h" + +static const char *efreet_trash_dir = NULL; + +/** + * @return Returns 1 on success or 0 on failure + * @brief Initializes the efreet trash system + */ +EAPI int +efreet_trash_init(void) +{ + return 1; +} + +/** + * @return Returns no value + * @brief Cleans up the efreet trash system + */ +EAPI void +efreet_trash_shutdown(void) +{ + IF_RELEASE(efreet_trash_dir); +} + +/** + * @return Returns the XDG Trash local directory or NULL on errors + * @brief Retrieves the XDG Trash local directory + */ +EAPI const char* +efreet_trash_dir_get(void) +{ + char buf[PATH_MAX]; + + if (efreet_trash_dir && ecore_file_exists(efreet_trash_dir)) + return efreet_trash_dir; + + snprintf(buf, sizeof(buf), "%s/Trash", efreet_data_home_get()); + if (!ecore_file_exists(buf) && !ecore_file_mkpath(buf)) + return NULL; + + IF_RELEASE(efreet_trash_dir); + efreet_trash_dir = ecore_string_instance(buf); + + snprintf(buf, sizeof(buf), "%s/files", efreet_trash_dir); + if (!ecore_file_exists(buf) && !ecore_file_mkpath(buf)) + return NULL; + + snprintf(buf, sizeof(buf), "%s/info", efreet_trash_dir); + if (!ecore_file_exists(buf) && !ecore_file_mkpath(buf)) + return NULL; + + return efreet_trash_dir; +} + +/** + * @param uri: The local uri to move in the trash + * @param force_delete: If you set this to 1 than files on different filesystems + * will be deleted permanently + * @return Return 1 on success, 0 on failure or -1 in case the uri is not on the + * same filesystem and force_delete is not set. + * @brief This function try to move the given uri to the trash. Files on + * different filesystem can't be moved to trash. If force_delete + * is 0 than non-local files will be ignored and -1 is returned, if you set + * force_delete to 1 non-local files will be deleted without asking. + */ +EAPI int +efreet_trash_delete_uri(Efreet_Uri *uri, int force_delete) +{ + char dest[PATH_MAX]; + char times[64]; + const char *fname; + const char *escaped; + int i = 1; + time_t now; + FILE *f; + + if (!uri || !uri->path || !ecore_file_can_write(uri->path)) return 0; + + fname = ecore_file_file_get(uri->path); + snprintf(dest, PATH_MAX, "%s/files/%s", efreet_trash_dir_get(), fname); + + /* search for a free filename */ + while (ecore_file_exists(dest)) + snprintf(dest, PATH_MAX, "%s/files/%s$%d", + efreet_trash_dir_get(), fname, i++); + fname = ecore_file_file_get(dest); + + /* move file to trash dir */ + if (rename(uri->path, dest)) + { + if (errno == EXDEV) + { + if (!force_delete) return -1; + if (!ecore_file_recursive_rm(uri->path)) + { + printf("EFREET TRASH ERROR: Can't delete file.\n"); + return 0; + } + } + else + { + printf("EFREET TRASH ERROR: Can't move file to trash.\n"); + return 0; + } + } + + + /* create info file */ + snprintf(dest, PATH_MAX, "%s/info/%s.trashinfo", + efreet_trash_dir_get(), fname); + + if (f = fopen(dest, "w")) + { + fputs("[Trash Info]\n", f); //TODO is '\n' right?? (or \r\c??) + + fputs("Path=", f); + escaped = efreet_uri_escape(uri); + fputs(escaped + 7, f); // +7 == don't write 'file://' + IF_RELEASE(escaped); + + time(&now); + strftime(times, sizeof(times), "%Y-%m-%dT%H:%M:%S", localtime(&now)); + fputs("\nDeletionDate=", f); + fputs(times, f); + fputs("\n", f); + fclose(f); + } + else + { + printf("EFREET TRASH ERROR: Can't create trash info file.\n"); + return 0; + } + + return 1; +} + +/** + * @return Return 1 if the trash is empty or 0 if some file are in. + * @brief Check if the trash is currently empty + */ +EAPI int +efreet_trash_is_empty(void) +{ + char buf[PATH_MAX]; + snprintf(buf, PATH_MAX, "%s/files", efreet_trash_dir_get()); + + /* TODO Check also trash in other filesystems */ + return ecore_file_dir_is_empty(buf); +} + +/** + * @return Return 1 on success or 0 on failure + * @brief Delete all the files inside the trash. + */ +EAPI int +efreet_trash_empty_trash(void) +{ + char buf[PATH_MAX]; + + snprintf(buf, PATH_MAX, "%s/info", efreet_trash_dir_get()); + if (!ecore_file_recursive_rm(buf)) return 0; + ecore_file_mkdir(buf); + + snprintf(buf, PATH_MAX, "%s/files", efreet_trash_dir_get()); + if (!ecore_file_recursive_rm(buf)) return 0; + ecore_file_mkdir(buf); + + /* TODO Empty also trash in other filesystems */ + return 1; +} + +/** + * @return Return a list of strings with filename (remember to free the list + * when you don't need anymore) + * @brief List all the files and directory currently inside the trash. + */ +EAPI Ecore_List* +efreet_trash_ls(void) +{ + char *infofile; + char buf[PATH_MAX]; + Ecore_List *files; + + // NOTE THIS FUNCTION NOW IS NOT COMPLETE AS I DON'T NEED IT + // TODO read the name from the infofile instead of the filename + + snprintf(buf, PATH_MAX, "%s/files", efreet_trash_dir_get()); + files = ecore_file_ls(buf); + + while (infofile = ecore_list_next(files)) + { + printf("FILE: %s\n", infofile); + } + + return files; +} + + +/** + * @param val: a valid uri string to parse + * @return Return The corresponding Efreet_Uri structure. Or NULL on errors. + * @brief Parse a single uri and return an Efreet_Uri struct. If there's no + * hostname in the uri then the hostname parameter is NULL. All the uri escaped + * chars will be converted back. + */ +EAPI Efreet_Uri * +efreet_uri_parse(const char *val) +{ + Efreet_Uri *uri; + const char *p; + char protocol[64], hostname[_POSIX_HOST_NAME_MAX], path[PATH_MAX]; + int i = 0; + + /* An uri should be in the form :/// */ + p = strstr(val, "://"); + if (!p) return NULL; + + memset(protocol, 0, 64); + memset(hostname, 0, _POSIX_HOST_NAME_MAX); + memset(path, 0, PATH_MAX); + + /* parse protocol */ + p = val; + for (i = 0; *p != ':' && *p != '\0' && i < 64; p++, i++) + protocol[i] = *p; + protocol[i] = '\0'; + + /* parse hostname */ + p += 3; + if (*p != '/') + { + for (i = 0; *p != '/' && *p != '\0' && i < _POSIX_HOST_NAME_MAX; p++, i++) + hostname[i] = *p; + hostname[i] = '\0'; + } + else + hostname[0] = '\0'; + + /* parse path */ + /* See http://www.faqs.org/rfcs/rfc1738.html for the escaped chars */ + for (i = 0; *p != '\0' && i < PATH_MAX; i++, p++) + { + if (*p == '%') + { + path[i] = *(++p); + path[i + 1] = *(++p); + path[i] = (char)strtol(&(path[i]), NULL, 16); + path[i + 1] = '\0'; + } + else + path[i] = *p; + } + + uri = NEW(Efreet_Uri, 1); + if (!uri) return NULL; + + uri->protocol = ecore_string_instance(protocol); + uri->hostname = ecore_string_instance(hostname); + uri->path = ecore_string_instance(path); + + return uri; +} + +/** + * @param uri: The uri structure to escape + * @return The string rapresentation of an uri (ex: 'file:///home/my%20name') + * @brief Get the string rapresentation of the given uri struct escaping + * illegal caracters. The resulting string will contain the protocol but not the + * hostname, as many apps doesn't handle it. + */ +EAPI const char * +efreet_uri_escape(Efreet_Uri *uri) +{ + char dest[PATH_MAX * 3 + 4]; + const char *p; + int i; + + if (!uri || !uri->path || !uri->protocol) return NULL; + memset(dest, 0, PATH_MAX * 3 + 4); + snprintf(dest, strlen(uri->protocol) + 4, "%s://", uri->protocol); + + + /* Most app doesn't handle the hostname in the uri so it's put to NULL */ + for (i = strlen(uri->protocol) + 3, p = uri->path; *p != '\0'; p++, i++) + { + if (isalnum(*p) || strchr("/$-_.+!*'()", *p)) + dest[i] = *p; + else + { + snprintf(&(dest[i]), 4, "%%%02X", *p); + i += 2; + } + } + + return ecore_string_instance(dest); +} + +/** + * @param uri: The uri to free + * @brief Free the given uri structure. + */ +EAPI void +efreet_uri_free(Efreet_Uri *uri) +{ + if (!uri) return; + IF_RELEASE(uri->protocol); + IF_RELEASE(uri->path); + IF_RELEASE(uri->hostname); + free(uri); + uri = NULL; +}