"
echo " -U Temporarily set umask to 0022 "
echo " -v Version and exit "
echo " -x hook Defines hook if not using default "./vee-pre"; hook "
echo " must be executable, i.e., chmod 755 vee-pre "
echo " "
echo "Examples: "
echo " "
echo "%vee "
echo " "
echo " user will be prompted for title and presented with vi "
echo " "
echo " if no default dir/files are found, they will be created "
echo " "
echo "%vee -t \"this is the title\" "
echo " "
echo " user will just be presented with a vi session; "
echo " "
echo "%cat text.txt | vee -b -t \"my title\" -m \"text to go before stdin\" "
echo " "
echo " This publishes contents of text.txt with provided title; -m's msg will be "
echo " shown above the cat'd text. This means of publishing content is well suited "
echo " for use with cronjobs or batch processes. It also works when GopherMode! is "
echo " invoked (-g|-G). "
echo " "
echo "%vee -l # edit and reformat the latest post "
echo "%vee -L 5 # allows one to edit and reformats the fifth latest post "
echo "%vee -r 8 # reformats the 8th latest post "
echo "%vee -n # see which post is the 8th latest post "
echo "%vee -R # reformats ALL posts that have *.raw files "
echo " "
echo "To delete a post forever: "
echo " "
echo "1) delete the entry in the INDEX "
echo " "
echo "2) purge the entry: "
echo " %vee -p # make sure it is the one you want to purge "
echo " %vee -P # purge it! "
echo " "
echo " brings up the latest entry as a vi sessions; when changes are save, "
echo " all messages are reformatted "
echo " "
echo " :E We Need to Talk About Gopher Support :E "
echo " "
echo "vee supports the creation of content in the gophersphere by formatting text-only"
echo "posts using the provided formatters (meant for text-only anyway). vee also goes"
echo "a step further and generates the gophermap (index listing) for you. "
echo " "
echo "All of the vee commands immediately above *should* work when GopherMode! is on"
echo "which is as simple as adding the -g xor -G flags. -g invokes the Gopher bits "
echo "*and* the default www support. -G only invokes the Gopher bits. Not using -g "
echo " or -G only involes the traditional www support. "
echo " "
echo "Usage examples from above, with GopherMode! enabled: "
echo " "
echo "%vee -l -G # edit and reformat the latest post "
echo "%vee -L 5 -g # allows one to edit and reformats the fifth latest post "
echo "%vee -r 8 -G # reformats the 8th latest post "
echo "%vee -n # see which post is the 8th latest post "
echo "%vee -R -g # reformats ALL posts that have *.raw files "
echo " "
echo "Notes: "
echo " "
echo "0. Reminder - vee requires zero configurations to start, but *can* be coed "
echo " by creating a .veerc file. This is also the case when in GopherGeb!Mode "
echo " "
echo "1. Batch mode looks for piped input via STDIN; if none after a short time, "
echo " message creation fails UNLESS something was passed in via '-m' as well. "
echo " If nothing was passed in via '-t' for the title, some default is used; "
echo " This is set at the top of the script as 'DEFAULT_TITLE'. "
echo " "
echo "2. Interactive mode (default) prompts for a title if no '-t' is provided. "
echo " Such is the case even if '-m' is used. If '-m' is not used in this "
echo " "
echo "3. Gopher support (-g|-G) is limited and users may discover weird issues with "
echo " updating posts or the batch reformatting options. It's a best effort. Also "
echo " the gophermap is fully regenerated whenever a new post is added; for a large"
echo " number of posts this may take a few seconds. "
echo " "
echo "4. Patches are welcome; the goal is not more feature bloat, but a nicer "
echo " way of dealing with STDIN, etc and reports/fixes for any weird gopher phlog"
echo " bugs or UX would be greatly welcomed. vee development laid dormant for years,"
echo " being used as a niche static site generator. But the rediscovery of Gopher "
echo " by the masses has made adding Gopher support a high priority. "
echo " "
disclaimer
exit 1
}
default_update_html_index()
{ echo "$PUBLISHED: $3" >> $INDEX
if [ -n "$SUMMARY" ]; then
SEC=$(expr "$SEC" - 1)
echo "$SUMMARY" >> "$INDEX"
fi
}
default_update_gophermap()
{ # rebuild the entire $GOPHERMAP
# toggle IFS if in -b mode
if [ 1 -eq $LISTENSTDIN ]; then
_OLDIFS=$IFS
IFS=$OLDIFS
fi
if [ -e $GOPHERMAP ]; then
echo Found existing $GOPHERMAP, renaming to $GOPHERMAP.bkp
mv $GOPHERMAP $GOPHERMAP.bkp #(be nice, just move to the side)
fi
default_setup_gophermap # initialize gophermap
for f in $(veels -d "$DIR" -e "$GOPHER_FORMAT"); do
_RAW=$(echo $f | sed 's/$GOPHER_FORMAT/$RAWEXT/')
_TITLE=$(echo $_RAW | veecat -t)
_DATE=$(echo $_RAW | veecat -d | awk '{print $3 " " $2 " " $6}') #e.g., Fri May 29 09:02:12 UTC 2020
# creating a symlink to $DIR because the default $DIR
# starts with a '.' and the gopher server seems to not
# want to serve files in such a directory
fileLink=$(echo $f | sed "s/$DIR/phlogsrc/")
# seems relative paths can't be directories that start
# with a dot (e.g., ".vee")
ln -s $DIR phlogsrc > /dev/null 2>&1 # rather than check if link exists, just try it and hide error
printf "0[$_DATE] $_TITLE\t$fileLink\n" >> $GOPHERMAP
done
echo >> $GOPHERMAP
echo >> $GOPHERMAP
echo $GOPHERMAP_FOOTER | fmt -w 67 >> $GOPHERMAP
echo >> $GOPHERMAP
echo >> $GOPHERMAP
echo Generated with vee. >> $GOPHERMAP
# toggle IFS back if temporarily set to interactive IFS above
if [ 1 -eq $LISTENSTDIN ]; then
IFS=$_OLDIFS
fi
}
#"$FINAL" "$gFINAL" "$RAW" "$gRAW" "$TITLE"
default_update_index()
{
if [ 2 != $GOPHERMODE ]; then
default_update_html_index "$1" "$3" "$5"
fi
if [ 0 != $GOPHERMODE ]; then
default_update_gophermap "$2" "$4" "$5"
fi
}
output_top()
{ echo "$HEADERTXT" > "$FINAL"
if [ -e "$TOP_TPL" ]; then
cat "$TOP_TPL" >> "$FINAL"
else
echo "" >> "$FINAL"
echo "" >> "$FINAL"
echo " $TITLE - $DATE" >> "$FINAL"
echo " " >> "$FINAL"
echo " " >> "$FINAL"
echo "[index][raw][main]" >> "$FINAL"
fi
echo >> "$FINAL"
}
output_bottom()
{ echo >> "$FINAL"
echo -- >> "$FINAL"
echo "$FOOTERTXT" >> "$FINAL"
if [ -e "$BOT_TPL" ]; then
cat "$BOT_TPL" >> "$FINAL"
else
echo "
" >> "$FINAL"
echo " " >> "$FINAL"
echo "" >> "$FINAL"
fi
}
# begin formatting funcs
format_with_groff()
{ #sed 1liner from http://sed.sourceforge.net/sed1line.txt
if [ "html" = "$_OUTPUT_TYPE" ]; then
groff -man -Tascii "$RAW" > $$.tmp.$RAWEXT
sed '/^$/N;/\n$/D' < $$.tmp.$RAWEXT > $$.tmp.final
cat $$.tmp.final >> "$FINAL"
fi
if [ "gopher" = "$_OUTPUT_TYPE" ]; then
groff -man -Tascii "$gRAW" > $$.tmp.$RAWEXT
sed '/^$/N;/\n$/D' < $$.tmp.$RAWEXT > $$.tmp.final
cat $$.tmp.final > "$gFINAL"
fi
rm $$.tmp.$RAWEXT $$.tmp.final
}
format_with_fmt()
{ if [ 0 -lt $MARGIN ]; then
if [ "html" = $_OUTPUT_TYPE ]; then
fmt -w $MARGIN "$RAW" > $$.tmp.$RAWEXT
cat $$.tmp.$RAWEXT >> "$FINAL"
fi
if [ "gopher" = $_OUTPUT_TYPE ]; then
fmt -w $MARGIN "$gRAW" > $$.tmp.$RAWEXT
cat $$.tmp.$RAWEXT > "$gFINAL"
fi
rm $$.tmp.$RAWEXT
else
with_no_formatting
fi
}
format_with_fold()
{ if [ 0 -lt $MARGIN ]; then
if [ "html" = $_OUTPUT_TYPE ]; then
fold -s -w $MARGIN "$RAW" > $$.tmp.$RAWEXT
cat $$.tmp.$RAWEXT >> "$FINAL"
fi
if [ "gopher" = $_OUTPUT_TYPE ]; then
fold -s -w $MARGIN "$gRAW" > $$.tmp.$RAWEXT
cat $$.tmp.$RAWEXT > "$gFINAL"
fi
rm $$.tmp.$RAWEXT
else
with_no_formatting
fi
}
with_no_formatting()
{ if [ "html" = $_OUTPUT_TYPE ]; then
cat "$RAW" >> "$FINAL"
fi
if [ "gopher" = $_OUTPUT_TYPE ]; then
cat "$gRAW" > "$gFINAL"
fi
}
#
# preformat hook has been changed to NOT be a filter;
#
# $1 is 'html' or 'gopher'
#
preformat()
{ if [ -x "$PREFORMAT_HOOK" ]; then
"$PREFORMAT_HOOK" "$1"
fi
}
#
# this hook is for any things to do after the post; a good example for use
# would be to integrate git or another SCM; another is a notification script
#
# $1 is 'html' or 'gopher'
#
postformat()
{ if [ -x "$POSTFORMAT_HOOK" ]; then
"$POSTFORMAT_HOOK" "$1"
fi
}
# dispatches formatting based on $GOPHERMODE; sets $_OUTPUT_TYPE
# for called functions to know for what $_OUTPUT_TYPE they're doing stuff
format_main_html()
{ FINAL=$DIR/$1
FINALNAME=$1
RAW=$DIR/$2
RAWNAME=$2
preformat $_OUTPUT_TYPE # expecting 'html'
if [ ! -e "$RAW" ]; then
echo "$DATE" > "$RAW" # in RAW, line 1 is date
echo >> "$RAW"
echo "$TITLE" >> "$RAW" # in RAW, line 2 is title
echo >> "$RAW"
echo "--" >> "$RAW"
echo >> "$RAW" # this blank line is important
cat "$DRAFT" >> "$RAW"
fi
$OUTPUT_TOP
$FORMAT_FUNC
$OUTPUT_BOT
postformat $_OUTPUT_TYPE # expecting 'html'
}
format_main_gopher()
{ gFINAL=$DIR/$1
gFINALNAME=$1
gRAW=$DIR/$2
gRAWNAME=$2
preformat $_OUTPUT_TYPE # expecting 'gopher'
if [ ! -e "$gRAW" ]; then
echo "$DATE" > "$gRAW" # in gRAW, line 1 is date
echo >> "$gRAW"
echo "$TITLE" >> "$gRAW" # in gRAW, line 2 is title
echo >> "$gRAW"
echo "--" >> "$gRAW"
echo >> "$gRAW" # this blank line is important
cat "$DRAFT" >> "$gRAW"
fi
$OUTPUT_TOP_GOPHER # NOTE: not set by default
$FORMAT_FUNC
$OUTPUT_BOT_GOPHER # NOTE not set by default
postformat $_OUTPUT_TYPE # expecting 'gopher'
}
format_main()
{ if [ 2 != $GOPHERMODE ]; then
_OUTPUT_TYPE=html # tracks formatting type
format_main_html "$1" "$3"
fi
if [ 0 != $GOPHERMODE ]; then
_OUTPUT_TYPE=gopher # tracks formatting type
format_main_gopher "$2" "$3"
fi
_OUTPUT_TYPE=none
}
reformat_singleton()
{ if [ -e "$DIR/$1.$RAWEXT" ]; then
cat "$DIR/$1.$RAWEXT" > "$DRAFT"
format_main "$1.$FORMAT" "$1.$GOPHER_FORMAT" "$1.$RAWEXT"
fi
}
reformat_all()
{
for f in $(veels -d "$DIR" -r); do
# From: Randall R Schulz
FULLNAME="$f"
DIR=${FULLNAME%/*}
FILE=${FULLNAME##*/}
MAXBASE=${FILE%.*}
MINBASE=${FILE%%.*}
MAXSUF=${FILE#*.}
MINSUF=${FILE##*.}
_TITLE=$(echo $f | veecat -t)
echo "..reformatting '$_TITLE'"
reformat_singleton "$MAXBASE"
done
}
list_newest_first()
{ COUNT=1
for _RAW in $(veels -d "$DIR"); do
_TITLE=$(echo $_RAW | veecat -t)
_DATE=$(echo $_RAW | veecat -d)
printf "%4d) " "$COUNT"
echo $_DATE - $_TITLE
COUNT=$(expr $COUNT + 1)
done
}
list_oldest_first()
{ COUNT=1
for _RAW in $(veels -d "$DIR" -r); do
_TITLE=$(echo $_RAW | veecat -t)
_DATE=$(echo $_RAW | veecat -d)
printf "%4d) " "$COUNT"
echo $_DATE - $_TITLE
COUNT=$(expr $COUNT + 1)
done
}
get_path2post()
{
GOAL=$1
COUNT=1
for FILE in $(veels -d "$DIR"); do
FULLNAME=$FILE
DIR=${FULLNAME%/*}
FILE=${FULLNAME##*/}
MAXBASE=${FILE%.*}
if [ "$COUNT" -eq "$GOAL" ]; then
echo "$MAXBASE"
break
fi
COUNT=$(expr "$COUNT" + 1)
done
}
purge_entries()
{ LEVEL=$1
COUNT=0
if [ ! -e "$INDEX" ]; then
echo "Can't find index, \"$INDEX\""
die_cleanly
fi
for FILE in $(veels -d "$DIR"); do
FULLNAME=$FILE
DIR=${FULLNAME%/*}
FILE=${FULLNAME##*/}
MAXBASE=${FILE%.*}
ENTRY=$(grep "$MAXBASE" "$INDEX")
if [ -z "$ENTRY" ]; then
COUNT=$(expr "$COUNT" + 1)
if [ "$LEVEL" -eq 1 ]; then
echo "$DIR/$FILE (not really purged, use -P for realz)"
elif [ "$LEVEL" -eq 2 ]; then
echo "$DIR/$MAXBASE[.$RAWEXT,$FORMAT] (delebed)"
rm -f "$DIR/$MAXBASE"*
fi
fi
done
if [ "$LEVEL" -eq 1 ]; then
echo "use -P to remove all $COUNT entrie(s)"
elif [ "$LEVEL" -eq 2 ]; then
echo "removed $COUNT entrie(s)..."
fi
}
die_cleanly()
{ if [ -e "$DRAFT" ]; then
rm -f "$DRAFT"
fi
exit 0
}
_POST2REFORMAT=0
_REFORMATALL=0
_PURGELEVEL=0
_POST2EDIT=0
SUMMARY=
MESSAGE=
SET_DEFAULT_FORMAT_FUNC=
# get opts ! stdin append to anything passed in by -m
while getopts 'DgGf:m:t:T:c:d:i:IbB:hRr:lL:novx:X:Pps:u:U' option; do
case $option in
u) _CUSTOM_UMASK=$OPTARG
;;
U) _CUSTOM_UMASK=0022
;;
D) set -x
echo Setting debug mode with, set -x
;;
g) # Gopher mode 1: output .txt and update $GOPHERMAP along side of HTML
GOPHERMODE=1
;;
G) # Gopher mode 2: treat as gopher phlog only (skip HTML stuff)
GOPHERMODE=2
;;
i) INDEX=$OPTARG # specify INDEX to $OPTARG
;;
I) INDEX="index.html" # force INDEX to index.html
;;
d) if [ -d "$OPTARG" ]; then
cd "$OPTARG"
else
echo "$OPTARG" is not a directory!
die_cleanly
fi
;;
r) _POST2REFORMAT=$OPTARG
;;
R) _REFORMATALL=1
;;
b) LISTENSTDIN=1
USE_EDITOR=0
;;
B) BOT_TPL=$OPTARG
;;
f) SET_DEFAULT_FORMAT_FUNC=$OPTARG
;;
c) MARGIN=$OPTARG
;;
l) _POST2EDIT=1
;;
L) _POST2EDIT=$OPTARG
;;
m) MESSAGE=$OPTARG
USE_EDITOR=0
;;
n) list_newest_first
die_cleanly
;;
o) list_oldest_first
die_cleanly
;;
s) SUMMARY=$OPTARG
;;
t) TITLE=$OPTARG
;;
T) TOP_TPL=$OPTARG
;;
v) echo $VERSION
die_cleanly
;;
p) _PURGELEVEL=1
;;
P) _PURGELEVEL=2
;;
h) usage | less
die_cleanly
;;
x) PREFORMAT_HOOK=$OPTARG
;;
?) #usage | less
die_cleanly
;;
esac
done
post_opts()
{
if [ -n "$_CUSTOM_UMASK" ]; then
umask "$_CUSTOM_UMASK"
fi
if [ $LISTENSTDIN -ne 1 ]; then
# brute check for umask 0022 if not using -b ($LISTENSTDIN -eq 1)
if [ $(umask) != "0022" ]; then
_default=yes
read -p "Would you like to temporarily set umask to 0022, to create files that are world readable [$_default]?" tmp_set_umask
if [ -z "$tmp_set_umask" ]; then
tmp_set_umask=$_default
fi
if [ "$tmp_set_umask" = "yes" ]; then
echo
umask 0022 && \
echo OK. To avoid this message in the future use -U, set umask in your login environment, or set the _CUSTOM_UMASK variable in your ./.veerc.
fi
fi
else
echo Warning: umask should be set to 0022. Your files may not be visible to others.
fi
if [ -e "$FORMAT_CUSTOM_DEFS" ]; then
. "$FORMAT_CUSTOM_DEFS"
fi
if [ -n "$SET_DEFAULT_FORMAT_FUNC" ]; then
"$FORMAT_DISPATCHER" "$SET_DEFAULT_FORMAT_FUNC" # default is set_format_func
fi
if [ "$_PURGELEVEL" -ge 1 ]; then
purge_entries "$_PURGELEVEL"
die_cleanly
fi
if [ "$_POST2EDIT" -ge 1 ]; then
LATEST=$(get_path2post "$_POST2EDIT")
$EDITOR "$DIR/$LATEST.$RAWEXT"
_POST2REFORMAT=$_POST2EDIT
fi
if [ "$_POST2REFORMAT" -ge 1 ]; then
LATEST=$(get_path2post "$_POST2REFORMAT")
reformat_singleton "$LATEST"
if [ 0 != $GOPHERMODE ]; then
default_update_gophermap
fi
die_cleanly
fi
# if "-R", or reformat all, is set
if [ "$_REFORMATALL" -eq 1 ]; then
# future may yield seperate "rebuild reindex" functionality
reformat_all
if [ 0 != $GOPHERMODE ]; then
default_update_gophermap
fi
die_cleanly
fi
# blocks vee -l (without the -r) from going on
if [ "$_POST2EDIT" -ge 1 ]; then
die_cleanly
fi
# Batch message creation: -m and stdin
# handles -m
if [ -n "$MESSAGE" ]; then
echo "$MESSAGE" >> "$DRAFT"
fi
if [ $LISTENSTDIN -eq 1 ]; then
OLDIFS=$IFS
IFS="" # ensures that leading spaces are retained
while read -r IN <&0 ; do # break after 1 sec of no stdin
echo "$IN" # echo's stdin back out so user can see
echo "$IN" >> "$DRAFT"
LISTENSTDIN=1
USE_EDITOR=0
done
fi
}
# generates INDEX file if none exists
default_setup_html()
{ if [ ! -e "$INDEX" ]; then
echo
echo "...creating $INDEX"
echo "my vee index" >> "$INDEX"
# header stuff
echo "" >> "$INDEX"
echo "" >> "$INDEX"
echo "" >> "$INDEX"
# footer stuff
echo "" >> "$INDEX"
echo "" >> "$INDEX"
echo "Powered by vee" >> "$INDEX"
echo "
" >> "$INDEX"
echo
fi
}
default_setup_gophermap()
{ if [ ! -e "$GOPHERMAP" ]; then
echo
echo "...generating updated $GOPHERMAP"
echo $GOPHERMAP_HEADER > $GOPHERMAP
echo >> $GOPHERMAP
echo >> $GOPHERMAP
fi
}
default_setup()
{
if [ 2 != $GOPHERMODE ]; then
default_setup_html
fi
if [ 0 != $GOPHERMODE ]; then
default_setup_gophermap
fi
}
use_editor()
{ if [ $USE_EDITOR -eq 1 ]; then
OK=0
$EDITOR "$DRAFT" && OK=1
if [ "$OK" -ne 1 ]; then
echo there has been a problem with your editor session
exit
fi
#else
#echo ...vi mode off
fi
}
# ask for title if not set with -t and not in batch mode
# if in batch mode with no -t set, use default title below
get_title()
{ if [ -z "$TITLE" ]; then
TITLE=$DEFAULT_TITLE
fi
}
read_config()
{ if [ -e ./.veerc ]; then
. ./.veerc
fi
}
# this case statement may be overkill if "sort -t';' -nr -k2,2" works across platforms
sort_index()
{ if [ -e "$INDEX" ]; then
case $ARCH in
linux) sort -t';' +0f -1 +1nr "$INDEX" > ".$INDEX.$$.sorted"
;;
freebsd) sort -t';' +0f -1 +1nr "$INDEX" > ".$INDEX.$$.sorted"
;;
netbsd) sort -t';' +0f -1 +1nr "$INDEX" > ".$INDEX.$$.sorted"
;;
macosx) # -k2,2 sorts by second field as delimted by -t';' - this may actually work
# for all platforms
sort -t';' -nr -k2,2 "$INDEX" > ".$INDEX.$$.sorted"
;;
*) sort -t';' +0f -1 +1nr "$INDEX" > ".$INDEX.$$.sorted"
;;
esac
mv ".$INDEX.$$.sorted" "$INDEX" # "rebuild $INDEX
fi
}
#-- main program body
mkdir -p "$DIR" || echo "found $DIR ..."
read_config # done after all options are read in, could look in -d before
# opts are processed though so opts could override defaults
# and config file .. yeah do that
post_opts # process options
"$CUSTOM_SETUP" # initialized indexes, can be defined in .veerc
get_title
use_editor
main()
{ if [ -e "$DRAFT" ]; then
RAWFILE="$SEC.$$.$TIME.$RAWEXT" # uses process id, $$, assuming there will
# not be duplicate process ids within 1 sec of each other
format_main "$SEC.$$.$TIME.$FORMAT" "$SEC.$$.$TIME.$GOPHER_FORMAT" "$RAWFILE"
"$UPDATE_INDEX" "$FINAL" "$gFINAL" "$RAW" "$gRAW" "$TITLE"
sort_index
die_cleanly
else
echo Error! "$DRAFT" not found
fi
}
main