#!/bin/sh VERSION=0.1.1 if [ ! ${EDITOR} ]; then EDITOR="vim" fi MARGIN=72 FORMAT=html INDEX=index.html DIR=.bj DRAFT=${DIR}/.bj.tmp.$$ DATE=`date` YEAR=`date "+%Y"` TIME=`date "+%Y-%m-%dT%H:%M:%S"` SEC=`date "+%s"` TITLE= INDEXTITLE="The Italian BlogJob" DEFAULT_TITLE="Entry # ${SEC}"; HEADERTXT= # text or `cat some.header.txt` FOOTERTXT= #"Powered by blogjob - © MMVIII" TOP_TPL=./bj-top.tpl BOT_TPL=./bj-bottom.tpl PREFORMAT_FILTER=./bj-filter # the filter is assumed to be executable, else it is ignored USE_EDITOR=1 LISTENSTDIN=0 SORT_ALL="sort -t. +0f -1 +1nr" # sorts all in file listing SORT_NEWEST="sort -t. -nr" # sorts all new to old SORT_OLDEST="sort -t. -r" # sorts all old to new #PUBLISHED=`date "+%m/%d/%Y"` # date formated for index page entry PUBLISHED=$SEC OUTPUT_TOP=output_top OUTPUT_BOT=output_bottom # define custome formatting FORMAT_FUNC=format_with_par FORMAT_DISPATCHER=default_set_format_func FORMAT_CUSTOM_DISPATCHER=custom_set_format_func # define custom functions file; see example in bj/sample-custom-format/ FORMAT_CUSTOM_DEFS=./bj-custom.sh UPDATE_INDEX=default_update_index CUSTOM_SETUP=default_setup #ROOT="$HOME/public_html" FTPDEST="stixx" # # bj is a zero configuration, commandline blog tool that # requires NO installation other than dropping the bj # script into your ~/bin, or someother directory in your PATH # # bj accepts input when in batch mode (-b), so it is well # suited for use in batch situations, such as in a cronjob # # System utilities required via PATH: # cd, pwd, ls, sort, head, tail, cat, grep, groff, fold, expr (built in) disclaimer() { echo "Copyright (c) 2007 Joe Galaxy" echo "Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the \"Software\"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:" echo "The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software." echo "THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE." } # # bj - the minimal, zero configuration command line blog thingy # # Instructions: # 1. put in directory accessible via PATH # 2. go to a web visible directory and type 'bj' # 3. put in your title and write your post in vi # 4. tell your mom to visit: http://..../yourdir/bj.html # # Tips: # # 1 You can force the index to be index.html using "-I", or # you can specify the index with "-i somefile.html". But, # if you do this, you'll have to specify this for all other # commands, otherwise bj defaults to bj.html # # 2 bj respects your EDITOR environmental variable # # CREDITS # Francois Saint-Jacques (fsaintjacques@networkdump.com) supplied 2nd patch ever :) # efbeha (efbeha@gmail.com) - supplied first patch ever :) # Oliver @ forums.bsdnexus.com # arun @ chat.taucher.net #bsd # J65nko @ bsdforums.com # The people beyond http://www.0x743.com/vee # vee version 0.0.9zeta # Joe Galaxy (joegalaxy at gmail dot com) # ideas: default_set_format_func() { case "$1" in default) FORMAT_FUNC=format_with_groff ;; groff) FORMAT_FUNC=format_with_groff ;; fold) FORMAT_FUNC=format_with_fold ;; par) FORMAT_FUNC=format_with_par ;; none) FORMAT_FUNC=with_no_formatting ;; # if not a supplied format, see if it is in the custom format file, if it exists *) if [ -e "${FORMAT_CUSTOM_DEFS}" ]; then # call dispatch function that is defined in # the custom format file, pass on format nickname ${FORMAT_CUSTOM_DISPATCHER} "${1}" else echo "bad format type" die_cleanly fi esac echo using $FORMAT_FUNC } usage() { echo " " echo "bj - the Zero-conf, commandline blog tool thingy " echo " " echo "Version: ${VERSION} " echo " " echo "Usage: " echo " See below. " echo " " echo "Options: " echo " -b batch mode; used when piping in msg via stdin " echo " -B file define bottom template; default is ./bj-bottom.tpl " echo " -c [1-9\d*] specify the number of characters 'fold' allows per line " echo " this only applies when 'fold' (-f) is used " echo " -d 'publis_dir' specify the directory .bj is in - defaults to PWD " echo " -f 'format' use defined format instead of the default, groff;" echo " 'groff', 'fold', and 'none' are supported out of the box" echo " -F publish the given source directory to ftp destination " echo " Remember you must supply a valid directory name. " echo " -h prints this blurb " echo " -i 'custom.html' specify a custom index file over the default " echo " -I force index file to be \"index.html\" " echo " -l edit latest post's *.txt; used with '-r' publishes changes;" echo " calls reformat automatically; " echo " -L [1-9\d*] edit the Nth latest, relative to last post; lp starts at 1" echo " -m 'message ...' specify entry message at commandline and avoid vi " echo " -n lists all entries, newest first, then quits " echo " -o lists all entries, oldest first, then quits " echo " -p see what *raw files don't have an entry in the INDEX " echo " -P forever deletes all *raw and formatted files associated with" echo " posts that are listed with -p; " echo " -r [1-9\d*] reformats the Nth latest post " echo " -R reformats _all_ .bj/*.txt files; -c applies as well " echo " -s "summary" placed below title in INDEX " echo " -t 'title' specify title at commandline and avoid annoying default prompt" echo " -T file define top template; default is ./bj-top.tpl " echo " -v version and exit " echo " -x filter defines filter if not using default "./bj-pre"; filter " echo " must be executable, i.e., chmod 755 bj-pre " echo " " echo "Examples: " echo " " echo "%bj " 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 "%bj -t \"this is the title\" " echo " " echo " user will just be presented with a vi session; " echo " " echo "%cat text.txt | bj -b -t \"my title\" -m \"text to go before stdin\" " echo " " echo " publishes contents of text.txt with provided title; -m's msg will be " echo " shown above the cat'd text " echo " " echo "%bj -l # edit and reformat the latest post " echo "%bj -L 5 # allows one to edit and reformats the fifth latest post " echo "%bj -r 8 # reformats the 8th latest post " echo "%bj -R # reformats ALL posts that have *.txt files " echo " " echo "To delete a post forever: " echo "1) delete the entry in the INDEX " echo "2) purge the entry: " echo " bj -p # make sure it is the one you want to purge" echo " bj -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 "Notes: " 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. Patches are welcome; the goal is not more feature bloat, but a nicer " echo " way of dealing with standard in, etc would be welcomed. " echo " " echo `disclaimer` exit 1 } # formats post link on index page default_update_index() { echo "${PUBLISHED}: ${TITLE}" >> ${INDEX} if [ -n "${SUMMARY}" ]; then SEC=`expr $SEC - 1` echo "${SUMMARY}" >> ${INDEX} fi } output_top() { echo ${HEADERTXT} > ${FINAL} if [ -e "${TOP_TPL}" ]; then cat "${TOP_TPL}" >> ${FINAL} echo "
"   >> ${FINAL}
   else
  #   echo ""  >> ${FINAL}
  #   echo "" >> ${FINAL}
  #   echo "${TITLE} - ${DATE}"  >> ${FINAL}
  #   echo ""  >> ${FINAL}
  #   echo "
