moduleWeb.Firefox(listPlacesFiles,listHistoryURLs,listAllHistoryURLs)whereimportDatabase.HDBC(disconnect,fromSql,quickQuery')importDatabase.HDBC.Sqlite3(connectSqlite3,setBusyTimeout)importNetwork.URL(importURL,URL)importData.List(isSuffixOf)importControl.Monad(forM)importData.Maybe(mapMaybe)importSystem.Directory(doesDirectoryExist,getDirectoryContents,getHomeDirectory,getTemporaryDirectory,copyFile,removeFile)importSystem.FilePath((</>))firefoxDirs::[String]firefoxDirs=[".mozilla",".mozilla-firefox",".firefox"]placesFile::StringplacesFile="places.sqlite"timeoutFox=5listPlacesFiles::IO[FilePath]listPlacesFiles=dohomeDir<-getHomeDirectoryxs<-mapM(getRecursiveContents.(homeDir</>))firefoxDirsreturn$filter(placesFile`isSuffixOf`)(concatxs)listAllHistoryURLs::IO[URL]listAllHistoryURLs=doputStrLn$"Please close your Firefox if you see this message longer than "++showtimeoutFox++" seconds..."places<-listPlacesFilesxs<-mapMlistHistoryURLsplacesreturn$concatxslistHistoryURLs::FilePath->IO[URL]listHistoryURLsname=doputStrLn$"Going to connect on Firefox SQLite DB: "++nametmpDir<-getTemporaryDirectorylettmpName=tmpDir</>"wiki4e_places.sqlite"copyFilenametmpNameconn<-connectSqlite3tmpNamesetBusyTimeoutconn(1000*timeoutFox)xs<-quickQuery'conn"select url from moz_places order by last_visit_date desc"[]letys=map(fromSql.head)xs::[String]removeFiletmpNamereturn$mapMaybeimportURLysgetRecursiveContents::FilePath->IO[FilePath]getRecursiveContentstopdir=doe<-doesDirectoryExisttopdirifethendonames<-getDirectoryContentstopdirletproperNames=filter(`notElem`[".",".."])namespaths<-forMproperNames$\name->doletpath=topdir</>namee2<-doesDirectoryExistpathife2thengetRecursiveContentspathelsereturn[path]return(concatpaths)elsereturn[]