diff --git a/LICENSE b/LICENSE
new file mode 100644
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,24 @@
+Copyright (c) 2011, Daniel Trstenjak
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of the <organization> nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL DANIEL TRSTENJAK BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
diff --git a/Setup.hs b/Setup.hs
new file mode 100644
--- /dev/null
+++ b/Setup.hs
@@ -0,0 +1,2 @@
+import Distribution.Simple
+main = defaultMain
diff --git a/dropsolve.cabal b/dropsolve.cabal
new file mode 100644
--- /dev/null
+++ b/dropsolve.cabal
@@ -0,0 +1,19 @@
+Name:          dropsolve
+Version:       0.1
+License:       BSD3
+License-file:  LICENSE
+Author:        Daniel Trstenjak
+Maintainer:    daniel.trstenjak@gmail.com
+Build-Type:    Simple
+Category:      Utils
+Cabal-Version: >=1.6
+Synopsis:      A command line tool for resolving dropbox conflicts.
+Description:   A command line tool for resolving dropbox conflicts.
+
+source-repository head
+  type:     git
+  location: https://github.com/dan-t/dropsolve
+
+Executable dropsolve
+  Main-is:       dropsolve.hs
+  Build-Depends: base >= 3 && < 5, regex-posix >= 0.94 && < 0.95, time >= 1.2 && < 1.3, process >= 1.0 && < 1.1, filepath >= 1.2 && < 1.3, directory >= 1.1 && < 1.2, haskell98 >= 1.1 && < 1.2 
diff --git a/dropsolve.hs b/dropsolve.hs
new file mode 100644
--- /dev/null
+++ b/dropsolve.hs
@@ -0,0 +1,182 @@
+{-# LANGUAGE ScopedTypeVariables #-}
+
+import System (getArgs)
+import System.Directory
+import System.IO
+import System.IO.Error (IOErrorType)
+import System.FilePath
+import System.Environment
+import System.Process
+import System.Exit
+import Data.Time.Clock
+import Data.Time.Calendar
+import Data.List (isInfixOf, isSuffixOf, concat)
+import Data.Char (intToDigit, digitToInt, isDigit, toUpper)
+import Text.Regex.Posix ((=~))
+import Control.Monad (when, mapM_, filterM)
+import Control.Exception.Base (try)
+
+main = do
+   hSetBuffering stdout NoBuffering
+   hSetBuffering stdin  NoBuffering
+   args <- getArgs
+   case args of
+	[]            -> printUsage >> printHelp
+        ("-h":[])     -> printUsage >> printHelp
+	("--help":[]) -> printUsage >> printHelp
+	(dropDir:[])  -> resolve dropDir
+	otherwise     -> error $ "Invalid Arguments\n" ++ usage
+
+printUsage = putStrLn usage
+usage = "\nUsage: dropsolve DROPBOXDIR"
+
+printHelp = do
+   trashDir <- trashDirectory
+   putStrLn $ ""
+   putStrLn $ "Runtime options:"
+   putStrLn $ "   Take File (NUM) => By pressing a digit, the conflicting file with the"
+   putStrLn $ "                      digit NUM is used as the new version. A copy of the"
+   putStrLn $ "                      current file and the other conflicting files is put"
+   putStrLn $ "                      into the trash directory (" ++ trashDir ++ ")."
+   putStrLn $ ""
+   putStrLn $ "   Move to (T)rash => By pressing 'T' or 't', all conflicting files are"
+   putStrLn $ "                      moved into the trash directory (" ++ trashDir ++ ")."
+   putStrLn $ ""
+   putStrLn $ "   Show (D)iff     => By pressing 'D' or 'd', the difference between the first"
+   putStrLn $ "                      and the second conflicting file is shown. The diff tool"
+   putStrLn $ "                      can be specified by the user by setting the environment"
+   putStrLn $ "                      variable 'DROPSOLVE_DIFF'. The default diff tool is 'gvimdiff -f'."
+   putStrLn $ ""
+   putStrLn $ "   (S)kip          => By pressing 'S' or 's', the current conflict is skipped"
+   putStrLn $ "                      and the next one is shown."
+   putStrLn $ ""
+   putStrLn $ "   (Q)uit          => By pressing 'Q' or 'q', the application is quit."
+   putStrLn $ ""
+   putStrLn $ "   (H)elp          => By pressing 'H' or 'h', this help is printed."
+   putStrLn $ ""
+
+resolve file = do
+   dirExists <- doesDirectoryExist file
+   if dirExists
+      then do
+	 entries <- getDirContents file
+	 mapM_ (\e -> resolve $ file </> e) entries
+      else do
+	 fileExists <- doesFileExist file
+	 when (fileExists && hasConflict file) $
+	    handleConflict file
+
+hasConflict file = "conflicted copy" `isInfixOf` file
+
+handleConflict file = do
+   exist <- doesFileExist file
+   when exist $ do
+      let confInfo = conflictInfo file
+      confFiles <- findConflicting confInfo
+      resolveConflict confInfo confFiles 
+
+   where
+      findConflicting confInfo = do
+	 let d  = dir confInfo
+	     fn = fileName confInfo
+	 entries <- getDirContents d
+	 let confs = filter (isConfFile fn) entries
+	 mapM (\e -> return $ d </> e) confs
+	 where
+	    isConfFile file = \e -> file `isInfixOf` e && hasConflict e
+
+      resolveConflict confInfo confFiles
+	 | length confFiles == 0 = return ()
+	 | otherwise = do
+	    let origFile = dir confInfo </> fileName confInfo
+	    putStrLn $ "\nConflicting file: " ++ origFile
+            putConfFiles confFiles 1
+	    askUser confInfo confFiles
+
+      putConfFiles (c:cs) num = do
+	 let confInfo = conflictInfo c
+	     h        = host confInfo
+	     d        = date confInfo
+	     digit    = intToDigit num
+	 putStrLn $ "   (" ++ [digit] ++ ") " ++ h ++ " from " ++ d
+	 putConfFiles cs (num + 1)
+      putConfFiles [] _ = return ()
+
+      askUser confInfo confFiles = do
+	 putStr "\nTake File (NUM) | Move to (T)rash | Show (D)iff | (S)kip | (Q)uit | (H)elp : " 
+	 char <- getChar
+	 let numConfs = length confFiles
+	     askAgain = askUser confInfo confFiles
+	 case toUpper char of
+	      c | c == 'D' && numConfs >= 2             -> showDiff (head confFiles) (confFiles !! 1) >> askAgain
+	        | c == 'T'                              -> mapM_ (\c -> moveToTrash c) confFiles  
+	        | c == 'S'                              -> return ()
+		| c == 'Q'                              -> exitSuccess
+		| c == 'H'                              -> printHelp >> askAgain
+		| c == '?'                              -> printHelp >> askAgain
+		| isDigit c && digitToInt c <= numConfs -> takeFile (digitToInt c) confInfo confFiles
+		| otherwise                             -> askAgain
+	 where
+	    moveToTrash file = do
+	       trashDir <- trashDirectory
+	       createDirectoryIfMissing True trashDir
+               let (dir, fileName) = splitFileName file
+	       copyFile file (trashDir </> fileName) 
+	       removeFile file
+
+	    takeFile num confInfo confFiles = do
+               (year, month, day) <- getCurrentDate
+	       let idx        = num - 1
+                   file       = confFiles !! idx
+		   origFile   = dir confInfo </> fileName confInfo
+		   origBackup = origFile ++ "_backup_" ++ show year ++ "-" ++ show month ++ "-" ++ show day
+	       copyFile origFile origBackup
+	       moveToTrash origBackup
+	       copyFile file origFile
+	       mapM_ (\c -> moveToTrash c) confFiles
+
+	    showDiff file1 file2 = do
+	       putStrLn ""
+	       diff <- getEnvOrDefault "DROPSOLVE_DIFF" defaultDiff
+	       handle <- runCommand $ diff ++ " " ++ quote file1 ++ " " ++ quote file2
+	       waitForProcess handle
+	       return ()
+
+	    quote string = "\"" ++ string ++ "\""
+
+-- conflicting file info
+data ConflictInfo = ConflictInfo {
+   filePath :: String,
+   dir      :: String,
+   fileName :: String,
+   host     :: String,
+   date     :: String }
+
+conflictInfo :: FilePath -> ConflictInfo
+conflictInfo filePath =
+   let (_:dir:fileName:host:date:[]) = concat (filePath =~ regex :: [[String]])
+       in ConflictInfo filePath dir fileName host date
+   where
+      regex = "(.*)" </> "(.*) \\((.*) conflicted copy (.*)\\).*"
+
+
+getDirContents dir = do
+   entries <- getDirectoryContents dir
+   filterM notDots entries
+   where
+      notDots entry = return . not $ "." `isSuffixOf` entry || ".." `isSuffixOf` entry
+
+
+appDirectory   = getAppUserDataDirectory "dropsolve"
+trashDirectory = appDirectory >>= \d -> return $ d </> "trash" 
+
+defaultDiff = "gvimdiff -f"
+
+getCurrentDate :: IO (Integer,Int,Int) -- :: (year,month,day)
+getCurrentDate = getCurrentTime >>= return . toGregorian . utctDay
+
+getEnvOrDefault envVar defaultValue = do
+   result <- try $ getEnv envVar
+   case result of
+	Right value          -> return value
+	Left  (_ :: IOError) -> return defaultValue