"   >> ${FINAL}
  #   echo "[index][raw][main]" >> ${FINAL}
echo " "  >> ${FINAL}
echo "${INDEXTITLE}" >> ${FINAL}
echo "" >> ${FINAL}
echo " " >> ${FINAL}
echo "
" >> ${FINAL} echo "
" >> ${FINAL} echo "
" >> ${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} echo "
" >> ${FINAL} echo "

__________________________
" >> ${FINAL} echo "
Powered by blogjob - © MMVIII Joe Galaxy
" >> ${FINAL} echo "" >> ${FINAL} fi } # begin formatting funcs format_with_groff() { #sed 1liner from http://sed.sourceforge.net/sed1line.txt groff -man -Tascii ${RAW} >> bla.txt sed -e '/^$/N;/\n$/D' -e 's/Posted:/\Posted:\<\/b\>/' -e 's/Title:/\Title:\<\/b\>/' bla.txt >> ${FINAL} rm bla.txt # groff -man -Tascii ${RAW} >> ${FINAL} } with_no_formatting() { cat ${RAW} >> ${FINAL} } format_with_fold() { if [ 0 -lt "${MARGIN}" ]; then fold -s -w ${MARGIN} ${RAW} >> ${FINAL} else with_no_formatting fi } format_with_par() { par 72 < ${RAW} | sed -e 's/Posted:/\Posted:\<\/b\>/' -e 's/Title:/\Title :\<\/b\>/' >> ${FINAL} } # # all filters must accepted STDIN and output via STDOUT # default arguments include: # preformat() { if [ -x "${PREFORMAT_FILTER}" ]; then cat "${DRAFT}" | "${PREFORMAT_FILTER}" "${FORMAT_FUNC}" > "${DRAFT}.tmp" mv -f "${DRAFT}.tmp" "${DRAFT}" fi } # postformat() #{ if [ -x "${POSTFORMAT_FILTER}" ]; then # cat "${FINAL}" | "${POSTFORMAT_FILTER}" > "${FINAL}.tmp" # mv -f "${FINAL}.tmp" "${FINAL}" # fi #} format_main() { FINAL=${DIR}/${1} FINALNAME=${1} RAW=${DIR}/${2} RAWNAME=${2} preformat # save raw form before formatting if it doesn't exist # which is the case when reformatting all if [ ! -e ${RAW} ]; then echo Posted: ${DATE} > ${RAW} # in RAW, line 1 is date echo >> ${RAW} echo Title: ${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 # not sure about this one yet } reformat_singleton() { if [ -e "${DIR}/${1}.txt" ]; then #echo "Reformatting message: \"${1}\"" cat "${DIR}/${1}.txt" > "${DRAFT}" format_main "${1}.${FORMAT}" "${1}.txt" fi } reformat_all() { FILES=`ls -c ${DIR}/*.txt | ${SORT_ALL}` for RAW in $FILES; do # From: Randall R Schulz FULLNAME="${RAW}" DIR="${FULLNAME%/*}" FILE="${FULLNAME##*/}" MAXBASE="${FILE%.*}" MINBASE="${FILE%%.*}" MAXSUF="${FILE#*.}" MINSUF="${FILE##*.}" reformat_singleton "${MAXBASE}" done } newest_first() { FILES=`ls -c ${DIR}/*.txt | ${SORT_NEWEST}` echo ${FILES} } list_newest_first() { FILES=`newest_first` COUNT=1 for FILE in ${FILES}; do FULLNAME="${FILE}" DIR="${FULLNAME%/*}" FILE="${FULLNAME##*/}" MAXBASE="${FILE%.*}" TITLE=`head -n 3 ${DIR}/${FILE} | tail -n 1` printf "%7d) " $COUNT echo ${MAXBASE} :: ${TITLE} COUNT=`expr $COUNT + 1` done } oldest_first() { FILES=`ls -c ${DIR}/*.txt | ${SORT_OLDEST}` echo ${FILES} } list_oldest_first() { FILES=`oldest_first` for FILE in ${FILES}; do FULLNAME="${FILE}" DIR="${FULLNAME%/*}" FILE="${FULLNAME##*/}" MAXBASE="${FILE%.*}" TITLE=`head -n 3 ${DIR}/${FILE} | tail -n 1` echo ${MAXBASE} :: ${TITLE} done } get_path2post() { FILES=`ls -c ${DIR}/*.txt | ${SORT_NEWEST}` GOAL=${1} COUNT=1 for FILE in ${FILES}; 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 FILES=`newest_first` for FILE in ${FILES}; 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[.txt,$FORMAT] (purged for realz)" rm -f $DIR/$MAXBASE* fi fi done echo removed $COUNT entrie\(s\)... } 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= publish() { lftp -d ${FTPDEST} -e "mirror -vnR ." ${FTPDEST} } # Style.css get_style() { if [ ! -f style.css ]; then cat << EOF >> style.css body { font-family: "Trebuchet MS", Arial, Helvetica, sans-serif; margin: 0% 20%; padding: 0; } pre { padding 0; background: #FFFFFF ; font-size: 12px; color: #4c4c4c; text-align: left; } em { font-family: "Trebuchet MS", Arial, Helvetica, sans-serif; font-size: 12px; color: #4c4c4c; text-align: center; } #container { margin: 0 auto; width: xxxpx; text-align: left; } #header { text-align: center; } #footer { text-align: center; } a { color: #7BAA0F; text-decoration: none; } a:hover { text-decoration: underline; } #logo { float: center; } #logo h1 { font-size: 36px; color: #7BAA0F; text-decoration: underline; } #menu { float: right; background: #fdffdf; } #menu ul { margin: 0; padding: 0 0 0 0; list-style: none; } #menu li { display: inline; } #menu a { display: block; float: left; margin-left: 5px; padding: 0 10px; text-decoration: none; font-size: 12px; color: #7BAA0F; } #menu a:hover { text-decoration: underline; } #menu .active a { } EOF fi } # get opts ! stdin append to anything passed in by -m while getopts 'f:m:t:T:c:d:i:IbB:hRr:lL:novx:X:Pps:F:' option; do case "$option" in i) INDEX="${OPTARG}" # specify INDEX to $OPTARG ;; I) INDEX="index.html" # force INDEX to index.html ;; d) if [ -d "${OPTARG}" ]; then cd "${OPTARG}" get_style else echo "${OPTARG}" is not a directory! die_cleanly fi echo `pwd` ;; r) POST2REFORMAT="${OPTARG}" ;; R) REFORMATALL=1 ;; b) LISTENSTDIN=1 USE_EDITOR=0 ;; B) BOT_TPL="${OPTARG}" ;; f) SET_DEFAULT_FORMAT_FUNC="${OPTARG}" ;; F) if [ -d "${OPTARG}" ]; then cd "${OPTARG}" publish die_cleanly else echo "${OPTARG}" is not a directory! die_cleanly fi ;; c) MARGIN=${OPTARG} # this option is about to be deprecated ;; 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 die_cleanly ;; x) PREFORMAT_FILTER="${OPTARG}" ;; ?) #usage | less die_cleanly ;; esac done post_opts() { if [ -e "${FORMAT_CUSTOM_DEFS}" ]; then . "${FORMAT_CUSTOM_DEFS}" fi if [ -n "${SET_DEFAULT_FORMAT_FUNC}" ]; then ${FORMAT_DISPATCHER} "${OPTARG}" # 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}.txt POST2REFORMAT=${POST2EDIT} fi if [ ${POST2REFORMAT} -ge 1 ]; then LATEST=`get_path2post ${POST2REFORMAT}` reformat_singleton "${LATEST}" die_cleanly fi # if "-R", or reformat all, is set if [ ${REFORMATALL} -eq 1 ]; then # future may yield seperate "rebuild reindex" functionality reformat_all die_cleanly fi # blocks bj -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 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() { mkdir -p ${DIR} || echo ${DIR} exists... if [ ! -e ${INDEX} ]; then echo echo "...creating ${INDEX}" echo "${INDEXTITLE}
" >> ${INDEX}
   # header stuff
    echo "" >> ${INDEX}
    echo "" >> ${INDEX}
    echo "" >> ${INDEX}
   # footer stuff
    echo "
" >> ${INDEX} echo "

__________________________
" >> ${INDEX} echo "
Powered by blogjob - © MMVIII Joe Galaxy
" >> ${INDEX} echo "" >> ${INDEX} echo fi } sort_index() { #echo sorting ${INDEX} ... #sort -t";" +0f -1 +1nr ${INDEX} > .${INDEX}.$$.sorted #${SORT_INDEX} sort -t';' +0f -1 +1nr ${INDEX} > .${INDEX}.$$.sorted #echo rebuilding ${INDEX} mv .${INDEX}.$$.sorted ${INDEX} # "rebuild ${INDEX} } 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 ./.bjrc ]; then . ./.bjrc fi } # -- main program body 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 $CUSTOM_SETUP # can be defined in .bjrc get_title use_editor if [ -e ${DRAFT} ]; then format_main "${SEC}.${TIME}.${FORMAT}" "${SEC}.${TIME}.txt" $UPDATE_INDEX sort_index die_cleanly else echo Error! ${DRAFT} not found fi