From fc72f21005a7443f1aa5f8b46efd63e345a33b6f Mon Sep 17 00:00:00 2001 From: Y Date: Sat, 8 Feb 2020 09:58:17 +0100 Subject: [PATCH] reorganize code before adding features --- epsiEDTtoICS.sh | 334 ++++++++++++++++++++++++++++++++++-------------- 1 file changed, 236 insertions(+), 98 deletions(-) diff --git a/epsiEDTtoICS.sh b/epsiEDTtoICS.sh index 60b0a2e..934331e 100755 --- a/epsiEDTtoICS.sh +++ b/epsiEDTtoICS.sh @@ -6,19 +6,218 @@ # This script only works when executed in the timezone of the calendar, and only if this timezone offset # is low enough to keep all events in the day they belong to in the web calendar (usually −6h ≤ TZ ≤ +8h). # -# from EPSI “edtmobilityeng” to ICS, for the current school year -# $1: EPSI Login (firstname.lastname) -# $2: output file (else standard output) +# From EPSI “edtmobilityeng” to ICS, for the current school year. Usage: +# +# epsiEDTtoICS.sh -u [ -c [ | - ] ] [ -j ] +# epsiEDTtoICS.sh -u [ -p [ | - ] [ -w ] ] [ -j ] +# : EPSI Login (firstname.lastname) +# : Location where the ICS file is created (-c) or patched (-p) +# : Number of weeks to update (including the current one), if -p is specified +# +# If no path is given, “-” is assumed, which is a placeholder for the standard output. +# If neither -c nor -p is given, “-c -” is assumed. +# If -p is used with “-” as a path, then only the updated weeks are sent to the standard output. +# If -p is given without -w, the default count of updated weeks is 5. +# If -j is used, logs are sent to systemd-journald instead of the standard error (needs systemd-cat). -if [ -n "$2" -a -d "$(dirname "$2")" -a -w "$(dirname "$2")" ]; then - exec >"$2" -fi +LANG8BIT=fr_FR@euro + +LOGIN= +PATCH= +OUTPUT=- +MAXOFFSET= +JOURNAL= +readonly -a LEVELS=( emerg alert crit err warning notice info debug ) + +while getopts u:c:p:w:j arg; do case "$arg" in +u) LOGIN="$OPTARG" ;; +c) OUTPUT="${OPTARG:--}"; PATCH= ;; +p) OUTPUT="${OPTARG:--}"; PATCH=true ;; +w) MAXOFFSET="${OPTARG//[^0-9]}" ;; +j) JOURNAL=true ;; +esac; done + +# $1: log level ∈ [0 … 7] +# $2: log text (“-” for STDIN) +function log() { + local l="$1" + shift + { + [ "$1" == - ] && cat || echo "$*" + } | { + [ -n "$JOURNAL" ] && systemd-cat -t epsi2ical -p ${LEVELS[$l]} || sed "s/^/[${LEVELS[$l]}] /" >&2 + } +} + +function check_parameters_and_set_defaults() { + if [ -z "$LOGIN" ]; then + log 2 'No user provided (option -u)' + exit 1 + fi + if [ "$OUTPUT" != - ] && ! [ \ + -n "$OUTPUT" -a \ + -d "$(dirname "$OUTPUT")" -a \ + -w "$(dirname "$OUTPUT")" -a \ + "$(basename "$OUTPUT")" != . -a \ + "$(basename "$OUTPUT")" != .. \ + ]; then + log 2 "The directory (option -c or -p) “$(dirname "$OUTPUT")” is not writeable, or the filename is invalid" + exit 2 + fi + if [ -n "$JOURNAL" ] && ! which systemd-cat >/dev/null; then + JOURNAL= + log 4 "Command “systemd-cat” not found" + fi + MAXOFFSET=$((${MAXOFFSET:-5}*7)) +} + +function fold_long_lines() { + env LANG="$LANG8BIT" sed -r 's/(.{73})(.)/\1\n \2/g' +} + +function lf_to_crlf() { + sed 's/$/\r/' +} + +function write_output() { + [ "$OUTPUT" == - ] && cat || { + cat >"${OUTPUT}.tmp" && mv -f "${OUTPUT}.tmp" "$OUTPUT" || { + log 3 "Failed to write to: $OUTPUT" + exit 20 + } + } +} + +# $1: string to encode +function urlencode() { + local saveLANG="$LANG" + export LANG="$LANG8BIT" + local index char + + for (( index=0; index<${#1}; index++ )); do + char=${1:$index:1} + case "$char" in + [-A-Za-z0-9._~]) printf '%s' "$char" ;; + *) printf '%%%02x' "'$char" ;; + esac + done + + export LANG="$saveLANG" +} + +# $1: date in format %m/%d/%Y +function fetch_html_week() { + local url="https://edtmobiliteng.wigorservices.net/WebPsDyn.aspx?action=posEDTBEECOME&serverid=C&Tel=$(urlencode "$LOGIN")&date=$1" + for ((i=1; i<5; i=i*2)); do + week="$(curl -s "$url")" && { echo "$week"; sleep 0.3s; return; } || log 7 "Request “${url}” failed" + sleep ${i}s + done + log 3 "Cannot get week calendar from upstream for Month/Day/Year: $1" + exit 10 +} + +# &0: html week (see: fetch_html_week) +# $1: offset (±) from today, to locate the week +# $2: timestamp for this particular ical generation +function html_week_to_ical_week() { + local offsetDayOfWeek=$(date +%u -d "${1}days") # ∈ [1=monday … 5=friday] + local mon=$(date +%Y%m%dT%z -d "$((${1}+1-$offsetDayOfWeek))days") + local tue=$(date +%Y%m%dT%z -d "$((${1}+2-$offsetDayOfWeek))days") + local wed=$(date +%Y%m%dT%z -d "$((${1}+3-$offsetDayOfWeek))days") + local thu=$(date +%Y%m%dT%z -d "$((${1}+4-$offsetDayOfWeek))days") + local fri=$(date +%Y%m%dT%z -d "$((${1}+5-$offsetDayOfWeek))days") + + tr '\r\n' ' ' \ + | sed -r 's/[[:blank:]]+/ /g' \ + | grep -oE '
]*class="Case" [^>]*style="[^"]*left *:[^"]*"|DIV [^>]*style="[^"]*left *:[^"]*" [^>]*class="Case"|]*class="TC(ase|Prof|hdeb|Salle)"([^<]|<[^/]|' \ + | awk -vmon=$mon -vtue=$tue -vwed=$wed -vthu=$thu -vfri=$fri -vid="epsi2ics/${LOGIN}@${HOSTNAME}" -vdtstamp=$2 -F$'\t' ' + function out() { + if (from!="" && to!="" && ase!="") printf( \ + "BEGIN:VEVENT\nUID:%s/%s/%s\nDTSTAMP:%s\nDTSTART:%s\nDTEND:%s\nSUMMARY:%s\nLOCATION:%s\nDESCRIPTION:🗣 %s 👥 %s\nEND:VEVENT\n", \ + from, id, prof, dtstamp, from, to, ase, where, prof, who) + from="" + to="" + ase="" + where="" + prof="" + who="" + day="" + zoneH=0 + zoneM=0 + } + function toZtime(localH, localM) { + localM-=zoneM + if (localM<0) { + localM+=60 + localH-=1 + } else if (localM>59) { + localM-=60 + localH+=1 + } + localH-=zoneH + return sprintf("%s%02d%02d00Z", day, localH, localM) + } + /class="Case"/ { + out() + pc=gensub(".*left *: *([0-9]+)[%.].*", "\\1", 1) + if (pc < 115) tmpd=mon + else if (pc < 135) tmpd=tue + else if (pc < 155) tmpd=wed + else if (pc < 175) tmpd=thu + else tmpd=fri + day=substr(tmpd, 1, 9) + zoneH=substr(tmpd, 10, 3)+0 + zoneM=(substr(tmpd, 10, 1) substr(tmpd, 13, 2))+0 + } + /class="TCase"/ { + ase=gensub(".*
(.*)(.*)
(.*) *0?([0-9]+):0?([0-9]+) *- *0?([0-9]+):0?([0-9]+) *(Salle:)?(.*)]*class="Case" [^>]*style="[^"]*left *:[^"]*"|DIV [^>]*style="[^"]*left *:[^"]*" [^>]*class="Case"|]*class="TC(ase|Prof|hdeb|Salle)"([^<]|<[^/]|' \ - | awk -vmon=$mon -vtue=$tue -vwed=$wed -vthu=$thu -vfri=$fri -vid="epsi2ics/${1}@${HOSTNAME}" -vdtstamp=$dtstamp -F$'\t' ' - function out() { - if (from!="" && to!="" && ase!="") printf( \ - "BEGIN:VEVENT\nUID:%s/%s/%s\nDTSTAMP:%s\nDTSTART:%s\nDTEND:%s\nSUMMARY:%s\nLOCATION:%s\nDESCRIPTION:🗣 %s 👥 %s\nEND:VEVENT\n", \ - from, id, prof, dtstamp, from, to, ase, where, prof, who) - from="" - to="" - ase="" - where="" - prof="" - who="" - day="" - zoneH=0 - zoneM=0 - } - function toZtime(localH, localM) { - localM-=zoneM - if (localM<0) { - localM+=60 - localH-=1 - } else if (localM>59) { - localM-=60 - localH+=1 - } - localH-=zoneH - return sprintf("%s%02d%02d00Z", day, localH, localM) - } - /class="Case"/ { - out() - pc=gensub(".*left *: *([0-9]+)[%.].*", "\\1", 1) - if (pc < 115) tmpd=mon - else if (pc < 135) tmpd=tue - else if (pc < 155) tmpd=wed - else if (pc < 175) tmpd=thu - else tmpd=fri - day=substr(tmpd, 1, 9) - zoneH=substr(tmpd, 10, 3)+0 - zoneM=(substr(tmpd, 10, 1) substr(tmpd, 13, 2))+0 - } - /class="TCase"/ { - ase=gensub(".*(.*)(.*)
(.*) *0?([0-9]+):0?([0-9]+) *- *0?([0-9]+):0?([0-9]+) *(Salle:)?(.*)