;;; alert.el --- Alerts for severe weather, new mail (biff), anything. ;; Time-stamp: <2005-08-31 17:25:44 deego> ;; Copyright (C) 2004 D. Goel ;; Emacs Lisp Archive entry ;; Filename: alert.el ;; Package: alert ;; Author: D. Goel ;; Keywords: ;; Version: ;; URL: http://gnufans.net/~deego ;; For latest version: (defconst alert-home-page "http://gnufans.net/~deego/emacspub/lisp-mine/alert/") ;; This file is NOT (yet) part of GNU Emacs. ;; This is free software; you can redistribute it and/or modify ;; it under the terms of the GNU General Public License as published by ;; the Free Software Foundation; either version 2, or (at your option) ;; any later version. ;; This is distributed in the hope that it will be useful, ;; but WITHOUT ANY WARRANTY; without even the implied warranty of ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ;; GNU General Public License for more details. ;; You should have received a copy of the GNU General Public License ;; along with GNU Emacs; see the file COPYING. If not, write to the ;; Free Software Foundation, Inc., 59 Temple Place - Suite 330, ;; Boston, MA 02111-1307, USA. ;; QUICKLIST OF DEBIAN PROGRAMS TO INSTALL: ;; kdeartwork* or kdeartwork-misc, rexima, aumix, alsamixer, esdplay ;; ... for the defaults to work. ;; Quick start: (defconst alert-quick-start "Help..." ) (defun alert-quick-start () "Provides electric help from variable `alert-quick-start'." (interactive) (with-electric-help '(lambda () (insert alert-quick-start) nil) "*doc*")) ;;; Introduction: ;; Stuff that gets posted to gnu.emacs.sources ;; as introduction (defconst alert-introduction "I wanted something to alert me when a SEVERE WEATHER ALERT occurred so I wrote this. I couldn't find any (free) alternatives for my area, but if you know any, please do let me know. :) This file really does nothing more than accept an arbitrary number of CHECKS/ACTIONS/INTERVALS, periodically calls a CHECK at its INTERVAL, if true, calls its ACTION. Two provided checks are a weather alert and a new-mail biff. For new mail, it makes a sound and displays a message. For severe weather, it also emails you an alert. Everything is customizable. You can add your own CHECKS/ACTIONS/INTERVALS. The variable you care about is `alert-alist' where you specify the CHECKS/ACTIONS/INTERVALS. In general, you can specify and program your own checks/actions in `alert-list'. Both the default provided actions for weather and biff are quick hacks, which liberally use shell-commands and assume that you have programs like frm (mailutils) and w3m installed. OTOH, on the good side, you can customize the names of those programs, etc. As far as biff is concerned, you probably want to investigate a good professional program instead. check out biff.el, vm-biff.el and check-mail.el. see also http://www.emacswiki.org/cgi-bin/wiki.pl?EmacsBiff FOR BIFF: If you do not want to have to customize this package, simply ensure that debian's mailutils is installed on your machine. Other emacs weather utilities: * The wx.el weather package posted here a day earlier. * http://www.emacswiki.org/cgi-bin/wiki.pl?EmacsWeather " ) ;;;###autoload (defun alert-introduction () "Provides electric help from variable `alert-introduction'." (interactive) (with-electric-help '(lambda () (insert alert-introduction) nil) "*doc*")) ;;; Commentary: (defconst alert-commentary "Help..." ) (defun alert-commentary () "Provides electric help from variable `alert-commentary'." (interactive) (with-electric-help '(lambda () (insert alert-commentary) nil) "*doc*")) ;;; History: ;;; Bugs: ;;; New features: (defconst alert-new-features "Help..." ) (defun alert-new-features () "Provides electric help from variable `alert-new-features'." (interactive) (with-electric-help '(lambda () (insert alert-new-features) nil) "*doc*")) ;;; TO DO: (defconst alert-todo "Help..." ) (defun alert-todo () "Provides electric help from variable `alert-todo'." (interactive) (with-electric-help '(lambda () (insert alert-todo) nil) "*doc*")) (defconst alert-version "0.1dev") (defun alert-version (&optional arg) "Display alert's version string. With prefix ARG, insert version string into current buffer at point." (interactive "P") (if arg (insert (message "alert version %s" alert-version)) (message "alert version %s" alert-version))) ;;========================================== ;;; Requires: (eval-when-compile (require 'cl)) ;;; Code: (defgroup alert nil "The group alert." :group 'applications) (defcustom alert-before-load-hook nil "Hook to run before loading alert." :group 'alert) (defcustom alert-after-load-hook nil "Hook to run after loading alert." :group 'alert) (run-hooks 'alert-before-load-hook) (defcustom alert-verbosity 0 "How verbose to be. Once you are experienced with this lib, 0 is the recommended value. Values between -90 to +90 are \"sane\". The rest are for debugging." :type 'integer :group 'alert) (defcustom alert-interactivity 0 "How interactive to be. Once you are experienced with this lib, 0 is the recommended value. Values between -90 and +90 are \"sane\". The rest are for debugging." :type 'integer :group 'alert) (defcustom alert-y-or-n-p-function 'alert-y-or-n-p "Function to use for interactivity-dependent `y-or-n-p'. Format same as that of `alert-y-or-n-p'." :type 'function :group 'alert) (defcustom alert-n-or-y-p-function 'alert-y-or-n-p "Function to use for interactivity-dependent `n-or-y-p'. Format same as that of `alert-n-or-y-p'." :type 'function :group 'alert) (defun alert-message (points &rest args) "Signal message, depending on POINTS andalert-verbosity. ARGS are passed to `message'." (unless (minusp (+ points alert-verbosity)) (apply #'message args))) (defun alert-y-or-n-p (add prompt) "Query or assume t, based on `alert-interactivity'. ADD is added to `alert-interactivity' to decide whether to query using PROMPT, or just return t." (if (minusp (+ add alert-interactivity)) t (funcall 'y-or-n-p prompt))) (defun alert-n-or-y-p (add prompt) "Query or assume t, based on `alert-interactivity'. ADD is added to `alert-interactivity' to decide whether to query using PROMPT, or just return t." (if (minusp (+ add alert-interactivity)) nil (funcall 'y-or-n-p prompt))) ;;; Real Code: ;;; Real Code: (defcustom alert-sound-style 'card " Allowed values are 'card, 'speaker and nil. Any other value is taken to be same as card. When 'card, we assume you have a sound card and play music. When 'speaker, we assume you only have a speaker, and beep the computer. When 'none or nil, wants you mean want no sound." ) (defcustom alert-weather-sound-style alert-sound-style "") (defcustom alert-biff-sound-style alert-sound-style "") (defcustom alert-play-command "esdplay " "") (defcustom alert-play-command-post "" "") (defvar alert-timers nil "List of timers. " ) (defvar alert-biff-size nil "internal") (defvar alert-biff-frm "" "internal") (defcustom alert-idle-timer-p nil "Whether to use idle timers instead of timers. ") (when alert-idle-timer-p (require 'timerfunctions)) (defcustom alert-list '((240 alert-biff-check alert-biff-action) (3600 alert-weather-check alert-weather-action 3600)) "Self-explanatory. These are the alerts. Define any more functions you like and add them here. Each member of the alert-list is of the form (INTERVAL CHECK-FUNCTION ACTION-FUNCTION &optional INITIAL-INTERVAL). Each action function should take an argument. When the argument is nil, it shouldn't do anything. For non-nil, it should do its ACTION (possibly based on the value of the argument). Thus, the result of the check function will be passed to the ACTION-FUNCTION for action based upon the result. ") (defun alert-call-timer (interval-initial interval functionq) "functionq means quoted function." (cond (alert-idle-timer-p (add-to-list 'alert-timers (tf-run-with-idle-timer interval-initial t interval t nil functionq))) (t (add-to-list 'alert-timers (run-with-timer interval-initial interval functionq))))) ;;;###autoload (defun alert-start () (interactive) (alert-stop) (mapc (lambda (arg) (let* (;; use eval so that one can use general arguments instead ;; of numbers. int == interval, inti == interval initial (int (eval (first arg))) (inti (eval (fourth arg))) (check (second arg)) (action (third arg)) (functionq `(lambda () (funcall ',action (,check))))) (alert-call-timer (or inti int) int functionq))) alert-list) (message "Alerts started ")) ;;; this for debugging (defun alert-once (n) "Perform the ARGth alert check and action." (interactive "p") (let* ((arg (nth n alert-list)) (int (eval (first arg))) (inti (eval (fourth arg))) (check (second arg)) (action (third arg))) (funcall action (funcall check)))) ;;;###autoload (defalias 'alert 'alert-start) (defun alert-stop () (interactive) (mapcar (lambda (arg) (when (timerp arg) (cancel-timer arg))) alert-timers) (setq alert-timers nil)) (defcustom alert-mail-to user-mail-address "This is where weather alerts are emailed.") ;;;==================================================== ;;; GENERAL UTILITIES ;;;==================================================== ;;;###autoload (defun alert-mail (to text &optional subject) "Copied from utils.el" (compose-mail (format "%s" to) (or subject "")) (insert text) (call-interactively (get mail-user-agent 'sendfunc))) ;;;==================================================== ;;; THE BIFF FUNCTIONS ;;;==================================================== (defun alert-biff-reset () (interactive) (setq alert-biff-size nil)) ;;;###autoload (defun alert-biff-file-size (file) (and (file-exists-p file) (nth 7 (file-attributes file)))) (defcustom alert-biff-frm-command "frm" "") (defun alert-biff-frm () (shell-command-to-string alert-biff-frm-command)) (defun alert-biff-new-mail-p-frm () (let* ((frm (funcall 'alert-biff-frm)) (diffp (and ;; do not want if empty mailbox.. (not (equal "" frm)) (not (equal frm alert-biff-frm))))) (setq alert-biff-frm frm) diffp)) ;;(defalias 'alert-biff-check 'alert-biff-new-mail-p-frm) (defun alert-biff-check () "This one will be used in timer. " (and ;; don't bother us if the user is using the emacs! (sit-for 2) (alert-biff-new-mail-p-frm))) ;;;###autoload (defun alert-biff-new-mail-p-mailbox-size () (let* ((newsize (alert-biff-file-size (funcall alert-biff-mail-file-name-function))) (diffp (cond ((and (numberp newsize) (numberp alert-biff-size)) (> newsize alert-biff-size)) (t (not (equal alert-biff-size newsize)))))) (setq alert-biff-size newsize) diffp)) (defcustom alert-biff-mail-file-name-function 'alert-biff-mail-file-name "") (defun alert-biff-mail-file-name () "" (concat "/var/mail/" (user-login-name))) (defcustom alert-biff-once-action-function 'alert-biff-once-action "") (defcustom alert-biff-sound-file "/usr/share/sounds/KDE_Logout.wav" "Other suggestions: /usr/share/sounds/KDE_Logout_new.wav Debian Packages: gnome-audio /usr/share/sounds/phone.wav kdeartwork-misc /usr/share/sounds/KDE_Startup_new.wav /usr/share/sounds/KDE_Logout_new.wav op-sounds gabber: /usr/share/sounds/gabber/gabber_subrequest.wav /usr/share/sounds/gabber/gabber_connected.wav " ) (defcustom alert-biff-sound-make-function 'alert-biff-sound-make "") (defun alert-biff-sound-make () (interactive) (progn (ding t) (sit-for 0.2) (ding t) (sit-for 0.1) (ding t) (sit-for 0.3) (ding t) (sit-for 0.2) (ding t) (sit-for 0.1) (ding t) )) (defun alert-biff-once-action (&optional action) (interactive "P") (cond ((null action) nil) ((member alert-biff-sound-style (list 'speaker)) (funcall alert-biff-sound-make-function)) ((member alert-biff-sound-style (list nil 'none)) nil) (t ;;(beep t) ;;(beep t) (shell-command (concat alert-play-command alert-biff-sound-file alert-play-command-post)) (beep t) (beep t) (beep t)) ) (message "%s" (shell-command-to-string ;;"frm | tail -5" "frm" ))) (defalias 'alert-biff-action 'alert-biff-once-action) ;;;==================================================== ;;; THE WEATHER FUNCTIONS ;;;==================================================== (defcustom alert-weather-url "http://weather.yahoo.com/forecast/USGA0230_f.html" "") (defcustom alert-weather-severe-regexp "severe weather\\(.\\|\n\\)*severe weather" "") (defcustom alert-weather-not-severe-regexp "no warnings" "") (defcustom alert-weather-check-command '(shell-command-to-string (concat "w3m -dump " ;;;(format "%S" alert-weather-url))) (format "%S" alert-weather-url-warning))) "") (defun alert-weather-check () (interactive) ;;(string-match ;;alert-weather-severe-regexp ;;(eval alert-weather-check-command)) (and ;; don't bother us if user is using emacs! (sit-for 2) (not (string-match alert-weather-not-severe-regexp (eval alert-weather-check-command))))) (defcustom alert-weather-url-warning "http://weather.yahoo.com/storm/USGA0230.html" "") (defvar alert-weather-result "internal") (defvar alert-weather-buffer "*Alert-weather*") (defcustom alert-weather-action-find-alarm-regexp "\\(advisor\\|warning\\b\\|freezing\\|watch\\b\\)" "") (defun alert-weather-action-find-alarm () (goto-char (point-min)) (if (search-forward-regexp alert-weather-action-find-alarm-regexp nil t) (buffer-substring-no-properties (line-beginning-position) (line-end-position)) "")) (defun alert-weather-action (&optional action) (interactive "P") (cond ((null action) nil) (t (setq alert-weather-result (shell-command-to-string (concat "w3m -dump " (format "%S" alert-weather-url-warning)))) (alert-weather-sound) (switch-to-buffer alert-weather-buffer) (erase-buffer) (insert alert-weather-result "\n") (delete-other-windows) (let* ((alarmstring (alert-weather-action-find-alarm)) (alarmsubject (concat "SEVERE WEATHER: " alarmstring))) (alert-mail alert-mail-to alert-weather-result alarmsubject) (message "%s" alarmsubject)) (switch-to-buffer alert-weather-buffer) (delete-other-windows)))) (defcustom alert-weather-volume-command "rexima vol 70" ;;"aumix -v+10" "Unless nil, the default weather-sound calls aumix to try to set this volume." ) (defun alert-weather-sound () (interactive) (cond ((member alert-weather-sound-style (list 'speaker)) (funcall alert-weather-sound-make-function)) ((member alert-weather-sound-style (list 'none nil)) nil) (t (beep t) (beep t) (when alert-weather-volume-command (shell-command alert-weather-volume-command)) (shell-command (concat alert-play-command alert-weather-sound-file alert-play-command-post)) (beep t) (beep t) (beep t)))) (defcustom alert-weather-sound-make-function 'alert-weather-sound-make "") (defcustom alert-weather-sound-file "/usr/share/sounds/phone.wav" "") (defun alert-weather-sound-make () (interactive) (progn (ding t) (ding t) (ding t) (dotimes (i 60) (sit-for 0.3) (ding t) (ding t) (ding t) ))) (provide 'alert) (run-hooks 'alert-after-load-hook) ;;; alert.el ends here