changeset 126:d0cd259345f3

Add Dropbox Uploader script See https://github.com/andreafabrizi/Dropbox-Uploader
author zegervdv <zegervdv@me.com>
date Tue, 30 Sep 2014 17:32:18 +0200
parents 18db7404aaf2
children 39f36bd51c23
files bin/db gitignore
diffstat 2 files changed, 1308 insertions(+), 0 deletions(-) [+]
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/bin/db	Tue Sep 30 17:32:18 2014 +0200
@@ -0,0 +1,1306 @@
+#!/usr/bin/env bash
+#
+# Dropbox Uploader
+#
+# Copyright (C) 2010-2014 Andrea Fabrizi <[email protected]>
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program 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 General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+#
+
+#Default configuration file
+CONFIG_FILE=~/.dropbox_uploader
+
+#Default chunk size in Mb for the upload process
+#It is recommended to increase this value only if you have enough free space on your /tmp partition
+#Lower values may increase the number of http requests
+CHUNK_SIZE=4
+
+#Curl location
+#If not set, curl will be searched into the $PATH
+#CURL_BIN="/usr/bin/curl"
+
+#Default values
+TMP_DIR="/tmp"
+DEBUG=0
+QUIET=0
+SHOW_PROGRESSBAR=0
+SKIP_EXISTING_FILES=0
+ERROR_STATUS=0
+
+#Don't edit these...
+API_REQUEST_TOKEN_URL="https://api.dropbox.com/1/oauth/request_token"
+API_USER_AUTH_URL="https://www2.dropbox.com/1/oauth/authorize"
+API_ACCESS_TOKEN_URL="https://api.dropbox.com/1/oauth/access_token"
+API_CHUNKED_UPLOAD_URL="https://api-content.dropbox.com/1/chunked_upload"
+API_CHUNKED_UPLOAD_COMMIT_URL="https://api-content.dropbox.com/1/commit_chunked_upload"
+API_UPLOAD_URL="https://api-content.dropbox.com/1/files_put"
+API_DOWNLOAD_URL="https://api-content.dropbox.com/1/files"
+API_DELETE_URL="https://api.dropbox.com/1/fileops/delete"
+API_MOVE_URL="https://api.dropbox.com/1/fileops/move"
+API_COPY_URL="https://api.dropbox.com/1/fileops/copy"
+API_METADATA_URL="https://api.dropbox.com/1/metadata"
+API_INFO_URL="https://api.dropbox.com/1/account/info"
+API_MKDIR_URL="https://api.dropbox.com/1/fileops/create_folder"
+API_SHARES_URL="https://api.dropbox.com/1/shares"
+APP_CREATE_URL="https://www2.dropbox.com/developers/apps"
+RESPONSE_FILE="$TMP_DIR/du_resp_$RANDOM"
+CHUNK_FILE="$TMP_DIR/du_chunk_$RANDOM"
+TEMP_FILE="$TMP_DIR/du_tmp_$RANDOM"
+BIN_DEPS="sed basename date grep stat dd mkdir"
+VERSION="0.14"
+
+umask 077
+
+#Check the shell
+if [ -z "$BASH_VERSION" ]; then
+    echo -e "Error: this script requires the BASH shell!"
+    exit 1
+fi
+
+shopt -s nullglob #Bash allows filename patterns which match no files to expand to a null string, rather than themselves
+shopt -s dotglob  #Bash includes filenames beginning with a "." in the results of filename expansion
+
+#Look for optional config file parameter
+while getopts ":qpskdf:" opt; do
+    case $opt in
+
+    f)
+      CONFIG_FILE=$OPTARG
+    ;;
+
+    d)
+      DEBUG=1
+    ;;
+
+    q)
+      QUIET=1
+    ;;
+
+    p)
+      SHOW_PROGRESSBAR=1
+    ;;
+
+    k)
+      CURL_ACCEPT_CERTIFICATES="-k"
+    ;;
+
+    s)
+      SKIP_EXISTING_FILES=1
+    ;;
+
+    \?)
+      echo "Invalid option: -$OPTARG" >&2
+      exit 1
+    ;;
+
+    :)
+      echo "Option -$OPTARG requires an argument." >&2
+      exit 1
+    ;;
+
+  esac
+done
+
+if [[ $DEBUG != 0 ]]; then
+    echo $VERSION
+    set -x
+    RESPONSE_FILE="$TMP_DIR/du_resp_debug"
+fi
+
+if [[ $CURL_BIN == "" ]]; then
+    BIN_DEPS="$BIN_DEPS curl"
+    CURL_BIN="curl"
+fi
+
+#Dependencies check
+which $BIN_DEPS > /dev/null
+if [[ $? != 0 ]]; then
+    for i in $BIN_DEPS; do
+        which $i > /dev/null ||
+            NOT_FOUND="$i $NOT_FOUND"
+    done
+    echo -e "Error: Required program could not be found: $NOT_FOUND"
+    exit 1
+fi
+
+#Check if readlink is installed and supports the -m option
+#It's not necessary, so no problem if it's not installed
+which readlink > /dev/null
+if [[ $? == 0 && $(readlink -m "//test" 2> /dev/null) == "/test" ]]; then
+    HAVE_READLINK=1
+else
+    HAVE_READLINK=0
+fi
+
+#Forcing to use the builtin printf, if it's present, because it's better
+#otherwise the external printf program will be used
+#Note that the external printf command can cause character encoding issues!
+builtin printf "" 2> /dev/null
+if [[ $? == 0 ]]; then
+    PRINTF="builtin printf"
+    PRINTF_OPT="-v o"
+else
+    PRINTF=$(which printf)
+    if [[ $? != 0 ]]; then
+        echo -e "Error: Required program could not be found: printf"
+    fi
+    PRINTF_OPT=""
+fi
+
+#Print the message based on $QUIET variable
+function print
+{
+    if [[ $QUIET == 0 ]]; then
+	    echo -ne "$1";
+    fi
+}
+
+#Returns unix timestamp
+function utime
+{
+    echo $(date +%s)
+}
+
+#Remove temporary files
+function remove_temp_files
+{
+    if [[ $DEBUG == 0 ]]; then
+        rm -fr "$RESPONSE_FILE"
+        rm -fr "$CHUNK_FILE"
+        rm -fr "$TEMP_FILE"
+    fi
+}
+
+#Returns the file size in bytes
+# generic GNU Linux: linux-gnu
+# windows cygwin:    cygwin
+# raspberry pi:      linux-gnueabihf
+# macosx:            darwin10.0
+# freebsd:           FreeBSD
+# qnap:              linux-gnueabi
+# iOS:               darwin9
+function file_size
+{
+    #Some embedded linux devices
+    if [[ $OSTYPE == "linux-gnueabi" || $OSTYPE == "linux-gnu" ]]; then
+        stat -c "%s" "$1"
+        return
+
+    #Generic Unix
+    elif [[ ${OSTYPE:0:5} == "linux" || $OSTYPE == "cygwin" || ${OSTYPE:0:7} == "solaris" ]]; then
+        stat --format="%s" "$1"
+        return
+
+    #BSD, OSX and other OSs
+    else
+        stat -f "%z" "$1"
+        return
+    fi
+}
+
+#Usage
+function usage
+{
+    echo -e "Dropbox Uploader v$VERSION"
+    echo -e "Andrea Fabrizi - [email protected]\n"
+    echo -e "Usage: $0 COMMAND [PARAMETERS]..."
+    echo -e "\nCommands:"
+
+    echo -e "\t upload   <LOCAL_FILE/DIR ...>  <REMOTE_FILE/DIR>"
+    echo -e "\t download <REMOTE_FILE/DIR> [LOCAL_FILE/DIR]"
+    echo -e "\t delete   <REMOTE_FILE/DIR>"
+    echo -e "\t move     <REMOTE_FILE/DIR> <REMOTE_FILE/DIR>"
+    echo -e "\t copy     <REMOTE_FILE/DIR> <REMOTE_FILE/DIR>"
+    echo -e "\t mkdir    <REMOTE_DIR>"
+    echo -e "\t list     [REMOTE_DIR]"
+    echo -e "\t share    <REMOTE_FILE>"
+    echo -e "\t info"
+    echo -e "\t unlink"
+
+    echo -e "\nOptional parameters:"
+    echo -e "\t-f <FILENAME> Load the configuration file from a specific file"
+    echo -e "\t-s            Skip already existing files when download/upload. Default: Overwrite"
+    echo -e "\t-d            Enable DEBUG mode"
+    echo -e "\t-q            Quiet mode. Don't show messages"
+    echo -e "\t-p            Show cURL progress meter"
+    echo -e "\t-k            Doesn't check for SSL certificates (insecure)"
+
+    echo -en "\nFor more info and examples, please see the README file.\n\n"
+    remove_temp_files
+    exit 1
+}
+
+#Check the curl exit code
+function check_http_response
+{
+    CODE=$?
+
+    #Checking curl exit code
+    case $CODE in
+
+        #OK
+        0)
+
+        ;;
+
+        #Proxy error
+        5)
+            print "\nError: Couldn't resolve proxy. The given proxy host could not be resolved.\n"
+
+            remove_temp_files
+            exit 1
+        ;;
+
+        #Missing CA certificates
+        60|58)
+            print "\nError: cURL is not able to performs peer SSL certificate verification.\n"
+            print "Please, install the default ca-certificates bundle.\n"
+            print "To do this in a Debian/Ubuntu based system, try:\n"
+            print "  sudo apt-get install ca-certificates\n\n"
+            print "If the problem persists, try to use the -k option (insecure).\n"
+
+            remove_temp_files
+            exit 1
+        ;;
+
+        6)
+            print "\nError: Couldn't resolve host.\n"
+
+            remove_temp_files
+            exit 1
+        ;;
+
+        7)
+            print "\nError: Couldn't connect to host.\n"
+
+            remove_temp_files
+            exit 1
+        ;;
+
+    esac
+
+    #Checking response file for generic errors
+    if grep -q "HTTP/1.1 400" "$RESPONSE_FILE"; then
+        ERROR_MSG=$(sed -n -e 's/{"error": "\([^"]*\)"}/\1/p' "$RESPONSE_FILE")
+
+        case $ERROR_MSG in
+             *access?attempt?failed?because?this?app?is?not?configured?to?have*)
+                echo -e "\nError: The Permission type/Access level configured doesn't match the DropBox App settings!\nPlease run \"$0 unlink\" and try again."
+                exit 1
+            ;;
+        esac
+
+    fi
+
+}
+
+#Urlencode
+function urlencode
+{
+    local string="${1}"
+    local strlen=${#string}
+    local encoded=""
+
+    for (( pos=0 ; pos<strlen ; pos++ )); do
+        c=${string:$pos:1}
+        case "$c" in
+            [-_.~a-zA-Z0-9] ) o="${c}" ;;
+            * ) $PRINTF $PRINTF_OPT '%%%02x' "'$c"
+        esac
+        encoded+="${o}"
+    done
+
+    echo "$encoded"
+}
+
+function normalize_path
+{
+    path=$(echo -e "$1")
+    if [[ $HAVE_READLINK == 1 ]]; then
+        new_path=$(readlink -m "$path")
+
+        #Adding back the final slash, if present in the source
+        if [[ "${path: -1}" == "/" ]]; then
+            new_path="$new_path/"
+        fi
+
+        echo "$new_path"
+    else
+        echo "$path"
+    fi
+}
+
+#Check if it's a file or directory
+#Returns FILE/DIR/ERR
+function db_stat
+{
+    local FILE=$(normalize_path "$1")
+
+    #Checking if it's a file or a directory
+    $CURL_BIN $CURL_ACCEPT_CERTIFICATES -s --show-error --globoff -i -o "$RESPONSE_FILE" "$API_METADATA_URL/$ACCESS_LEVEL/$(urlencode "$FILE")?oauth_consumer_key=$APPKEY&oauth_token=$OAUTH_ACCESS_TOKEN&oauth_signature_method=PLAINTEXT&oauth_signature=$APPSECRET%26$OAUTH_ACCESS_TOKEN_SECRET&oauth_timestamp=$(utime)&oauth_nonce=$RANDOM" 2> /dev/null
+    check_http_response
+
+    #Even if the file/dir has been deleted from DropBox we receive a 200 OK response
+    #So we must check if the file exists or if it has been deleted
+    if grep -q "\"is_deleted\":" "$RESPONSE_FILE"; then
+        local IS_DELETED=$(sed -n 's/.*"is_deleted":.\([^,]*\).*/\1/p' "$RESPONSE_FILE")
+    else
+        local IS_DELETED="false"
+    fi
+
+    #Exits...
+    grep -q "^HTTP/1.1 200 OK" "$RESPONSE_FILE"
+    if [[ $? == 0 && $IS_DELETED != "true" ]]; then
+
+        local IS_DIR=$(sed -n 's/^\(.*\)\"contents":.\[.*/\1/p' "$RESPONSE_FILE")
+
+        #It's a directory
+        if [[ $IS_DIR != "" ]]; then
+            echo "DIR"
+        #It's a file
+        else
+            echo "FILE"
+        fi
+
+    #Doesn't exists
+    else
+        echo "ERR"
+    fi
+}
+
+#Generic upload wrapper around db_upload_file and db_upload_dir functions
+#$1 = Local source file/dir
+#$2 = Remote destination file/dir
+function db_upload
+{
+    local SRC=$(normalize_path "$1")
+    local DST=$(normalize_path "$2")
+
+    #Checking if the file/dir exists
+    if [[ ! -e $SRC && ! -d $SRC ]]; then
+        print " > No such file or directory: $SRC\n"
+        ERROR_STATUS=1
+        return
+    fi
+
+    #Checking if the file/dir has read permissions
+    if [[ ! -r $SRC ]]; then
+        print " > Error reading file $SRC: permission denied\n"
+        ERROR_STATUS=1
+        return
+    fi
+
+    TYPE=$(db_stat "$DST")
+
+    #If DST it's a file, do nothing, it's the default behaviour
+    if [[ $TYPE == "FILE" ]]; then
+        DST="$DST"
+
+    #if DST doesn't exists and doesn't ends with a /, it will be the destination file name
+    elif [[ $TYPE == "ERR" && "${DST: -1}" != "/" ]]; then
+        DST="$DST"
+
+    #if DST doesn't exists and ends with a /, it will be the destination folder
+    elif [[ $TYPE == "ERR" && "${DST: -1}" == "/" ]]; then
+        local filename=$(basename "$SRC")
+        DST="$DST/$filename"
+
+    #If DST it'a directory, it will be the destination folder
+    elif [[ $TYPE == "DIR" ]]; then
+        local filename=$(basename "$SRC")
+        DST="$DST/$filename"
+    fi
+
+    #It's a directory
+    if [[ -d $SRC ]]; then
+        db_upload_dir "$SRC" "$DST"
+
+    #It's a file
+    elif [[ -e $SRC ]]; then
+        db_upload_file "$SRC" "$DST"
+
+    #Unsupported object...
+    else
+        print " > Skipping not regular file \"$SRC\"\n"
+    fi
+}
+
+#Generic upload wrapper around db_chunked_upload_file and db_simple_upload_file
+#The final upload function will be choosen based on the file size
+#$1 = Local source file
+#$2 = Remote destination file
+function db_upload_file
+{
+    local FILE_SRC=$(normalize_path "$1")
+    local FILE_DST=$(normalize_path "$2")
+
+    shopt -s nocasematch
+
+    #Checking not allowed file names
+    basefile_dst=$(basename "$FILE_DST")
+    if [[ $basefile_dst == "thumbs.db" || \
+          $basefile_dst == "desktop.ini" || \
+          $basefile_dst == ".ds_store" || \
+          $basefile_dst == "icon\r" || \
+          $basefile_dst == ".dropbox" || \
+          $basefile_dst == ".dropbox.attr" \
+       ]]; then
+        print " > Skipping not allowed file name \"$FILE_DST\"\n"
+        return
+    fi
+
+    shopt -u nocasematch
+
+    #Checking file size
+    FILE_SIZE=$(file_size "$FILE_SRC")
+
+    #Checking if the file already exists
+    TYPE=$(db_stat "$FILE_DST")
+    if [[ $TYPE != "ERR" && $SKIP_EXISTING_FILES == 1 ]]; then
+        print " > Skipping already existing file \"$FILE_DST\"\n"
+        return
+    fi
+
+    if [[ $FILE_SIZE -gt 157286000 ]]; then
+        #If the file is greater than 150Mb, the chunked_upload API will be used
+        db_chunked_upload_file "$FILE_SRC" "$FILE_DST"
+    else
+        db_simple_upload_file "$FILE_SRC" "$FILE_DST"
+    fi
+
+}
+
+#Simple file upload
+#$1 = Local source file
+#$2 = Remote destination file
+function db_simple_upload_file
+{
+    local FILE_SRC=$(normalize_path "$1")
+    local FILE_DST=$(normalize_path "$2")
+
+    if [[ $SHOW_PROGRESSBAR == 1 && $QUIET == 0 ]]; then
+        CURL_PARAMETERS="--progress-bar"
+        LINE_CR="\n"
+    else
+        CURL_PARAMETERS="-s"
+        LINE_CR=""
+    fi
+
+    print " > Uploading \"$FILE_SRC\" to \"$FILE_DST\"... $LINE_CR"
+    $CURL_BIN $CURL_ACCEPT_CERTIFICATES $CURL_PARAMETERS -i --globoff -o "$RESPONSE_FILE" --upload-file "$FILE_SRC" "$API_UPLOAD_URL/$ACCESS_LEVEL/$(urlencode "$FILE_DST")?oauth_consumer_key=$APPKEY&oauth_token=$OAUTH_ACCESS_TOKEN&oauth_signature_method=PLAINTEXT&oauth_signature=$APPSECRET%26$OAUTH_ACCESS_TOKEN_SECRET&oauth_timestamp=$(utime)&oauth_nonce=$RANDOM"
+    check_http_response
+
+    #Check
+    if grep -q "^HTTP/1.1 200 OK" "$RESPONSE_FILE"; then
+        print "DONE\n"
+    else
+        print "FAILED\n"
+        print "An error occurred requesting /upload\n"
+        ERROR_STATUS=1
+    fi
+}
+
+#Chunked file upload
+#$1 = Local source file
+#$2 = Remote destination file
+function db_chunked_upload_file
+{
+    local FILE_SRC=$(normalize_path "$1")
+    local FILE_DST=$(normalize_path "$2")
+
+    print " > Uploading \"$FILE_SRC\" to \"$FILE_DST\""
+
+    local FILE_SIZE=$(file_size "$FILE_SRC")
+    local OFFSET=0
+    local UPLOAD_ID=""
+    local UPLOAD_ERROR=0
+    local CHUNK_PARAMS=""
+
+    #Uploading chunks...
+    while ([[ $OFFSET != $FILE_SIZE ]]); do
+
+        let OFFSET_MB=$OFFSET/1024/1024
+
+        #Create the chunk
+        dd if="$FILE_SRC" of="$CHUNK_FILE" bs=1048576 skip=$OFFSET_MB count=$CHUNK_SIZE 2> /dev/null
+
+        #Only for the first request these parameters are not included
+        if [[ $OFFSET != 0 ]]; then
+            CHUNK_PARAMS="upload_id=$UPLOAD_ID&offset=$OFFSET"
+        fi
+
+        #Uploading the chunk...
+        $CURL_BIN $CURL_ACCEPT_CERTIFICATES -s --show-error --globoff -i -o "$RESPONSE_FILE" --upload-file "$CHUNK_FILE" "$API_CHUNKED_UPLOAD_URL?$CHUNK_PARAMS&oauth_consumer_key=$APPKEY&oauth_token=$OAUTH_ACCESS_TOKEN&oauth_signature_method=PLAINTEXT&oauth_signature=$APPSECRET%26$OAUTH_ACCESS_TOKEN_SECRET&oauth_timestamp=$(utime)&oauth_nonce=$RANDOM" 2> /dev/null
+        check_http_response
+
+        #Check
+        if grep -q "^HTTP/1.1 200 OK" "$RESPONSE_FILE"; then
+            print "."
+            UPLOAD_ERROR=0
+            UPLOAD_ID=$(sed -n 's/.*"upload_id": *"*\([^"]*\)"*.*/\1/p' "$RESPONSE_FILE")
+            OFFSET=$(sed -n 's/.*"offset": *\([^}]*\).*/\1/p' "$RESPONSE_FILE")
+        else
+            print "*"
+            let UPLOAD_ERROR=$UPLOAD_ERROR+1
+
+            #On error, the upload is retried for max 3 times
+            if [[ $UPLOAD_ERROR -gt 2 ]]; then
+                print " FAILED\n"
+                print "An error occurred requesting /chunked_upload\n"
+                ERROR_STATUS=1
+                return
+            fi
+        fi
+
+    done
+
+    UPLOAD_ERROR=0
+
+    #Commit the upload
+    while (true); do
+
+        $CURL_BIN $CURL_ACCEPT_CERTIFICATES -s --show-error --globoff -i -o "$RESPONSE_FILE" --data "upload_id=$UPLOAD_ID&oauth_consumer_key=$APPKEY&oauth_token=$OAUTH_ACCESS_TOKEN&oauth_signature_method=PLAINTEXT&oauth_signature=$APPSECRET%26$OAUTH_ACCESS_TOKEN_SECRET&oauth_timestamp=$(utime)&oauth_nonce=$RANDOM" "$API_CHUNKED_UPLOAD_COMMIT_URL/$ACCESS_LEVEL/$(urlencode "$FILE_DST")" 2> /dev/null
+        check_http_response
+
+        #Check
+        if grep -q "^HTTP/1.1 200 OK" "$RESPONSE_FILE"; then
+            print "."
+            UPLOAD_ERROR=0
+            break
+        else
+            print "*"
+            let UPLOAD_ERROR=$UPLOAD_ERROR+1
+
+            #On error, the commit is retried for max 3 times
+            if [[ $UPLOAD_ERROR -gt 2 ]]; then
+                print " FAILED\n"
+                print "An error occurred requesting /commit_chunked_upload\n"
+                ERROR_STATUS=1
+                return
+            fi
+        fi
+
+    done
+
+    print " DONE\n"
+}
+
+#Directory upload
+#$1 = Local source dir
+#$2 = Remote destination dir
+function db_upload_dir
+{
+    local DIR_SRC=$(normalize_path "$1")
+    local DIR_DST=$(normalize_path "$2")
+
+    #Creatig remote directory
+    db_mkdir "$DIR_DST"
+
+    for file in "$DIR_SRC/"*; do
+        db_upload "$file" "$DIR_DST"
+    done
+}
+
+#Returns the free space on DropBox in bytes
+function db_free_quota
+{
+    $CURL_BIN $CURL_ACCEPT_CERTIFICATES -s --show-error --globoff -i -o "$RESPONSE_FILE" --data "oauth_consumer_key=$APPKEY&oauth_token=$OAUTH_ACCESS_TOKEN&oauth_signature_method=PLAINTEXT&oauth_signature=$APPSECRET%26$OAUTH_ACCESS_TOKEN_SECRET&oauth_timestamp=$(utime)&oauth_nonce=$RANDOM" "$API_INFO_URL" 2> /dev/null
+    check_http_response
+
+    #Check
+    if grep -q "^HTTP/1.1 200 OK" "$RESPONSE_FILE"; then
+
+        quota=$(sed -n 's/.*"quota": \([0-9]*\).*/\1/p' "$RESPONSE_FILE")
+        used=$(sed -n 's/.*"normal": \([0-9]*\).*/\1/p' "$RESPONSE_FILE")
+        let free_quota=$quota-$used
+        echo $free_quota
+
+    else
+        echo 0
+    fi
+}
+
+#Generic download wrapper
+#$1 = Remote source file/dir
+#$2 = Local destination file/dir
+function db_download
+{
+    local SRC=$(normalize_path "$1")
+    local DST=$(normalize_path "$2")
+
+    TYPE=$(db_stat "$SRC")
+
+    #It's a directory
+    if [[ $TYPE == "DIR" ]]; then
+
+        #If the DST folder is not specified, I assume that is the current directory
+        if [[ $DST == "" ]]; then
+            DST="."
+        fi
+
+        #Checking if the destination directory exists
+        if [[ ! -d $DST ]]; then
+            local basedir=""
+        else
+            local basedir=$(basename "$SRC")
+        fi
+
+        local DEST_DIR=$(normalize_path "$DST/$basedir")
+        print " > Downloading \"$SRC\" to \"$DEST_DIR\"... \n"
+        print " > Creating local directory \"$DEST_DIR\"... "
+        mkdir -p "$DEST_DIR"
+
+        #Check
+        if [[ $? == 0 ]]; then
+            print "DONE\n"
+        else
+            print "FAILED\n"
+            ERROR_STATUS=1
+            return
+        fi
+
+        #Extracting directory content [...]
+        #and replacing "}, {" with "}\n{"
+        #I don't like this piece of code... but seems to be the only way to do this with SED, writing a portable code...
+        local DIR_CONTENT=$(sed -n 's/.*: \[{\(.*\)/\1/p' "$RESPONSE_FILE" | sed 's/}, *{/}\
+{/g')
+
+        #Extracting files and subfolders
+        TMP_DIR_CONTENT_FILE="${RESPONSE_FILE}_$RANDOM"
+        echo "$DIR_CONTENT" | sed -n 's/.*"path": *"\([^"]*\)",.*"is_dir": *\([^"]*\),.*/\1:\2/p' > $TMP_DIR_CONTENT_FILE
+
+        #For each entry...
+        while read -r line; do
+
+            local FILE=${line%:*}
+            local TYPE=${line#*:}
+
+            #Removing unneeded /
+            FILE=${FILE##*/}
+
+            if [[ $TYPE == "false" ]]; then
+                db_download_file "$SRC/$FILE" "$DEST_DIR/$FILE"
+            else
+                db_download "$SRC/$FILE" "$DEST_DIR"
+            fi
+
+        done < $TMP_DIR_CONTENT_FILE
+
+        rm -fr $TMP_DIR_CONTENT_FILE
+
+    #It's a file
+    elif [[ $TYPE == "FILE" ]]; then
+
+        #Checking DST
+        if [[ $DST == "" ]]; then
+            DST=$(basename "$SRC")
+        fi
+
+        #If the destination is a directory, the file will be download into
+        if [[ -d $DST ]]; then
+            DST="$DST/$SRC"
+        fi
+
+        db_download_file "$SRC" "$DST"
+
+    #Doesn't exists
+    else
+        print " > No such file or directory: $SRC\n"
+        ERROR_STATUS=1
+        return
+    fi
+}
+
+#Simple file download
+#$1 = Remote source file
+#$2 = Local destination file
+function db_download_file
+{
+    local FILE_SRC=$(normalize_path "$1")
+    local FILE_DST=$(normalize_path "$2")
+
+    if [[ $SHOW_PROGRESSBAR == 1 && $QUIET == 0 ]]; then
+        CURL_PARAMETERS="--progress-bar"
+        LINE_CR="\n"
+    else
+        CURL_PARAMETERS="-s"
+        LINE_CR=""
+    fi
+
+    #Checking if the file already exists
+    if [[ -e $FILE_DST && $SKIP_EXISTING_FILES == 1 ]]; then
+        print " > Skipping already existing file \"$FILE_DST\"\n"
+        return
+    fi
+
+    #Creating the empty file, that for two reasons:
+    #1) In this way I can check if the destination file is writable or not
+    #2) Curl doesn't automatically creates files with 0 bytes size
+    dd if=/dev/zero of="$FILE_DST" count=0 2> /dev/null
+    if [[ $? != 0 ]]; then
+        print " > Error writing file $FILE_DST: permission denied\n"
+        ERROR_STATUS=1
+        return
+    fi
+
+    print " > Downloading \"$FILE_SRC\" to \"$FILE_DST\"... $LINE_CR"
+    $CURL_BIN $CURL_ACCEPT_CERTIFICATES $CURL_PARAMETERS --globoff -D "$RESPONSE_FILE" -o "$FILE_DST" "$API_DOWNLOAD_URL/$ACCESS_LEVEL/$(urlencode "$FILE_SRC")?oauth_consumer_key=$APPKEY&oauth_token=$OAUTH_ACCESS_TOKEN&oauth_signature_method=PLAINTEXT&oauth_signature=$APPSECRET%26$OAUTH_ACCESS_TOKEN_SECRET&oauth_timestamp=$(utime)&oauth_nonce=$RANDOM"
+    check_http_response
+
+    #Check
+    if grep -q "^HTTP/1.1 200 OK" "$RESPONSE_FILE"; then
+        print "DONE\n"
+    else
+        print "FAILED\n"
+        rm -fr "$FILE_DST"
+        ERROR_STATUS=1
+        return
+    fi
+}
+
+#Prints account info
+function db_account_info
+{
+    print "Dropbox Uploader v$VERSION\n\n"
+    print " > Getting info... "
+    $CURL_BIN $CURL_ACCEPT_CERTIFICATES -s --show-error --globoff -i -o "$RESPONSE_FILE" --data "oauth_consumer_key=$APPKEY&oauth_token=$OAUTH_ACCESS_TOKEN&oauth_signature_method=PLAINTEXT&oauth_signature=$APPSECRET%26$OAUTH_ACCESS_TOKEN_SECRET&oauth_timestamp=$(utime)&oauth_nonce=$RANDOM" "$API_INFO_URL" 2> /dev/null
+    check_http_response
+
+    #Check
+    if grep -q "^HTTP/1.1 200 OK" "$RESPONSE_FILE"; then
+
+        name=$(sed -n 's/.*"display_name": "\([^"]*\).*/\1/p' "$RESPONSE_FILE")
+        echo -e "\n\nName:\t$name"
+
+        uid=$(sed -n 's/.*"uid": \([0-9]*\).*/\1/p' "$RESPONSE_FILE")
+        echo -e "UID:\t$uid"
+
+        email=$(sed -n 's/.*"email": "\([^"]*\).*/\1/p' "$RESPONSE_FILE")
+        echo -e "Email:\t$email"
+
+        quota=$(sed -n 's/.*"quota": \([0-9]*\).*/\1/p' "$RESPONSE_FILE")
+        let quota_mb=$quota/1024/1024
+        echo -e "Quota:\t$quota_mb Mb"
+
+        used=$(sed -n 's/.*"normal": \([0-9]*\).*/\1/p' "$RESPONSE_FILE")
+        let used_mb=$used/1024/1024
+        echo -e "Used:\t$used_mb Mb"
+
+        let free_mb=($quota-$used)/1024/1024
+        echo -e "Free:\t$free_mb Mb"
+
+        echo ""
+
+    else
+        print "FAILED\n"
+        ERROR_STATUS=1
+    fi
+}
+
+#Account unlink
+function db_unlink
+{
+    echo -ne "Are you sure you want unlink this script from your Dropbox account? [y/n]"
+    read answer
+    if [[ $answer == "y" ]]; then
+        rm -fr "$CONFIG_FILE"
+        echo -ne "DONE\n"
+    fi
+}
+
+#Delete a remote file
+#$1 = Remote file to delete
+function db_delete
+{
+    local FILE_DST=$(normalize_path "$1")
+
+    print " > Deleting \"$FILE_DST\"... "
+    $CURL_BIN $CURL_ACCEPT_CERTIFICATES -s --show-error --globoff -i -o "$RESPONSE_FILE" --data "oauth_consumer_key=$APPKEY&oauth_token=$OAUTH_ACCESS_TOKEN&oauth_signature_method=PLAINTEXT&oauth_signature=$APPSECRET%26$OAUTH_ACCESS_TOKEN_SECRET&oauth_timestamp=$(utime)&oauth_nonce=$RANDOM&root=$ACCESS_LEVEL&path=$(urlencode "$FILE_DST")" "$API_DELETE_URL" 2> /dev/null
+    check_http_response
+
+    #Check
+    if grep -q "^HTTP/1.1 200 OK" "$RESPONSE_FILE"; then
+        print "DONE\n"
+    else
+        print "FAILED\n"
+        ERROR_STATUS=1
+    fi
+}
+
+#Move/Rename a remote file
+#$1 = Remote file to rename or move
+#$2 = New file name or location
+function db_move
+{
+    local FILE_SRC=$(normalize_path "$1")
+    local FILE_DST=$(normalize_path "$2")
+
+    TYPE=$(db_stat "$FILE_DST")
+
+    #If the destination it's a directory, the source will be moved into it
+    if [[ $TYPE == "DIR" ]]; then
+        local filename=$(basename "$FILE_SRC")
+        FILE_DST=$(normalize_path "$FILE_DST/$filename")
+    fi
+
+    print " > Moving \"$FILE_SRC\" to \"$FILE_DST\" ... "
+    $CURL_BIN $CURL_ACCEPT_CERTIFICATES -s --show-error --globoff -i -o "$RESPONSE_FILE" --data "oauth_consumer_key=$APPKEY&oauth_token=$OAUTH_ACCESS_TOKEN&oauth_signature_method=PLAINTEXT&oauth_signature=$APPSECRET%26$OAUTH_ACCESS_TOKEN_SECRET&oauth_timestamp=$(utime)&oauth_nonce=$RANDOM&root=$ACCESS_LEVEL&from_path=$(urlencode "$FILE_SRC")&to_path=$(urlencode "$FILE_DST")" "$API_MOVE_URL" 2> /dev/null
+    check_http_response
+
+    #Check
+    if grep -q "^HTTP/1.1 200 OK" "$RESPONSE_FILE"; then
+        print "DONE\n"
+    else
+        print "FAILED\n"
+        ERROR_STATUS=1
+    fi
+}
+
+#Copy a remote file to a remote location
+#$1 = Remote file to rename or move
+#$2 = New file name or location
+function db_copy
+{
+    local FILE_SRC=$(normalize_path "$1")
+    local FILE_DST=$(normalize_path "$2")
+
+    TYPE=$(db_stat "$FILE_DST")
+
+    #If the destination it's a directory, the source will be copied into it
+    if [[ $TYPE == "DIR" ]]; then
+        local filename=$(basename "$FILE_SRC")
+        FILE_DST=$(normalize_path "$FILE_DST/$filename")
+    fi
+
+    print " > Copying \"$FILE_SRC\" to \"$FILE_DST\" ... "
+    $CURL_BIN $CURL_ACCEPT_CERTIFICATES -s --show-error --globoff -i -o "$RESPONSE_FILE" --data "oauth_consumer_key=$APPKEY&oauth_token=$OAUTH_ACCESS_TOKEN&oauth_signature_method=PLAINTEXT&oauth_signature=$APPSECRET%26$OAUTH_ACCESS_TOKEN_SECRET&oauth_timestamp=$(utime)&oauth_nonce=$RANDOM&root=$ACCESS_LEVEL&from_path=$(urlencode "$FILE_SRC")&to_path=$(urlencode "$FILE_DST")" "$API_COPY_URL" 2> /dev/null
+    check_http_response
+
+    #Check
+    if grep -q "^HTTP/1.1 200 OK" "$RESPONSE_FILE"; then
+        print "DONE\n"
+    else
+        print "FAILED\n"
+        ERROR_STATUS=1
+    fi
+}
+
+#Create a new directory
+#$1 = Remote directory to create
+function db_mkdir
+{
+    local DIR_DST=$(normalize_path "$1")
+
+    print " > Creating Directory \"$DIR_DST\"... "
+    $CURL_BIN $CURL_ACCEPT_CERTIFICATES -s --show-error --globoff -i -o "$RESPONSE_FILE" --data "oauth_consumer_key=$APPKEY&oauth_token=$OAUTH_ACCESS_TOKEN&oauth_signature_method=PLAINTEXT&oauth_signature=$APPSECRET%26$OAUTH_ACCESS_TOKEN_SECRET&oauth_timestamp=$(utime)&oauth_nonce=$RANDOM&root=$ACCESS_LEVEL&path=$(urlencode "$DIR_DST")" "$API_MKDIR_URL" 2> /dev/null
+    check_http_response
+
+    #Check
+    if grep -q "^HTTP/1.1 200 OK" "$RESPONSE_FILE"; then
+        print "DONE\n"
+    elif grep -q "^HTTP/1.1 403 Forbidden" "$RESPONSE_FILE"; then
+        print "ALREADY EXISTS\n"
+    else
+        print "FAILED\n"
+        ERROR_STATUS=1
+    fi
+}
+
+#List remote directory
+#$1 = Remote directory
+function db_list
+{
+    local DIR_DST=$(normalize_path "$1")
+
+    print " > Listing \"$DIR_DST\"... "
+    $CURL_BIN $CURL_ACCEPT_CERTIFICATES -s --show-error --globoff -i -o "$RESPONSE_FILE" "$API_METADATA_URL/$ACCESS_LEVEL/$(urlencode "$DIR_DST")?oauth_consumer_key=$APPKEY&oauth_token=$OAUTH_ACCESS_TOKEN&oauth_signature_method=PLAINTEXT&oauth_signature=$APPSECRET%26$OAUTH_ACCESS_TOKEN_SECRET&oauth_timestamp=$(utime)&oauth_nonce=$RANDOM" 2> /dev/null
+    check_http_response
+
+    #Check
+    if grep -q "^HTTP/1.1 200 OK" "$RESPONSE_FILE"; then
+
+        local IS_DIR=$(sed -n 's/^\(.*\)\"contents":.\[.*/\1/p' "$RESPONSE_FILE")
+
+        #It's a directory
+        if [[ $IS_DIR != "" ]]; then
+
+            print "DONE\n"
+
+            #Extracting directory content [...]
+            #and replacing "}, {" with "}\n{"
+            #I don't like this piece of code... but seems to be the only way to do this with SED, writing a portable code...
+            local DIR_CONTENT=$(sed -n 's/.*: \[{\(.*\)/\1/p' "$RESPONSE_FILE" | sed 's/}, *{/}\
+{/g')
+
+            #Converting escaped quotes to unicode format
+            echo "$DIR_CONTENT" | sed 's/\\"/\\u0022/' > "$TEMP_FILE"
+
+            #Extracting files and subfolders
+            rm -fr "$RESPONSE_FILE"
+            while read -r line; do
+
+                local FILE=$(echo "$line" | sed -n 's/.*"path": *"\([^"]*\)".*/\1/p')
+                local IS_DIR=$(echo "$line" | sed -n 's/.*"is_dir": *\([^,]*\).*/\1/p')
+                local SIZE=$(echo "$line" | sed -n 's/.*"bytes": *\([0-9]*\).*/\1/p')
+
+                echo -e "$FILE:$IS_DIR;$SIZE" >> "$RESPONSE_FILE"
+
+            done < "$TEMP_FILE"
+
+            #Looking for the biggest file size
+            #to calculate the padding to use
+            local padding=0
+            while read -r line; do
+                local FILE=${line%:*}
+                local META=${line##*:}
+                local SIZE=${META#*;}
+
+                if [[ ${#SIZE} -gt $padding ]]; then
+                    padding=${#SIZE}
+                fi
+            done < "$RESPONSE_FILE"
+
+            #For each entry, printing directories...
+            while read -r line; do
+
+                local FILE=${line%:*}
+                local META=${line##*:}
+                local TYPE=${META%;*}
+                local SIZE=${META#*;}
+
+                #Removing unneeded /
+                FILE=${FILE##*/}
+
+                if [[ $TYPE == "true" ]]; then
+                    FILE=$(echo -e "$FILE")
+                    $PRINTF " [D] %-${padding}s %s\n" "$SIZE" "$FILE"
+                fi
+
+            done < "$RESPONSE_FILE"
+
+            #For each entry, printing files...
+            while read -r line; do
+
+                local FILE=${line%:*}
+                local META=${line##*:}
+                local TYPE=${META%;*}
+                local SIZE=${META#*;}
+
+                #Removing unneeded /
+                FILE=${FILE##*/}
+
+                if [[ $TYPE == "false" ]]; then
+                    FILE=$(echo -e "$FILE")
+                    $PRINTF " [F] %-${padding}s %s\n" "$SIZE" "$FILE"
+                fi
+
+            done < "$RESPONSE_FILE"
+
+        #It's a file
+        else
+            print "FAILED: $DIR_DST is not a directory!\n"
+            ERROR_STATUS=1
+        fi
+
+    else
+        print "FAILED\n"
+        ERROR_STATUS=1
+    fi
+}
+
+#Share remote file
+#$1 = Remote file
+function db_share
+{
+    local FILE_DST=$(normalize_path "$1")
+
+    $CURL_BIN $CURL_ACCEPT_CERTIFICATES -s --show-error --globoff -i -o "$RESPONSE_FILE" "$API_SHARES_URL/$ACCESS_LEVEL/$(urlencode "$FILE_DST")?oauth_consumer_key=$APPKEY&oauth_token=$OAUTH_ACCESS_TOKEN&oauth_signature_method=PLAINTEXT&oauth_signature=$APPSECRET%26$OAUTH_ACCESS_TOKEN_SECRET&oauth_timestamp=$(utime)&oauth_nonce=$RANDOM&short_url=false" 2> /dev/null
+    check_http_response
+
+    #Check
+    if grep -q "^HTTP/1.1 200 OK" "$RESPONSE_FILE"; then
+        print " > Share link: "
+        SHARE_LINK=$(sed -n 's/.*"url": "\([^"]*\).*/\1/p' "$RESPONSE_FILE")
+        echo "$SHARE_LINK"
+    else
+        print "FAILED\n"
+        ERROR_STATUS=1
+    fi
+}
+
+################
+#### SETUP  ####
+################
+
+#CHECKING FOR AUTH FILE
+if [[ -e $CONFIG_FILE ]]; then
+
+    #Loading data... and change old format config if necesary.
+    source "$CONFIG_FILE" 2>/dev/null || {
+        sed -i'' 's/:/=/' "$CONFIG_FILE" && source "$CONFIG_FILE" 2>/dev/null
+    }
+
+    #Checking the loaded data
+    if [[ $APPKEY == "" || $APPSECRET == "" || $OAUTH_ACCESS_TOKEN_SECRET == "" || $OAUTH_ACCESS_TOKEN == "" ]]; then
+        echo -ne "Error loading data from $CONFIG_FILE...\n"
+        echo -ne "It is recommended to run $0 unlink\n"
+        remove_temp_files
+        exit 1
+    fi
+
+    #Back compatibility with previous Dropbox Uploader versions
+    if [[ $ACCESS_LEVEL == "" ]]; then
+        ACCESS_LEVEL="dropbox"
+    fi
+
+#NEW SETUP...
+else
+
+    echo -ne "\n This is the first time you run this script.\n\n"
+    echo -ne " 1) Open the following URL in your Browser, and log in using your account: $APP_CREATE_URL\n"
+    echo -ne " 2) Click on \"Create App\", then select \"Dropbox API app\"\n"
+    echo -ne " 3) Select \"Files and datastores\"\n"
+    echo -ne " 4) Now go on with the configuration, choosing the app permissions and access restrictions to your DropBox folder\n"
+    echo -ne " 5) Enter the \"App Name\" that you prefer (e.g. MyUploader$RANDOM$RANDOM$RANDOM)\n\n"
+
+    echo -ne " Now, click on the \"Create App\" button.\n\n"
+
+    echo -ne " When your new App is successfully created, please type the\n"
+    echo -ne " App Key, App Secret and the Permission type shown in the confirmation page:\n\n"
+
+    #Getting the app key and secret from the user
+    while (true); do
+
+        echo -n " # App key: "
+        read APPKEY
+
+        echo -n " # App secret: "
+        read APPSECRET
+
+        echo -n " # Permission type, App folder or Full Dropbox [a/f]: "
+        read ACCESS_LEVEL
+
+        if [[ $ACCESS_LEVEL == "a" ]]; then
+            ACCESS_LEVEL="sandbox"
+            ACCESS_MSG="App Folder"
+        else
+            ACCESS_LEVEL="dropbox"
+            ACCESS_MSG="Full Dropbox"
+        fi
+
+        echo -ne "\n > App key is $APPKEY, App secret is $APPSECRET and Access level is $ACCESS_MSG. Looks ok? [y/n]: "
+        read answer
+        if [[ $answer == "y" ]]; then
+            break;
+        fi
+
+    done
+
+    #TOKEN REQUESTS
+    echo -ne "\n > Token request... "
+    $CURL_BIN $CURL_ACCEPT_CERTIFICATES -s --show-error --globoff -i -o "$RESPONSE_FILE" --data "oauth_consumer_key=$APPKEY&oauth_signature_method=PLAINTEXT&oauth_signature=$APPSECRET%26&oauth_timestamp=$(utime)&oauth_nonce=$RANDOM" "$API_REQUEST_TOKEN_URL" 2> /dev/null
+    check_http_response
+    OAUTH_TOKEN_SECRET=$(sed -n 's/oauth_token_secret=\([a-z A-Z 0-9]*\).*/\1/p' "$RESPONSE_FILE")
+    OAUTH_TOKEN=$(sed -n 's/.*oauth_token=\([a-z A-Z 0-9]*\)/\1/p' "$RESPONSE_FILE")
+
+    if [[ $OAUTH_TOKEN != "" && $OAUTH_TOKEN_SECRET != "" ]]; then
+        echo -ne "OK\n"
+    else
+        echo -ne " FAILED\n\n Please, check your App key and secret...\n\n"
+        remove_temp_files
+        exit 1
+    fi
+
+    while (true); do
+
+        #USER AUTH
+        echo -ne "\n Please open the following URL in your browser, and allow Dropbox Uploader\n"
+        echo -ne " to access your DropBox folder:\n\n --> ${API_USER_AUTH_URL}?oauth_token=$OAUTH_TOKEN\n"
+        echo -ne "\nPress enter when done...\n"
+        read
+
+        #API_ACCESS_TOKEN_URL
+        echo -ne " > Access Token request... "
+        $CURL_BIN $CURL_ACCEPT_CERTIFICATES -s --show-error --globoff -i -o "$RESPONSE_FILE" --data "oauth_consumer_key=$APPKEY&oauth_token=$OAUTH_TOKEN&oauth_signature_method=PLAINTEXT&oauth_signature=$APPSECRET%26$OAUTH_TOKEN_SECRET&oauth_timestamp=$(utime)&oauth_nonce=$RANDOM" "$API_ACCESS_TOKEN_URL" 2> /dev/null
+        check_http_response
+        OAUTH_ACCESS_TOKEN_SECRET=$(sed -n 's/oauth_token_secret=\([a-z A-Z 0-9]*\)&.*/\1/p' "$RESPONSE_FILE")
+        OAUTH_ACCESS_TOKEN=$(sed -n 's/.*oauth_token=\([a-z A-Z 0-9]*\)&.*/\1/p' "$RESPONSE_FILE")
+        OAUTH_ACCESS_UID=$(sed -n 's/.*uid=\([0-9]*\)/\1/p' "$RESPONSE_FILE")
+
+        if [[ $OAUTH_ACCESS_TOKEN != "" && $OAUTH_ACCESS_TOKEN_SECRET != "" && $OAUTH_ACCESS_UID != "" ]]; then
+            echo -ne "OK\n"
+
+            #Saving data in new format, compatible with source command.
+            echo "APPKEY=$APPKEY" > "$CONFIG_FILE"
+            echo "APPSECRET=$APPSECRET" >> "$CONFIG_FILE"
+            echo "ACCESS_LEVEL=$ACCESS_LEVEL" >> "$CONFIG_FILE"
+            echo "OAUTH_ACCESS_TOKEN=$OAUTH_ACCESS_TOKEN" >> "$CONFIG_FILE"
+            echo "OAUTH_ACCESS_TOKEN_SECRET=$OAUTH_ACCESS_TOKEN_SECRET" >> "$CONFIG_FILE"
+
+            echo -ne "\n Setup completed!\n"
+            break
+        else
+            print " FAILED\n"
+            ERROR_STATUS=1
+        fi
+
+    done;
+
+    remove_temp_files
+    exit $ERROR_STATUS
+fi
+
+################
+#### START  ####
+################
+
+COMMAND=${@:$OPTIND:1}
+ARG1=${@:$OPTIND+1:1}
+ARG2=${@:$OPTIND+2:1}
+
+let argnum=$#-$OPTIND
+
+#CHECKING PARAMS VALUES
+case $COMMAND in
+
+    upload)
+
+        if [[ $argnum -lt 2 ]]; then
+            usage
+        fi
+
+        FILE_DST=${@:$#:1}
+
+        for (( i=$OPTIND+1; i<$#; i++ )); do
+            FILE_SRC=${@:$i:1}
+            db_upload "$FILE_SRC" "/$FILE_DST"
+        done
+
+    ;;
+
+    download)
+
+        if [[ $argnum -lt 1 ]]; then
+            usage
+        fi
+
+        FILE_SRC=$ARG1
+        FILE_DST=$ARG2
+
+        db_download "/$FILE_SRC" "$FILE_DST"
+
+    ;;
+
+    share)
+
+        if [[ $argnum -lt 1 ]]; then
+            usage
+        fi
+
+        FILE_DST=$ARG1
+
+        db_share "/$FILE_DST"
+
+    ;;
+
+    info)
+
+        db_account_info
+
+    ;;
+
+    delete|remove)
+
+        if [[ $argnum -lt 1 ]]; then
+            usage
+        fi
+
+        FILE_DST=$ARG1
+
+        db_delete "/$FILE_DST"
+
+    ;;
+
+    move|rename)
+
+        if [[ $argnum -lt 2 ]]; then
+            usage
+        fi
+
+        FILE_SRC=$ARG1
+        FILE_DST=$ARG2
+
+        db_move "/$FILE_SRC" "/$FILE_DST"
+
+    ;;
+
+    copy)
+
+        if [[ $argnum -lt 2 ]]; then
+            usage
+        fi
+
+        FILE_SRC=$ARG1
+        FILE_DST=$ARG2
+
+        db_copy "/$FILE_SRC" "/$FILE_DST"
+
+    ;;
+
+    mkdir)
+
+        if [[ $argnum -lt 1 ]]; then
+            usage
+        fi
+
+        DIR_DST=$ARG1
+
+        db_mkdir "/$DIR_DST"
+
+    ;;
+
+    list)
+
+        DIR_DST=$ARG1
+
+        #Checking DIR_DST
+        if [[ $DIR_DST == "" ]]; then
+            DIR_DST="/"
+        fi
+
+        db_list "/$DIR_DST"
+
+    ;;
+
+    unlink)
+
+        db_unlink
+
+    ;;
+
+    *)
+
+        if [[ $COMMAND != "" ]]; then
+            print "Error: Unknown command: $COMMAND\n\n"
+            ERROR_STATUS=1
+        fi
+        usage
+
+    ;;
+
+esac
+
+remove_temp_files
+exit $ERROR_STATUS
--- a/gitignore	Tue Sep 30 09:36:17 2014 +0200
+++ b/gitignore	Tue Sep 30 17:32:18 2014 +0200
@@ -78,3 +78,5 @@
 *.pdf
 
 .rake_tasks
+
+.sync