def _on_share_paths_cb(paths, share_links, error_info='', move=False, save_to_clipboard=True, context=''): ''' Callback to be called after processing of 'share_path' shell command @param paths Filesystem paths [list] @param share_links Links URLs [list] or None if links getting failed ''' if share_links: if save_to_clipboard: Application.show_tray_notification( tr("URL(s) for downloading copied to clipboard"), tr("Sharing")) else: params.ipc_ws_server.on_paths_links(paths, share_links, context, move) elif paths: try: share_names = list(map(lambda p: get_relpath(p)[1], paths)) signals.share_path_failed.emit(share_names) except Exception as e: logger.warning( "on_share_paths_cb, share_path_failed exception: %s", e) Application.show_tray_notification( tr("Sharing {} file(s) failed: {}").format(len(paths), error_info), tr("Sharing"))
def show_copying_failed(path): ''' Shows message when copying of file/dir into sync directory failed @param path Filesystem path [unicode] ''' name = op.basename(path) Application.show_tray_notification( tr("Failed to copy '{}' into sync directory").format(name), tr("Shell"))
def block_path_slot(paths): ''' Callback to be called after processing 'block_path' shell command @param path Filesystem path [unicode] ''' # Request share cancelling if cancel_sharing(paths): Application.show_tray_notification(tr("Sharing cancelled"), tr("Sharing")) else: Application.show_tray_notification(tr("Failed to cancel path sharing"), tr("Sharing"))
def _on_open_link_cb(path, share_link): ''' Callback to be called after processing 'open_link' shell command @param path Filesystem path [unicode] @param share_link Link URL [unicode] or None if link getting failed ''' # Open URL in the web browser (if any) if share_link: webbrowser.open_new(share_link) else: name = op.basename(path) Application.show_tray_notification( tr("Failed to share file: {}").format(name), tr("Sharing"))
def _check_free_space(path, root, move, is_file): if is_file: size = op.getsize(path) else: size = get_dir_size(path) if move: path_list = path.split('/') root_list = root.split('/') # check if we have same drive for move if path_list[0] == root_list[0]: return True approx_total_size = size * 2 + size * 0.1 # size for files, copies, signs if get_free_space(root) < approx_total_size: logger.warning("Not enough disk space for (moving) '%s'", path) msg = tr("Not enough disk space for copying (moving)\n{} to {}.\n" "Please clean disk") Application.show_tray_notification(msg.format(path, root), tr("Sharing")) return False return True
def _on_email_link_cb(paths, share_links, error_info=''): ''' Processes 'email_link' shell command @param path Filesystem path [unicode] @param share_link Link URL [unicode] or None if link getting failed ''' # Pass share link to default mail client as 'mailto' protocol (if any) if share_links: subject = "Link for shared files/folders by Pvtbox" body = "Shared by Pvtbox:\r\n" for path, link in zip(paths, share_links): _, share_name = get_relpath(path) body += "{} - {}\r\n".format(share_name, link) mailto_url = "mailto:?subject={}&body={}" \ .format(quote(subject.encode("utf-8")), quote(body.encode("utf-8"))) webbrowser.open_new(mailto_url) else: share_names = list(map(lambda p: get_relpath(p)[1], paths)) signals.share_path_failed.emit(share_names) Application.show_tray_notification( tr("Failed to share {} file(s)").format(len(paths)), tr("Sharing"))
def add_to_sync_dir(paths, move, callback): ''' Copies given paths (files or directories) into sync directory. If destination path exists, new name in sync directory will be created @param paths to be copied [list] ''' # Get sync directory path root = params.cfg.sync_directory if not root: logger.warning("Sync directory is not set") return logger.debug("Copying %d paths", len(paths)) signals.show.emit() result_paths = [] offline_paths = [] online_paths = [] for path in paths: is_file = op.isfile(path) path = FilePath(path) # Path is in sync directory already if path in FilePath(root): logger.debug("Path '%s' is in sync directory '%s' already", path, root) result_paths.append(path) if is_file and not move: if path.endswith(FILE_LINK_SUFFIX): online_paths.append(path) else: offline_paths.append(path) continue if not op.exists(path.longpath): logger.warning( "Path requested for copying does not exist " "or not enough rights " "are granted to access it: '%s'", FilePath(path)) Application.show_tray_notification( tr("Failed to copy to synchronized directory. Specified path " "does not exist."), tr("Sharing")) continue basename = op.basename(path) destname = get_next_name(FilePath(op.join(root, basename)).longpath) if not _check_free_space(path, root, move, is_file): continue file_dir = 'file' if is_file else 'dir' logger.debug("Copying (moving) %s '%s' into sync directory...", file_dir, path) # Emit corresponding signal signals.copying_started.emit(path) # Copy or move file or directory into sync directory try: if move: shutil.move(path, destname) elif is_file: copy_file(path, destname) else: shutil.copytree(path, destname) except Exception as e: logger.error("Failed to copy (move) '%s' into sync directory (%s)", path, e) signals.copying_failed.emit(path) continue # Emit corresponding signal signals.copying_finished.emit(path) result_paths.append(destname) logger.debug("Copied successfully") if offline_paths: signals.offline_paths.emit(offline_paths, False, True) if online_paths: signals.offline_paths.emit(online_paths, True, True) logger.debug("All paths copied") if callable(callback): callback(result_paths)
def offline_paths(paths, is_offline=True, is_recursive=True): """ Makes given paths offline as is_offline flag @param paths paths [list] @param is_offline flag [bool] @return None """ def process_error(error, error_info=''): msg = { INCORRECT_PATH: "Failed to change offline status '%s'. Incorrect path", NOT_IN_SYNC: "Path for changing offline status not in sync '%s'", } logger.error(msg[error], paths) if params.tracker: tracker_errors = { INCORRECT_PATH: params.tracker.INCORRECT_PATH, NOT_IN_SYNC: params.tracker.NOT_IN_SYNC, } params.tracker.share_error(0, tracker_errors[error], time.time() - start_time) start_time = time.time() timeout = 10 * 60 # seconds message_timeout = 2 # seconds step = 0 command_str = tr("add to offline") if is_offline \ else tr("remove from offline") for path in paths: path = ensure_unicode(path) try: # Name of the file relative to the root directory root, rel_path = get_relpath(path) if not rel_path: raise SharePathException() except SharePathException: process_error(INCORRECT_PATH) return if rel_path.endswith(FILE_LINK_SUFFIX): rel_path = rel_path[:-len(FILE_LINK_SUFFIX)] if not rel_path: process_error(INCORRECT_PATH) return logger.info("Offline on=%s, path '%s'...", is_offline, rel_path) while True: # Wait if file not in db yet try: if op.isfile(path): uuid = params.sync.get_file_uuid(rel_path) elif op.isdir(path): uuid = params.sync.get_folder_uuid(rel_path) else: process_error(INCORRECT_PATH) return except (FileNotFound, FileInProcessing, FileEventsDBError): uuid = None if uuid or (time.time() - start_time > timeout and node_synced): break if step == message_timeout: filename = op.basename(path) Application.show_tray_notification( tr("Prepare {}.\n" "Action will be completed after {} synced").format( command_str, filename)) step += 1 time.sleep(1) if not uuid: process_error(NOT_IN_SYNC) Application.show_tray_notification( tr("Can't {}.\n" "{} not in sync").format(command_str, path)) return try: params.sync.file_added_to_indexing.emit(FilePath(path)) success = params.sync.make_offline(uuid, is_offline, is_recursive=is_recursive) except FileEventsDBError: success = False if not success: params.sync.file_removed_from_indexing.emit(FilePath(path)) Application.show_tray_notification( tr("Can't {} for path: {}.").format(command_str, path))
def collaboration_path_settings(paths): """ Prepares opening of collaboration settings dialog for given paths @param paths Path (1 element list) to folder with (potential) collaboration [list] @return None """ def process_error(error, error_info=''): msg = { INCORRECT_PATH: "Failed to open collaboration settings '%s'. Incorrect path", NOT_IN_SYNC: "Path for collaboration settings not in sync '%s'", } logger.error(msg[error], paths) if params.tracker: tracker_errors = { INCORRECT_PATH: params.tracker.INCORRECT_PATH, NOT_IN_SYNC: params.tracker.NOT_IN_SYNC, } params.tracker.share_error( 0, tracker_errors[error], time.time() - start_time) start_time = time.time() timeout = 10 * 60 # seconds message_timeout = 2 # seconds step = 0 if len(paths) != 1: process_error(INCORRECT_PATH) return path = ensure_unicode(paths[0]) if not op.isdir(path): process_error(INCORRECT_PATH) return try: # Name of the file relative to the root directory root, rel_path = get_relpath(path) if not rel_path or '/' in rel_path: raise SharePathException() except SharePathException: process_error(INCORRECT_PATH) return logger.info("Collaboration settings path '%s'...", rel_path) while True: # Wait if file not in db yet try: uuid = params.sync.get_folder_uuid(rel_path) except (FileNotFound, FileInProcessing, FileEventsDBError): uuid = None if uuid or (time.time() - start_time > timeout and node_synced): break if step == message_timeout: filename = op.basename(path) Application.show_tray_notification( tr("Prepare open collaboration settings.\n" "Dialog will be opened after {} synced").format( filename)) step += 1 time.sleep(1) if not uuid: process_error(NOT_IN_SYNC) Application.show_tray_notification( tr("Can't open collaboration settings.\n" "{} not in sync").format(path)) return logger.debug("Collaboration settings requested for path %s, uuid %s", rel_path, uuid) signals.show_collaboration_settings.emit(rel_path, uuid)