Implement packing/unpacking which are enough for basic use

This commit is contained in:
Konstantin Nazarov 2021-05-16 20:20:26 +00:00
parent ec46a11cc6
commit 9032586abf
Signed by: knazarov
GPG key ID: 4CFE0A42FA409C22
3 changed files with 168 additions and 31 deletions

133
notes.sh
View file

@ -3,9 +3,16 @@
set -e set -e
DATE_FORMAT="%a, %d %b %Y %H:%M:%S %z" DATE_FORMAT="%a, %d %b %Y %H:%M:%S %z"
BASEDIR=~/Maildir/personal/Notes
PID=$$ PID=$$
BASEDIR=~/Maildir/personal/Notes
if [ -n "$NOTES_SH_BASEDIR" ]; then
BASEDIR="$NOTES_SH_BASEDIR"
fi
if [ -z "$EDITOR" ]; then
EDITOR=vim
fi
if [ ! -d "$BASEDIR" ]; then if [ ! -d "$BASEDIR" ]; then
mkdir -p "$BASEDIR"/{tmp,new,cur} mkdir -p "$BASEDIR"/{tmp,new,cur}
@ -17,7 +24,7 @@ uuid()
for (( N=0; N < 16; ++N )) for (( N=0; N < 16; ++N ))
do do
B=$(( $RANDOM%255 )) B=$(( RANDOM%255 ))
if (( N == 6 )) if (( N == 6 ))
then then
@ -25,7 +32,7 @@ uuid()
elif (( N == 8 )) elif (( N == 8 ))
then then
local C='89ab' local C='89ab'
printf '%c%x' ${C:$(( $RANDOM%${#C} )):1} $(( B%15 )) printf '%c%x' ${C:$(( RANDOM%${#C} )):1} $(( B%15 ))
else else
printf '%02x' $B printf '%02x' $B
fi fi
@ -43,10 +50,33 @@ uuid()
echo echo
} }
get_headers() {
FILE="$1"
FILTER="\
{ \
if (\$0~/^$/) {exit} \
print \$0 \
} \
"
awk "$FILTER" "$FILE"
}
get_body() {
FILE="$1"
FILTER="\
{ \
if (body==1) {print \$0}\
if (\$0~/^$/) {body=1} \
} \
"
awk "$FILTER" "$FILE"
}
get_header() { get_header() {
FILE="$1" FILE="$1"
HEADER="$2" HEADER="$2"
echo $(grep -m1 "^${HEADER}: " < "$FILE" | sed -n "s/^${HEADER}: \(.*\)$/\1/p") grep -m1 "^${HEADER}: " < "$FILE" | sed -n "s/^${HEADER}: \(.*\)$/\1/p"
} }
get_part() { get_part() {
@ -81,7 +111,7 @@ unpack_part() {
if [[ $DISPOSITION == *"attachment"* ]]; then if [[ $DISPOSITION == *"attachment"* ]]; then
ENCODING=$(get_header "$FILE" Content-Transfer-Encoding) ENCODING=$(get_header "$FILE" Content-Transfer-Encoding)
FILENAME=$(echo $DISPOSITION | \ FILENAME=$(echo "$DISPOSITION" | \
sed -n 's/^.*filename="\{0,1\}\(.*\)"\{0,1\}$/\1/p') sed -n 's/^.*filename="\{0,1\}\(.*\)"\{0,1\}$/\1/p')
FILTER="\ FILTER="\
{ \ { \
@ -104,7 +134,7 @@ unpack_part() {
" "
awk "$FILTER" "$FILE" >> "$DIR/note.md" awk "$FILTER" "$FILE" >> "$DIR/note.md"
elif [[ $MIME_TYPE == *"multipart/mixed"* ]]; then elif [[ $MIME_TYPE == *"multipart/mixed"* ]]; then
BOUNDARY=$(echo $MIME_TYPE | sed -n 's/^.*boundary="\(.*\)"$/\1/p') BOUNDARY=$(echo "$MIME_TYPE" | sed -n 's/^.*boundary="\(.*\)"$/\1/p')
i=1 i=1
while true; do while true; do
TMP=$(mktemp --tmpdir="$DIR") TMP=$(mktemp --tmpdir="$DIR")
@ -136,7 +166,7 @@ unpack_mime() {
MESSAGE_ID=$(get_header "$FILE" Message-Id) MESSAGE_ID=$(get_header "$FILE" Message-Id)
echo "Date: $DATE" > "$DIR/note.md" echo "Date: $DATE" > "$DIR/note.md"
if [ ! -z "$MESSAGE_ID" ]; then if [ -n "$MESSAGE_ID" ]; then
echo "Message-Id: $MESSAGE_ID" >> "$DIR/note.md" echo "Message-Id: $MESSAGE_ID" >> "$DIR/note.md"
fi fi
echo "Subject: $SUBJECT" >> "$DIR/note.md" echo "Subject: $SUBJECT" >> "$DIR/note.md"
@ -149,46 +179,85 @@ unpack_mime() {
rm "$TMP" rm "$TMP"
} }
pack_mime() {
DIR="$1"
FILE="$2"
{
echo "MIME-Version: 1.0"
echo "Content-Type: text/plain; charset=utf-8"
echo "Content-Disposition: inline"
cat "$DIR/note.md"
} >> "$FILE"
}
new_entry() { new_entry() {
ENTRY_FILE=$(mktemp) DIR=$(mktemp -d)
ENTRY_FILE="$DIR/note.md"
vim -c ":set syntax=markdown" \ ENTRY_FILE_START="$(mktemp)"
-c "1 s/^/# /" \
-c "norm $" \
"$ENTRY_FILE"
if [ -s "$ENTRY_FILE" ]; then
MIME_TIMESTAMP=$(LC_ALL="en_US.UTF-8" date "+$DATE_FORMAT") MIME_TIMESTAMP=$(LC_ALL="en_US.UTF-8" date "+$DATE_FORMAT")
cat > "$ENTRY_FILE" <<- EOF
Date: $MIME_TIMESTAMP
Message-Id: <$(uuid)@notes.sh>
Subject:
EOF
cp "$ENTRY_FILE" "$ENTRY_FILE_START"
if [ -t 0 ]; then
"$EDITOR" "$ENTRY_FILE"
else
ENTRY_FILE_STDIN="$(mktemp)"
while read -r line ; do
echo "$line" >> "$ENTRY_FILE_STDIN"
done
HEADERS=$( echo "$(
get_headers "$ENTRY_FILE_STDIN"
get_headers "$ENTRY_FILE"
)" | sort -u -k1,1)
{
echo "$HEADERS"
echo ""
get_body "$ENTRY_FILE_STDIN"
} > "$ENTRY_FILE"
fi
if ! cmp -s "$ENTRY_FILE" "$ENTRY_FILE_START" ; then
UNIX_TIMESTAMP=$(date "+%s") UNIX_TIMESTAMP=$(date "+%s")
HOSTNAME=$(hostname -s) HOSTNAME=$(hostname -s)
SUBJECT=$(head -1 "$ENTRY_FILE")
SUBJECT=${SUBJECT#"# "}
RESULT=$(mktemp) RESULT=$(mktemp)
echo "Date: $MIME_TIMESTAMP" >> "$RESULT" pack_mime "$DIR" "$RESULT"
echo "MIME-Version: 1.0" >> "$RESULT"
echo "Content-Type: text/plain; charset=utf-8" >> "$RESULT"
echo "Content-Disposition: inline" >> "$RESULT"
echo "Message-Id: <$(uuid)@notes.sh>" >> "$RESULT"
echo "Subject: $SUBJECT" >> "$RESULT"
echo "" >> "$RESULT"
sed "1d" < "$ENTRY_FILE" >> "$RESULT"
#cat "$RESULT"
FILENAME="$UNIX_TIMESTAMP.${PID}_1.${HOSTNAME}:2,S" FILENAME="$UNIX_TIMESTAMP.${PID}_1.${HOSTNAME}:2,S"
mv "$RESULT" "$BASEDIR/cur/$FILENAME" mv "$RESULT" "$BASEDIR/cur/$FILENAME"
echo "done"
fi fi
} }
edit_entry() { edit_entry() {
unpack_mime "$1" ~/scratch/notes FILENAME="$(echo "$1" | sed 's/\o037.*//' )"
DIR=$(mktemp -d)
unpack_mime "$FILENAME" "$DIR"
"$EDITOR" "$DIR/note.md"
UNIX_TIMESTAMP=$(date "+%s")
HOSTNAME=$(hostname -s)
RESULT=$(mktemp)
pack_mime "$DIR" "$RESULT"
if ! cmp -s "$RESULT" "$FILENAME"; then
DEST_FILENAME="$UNIX_TIMESTAMP.${PID}_1.${HOSTNAME}:2,S"
mv "$RESULT" "$BASEDIR/cur/$DEST_FILENAME"
rm "$FILENAME"
fi
} }
list_entries() { list_entries() {
grep -m1 -r "^Subject:" "$BASEDIR" | sed -n 's/^\(.*\):Subject: \(.*\)$/\1:\2/p' grep -m1 -r "^Subject:" "$BASEDIR" | sed -n 's/^\(.*\):Subject: \(.*\)$/\1\o037 \2/p'
} }

12
test/mime-simple Normal file
View file

@ -0,0 +1,12 @@
Date: Mon, 03 May 2021 17:01:44 +0000
MIME-Version: 1.0
Content-Type: text/plain; charset=utf-8
Content-Disposition: inline
Message-Id: <b5e0e496-21a7-4492-bb78-531e5b0437fa@notes.sh>
Subject: This is a header
This is a body
- list item 1
- list item 2

56
test/test.sh Executable file
View file

@ -0,0 +1,56 @@
#!/bin/bash
BASE_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )/.." &> /dev/null && pwd )"
export BASE_DIR
cd "$BASE_DIR"
RESULT=0
testcase() {
TMP=$(mktemp -d)
cd "$TMP"
NOTES_SH_BASEDIR="$(pwd)/notes"
export NOTES_SH_BASEDIR
(set -e && eval "$@")
RES="$?"
if [[ "$RES" == "0" ]]; then
echo "$*: pass"
else
echo "$*: fail"
RESULT=1
fi
cd "$BASE_DIR"
rm -rf "$TMP"
}
assert() {
if "$@"; then
return 0
else
echo "Assert:
fi
}
new_note_from_stdin() {
"$BASE_DIR/notes.sh" -n <<- EOF
Subject: This is a header
# This is a body
EOF
OUTPUT="$(cat "$(pwd)/notes/cur"/*)"
test 1 = 2
}
testcase new_note_from_stdin
if [[ "$RESULT" == "0" ]]; then
echo "All tests passed."
else
echo "Some tests failed."
exit 1
fi