Implement packing/unpacking which are enough for basic use
This commit is contained in:
parent
ec46a11cc6
commit
9032586abf
3 changed files with 168 additions and 31 deletions
133
notes.sh
133
notes.sh
|
@ -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
12
test/mime-simple
Normal 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
56
test/test.sh
Executable 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
|
Loading…
Reference in a new issue