#!/bin/bash # NAME,OUT都是用于zenity的选项参数 # DATE,TIME是保存所选择的日期和时间 # TITLE,CONTEXT是保存新建任务的标题和内容 # STIME="$DATE $TIME",由spl-time设置,将文件名分开两部分 NAME='--title=oalarm' OUT='--display=:0.0' DATE='' TIME='' TITLE='' CONTEXT='' STIME='' # 选择日期,在新建任务和任务延迟的时候使用,无参数 select-date() { DATE=`zenity --calendar $NAME --text="select date:" \ --date-format=%y%m%d $OUT` if [ -z $DATE ] ; then return 1 fi return 0 } # 选择时间,在新建任务和任务延迟的时候使用,无参数 select-time() { now=`date +%H` # 如果小时是0开头,则截掉0,以适应zenity的value参数 if [ $now -lt 10 ] ; then now=`echo $now | grep -o .$` fi hour=`zenity --scale $NAME $OUT --text="select hour:" \ --max-value=23 --min-value=0 --step=1 --value=$now` # 如果选择小时的时候,按下了取消 if [ -z $hour ] ; then return 1 fi # 如果选择的小时是一位数,补上0 if [ `expr length $hour` -lt 2 ] ; then hour="0$hour" fi # 分钟选择,解释同小时 now=`date +%M` if [ $now -lt 10 ] ; then now=`echo $now | grep -o .$` fi minute=`zenity --scale $NAME --text="select minute:" \ --max-value=59 --min-value=0 --step=1 --value=$now $OUT` if [ -z $minute ] ; then return 2 fi if [ `expr length $minute` -lt 2 ] ; then minute="0$minute" fi TIME=$hour$minute return 0 } # 输入任务标题,必须检查是否空值 enter-title() { TITLE=`zenity --entry $NAME --text='enter title' $OUT` if [ -z "$TITLE" ] ; then return 1 fi return 0 } # 输入任务内容,是否空值都接受 enter-context() { CONTEXT=`zenity --text-info $name --editable $OUT` return 0 } # 保存任务 save-task() { path="$HOME/.oalarm/wait/$DATE$TIME" task="$HOME/.oalarm/oalarm.bash --check $DATE$TIME" #echo `date +"%y-%m-%d %H:%M" --date="$DATE $TIME"` > $path # 如果同一时间有多于1个任务,那么任务以最后一个为准,即覆盖 # 之前没考虑到这个问题 exist=no if [ -f $path ] ; then exist=yes fi echo $TITLE > $path echo "$CONTEXT" >> $path if [ $exist == no ] ; then echo "$task" | at -t $DATE$TIME > /dev/null 2>&1 fi return 0 } # 延迟任务,在waiting列表选择delay或者任务到期后的延迟 # 一个参数,为任务文件的绝对路径 delay-task() { # 如果文件名大于现在的时间,则调用为waiting列表的delay操作 if [ "`basename $1`" -gt "`date +'%y%m%d%H%M'`" ] ; then from=wait else from=past fi select-date if [ $? -eq 1 ] ; then # 如果选择延迟日期的时候按下取消,则视来源操作 # 如果是到期延迟,则移走任务文件,并结束程序 if [ $from == past ] ; then mv $1 $HOME/.oalarm/past exit 1 fi return 0 fi select-time if [ $? -eq 1 ] ; then # 同上 if [ $from == past ] ; then mv $1 $HOME/.oalarm/past exit 1 fi return 0 fi # 有可能在选择延期时间的时候,任务到期删走了文件 if [ -f $1 ] ; then task="$HOME/.oalarm/oalarm.bash --check $DATE$TIME" echo "$task" | at -t $DATE$TIME > /dev/null 2>&1 mv $1 $HOME/.oalarm/wait/$DATE$TIME t=`date +"%y-%m-%d %H:%M" --date="$DATE $TIME"` zenity --info $NAME --text="OK!\nI will call you at:\n$t" $OUT fi return 0 } # 删掉任务,一个参数为任务文件绝对路径 delete-task() { if [ -f $1 ] ; then mv $1 $HOME/.oalarm/past fi return 0 } # 在waiting列表选择了一个任务之后,选择操作 # 一个参数为任务文件名,非绝对路径 # 被list-wait调用,list-wait返回后重启程序 show-task-action() { ret="`zenity --list --radiolist $NAME $OUT --text='select one operation'\ --column='' --column='operation' 'true' 'delay' '' 'delete'`" if [ "$ret" == "delay" ] ; then delay-task $HOME/.oalarm/wait/$1 elif [ "$ret" == "delete" ] ; then delete-task $HOME/.oalarm/wait/$1 fi return 0 } # 将文件名拆分成日期和时间两部分 # 一个参数,为文件名,非绝对路径 # 函数执行后会设置STIME spl-time() { STIME='' a=`echo $1 | grep -o ^......` b=`echo $1 | grep -o ....$` STIME="$a $b" } # 列出过期的任务,无参数 list-past() { # 如果该目录没有过期任务文件 if [ -z "`ls $HOME/.oalarm/past`" ] ; then zenity --info $NAME --text="no past tasks!" $OUT return 1 fi # 将文件名转换为可读时间格式,并抽取标题 arg="" for i in $HOME/.oalarm/past/* do spl-time "`basename $i`" t=`date +'%y-%m-%d %H:%M' --date="$STIME"` arg="$arg'$t' " t="`sed -n '1p' $i`" arg="$arg'$t' " done arg="zenity --list $NAME --text='past tasks:' $OUT \ --column='time' --column='title' $arg" # 显示列表 eval $arg return 0 } # 列出等待中的任务,无参数 list-wait() { # 如果改目录下没有任务文件 if [ -z "`ls $HOME/.oalarm/wait`" ] ; then zenity --info $NAME --text="no waiting tasks!" $OUT return 1 fi # 时间格式转换和抽取标题,显示列表选择按钮 arg="" for i in $HOME/.oalarm/wait/* do t="" arg="$arg'$t' " spl-time `basename $i` t=`date +'%y-%m-%d %H:%M' --date="$STIME"` arg="$arg'$t' " t="`sed -n '1p' $i`" arg="$arg'$t' " done arg="zenity --list --radiolist $NAME $OUT --text='waiting tasks:select one,\ then delay or delete it' --column='' --column='time' --column='title' \ $arg" # 显示列表,获取返回值 tim=`eval $arg` # 如果没有选择任务 if [ -z "$tim" ] ; then return 0 fi # 调用任务操作选择 tim=`date +%y%m%d%H%M --date="$tim"` show-task-action $tim return 0 } # 任务到期提醒,一个参数,为任务文件名 alert-timeout() { pathname="$HOME/.oalarm/wait/$1" # 判断声音文件是否存在 sound="$HOME/.oalarm/voice" pid="" if [ -f $sound ] ; then # 如果设置了音量,会改变所有mplayer进程的声音 #mplayer $sound -loop 0 -volume 80 > /dev/null 2>&1 & mplayer $sound -loop 0 > /dev/null 2>&1 & pid=$! fi spl-time $1 tmp=`date +'%y-%m-%d %H:%M' --date="$STIME"` # 读取任务文件显示 txt=`sed -n '1,$p' $pathname` zenity --question --title="$tmp" --text="$txt" $OUT ret=$? # 如果调用了mplayer if [ -n $pid ] ; then kill -s 15 $pid fi # 如果按下了取消,则视为延迟 if [ $ret == 1 ] ; then delay-task $pathname else mv $pathname "$HOME/.oalarm/past" fi return 0 } # 检查任务是否到期 # 无参数或者一个参数 # 无参数为登录图形界面时使用, # 检查全部等待中的任务 # 一个参数,为指定文件名,只检查该文件 check-timeout() { # 如果没有文件 if [ -z "`ls $HOME/.oalarm/wait`" ] ; then return 0 fi # 一个参数 if [ $# -ge 1 ] ; then for i in $HOME/.oalarm/wait/* do if [ "`basename $i`" -eq "$1" ] ; then alert-timeout $1 fi done # 无参数 else now=`date +%y%m%d%H%M` for i in $HOME/.oalarm/wait/* do if [ "`basename $i`" -le "$now" ] ; then alert-timeout `basename $i` fi done fi return 0 } show-about() { txt="\ oalarm 0.1.0\nBy Onway 2012-03-06\n\n\ debug yourself or report to:\n\ blog: www.cppblog.com/onway\n\ mail: aluohuai@126.com\n\n\ 如果本程序让你错过了和女友的约会,或者\ 把水烧干了,或者出现其他问题,本人概不负责。\n" echo -e $txt | zenity --text-info $NAME $OUT return 0 } show-howto() { txt="Sorry.\nI prefer 'about' rather than 'howto'" echo -e $txt | zenity --text-info $NAME $OUT return 0 } # 新建任务,无参数 # 如果必选内容为空,则重启程序 add-task() { enter-title if [ $? == 1 ] ; then $HOME/.oalarm/oalarm.bash --start & exit 1 fi enter-context select-date if [ $? == 1 ] ; then $HOME/.oalarm/oalarm.bash --start & exit 1 fi select-time if [ $? != 0 ] ; then $HOME/.oalarm/oalarm.bash --start & exit 1 fi save-task t=`date +"%y-%m-%d %H:%M" --date="$DATE $TIME"` zenity --info $NAME --text="OK!\nI will call you at:\n$t" $OUT return 0 } # 安装失败,必须是检查了gnome-session和zenity之后 inst-failure() { zenity --error $NAME --text="Oh...\ninstall failure\n$@" $OUT return 0 } inst-succeed() { txt="\ install successfully!\n\n\ note:\n\ 1 Now you may copy a sound file into $HOME/.oalarm directory,\ and rename it 'voice'.you should make a backup for that sound file,\ I will delete it when uninstall.\n\ 2 This bash script is no longer to use,you may delete it if you like\n\ 3 You can open oalarm from applications->Utility->oalarm\n\ 4 If you find bugs,report to aluohuai@126.com or debug yourself\n\n\ good luck!" echo -e $txt | zenity --text-info $NAME $OUT return 0 } # 安装 inst-oalarm() { # 必要命令的检查 if [ ! -f /usr/bin/at -o ! -f /usr/bin/zenity -o \ ! -f /usr/bin/mplayer ] ; then echo "at,zenity or mplayer not found" return 1 fi # 两个目录检查 if [ ! -d $HOME/.config/autostart ] ; then inst-failure "directory:$HOME/.config/autostart not exist" return 1 fi if [ ! -d $HOME/.local/share/applications ] ; then inst-failure "directory:$HOME/.local/share/applications not exist" return 1 fi path="$HOME/.config/autostart/oalarm.desktop" echo "[Desktop Entry]" > $path echo "Name=oalarm" >> $path echo "Exec=$HOME/.oalarm/oalarm.bash --check" >> $path echo "Type=Application" >> $path echo "Categories=Utility;" >> $path echo "X-GNOME-Autostart-enabled=true" >> $path path="$HOME/.local/share/applications/oalarm.desktop" echo "[Desktop Entry]" > $path echo "Name=oalarm" >> $path echo "Exec=$HOME/.oalarm/oalarm.bash --start" >> $path echo "Categories=Utility;" >> $path echo "Type=Application" >> $path mkdir $HOME/.oalarm mkdir $HOME/.oalarm/wait mkdir $HOME/.oalarm/past cp $0 $HOME/.oalarm/oalarm.bash voice=/usr/share/sounds/gnome/default/alerts/bark.ogg if [ ! -f $voice ] ; then zenity --warning --text="I cannot find the sound file:\n$voice" $OUT else cp /usr/share/sounds/gnome/default/alerts/bark.ogg $HOME/.oalarm/voice fi inst-succeed return 0 } #卸载 uninst-oalarm() { rm -f $HOME/.config/autostart/oalarm.desktop rm -f $HOME/.local/share/applications/oalarm.desktop rm -rf $HOME/.oalarm zenity --info --text="uninstall successfully!" $OUT return 0 } # 安装之后的主界面,所有安装条件都满足了 show-start() { ret=`zenity --list --radiolist $NAME $OUT --width=200 --height=270\ --column='' --column='operations' \ 'true' 'add' \ '' 'list-waiting' \ '' 'list-past' \ '' 'about' \ '' 'howto' \ '' 'uninstall'` case $ret in add) add-task $HOME/.oalarm/oalarm.bash --start & exit 0 ;; list-waiting) list-wait $HOME/.oalarm/oalarm.bash --start & exit 0 ;; list-past) list-past $HOME/.oalarm/oalarm.bash --start & exit 0 ;; about) show-about $HOME/.oalarm/oalarm.bash --start & exit 0 ;; howto) show-howto $HOME/.oalarm/oalarm.bash --start & exit 0 ;; uninstall) uninst-oalarm ;; # 没有任何选择,退出 *) exit 0 ;; esac } # 安装前的第一次显示 show-before-inst() { # 必须具有zenity才能显示界面 # 至于gnome-session在程序入口处检查了 if [ ! -f /usr/bin/zenity ] ; then echo "zenity not found" exit 1 fi ret=`zenity --list --radiolist $NAME $OUT \ --column='' --column='operations' \ 'true' 'install' \ '' 'about' \ '' 'howto'` case $ret in install) inst-oalarm exit 0 ;; about) show-about $0 & exit 0 ;; howto) show-howto $0 & exit 0 ;; *) exit 0 ;; esac } #main # 如果不存在gnome-session,则任务没有登录图形界面 tmp="`ps -eo ruid,comm | grep $UID.*gnome-session`" if [ -z "$tmp" ] ; then echo "must run in graphical user environment!" exit 1 fi # 安装前的启动 if [ $# -lt 1 ] ; then show-before-inst exit 0 fi # 安装后的启动,一个或两个参数 case $1 in --start) show-start ;; --check) if [ $# -ge 2 ] ; then check-timeout $2 else sleep 10 check-timeout fi ;; esac exit 0;