├── res ├── drawable-hdpi │ ├── icon.png │ ├── connect.png │ ├── folder.png │ ├── arrow_up.png │ ├── up_level.png │ ├── arrow_down.png │ ├── disconnect.png │ ├── dropdown.9.png │ ├── empty_icon.png │ ├── folder_fav.png │ ├── ic_menu_sort.png │ ├── legend_apk.png │ ├── legend_music.png │ ├── legend_other.png │ ├── legend_theme.png │ ├── legend_video.png │ ├── legend_zip.png │ ├── notification.png │ ├── path_pane.9.png │ ├── popup_bg.9.png │ ├── sd_card_icon.png │ ├── wifi_state0.png │ ├── wifi_state4.png │ ├── file_icon_mid.png │ ├── file_icon_mp3.png │ ├── file_icon_pdf.png │ ├── file_icon_rar.png │ ├── file_icon_txt.png │ ├── file_icon_wav.png │ ├── file_icon_wma.png │ ├── file_icon_zip.png │ ├── image_icon_bg.png │ ├── ipaddress_bg.9.png │ ├── legend_picture.png │ ├── category_bar_apk.png │ ├── category_bar_zip.png │ ├── category_icon_apk.png │ ├── category_icon_zip.png │ ├── dropdown_normal.9.png │ ├── file_icon_default.png │ ├── file_icon_office.png │ ├── file_icon_picture.png │ ├── file_icon_theme.png │ ├── file_icon_video.png │ ├── ic_menu_refresh.png │ ├── ic_menu_show_sys.png │ ├── information_bg.9.png │ ├── legend_document.png │ ├── remote_button.9.png │ ├── sd_not_available.png │ ├── up_level_pressed.png │ ├── btn_bottom_normal.9.png │ ├── category_bar_empty.png │ ├── category_bar_mask.9.png │ ├── category_bar_music.png │ ├── category_bar_other.png │ ├── category_bar_theme.png │ ├── category_bar_video.png │ ├── category_icon_music.png │ ├── category_icon_theme.png │ ├── category_icon_video.png │ ├── dropdown_icon_root.png │ ├── dropdown_pressed.9.png │ ├── ic_menu_new_folder.png │ ├── ic_menu_select_all.png │ ├── operation_bar_bg.9.png │ ├── path_pane_pressed.9.png │ ├── btn_bottom_pressed.9.png │ ├── category_bar_document.png │ ├── category_bar_picture.png │ ├── category_icon_document.png │ ├── category_icon_favorite.png │ ├── category_icon_picture.png │ ├── dropdown_icon_folder.png │ ├── operation_button_copy.png │ ├── operation_button_info.png │ ├── operation_button_move.png │ ├── operation_button_send.png │ ├── sd_card_available_icon.png │ ├── btn_bottom_last_normal.9.png │ ├── btn_check_off_holo_light.png │ ├── btn_check_on_holo_light.png │ ├── ic_menu_delete_favorite.png │ ├── operation_button_cancel.png │ ├── operation_button_delete.png │ ├── remote_button_pressed.9.png │ ├── bottom_button_bar_normal.9.png │ ├── bottom_button_bar_pressed.9.png │ ├── btn_bottom_last_pressed.9.png │ ├── category_button_bg_left.9.png │ ├── category_button_bg_middle.9.png │ ├── category_button_bg_right.9.png │ ├── operation_button_info_gray.png │ ├── operation_button_pressed.9.png │ ├── operation_button_selectall.png │ ├── stat_sys_install_complete.png │ ├── category_button_bg_selected.9.png │ └── secondary_title_background.9.png ├── drawable-land-hdpi │ ├── category_bar_apk.png │ ├── category_bar_zip.png │ ├── information_bg.9.png │ ├── category_bar_empty.png │ ├── category_bar_mask.9.png │ ├── category_bar_music.png │ ├── category_bar_other.png │ ├── category_bar_theme.png │ ├── category_bar_video.png │ ├── category_bar_document.png │ ├── category_bar_picture.png │ ├── category_button_bg_top.9.png │ ├── category_button_bg_bottom.9.png │ └── category_button_bg_selected.9.png ├── drawable │ ├── operation_button_background.xml │ ├── btn_bottom.xml │ ├── btn_bottom_last.xml │ ├── path_pane_bg.xml │ ├── path_up_level.xml │ ├── dropdown_item_bg.xml │ ├── remote_button_bg.xml │ ├── bottom_button_bar.xml │ ├── category_button_left.xml │ ├── category_button_right.xml │ ├── category_button_top.xml │ ├── category_button_bottom.xml │ └── category_button_middle.xml ├── layout │ ├── fragment_pager.xml │ ├── textinput_dialog.xml │ ├── dropdown_item.xml │ ├── favorite_item.xml │ ├── information_dialog.xml │ ├── server_control_activity.xml │ ├── file_browser_item.xml │ └── category_file_browser_item.xml ├── xml │ ├── searchable.xml │ └── preferences.xml ├── values │ └── color.xml ├── menu │ └── operation_menu.xml └── values-zh-rCN │ └── strings.xml ├── libs └── android-support-v13.jar ├── .gitignore ├── src ├── org │ └── swiftp │ │ ├── UiUpdateClient.java │ │ ├── Account.java │ │ ├── QuotaStats.java │ │ ├── CmdAPPE.java │ │ ├── CmdSTOR.java │ │ ├── CmdNOOP.java │ │ ├── CmdTemplate.java │ │ ├── CmdQUIT.java │ │ ├── CmdSYST.java │ │ ├── CmdMap.java │ │ ├── CmdFEAT.java │ │ ├── CmdUSER.java │ │ ├── ProxyDataSocketInfo.java │ │ ├── UiUpdater.java │ │ ├── CmdTYPE.java │ │ ├── CmdSIZE.java │ │ ├── CmdRNFR.java │ │ ├── MyLog.java │ │ ├── CmdDELE.java │ │ ├── TcpListener.java │ │ ├── CmdRNTO.java │ │ ├── CmdMKD.java │ │ ├── CmdCWD.java │ │ ├── DataSocketFactory.java │ │ ├── WifiStateReceiver.java │ │ ├── CmdCDUP.java │ │ ├── CmdOPTS.java │ │ ├── Globals.java │ │ ├── CmdPASV.java │ │ ├── Settings.java │ │ ├── CmdPWD.java │ │ ├── CmdRMD.java │ │ ├── CmdPORT.java │ │ ├── CmdPASS.java │ │ ├── CmdAbstractListing.java │ │ ├── CmdNLST.java │ │ ├── NormalDataSocketFactory.java │ │ ├── ProxyDataSocketFactory.java │ │ ├── Defaults.java │ │ └── CmdRETR.java └── net │ └── micode │ └── fileexplorer │ ├── SearchActivity.java │ ├── FavoriteItem.java │ ├── FileInfo.java │ ├── Settings.java │ ├── FilenameOtherExtFilter.java │ ├── GlobalConsts.java │ ├── ActivitiesManager.java │ ├── FilenameExtFilter.java │ ├── IFileInteractionListener.java │ ├── FileListAdapter.java │ ├── TextInputDialog.java │ ├── FavoriteListAdapter.java │ ├── FileSortHelper.java │ ├── FileListCursorAdapter.java │ ├── FileExplorerPreferenceActivity.java │ ├── FavoriteDatabaseHelper.java │ ├── IntentBuilder.java │ └── FileIconHelper.java ├── README └── AndroidManifest.xml /res/drawable-hdpi/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MiCode/FileExplorer/HEAD/res/drawable-hdpi/icon.png -------------------------------------------------------------------------------- /libs/android-support-v13.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MiCode/FileExplorer/HEAD/libs/android-support-v13.jar -------------------------------------------------------------------------------- /res/drawable-hdpi/connect.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MiCode/FileExplorer/HEAD/res/drawable-hdpi/connect.png -------------------------------------------------------------------------------- /res/drawable-hdpi/folder.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MiCode/FileExplorer/HEAD/res/drawable-hdpi/folder.png -------------------------------------------------------------------------------- /res/drawable-hdpi/arrow_up.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MiCode/FileExplorer/HEAD/res/drawable-hdpi/arrow_up.png -------------------------------------------------------------------------------- /res/drawable-hdpi/up_level.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MiCode/FileExplorer/HEAD/res/drawable-hdpi/up_level.png -------------------------------------------------------------------------------- /res/drawable-hdpi/arrow_down.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MiCode/FileExplorer/HEAD/res/drawable-hdpi/arrow_down.png -------------------------------------------------------------------------------- /res/drawable-hdpi/disconnect.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MiCode/FileExplorer/HEAD/res/drawable-hdpi/disconnect.png -------------------------------------------------------------------------------- /res/drawable-hdpi/dropdown.9.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MiCode/FileExplorer/HEAD/res/drawable-hdpi/dropdown.9.png -------------------------------------------------------------------------------- /res/drawable-hdpi/empty_icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MiCode/FileExplorer/HEAD/res/drawable-hdpi/empty_icon.png -------------------------------------------------------------------------------- /res/drawable-hdpi/folder_fav.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MiCode/FileExplorer/HEAD/res/drawable-hdpi/folder_fav.png -------------------------------------------------------------------------------- /res/drawable-hdpi/ic_menu_sort.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MiCode/FileExplorer/HEAD/res/drawable-hdpi/ic_menu_sort.png -------------------------------------------------------------------------------- /res/drawable-hdpi/legend_apk.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MiCode/FileExplorer/HEAD/res/drawable-hdpi/legend_apk.png -------------------------------------------------------------------------------- /res/drawable-hdpi/legend_music.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MiCode/FileExplorer/HEAD/res/drawable-hdpi/legend_music.png -------------------------------------------------------------------------------- /res/drawable-hdpi/legend_other.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MiCode/FileExplorer/HEAD/res/drawable-hdpi/legend_other.png -------------------------------------------------------------------------------- /res/drawable-hdpi/legend_theme.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MiCode/FileExplorer/HEAD/res/drawable-hdpi/legend_theme.png -------------------------------------------------------------------------------- /res/drawable-hdpi/legend_video.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MiCode/FileExplorer/HEAD/res/drawable-hdpi/legend_video.png -------------------------------------------------------------------------------- /res/drawable-hdpi/legend_zip.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MiCode/FileExplorer/HEAD/res/drawable-hdpi/legend_zip.png -------------------------------------------------------------------------------- /res/drawable-hdpi/notification.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MiCode/FileExplorer/HEAD/res/drawable-hdpi/notification.png -------------------------------------------------------------------------------- /res/drawable-hdpi/path_pane.9.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MiCode/FileExplorer/HEAD/res/drawable-hdpi/path_pane.9.png -------------------------------------------------------------------------------- /res/drawable-hdpi/popup_bg.9.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MiCode/FileExplorer/HEAD/res/drawable-hdpi/popup_bg.9.png -------------------------------------------------------------------------------- /res/drawable-hdpi/sd_card_icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MiCode/FileExplorer/HEAD/res/drawable-hdpi/sd_card_icon.png -------------------------------------------------------------------------------- /res/drawable-hdpi/wifi_state0.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MiCode/FileExplorer/HEAD/res/drawable-hdpi/wifi_state0.png -------------------------------------------------------------------------------- /res/drawable-hdpi/wifi_state4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MiCode/FileExplorer/HEAD/res/drawable-hdpi/wifi_state4.png -------------------------------------------------------------------------------- /res/drawable-hdpi/file_icon_mid.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MiCode/FileExplorer/HEAD/res/drawable-hdpi/file_icon_mid.png -------------------------------------------------------------------------------- /res/drawable-hdpi/file_icon_mp3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MiCode/FileExplorer/HEAD/res/drawable-hdpi/file_icon_mp3.png -------------------------------------------------------------------------------- /res/drawable-hdpi/file_icon_pdf.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MiCode/FileExplorer/HEAD/res/drawable-hdpi/file_icon_pdf.png -------------------------------------------------------------------------------- /res/drawable-hdpi/file_icon_rar.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MiCode/FileExplorer/HEAD/res/drawable-hdpi/file_icon_rar.png -------------------------------------------------------------------------------- /res/drawable-hdpi/file_icon_txt.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MiCode/FileExplorer/HEAD/res/drawable-hdpi/file_icon_txt.png -------------------------------------------------------------------------------- /res/drawable-hdpi/file_icon_wav.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MiCode/FileExplorer/HEAD/res/drawable-hdpi/file_icon_wav.png -------------------------------------------------------------------------------- /res/drawable-hdpi/file_icon_wma.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MiCode/FileExplorer/HEAD/res/drawable-hdpi/file_icon_wma.png -------------------------------------------------------------------------------- /res/drawable-hdpi/file_icon_zip.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MiCode/FileExplorer/HEAD/res/drawable-hdpi/file_icon_zip.png -------------------------------------------------------------------------------- /res/drawable-hdpi/image_icon_bg.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MiCode/FileExplorer/HEAD/res/drawable-hdpi/image_icon_bg.png -------------------------------------------------------------------------------- /res/drawable-hdpi/ipaddress_bg.9.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MiCode/FileExplorer/HEAD/res/drawable-hdpi/ipaddress_bg.9.png -------------------------------------------------------------------------------- /res/drawable-hdpi/legend_picture.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MiCode/FileExplorer/HEAD/res/drawable-hdpi/legend_picture.png -------------------------------------------------------------------------------- /res/drawable-hdpi/category_bar_apk.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MiCode/FileExplorer/HEAD/res/drawable-hdpi/category_bar_apk.png -------------------------------------------------------------------------------- /res/drawable-hdpi/category_bar_zip.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MiCode/FileExplorer/HEAD/res/drawable-hdpi/category_bar_zip.png -------------------------------------------------------------------------------- /res/drawable-hdpi/category_icon_apk.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MiCode/FileExplorer/HEAD/res/drawable-hdpi/category_icon_apk.png -------------------------------------------------------------------------------- /res/drawable-hdpi/category_icon_zip.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MiCode/FileExplorer/HEAD/res/drawable-hdpi/category_icon_zip.png -------------------------------------------------------------------------------- /res/drawable-hdpi/dropdown_normal.9.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MiCode/FileExplorer/HEAD/res/drawable-hdpi/dropdown_normal.9.png -------------------------------------------------------------------------------- /res/drawable-hdpi/file_icon_default.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MiCode/FileExplorer/HEAD/res/drawable-hdpi/file_icon_default.png -------------------------------------------------------------------------------- /res/drawable-hdpi/file_icon_office.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MiCode/FileExplorer/HEAD/res/drawable-hdpi/file_icon_office.png -------------------------------------------------------------------------------- /res/drawable-hdpi/file_icon_picture.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MiCode/FileExplorer/HEAD/res/drawable-hdpi/file_icon_picture.png -------------------------------------------------------------------------------- /res/drawable-hdpi/file_icon_theme.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MiCode/FileExplorer/HEAD/res/drawable-hdpi/file_icon_theme.png -------------------------------------------------------------------------------- /res/drawable-hdpi/file_icon_video.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MiCode/FileExplorer/HEAD/res/drawable-hdpi/file_icon_video.png -------------------------------------------------------------------------------- /res/drawable-hdpi/ic_menu_refresh.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MiCode/FileExplorer/HEAD/res/drawable-hdpi/ic_menu_refresh.png -------------------------------------------------------------------------------- /res/drawable-hdpi/ic_menu_show_sys.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MiCode/FileExplorer/HEAD/res/drawable-hdpi/ic_menu_show_sys.png -------------------------------------------------------------------------------- /res/drawable-hdpi/information_bg.9.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MiCode/FileExplorer/HEAD/res/drawable-hdpi/information_bg.9.png -------------------------------------------------------------------------------- /res/drawable-hdpi/legend_document.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MiCode/FileExplorer/HEAD/res/drawable-hdpi/legend_document.png -------------------------------------------------------------------------------- /res/drawable-hdpi/remote_button.9.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MiCode/FileExplorer/HEAD/res/drawable-hdpi/remote_button.9.png -------------------------------------------------------------------------------- /res/drawable-hdpi/sd_not_available.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MiCode/FileExplorer/HEAD/res/drawable-hdpi/sd_not_available.png -------------------------------------------------------------------------------- /res/drawable-hdpi/up_level_pressed.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MiCode/FileExplorer/HEAD/res/drawable-hdpi/up_level_pressed.png -------------------------------------------------------------------------------- /res/drawable-hdpi/btn_bottom_normal.9.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MiCode/FileExplorer/HEAD/res/drawable-hdpi/btn_bottom_normal.9.png -------------------------------------------------------------------------------- /res/drawable-hdpi/category_bar_empty.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MiCode/FileExplorer/HEAD/res/drawable-hdpi/category_bar_empty.png -------------------------------------------------------------------------------- /res/drawable-hdpi/category_bar_mask.9.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MiCode/FileExplorer/HEAD/res/drawable-hdpi/category_bar_mask.9.png -------------------------------------------------------------------------------- /res/drawable-hdpi/category_bar_music.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MiCode/FileExplorer/HEAD/res/drawable-hdpi/category_bar_music.png -------------------------------------------------------------------------------- /res/drawable-hdpi/category_bar_other.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MiCode/FileExplorer/HEAD/res/drawable-hdpi/category_bar_other.png -------------------------------------------------------------------------------- /res/drawable-hdpi/category_bar_theme.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MiCode/FileExplorer/HEAD/res/drawable-hdpi/category_bar_theme.png -------------------------------------------------------------------------------- /res/drawable-hdpi/category_bar_video.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MiCode/FileExplorer/HEAD/res/drawable-hdpi/category_bar_video.png -------------------------------------------------------------------------------- /res/drawable-hdpi/category_icon_music.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MiCode/FileExplorer/HEAD/res/drawable-hdpi/category_icon_music.png -------------------------------------------------------------------------------- /res/drawable-hdpi/category_icon_theme.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MiCode/FileExplorer/HEAD/res/drawable-hdpi/category_icon_theme.png -------------------------------------------------------------------------------- /res/drawable-hdpi/category_icon_video.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MiCode/FileExplorer/HEAD/res/drawable-hdpi/category_icon_video.png -------------------------------------------------------------------------------- /res/drawable-hdpi/dropdown_icon_root.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MiCode/FileExplorer/HEAD/res/drawable-hdpi/dropdown_icon_root.png -------------------------------------------------------------------------------- /res/drawable-hdpi/dropdown_pressed.9.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MiCode/FileExplorer/HEAD/res/drawable-hdpi/dropdown_pressed.9.png -------------------------------------------------------------------------------- /res/drawable-hdpi/ic_menu_new_folder.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MiCode/FileExplorer/HEAD/res/drawable-hdpi/ic_menu_new_folder.png -------------------------------------------------------------------------------- /res/drawable-hdpi/ic_menu_select_all.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MiCode/FileExplorer/HEAD/res/drawable-hdpi/ic_menu_select_all.png -------------------------------------------------------------------------------- /res/drawable-hdpi/operation_bar_bg.9.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MiCode/FileExplorer/HEAD/res/drawable-hdpi/operation_bar_bg.9.png -------------------------------------------------------------------------------- /res/drawable-hdpi/path_pane_pressed.9.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MiCode/FileExplorer/HEAD/res/drawable-hdpi/path_pane_pressed.9.png -------------------------------------------------------------------------------- /res/drawable-hdpi/btn_bottom_pressed.9.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MiCode/FileExplorer/HEAD/res/drawable-hdpi/btn_bottom_pressed.9.png -------------------------------------------------------------------------------- /res/drawable-hdpi/category_bar_document.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MiCode/FileExplorer/HEAD/res/drawable-hdpi/category_bar_document.png -------------------------------------------------------------------------------- /res/drawable-hdpi/category_bar_picture.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MiCode/FileExplorer/HEAD/res/drawable-hdpi/category_bar_picture.png -------------------------------------------------------------------------------- /res/drawable-hdpi/category_icon_document.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MiCode/FileExplorer/HEAD/res/drawable-hdpi/category_icon_document.png -------------------------------------------------------------------------------- /res/drawable-hdpi/category_icon_favorite.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MiCode/FileExplorer/HEAD/res/drawable-hdpi/category_icon_favorite.png -------------------------------------------------------------------------------- /res/drawable-hdpi/category_icon_picture.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MiCode/FileExplorer/HEAD/res/drawable-hdpi/category_icon_picture.png -------------------------------------------------------------------------------- /res/drawable-hdpi/dropdown_icon_folder.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MiCode/FileExplorer/HEAD/res/drawable-hdpi/dropdown_icon_folder.png -------------------------------------------------------------------------------- /res/drawable-hdpi/operation_button_copy.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MiCode/FileExplorer/HEAD/res/drawable-hdpi/operation_button_copy.png -------------------------------------------------------------------------------- /res/drawable-hdpi/operation_button_info.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MiCode/FileExplorer/HEAD/res/drawable-hdpi/operation_button_info.png -------------------------------------------------------------------------------- /res/drawable-hdpi/operation_button_move.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MiCode/FileExplorer/HEAD/res/drawable-hdpi/operation_button_move.png -------------------------------------------------------------------------------- /res/drawable-hdpi/operation_button_send.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MiCode/FileExplorer/HEAD/res/drawable-hdpi/operation_button_send.png -------------------------------------------------------------------------------- /res/drawable-hdpi/sd_card_available_icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MiCode/FileExplorer/HEAD/res/drawable-hdpi/sd_card_available_icon.png -------------------------------------------------------------------------------- /res/drawable-land-hdpi/category_bar_apk.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MiCode/FileExplorer/HEAD/res/drawable-land-hdpi/category_bar_apk.png -------------------------------------------------------------------------------- /res/drawable-land-hdpi/category_bar_zip.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MiCode/FileExplorer/HEAD/res/drawable-land-hdpi/category_bar_zip.png -------------------------------------------------------------------------------- /res/drawable-land-hdpi/information_bg.9.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MiCode/FileExplorer/HEAD/res/drawable-land-hdpi/information_bg.9.png -------------------------------------------------------------------------------- /res/drawable-hdpi/btn_bottom_last_normal.9.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MiCode/FileExplorer/HEAD/res/drawable-hdpi/btn_bottom_last_normal.9.png -------------------------------------------------------------------------------- /res/drawable-hdpi/btn_check_off_holo_light.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MiCode/FileExplorer/HEAD/res/drawable-hdpi/btn_check_off_holo_light.png -------------------------------------------------------------------------------- /res/drawable-hdpi/btn_check_on_holo_light.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MiCode/FileExplorer/HEAD/res/drawable-hdpi/btn_check_on_holo_light.png -------------------------------------------------------------------------------- /res/drawable-hdpi/ic_menu_delete_favorite.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MiCode/FileExplorer/HEAD/res/drawable-hdpi/ic_menu_delete_favorite.png -------------------------------------------------------------------------------- /res/drawable-hdpi/operation_button_cancel.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MiCode/FileExplorer/HEAD/res/drawable-hdpi/operation_button_cancel.png -------------------------------------------------------------------------------- /res/drawable-hdpi/operation_button_delete.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MiCode/FileExplorer/HEAD/res/drawable-hdpi/operation_button_delete.png -------------------------------------------------------------------------------- /res/drawable-hdpi/remote_button_pressed.9.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MiCode/FileExplorer/HEAD/res/drawable-hdpi/remote_button_pressed.9.png -------------------------------------------------------------------------------- /res/drawable-land-hdpi/category_bar_empty.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MiCode/FileExplorer/HEAD/res/drawable-land-hdpi/category_bar_empty.png -------------------------------------------------------------------------------- /res/drawable-land-hdpi/category_bar_mask.9.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MiCode/FileExplorer/HEAD/res/drawable-land-hdpi/category_bar_mask.9.png -------------------------------------------------------------------------------- /res/drawable-land-hdpi/category_bar_music.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MiCode/FileExplorer/HEAD/res/drawable-land-hdpi/category_bar_music.png -------------------------------------------------------------------------------- /res/drawable-land-hdpi/category_bar_other.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MiCode/FileExplorer/HEAD/res/drawable-land-hdpi/category_bar_other.png -------------------------------------------------------------------------------- /res/drawable-land-hdpi/category_bar_theme.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MiCode/FileExplorer/HEAD/res/drawable-land-hdpi/category_bar_theme.png -------------------------------------------------------------------------------- /res/drawable-land-hdpi/category_bar_video.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MiCode/FileExplorer/HEAD/res/drawable-land-hdpi/category_bar_video.png -------------------------------------------------------------------------------- /res/drawable-hdpi/bottom_button_bar_normal.9.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MiCode/FileExplorer/HEAD/res/drawable-hdpi/bottom_button_bar_normal.9.png -------------------------------------------------------------------------------- /res/drawable-hdpi/bottom_button_bar_pressed.9.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MiCode/FileExplorer/HEAD/res/drawable-hdpi/bottom_button_bar_pressed.9.png -------------------------------------------------------------------------------- /res/drawable-hdpi/btn_bottom_last_pressed.9.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MiCode/FileExplorer/HEAD/res/drawable-hdpi/btn_bottom_last_pressed.9.png -------------------------------------------------------------------------------- /res/drawable-hdpi/category_button_bg_left.9.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MiCode/FileExplorer/HEAD/res/drawable-hdpi/category_button_bg_left.9.png -------------------------------------------------------------------------------- /res/drawable-hdpi/category_button_bg_middle.9.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MiCode/FileExplorer/HEAD/res/drawable-hdpi/category_button_bg_middle.9.png -------------------------------------------------------------------------------- /res/drawable-hdpi/category_button_bg_right.9.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MiCode/FileExplorer/HEAD/res/drawable-hdpi/category_button_bg_right.9.png -------------------------------------------------------------------------------- /res/drawable-hdpi/operation_button_info_gray.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MiCode/FileExplorer/HEAD/res/drawable-hdpi/operation_button_info_gray.png -------------------------------------------------------------------------------- /res/drawable-hdpi/operation_button_pressed.9.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MiCode/FileExplorer/HEAD/res/drawable-hdpi/operation_button_pressed.9.png -------------------------------------------------------------------------------- /res/drawable-hdpi/operation_button_selectall.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MiCode/FileExplorer/HEAD/res/drawable-hdpi/operation_button_selectall.png -------------------------------------------------------------------------------- /res/drawable-hdpi/stat_sys_install_complete.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MiCode/FileExplorer/HEAD/res/drawable-hdpi/stat_sys_install_complete.png -------------------------------------------------------------------------------- /res/drawable-land-hdpi/category_bar_document.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MiCode/FileExplorer/HEAD/res/drawable-land-hdpi/category_bar_document.png -------------------------------------------------------------------------------- /res/drawable-land-hdpi/category_bar_picture.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MiCode/FileExplorer/HEAD/res/drawable-land-hdpi/category_bar_picture.png -------------------------------------------------------------------------------- /res/drawable-hdpi/category_button_bg_selected.9.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MiCode/FileExplorer/HEAD/res/drawable-hdpi/category_button_bg_selected.9.png -------------------------------------------------------------------------------- /res/drawable-hdpi/secondary_title_background.9.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MiCode/FileExplorer/HEAD/res/drawable-hdpi/secondary_title_background.9.png -------------------------------------------------------------------------------- /res/drawable-land-hdpi/category_button_bg_top.9.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MiCode/FileExplorer/HEAD/res/drawable-land-hdpi/category_button_bg_top.9.png -------------------------------------------------------------------------------- /res/drawable-land-hdpi/category_button_bg_bottom.9.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MiCode/FileExplorer/HEAD/res/drawable-land-hdpi/category_button_bg_bottom.9.png -------------------------------------------------------------------------------- /res/drawable-land-hdpi/category_button_bg_selected.9.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MiCode/FileExplorer/HEAD/res/drawable-land-hdpi/category_button_bg_selected.9.png -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # generated files 2 | bin/ 3 | gen/ 4 | 5 | # Local configuration file (sdk path, etc) 6 | proguard.cfg 7 | project.properties 8 | .settings/ 9 | .classpath 10 | .project 11 | -------------------------------------------------------------------------------- /res/drawable/operation_button_background.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /res/drawable/btn_bottom.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /res/drawable/btn_bottom_last.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /res/drawable/path_pane_bg.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /res/drawable/path_up_level.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /res/layout/fragment_pager.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 8 | 9 | -------------------------------------------------------------------------------- /res/drawable/dropdown_item_bg.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /res/drawable/remote_button_bg.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /res/drawable/bottom_button_bar.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /res/xml/searchable.xml: -------------------------------------------------------------------------------- 1 | 2 | 11 | -------------------------------------------------------------------------------- /res/drawable/category_button_left.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /res/drawable/category_button_right.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /res/drawable/category_button_top.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /res/drawable/category_button_bottom.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /res/drawable/category_button_middle.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /res/layout/textinput_dialog.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | 15 | 16 | -------------------------------------------------------------------------------- /res/values/color.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | #FFF000 6 | #A6A6A0 7 | #ff9900 8 | #faaa5f 9 | #333333 10 | #ABABAB 11 | #FF0000 12 | #272727 13 | #9b9ba0 14 | 15 | #80000000 16 | 17 | #FFe78018 18 | #FF901821 19 | 20 | 21 | -------------------------------------------------------------------------------- /src/org/swiftp/UiUpdateClient.java: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2009 David Revell 3 | 4 | This file is part of SwiFTP. 5 | 6 | SwiFTP is free software: you can redistribute it and/or modify 7 | it under the terms of the GNU General Public License as published by 8 | the Free Software Foundation, either version 3 of the License, or 9 | (at your option) any later version. 10 | 11 | SwiFTP is distributed in the hope that it will be useful, 12 | but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | GNU General Public License for more details. 15 | 16 | You should have received a copy of the GNU General Public License 17 | along with SwiFTP. If not, see . 18 | */ 19 | 20 | /* 21 | package org.swiftp; 22 | 23 | 24 | public interface UiUpdateClient { 25 | public void updateUi(); 26 | } 27 | */ 28 | -------------------------------------------------------------------------------- /README: -------------------------------------------------------------------------------- 1 | [中文] 2 | 3 | 1. 本项目是MIUI文件管理器的社区开源版,由MIUI团队(www.miui.com) 发起并贡献第一批代码,遵循NOTICE文件所描述的开源协议, 4 | 今后为MiCode社区(www.micode.net) 拥有,并由社区发布和维护。 5 | 6 | 2. Bug反馈和跟踪,请访问Github, 7 | https://github.com/MiCode/FileExplorer/issues?sort=created&direction=desc&state=open 8 | 9 | 3. 功能建议和综合讨论,请访问MiCode, 10 | http://micode.net/forum-51-1.html 11 | 12 | 13 | [English] 14 | 15 | 1. This is open source edition of MIUI File Explorer, it's first initiated and sponsored by MIUI team (www.miui.com). 16 | It's opened under license described by NOTICE file. It's owned by the MiCode community (www.micode.net). In future, 17 | the MiCode community will release and maintain this project. 18 | 19 | 2. Regarding issue tracking, please visit Github, 20 | https://github.com/MiCode/FileExplorer/issues?sort=created&direction=desc&state=open 21 | 22 | 3. Regarding feature request and general discussion, please visit Micode forum, 23 | http://micode.net/forum-51-1.html 24 | -------------------------------------------------------------------------------- /src/net/micode/fileexplorer/SearchActivity.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2010-2011, The MiCode Open Source Community (www.micode.net) 3 | * 4 | * This file is part of FileExplorer. 5 | * 6 | * FileExplorer is free software: you can redistribute it and/or modify 7 | * it under the terms of the GNU General Public License as published by 8 | * the Free Software Foundation, either version 3 of the License, or 9 | * (at your option) any later version. 10 | * 11 | * FileExplorer is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU General Public License 17 | * along with SwiFTP. If not, see . 18 | */ 19 | 20 | package net.micode.fileexplorer; 21 | 22 | import android.app.Activity; 23 | 24 | public class SearchActivity extends Activity { 25 | } 26 | -------------------------------------------------------------------------------- /res/xml/preferences.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 10 | 11 | 15 | 16 | 21 | 22 | 23 | 24 | -------------------------------------------------------------------------------- /src/org/swiftp/Account.java: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2009 David Revell 3 | 4 | This file is part of SwiFTP. 5 | 6 | SwiFTP is free software: you can redistribute it and/or modify 7 | it under the terms of the GNU General Public License as published by 8 | the Free Software Foundation, either version 3 of the License, or 9 | (at your option) any later version. 10 | 11 | SwiFTP is distributed in the hope that it will be useful, 12 | but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | GNU General Public License for more details. 15 | 16 | You should have received a copy of the GNU General Public License 17 | along with SwiFTP. If not, see . 18 | */ 19 | 20 | package org.swiftp; 21 | 22 | public class Account { 23 | protected String username = null; 24 | 25 | public String getUsername() { 26 | return username; 27 | } 28 | 29 | public void setUsername(String username) { 30 | this.username = username; 31 | } 32 | 33 | 34 | } 35 | -------------------------------------------------------------------------------- /src/org/swiftp/QuotaStats.java: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2009 David Revell 3 | 4 | This file is part of SwiFTP. 5 | 6 | SwiFTP is free software: you can redistribute it and/or modify 7 | it under the terms of the GNU General Public License as published by 8 | the Free Software Foundation, either version 3 of the License, or 9 | (at your option) any later version. 10 | 11 | SwiFTP is distributed in the hope that it will be useful, 12 | but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | GNU General Public License for more details. 15 | 16 | You should have received a copy of the GNU General Public License 17 | along with SwiFTP. If not, see . 18 | */ 19 | 20 | package org.swiftp; 21 | 22 | public class QuotaStats { 23 | private int quota; 24 | private int used; 25 | 26 | public QuotaStats(int used, int quota) { 27 | this.quota = quota; 28 | this.used = used; 29 | } 30 | 31 | public int getQuota() { 32 | return quota; 33 | } 34 | public int getUsed() { 35 | return used; 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /src/org/swiftp/CmdAPPE.java: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2009 David Revell 3 | 4 | This file is part of SwiFTP. 5 | 6 | SwiFTP is free software: you can redistribute it and/or modify 7 | it under the terms of the GNU General Public License as published by 8 | the Free Software Foundation, either version 3 of the License, or 9 | (at your option) any later version. 10 | 11 | SwiFTP is distributed in the hope that it will be useful, 12 | but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | GNU General Public License for more details. 15 | 16 | You should have received a copy of the GNU General Public License 17 | along with SwiFTP. If not, see . 18 | */ 19 | 20 | package org.swiftp; 21 | 22 | 23 | public class CmdAPPE extends CmdAbstractStore implements Runnable { 24 | protected String input; 25 | 26 | public CmdAPPE(SessionThread sessionThread, String input) { 27 | super(sessionThread, CmdAPPE.class.toString()); 28 | this.input = input; 29 | } 30 | 31 | public void run() { 32 | doStorOrAppe(getParameter(input), true); 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /src/org/swiftp/CmdSTOR.java: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2009 David Revell 3 | 4 | This file is part of SwiFTP. 5 | 6 | SwiFTP is free software: you can redistribute it and/or modify 7 | it under the terms of the GNU General Public License as published by 8 | the Free Software Foundation, either version 3 of the License, or 9 | (at your option) any later version. 10 | 11 | SwiFTP is distributed in the hope that it will be useful, 12 | but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | GNU General Public License for more details. 15 | 16 | You should have received a copy of the GNU General Public License 17 | along with SwiFTP. If not, see . 18 | */ 19 | 20 | package org.swiftp; 21 | 22 | 23 | public class CmdSTOR extends CmdAbstractStore implements Runnable { 24 | protected String input; 25 | 26 | public CmdSTOR(SessionThread sessionThread, String input) { 27 | super(sessionThread, CmdSTOR.class.toString()); 28 | this.input = input; 29 | } 30 | 31 | public void run() { 32 | doStorOrAppe(getParameter(input), false); 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /src/org/swiftp/CmdNOOP.java: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2009 David Revell 3 | 4 | This file is part of SwiFTP. 5 | 6 | SwiFTP is free software: you can redistribute it and/or modify 7 | it under the terms of the GNU General Public License as published by 8 | the Free Software Foundation, either version 3 of the License, or 9 | (at your option) any later version. 10 | 11 | SwiFTP is distributed in the hope that it will be useful, 12 | but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | GNU General Public License for more details. 15 | 16 | You should have received a copy of the GNU General Public License 17 | along with SwiFTP. If not, see . 18 | */ 19 | 20 | package org.swiftp; 21 | 22 | 23 | public class CmdNOOP extends FtpCmd implements Runnable { 24 | public static final String message = "TEMPLATE!!"; 25 | 26 | public CmdNOOP(SessionThread sessionThread, String input) { 27 | super(sessionThread, CmdNOOP.class.toString()); 28 | } 29 | 30 | public void run() { 31 | sessionThread.writeString("200 NOOP ok\r\n"); 32 | //myLog.l(Log.INFO, "Executing NOOP, done"); 33 | } 34 | 35 | } 36 | -------------------------------------------------------------------------------- /src/org/swiftp/CmdTemplate.java: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2009 David Revell 3 | 4 | This file is part of SwiFTP. 5 | 6 | SwiFTP is free software: you can redistribute it and/or modify 7 | it under the terms of the GNU General Public License as published by 8 | the Free Software Foundation, either version 3 of the License, or 9 | (at your option) any later version. 10 | 11 | SwiFTP is distributed in the hope that it will be useful, 12 | but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | GNU General Public License for more details. 15 | 16 | You should have received a copy of the GNU General Public License 17 | along with SwiFTP. If not, see . 18 | */ 19 | 20 | package org.swiftp; 21 | 22 | import android.util.Log; 23 | 24 | public class CmdTemplate extends FtpCmd implements Runnable { 25 | public static final String message = "TEMPLATE!!"; 26 | 27 | public CmdTemplate(SessionThread sessionThread, String input) { 28 | super(sessionThread, CmdTemplate.class.toString()); 29 | } 30 | 31 | public void run() { 32 | sessionThread.writeString(message); 33 | myLog.l(Log.INFO, "Template log message"); 34 | } 35 | 36 | } 37 | -------------------------------------------------------------------------------- /src/org/swiftp/CmdQUIT.java: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2009 David Revell 3 | 4 | This file is part of SwiFTP. 5 | 6 | SwiFTP is free software: you can redistribute it and/or modify 7 | it under the terms of the GNU General Public License as published by 8 | the Free Software Foundation, either version 3 of the License, or 9 | (at your option) any later version. 10 | 11 | SwiFTP is distributed in the hope that it will be useful, 12 | but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | GNU General Public License for more details. 15 | 16 | You should have received a copy of the GNU General Public License 17 | along with SwiFTP. If not, see . 18 | */ 19 | 20 | package org.swiftp; 21 | 22 | import android.util.Log; 23 | 24 | public class CmdQUIT extends FtpCmd implements Runnable { 25 | public static final String message = "TEMPLATE!!"; 26 | 27 | public CmdQUIT(SessionThread sessionThread, String input) { 28 | super(sessionThread, CmdQUIT.class.toString()); 29 | } 30 | 31 | public void run() { 32 | myLog.l(Log.DEBUG, "QUITting"); 33 | sessionThread.writeString("221 Goodbye\r\n"); 34 | sessionThread.closeSocket(); 35 | } 36 | 37 | } 38 | -------------------------------------------------------------------------------- /res/menu/operation_menu.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 7 | 11 | 14 | 17 | 19 | 22 | 25 | -------------------------------------------------------------------------------- /src/org/swiftp/CmdSYST.java: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2009 David Revell 3 | 4 | This file is part of SwiFTP. 5 | 6 | SwiFTP is free software: you can redistribute it and/or modify 7 | it under the terms of the GNU General Public License as published by 8 | the Free Software Foundation, either version 3 of the License, or 9 | (at your option) any later version. 10 | 11 | SwiFTP is distributed in the hope that it will be useful, 12 | but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | GNU General Public License for more details. 15 | 16 | You should have received a copy of the GNU General Public License 17 | along with SwiFTP. If not, see . 18 | */ 19 | 20 | package org.swiftp; 21 | 22 | import android.util.Log; 23 | 24 | public class CmdSYST extends FtpCmd implements Runnable { 25 | // This is considered a safe response to the SYST command, see 26 | // http://cr.yp.to/ftp/syst.html 27 | public static final String response = "215 UNIX Type: L8\r\n"; 28 | 29 | public CmdSYST(SessionThread sessionThread, String input) { 30 | super(sessionThread, CmdSYST.class.toString()); 31 | } 32 | 33 | 34 | public void run() { 35 | myLog.l(Log.DEBUG, "SYST executing"); 36 | sessionThread.writeString(response); 37 | myLog.l(Log.DEBUG, "SYST finished"); 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /src/org/swiftp/CmdMap.java: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2009 David Revell 3 | 4 | This file is part of SwiFTP. 5 | 6 | SwiFTP is free software: you can redistribute it and/or modify 7 | it under the terms of the GNU General Public License as published by 8 | the Free Software Foundation, either version 3 of the License, or 9 | (at your option) any later version. 10 | 11 | SwiFTP is distributed in the hope that it will be useful, 12 | but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | GNU General Public License for more details. 15 | 16 | You should have received a copy of the GNU General Public License 17 | along with SwiFTP. If not, see . 18 | */ 19 | 20 | package org.swiftp; 21 | 22 | public class CmdMap { 23 | protected Class cmdClass; 24 | String name; 25 | 26 | 27 | public CmdMap(String name, Class cmdClass) { 28 | super(); 29 | this.name = name; 30 | this.cmdClass = cmdClass; 31 | } 32 | 33 | public Class getCommand() { 34 | return cmdClass; 35 | } 36 | 37 | public void setCommand(Class cmdClass) { 38 | this.cmdClass = cmdClass; 39 | } 40 | 41 | public String getName() { 42 | return name; 43 | } 44 | 45 | public void setName(String name) { 46 | this.name = name; 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /res/layout/dropdown_item.xml: -------------------------------------------------------------------------------- 1 | 2 | 8 | 9 | 16 | 17 | 25 | 26 | 33 | 34 | 35 | 36 | -------------------------------------------------------------------------------- /src/net/micode/fileexplorer/FavoriteItem.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2010-2011, The MiCode Open Source Community (www.micode.net) 3 | * 4 | * This file is part of FileExplorer. 5 | * 6 | * FileExplorer is free software: you can redistribute it and/or modify 7 | * it under the terms of the GNU General Public License as published by 8 | * the Free Software Foundation, either version 3 of the License, or 9 | * (at your option) any later version. 10 | * 11 | * FileExplorer is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU General Public License 17 | * along with SwiFTP. If not, see . 18 | */ 19 | 20 | package net.micode.fileexplorer; 21 | 22 | public class FavoriteItem { 23 | // id in the database 24 | public long id; 25 | 26 | public String title; 27 | 28 | // path 29 | public String location; 30 | 31 | public FileInfo fileInfo; 32 | 33 | public FavoriteItem(String t, String l) { 34 | title = t; 35 | location = l; 36 | } 37 | 38 | public FavoriteItem(long i, String t, String l) { 39 | id = i; 40 | title = t; 41 | location = l; 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /src/net/micode/fileexplorer/FileInfo.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2010-2011, The MiCode Open Source Community (www.micode.net) 3 | * 4 | * This file is part of FileExplorer. 5 | * 6 | * FileExplorer is free software: you can redistribute it and/or modify 7 | * it under the terms of the GNU General Public License as published by 8 | * the Free Software Foundation, either version 3 of the License, or 9 | * (at your option) any later version. 10 | * 11 | * FileExplorer is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU General Public License 17 | * along with SwiFTP. If not, see . 18 | */ 19 | 20 | package net.micode.fileexplorer; 21 | 22 | public class FileInfo { 23 | 24 | public String fileName; 25 | 26 | public String filePath; 27 | 28 | public long fileSize; 29 | 30 | public boolean IsDir; 31 | 32 | public int Count; 33 | 34 | public long ModifiedDate; 35 | 36 | public boolean Selected; 37 | 38 | public boolean canRead; 39 | 40 | public boolean canWrite; 41 | 42 | public boolean isHidden; 43 | 44 | public long dbId; // id in the database, if is from database 45 | 46 | } 47 | -------------------------------------------------------------------------------- /src/org/swiftp/CmdFEAT.java: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2009 David Revell 3 | 4 | This file is part of SwiFTP. 5 | 6 | SwiFTP is free software: you can redistribute it and/or modify 7 | it under the terms of the GNU General Public License as published by 8 | the Free Software Foundation, either version 3 of the License, or 9 | (at your option) any later version. 10 | 11 | SwiFTP is distributed in the hope that it will be useful, 12 | but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | GNU General Public License for more details. 15 | 16 | You should have received a copy of the GNU General Public License 17 | along with SwiFTP. If not, see . 18 | */ 19 | 20 | package org.swiftp; 21 | 22 | import android.util.Log; 23 | 24 | public class CmdFEAT extends FtpCmd implements Runnable { 25 | public static final String message = "TEMPLATE!!"; 26 | 27 | public CmdFEAT(SessionThread sessionThread, String input) { 28 | super(sessionThread, CmdFEAT.class.toString()); 29 | } 30 | 31 | public void run() { 32 | //sessionThread.writeString("211 No extended features\r\n"); 33 | sessionThread.writeString("211-Features supported\r\n"); 34 | sessionThread.writeString(" UTF8\r\n"); // advertise UTF8 support (fixes bug 14) 35 | sessionThread.writeString("211 End\r\n"); 36 | myLog.l(Log.DEBUG, "Gave FEAT response"); 37 | } 38 | 39 | } 40 | -------------------------------------------------------------------------------- /src/org/swiftp/CmdUSER.java: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2009 David Revell 3 | 4 | This file is part of SwiFTP. 5 | 6 | SwiFTP is free software: you can redistribute it and/or modify 7 | it under the terms of the GNU General Public License as published by 8 | the Free Software Foundation, either version 3 of the License, or 9 | (at your option) any later version. 10 | 11 | SwiFTP is distributed in the hope that it will be useful, 12 | but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | GNU General Public License for more details. 15 | 16 | You should have received a copy of the GNU General Public License 17 | along with SwiFTP. If not, see . 18 | */ 19 | 20 | package org.swiftp; 21 | 22 | import android.util.Log; 23 | 24 | public class CmdUSER extends FtpCmd implements Runnable { 25 | protected String input; 26 | 27 | public CmdUSER(SessionThread sessionThread, String input) { 28 | super(sessionThread, CmdUSER.class.toString()); 29 | this.input = input; 30 | 31 | } 32 | 33 | public void run() { 34 | myLog.l(Log.DEBUG, "USER executing"); 35 | String username = FtpCmd.getParameter(input); 36 | if(!username.matches("[A-Za-z0-9]+")) { 37 | sessionThread.writeString("530 Invalid username\r\n"); 38 | return; 39 | } 40 | sessionThread.writeString("331 Send password\r\n"); 41 | sessionThread.account.setUsername(username); 42 | } 43 | 44 | } 45 | -------------------------------------------------------------------------------- /src/org/swiftp/ProxyDataSocketInfo.java: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2009 David Revell 3 | 4 | This file is part of SwiFTP. 5 | 6 | SwiFTP is free software: you can redistribute it and/or modify 7 | it under the terms of the GNU General Public License as published by 8 | the Free Software Foundation, either version 3 of the License, or 9 | (at your option) any later version. 10 | 11 | SwiFTP is distributed in the hope that it will be useful, 12 | but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | GNU General Public License for more details. 15 | 16 | You should have received a copy of the GNU General Public License 17 | along with SwiFTP. If not, see . 18 | */ 19 | 20 | package org.swiftp; 21 | 22 | import java.net.Socket; 23 | 24 | public class ProxyDataSocketInfo extends Socket { 25 | private int remotePublicPort; 26 | private Socket socket; 27 | 28 | public Socket getSocket() { 29 | return socket; 30 | } 31 | 32 | public void setSocket(Socket socket) { 33 | this.socket = socket; 34 | } 35 | 36 | public ProxyDataSocketInfo(Socket socket, int remotePublicPort) { 37 | this.remotePublicPort = remotePublicPort; 38 | this.socket = socket; 39 | } 40 | 41 | public int getRemotePublicPort() { 42 | return remotePublicPort; 43 | } 44 | 45 | public void setRemotePublicPort(int remotePublicPort) { 46 | this.remotePublicPort = remotePublicPort; 47 | } 48 | 49 | } 50 | -------------------------------------------------------------------------------- /src/net/micode/fileexplorer/Settings.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2010-2011, The MiCode Open Source Community (www.micode.net) 3 | * 4 | * This file is part of FileExplorer. 5 | * 6 | * FileExplorer is free software: you can redistribute it and/or modify 7 | * it under the terms of the GNU General Public License as published by 8 | * the Free Software Foundation, either version 3 of the License, or 9 | * (at your option) any later version. 10 | * 11 | * FileExplorer is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU General Public License 17 | * along with SwiFTP. If not, see . 18 | */ 19 | 20 | package net.micode.fileexplorer; 21 | 22 | public class Settings { 23 | // whether show system and cache images, default not 24 | private boolean mShowDotAndHiddenFiles; 25 | private static Settings mInstance; 26 | 27 | private Settings() { 28 | 29 | } 30 | 31 | public static Settings instance() { 32 | if(mInstance == null) { 33 | mInstance = new Settings(); 34 | } 35 | return mInstance; 36 | } 37 | 38 | public boolean getShowDotAndHiddenFiles() { 39 | return mShowDotAndHiddenFiles; 40 | } 41 | 42 | public void setShowDotAndHiddenFiles(boolean s) { 43 | mShowDotAndHiddenFiles = s; 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /src/org/swiftp/UiUpdater.java: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2009 David Revell 3 | 4 | This file is part of SwiFTP. 5 | 6 | SwiFTP is free software: you can redistribute it and/or modify 7 | it under the terms of the GNU General Public License as published by 8 | the Free Software Foundation, either version 3 of the License, or 9 | (at your option) any later version. 10 | 11 | SwiFTP is distributed in the hope that it will be useful, 12 | but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | GNU General Public License for more details. 15 | 16 | You should have received a copy of the GNU General Public License 17 | along with SwiFTP. If not, see . 18 | */ 19 | 20 | package org.swiftp; 21 | 22 | import java.util.ArrayList; 23 | import java.util.List; 24 | 25 | import android.os.Handler; 26 | 27 | public class UiUpdater { 28 | protected static MyLog myLog = new MyLog("UiUpdater"); 29 | protected static List clients = new ArrayList(); 30 | 31 | public static void registerClient(Handler client) { 32 | if(!clients.contains(client)) { 33 | clients.add(client); 34 | } 35 | } 36 | 37 | public static void unregisterClient(Handler client) { 38 | while(clients.contains(client)) { 39 | clients.remove(client); 40 | } 41 | } 42 | 43 | public static void updateClients() { 44 | //myLog.l(Log.DEBUG, "UI update"); 45 | //Log.d("UiUpdate", "Update now"); 46 | for (Handler client : clients) { 47 | client.sendEmptyMessage(0); 48 | } 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /src/net/micode/fileexplorer/FilenameOtherExtFilter.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2010-2011, The MiCode Open Source Community (www.micode.net) 3 | * 4 | * This file is part of FileExplorer. 5 | * 6 | * FileExplorer is free software: you can redistribute it and/or modify 7 | * it under the terms of the GNU General Public License as published by 8 | * the Free Software Foundation, either version 3 of the License, or 9 | * (at your option) any later version. 10 | * 11 | * FileExplorer is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU General Public License 17 | * along with SwiFTP. If not, see . 18 | */ 19 | 20 | package net.micode.fileexplorer; 21 | 22 | import java.util.Arrays; 23 | import java.util.HashSet; 24 | 25 | public class FilenameOtherExtFilter extends FilenameExtFilter { 26 | 27 | private HashSet mExts; 28 | 29 | // using lower case 30 | public FilenameOtherExtFilter(FilenameExtFilter[] exts) { 31 | super(null); 32 | mExts = new HashSet(); 33 | mExts.addAll(Arrays.asList(exts)); 34 | } 35 | 36 | @Override 37 | public boolean contains(String ext) { 38 | for (FilenameExtFilter f : mExts) { 39 | if (f.contains(ext)) 40 | return false; 41 | } 42 | return true; 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /src/org/swiftp/CmdTYPE.java: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2009 David Revell 3 | 4 | This file is part of SwiFTP. 5 | 6 | SwiFTP is free software: you can redistribute it and/or modify 7 | it under the terms of the GNU General Public License as published by 8 | the Free Software Foundation, either version 3 of the License, or 9 | (at your option) any later version. 10 | 11 | SwiFTP is distributed in the hope that it will be useful, 12 | but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | GNU General Public License for more details. 15 | 16 | You should have received a copy of the GNU General Public License 17 | along with SwiFTP. If not, see . 18 | */ 19 | 20 | package org.swiftp; 21 | 22 | import android.util.Log; 23 | 24 | public class CmdTYPE extends FtpCmd implements Runnable { 25 | String input; 26 | 27 | public CmdTYPE(SessionThread sessionThread, String input) { 28 | super(sessionThread, CmdTYPE.class.toString()); 29 | this.input = input; 30 | } 31 | 32 | public void run() { 33 | String output; 34 | myLog.l(Log.DEBUG, "TYPE executing"); 35 | String param = getParameter(input); 36 | if(param.equals("I") || param.equals("L 8")) { 37 | output = "200 Binary type set\r\n"; 38 | sessionThread.setBinaryMode(true); 39 | } else if (param.equals("A") || param.equals("A N")) { 40 | output = "200 ASCII type set\r\n"; 41 | sessionThread.setBinaryMode(false); 42 | } else { 43 | output = "503 Malformed TYPE command\r\n"; 44 | } 45 | sessionThread.writeString(output); 46 | myLog.l(Log.DEBUG, "TYPE complete"); 47 | } 48 | 49 | } 50 | -------------------------------------------------------------------------------- /src/org/swiftp/CmdSIZE.java: -------------------------------------------------------------------------------- 1 | package org.swiftp; 2 | 3 | import java.io.File; 4 | import java.io.IOException; 5 | 6 | public class CmdSIZE extends FtpCmd { 7 | protected String input; 8 | 9 | public CmdSIZE(SessionThread sessionThread, String input) { 10 | super(sessionThread, CmdSIZE.class.toString()); 11 | this.input = input; 12 | } 13 | 14 | public void run() { 15 | myLog.d("SIZE executing"); 16 | 17 | String errString = null; 18 | String param = getParameter(input); 19 | long size = 0; 20 | mainblock: { 21 | File currentDir = sessionThread.getWorkingDir(); 22 | if(param.contains(File.separator)) { 23 | errString = "550 No directory traversal allowed in SIZE param\r\n"; 24 | break mainblock; 25 | } 26 | File target = new File(currentDir, param); 27 | 28 | // We should have caught any invalid location access before now, but 29 | // here we check again, just to be explicitly sure. 30 | if(violatesChroot(target)) { 31 | errString = "550 SIZE target violates chroot\r\n"; 32 | break mainblock; 33 | } 34 | if(!target.exists()) { 35 | errString = "550 Cannot get the SIZE of nonexistent object\r\n"; 36 | try { 37 | myLog.i("Failed getting size of: " + target.getCanonicalPath()); 38 | } catch (IOException e) {} 39 | break mainblock; 40 | } 41 | if(!target.isFile()) { 42 | errString = "550 Cannot get the size of a non-file\r\n"; 43 | break mainblock; 44 | } 45 | size = target.length(); 46 | } 47 | if(errString != null) { 48 | sessionThread.writeString(errString); 49 | } else { 50 | sessionThread.writeString("213 " + size + "\r\n"); 51 | } 52 | myLog.d("SIZE complete"); 53 | } 54 | 55 | } 56 | -------------------------------------------------------------------------------- /src/net/micode/fileexplorer/GlobalConsts.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2010-2011, The MiCode Open Source Community (www.micode.net) 3 | * 4 | * This file is part of FileExplorer. 5 | * 6 | * FileExplorer is free software: you can redistribute it and/or modify 7 | * it under the terms of the GNU General Public License as published by 8 | * the Free Software Foundation, either version 3 of the License, or 9 | * (at your option) any later version. 10 | * 11 | * FileExplorer is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU General Public License 17 | * along with SwiFTP. If not, see . 18 | */ 19 | 20 | package net.micode.fileexplorer; 21 | 22 | public abstract class GlobalConsts { 23 | public static final String KEY_BASE_SD = "key_base_sd"; 24 | 25 | public static final String KEY_SHOW_CATEGORY = "key_show_category"; 26 | 27 | public static final String INTENT_EXTRA_TAB = "TAB"; 28 | 29 | public static final String ROOT_PATH = "/"; 30 | 31 | public static final String SDCARD_PATH = ROOT_PATH + "sdcard"; 32 | 33 | // Menu id 34 | public static final int MENU_NEW_FOLDER = 100; 35 | public static final int MENU_FAVORITE = 101; 36 | public static final int MENU_COPY = 104; 37 | public static final int MENU_PASTE = 105; 38 | public static final int MENU_MOVE = 106; 39 | public static final int MENU_SHOWHIDE = 117; 40 | public static final int MENU_COPY_PATH = 118; 41 | 42 | public static final int OPERATION_UP_LEVEL = 3; 43 | } 44 | -------------------------------------------------------------------------------- /src/org/swiftp/CmdRNFR.java: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2009 David Revell 3 | 4 | This file is part of SwiFTP. 5 | 6 | SwiFTP is free software: you can redistribute it and/or modify 7 | it under the terms of the GNU General Public License as published by 8 | the Free Software Foundation, either version 3 of the License, or 9 | (at your option) any later version. 10 | 11 | SwiFTP is distributed in the hope that it will be useful, 12 | but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | GNU General Public License for more details. 15 | 16 | You should have received a copy of the GNU General Public License 17 | along with SwiFTP. If not, see . 18 | */ 19 | 20 | package org.swiftp; 21 | 22 | import java.io.File; 23 | 24 | import android.util.Log; 25 | 26 | public class CmdRNFR extends FtpCmd implements Runnable { 27 | protected String input; 28 | 29 | public CmdRNFR(SessionThread sessionThread, String input) { 30 | super(sessionThread, CmdRNFR.class.toString()); 31 | this.input = input; 32 | } 33 | 34 | public void run() { 35 | String param = getParameter(input); 36 | String errString = null; 37 | File file = null; 38 | mainblock: { 39 | file = inputPathToChrootedFile(sessionThread.getWorkingDir(), param); 40 | if(violatesChroot(file)) { 41 | errString = "550 Invalid name or chroot violation\r\n"; 42 | break mainblock; 43 | } 44 | if(!file.exists()) { 45 | errString = "450 Cannot rename nonexistent file\r\n"; 46 | } 47 | } 48 | if(errString != null) { 49 | sessionThread.writeString(errString); 50 | myLog.l(Log.INFO, "RNFR failed: " + errString.trim()); 51 | sessionThread.setRenameFrom(null); 52 | } else { 53 | sessionThread.writeString("350 Filename noted, now send RNTO\r\n"); 54 | sessionThread.setRenameFrom(file); 55 | } 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /src/org/swiftp/MyLog.java: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2009 David Revell 3 | 4 | This file is part of SwiFTP. 5 | 6 | SwiFTP is free software: you can redistribute it and/or modify 7 | it under the terms of the GNU General Public License as published by 8 | the Free Software Foundation, either version 3 of the License, or 9 | (at your option) any later version. 10 | 11 | SwiFTP is distributed in the hope that it will be useful, 12 | but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | GNU General Public License for more details. 15 | 16 | You should have received a copy of the GNU General Public License 17 | along with SwiFTP. If not, see . 18 | */ 19 | 20 | package org.swiftp; 21 | 22 | import net.micode.fileexplorer.FTPServerService; 23 | 24 | import android.util.Log; 25 | 26 | public class MyLog { 27 | protected String tag; 28 | 29 | public MyLog(String tag) { 30 | this.tag = tag; 31 | } 32 | 33 | public void l(int level, String str, boolean sysOnly) { 34 | synchronized (MyLog.class) { 35 | str = str.trim(); 36 | // Messages of this severity are handled specially 37 | if(level == Log.ERROR || level == Log.WARN) { 38 | Globals.setLastError(str); 39 | } 40 | if(level >= Defaults.getConsoleLogLevel()) { 41 | Log.println(level,tag, str); 42 | } 43 | if(!sysOnly) { // some messages only go to the Android log 44 | if(level >= Defaults.getUiLogLevel()) { 45 | FTPServerService.log(level, str); 46 | } 47 | } 48 | } 49 | } 50 | 51 | public void l(int level, String str) { 52 | l(level, str, false); 53 | } 54 | 55 | public void e(String s) { 56 | l(Log.ERROR, s, false); 57 | } 58 | public void w(String s) { 59 | l(Log.WARN, s, false); 60 | } 61 | public void i(String s) { 62 | l(Log.INFO, s, false); 63 | } 64 | public void d(String s) { 65 | l(Log.DEBUG, s, false); 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /src/net/micode/fileexplorer/ActivitiesManager.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2010-2011, The MiCode Open Source Community (www.micode.net) 3 | * 4 | * This file is part of FileExplorer. 5 | * 6 | * FileExplorer is free software: you can redistribute it and/or modify 7 | * it under the terms of the GNU General Public License as published by 8 | * the Free Software Foundation, either version 3 of the License, or 9 | * (at your option) any later version. 10 | * 11 | * FileExplorer is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU General Public License 17 | * along with SwiFTP. If not, see . 18 | */ 19 | 20 | package net.micode.fileexplorer; 21 | 22 | import java.util.HashMap; 23 | 24 | import android.app.Activity; 25 | 26 | public class ActivitiesManager { 27 | public static final String ACTIVITY_FILE_VIEW = "FileView"; 28 | 29 | public static final String ACTIVITY_FILE_CATEGORY = "FileCategory"; 30 | 31 | public static final String ACTIVITY_TAB = "FileExplorerTab"; 32 | 33 | private static ActivitiesManager instance; 34 | 35 | private HashMap activities = new HashMap(); 36 | 37 | private ActivitiesManager() { 38 | } 39 | 40 | // return true indicates successful, false indicates the name exists 41 | public void registerActivity(String name, Activity a) { 42 | activities.put(name, a); 43 | } 44 | 45 | public Activity getActivity(String name) { 46 | return activities.get(name); 47 | } 48 | 49 | public static ActivitiesManager getInstance() { 50 | if (instance == null) 51 | instance = new ActivitiesManager(); 52 | return instance; 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /src/org/swiftp/CmdDELE.java: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2009 David Revell 3 | 4 | This file is part of SwiFTP. 5 | 6 | SwiFTP is free software: you can redistribute it and/or modify 7 | it under the terms of the GNU General Public License as published by 8 | the Free Software Foundation, either version 3 of the License, or 9 | (at your option) any later version. 10 | 11 | SwiFTP is distributed in the hope that it will be useful, 12 | but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | GNU General Public License for more details. 15 | 16 | You should have received a copy of the GNU General Public License 17 | along with SwiFTP. If not, see . 18 | */ 19 | 20 | package org.swiftp; 21 | 22 | import java.io.File; 23 | 24 | import android.util.Log; 25 | 26 | public class CmdDELE extends FtpCmd implements Runnable { 27 | protected String input; 28 | 29 | public CmdDELE(SessionThread sessionThread, String input) { 30 | super(sessionThread, CmdDELE.class.toString()); 31 | this.input = input; 32 | } 33 | 34 | public void run() { 35 | myLog.l(Log.INFO, "DELE executing"); 36 | String param = getParameter(input); 37 | File storeFile = inputPathToChrootedFile(sessionThread.getWorkingDir(), param); 38 | String errString = null; 39 | if(violatesChroot(storeFile)) { 40 | errString = "550 Invalid name or chroot violation\r\n"; 41 | } else if(storeFile.isDirectory()) { 42 | errString = "550 Can't DELE a directory\r\n"; 43 | } else if(!storeFile.delete()) { 44 | errString = "450 Error deleting file\r\n"; 45 | } 46 | 47 | if(errString != null) { 48 | sessionThread.writeString(errString); 49 | myLog.l(Log.INFO, "DELE failed: " + errString.trim()); 50 | } else { 51 | sessionThread.writeString("250 File successfully deleted\r\n"); 52 | Util.deletedFileNotify(storeFile.getPath()); 53 | } 54 | myLog.l(Log.INFO, "DELE finished"); 55 | } 56 | 57 | } 58 | -------------------------------------------------------------------------------- /src/net/micode/fileexplorer/FilenameExtFilter.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2010-2011, The MiCode Open Source Community (www.micode.net) 3 | * 4 | * This file is part of FileExplorer. 5 | * 6 | * FileExplorer is free software: you can redistribute it and/or modify 7 | * it under the terms of the GNU General Public License as published by 8 | * the Free Software Foundation, either version 3 of the License, or 9 | * (at your option) any later version. 10 | * 11 | * FileExplorer is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU General Public License 17 | * along with SwiFTP. If not, see . 18 | */ 19 | 20 | package net.micode.fileexplorer; 21 | 22 | import java.io.File; 23 | import java.io.FilenameFilter; 24 | import java.util.Arrays; 25 | import java.util.HashSet; 26 | 27 | public class FilenameExtFilter implements FilenameFilter { 28 | 29 | private HashSet mExts = new HashSet(); 30 | 31 | // using lower case 32 | public FilenameExtFilter(String[] exts) { 33 | if (exts != null) { 34 | mExts.addAll(Arrays.asList(exts)); 35 | } 36 | } 37 | 38 | public boolean contains(String ext) { 39 | return mExts.contains(ext.toLowerCase()); 40 | } 41 | 42 | @Override 43 | public boolean accept(File dir, String filename) { 44 | 45 | File file = new File(dir + File.separator + filename); 46 | if (file.isDirectory()) { 47 | return true; 48 | } 49 | 50 | int dotPosition = filename.lastIndexOf('.'); 51 | if (dotPosition != -1) { 52 | String ext = (String) filename.subSequence(dotPosition + 1, filename.length()); 53 | return contains(ext.toLowerCase()); 54 | } 55 | 56 | return false; 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /src/org/swiftp/TcpListener.java: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2009 David Revell 3 | 4 | This file is part of SwiFTP. 5 | 6 | SwiFTP is free software: you can redistribute it and/or modify 7 | it under the terms of the GNU General Public License as published by 8 | the Free Software Foundation, either version 3 of the License, or 9 | (at your option) any later version. 10 | 11 | SwiFTP is distributed in the hope that it will be useful, 12 | but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | GNU General Public License for more details. 15 | 16 | You should have received a copy of the GNU General Public License 17 | along with SwiFTP. If not, see . 18 | */ 19 | 20 | package org.swiftp; 21 | 22 | import net.micode.fileexplorer.FTPServerService; 23 | 24 | import java.net.ServerSocket; 25 | import java.net.Socket; 26 | 27 | import android.util.Log; 28 | 29 | public class TcpListener extends Thread { 30 | ServerSocket listenSocket; 31 | FTPServerService ftpServerService; 32 | MyLog myLog = new MyLog(getClass().getName()); 33 | 34 | public TcpListener(ServerSocket listenSocket, FTPServerService ftpServerService) { 35 | this.listenSocket = listenSocket; 36 | this.ftpServerService = ftpServerService; 37 | } 38 | 39 | public void quit() { 40 | try { 41 | listenSocket.close(); // if the TcpListener thread is blocked on accept, 42 | // closing the socket will raise an exception 43 | } catch (Exception e) { 44 | myLog.l(Log.DEBUG, "Exception closing TcpListener listenSocket"); 45 | } 46 | } 47 | 48 | public void run() { 49 | try { 50 | while(true) { 51 | 52 | Socket clientSocket = listenSocket.accept(); 53 | myLog.l(Log.INFO, "New connection, spawned thread"); 54 | SessionThread newSession = new SessionThread(clientSocket, 55 | new NormalDataSocketFactory(), 56 | SessionThread.Source.LOCAL); 57 | newSession.start(); 58 | ftpServerService.registerSessionThread(newSession); 59 | } 60 | } catch (Exception e) { 61 | myLog.l(Log.DEBUG, "Exception in TcpListener"); 62 | } 63 | } 64 | } 65 | 66 | -------------------------------------------------------------------------------- /src/org/swiftp/CmdRNTO.java: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2009 David Revell 3 | 4 | This file is part of SwiFTP. 5 | 6 | SwiFTP is free software: you can redistribute it and/or modify 7 | it under the terms of the GNU General Public License as published by 8 | the Free Software Foundation, either version 3 of the License, or 9 | (at your option) any later version. 10 | 11 | SwiFTP is distributed in the hope that it will be useful, 12 | but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | GNU General Public License for more details. 15 | 16 | You should have received a copy of the GNU General Public License 17 | along with SwiFTP. If not, see . 18 | */ 19 | 20 | package org.swiftp; 21 | 22 | import java.io.File; 23 | 24 | import android.util.Log; 25 | 26 | public class CmdRNTO extends FtpCmd implements Runnable { 27 | protected String input; 28 | 29 | public CmdRNTO(SessionThread sessionThread, String input) { 30 | super(sessionThread, CmdRNTO.class.toString()); 31 | this.input = input; 32 | } 33 | 34 | public void run() { 35 | String param = getParameter(input); 36 | String errString = null; 37 | File toFile = null; 38 | myLog.l(Log.DEBUG, "RNTO executing\r\n"); 39 | mainblock: { 40 | myLog.l(Log.INFO, "param: " + param); 41 | toFile = inputPathToChrootedFile(sessionThread.getWorkingDir(), param); 42 | myLog.l(Log.INFO, "RNTO parsed: " + toFile.getPath()); 43 | if(violatesChroot(toFile)) { 44 | errString = "550 Invalid name or chroot violation\r\n"; 45 | break mainblock; 46 | } 47 | File fromFile = sessionThread.getRenameFrom(); 48 | if(fromFile == null) { 49 | errString = "550 Rename error, maybe RNFR not sent\r\n"; 50 | break mainblock; 51 | } 52 | if(!fromFile.renameTo(toFile)) { 53 | errString = "550 Error during rename operation\r\n"; 54 | break mainblock; 55 | } 56 | } 57 | if(errString != null) { 58 | sessionThread.writeString(errString); 59 | myLog.l(Log.INFO, "RNFR failed: " + errString.trim()); 60 | } else { 61 | sessionThread.writeString("250 rename successful\r\n"); 62 | } 63 | sessionThread.setRenameFrom(null); 64 | myLog.l(Log.DEBUG, "RNTO finished"); 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /src/org/swiftp/CmdMKD.java: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2009 David Revell 3 | 4 | This file is part of SwiFTP. 5 | 6 | SwiFTP is free software: you can redistribute it and/or modify 7 | it under the terms of the GNU General Public License as published by 8 | the Free Software Foundation, either version 3 of the License, or 9 | (at your option) any later version. 10 | 11 | SwiFTP is distributed in the hope that it will be useful, 12 | but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | GNU General Public License for more details. 15 | 16 | You should have received a copy of the GNU General Public License 17 | along with SwiFTP. If not, see . 18 | */ 19 | 20 | package org.swiftp; 21 | 22 | import java.io.File; 23 | 24 | import android.util.Log; 25 | 26 | public class CmdMKD extends FtpCmd implements Runnable { 27 | String input; 28 | 29 | public CmdMKD(SessionThread sessionThread, String input) { 30 | super(sessionThread, CmdMKD.class.toString()); 31 | this.input = input; 32 | } 33 | 34 | public void run() { 35 | myLog.l(Log.DEBUG, "MKD executing"); 36 | String param = getParameter(input); 37 | File toCreate; 38 | String errString = null; 39 | mainblock: { 40 | // If the param is an absolute path, use it as is. If it's a 41 | // relative path, prepend the current working directory. 42 | if(param.length() < 1) { 43 | errString = "550 Invalid name\r\n"; 44 | break mainblock; 45 | } 46 | toCreate = inputPathToChrootedFile(sessionThread.getWorkingDir(), param); 47 | if(violatesChroot(toCreate)) { 48 | errString = "550 Invalid name or chroot violation\r\n"; 49 | break mainblock; 50 | } 51 | if(toCreate.exists()) { 52 | errString = "550 Already exists\r\n"; 53 | break mainblock; 54 | } 55 | if(!toCreate.mkdir()) { 56 | errString = "550 Error making directory (permissions?)\r\n"; 57 | break mainblock; 58 | } 59 | } 60 | if(errString != null) { 61 | sessionThread.writeString(errString); 62 | myLog.l(Log.INFO, "MKD error: " + errString.trim()); 63 | } else { 64 | sessionThread.writeString("250 Directory created\r\n"); 65 | } 66 | myLog.l(Log.INFO, "MKD complete"); 67 | } 68 | 69 | } 70 | -------------------------------------------------------------------------------- /src/org/swiftp/CmdCWD.java: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2009 David Revell 3 | 4 | This file is part of SwiFTP. 5 | 6 | SwiFTP is free software: you can redistribute it and/or modify 7 | it under the terms of the GNU General Public License as published by 8 | the Free Software Foundation, either version 3 of the License, or 9 | (at your option) any later version. 10 | 11 | SwiFTP is distributed in the hope that it will be useful, 12 | but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | GNU General Public License for more details. 15 | 16 | You should have received a copy of the GNU General Public License 17 | along with SwiFTP. If not, see . 18 | */ 19 | 20 | package org.swiftp; 21 | 22 | import java.io.File; 23 | import java.io.IOException; 24 | 25 | import android.util.Log; 26 | 27 | public class CmdCWD extends FtpCmd implements Runnable { 28 | protected String input; 29 | 30 | public CmdCWD(SessionThread sessionThread, String input) { 31 | super(sessionThread, CmdCWD.class.toString()); 32 | this.input = input; 33 | } 34 | 35 | public void run() { 36 | myLog.l(Log.DEBUG, "CWD executing"); 37 | String param = getParameter(input); 38 | File newDir; 39 | String errString = null; 40 | mainblock: { 41 | newDir = inputPathToChrootedFile(sessionThread.getWorkingDir(), param); 42 | 43 | // Ensure the new path does not violate the chroot restriction 44 | if(violatesChroot(newDir)) { 45 | errString = "550 Invalid name or chroot violation\r\n"; 46 | sessionThread.writeString(errString); 47 | myLog.l(Log.INFO, errString); 48 | break mainblock; 49 | } 50 | 51 | try { 52 | newDir = newDir.getCanonicalFile(); 53 | if(!newDir.isDirectory()) { 54 | sessionThread.writeString("550 Can't CWD to invalid directory\r\n"); 55 | } else if(newDir.canRead()) { 56 | sessionThread.setWorkingDir(newDir); 57 | sessionThread.writeString("250 CWD successful\r\n"); 58 | } else { 59 | sessionThread.writeString("550 That path is inaccessible\r\n"); 60 | } 61 | } catch(IOException e) { 62 | sessionThread.writeString("550 Invalid path\r\n"); 63 | break mainblock; 64 | } 65 | } 66 | myLog.l(Log.DEBUG, "CWD complete"); 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /src/net/micode/fileexplorer/IFileInteractionListener.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2010-2011, The MiCode Open Source Community (www.micode.net) 3 | * 4 | * This file is part of FileExplorer. 5 | * 6 | * FileExplorer is free software: you can redistribute it and/or modify 7 | * it under the terms of the GNU General Public License as published by 8 | * the Free Software Foundation, either version 3 of the License, or 9 | * (at your option) any later version. 10 | * 11 | * FileExplorer is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU General Public License 17 | * along with SwiFTP. If not, see . 18 | */ 19 | 20 | package net.micode.fileexplorer; 21 | 22 | import android.content.Context; 23 | import android.content.Intent; 24 | import android.view.View; 25 | 26 | import java.util.Collection; 27 | 28 | public interface IFileInteractionListener { 29 | 30 | public View getViewById(int id); 31 | 32 | public Context getContext(); 33 | 34 | public void startActivity(Intent intent); 35 | 36 | public void onDataChanged(); 37 | 38 | public void onPick(FileInfo f); 39 | 40 | public boolean shouldShowOperationPane(); 41 | 42 | /** 43 | * Handle operation listener. 44 | * @param id 45 | * @return true: indicate have operated it; false: otherwise. 46 | */ 47 | public boolean onOperation(int id); 48 | 49 | public String getDisplayPath(String path); 50 | 51 | public String getRealPath(String displayPath); 52 | 53 | public void runOnUiThread(Runnable r); 54 | 55 | // return true indicates the navigation has been handled 56 | public boolean onNavigation(String path); 57 | 58 | public boolean shouldHideMenu(int menu); 59 | 60 | public FileIconHelper getFileIconHelper(); 61 | 62 | public FileInfo getItem(int pos); 63 | 64 | public void sortCurrentList(FileSortHelper sort); 65 | 66 | public Collection getAllFiles(); 67 | 68 | public void addSingleFile(FileInfo file); 69 | 70 | public boolean onRefreshFileList(String path, FileSortHelper sort); 71 | 72 | public int getItemCount(); 73 | } 74 | -------------------------------------------------------------------------------- /src/org/swiftp/DataSocketFactory.java: -------------------------------------------------------------------------------- 1 | package org.swiftp; 2 | 3 | import java.net.InetAddress; 4 | import java.net.Socket; 5 | 6 | 7 | abstract public class DataSocketFactory { 8 | 9 | /** 10 | * A DataSocketFactory hides the implementation of the opening and closing 11 | * of the data sockets which are used to transmit directory listings and 12 | * file contents. This is necessary because normal FTP data sockets are 13 | * opened and closed very differently from the abnormal sort of data sockets 14 | * we use in conjunction with our proxy system. 15 | */ 16 | protected MyLog myLog = new MyLog(getClass().getName()); 17 | 18 | /** 19 | * When SwiFTP receives a PORT command, this will be called. Subclasses should 20 | * perform whatever initialization is necessary. 21 | * @return Whether the necessary actions completed successfully 22 | */ 23 | abstract public boolean onPort(InetAddress dest, int port); 24 | 25 | /** 26 | * When SwiFTP receives a PASV command, this will be called. Subclasses should 27 | * perform whatever initialization is necessary. 28 | * @return Whether the necessary actions completed successfully 29 | */ 30 | abstract public int onPasv(); 31 | 32 | /** 33 | * When it's time for data transfer to begin, the SessionThread will call this 34 | * method to perform any necessary actions to prepare the Socket for use and 35 | * return it in a state that's ready for reading or writing. 36 | * @return The opened Socket 37 | */ 38 | abstract public Socket onTransfer(); 39 | 40 | /** 41 | * Sometimes we'll need to know the IP address at which we can be contacted. For 42 | * instance, the response to a PASV command will be the IP and port that the 43 | * client should use to connect it's data socket. 44 | */ 45 | abstract public InetAddress getPasvIp(); 46 | 47 | /** 48 | * We sometimes want to track the total number of bytes that go over the 49 | * command and data sockets. The SessionThread can call this function to 50 | * reports its usage, and different DataSocketFactory subclasses can 51 | * handle the data however is appropriate. For the ProxyDataSocketFactory, 52 | * we want to present the total to the user in the UI to guilt them into 53 | * donating. 54 | * @param numBytes the number of bytes to add to the total 55 | */ 56 | abstract public void reportTraffic(long numBytes); 57 | } 58 | 59 | -------------------------------------------------------------------------------- /src/org/swiftp/WifiStateReceiver.java: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2009 David Revell 3 | 4 | This file is part of SwiFTP. 5 | 6 | SwiFTP is free software: you can redistribute it and/or modify 7 | it under the terms of the GNU General Public License as published by 8 | the Free Software Foundation, either version 3 of the License, or 9 | (at your option) any later version. 10 | 11 | SwiFTP is distributed in the hope that it will be useful, 12 | but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | GNU General Public License for more details. 15 | 16 | You should have received a copy of the GNU General Public License 17 | along with SwiFTP. If not, see . 18 | */ 19 | 20 | /*package org.swiftp; 21 | 22 | import android.content.BroadcastReceiver; 23 | import android.content.Context; 24 | import android.content.Intent; 25 | import android.content.SharedPreferences; 26 | import android.net.NetworkInfo; 27 | import android.net.NetworkInfo.State; 28 | import android.net.wifi.WifiManager; 29 | import android.util.Log; 30 | 31 | public class WifiStateReceiver extends BroadcastReceiver { 32 | 33 | @Override 34 | public void onReceive(Context context, Intent wifiIntent) { 35 | MyLog myLog = new MyLog(this.getClass().getName()); 36 | myLog.l(Log.DEBUG, "WifiStateReceiver running!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!"); 37 | SharedPreferences settings; 38 | if(context == null) { 39 | myLog.l(Log.INFO, "Null context in WifiStateReceiver"); 40 | return; 41 | } 42 | settings = context.getSharedPreferences(Defaults.getSettingsName(), 43 | Defaults.getSettingsMode()); 44 | if(wifiIntent.getAction() == WifiManager.NETWORK_STATE_CHANGED_ACTION) { 45 | NetworkInfo netInfo; 46 | netInfo = (NetworkInfo)wifiIntent.getParcelableExtra( 47 | WifiManager.EXTRA_NETWORK_INFO); 48 | Intent intent = new Intent(context, FTPServerService.class); 49 | if(netInfo.getState() == State.CONNECTED) { 50 | myLog.l(Log.DEBUG, "Wifi up"); 51 | if(settings.getBoolean("autostart", false) == true) { 52 | myLog.l(Log.INFO, "Autostart on, starting server"); 53 | context.startService(intent); 54 | } 55 | } else { 56 | // Wifi is connecting or shutting down, but not up 57 | myLog.l(Log.INFO, "Stopping service due to unconnected wifi"); 58 | context.stopService(intent); 59 | } 60 | } 61 | } 62 | 63 | } 64 | */ -------------------------------------------------------------------------------- /src/org/swiftp/CmdCDUP.java: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2009 David Revell 3 | 4 | This file is part of SwiFTP. 5 | 6 | SwiFTP is free software: you can redistribute it and/or modify 7 | it under the terms of the GNU General Public License as published by 8 | the Free Software Foundation, either version 3 of the License, or 9 | (at your option) any later version. 10 | 11 | SwiFTP is distributed in the hope that it will be useful, 12 | but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | GNU General Public License for more details. 15 | 16 | You should have received a copy of the GNU General Public License 17 | along with SwiFTP. If not, see . 18 | */ 19 | 20 | package org.swiftp; 21 | 22 | import java.io.File; 23 | import java.io.IOException; 24 | 25 | import android.util.Log; 26 | 27 | public class CmdCDUP extends FtpCmd implements Runnable { 28 | protected String input; 29 | 30 | public CmdCDUP(SessionThread sessionThread, String input) { 31 | super(sessionThread, CmdCDUP.class.toString()); 32 | } 33 | 34 | public void run() { 35 | myLog.l(Log.DEBUG, "CDUP executing"); 36 | File newDir; 37 | String errString = null; 38 | mainBlock: { 39 | File workingDir = sessionThread.getWorkingDir(); 40 | newDir = workingDir.getParentFile(); 41 | if(newDir == null) { 42 | errString = "550 Current dir cannot find parent\r\n"; 43 | break mainBlock; 44 | } 45 | // Ensure the new path does not violate the chroot restriction 46 | if(violatesChroot(newDir)) { 47 | errString = "550 Invalid name or chroot violation\r\n"; 48 | break mainBlock; 49 | } 50 | 51 | try { 52 | newDir = newDir.getCanonicalFile(); 53 | if(!newDir.isDirectory()) { 54 | errString = "550 Can't CWD to invalid directory\r\n"; 55 | break mainBlock; 56 | } else if(newDir.canRead()) { 57 | sessionThread.setWorkingDir(newDir); 58 | } else { 59 | errString = "550 That path is inaccessible\r\n"; 60 | break mainBlock; 61 | } 62 | } catch(IOException e) { 63 | errString = "550 Invalid path\r\n"; 64 | break mainBlock; 65 | } 66 | } 67 | if(errString != null) { 68 | sessionThread.writeString(errString); 69 | myLog.i("CDUP error: " + errString); 70 | } else { 71 | sessionThread.writeString("200 CDUP successful\r\n"); 72 | myLog.l(Log.DEBUG, "CDUP success"); 73 | } 74 | } 75 | } 76 | -------------------------------------------------------------------------------- /src/org/swiftp/CmdOPTS.java: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2009 David Revell 3 | 4 | This file is part of SwiFTP. 5 | 6 | SwiFTP is free software: you can redistribute it and/or modify 7 | it under the terms of the GNU General Public License as published by 8 | the Free Software Foundation, either version 3 of the License, or 9 | (at your option) any later version. 10 | 11 | SwiFTP is distributed in the hope that it will be useful, 12 | but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | GNU General Public License for more details. 15 | 16 | You should have received a copy of the GNU General Public License 17 | along with SwiFTP. If not, see . 18 | */ 19 | 20 | package org.swiftp; 21 | 22 | 23 | public class CmdOPTS extends FtpCmd implements Runnable { 24 | public static final String message = "TEMPLATE!!"; 25 | private String input; 26 | 27 | public CmdOPTS(SessionThread sessionThread, String input) { 28 | super(sessionThread, CmdOPTS.class.toString()); 29 | this.input = input; 30 | } 31 | 32 | public void run() { 33 | String param = getParameter(input); 34 | String errString = null; 35 | 36 | mainBlock: { 37 | if(param == null) { 38 | errString = "550 Need argument to OPTS\r\n"; 39 | myLog.w("Couldn't understand empty OPTS command"); 40 | break mainBlock; 41 | } 42 | String[] splits = param.split(" "); 43 | if(splits.length != 2) { 44 | errString = "550 Malformed OPTS command\r\n"; 45 | myLog.w("Couldn't parse OPTS command"); 46 | break mainBlock; 47 | } 48 | String optName = splits[0].toUpperCase(); 49 | String optVal = splits[1].toUpperCase(); 50 | if(optName.equals("UTF8")) { 51 | // OK, whatever. Don't really know what to do here. We 52 | // always operate in UTF8 mode. 53 | if(optVal.equals("ON")) { 54 | myLog.d("Got OPTS UTF8 ON"); 55 | sessionThread.setEncoding("UTF-8"); 56 | } else { 57 | myLog.i("Ignoring OPTS UTF8 for something besides ON"); 58 | } 59 | break mainBlock; 60 | } else { 61 | myLog.d("Unrecognized OPTS option: " + optName); 62 | errString = "502 Unrecognized option\r\n"; 63 | break mainBlock; 64 | } 65 | } 66 | if(errString != null) { 67 | sessionThread.writeString(errString); 68 | myLog.i("Template log message"); 69 | } else { 70 | sessionThread.writeString("200 OPTS accepted\r\n"); 71 | myLog.d("Handled OPTS ok"); 72 | } 73 | } 74 | 75 | } 76 | -------------------------------------------------------------------------------- /src/org/swiftp/Globals.java: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2009 David Revell 3 | 4 | This file is part of SwiFTP. 5 | 6 | SwiFTP is free software: you can redistribute it and/or modify 7 | it under the terms of the GNU General Public License as published by 8 | the Free Software Foundation, either version 3 of the License, or 9 | (at your option) any later version. 10 | 11 | SwiFTP is distributed in the hope that it will be useful, 12 | but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | GNU General Public License for more details. 15 | 16 | You should have received a copy of the GNU General Public License 17 | along with SwiFTP. If not, see . 18 | */ 19 | 20 | package org.swiftp; 21 | 22 | import java.io.File; 23 | 24 | import android.content.Context; 25 | 26 | public class Globals { 27 | private static Context context; 28 | private static String lastError; 29 | private static File chrootDir = new File(Defaults.chrootDir); 30 | private static ProxyConnector proxyConnector = null; 31 | private static String username = null; 32 | 33 | public static ProxyConnector getProxyConnector() { 34 | if(proxyConnector != null) { 35 | if(!proxyConnector.isAlive()) { 36 | return null; 37 | } 38 | } 39 | return proxyConnector; 40 | } 41 | 42 | public static void setProxyConnector(ProxyConnector proxyConnector) { 43 | Globals.proxyConnector = proxyConnector; 44 | } 45 | 46 | public static File getChrootDir() { 47 | return chrootDir; 48 | } 49 | 50 | public static void setChrootDir(File chrootDir) { 51 | if(chrootDir.isDirectory()) { 52 | Globals.chrootDir = chrootDir; 53 | } 54 | } 55 | 56 | public static String getLastError() { 57 | return lastError; 58 | } 59 | 60 | public static void setLastError(String lastError) { 61 | Globals.lastError = lastError; 62 | } 63 | 64 | public static Context getContext() { 65 | return context; 66 | } 67 | 68 | public static void setContext(Context context) { 69 | if(context != null) { 70 | Globals.context = context; 71 | } 72 | } 73 | 74 | public static String getUsername() { 75 | return username; 76 | } 77 | 78 | public static void setUsername(String username) { 79 | Globals.username = username; 80 | } 81 | 82 | } 83 | -------------------------------------------------------------------------------- /src/org/swiftp/CmdPASV.java: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2009 David Revell 3 | 4 | This file is part of SwiFTP. 5 | 6 | SwiFTP is free software: you can redistribute it and/or modify 7 | it under the terms of the GNU General Public License as published by 8 | the Free Software Foundation, either version 3 of the License, or 9 | (at your option) any later version. 10 | 11 | SwiFTP is distributed in the hope that it will be useful, 12 | but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | GNU General Public License for more details. 15 | 16 | You should have received a copy of the GNU General Public License 17 | along with SwiFTP. If not, see . 18 | */ 19 | 20 | package org.swiftp; 21 | 22 | import java.net.InetAddress; 23 | 24 | import android.util.Log; 25 | 26 | public class CmdPASV extends FtpCmd implements Runnable { 27 | //public static final String message = "TEMPLATE!!"; 28 | 29 | public CmdPASV(SessionThread sessionThread, String input) { 30 | super(sessionThread, CmdPASV.class.toString()); 31 | } 32 | 33 | public void run() { 34 | String cantOpen = "502 Couldn't open a port\r\n"; 35 | myLog.l(Log.DEBUG, "PASV running"); 36 | int port; 37 | if((port = sessionThread.onPasv()) == 0) { 38 | // There was a problem opening a port 39 | myLog.l(Log.ERROR, "Couldn't open a port for PASV"); 40 | sessionThread.writeString(cantOpen); 41 | return; 42 | } 43 | InetAddress addr = sessionThread.getDataSocketPasvIp(); 44 | 45 | if(addr == null) { 46 | myLog.l(Log.ERROR, "PASV IP string invalid"); 47 | sessionThread.writeString(cantOpen); 48 | return; 49 | } 50 | myLog.d("PASV sending IP: " + addr.getHostAddress()); 51 | if(port < 1) { 52 | myLog.l(Log.ERROR, "PASV port number invalid"); 53 | sessionThread.writeString(cantOpen); 54 | return; 55 | } 56 | StringBuilder response = new StringBuilder( 57 | "227 Entering Passive Mode ("); 58 | // Output our IP address in the format xxx,xxx,xxx,xxx 59 | response.append(addr.getHostAddress().replace('.', ',')); 60 | response.append(","); 61 | 62 | // Output our port in the format p1,p2 where port=p1*256+p2 63 | response.append(port / 256); 64 | response.append(","); 65 | response.append(port % 256); 66 | response.append(").\r\n"); 67 | String responseString = response.toString(); 68 | sessionThread.writeString(responseString); 69 | myLog.l(Log.DEBUG, "PASV completed, sent: " + responseString); 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /src/org/swiftp/Settings.java: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2009 David Revell 3 | 4 | This file is part of SwiFTP. 5 | 6 | SwiFTP is free software: you can redistribute it and/or modify 7 | it under the terms of the GNU General Public License as published by 8 | the Free Software Foundation, either version 3 of the License, or 9 | (at your option) any later version. 10 | 11 | SwiFTP is distributed in the hope that it will be useful, 12 | but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | GNU General Public License for more details. 15 | 16 | You should have received a copy of the GNU General Public License 17 | along with SwiFTP. If not, see . 18 | */ 19 | 20 | package org.swiftp; 21 | 22 | import android.util.Log; 23 | 24 | public class Settings { 25 | protected static int inputBufferSize = 256; 26 | protected static boolean allowOverwrite = false; 27 | protected static int dataChunkSize = 8192; // do file I/O in 8k chunks 28 | protected static int sessionMonitorScrollBack = 10; 29 | protected static int serverLogScrollBack = 10; 30 | protected static int uiLogLevel = Log.INFO; 31 | 32 | public static int getUiLogLevel() { 33 | return uiLogLevel; 34 | } 35 | 36 | public static void setUiLogLevel(int uiLogLevel) { 37 | Settings.uiLogLevel = uiLogLevel; 38 | } 39 | 40 | public static int getInputBufferSize() { 41 | return inputBufferSize; 42 | } 43 | 44 | public static void setInputBufferSize(int inputBufferSize) { 45 | Settings.inputBufferSize = inputBufferSize; 46 | } 47 | 48 | public static boolean isAllowOverwrite() { 49 | return allowOverwrite; 50 | } 51 | 52 | public static void setAllowOverwrite(boolean allowOverwrite) { 53 | Settings.allowOverwrite = allowOverwrite; 54 | } 55 | 56 | public static int getDataChunkSize() { 57 | return dataChunkSize; 58 | } 59 | 60 | public static void setDataChunkSize(int dataChunkSize) { 61 | Settings.dataChunkSize = dataChunkSize; 62 | } 63 | 64 | public static int getSessionMonitorScrollBack() { 65 | return sessionMonitorScrollBack; 66 | } 67 | 68 | public static void setSessionMonitorScrollBack( 69 | int sessionMonitorScrollBack) 70 | { 71 | Settings.sessionMonitorScrollBack = sessionMonitorScrollBack; 72 | } 73 | 74 | public static int getServerLogScrollBack() { 75 | return serverLogScrollBack; 76 | } 77 | 78 | public static void setLogScrollBack(int serverLogScrollBack) { 79 | Settings.serverLogScrollBack = serverLogScrollBack; 80 | } 81 | 82 | 83 | } 84 | -------------------------------------------------------------------------------- /src/org/swiftp/CmdPWD.java: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2009 David Revell 3 | 4 | This file is part of SwiFTP. 5 | 6 | SwiFTP is free software: you can redistribute it and/or modify 7 | it under the terms of the GNU General Public License as published by 8 | the Free Software Foundation, either version 3 of the License, or 9 | (at your option) any later version. 10 | 11 | SwiFTP is distributed in the hope that it will be useful, 12 | but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | GNU General Public License for more details. 15 | 16 | You should have received a copy of the GNU General Public License 17 | along with SwiFTP. If not, see . 18 | */ 19 | 20 | package org.swiftp; 21 | 22 | import java.io.File; 23 | import java.io.IOException; 24 | 25 | import android.util.Log; 26 | 27 | public class CmdPWD extends FtpCmd implements Runnable { 28 | // public static final String message = "TEMPLATE!!"; 29 | 30 | public CmdPWD(SessionThread sessionThread, String input) { 31 | super(sessionThread, CmdPWD.class.toString()); 32 | } 33 | 34 | public void run() { 35 | myLog.l(Log.DEBUG, "PWD executing"); 36 | 37 | // We assume that the chroot restriction has been applied, and that 38 | // therefore the current directory is located somewhere within the 39 | // chroot directory. Therefore, we can just slice of the chroot 40 | // part of the current directory path in order to get the 41 | // user-visible path (inside the chroot directory). 42 | try { 43 | File workingDir = sessionThread.getWorkingDir(); 44 | String currentDir = workingDir != null ? workingDir.getCanonicalPath() : Globals.getChrootDir() 45 | .getCanonicalPath(); 46 | currentDir = currentDir.substring(Globals.getChrootDir().getCanonicalPath().length()); 47 | // The root directory requires special handling to restore its 48 | // leading slash 49 | if (currentDir.length() == 0) { 50 | currentDir = "/"; 51 | } 52 | sessionThread.writeString("257 \"" + currentDir + "\"\r\n"); 53 | } catch (IOException e) { 54 | // This shouldn't happen unless our input validation has failed 55 | myLog.l(Log.ERROR, "PWD canonicalize"); 56 | sessionThread.closeSocket(); // should cause thread termination 57 | } 58 | myLog.l(Log.DEBUG, "PWD complete"); 59 | } 60 | 61 | } 62 | -------------------------------------------------------------------------------- /src/net/micode/fileexplorer/FileListAdapter.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2010-2011, The MiCode Open Source Community (www.micode.net) 3 | * 4 | * This file is part of FileExplorer. 5 | * 6 | * FileExplorer is free software: you can redistribute it and/or modify 7 | * it under the terms of the GNU General Public License as published by 8 | * the Free Software Foundation, either version 3 of the License, or 9 | * (at your option) any later version. 10 | * 11 | * FileExplorer is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU General Public License 17 | * along with SwiFTP. If not, see . 18 | */ 19 | 20 | package net.micode.fileexplorer; 21 | 22 | import android.content.Context; 23 | import android.view.LayoutInflater; 24 | import android.view.View; 25 | import android.view.ViewGroup; 26 | import android.widget.ArrayAdapter; 27 | 28 | import java.util.List; 29 | 30 | public class FileListAdapter extends ArrayAdapter { 31 | private LayoutInflater mInflater; 32 | 33 | private FileViewInteractionHub mFileViewInteractionHub; 34 | 35 | private FileIconHelper mFileIcon; 36 | 37 | private Context mContext; 38 | 39 | public FileListAdapter(Context context, int resource, 40 | List objects, FileViewInteractionHub f, 41 | FileIconHelper fileIcon) { 42 | super(context, resource, objects); 43 | mInflater = LayoutInflater.from(context); 44 | mFileViewInteractionHub = f; 45 | mFileIcon = fileIcon; 46 | mContext = context; 47 | } 48 | 49 | @Override 50 | public View getView(int position, View convertView, ViewGroup parent) { 51 | View view = null; 52 | if (convertView != null) { 53 | view = convertView; 54 | } else { 55 | view = mInflater.inflate(R.layout.file_browser_item, parent, false); 56 | } 57 | 58 | FileInfo lFileInfo = mFileViewInteractionHub.getItem(position); 59 | FileListItem.setupFileListItemInfo(mContext, view, lFileInfo, 60 | mFileIcon, mFileViewInteractionHub); 61 | view.findViewById(R.id.file_checkbox_area).setOnClickListener( 62 | new FileListItem.FileItemOnClickListener(mContext, 63 | mFileViewInteractionHub)); 64 | return view; 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /res/layout/favorite_item.xml: -------------------------------------------------------------------------------- 1 | 2 | 10 | 11 | 16 | 25 | 32 | 33 | 41 | 42 | 48 | 49 | 53 | 60 | 68 | 69 | 70 | 71 | 72 | -------------------------------------------------------------------------------- /src/org/swiftp/CmdRMD.java: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2009 David Revell 3 | 4 | This file is part of SwiFTP. 5 | 6 | SwiFTP is free software: you can redistribute it and/or modify 7 | it under the terms of the GNU General Public License as published by 8 | the Free Software Foundation, either version 3 of the License, or 9 | (at your option) any later version. 10 | 11 | SwiFTP is distributed in the hope that it will be useful, 12 | but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | GNU General Public License for more details. 15 | 16 | You should have received a copy of the GNU General Public License 17 | along with SwiFTP. If not, see . 18 | */ 19 | 20 | package org.swiftp; 21 | 22 | import java.io.File; 23 | 24 | import android.util.Log; 25 | 26 | public class CmdRMD extends FtpCmd implements Runnable { 27 | public static final String message = "TEMPLATE!!"; 28 | protected String input; 29 | 30 | public CmdRMD(SessionThread sessionThread, String input) { 31 | super(sessionThread, CmdRMD.class.toString()); 32 | this.input = input; 33 | } 34 | 35 | public void run() { 36 | myLog.l(Log.INFO, "RMD executing"); 37 | String param = getParameter(input); 38 | File toRemove; 39 | String errString = null; 40 | mainblock: { 41 | if(param.length() < 1) { 42 | errString = "550 Invalid argument\r\n"; 43 | break mainblock; 44 | } 45 | toRemove = inputPathToChrootedFile(sessionThread.getWorkingDir(), param); 46 | if(violatesChroot(toRemove)) { 47 | errString = "550 Invalid name or chroot violation\r\n"; 48 | break mainblock; 49 | } 50 | if(!toRemove.isDirectory()) { 51 | errString = "550 Can't RMD a non-directory\r\n"; 52 | break mainblock; 53 | } 54 | if(toRemove.equals(new File("/"))) { 55 | errString = "550 Won't RMD the root directory\r\n"; 56 | break mainblock; 57 | } 58 | if(!recursiveDelete(toRemove)) { 59 | errString = "550 Deletion error, possibly incomplete\r\n"; 60 | break mainblock; 61 | } 62 | } 63 | if(errString != null) { 64 | sessionThread.writeString(errString); 65 | myLog.l(Log.INFO, "RMD failed: " + errString.trim()); 66 | } else { 67 | sessionThread.writeString("250 Removed directory\r\n"); 68 | } 69 | myLog.l(Log.DEBUG, "RMD finished"); 70 | } 71 | 72 | /** 73 | * Accepts a file or directory name, and recursively deletes the contents 74 | * of that directory and all subdirectories. 75 | * @param toDelete 76 | * @return Whether the operation completed successfully 77 | */ 78 | protected boolean recursiveDelete(File toDelete) { 79 | if(!toDelete.exists()) { 80 | return false; 81 | } 82 | if(toDelete.isDirectory()) { 83 | // If any of the recursive operations fail, then we return false 84 | boolean success = true; 85 | for(File entry : toDelete.listFiles()) { 86 | success &= recursiveDelete(entry); 87 | } 88 | myLog.l(Log.DEBUG, "Recursively deleted: " + toDelete); 89 | return success && toDelete.delete(); 90 | } else { 91 | myLog.l(Log.DEBUG, "RMD deleting file: " + toDelete); 92 | return toDelete.delete(); 93 | } 94 | } 95 | } 96 | -------------------------------------------------------------------------------- /src/net/micode/fileexplorer/TextInputDialog.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2010-2011, The MiCode Open Source Community (www.micode.net) 3 | * 4 | * This file is part of FileExplorer. 5 | * 6 | * FileExplorer is free software: you can redistribute it and/or modify 7 | * it under the terms of the GNU General Public License as published by 8 | * the Free Software Foundation, either version 3 of the License, or 9 | * (at your option) any later version. 10 | * 11 | * FileExplorer is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU General Public License 17 | * along with SwiFTP. If not, see . 18 | */ 19 | 20 | package net.micode.fileexplorer; 21 | 22 | import android.app.AlertDialog; 23 | import android.content.Context; 24 | import android.content.DialogInterface; 25 | import android.os.Bundle; 26 | import android.view.View; 27 | import android.widget.EditText; 28 | 29 | public class TextInputDialog extends AlertDialog { 30 | private String mInputText; 31 | private String mTitle; 32 | private String mMsg; 33 | private OnFinishListener mListener; 34 | private Context mContext; 35 | private View mView; 36 | private EditText mFolderName; 37 | 38 | public interface OnFinishListener { 39 | // return true to accept and dismiss, false reject 40 | boolean onFinish(String text); 41 | } 42 | 43 | public TextInputDialog(Context context, String title, String msg, String text, OnFinishListener listener) { 44 | super(context); 45 | mTitle = title; 46 | mMsg = msg; 47 | mListener = listener; 48 | mInputText = text; 49 | mContext = context; 50 | } 51 | 52 | public String getInputText() { 53 | return mInputText; 54 | } 55 | 56 | protected void onCreate(Bundle savedInstanceState) { 57 | mView = getLayoutInflater().inflate(R.layout.textinput_dialog, null); 58 | 59 | setTitle(mTitle); 60 | setMessage(mMsg); 61 | 62 | mFolderName = (EditText) mView.findViewById(R.id.text); 63 | mFolderName.setText(mInputText); 64 | 65 | setView(mView); 66 | setButton(BUTTON_POSITIVE, mContext.getString(android.R.string.ok), 67 | new DialogInterface.OnClickListener() { 68 | @Override 69 | public void onClick(DialogInterface dialog, int which) { 70 | if (which == BUTTON_POSITIVE) { 71 | mInputText = mFolderName.getText().toString(); 72 | if (mListener.onFinish(mInputText)) { 73 | dismiss(); 74 | } 75 | } 76 | } 77 | }); 78 | setButton(BUTTON_NEGATIVE, mContext.getString(android.R.string.cancel), 79 | (DialogInterface.OnClickListener) null); 80 | 81 | super.onCreate(savedInstanceState); 82 | } 83 | } 84 | -------------------------------------------------------------------------------- /src/org/swiftp/CmdPORT.java: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2009 David Revell 3 | 4 | This file is part of SwiFTP. 5 | 6 | SwiFTP is free software: you can redistribute it and/or modify 7 | it under the terms of the GNU General Public License as published by 8 | the Free Software Foundation, either version 3 of the License, or 9 | (at your option) any later version. 10 | 11 | SwiFTP is distributed in the hope that it will be useful, 12 | but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | GNU General Public License for more details. 15 | 16 | You should have received a copy of the GNU General Public License 17 | along with SwiFTP. If not, see . 18 | */ 19 | 20 | package org.swiftp; 21 | 22 | import java.net.InetAddress; 23 | import java.net.UnknownHostException; 24 | 25 | import android.util.Log; 26 | 27 | public class CmdPORT extends FtpCmd implements Runnable { 28 | //public static final String message = "TEMPLATE!!"; 29 | String input; 30 | 31 | public CmdPORT(SessionThread sessionThread, String input) { 32 | super(sessionThread, CmdPORT.class.toString()); 33 | this.input = input; 34 | } 35 | 36 | public void run() { 37 | myLog.l(Log.DEBUG, "PORT running"); 38 | String errString = null; 39 | mainBlock: { 40 | String param = getParameter(input); 41 | if(param.contains("|") && param.contains("::")) { 42 | errString = "550 No IPv6 support, reconfigure your client\r\n"; 43 | break mainBlock; 44 | } 45 | String[] substrs = param.split(","); 46 | if(substrs.length != 6) { 47 | errString = "550 Malformed PORT argument\r\n"; 48 | break mainBlock; 49 | } 50 | for(int i=0; i 3) 54 | { 55 | errString = "550 Invalid PORT argument: " + substrs[i] + 56 | "\r\n"; 57 | break mainBlock; 58 | } 59 | } 60 | byte[] ipBytes = new byte[4]; 61 | for(int i=0; i<4; i++) { 62 | try { 63 | // We have to manually convert unsigned to signed 64 | // byte representation. 65 | int ipByteAsInt = Integer.parseInt(substrs[i]); 66 | if(ipByteAsInt >= 128) { 67 | ipByteAsInt -= 256; 68 | } 69 | ipBytes[i] = (byte)ipByteAsInt; 70 | } catch (Exception e) { 71 | errString = "550 Invalid PORT format: " 72 | + substrs[i] + "\r\n"; 73 | break mainBlock; 74 | } 75 | } 76 | InetAddress inetAddr; 77 | try { 78 | inetAddr = InetAddress.getByAddress(ipBytes); 79 | } catch (UnknownHostException e) { 80 | errString = "550 Unknown host\r\n"; 81 | break mainBlock; 82 | } 83 | 84 | int port = Integer.parseInt(substrs[4]) * 256 + 85 | Integer.parseInt(substrs[5]); 86 | 87 | sessionThread.onPort(inetAddr, port); 88 | } 89 | if(errString == null) { 90 | sessionThread.writeString("200 PORT OK\r\n"); 91 | myLog.l(Log.DEBUG, "PORT completed"); 92 | } else { 93 | myLog.l(Log.INFO, "PORT error: " + errString); 94 | sessionThread.writeString(errString); 95 | } 96 | } 97 | } 98 | -------------------------------------------------------------------------------- /src/org/swiftp/CmdPASS.java: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2009 David Revell 3 | 4 | This file is part of SwiFTP. 5 | 6 | SwiFTP is free software: you can redistribute it and/or modify 7 | it under the terms of the GNU General Public License as published by 8 | the Free Software Foundation, either version 3 of the License, or 9 | (at your option) any later version. 10 | 11 | SwiFTP is distributed in the hope that it will be useful, 12 | but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | GNU General Public License for more details. 15 | 16 | You should have received a copy of the GNU General Public License 17 | along with SwiFTP. If not, see . 18 | */ 19 | 20 | package org.swiftp; 21 | 22 | import android.content.Context; 23 | import android.content.SharedPreferences; 24 | import android.util.Log; 25 | 26 | public class CmdPASS extends FtpCmd implements Runnable { 27 | String input; 28 | 29 | public CmdPASS(SessionThread sessionThread, String input) { 30 | // We can just discard the password for now. We're just 31 | // following the expected dialogue, we're going to allow 32 | // access in any case. 33 | super(sessionThread, CmdPASS.class.toString()); 34 | this.input = input; 35 | } 36 | 37 | public void run() { 38 | // User must have already executed a USER command to 39 | // populate the Account object's username 40 | myLog.l(Log.DEBUG, "Executing PASS"); 41 | 42 | sessionThread.writeString("230 Access granted\r\n"); 43 | sessionThread.authAttempt(true); 44 | // 45 | // String attemptPassword = getParameter(input, true); // silent 46 | // String attemptUsername = sessionThread.account.getUsername(); 47 | // if(attemptUsername == null) { 48 | // sessionThread.writeString("503 Must send USER first\r\n"); 49 | // return; 50 | // } 51 | // Context ctx = Globals.getContext(); 52 | // if(ctx == null) { 53 | // // This will probably never happen, since the global 54 | // // context is configured by the Service 55 | // myLog.l(Log.ERROR, "No global context in PASS\r\n"); 56 | // } 57 | // String password; 58 | // String username; 59 | // SharedPreferences settings = ctx.getSharedPreferences( 60 | // Defaults.getSettingsName(), Defaults.getSettingsMode()); 61 | // username = settings.getString("username", null); 62 | // password = settings.getString("password", null); 63 | // if(username == null || password == null) { 64 | // myLog.l(Log.ERROR, "Username or password misconfigured"); 65 | // sessionThread.writeString("500 Internal error during authentication"); 66 | // } else if(username.equals(attemptUsername) && 67 | // password.equals(attemptPassword)) { 68 | // sessionThread.writeString("230 Access granted\r\n"); 69 | // myLog.l(Log.INFO, "User " + username + " password verified"); 70 | // sessionThread.authAttempt(true); 71 | // } else { 72 | // try { 73 | // // If the login failed, sleep for one second to foil 74 | // // brute force attacks 75 | // Thread.sleep(1000); 76 | // } catch(InterruptedException e) {} 77 | // myLog.l(Log.INFO, "Failed authentication"); 78 | // sessionThread.writeString("530 Login incorrect.\r\n"); 79 | // sessionThread.authAttempt(false); 80 | // } 81 | } 82 | } 83 | -------------------------------------------------------------------------------- /src/net/micode/fileexplorer/FavoriteListAdapter.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2010-2011, The MiCode Open Source Community (www.micode.net) 3 | * 4 | * This file is part of FileExplorer. 5 | * 6 | * FileExplorer is free software: you can redistribute it and/or modify 7 | * it under the terms of the GNU General Public License as published by 8 | * the Free Software Foundation, either version 3 of the License, or 9 | * (at your option) any later version. 10 | * 11 | * FileExplorer is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU General Public License 17 | * along with SwiFTP. If not, see . 18 | */ 19 | 20 | package net.micode.fileexplorer; 21 | 22 | import java.util.List; 23 | 24 | import android.content.Context; 25 | import android.view.LayoutInflater; 26 | import android.view.View; 27 | import android.view.ViewGroup; 28 | import android.widget.ArrayAdapter; 29 | import android.widget.ImageView; 30 | 31 | public class FavoriteListAdapter extends ArrayAdapter { 32 | private Context mContext; 33 | 34 | private LayoutInflater mInflater; 35 | 36 | private FileIconHelper mFileIcon; 37 | 38 | public FavoriteListAdapter(Context context, int resource, List objects, FileIconHelper fileIcon) { 39 | super(context, resource, objects); 40 | mContext = context; 41 | mInflater = LayoutInflater.from(context); 42 | mFileIcon = fileIcon; 43 | } 44 | 45 | @Override 46 | public View getView(int position, View convertView, ViewGroup parent) { 47 | View view = null; 48 | if (convertView != null) { 49 | view = convertView; 50 | } else { 51 | view = mInflater.inflate(R.layout.favorite_item, parent, false); 52 | } 53 | 54 | FavoriteItem item = getItem(position); 55 | FileInfo lFileInfo = item.fileInfo; 56 | 57 | Util.setText(view, R.id.file_name, item.title != null ? item.title : lFileInfo.fileName); 58 | if (lFileInfo.ModifiedDate > 0) { 59 | Util.setText(view, R.id.modified_time, Util.formatDateString(mContext, lFileInfo.ModifiedDate)); 60 | view.findViewById(R.id.modified_time).setVisibility(View.VISIBLE); 61 | } else { 62 | view.findViewById(R.id.modified_time).setVisibility(View.GONE); 63 | } 64 | view.findViewById(R.id.modified_time).setVisibility(lFileInfo.ModifiedDate > 0 ? View.VISIBLE: View.GONE); 65 | if (lFileInfo.IsDir) { 66 | view.findViewById(R.id.file_size).setVisibility(View.GONE); 67 | } else { 68 | view.findViewById(R.id.file_size).setVisibility(View.VISIBLE); 69 | Util.setText(view, R.id.file_size, Util.convertStorage(lFileInfo.fileSize)); 70 | } 71 | 72 | ImageView lFileImage = (ImageView) view.findViewById(R.id.file_image); 73 | ImageView lFileImageFrame = (ImageView) view.findViewById(R.id.file_image_frame); 74 | lFileImage.setTag(position); 75 | 76 | if (lFileInfo.IsDir) { 77 | lFileImageFrame.setVisibility(View.GONE); 78 | lFileImage.setImageResource(R.drawable.folder_fav); 79 | } else { 80 | mFileIcon.setIcon(lFileInfo, lFileImage, lFileImageFrame); 81 | } 82 | 83 | return view; 84 | } 85 | 86 | } 87 | -------------------------------------------------------------------------------- /res/layout/information_dialog.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 10 | 11 | 17 | 21 | 22 | 23 | 29 | 33 | 34 | 35 | 41 | 45 | 46 | 47 | 53 | 57 | 58 | 59 | 65 | 69 | 70 | 71 | 77 | 81 | 82 | 83 | -------------------------------------------------------------------------------- /src/org/swiftp/CmdAbstractListing.java: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2009 David Revell 3 | 4 | This file is part of SwiFTP. 5 | 6 | SwiFTP is free software: you can redistribute it and/or modify 7 | it under the terms of the GNU General Public License as published by 8 | the Free Software Foundation, either version 3 of the License, or 9 | (at your option) any later version. 10 | 11 | SwiFTP is distributed in the hope that it will be useful, 12 | but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | GNU General Public License for more details. 15 | 16 | You should have received a copy of the GNU General Public License 17 | along with SwiFTP. If not, see . 18 | */ 19 | 20 | /* 21 | * Since the FTP verbs LIST and NLST do very similar things related to listing 22 | * directory contents, the common tasks that they share have been factored 23 | * out into this abstract class. Both CmdLIST and CmdNLST inherit from this 24 | * class. 25 | */ 26 | 27 | package org.swiftp; 28 | 29 | import java.io.File; 30 | 31 | import android.util.Log; 32 | 33 | public abstract class CmdAbstractListing extends FtpCmd { 34 | protected static MyLog staticLog = new MyLog(CmdLIST.class.toString()); 35 | 36 | public CmdAbstractListing(SessionThread sessionThread, String input) { 37 | super(sessionThread, CmdAbstractListing.class.toString()); 38 | } 39 | 40 | abstract String makeLsString(File file); 41 | 42 | // Creates a directory listing by finding the contents of the directory, 43 | // calling makeLsString on each file, and concatenating the results. 44 | // Returns an error string if failure, returns null on success. May be 45 | // called by CmdLIST or CmdNLST, since they each override makeLsString 46 | // in a different way. 47 | public String listDirectory(StringBuilder response, File dir) { 48 | if(!dir.isDirectory()) { 49 | return "500 Internal error, listDirectory on non-directory\r\n"; 50 | } 51 | myLog.l(Log.DEBUG, "Listing directory: " + dir.toString()); 52 | 53 | // Get a listing of all files and directories in the path 54 | File[] entries = dir.listFiles(); 55 | if(entries == null) { 56 | return "500 Couldn't list directory. Check config and mount status.\r\n"; 57 | } 58 | myLog.l(Log.DEBUG, "Dir len " + entries.length); 59 | for(File entry : entries) { 60 | String curLine = makeLsString(entry); 61 | if(curLine != null) { 62 | response.append(curLine); 63 | } 64 | } 65 | return null; 66 | } 67 | 68 | // Send the directory listing over the data socket. Used by CmdLIST and 69 | // CmdNLST. 70 | // Returns an error string on failure, or returns null if successful. 71 | protected String sendListing(String listing) { 72 | if(sessionThread.startUsingDataSocket()) { 73 | myLog.l(Log.DEBUG, "LIST/NLST done making socket"); 74 | } else { 75 | sessionThread.closeDataSocket(); 76 | return "425 Error opening data socket\r\n"; 77 | } 78 | String mode = sessionThread.isBinaryMode() ? "BINARY" : "ASCII"; 79 | sessionThread.writeString( 80 | "150 Opening "+mode+" mode data connection for file list\r\n"); 81 | myLog.l(Log.DEBUG, "Sent code 150, sending listing string now"); 82 | if(!sessionThread.sendViaDataSocket(listing)) { 83 | myLog.l(Log.DEBUG, "sendViaDataSocket failure"); 84 | sessionThread.closeDataSocket(); 85 | return "426 Data socket or network error\r\n"; 86 | } 87 | sessionThread.closeDataSocket(); 88 | myLog.l(Log.DEBUG, "Listing sendViaDataSocket success"); 89 | sessionThread.writeString("226 Data transmission OK\r\n"); 90 | return null; 91 | } 92 | } 93 | -------------------------------------------------------------------------------- /res/layout/server_control_activity.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 8 | 14 | 21 | 30 | 36 | 37 | 42 | 50 | 57 | 58 | 73 | 74 | 83 | 90 | 91 | 92 | 93 | -------------------------------------------------------------------------------- /src/net/micode/fileexplorer/FileSortHelper.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2010-2011, The MiCode Open Source Community (www.micode.net) 3 | * 4 | * This file is part of FileExplorer. 5 | * 6 | * FileExplorer is free software: you can redistribute it and/or modify 7 | * it under the terms of the GNU General Public License as published by 8 | * the Free Software Foundation, either version 3 of the License, or 9 | * (at your option) any later version. 10 | * 11 | * FileExplorer is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU General Public License 17 | * along with SwiFTP. If not, see . 18 | */ 19 | 20 | package net.micode.fileexplorer; 21 | 22 | import java.util.Comparator; 23 | import java.util.HashMap; 24 | 25 | public class FileSortHelper { 26 | 27 | public enum SortMethod { 28 | name, size, date, type 29 | } 30 | 31 | private SortMethod mSort; 32 | 33 | private boolean mFileFirst; 34 | 35 | private HashMap mComparatorList = new HashMap(); 36 | 37 | public FileSortHelper() { 38 | mSort = SortMethod.name; 39 | mComparatorList.put(SortMethod.name, cmpName); 40 | mComparatorList.put(SortMethod.size, cmpSize); 41 | mComparatorList.put(SortMethod.date, cmpDate); 42 | mComparatorList.put(SortMethod.type, cmpType); 43 | } 44 | 45 | public void setSortMethog(SortMethod s) { 46 | mSort = s; 47 | } 48 | 49 | public SortMethod getSortMethod() { 50 | return mSort; 51 | } 52 | 53 | public void setFileFirst(boolean f) { 54 | mFileFirst = f; 55 | } 56 | 57 | public Comparator getComparator() { 58 | return mComparatorList.get(mSort); 59 | } 60 | 61 | private abstract class FileComparator implements Comparator { 62 | 63 | @Override 64 | public int compare(FileInfo object1, FileInfo object2) { 65 | if (object1.IsDir == object2.IsDir) { 66 | return doCompare(object1, object2); 67 | } 68 | 69 | if (mFileFirst) { 70 | // the files are listed before the dirs 71 | return (object1.IsDir ? 1 : -1); 72 | } else { 73 | // the dir-s are listed before the files 74 | return object1.IsDir ? -1 : 1; 75 | } 76 | } 77 | 78 | protected abstract int doCompare(FileInfo object1, FileInfo object2); 79 | } 80 | 81 | private Comparator cmpName = new FileComparator() { 82 | @Override 83 | public int doCompare(FileInfo object1, FileInfo object2) { 84 | return object1.fileName.compareToIgnoreCase(object2.fileName); 85 | } 86 | }; 87 | 88 | private Comparator cmpSize = new FileComparator() { 89 | @Override 90 | public int doCompare(FileInfo object1, FileInfo object2) { 91 | return longToCompareInt(object1.fileSize - object2.fileSize); 92 | } 93 | }; 94 | 95 | private Comparator cmpDate = new FileComparator() { 96 | @Override 97 | public int doCompare(FileInfo object1, FileInfo object2) { 98 | return longToCompareInt(object2.ModifiedDate - object1.ModifiedDate); 99 | } 100 | }; 101 | 102 | private int longToCompareInt(long result) { 103 | return result > 0 ? 1 : (result < 0 ? -1 : 0); 104 | } 105 | 106 | private Comparator cmpType = new FileComparator() { 107 | @Override 108 | public int doCompare(FileInfo object1, FileInfo object2) { 109 | int result = Util.getExtFromFilename(object1.fileName).compareToIgnoreCase( 110 | Util.getExtFromFilename(object2.fileName)); 111 | if (result != 0) 112 | return result; 113 | 114 | return Util.getNameFromFilename(object1.fileName).compareToIgnoreCase( 115 | Util.getNameFromFilename(object2.fileName)); 116 | } 117 | }; 118 | } 119 | -------------------------------------------------------------------------------- /res/layout/file_browser_item.xml: -------------------------------------------------------------------------------- 1 | 2 | 10 | 11 | 16 | 25 | 32 | 33 | 41 | 42 | 46 | 47 | 53 | 60 | 61 | 62 | 63 | 67 | 74 | 82 | 83 | 84 | 85 | 86 | 93 | 94 | 101 | 102 | 103 | 104 | 105 | -------------------------------------------------------------------------------- /res/layout/category_file_browser_item.xml: -------------------------------------------------------------------------------- 1 | 2 | 10 | 11 | 16 | 25 | 32 | 33 | 41 | 42 | 46 | 47 | 53 | 60 | 61 | 62 | 63 | 67 | 74 | 82 | 83 | 84 | 85 | 86 | 93 | 94 | 101 | 102 | 103 | 104 | 105 | -------------------------------------------------------------------------------- /AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 20 | 21 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 42 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 82 | 83 | 84 | 89 | 90 | 91 | 94 | 95 | 96 | 97 | 98 | 99 | -------------------------------------------------------------------------------- /src/org/swiftp/CmdNLST.java: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2009 David Revell 3 | 4 | This file is part of SwiFTP. 5 | 6 | SwiFTP is free software: you can redistribute it and/or modify 7 | it under the terms of the GNU General Public License as published by 8 | the Free Software Foundation, either version 3 of the License, or 9 | (at your option) any later version. 10 | 11 | SwiFTP is distributed in the hope that it will be useful, 12 | but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | GNU General Public License for more details. 15 | 16 | You should have received a copy of the GNU General Public License 17 | along with SwiFTP. If not, see . 18 | */ 19 | 20 | /* The code that is common to LIST and NLST is implemented in the abstract 21 | * class CmdAbstractListing, which is inherited here. 22 | * CmdLIST and CmdNLST just override the 23 | * makeLsString() function in different ways to provide the different forms 24 | * of output. 25 | */ 26 | 27 | package org.swiftp; 28 | 29 | import java.io.File; 30 | 31 | import android.util.Log; 32 | 33 | public class CmdNLST extends CmdAbstractListing implements Runnable { 34 | // The approximate number of milliseconds in 6 months 35 | public final static long MS_IN_SIX_MONTHS = 6 * 30 * 24 * 60 * 60 * 1000; 36 | private String input; 37 | 38 | 39 | public CmdNLST(SessionThread sessionThread, String input) { 40 | super(sessionThread, input); 41 | this.input = input; 42 | } 43 | 44 | public void run() { 45 | String errString = null; 46 | 47 | mainblock: { 48 | String param = getParameter(input); 49 | if(param.startsWith("-")) { 50 | // Ignore options to list, which start with a dash 51 | param = ""; 52 | } 53 | File fileToList = null; 54 | if(param.equals("")) { 55 | fileToList = sessionThread.getWorkingDir(); 56 | } else { 57 | if(param.contains("*")) { 58 | errString = "550 NLST does not support wildcards\r\n"; 59 | break mainblock; 60 | } 61 | fileToList = new File(sessionThread.getWorkingDir(), param); 62 | if(violatesChroot(fileToList)) { 63 | errString = "450 Listing target violates chroot\r\n"; 64 | break mainblock; 65 | } else if(fileToList.isFile()) { 66 | // Bernstein suggests that NLST should fail when a 67 | // parameter is given and the parameter names a regular 68 | // file (not a directory). 69 | errString = "550 NLST for regular files is unsupported\r\n"; 70 | break mainblock; 71 | } 72 | } 73 | String listing; 74 | if(fileToList.isDirectory()) { 75 | StringBuilder response = new StringBuilder(); 76 | errString = listDirectory(response, fileToList); 77 | if(errString != null) { 78 | break mainblock; 79 | } 80 | listing = response.toString(); 81 | } else { 82 | listing = makeLsString(fileToList); 83 | if(listing == null) { 84 | errString = "450 Couldn't list that file\r\n"; 85 | break mainblock; 86 | } 87 | } 88 | errString = sendListing(listing); 89 | if(errString != null) { 90 | break mainblock; 91 | } 92 | } 93 | 94 | if(errString != null) { 95 | sessionThread.writeString(errString); 96 | myLog.l(Log.DEBUG, "NLST failed with: " + errString); 97 | } else { 98 | myLog.l(Log.DEBUG, "NLST completed OK"); 99 | } 100 | // The success or error response over the control connection will 101 | // have already been handled by sendListing, so we can just quit now. 102 | } 103 | 104 | protected String makeLsString(File file) { 105 | if(!file.exists()) { 106 | staticLog.l(Log.INFO, "makeLsString had nonexistent file"); 107 | return null; 108 | } 109 | 110 | // See Daniel Bernstein's explanation of NLST format at: 111 | // http://cr.yp.to/ftp/list/binls.html 112 | // This stuff is almost entirely based on his recommendations. 113 | 114 | String lastNamePart = file.getName(); 115 | // Many clients can't handle files containing these symbols 116 | if(lastNamePart.contains("*") || 117 | lastNamePart.contains("/")) 118 | { 119 | staticLog.l(Log.INFO, "Filename omitted due to disallowed character"); 120 | return null; 121 | } else { 122 | staticLog.l(Log.DEBUG, "Filename: " + lastNamePart ); 123 | return lastNamePart + "\r\n"; 124 | } 125 | } 126 | } 127 | -------------------------------------------------------------------------------- /src/org/swiftp/NormalDataSocketFactory.java: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2009 David Revell 3 | 4 | This file is part of SwiFTP. 5 | 6 | SwiFTP is free software: you can redistribute it and/or modify 7 | it under the terms of the GNU General Public License as published by 8 | the Free Software Foundation, either version 3 of the License, or 9 | (at your option) any later version. 10 | 11 | SwiFTP is distributed in the hope that it will be useful, 12 | but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | GNU General Public License for more details. 15 | 16 | You should have received a copy of the GNU General Public License 17 | along with SwiFTP. If not, see . 18 | */ 19 | 20 | package org.swiftp; 21 | 22 | import net.micode.fileexplorer.FTPServerService; 23 | 24 | import java.io.IOException; 25 | import java.net.InetAddress; 26 | import java.net.ServerSocket; 27 | import java.net.Socket; 28 | 29 | import android.util.Log; 30 | 31 | public class NormalDataSocketFactory extends DataSocketFactory { 32 | /** 33 | * This class implements normal, traditional opening and closing of data sockets 34 | * used for transmitting directory listings and file contents. PORT and PASV 35 | * work according to the FTP specs. This is in contrast to a 36 | * ProxyDataSocketFactory, which performs contortions to allow data sockets 37 | * to be proxied through a server out in the cloud. 38 | * 39 | */ 40 | 41 | // Listener socket used for PASV mode 42 | ServerSocket server = null; 43 | // Remote IP & port information used for PORT mode 44 | InetAddress remoteAddr; 45 | int remotePort; 46 | boolean isPasvMode = true; 47 | 48 | public NormalDataSocketFactory() { 49 | clearState(); 50 | } 51 | 52 | 53 | private void clearState() { 54 | /** 55 | * Clears the state of this object, as if no pasv() or port() had occurred. 56 | * All sockets are closed. 57 | */ 58 | if(server != null) { 59 | try { 60 | server.close(); 61 | } catch (IOException e) {} 62 | } 63 | server = null; 64 | remoteAddr = null; 65 | remotePort = 0; 66 | myLog.l(Log.DEBUG, "NormalDataSocketFactory state cleared"); 67 | } 68 | 69 | public int onPasv() { 70 | clearState(); 71 | try { 72 | // Listen on any port (port parameter 0) 73 | server = new ServerSocket(0, Defaults.tcpConnectionBacklog); 74 | myLog.l(Log.DEBUG, "Data socket pasv() listen successful"); 75 | return server.getLocalPort(); 76 | } catch(IOException e) { 77 | myLog.l(Log.ERROR, "Data socket creation error"); 78 | clearState(); 79 | return 0; 80 | } 81 | } 82 | 83 | public boolean onPort(InetAddress remoteAddr, int remotePort) { 84 | clearState(); 85 | this.remoteAddr = remoteAddr; 86 | this.remotePort = remotePort; 87 | return true; 88 | } 89 | 90 | public Socket onTransfer() { 91 | if(server == null) { 92 | // We're in PORT mode (not PASV) 93 | if(remoteAddr == null || remotePort == 0) { 94 | myLog.l(Log.INFO, "PORT mode but not initialized correctly"); 95 | clearState(); 96 | return null; 97 | } 98 | Socket socket; 99 | try { 100 | socket = new Socket(remoteAddr, remotePort); 101 | } catch (IOException e) { 102 | myLog.l(Log.INFO, 103 | "Couldn't open PORT data socket to: " + 104 | remoteAddr.toString() + ":" + remotePort); 105 | clearState(); 106 | return null; 107 | } 108 | 109 | // Kill the socket if nothing happens for X milliseconds 110 | try { 111 | socket.setSoTimeout(Defaults.SO_TIMEOUT_MS); 112 | } catch (Exception e) { 113 | myLog.l(Log.ERROR, "Couldn't set SO_TIMEOUT"); 114 | clearState(); 115 | return null; 116 | } 117 | 118 | return socket; 119 | } else { 120 | // We're in PASV mode (not PORT) 121 | Socket socket = null; 122 | try { 123 | socket = server.accept(); 124 | myLog.l(Log.DEBUG, "onTransfer pasv accept successful"); 125 | } catch (Exception e) { 126 | myLog.l(Log.INFO, "Exception accepting PASV socket"); 127 | socket = null; 128 | } 129 | clearState(); 130 | return socket; // will be null if error occurred 131 | } 132 | } 133 | 134 | /** 135 | * Return the port number that the remote client should be informed of (in the body 136 | * of the PASV response). 137 | * @return The port number, or -1 if error. 138 | */ 139 | public int getPortNumber() { 140 | if(server != null) { 141 | return server.getLocalPort(); // returns -1 if serversocket is unbound 142 | } else { 143 | return -1; 144 | } 145 | } 146 | 147 | public InetAddress getPasvIp() { 148 | //String retVal = server.getInetAddress().getHostAddress(); 149 | return FTPServerService.getWifiIp(); 150 | } 151 | 152 | public void reportTraffic(long bytes) { 153 | // ignore, we don't care about how much traffic goes over wifi. 154 | } 155 | } -------------------------------------------------------------------------------- /src/net/micode/fileexplorer/FileListCursorAdapter.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2010-2011, The MiCode Open Source Community (www.micode.net) 3 | * 4 | * This file is part of FileExplorer. 5 | * 6 | * FileExplorer is free software: you can redistribute it and/or modify 7 | * it under the terms of the GNU General Public License as published by 8 | * the Free Software Foundation, either version 3 of the License, or 9 | * (at your option) any later version. 10 | * 11 | * FileExplorer is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU General Public License 17 | * along with SwiFTP. If not, see . 18 | */ 19 | 20 | package net.micode.fileexplorer; 21 | 22 | import android.content.Context; 23 | import android.database.Cursor; 24 | import android.view.LayoutInflater; 25 | import android.view.View; 26 | import android.view.ViewGroup; 27 | import android.widget.CursorAdapter; 28 | 29 | import java.util.Collection; 30 | import java.util.HashMap; 31 | 32 | public class FileListCursorAdapter extends CursorAdapter { 33 | 34 | private final LayoutInflater mFactory; 35 | 36 | private FileViewInteractionHub mFileViewInteractionHub; 37 | 38 | private FileIconHelper mFileIcon; 39 | 40 | private HashMap mFileNameList = new HashMap(); 41 | 42 | private Context mContext; 43 | 44 | public FileListCursorAdapter(Context context, Cursor cursor, 45 | FileViewInteractionHub f, FileIconHelper fileIcon) { 46 | super(context, cursor, false /* auto-requery */); 47 | mFactory = LayoutInflater.from(context); 48 | mFileViewInteractionHub = f; 49 | mFileIcon = fileIcon; 50 | mContext = context; 51 | } 52 | 53 | @Override 54 | public void bindView(View view, Context context, Cursor cursor) { 55 | FileInfo fileInfo = getFileItem(cursor.getPosition()); 56 | if (fileInfo == null) { 57 | // file is not existing, create a fake info 58 | fileInfo = new FileInfo(); 59 | fileInfo.dbId = cursor.getLong(FileCategoryHelper.COLUMN_ID); 60 | fileInfo.filePath = cursor.getString(FileCategoryHelper.COLUMN_PATH); 61 | fileInfo.fileName = Util.getNameFromFilepath(fileInfo.filePath); 62 | fileInfo.fileSize = cursor.getLong(FileCategoryHelper.COLUMN_SIZE); 63 | fileInfo.ModifiedDate = cursor.getLong(FileCategoryHelper.COLUMN_DATE); 64 | } 65 | FileListItem.setupFileListItemInfo(mContext, view, fileInfo, mFileIcon, 66 | mFileViewInteractionHub); 67 | view.findViewById(R.id.category_file_checkbox_area).setOnClickListener( 68 | new FileListItem.FileItemOnClickListener(mContext, mFileViewInteractionHub)); 69 | } 70 | 71 | @Override 72 | public View newView(Context context, Cursor cursor, ViewGroup parent) { 73 | return mFactory.inflate(R.layout.category_file_browser_item, parent, false); 74 | } 75 | 76 | @Override 77 | public void changeCursor(Cursor cursor) { 78 | mFileNameList.clear(); 79 | super.changeCursor(cursor); 80 | } 81 | 82 | public Collection getAllFiles() { 83 | if (mFileNameList.size() == getCount()) 84 | return mFileNameList.values(); 85 | 86 | Cursor cursor = getCursor(); 87 | if (cursor.moveToFirst()) { 88 | do { 89 | Integer position = Integer.valueOf(cursor.getPosition()); 90 | if (mFileNameList.containsKey(position)) 91 | continue; 92 | FileInfo fileInfo = getFileInfo(cursor); 93 | if (fileInfo != null) { 94 | mFileNameList.put(position, fileInfo); 95 | } 96 | } while (cursor.moveToNext()); 97 | } 98 | 99 | return mFileNameList.values(); 100 | } 101 | 102 | public FileInfo getFileItem(int pos) { 103 | Integer position = Integer.valueOf(pos); 104 | if (mFileNameList.containsKey(position)) 105 | return mFileNameList.get(position); 106 | 107 | Cursor cursor = (Cursor) getItem(pos); 108 | FileInfo fileInfo = getFileInfo(cursor); 109 | if (fileInfo == null) 110 | return null; 111 | 112 | fileInfo.dbId = cursor.getLong(FileCategoryHelper.COLUMN_ID); 113 | mFileNameList.put(position, fileInfo); 114 | return fileInfo; 115 | } 116 | 117 | private FileInfo getFileInfo(Cursor cursor) { 118 | return (cursor == null || cursor.getCount() == 0) ? null : Util 119 | .GetFileInfo(cursor.getString(FileCategoryHelper.COLUMN_PATH)); 120 | } 121 | } 122 | -------------------------------------------------------------------------------- /src/net/micode/fileexplorer/FileExplorerPreferenceActivity.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2010-2011, The MiCode Open Source Community (www.micode.net) 3 | * 4 | * This file is part of FileExplorer. 5 | * 6 | * FileExplorer is free software: you can redistribute it and/or modify 7 | * it under the terms of the GNU General Public License as published by 8 | * the Free Software Foundation, either version 3 of the License, or 9 | * (at your option) any later version. 10 | * 11 | * FileExplorer is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU General Public License 17 | * along with SwiFTP. If not, see . 18 | */ 19 | 20 | package net.micode.fileexplorer; 21 | 22 | import java.io.File; 23 | 24 | import android.content.Context; 25 | import android.content.SharedPreferences; 26 | import android.content.SharedPreferences.OnSharedPreferenceChangeListener; 27 | import android.os.Bundle; 28 | import android.preference.EditTextPreference; 29 | import android.preference.PreferenceActivity; 30 | import android.preference.PreferenceManager; 31 | import android.text.TextUtils; 32 | 33 | /** 34 | * 35 | * @author ShunLi 36 | */ 37 | public class FileExplorerPreferenceActivity extends PreferenceActivity implements OnSharedPreferenceChangeListener { 38 | private static final String PRIMARY_FOLDER = "pref_key_primary_folder"; 39 | private static final String READ_ROOT = "pref_key_read_root"; 40 | private static final String SHOW_REAL_PATH = "pref_key_show_real_path"; 41 | private static final String SYSTEM_SEPARATOR = File.separator; 42 | 43 | private EditTextPreference mEditTextPreference; 44 | 45 | @Override 46 | protected void onCreate(Bundle savedInstanceState) { 47 | super.onCreate(savedInstanceState); 48 | addPreferencesFromResource(R.xml.preferences); 49 | 50 | mEditTextPreference = (EditTextPreference) findPreference(PRIMARY_FOLDER); 51 | } 52 | 53 | @Override 54 | protected void onResume() { 55 | super.onResume(); 56 | 57 | // Setup the initial values 58 | SharedPreferences sharedPreferences = getPreferenceScreen().getSharedPreferences(); 59 | 60 | mEditTextPreference.setSummary(this.getString( 61 | R.string.pref_primary_folder_summary, 62 | sharedPreferences.getString(PRIMARY_FOLDER, GlobalConsts.ROOT_PATH))); 63 | 64 | // Set up a listener whenever a key changes 65 | sharedPreferences.registerOnSharedPreferenceChangeListener(this); 66 | } 67 | 68 | @Override 69 | protected void onPause() { 70 | super.onPause(); 71 | 72 | // Unregister the listener whenever a key changes 73 | getPreferenceScreen().getSharedPreferences().unregisterOnSharedPreferenceChangeListener(this); 74 | } 75 | 76 | @Override 77 | public void onSharedPreferenceChanged(SharedPreferences sharedpreferences, String key) { 78 | if (PRIMARY_FOLDER.equals(key)) { 79 | mEditTextPreference.setSummary(this.getString( 80 | R.string.pref_primary_folder_summary, 81 | sharedpreferences.getString(PRIMARY_FOLDER, GlobalConsts.ROOT_PATH))); 82 | } 83 | } 84 | 85 | public static String getPrimaryFolder(Context context) { 86 | SharedPreferences settings = PreferenceManager.getDefaultSharedPreferences(context); 87 | String primaryFolder = settings.getString(PRIMARY_FOLDER, context.getString(R.string.default_primary_folder, GlobalConsts.ROOT_PATH)); 88 | 89 | if (TextUtils.isEmpty(primaryFolder)) { // setting primary folder = empty("") 90 | primaryFolder = GlobalConsts.ROOT_PATH; 91 | } 92 | 93 | // it's remove the end char of the home folder setting when it with the '/' at the end. 94 | // if has the backslash at end of the home folder, it's has minor bug at "UpLevel" function. 95 | int length = primaryFolder.length(); 96 | if (length > 1 && SYSTEM_SEPARATOR.equals(primaryFolder.substring(length - 1))) { // length = 1, ROOT_PATH 97 | return primaryFolder.substring(0, length - 1); 98 | } else { 99 | return primaryFolder; 100 | } 101 | } 102 | 103 | public static boolean isReadRoot(Context context) { 104 | SharedPreferences settings = PreferenceManager.getDefaultSharedPreferences(context); 105 | 106 | boolean isReadRootFromSetting = settings.getBoolean(READ_ROOT, false); 107 | boolean isReadRootWhenSettingPrimaryFolderWithoutSdCardPrefix = !getPrimaryFolder(context).startsWith(Util.getSdDirectory()); 108 | 109 | return isReadRootFromSetting || isReadRootWhenSettingPrimaryFolderWithoutSdCardPrefix; 110 | } 111 | 112 | public static boolean showRealPath(Context context) { 113 | SharedPreferences settings = PreferenceManager.getDefaultSharedPreferences(context); 114 | return settings.getBoolean(SHOW_REAL_PATH, false); 115 | } 116 | 117 | } 118 | -------------------------------------------------------------------------------- /src/org/swiftp/ProxyDataSocketFactory.java: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2009 David Revell 3 | 4 | This file is part of SwiFTP. 5 | 6 | SwiFTP is free software: you can redistribute it and/or modify 7 | it under the terms of the GNU General Public License as published by 8 | the Free Software Foundation, either version 3 of the License, or 9 | (at your option) any later version. 10 | 11 | SwiFTP is distributed in the hope that it will be useful, 12 | but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | GNU General Public License for more details. 15 | 16 | You should have received a copy of the GNU General Public License 17 | along with SwiFTP. If not, see . 18 | */ 19 | 20 | package org.swiftp; 21 | 22 | import java.net.InetAddress; 23 | import java.net.Socket; 24 | 25 | import android.util.Log; 26 | 27 | /** 28 | * @author david 29 | * 30 | */ 31 | public class ProxyDataSocketFactory extends DataSocketFactory { 32 | /** 33 | * Implements data socket connections that go through our proxy server 34 | * out on the net. The proxy sits between the FTP client and us, the server. 35 | * We have to build in some coordination between the server and proxy in order 36 | * for data sockets to be handled properly. 37 | * 38 | * When we receive a "PASV" command from a client, we have to request that the 39 | * proxy server open a port, accept a connection, and proxy all data on that 40 | * socket between ourself and the FTP client. 41 | * 42 | * When we receive a PORT command, we store the client's connection info, 43 | * and when it's time to being transferring data, we request that the proxy 44 | * make a connection to the client's IP & port and then proxy all data between 45 | * ourself and the FTP client. 46 | */ 47 | 48 | private Socket socket; 49 | private int proxyListenPort; 50 | ProxyConnector proxyConnector; 51 | InetAddress clientAddress; 52 | int clientPort; 53 | 54 | public ProxyDataSocketFactory() { 55 | clearState(); 56 | } 57 | 58 | private void clearState() { 59 | if(socket != null) { 60 | try { 61 | socket.close(); 62 | } catch (Exception e) {} 63 | } 64 | socket = null; 65 | proxyConnector = null; 66 | clientAddress = null; 67 | proxyListenPort = 0; 68 | clientPort = 0; 69 | } 70 | 71 | public InetAddress getPasvIp() { 72 | ProxyConnector pc = Globals.getProxyConnector(); 73 | if(pc == null) { 74 | return null; 75 | } 76 | return pc.getProxyIp(); 77 | } 78 | 79 | // public int getPortNumber() { 80 | // if(socket == ) 81 | // return 0; 82 | // } 83 | 84 | public int onPasv() { 85 | clearState(); 86 | proxyConnector = Globals.getProxyConnector(); 87 | if(proxyConnector == null) { 88 | myLog.l(Log.INFO, "Unexpected null proxyConnector in onPasv"); 89 | clearState(); 90 | return 0; 91 | } 92 | ProxyDataSocketInfo info = proxyConnector.pasvListen(); 93 | if(info == null) { 94 | myLog.l(Log.INFO, "Null ProxyDataSocketInfo"); 95 | clearState(); 96 | return 0; 97 | } 98 | socket = info.getSocket(); 99 | proxyListenPort = info.getRemotePublicPort(); 100 | return proxyListenPort; 101 | } 102 | 103 | public boolean onPort(InetAddress dest, int port) { 104 | clearState(); 105 | proxyConnector = Globals.getProxyConnector(); 106 | this.clientAddress = dest; 107 | this.clientPort = port; 108 | myLog.d("ProxyDataSocketFactory client port settings stored"); 109 | return true; 110 | } 111 | 112 | /** 113 | * When the it's time for the SessionThread to actually begin PASV 114 | * data transfer with the client, it will call this function to get 115 | * a valid socket. The socket will have been created earlier with 116 | * a call to onPasv(). The result of calling onTransfer() will be 117 | * to cause the proxy to accept the incoming connection from the FTP 118 | * client and start proxying back to us (the FTP server). The socket 119 | * can then be handed back to the SessionThread which can use it as 120 | * if it were directly connected to the client. 121 | */ 122 | public Socket onTransfer() { 123 | if(proxyConnector == null) { 124 | myLog.w("Unexpected null proxyConnector in onTransfer"); 125 | return null; 126 | } 127 | 128 | if(socket == null) { 129 | // We are in PORT mode (not PASV mode) 130 | if(proxyConnector == null) { 131 | myLog.l(Log.INFO, "Unexpected null proxyConnector in onTransfer"); 132 | return null; 133 | } 134 | // May return null, that's fine. ProxyConnector will log errors. 135 | socket = proxyConnector.dataPortConnect(clientAddress, clientPort); 136 | return socket; 137 | } else { 138 | // We are in PASV mode (not PORT mode) 139 | if(proxyConnector.pasvAccept(socket)) { 140 | return socket; 141 | } else { 142 | myLog.w("proxyConnector pasvAccept failed"); 143 | return null; 144 | } 145 | } 146 | } 147 | 148 | public void reportTraffic(long bytes) { 149 | ProxyConnector pc = Globals.getProxyConnector(); 150 | if(pc == null) { 151 | myLog.d("Can't report traffic, null ProxyConnector"); 152 | } else { 153 | pc.incrementProxyUsage(bytes); 154 | } 155 | } 156 | } 157 | -------------------------------------------------------------------------------- /src/org/swiftp/Defaults.java: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2009 David Revell 3 | 4 | This file is part of SwiFTP. 5 | 6 | SwiFTP is free software: you can redistribute it and/or modify 7 | it under the terms of the GNU General Public License as published by 8 | the Free Software Foundation, either version 3 of the License, or 9 | (at your option) any later version. 10 | 11 | SwiFTP is distributed in the hope that it will be useful, 12 | but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | GNU General Public License for more details. 15 | 16 | You should have received a copy of the GNU General Public License 17 | along with SwiFTP. If not, see . 18 | */ 19 | 20 | package org.swiftp; 21 | 22 | import android.content.Context; 23 | import android.util.Log; 24 | 25 | public class Defaults { 26 | protected static int inputBufferSize = 256; 27 | protected static int dataChunkSize = 65536; // do file I/O in 64k chunks 28 | protected static int sessionMonitorScrollBack = 10; 29 | protected static int serverLogScrollBack = 10; 30 | protected static int uiLogLevel = Defaults.release ? Log.INFO : Log.DEBUG; 31 | protected static int consoleLogLevel = Defaults.release ? Log.INFO : Log.DEBUG; 32 | protected static String settingsName = "SwiFTP"; 33 | //protected static String username = "user"; 34 | //protected static String password = ""; 35 | public static int portNumber = 2121; 36 | // protected static int ipRetrievalAttempts = 5; 37 | public static final int tcpConnectionBacklog = 5; 38 | public static final String chrootDir = net.micode.fileexplorer.Util.getSdDirectory(); 39 | public static final boolean acceptWifi = true; 40 | public static final boolean acceptNet = false; // don't incur bandwidth charges 41 | public static final boolean stayAwake = false; 42 | public static final int REMOTE_PROXY_PORT = 2222; 43 | public static final String STRING_ENCODING = "UTF-8"; 44 | public static final int SO_TIMEOUT_MS = 30000; // socket timeout millis 45 | // FTP control sessions should start out in ASCII, according to the RFC. 46 | // However, many clients don't turn on UTF-8 even though they support it, 47 | // so we just turn it on by default. 48 | public static final String SESSION_ENCODING = "UTF-8"; 49 | 50 | // This is a flag that should be true for public builds and false for dev builds 51 | public static final boolean release = true; 52 | 53 | // Try to fix the transfer stall bug, reopen the destination file periodically 54 | //public static final boolean do_reopen_hack = false; 55 | //public static final int bytes_between_reopen = 4000000; 56 | 57 | // Try to fix the transfer stall bug, flush the file periodically 58 | //public static final boolean do_flush_hack = false; 59 | //public static final int bytes_between_flush = 500000; 60 | 61 | public static final boolean do_mediascanner_notify = true; 62 | 63 | 64 | // public static int getIpRetrievalAttempts() { 65 | // return ipRetrievalAttempts; 66 | // } 67 | 68 | // public static void setIpRetrievalAttempts(int ipRetrievalAttempts) { 69 | // Defaults.ipRetrievalAttempts = ipRetrievalAttempts; 70 | // } 71 | 72 | public static int getPortNumber() { 73 | return portNumber; 74 | } 75 | 76 | public static void setPortNumber(int portNumber) { 77 | Defaults.portNumber = portNumber; 78 | } 79 | 80 | public static String getSettingsName() { 81 | return settingsName; 82 | } 83 | 84 | public static void setSettingsName(String settingsName) { 85 | Defaults.settingsName = settingsName; 86 | } 87 | 88 | public static int getSettingsMode() { 89 | return settingsMode; 90 | } 91 | 92 | public static void setSettingsMode(int settingsMode) { 93 | Defaults.settingsMode = settingsMode; 94 | } 95 | 96 | public static void setServerLogScrollBack(int serverLogScrollBack) { 97 | Defaults.serverLogScrollBack = serverLogScrollBack; 98 | } 99 | 100 | protected static int settingsMode = Context.MODE_WORLD_WRITEABLE; 101 | 102 | public static int getUiLogLevel() { 103 | return uiLogLevel; 104 | } 105 | 106 | public static void setUiLogLevel(int uiLogLevel) { 107 | Defaults.uiLogLevel = uiLogLevel; 108 | } 109 | 110 | public static int getInputBufferSize() { 111 | return inputBufferSize; 112 | } 113 | 114 | public static void setInputBufferSize(int inputBufferSize) { 115 | Defaults.inputBufferSize = inputBufferSize; 116 | } 117 | 118 | public static int getDataChunkSize() { 119 | return dataChunkSize; 120 | } 121 | 122 | public static void setDataChunkSize(int dataChunkSize) { 123 | Defaults.dataChunkSize = dataChunkSize; 124 | } 125 | 126 | public static int getSessionMonitorScrollBack() { 127 | return sessionMonitorScrollBack; 128 | } 129 | 130 | public static void setSessionMonitorScrollBack( 131 | int sessionMonitorScrollBack) 132 | { 133 | Defaults.sessionMonitorScrollBack = sessionMonitorScrollBack; 134 | } 135 | 136 | public static int getServerLogScrollBack() { 137 | return serverLogScrollBack; 138 | } 139 | 140 | public static void setLogScrollBack(int serverLogScrollBack) { 141 | Defaults.serverLogScrollBack = serverLogScrollBack; 142 | } 143 | 144 | public static int getConsoleLogLevel() { 145 | return consoleLogLevel; 146 | } 147 | 148 | public static void setConsoleLogLevel(int consoleLogLevel) { 149 | Defaults.consoleLogLevel = consoleLogLevel; 150 | } 151 | 152 | 153 | } 154 | -------------------------------------------------------------------------------- /src/net/micode/fileexplorer/FavoriteDatabaseHelper.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2010-2011, The MiCode Open Source Community (www.micode.net) 3 | * 4 | * This file is part of FileExplorer. 5 | * 6 | * FileExplorer is free software: you can redistribute it and/or modify 7 | * it under the terms of the GNU General Public License as published by 8 | * the Free Software Foundation, either version 3 of the License, or 9 | * (at your option) any later version. 10 | * 11 | * FileExplorer is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU General Public License 17 | * along with SwiFTP. If not, see . 18 | */ 19 | 20 | package net.micode.fileexplorer; 21 | 22 | import android.content.ContentValues; 23 | import android.content.Context; 24 | import android.database.Cursor; 25 | import android.database.sqlite.SQLiteDatabase; 26 | import android.database.sqlite.SQLiteOpenHelper; 27 | 28 | public class FavoriteDatabaseHelper extends SQLiteOpenHelper { 29 | 30 | private final static String DATABASE_NAME = "file_explorer"; 31 | 32 | private final static int DATABASE_VERSION = 1; 33 | 34 | private final static String TABLE_NAME = "favorite"; 35 | 36 | public final static String FIELD_ID = "_id"; 37 | 38 | public final static String FIELD_TITLE = "title"; 39 | 40 | public final static String FIELD_LOCATION = "location"; 41 | 42 | private boolean firstCreate; 43 | 44 | private FavoriteDatabaseListener mListener; 45 | 46 | private static FavoriteDatabaseHelper instance; 47 | 48 | public interface FavoriteDatabaseListener { 49 | void onFavoriteDatabaseChanged(); 50 | } 51 | 52 | public FavoriteDatabaseHelper(Context context, FavoriteDatabaseListener listener) { 53 | super(context, DATABASE_NAME, null, DATABASE_VERSION); 54 | instance = this; 55 | mListener = listener; 56 | } 57 | 58 | public static FavoriteDatabaseHelper getInstance() { 59 | return instance; 60 | } 61 | 62 | @Override 63 | public void onCreate(SQLiteDatabase db) { 64 | String sql = "Create table " + TABLE_NAME + "(" + FIELD_ID + " integer primary key autoincrement," 65 | + FIELD_TITLE + " text, " + FIELD_LOCATION + " text );"; 66 | db.execSQL(sql); 67 | firstCreate = true; 68 | } 69 | 70 | @Override 71 | public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) { 72 | String sql = " DROP TABLE IF EXISTS " + TABLE_NAME; 73 | db.execSQL(sql); 74 | onCreate(db); 75 | } 76 | 77 | public boolean isFirstCreate() { 78 | return firstCreate; 79 | } 80 | 81 | public boolean isFavorite(String path) { 82 | String selection = FIELD_LOCATION + "=?"; 83 | String[] selectionArgs = new String[] { 84 | path 85 | }; 86 | SQLiteDatabase db = this.getReadableDatabase(); 87 | Cursor cursor = db.query(TABLE_NAME, null, selection, selectionArgs, null, null, null); 88 | if (cursor == null) 89 | return false; 90 | boolean ret = cursor.getCount() > 0; 91 | cursor.close(); 92 | return ret; 93 | } 94 | 95 | public Cursor query() { 96 | SQLiteDatabase db = this.getReadableDatabase(); 97 | Cursor cursor = db.query(TABLE_NAME, null, null, null, null, null, null); 98 | return cursor; 99 | } 100 | 101 | public long insert(String title, String location) { 102 | if (isFavorite(location)) 103 | return -1; 104 | 105 | SQLiteDatabase db = this.getWritableDatabase(); 106 | long ret = db.insert(TABLE_NAME, null, createValues(title, location)); 107 | mListener.onFavoriteDatabaseChanged(); 108 | return ret; 109 | } 110 | 111 | public void delete(long id, boolean notify) { 112 | SQLiteDatabase db = this.getWritableDatabase(); 113 | String where = FIELD_ID + "=?"; 114 | String[] whereValue = { 115 | Long.toString(id) 116 | }; 117 | db.delete(TABLE_NAME, where, whereValue); 118 | 119 | if (notify) 120 | mListener.onFavoriteDatabaseChanged(); 121 | } 122 | 123 | public void delete(String location) { 124 | SQLiteDatabase db = this.getWritableDatabase(); 125 | String where = FIELD_LOCATION + "=?"; 126 | String[] whereValue = { 127 | location 128 | }; 129 | db.delete(TABLE_NAME, where, whereValue); 130 | mListener.onFavoriteDatabaseChanged(); 131 | } 132 | 133 | public void update(int id, String title, String location) { 134 | SQLiteDatabase db = this.getWritableDatabase(); 135 | String where = FIELD_ID + "=?"; 136 | String[] whereValue = { 137 | Integer.toString(id) 138 | }; 139 | db.update(TABLE_NAME, createValues(title, location), where, whereValue); 140 | mListener.onFavoriteDatabaseChanged(); 141 | } 142 | 143 | private ContentValues createValues(String title, String location) { 144 | ContentValues cv = new ContentValues(); 145 | cv.put(FIELD_TITLE, title); 146 | cv.put(FIELD_LOCATION, location); 147 | return cv; 148 | } 149 | } 150 | -------------------------------------------------------------------------------- /src/net/micode/fileexplorer/IntentBuilder.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2010-2011, The MiCode Open Source Community (www.micode.net) 3 | * 4 | * This file is part of FileExplorer. 5 | * 6 | * FileExplorer is free software: you can redistribute it and/or modify 7 | * it under the terms of the GNU General Public License as published by 8 | * the Free Software Foundation, either version 3 of the License, or 9 | * (at your option) any later version. 10 | * 11 | * FileExplorer is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU General Public License 17 | * along with SwiFTP. If not, see . 18 | */ 19 | 20 | package net.micode.fileexplorer; 21 | 22 | import java.io.File; 23 | import java.util.ArrayList; 24 | 25 | import android.app.AlertDialog; 26 | import android.content.Context; 27 | import android.content.DialogInterface; 28 | import android.content.Intent; 29 | import android.net.Uri; 30 | import android.text.TextUtils; 31 | 32 | public class IntentBuilder { 33 | 34 | public static void viewFile(final Context context, final String filePath) { 35 | String type = getMimeType(filePath); 36 | 37 | if (!TextUtils.isEmpty(type) && !TextUtils.equals(type, "*/*")) { 38 | /* 设置intent的file与MimeType */ 39 | Intent intent = new Intent(); 40 | intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); 41 | intent.setAction(android.content.Intent.ACTION_VIEW); 42 | intent.setDataAndType(Uri.fromFile(new File(filePath)), type); 43 | context.startActivity(intent); 44 | } else { 45 | // unknown MimeType 46 | AlertDialog.Builder dialogBuilder = new AlertDialog.Builder(context); 47 | dialogBuilder.setTitle(R.string.dialog_select_type); 48 | 49 | CharSequence[] menuItemArray = new CharSequence[] { 50 | context.getString(R.string.dialog_type_text), 51 | context.getString(R.string.dialog_type_audio), 52 | context.getString(R.string.dialog_type_video), 53 | context.getString(R.string.dialog_type_image) }; 54 | dialogBuilder.setItems(menuItemArray, 55 | new DialogInterface.OnClickListener() { 56 | @Override 57 | public void onClick(DialogInterface dialog, int which) { 58 | String selectType = "*/*"; 59 | switch (which) { 60 | case 0: 61 | selectType = "text/plain"; 62 | break; 63 | case 1: 64 | selectType = "audio/*"; 65 | break; 66 | case 2: 67 | selectType = "video/*"; 68 | break; 69 | case 3: 70 | selectType = "image/*"; 71 | break; 72 | } 73 | Intent intent = new Intent(); 74 | intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); 75 | intent.setAction(android.content.Intent.ACTION_VIEW); 76 | intent.setDataAndType(Uri.fromFile(new File(filePath)), selectType); 77 | context.startActivity(intent); 78 | } 79 | }); 80 | dialogBuilder.show(); 81 | } 82 | } 83 | 84 | public static Intent buildSendFile(ArrayList files) { 85 | ArrayList uris = new ArrayList(); 86 | 87 | String mimeType = "*/*"; 88 | for (FileInfo file : files) { 89 | if (file.IsDir) 90 | continue; 91 | 92 | File fileIn = new File(file.filePath); 93 | mimeType = getMimeType(file.fileName); 94 | Uri u = Uri.fromFile(fileIn); 95 | uris.add(u); 96 | } 97 | 98 | if (uris.size() == 0) 99 | return null; 100 | 101 | boolean multiple = uris.size() > 1; 102 | Intent intent = new Intent(multiple ? android.content.Intent.ACTION_SEND_MULTIPLE 103 | : android.content.Intent.ACTION_SEND); 104 | 105 | if (multiple) { 106 | intent.setType("*/*"); 107 | intent.putParcelableArrayListExtra(Intent.EXTRA_STREAM, uris); 108 | } else { 109 | intent.setType(mimeType); 110 | intent.putExtra(Intent.EXTRA_STREAM, uris.get(0)); 111 | } 112 | 113 | return intent; 114 | } 115 | 116 | private static String getMimeType(String filePath) { 117 | int dotPosition = filePath.lastIndexOf('.'); 118 | if (dotPosition == -1) 119 | return "*/*"; 120 | 121 | String ext = filePath.substring(dotPosition + 1, filePath.length()).toLowerCase(); 122 | String mimeType = MimeUtils.guessMimeTypeFromExtension(ext); 123 | if (ext.equals("mtz")) { 124 | mimeType = "application/miui-mtz"; 125 | } 126 | 127 | return mimeType != null ? mimeType : "*/*"; 128 | } 129 | } 130 | -------------------------------------------------------------------------------- /src/net/micode/fileexplorer/FileIconHelper.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2010-2011, The MiCode Open Source Community (www.micode.net) 3 | * 4 | * This file is part of FileExplorer. 5 | * 6 | * FileExplorer is free software: you can redistribute it and/or modify 7 | * it under the terms of the GNU General Public License as published by 8 | * the Free Software Foundation, either version 3 of the License, or 9 | * (at your option) any later version. 10 | * 11 | * FileExplorer is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU General Public License 17 | * along with SwiFTP. If not, see . 18 | */ 19 | 20 | package net.micode.fileexplorer; 21 | 22 | 23 | import net.micode.fileexplorer.FileCategoryHelper.FileCategory; 24 | import net.micode.fileexplorer.FileIconLoader.IconLoadFinishListener; 25 | 26 | import android.content.Context; 27 | import android.view.View; 28 | import android.widget.ImageView; 29 | 30 | import java.util.HashMap; 31 | 32 | public class FileIconHelper implements IconLoadFinishListener { 33 | 34 | private static final String LOG_TAG = "FileIconHelper"; 35 | 36 | private static HashMap imageFrames = new HashMap(); 37 | 38 | private static HashMap fileExtToIcons = new HashMap(); 39 | 40 | private FileIconLoader mIconLoader; 41 | 42 | static { 43 | addItem(new String[] { 44 | "mp3" 45 | }, R.drawable.file_icon_mp3); 46 | addItem(new String[] { 47 | "wma" 48 | }, R.drawable.file_icon_wma); 49 | addItem(new String[] { 50 | "wav" 51 | }, R.drawable.file_icon_wav); 52 | addItem(new String[] { 53 | "mid" 54 | }, R.drawable.file_icon_mid); 55 | addItem(new String[] { 56 | "mp4", "wmv", "mpeg", "m4v", "3gp", "3gpp", "3g2", "3gpp2", "asf" 57 | }, R.drawable.file_icon_video); 58 | addItem(new String[] { 59 | "jpg", "jpeg", "gif", "png", "bmp", "wbmp" 60 | }, R.drawable.file_icon_picture); 61 | addItem(new String[] { 62 | "txt", "log", "xml", "ini", "lrc" 63 | }, R.drawable.file_icon_txt); 64 | addItem(new String[] { 65 | "doc", "ppt", "docx", "pptx", "xsl", "xslx", 66 | }, R.drawable.file_icon_office); 67 | addItem(new String[] { 68 | "pdf" 69 | }, R.drawable.file_icon_pdf); 70 | addItem(new String[] { 71 | "zip" 72 | }, R.drawable.file_icon_zip); 73 | addItem(new String[] { 74 | "mtz" 75 | }, R.drawable.file_icon_theme); 76 | addItem(new String[] { 77 | "rar" 78 | }, R.drawable.file_icon_rar); 79 | } 80 | 81 | public FileIconHelper(Context context) { 82 | mIconLoader = new FileIconLoader(context, this); 83 | } 84 | 85 | private static void addItem(String[] exts, int resId) { 86 | if (exts != null) { 87 | for (String ext : exts) { 88 | fileExtToIcons.put(ext.toLowerCase(), resId); 89 | } 90 | } 91 | } 92 | 93 | public static int getFileIcon(String ext) { 94 | Integer i = fileExtToIcons.get(ext.toLowerCase()); 95 | if (i != null) { 96 | return i.intValue(); 97 | } else { 98 | return R.drawable.file_icon_default; 99 | } 100 | 101 | } 102 | 103 | public void setIcon(FileInfo fileInfo, ImageView fileImage, ImageView fileImageFrame) { 104 | String filePath = fileInfo.filePath; 105 | long fileId = fileInfo.dbId; 106 | String extFromFilename = Util.getExtFromFilename(filePath); 107 | FileCategory fc = FileCategoryHelper.getCategoryFromPath(filePath); 108 | fileImageFrame.setVisibility(View.GONE); 109 | boolean set = false; 110 | int id = getFileIcon(extFromFilename); 111 | fileImage.setImageResource(id); 112 | 113 | mIconLoader.cancelRequest(fileImage); 114 | switch (fc) { 115 | case Apk: 116 | set = mIconLoader.loadIcon(fileImage, filePath, fileId, fc); 117 | break; 118 | case Picture: 119 | case Video: 120 | set = mIconLoader.loadIcon(fileImage, filePath, fileId, fc); 121 | if (set) 122 | fileImageFrame.setVisibility(View.VISIBLE); 123 | else { 124 | fileImage.setImageResource(fc == FileCategory.Picture ? R.drawable.file_icon_picture 125 | : R.drawable.file_icon_video); 126 | imageFrames.put(fileImage, fileImageFrame); 127 | set = true; 128 | } 129 | break; 130 | default: 131 | set = true; 132 | break; 133 | } 134 | 135 | if (!set) 136 | fileImage.setImageResource(R.drawable.file_icon_default); 137 | } 138 | 139 | @Override 140 | public void onIconLoadFinished(ImageView view) { 141 | ImageView frame = imageFrames.get(view); 142 | if (frame != null) { 143 | frame.setVisibility(View.VISIBLE); 144 | imageFrames.remove(view); 145 | } 146 | } 147 | 148 | } 149 | -------------------------------------------------------------------------------- /src/org/swiftp/CmdRETR.java: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2009 David Revell 3 | 4 | This file is part of SwiFTP. 5 | 6 | SwiFTP is free software: you can redistribute it and/or modify 7 | it under the terms of the GNU General Public License as published by 8 | the Free Software Foundation, either version 3 of the License, or 9 | (at your option) any later version. 10 | 11 | SwiFTP is distributed in the hope that it will be useful, 12 | but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | GNU General Public License for more details. 15 | 16 | You should have received a copy of the GNU General Public License 17 | along with SwiFTP. If not, see . 18 | */ 19 | 20 | package org.swiftp; 21 | 22 | import java.io.File; 23 | import java.io.FileInputStream; 24 | import java.io.FileNotFoundException; 25 | import java.io.IOException; 26 | 27 | import android.util.Log; 28 | 29 | public class CmdRETR extends FtpCmd implements Runnable { 30 | //public static final String message = "TEMPLATE!!"; 31 | protected String input; 32 | 33 | public CmdRETR(SessionThread sessionThread, String input) { 34 | super(sessionThread, CmdRETR.class.toString()); 35 | this.input = input; 36 | } 37 | 38 | public void run() { 39 | myLog.l(Log.DEBUG, "RETR executing"); 40 | String param = getParameter(input); 41 | File fileToRetr; 42 | String errString = null; 43 | 44 | mainblock: { 45 | fileToRetr = inputPathToChrootedFile(sessionThread.getWorkingDir(), param); 46 | if(violatesChroot(fileToRetr)) { 47 | errString = "550 Invalid name or chroot violation\r\n"; 48 | break mainblock; 49 | } else if(fileToRetr.isDirectory()) { 50 | myLog.l(Log.DEBUG, "Ignoring RETR for directory"); 51 | errString = "550 Can't RETR a directory\r\n"; 52 | break mainblock; 53 | } else if(!fileToRetr.exists()) { 54 | myLog.l(Log.INFO, "Can't RETR nonexistent file: " + 55 | fileToRetr.getAbsolutePath()); 56 | errString = "550 File does not exist\r\n"; 57 | break mainblock; 58 | } else if(!fileToRetr.canRead()) { 59 | myLog.l(Log.INFO, "Failed RETR permission (canRead() is false)"); 60 | errString = "550 No read permissions\r\n"; 61 | break mainblock; 62 | } /*else if(!sessionThread.isBinaryMode()) { 63 | myLog.l(Log.INFO, "Failed RETR in text mode"); 64 | errString = "550 Text mode RETR not supported\r\n"; 65 | break mainblock; 66 | }*/ 67 | try { 68 | FileInputStream in = new FileInputStream(fileToRetr); 69 | byte[] buffer = new byte[Defaults.getDataChunkSize()]; 70 | int bytesRead; 71 | if(sessionThread.startUsingDataSocket()) { 72 | myLog.l(Log.DEBUG, "RETR opened data socket"); 73 | } else { 74 | errString = "425 Error opening socket\r\n"; 75 | myLog.l(Log.INFO, "Error in initDataSocket()"); 76 | break mainblock; 77 | } 78 | sessionThread.writeString("150 Sending file\r\n"); 79 | if(sessionThread.isBinaryMode()) { 80 | myLog.l(Log.DEBUG, "Transferring in binary mode"); 81 | while((bytesRead = in.read(buffer)) != -1) { 82 | //myLog.l(Log.DEBUG, 83 | // String.format("CmdRETR sending %d bytes", bytesRead)); 84 | if(sessionThread 85 | .sendViaDataSocket(buffer, bytesRead) == false) 86 | { 87 | errString = "426 Data socket error\r\n"; 88 | myLog.l(Log.INFO, "Data socket error"); 89 | break mainblock; 90 | } 91 | } 92 | } else { // We're in ASCII mode 93 | myLog.l(Log.DEBUG, "Transferring in ASCII mode"); 94 | // We have to convert all solitary \n to \r\n 95 | boolean lastBufEndedWithCR = false; 96 | while((bytesRead = in.read(buffer)) != -1) { 97 | int startPos = 0, endPos = 0; 98 | byte[] crnBuf = {'\r','\n'}; 99 | for(endPos = 0; endPos 2 | 3 | 4 | 文件管理 5 | 确定 6 | 搜索 7 | 新建文件夹 8 | 排序 9 | 名称 10 | 大小 11 | 时间 12 | 类型 13 | 收藏 14 | 取消收藏 15 | 复制 16 | 复制路径 17 | 粘贴 18 | 剪切 19 | 发送 20 | 重命名 21 | 删除 22 | 详情 23 | 取消 24 | 刷新 25 | 全选 26 | 取消全选 27 | 显示点文件和隐藏文件 28 | 隐藏点文件和隐藏文件 29 | 取消 30 | 没有文件 31 | 分类浏览 32 | 文件管理 33 | 远程管理 34 | SD卡 35 | 所有 36 | 音乐 37 | 视频 38 | 图片 39 | 主题 40 | 文档 41 | 压缩包 42 | 安装包 43 | 其它 44 | 收藏夹 45 | 请输入新名称 46 | 请输入文件夹名称 47 | 确认删除? 48 | 新建文件夹 49 | SD卡:%1$s 50 | 可用:%1$s 51 | 位置: 52 | 大小: 53 | 时间: 54 | 可读: 55 | 可写: 56 | 隐藏: 57 | 58 | 59 | 正在删除... 60 | 正在复制... 61 | 正在移动... 62 | 知道了 63 | 安装成功 64 | 安装失败 65 | 不能发送文件夹 66 | 已加入收藏夹 67 | 已从收藏夹移除 68 | 创建文件夹失败,文件夹已存在。 69 | 重命名失败失败,可能使用该名称的文件或文件夹已存在。 70 | 无可用SD卡,请插入或连接SD卡 71 | 启动服务 72 | 停止服务 73 | 远程管理服务已启动 74 | 远程管理服务正在运行 75 | 外部存储不可用. 76 | WiFi状态 77 | 启动后可以从电脑端远程管理手机文件 78 | 请在“我的电脑”地址栏中输入: 79 | 无WiFi网络 80 | 无WiFi网络,点击以查看WiFi设置 81 | 搜索文件 82 | 输入部分或全部文件名 83 | %d 字节 84 | 选择文件类型 85 | 文本 86 | 音频 87 | 视频 88 | 图像 89 | 照片 90 | SD卡 91 | 根目录 92 | MIUI截屏 93 | 铃声 94 | 已选择 %1$s 95 | 设置 96 | 退出 97 | 常规设置 98 | 主页文件夹 99 | 读取根目录 100 | 显示真实路径 101 | 程序启动时显示的文件夹,当前路径为%1$s 102 | 在导航栏中显示真实路径 103 | 104 | --------------------------------------------------------------------------------