notifirc 4.4KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177
  1. #!/bin/bash
  2. usage() {
  3. local self # our name
  4. self=$(basename "$0")
  5. echo "usage: $self [options] message" >&2
  6. echo "usage: $self [options] [-l max_lines] [-L max_width] -f message_file|-" >&2
  7. echo "options: [-h host] [-p port] [-n nick] [-c context] [-u user]" >&2
  8. exit 2
  9. }
  10. mkcommands() {
  11. local user="$1" # target user
  12. local nick="$2" # our nickname
  13. local message
  14. echo "NICK $nick"
  15. echo "USER $nick 8 * :notifirc bot"
  16. while read -r message;
  17. do
  18. echo "PRIVMSG $user :$message"
  19. done
  20. echo "QUIT"
  21. }
  22. mknick() {
  23. case "$context" in
  24. "") echo "$nick" ;;
  25. *) echo "$nick|$context" ;;
  26. esac
  27. }
  28. die() {
  29. local msg="fatal: $1" # message
  30. log "$msg"
  31. log "-----END *-----"
  32. echo "$msg" >&2
  33. exit 3
  34. }
  35. warn() {
  36. local msg="warning: $1" # full message
  37. echo "$msg" >&2
  38. log "$msg"
  39. }
  40. log_pipe() {
  41. local line # each line of input
  42. while IFS= read -r line;
  43. do
  44. log "$line"
  45. done
  46. }
  47. log() {
  48. echo "$1" >>"$logfile"
  49. }
  50. load_defaults() {
  51. local rcfile=$1 # RC file to load
  52. test -e "$rcfile" || return 0
  53. test -f "$rcfile" || {
  54. warn "defaults file is not a file: $rcfile"
  55. return 3
  56. }
  57. test -r "$rcfile" || {
  58. warn "defaults file not readable: $rcfile"
  59. return 3
  60. }
  61. bash -n "$rcfile" || {
  62. warn "syntax error in defaults file: $rcfile"
  63. return 3
  64. }
  65. . "$rcfile" || {
  66. warn "error in defaults file: $rcfile"
  67. return 3
  68. }
  69. }
  70. trim() {
  71. local limit_l=$1 # max. lines per message
  72. local limit_c=$2 # max. chars per line
  73. local lines_read=0 # how many lines we read
  74. local suff="" # suffix (ellipsis)
  75. while true;
  76. do
  77. test $lines_read -ge "$limit_l" && break
  78. IFS= read -r line || break
  79. (( lines_read++ ))
  80. test ${#line} -gt "$limit_c" && suff=…
  81. line=${line:0:$limit_c}$suff
  82. echo "$line"
  83. done
  84. }
  85. choose_logfile() {
  86. local path # path to log file
  87. {
  88. echo /var/log/notifirc.log
  89. echo "$HOME/.notifirc.log"
  90. echo /tmp/notifirc.log
  91. } \
  92. | while read -r path;
  93. do
  94. if test -w "$(dirname "$path")" \
  95. || test -w "$path";
  96. then
  97. echo "$path"
  98. break
  99. fi
  100. done
  101. }
  102. main() {
  103. local context # context tag for nickname
  104. local nick # bot's nickname
  105. local host # IRC server hostname
  106. local port # ... ^^ ... port
  107. local user # user to notify
  108. local message # message to send
  109. local logfile # logfile to use
  110. local msgfile # file to read message from
  111. local f_maxlines=3 # maximum number of lines per notification
  112. local f_maxwidth=80 # maximum characters per notification line
  113. logfile=$(choose_logfile)
  114. test -n "$logfile" || {
  115. echo "could not find writable logfile location" >&2
  116. echo "logging will be off!" >&2
  117. logfile=/dev/null
  118. }
  119. load_defaults /etc/notifirc.rc
  120. load_defaults "$HOME/.notifirc.rc"
  121. while true; do case $1 in
  122. -c) context=$2; shift 2 || usage ;;
  123. -f) msgfile=$2; shift 2 || usage ;;
  124. -h) host=$2; shift 2 || usage ;;
  125. -l) f_maxlines=$2; shift 2 || usage ;;
  126. -L) f_maxwidth=$2; shift 2 || usage ;;
  127. -n) nick=$2; shift 2 || usage ;;
  128. -p) port=$2; shift 2 || usage ;;
  129. -u) user=$2; shift 2 || usage ;;
  130. --) shift; break ;;
  131. -*) usage ;;
  132. *) break ;;
  133. esac done
  134. message="$*"
  135. test -n "$host" || usage
  136. test -n "$port" || usage
  137. test -n "$user" || usage
  138. test -n "$nick" || nick="notifirc"
  139. test -z "$message$msgfile" && usage
  140. log "-----BEGIN sending notification-----"
  141. log "host='$host'"
  142. log "port='$port'"
  143. log "nick='$nick'"
  144. log "context='$context'"
  145. log "user='$user'"
  146. log "msgfile='$msgfile'"
  147. log "f_maxlines='$f_maxlines'"
  148. log "f_maxwidth='$f_maxwidth'"
  149. log "message='$message'"
  150. {
  151. test -n "$message" && printf '%s\n' "$message"
  152. test -n "$msgfile" && grep . "$msgfile" | trim "$f_maxlines" "$f_maxwidth"
  153. } \
  154. | mkcommands "$user" "$(mknick)" \
  155. | nc "$host" "$port" 2>&1 \
  156. | log_pipe
  157. log "-----END sending notification-----"
  158. }
  159. main "$@"