shell32: Add trashing support functions.
diff --git a/dlls/shell32/Makefile.in b/dlls/shell32/Makefile.in
index 4ab01f1..58376e9 100644
--- a/dlls/shell32/Makefile.in
+++ b/dlls/shell32/Makefile.in
@@ -48,7 +48,9 @@
 	shpolicy.c \
 	shv_bg_cmenu.c \
 	shv_item_cmenu.c \
-	systray.c
+	systray.c \
+	trash.c \
+	xdg.c
 
 RC_SRCS = shres.rc
 RC_BINSRC = shres.rc
diff --git a/dlls/shell32/trash.c b/dlls/shell32/trash.c
new file mode 100644
index 0000000..595ab08
--- /dev/null
+++ b/dlls/shell32/trash.c
@@ -0,0 +1,308 @@
+/*
+ * The freedesktop.org Trash, implemented using the 0.7 spec version
+ * (see http://www.ramendik.ru/docs/trashspec.html)
+ *
+ * Copyright (C) 2006 Mikolaj Zalewski
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#include <stdarg.h>
+#include <sys/stat.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+#include "windef.h"
+#include "winbase.h"
+#include "winerror.h"
+#include "winreg.h"
+#include "shlwapi.h"
+
+#include <stdio.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <time.h>
+#include "wine/debug.h"
+#include "shell32_main.h"
+#include "xdg.h"
+
+WINE_DEFAULT_DEBUG_CHANNEL(trash);
+
+static CRITICAL_SECTION TRASH_Creating;
+static CRITICAL_SECTION_DEBUG TRASH_Creating_Debug =
+{
+    0, 0, &TRASH_Creating,
+    { &TRASH_Creating_Debug.ProcessLocksList,
+      &TRASH_Creating_Debug.ProcessLocksList},
+    0, 0, { (DWORD_PTR)__FILE__ ": TRASH_Creating"}
+};
+static CRITICAL_SECTION TRASH_Creating = { &TRASH_Creating_Debug, -1, 0, 0, 0, 0 };
+
+static const char trashinfo_suffix[] = ".trashinfo";
+static const char trashinfo_header[] = "[Trash Info]\n";
+
+typedef struct
+{
+    char *info_dir;
+    char *files_dir;
+    dev_t device;
+} TRASH_BUCKET;
+
+static TRASH_BUCKET *home_trash=NULL;
+
+static char *init_home_dir(const char *subpath)
+{
+    char *path = XDG_BuildPath(XDG_DATA_HOME, subpath);
+    if (path == NULL) return NULL;
+    if (!XDG_MakeDirs(path))
+    {
+        ERR("Couldn't create directory %s (errno=%d). Trash won't be available\n", debugstr_a(path), errno);
+        SHFree(path);
+        path=NULL;
+    }
+    return path;
+}
+
+static TRASH_BUCKET *TRASH_CreateHomeBucket(void)
+{
+    TRASH_BUCKET *bucket;
+    struct stat trash_stat;
+    char *trash_path = NULL;
+    
+    bucket = SHAlloc(sizeof(TRASH_BUCKET));
+    if (bucket == NULL)
+    {
+        errno = ENOMEM;
+        goto error;
+    }
+    memset(bucket, 0, sizeof(*bucket));
+    bucket->info_dir = init_home_dir("Trash/info/");
+    if (bucket->info_dir == NULL) goto error;
+    bucket->files_dir = init_home_dir("Trash/files/");
+    if (bucket->files_dir == NULL) goto error;
+    
+    trash_path = XDG_BuildPath(XDG_DATA_HOME, "Trash/");
+    if (stat(trash_path, &trash_stat) == -1)
+        goto error;
+    bucket->device = trash_stat.st_dev;
+    SHFree(trash_path);
+    return bucket;
+error:
+    SHFree(trash_path);
+    if (bucket)
+    {
+        SHFree(bucket->info_dir);
+        SHFree(bucket->files_dir);
+    }
+    SHFree(bucket);
+    return NULL;
+}
+
+static BOOL TRASH_EnsureInitialized(void)
+{
+    if (home_trash == NULL)
+    {
+        EnterCriticalSection(&TRASH_Creating);
+        if (home_trash == NULL)
+            home_trash = TRASH_CreateHomeBucket();
+        LeaveCriticalSection(&TRASH_Creating);
+    }
+
+    if (home_trash == NULL)
+    {
+        ERR("Couldn't initialize home trash (errno=%d)\n", errno);
+        return FALSE;
+    }
+    return TRUE;
+}
+
+static BOOL file_good_for_bucket(TRASH_BUCKET *pBucket, struct stat *file_stat)
+{
+    if (pBucket->device != file_stat->st_dev)
+        return FALSE;
+    return S_ISREG(file_stat->st_mode);
+}
+
+BOOL TRASH_CanTrashFile(LPCWSTR wszPath)
+{
+    struct stat file_stat;
+    char *unix_path;
+    
+    TRACE("(%s)\n", debugstr_w(wszPath));
+    if (!TRASH_EnsureInitialized()) return FALSE;
+    if (!(unix_path = wine_get_unix_file_name(wszPath)))
+        return FALSE;
+    if (lstat(unix_path, &file_stat)==-1)
+    {
+        HeapFree(GetProcessHeap(), 0, unix_path);
+        return FALSE;
+    }
+    HeapFree(GetProcessHeap(), 0, unix_path);
+    return file_good_for_bucket(home_trash, &file_stat);
+}
+
+/*
+ * Try to create a single .trashinfo file. Return TRUE if successfull, else FALSE
+ */
+static BOOL try_create_trashinfo_file(const char *info_dir, const char *file_name,
+    const char *original_file_name)
+{
+    struct tm curr_time;
+    time_t curr_time_secs;
+    char datebuf[200];
+    char *path = SHAlloc(strlen(info_dir)+strlen(file_name)+strlen(trashinfo_suffix)+1);
+    int writer = -1;
+    
+    if (path==NULL) return FALSE;
+    wsprintfA(path, "%s%s%s", info_dir, file_name, trashinfo_suffix);
+    TRACE("Trying to create '%s'\n", path);
+    writer = open(path, O_CREAT|O_WRONLY|O_TRUNC|O_EXCL, 0600);
+    if (writer==-1) goto error;
+    
+    write(writer, trashinfo_header, strlen(trashinfo_header));
+    if (!XDG_WriteDesktopStringEntry(writer, "Path", XDG_URLENCODE, original_file_name))
+        goto error;
+    
+    time(&curr_time_secs);
+    localtime_r(&curr_time_secs, &curr_time);
+    wnsprintfA(datebuf, 200, "%04d-%02d-%02dT%02d:%02d:%02d",
+        curr_time.tm_year+1900,
+        curr_time.tm_mon+1,
+        curr_time.tm_mday,
+        curr_time.tm_hour,
+        curr_time.tm_min,
+        curr_time.tm_sec);
+    if (!XDG_WriteDesktopStringEntry(writer, "DeletionDate", 0, datebuf))
+        goto error;
+    close(writer);
+    SHFree(path);
+    return TRUE;
+
+error:
+    if (writer != -1)
+    {
+        close(writer);
+        unlink(path);
+    }
+    SHFree(path);
+    return FALSE;
+}
+
+/*
+ * Try to create a .trashinfo file. This function will make several attempts with
+ * different filenames. It will return the filename that succeded or NULL if a file
+ * couldn't be created.
+ */
+static char *create_trashinfo(const char *info_dir, const char *file_path)
+{
+    const char *base_name;
+    char *filename_buffer;
+    unsigned int seed = (unsigned int)time(NULL);
+    int i;
+
+    errno = ENOMEM;       /* out-of-memory is the only case when errno isn't set */
+    base_name = strrchr(file_path, '/');
+    if (base_name == NULL)
+        base_name = file_path;
+    else
+        base_name++;
+
+    filename_buffer = SHAlloc(strlen(base_name)+9+1);
+    if (filename_buffer == NULL)
+        return NULL;
+    lstrcpyA(filename_buffer, base_name);
+    if (try_create_trashinfo_file(info_dir, filename_buffer, file_path))
+        return filename_buffer;
+    for (i=0; i<30; i++)
+    {
+        sprintf(filename_buffer, "%s-%d", base_name, i+1);
+        if (try_create_trashinfo_file(info_dir, filename_buffer, file_path))
+            return filename_buffer;
+    }
+    
+    for (i=0; i<1000; i++)
+    {
+        sprintf(filename_buffer, "%s-%08x", base_name, rand_r(&seed));
+        if (try_create_trashinfo_file(info_dir, filename_buffer, file_path))
+            return filename_buffer;
+    }
+    
+    WARN("Couldn't create trashinfo after 1031 tries (errno=%d)\n", errno);
+    SHFree(filename_buffer);
+    return NULL;
+}
+
+void remove_trashinfo_file(const char *info_dir, const char *base_name)
+{
+    char *filename_buffer;
+    
+    filename_buffer = SHAlloc(lstrlenA(info_dir)+lstrlenA(base_name)+lstrlenA(trashinfo_suffix)+1);
+    if (filename_buffer == NULL) return;
+    sprintf(filename_buffer, "%s%s%s", info_dir, base_name, trashinfo_suffix);
+    unlink(filename_buffer);
+    SHFree(filename_buffer);
+}
+
+static BOOL TRASH_MoveFileToBucket(TRASH_BUCKET *pBucket, const char *unix_path)
+{
+    struct stat file_stat;
+    char *trash_file_name = NULL;
+    char *trash_path = NULL;
+    BOOL ret = TRUE;
+
+    if (lstat(unix_path, &file_stat)==-1)
+        return FALSE;
+    if (!file_good_for_bucket(pBucket, &file_stat))
+        return FALSE;
+        
+    trash_file_name = create_trashinfo(pBucket->info_dir, unix_path);
+    if (trash_file_name == NULL)
+        return FALSE;
+        
+    trash_path = SHAlloc(strlen(pBucket->files_dir)+strlen(trash_file_name)+1);
+    if (trash_path == NULL) goto error;
+    lstrcpyA(trash_path, pBucket->files_dir);
+    lstrcatA(trash_path, trash_file_name);
+    
+    if (rename(unix_path, trash_path)==0)
+    {
+        TRACE("rename succeded\n");
+        goto cleanup;
+    }
+    
+    /* TODO: try to manually move the file */
+    ERR("Couldn't move file\n");
+error:
+    ret = FALSE;
+    remove_trashinfo_file(pBucket->info_dir, trash_file_name);
+cleanup:
+    SHFree(trash_file_name);
+    SHFree(trash_path);
+    return ret;
+}
+
+BOOL TRASH_TrashFile(LPCWSTR wszPath)
+{
+    char *unix_path;
+    BOOL result;
+    
+    TRACE("(%s)\n", debugstr_w(wszPath));
+    if (!TRASH_EnsureInitialized()) return FALSE;
+    if (!(unix_path = wine_get_unix_file_name(wszPath)))
+        return FALSE;
+    result = TRASH_MoveFileToBucket(home_trash, unix_path);
+    HeapFree(GetProcessHeap(), 0, unix_path);
+    return result;
+}
diff --git a/dlls/shell32/xdg.c b/dlls/shell32/xdg.c
new file mode 100644
index 0000000..7166650
--- /dev/null
+++ b/dlls/shell32/xdg.c
@@ -0,0 +1,372 @@
+/*
+ * Generic freedesktop.org support code
+ *
+ * Copyright (C) 2006 Mikolaj Zalewski
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+ 
+#include <stdarg.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <errno.h>
+ 
+#include "windef.h"
+#include "winbase.h"
+#include "winreg.h"
+#include "shlwapi.h"
+#include "wine/debug.h"
+#include "shell32_main.h"
+#include "xdg.h"
+
+WINE_DEFAULT_DEBUG_CHANNEL(xdg);
+
+/*
+ * XDG paths implemented using Desktop Base Directory spec version 0.6
+ * (from http://standards.freedesktop.org/basedir-spec/basedir-spec-0.6.html)
+ */
+
+static CRITICAL_SECTION XDG_PathsLock;
+static CRITICAL_SECTION_DEBUG XDG_PathsLock_Debug =
+{
+    0, 0, &XDG_PathsLock,
+    { &XDG_PathsLock_Debug.ProcessLocksList,
+      &XDG_PathsLock_Debug.ProcessLocksList},
+    0, 0, { (DWORD_PTR)__FILE__ ": XDG_PathsLock"}
+};
+static CRITICAL_SECTION XDG_PathsLock = { &XDG_PathsLock_Debug, -1, 0, 0, 0, 0 };
+
+typedef struct
+{
+    const char *var_name;
+    const char *default_value;
+} std_path;
+
+static const std_path paths[] = {
+    {"XDG_DATA_HOME", "$HOME/.local/share"},
+    {"XDG_CONFIG_HOME", "$HOME/.config"},
+    {"XDG_DATA_DIRS", "/usr/local/share:/usr/share"},
+    {"XDG_CONFIG_DIRS", "/etc/xdg"},
+    {"XDG_CACHE_HOME", "$HOME/.cache"}
+};
+
+#define PATHS_COUNT (sizeof(paths)/sizeof(paths[0]))
+
+/* will be filled with paths as they are computed */
+static const char *path_values[PATHS_COUNT] = {
+    NULL,
+    NULL,
+    NULL,
+    NULL,
+    NULL
+};
+
+static char *load_path(int path_id)
+{
+    char *env = getenv(paths[path_id].var_name);
+    char *ret;
+    
+    if (env != NULL && env[0]=='/')
+    {
+        ret = SHAlloc(strlen(env)+1);
+        if (ret != NULL)
+            lstrcpyA(ret, env);
+        return ret;
+    }
+    
+    if (memcmp(paths[path_id].default_value, "$HOME", 5)==0)
+    {
+	char *home = getenv("HOME");
+	int len;
+
+        if (!home) return NULL;
+	ret = SHAlloc(strlen(home)+strlen(paths[path_id].default_value)-5+1);
+	if (ret == NULL) return NULL;
+	
+	lstrcpyA(ret, home);
+	len = strlen(ret);
+	if (len>0 && ret[len-1]=='/')
+	    ret[--len]=0;
+	lstrcatA(ret, paths[path_id].default_value+5);
+	return ret;
+    }
+    
+    ret = SHAlloc(strlen(paths[path_id].default_value)+1);
+    if (ret != NULL)
+        lstrcpyA(ret, env);
+    return ret;
+}
+
+/******************************************************************************
+ * XDG_GetPath    [internal]
+ *
+ * Get one of the XDG standard patch. The return value shouldn't be modified nor
+ * freed. A return value of NULL means that the memory is exhausted or the input
+ * is invalid
+ *
+ * For XDG_DATA_HOME, XDG_CONFIG_HOME and XDG_CACHE_HOME the result is a Unix path.
+ * For XDG_DATA_DIRS and XDG_CONFIG_DIRS the result is a colon-separated list of Unix
+ * paths
+ *
+ * The paths are guaranteed to start with '/'
+ */
+const char *XDG_GetPath(int path_id)
+{
+    if (path_id >= PATHS_COUNT || path_id < 0)
+    {
+	ERR("Invalid path_id %d\n", path_id);
+	return NULL;
+    }
+    
+    if (path_values[path_id] != NULL)
+	return path_values[path_id];
+    EnterCriticalSection(&XDG_PathsLock);
+    if (path_values[path_id] == NULL)
+	path_values[path_id] = load_path(path_id);
+    LeaveCriticalSection(&XDG_PathsLock);
+    return path_values[path_id];
+}
+
+/******************************************************************************
+ * XDG_GetPath    [internal]
+ *
+ * Build a string with a subpath of one of the XDG standard paths.
+ * The root can be one of XDG_DATA_HOME, XDG_CONFIG_HOME and XDG_CACHE_HOME.
+ * The subpath is a path relative to that root (it shouldn't start with a slash)
+ *
+ * The returned path should be freed with SHFree. A return of NULL means that the
+ * memory is exhausted or the parameters are invalid
+ */
+char *XDG_BuildPath(int root_id, const char *subpath)
+{
+    const char *root_path = XDG_GetPath(root_id);
+    char *ret_buffer;
+    int root_len;
+    
+    if (root_id == XDG_DATA_DIRS || root_id == XDG_CONFIG_DIRS)
+    {
+        ERR("Invalid path id %d\n", root_id);
+        return NULL;
+    }
+    
+    if (root_path == NULL) return NULL;
+    root_len = strlen(root_path);
+    if (root_path[root_len-1]=='/') root_len--;
+    ret_buffer = SHAlloc(root_len+1+strlen(subpath)+1);
+    if (ret_buffer == NULL) return NULL;
+    lstrcpyA(ret_buffer, root_path);
+    ret_buffer[root_len]='/';
+    lstrcpyA(ret_buffer+root_len+1, subpath);
+    return ret_buffer;
+}
+
+/******************************************************************************
+ * XDG_MakeDirs    [internal]
+ *
+ * Checks that all the directories on the specified path exists. If some don't exists
+ * they are created with mask 0700 as required by many the freedeskop.org specs.
+ * If the path doesn't end with '/' it is assumed to be a path to a file and the last
+ * segment is not checked
+ *
+ * In case of a failure the errno is always set and can be used e.g for debugging
+ *
+ * RETURNS
+ *   TRUE on success, FALSE on error
+ */
+BOOL XDG_MakeDirs(const char *path)
+{
+    int last_slash = 0;
+    BOOL success = TRUE;
+    struct stat tmp;
+    char *buffer = SHAlloc(strlen(path)+1);
+    
+    if (buffer == NULL)
+    {
+        errno = ENOMEM;
+        return FALSE;
+    }
+    lstrcpyA(buffer, path);
+    
+    TRACE("(%s)\n", debugstr_a(path));
+    while (1)
+    {
+        char *slash=strchr(buffer+last_slash+1, '/');
+        if (slash==NULL)
+            break;
+        
+        /* cut the string at that position and create the directory if it doesn't exist */
+        *slash=0;
+        TRACE("Checking path %s\n", debugstr_a(buffer));
+        success = (stat(buffer, &tmp)==0);
+        if (!success && errno==ENOENT)
+        {
+            TRACE("Creating\n");
+            success = (mkdir(buffer, 0700)==0);
+        }
+        if (!success)
+        {
+            WARN("Couldn't process directory %s (errno=%d)\n", debugstr_a(buffer), errno);
+            break;
+        }
+        *slash='/';
+        last_slash = slash-buffer;
+    }
+    SHFree(buffer);
+    return success;
+}
+
+/*
+ * .desktop files functions
+ */
+
+
+/******************************************************************************
+ * dskentry_encode    [internal]
+ *
+ * Escape the characters that can't be present in a desktop entry value like \n, leading
+ * spaces etc. The output parameter may be NULL. Then only the number of characters will
+ * be computers.
+ *
+ * RETURNS
+ *   The number of characters after escaping the special characters, including the
+ * terminating NUL.
+ */
+static int dskentry_encode(const char *value, char *output)
+{
+    int only_spc = TRUE;
+    int num_written = 0;
+    const char *c;
+    for (c = value; *c; c++)
+    {
+        if (only_spc && *c==' ')
+        {
+            if (output)
+            {
+                *(output++) = '\\';
+                *(output++) = 's';
+            }
+            num_written += 2;
+            continue;
+        }
+        only_spc = FALSE;
+        
+        if (*c=='\t' || *c=='\r' || *c=='\n' || *c=='\\')
+        {
+            if (output)
+            {
+                *(output++) = '\\';
+                if (*c=='\t') *(output++) = 't';
+                if (*c=='\r') *(output++) = 'r';
+                if (*c=='\n') *(output++) = 'n';
+                if (*c=='\\') *(output++) = '\\';
+            }
+            num_written += 2;
+        }
+        else
+        {
+            if (output)
+                *(output++)=*c;
+            num_written++;
+        }
+    }
+    
+    if (output)
+        *(output++) = 0;
+    num_written++;
+    return num_written;
+}
+
+
+/******************************************************************************
+ * url_encode    [internal]
+ *
+ * URL-encode the given string (i.e. use escape codes like %20). Note that an
+ * URL-encoded string can be used as a value in desktop entry files as all
+ * unsafe characters are escaped.
+ *
+ * The output can be NULL. Then only the number of characters will be counted
+ *
+ * RETURNS
+ *   The number of characters after escaping the special characters, including the
+ * terminating NUL.
+ */
+static int url_encode(const char *value, char *output)
+{
+    static const char *unsafechars = "^&`{}|[]'<>\\#%\"+";
+    static const char *hexchars = "0123456789ABCDEF";
+    int num_written = 0;
+    const char *c;
+
+    for (c = value; *c; c++)
+    {
+        if (*c<=0x20 || *c>=0x7f || strchr(unsafechars, *c))
+        {
+            if (output)
+            {
+                *(output++) = '%';
+                *(output++) = hexchars[(unsigned)(*c)/16];
+                *(output++) = hexchars[(unsigned)(*c)%16];
+            }
+            num_written += 3;
+        }
+        else
+        {
+            if (output)
+                *(output++) = *c;
+            num_written++;
+        }
+    }
+
+    if (output)
+        *(output++) = 0;
+    num_written++;
+
+    return num_written;
+}
+
+static int escape_value(const char *value, DWORD dwFlags, char *output)
+{
+    if (dwFlags & XDG_URLENCODE)
+        return url_encode(value, output);
+    return dskentry_encode(value, output);
+}
+
+/******************************************************************************
+ * XDG_WriteDesktopStringEntry    [internal]
+ *
+ * Writes a key=value pair into the specified file descriptor.
+ *
+ * RETURNS
+ *   TRUE on success, else FALSE
+ */
+BOOL XDG_WriteDesktopStringEntry(int writer, const char *keyName, DWORD dwFlags, const char *value)
+{
+    int keyLen = lstrlenA(keyName);
+    int valueLen = escape_value(value, dwFlags, NULL);
+    char *string = SHAlloc(keyLen+1+valueLen);
+    BOOL ret;
+    
+    if (string == NULL)
+        return FALSE;
+    lstrcpyA(string, keyName);
+    string[keyLen] = '=';
+    escape_value(value, dwFlags, string+keyLen+1);
+    string[keyLen+1+valueLen-1]='\n';   /* -1 because valueLen contains the last NUL character */
+    ret = (write(writer, string, keyLen+1+valueLen)!=-1);
+    SHFree(string);
+    return ret;
+}
diff --git a/dlls/shell32/xdg.h b/dlls/shell32/xdg.h
new file mode 100644
index 0000000..46a8618
--- /dev/null
+++ b/dlls/shell32/xdg.h
@@ -0,0 +1,39 @@
+/*
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+#ifndef __XDG_H__
+#define __XDG_H__
+
+/*
+ * XDG directories access
+ */
+#define XDG_DATA_HOME 0
+#define XDG_CONFIG_HOME 1
+#define XDG_DATA_DIRS 2
+#define XDG_CONFIG_DIRS 3
+#define XDG_CACHE_HOME 4
+
+const char *XDG_GetPath(int path_id);
+char *XDG_BuildPath(int root_id, const char *subpath);
+int XDG_MakeDirs(const char *path);
+
+#define XDG_URLENCODE 0x1
+BOOL XDG_WriteDesktopStringEntry(int fd, const char *keyName, DWORD dwFlags, const char *value);
+
+/* implemented in trash.c */
+BOOL TRASH_CanTrashFile(LPCWSTR wszPath);
+BOOL TRASH_TrashFile(LPCWSTR wszPath);
+
+#endif /* ndef __XDG_H__ */