diff --git a/bin/link-development-folders b/bin/link-development-folders new file mode 100755 index 0000000..2c05283 --- /dev/null +++ b/bin/link-development-folders @@ -0,0 +1,122 @@ +#!/bin/sh +PATH_TO_LIBRARY="${HOME}/Projects"; +PATH_TO_DEVELOPER="${HOME}/Developer"; + +check_for_folder_or_return_error() { + path2check="${1}"; + if [ ! -d "${path2check}" ]; then + echo "Path ${path2check} is not a folder. Skipping."; + return 1; + fi +} + +check_for_development_folder_or_return_error() { + path2check="${1}"; + if [ "${path2check##*/}" != "Development" ]; then + echo "Path ${path2check} is not a Development folder. Skipping."; + return 2; + fi +} + +remove_library_path_prefix() { + given_path="${1}"; + path_with_library_prefix_removed="${given_path#${PATH_TO_LIBRARY}/}"; + path_with_root_dot="${path_with_library_prefix_removed:-.}"; + echo "${path_with_root_dot}"; +} + +remove_trailing_slash_in_path() { + given_path="${1}"; + path_without_tailing_slash="${given_path%/}"; + path_with_root_slash="${path_without_last_slash:-/}"; + echo "${path_with_root_slash}"; +} + +remove_trailing_development_folder() { + given_path="${1}"; + path_with_development_remove="${given_path%/Development}"; + echo "${path_with_development_remove}"; +} + +remove_last_path_element() { + given_path="${1}"; + path_without_last_element="${given_path%/*}"; + path_with_root_slash="${path_without_last_element:-/}"; + echo "${path_with_root_slash}"; +} + +remove_file_from_path() { + given_path="${1}"; + [ -f "${given_path}" ] && given_path=`remove_last_path_element "${given_path}"`; + echo "${given_path}"; +} + +get_last_folder_in_path() { + given_path=`remove_file_from_path ${1}`; + tail_of_path="${given_path##*/}"; + tail_with_root_slash="${tail_of_path:-/}"; + echo "${tail_with_root_slash}"; +} + +reduce_path_to_owner_and_client() { + given_path="${1}"; + relative_path=`remove_library_path_prefix "${library_path}"`; + owner_and_client_folder=`remove_trailing_development_folder "${relative_path}"`; + echo "${owner_and_client_folder}"; +} + +create_owner_folder_in_developer() { + owner="${1}"; + development_path="${PATH_TO_DEVELOPER}/${owner}"; + + if [ ! -d "${development_path}" ]; then + echo "Creating: ${development_path}"; + mkdir -p "${development_path}"; + fi +} + +link_folder_to_developer_as_client() { + folder="${1}"; + owner="${2}"; + client="${3}"; + + development_path="${PATH_TO_DEVELOPER}/${owner}"; + + if [ ! -L "${development_path}/${client}" ]; then + echo " >Linked Development for client ${client} to owner ${development_path%/*}"; + ln -s "${folder}" "${development_path}/${client}"; + fi +} + +link_development_folders() { + library_path=`remove_trailing_slash_in_path "${1}"`; + check_for_folder_or_return_error "${library_path}" || exit $?; + check_for_development_folder_or_return_error "${library_path}" || exit $?; + + owner_and_client_folder=`reduce_path_to_owner_and_client "${library_path}"`; + client=`get_last_folder_in_path "${owner_and_client_folder}"`; + owner="${owner_and_client_folder%/${client}}"; + + create_owner_folder_in_developer "${owner}"; + link_folder_to_developer_as_client "${library_path}" "${owner}" "${client}"; +} + +find_and_link_development_folders() { + find "${PATH_TO_LIBRARY}" -type d -name "Development" -maxdepth 4 -print0 2> /dev/null | + while IFS= read -r -d '' line; do + link_development_folders "${line}"; + done +} + +find_and_link_executables() { + find "${PATH_TO_LIBRARY}" -type d -name "Development" -maxdepth 4 -print0 2> /dev/null | + while IFS= read -r -d '' line; do + link_development_folders "${line}"; + done +} + +main() { + find_and_link_development_folders; + find_and_link_executables; +} + diff --git a/bin/ocr b/bin/ocr new file mode 100755 index 0000000..8dfa437 --- /dev/null +++ b/bin/ocr @@ -0,0 +1,9 @@ +#!/bin/sh +for pdf in ./*.pdf; do + filename="`basename "${pdf}"`"; + path="`dirname "${pdf}"`"; + mkdir -p OCRed; + printf 'OCRing %s' "${pdf}"; + ocrmypdf -l deu "${pdf}" "${path}/OCRed/${filename}"; + printf '...done\n'; +done diff --git a/bin/pwdf b/bin/pwdf new file mode 100755 index 0000000..e3de211 --- /dev/null +++ b/bin/pwdf @@ -0,0 +1,33 @@ +#!/usr/bin/osascript +# Taken from https://gist.githubusercontent.com/scriptingosx/4a237fcf7b0cc473e7c175a86b6b3ecc/raw/8d5f184e4bd83dc481411a385a23a4b9bcf17c0e/pwdf + +on run arguments + tell application "Finder" + -- no argument: get frontmost window or desktop + if (count of arguments) is 0 then + if (count of windows) is 0 then + set dir to (desktop as alias) + else + set dir to ((target of Finder window 1) as alias) + end if + else + if first item of arguments is in {"all", "-a", "-all", "--all"} then + -- list all Finder windows + copy target of every Finder window to theList + repeat with w in theList + log POSIX path of (w as alias) + end repeat + return + end if + -- see if there is a window matching the name + set t to arguments as text + set wins to every Finder window where name contains t + if (count of wins) > 0 then + set dir to ((target of item 1 of wins) as alias) + else + return + end if + end if + return POSIX path of dir + end tell +end run diff --git a/bin/resolve-macos-alias b/bin/resolve-macos-alias new file mode 100755 index 0000000..f7e3733 --- /dev/null +++ b/bin/resolve-macos-alias @@ -0,0 +1,28 @@ +#!/usr/bin/osascript -l JavaScript +ObjC.import("stdlib") + +function showNSError(error) { + console.log(ObjC.unwrap(error.localizedDescription)) +} + +function resolveFileAlias(filePath) { + const aliasFile = $.NSURL.fileURLWithPathIsDirectory(filePath, false) + let error = $() + const exists = aliasFile.checkResourceIsReachableAndReturnError(error) + if (!exists) { + showNSError(error) + return filePath + } + + error = $() + const file = $.NSURL.URLByResolvingAliasFileAtURLOptionsError(aliasFile, $.NSURLBookmarkResolutionWithoutUI, error) + if (file.path === aliasFile.path) showNSError(error) + return file.path +} + +let args = $.NSProcessInfo.processInfo.arguments +let lastIndex = args.count - 1 +var filePath = ObjC.unwrap(args.objectAtIndex(lastIndex)) +newFilePath = resolveFileAlias(filePath) +if (newFilePath === filePath) $.exit(1) +newFilePath diff --git a/bin/strip-mail-attachments b/bin/strip-mail-attachments new file mode 100755 index 0000000..2206aad --- /dev/null +++ b/bin/strip-mail-attachments @@ -0,0 +1,102 @@ +#!/usr/bin/env python3 +import os +import email +import sys +import re +import hashlib +from email.header import decode_header +from io import BytesIO + +def update_sha256(sha256, stream): + for byte_block in iter(lambda: stream.read(4096), b""): + sha256.update(byte_block) + +def get_filename_by_sha256(sha256hash, at_path='.'): + with os.scandir(at_path) as it: + for file_or_folder in it: + if not file_or_folder.is_file(): continue + sha256 = hashlib.sha256() + with open(file_or_folder, "rb") as f: + update_sha256(sha256, f) + if sha256.hexdigest() == sha256hash: + return file_or_folder.name + return None + +ReplaceString = """ + +This message contained an attachment that was stripped out. +The original type was: %(content_type)s +The filename was: %(filename)s +It is now stored as: %(newfilename)s +""" +BAD_CONTENT_RE = re.compile('application/(msword|msexcel|pdf)', re.I) +BAD_FILEEXT_RE = re.compile(r'(\.exe|\.zip|\.pif|\.scr|\.ps|\.pdf)$', re.I) + +def sanitise(msg): + # Strip out all payloads of a particular type + ct = msg.get_content_type() + # We also want to check for bad filename extensions + fn = msg.get_filename() + if decode_header(fn or '')[0][1] is not None: + fn = decode_header(fn)[0][0].decode(decode_header(fn)[0][1]) + # get_filename() returns None if there's no filename + if BAD_CONTENT_RE.search(ct) or (fn and BAD_FILEEXT_RE.search(fn)): + payload = msg.get_payload(None, True) + newfn = 'cannot tell' + if isinstance(payload, bytes): + payload = BytesIO(payload) + sha256 = hashlib.sha256() + update_sha256(sha256, payload) + check_newfn = get_filename_by_sha256(sha256.hexdigest()) + if check_newfn is not None: newfn = check_newfn + # Ok. This part of the message is bad, and we're going to stomp + # on it. First, though, we pull out the information we're about to + # destroy so we can tell the user about it. + # This returns the parameters to the content-type. The first entry + # is the content-type itself, which we already have. + params = msg.get_params()[1:] + # The parameters are a list of (key, value) pairs - join the + # key-value with '=', and the parameter list with ', ' + params = ', '.join([ '='.join(p) for p in params ]) + # Format up the replacement text, telling the user we ate their + # email attachment. + replace = ReplaceString % dict(content_type=ct, + filename=fn, + newfilename=newfn, + params=params) + # Install the text body as the new payload. + msg.set_payload(replace, charset='utf-8') + # Now we manually strip away any paramaters to the content-type + # header. Again, we skip the first parameter, as it's the + # content-type itself, and we'll stomp that next. + for k, v in msg.get_params()[1:]: + msg.del_param(k) + # And set the content-type appropriately. + msg.set_type('text/plain; charset="utf-8"') + # Since we've just stomped the content-type, we also kill these + # headers - they make no sense otherwise. + del msg['Content-Transfer-Encoding'] + del msg['Content-Disposition'] + else: + # Now we check for any sub-parts to the message + if msg.is_multipart(): + # Call the sanitise routine on any subparts + payload = [ sanitise(x) for x in msg.get_payload() ] + # We replace the payload with our list of sanitised parts + msg.set_payload(payload) + # Return the sanitised message + return msg + +if __name__=='__main__': + incontent=sys.stdin.read() + try: + rootmsg=email.message_from_string(incontent) + except: + sys.stderr.write("Message could not be parsed") + sys.exit(1) + src=sanitise(rootmsg).as_string() + + if src!=None: + sys.stdout.write(src) + else: + sys.stdout.write(incontent) diff --git a/modules/07-install-binaries.sh b/modules/07-install-binaries.sh new file mode 100755 index 0000000..326ebed --- /dev/null +++ b/modules/07-install-binaries.sh @@ -0,0 +1,54 @@ +#!/usr/bin/env zsh +# vi: ft=zsh + +function ensureRightAccess() { + local filesystemItem="$1" + chown root:admin "${filesystemItem}" + chmod ugo=rx "${filesystemItem}" +} + +function configure_system() { + local dstDir='/usr/local/bin' + [[ -d ${dstDir} ]] || { + lop -- -e "Could not install binaries. Directory ${dstDir} does not exist." + return 10 + } + pushd -q ${_DIR}/../bin + for file in *; do + indicateActivity cp,${file},${dstDir} "Copying ${file}" + ensureRightAccess "${dstDir}/${file}" + done + popd -q +} + +function getExecPrerequisites() { + cmds=( + [cp]='' + ) +} + +function getUsage() { + read -r -d '' text <<- USAGE + Usage: + $cmdName show-questions [ ]... + $cmdName [-v] [-d FILE] + + Install convenient binaries for all users. + + Options: + -d FILE, --logfile FILE Print log message to logfile instead of stdout. + -v, --verbose Be more verbose. + ---- + $cmdName 0.1.0 + Copyright (C) 2022 Rezart Qelibari, Astzweig GmbH & Co. KG + License EUPL-1.2. There is NO WARRANTY, to the extent permitted by law. + USAGE + print -- ${text} +} + +if [[ "${ZSH_EVAL_CONTEXT}" == toplevel ]]; then + _DIR="${0:A:h}" + test -f "${ASTZWEIG_MACOS_SYSTEM_LIB}" || { echo 'This module requires macos-system library. Please run again with macos-system library provieded as a path in ASTZWEIG_MACOS_SYSTEM_LIB env variable.'; return 10 } + source "${ASTZWEIG_MACOS_SYSTEM_LIB}" + module_main $0 "$@" +fi