#!/bin/bash # getSo.sh - Sample HTTPS client w/Connection_Keep-Alive, using OpenSSL # (C) 2020 - F-Hauri.ch # Licensed by GNU GENERAL PUBLIC LICENSE Version 3 shopt -s extglob notifySong=/usr/share/sounds/sound-icons/cockchafer-gentleman-1.wav notifyIcon=~/.icons/iconSO.png SRCDIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" # To create 'socred.gpg':$ gpg -aer $USER <<<"mailUser@mailServer:soPassword" >socred.gpg IFS=: read -r user pass < <(gpg -qd <"$SRCDIR/socred.gpg") URL='https://stackoverflow.com/' IFS=/ read -r _ _ hst _ <<<"$URL" OpenSSLcmd=(openssl s_client -quiet -connect "$hst":443 -ign_eof) check4Proxy() { local _c4P_ANS { echo -e "HEAD http://localhost/ HTTP/1.0\r\n\r" read -rt 2 _c4P_ANS && [ "$_c4P_ANS" ] && [ -z "${_c4P_ANS%%HTTP/*}" ] } 2>/dev/null >/dev/tcp/$proxy/$port <&1 } if [ -v https_proxy ] ;then IFS=:/ read -r _ _ _ proxy port _ <<<"$https_proxy" if [ "$proxy" ] && ((port)) && check4Proxy ;then OpenSSLcmd+=(-proxy $proxy:$port) fi fi openConnection() { ((osslpid)) && [ -d /proc/$osslpid ] && readlink /proc/$osslpid/exe | grep -q openssl && kill $osslpid ((wwwE)) && exec {wwwE}<&- ((wwwI)) && exec {wwwI}>&- ((wwwO)) && exec {wwwO}<&- exec {wwwE}<> <(: - O) exec {wwwI}<> <(: - b) exec {wwwO}< <( exec stdbuf -o0 ${OpenSSLcmd[@]} <&$wwwI 2>&$wwwE ) osslpid=$! } doReq() { # doReq [GET|POST] [data to post] hthead=() htbody=('') hterr=() local target=$1 method=${2:-GET} head=true line cookies ccnt=0 printf >&$wwwI '%s\r\n' \ "$method $target HTTP/1.1" \ "Host: $hst" \ "User-Agent: aobs/0.01" \ "Connection: keep-alive" \ "Accept: */*" [ "$cookie" ] && printf >&$wwwI '%s' "$cookie" if [ "$method" = "POST" ];then printf >&$wwwI '%s\r\n%s\r\n\r\n%s' \ "Content-Length: ${#3}" \ 'Content-Type: application/x-www-form-urlencoded' \ \ "$3" else printf >&$wwwI '\r\n' fi read -t 10 -ru $wwwO line htstatus=${line%$'\r'} hthead=("$htstatus") while IFS= read -t .3 -ru $wwwO line;do [ "${line%$'\r'}" ] || head=false; if $head ;then hthead+=("${line%$'\r'}"); case "$line" in [sS]et-[cC]ookie:* ) line=${line#*: } line="${line%%;*}" cookies+=("$line");; * ) ;; esac else if [[ "${line%$'\r'}" =~ ^[0-9a-f]{1,6}$ ]] ;then # printf " -- %04X -> %6d (%6d)\n" 0x${line%$'\r'}{,} $ccnt ccnt=0 else if ((ccnt==0)) ;then htbody[-1]+="${line%$'\r'}" ccnt=1 # ((ccnt+=${#line}+1)) else htbody+=("${line%$'\r'}") # ((ccnt+=${#line}+1)) fi fi fi done if read -t 0 -ru $wwwE;then while read -t .1 -ru $wwwE line;do hterr+=("${line%$'\r'}") case $line in depth* | verify* ) ;; * ) echo "ERR: $line" ;; esac done fi [ ! -v "cookie" ] && [ "${cookies[0]}" ] && printf -v cookie 'Cookie: %s\r\n' "${cookies[@]}" } trUnicode() { # trUnicode local lhs rhs chr; local -n string=$1; while [ "$string" ] && [ -z "${string//*&#*([0-9]);*}" ]; do rhs="${string#*&#*([0-9]);}" lhs="${string%&#*([0-9]);$rhs}" chr="${string%;$rhs}" printf -v chr '\\U%X' "${chr#$lhs&#}" printf -v chr %b "$chr" string="$lhs $chr $rhs" done } iSleep() { # interruptible sleep d: dump, r: retry and q: quit. if read -sn 1 -rt "$1" userKey ;then case $userKey in d ) declare -p hthead htbody >/tmp/getSo.dump.$$;echo DUMP;echo ;; r ) return 1 ;; q ) return 2 ;; esac fi : } printf -v bullet '\U25cf' openConnection doReq /users/login POST "email=$user&password=$pass" declare -p hthead htbody >/tmp/getSo.dump_init.$$ [[ ${htbody[*]//password is incorrect} == "${htbody[*]}" ]] && while true;do doReq / out='' badges='' repscor='' inbox='' datacnt=0 for ((i=${#htbody[@]};i--;)) ;do line="${htbody[i]}" case $line in *reputation-score* ) ;; *badge1* ) startdiv=$i enddiv=$i while [ "${htbody[startdiv]//*
*}" ];do ((enddiv++));done line="" for ((i=startdiv;i<=enddiv+1;i++)) ;do line+="${htbody[i]//*([$'\n\r\t']}" done line=${line//>+([0-9])<} line=${line//<+([^>])>} line=${line//bronze/ bronze} line=${line//silver/ silver} line=${line//gold/ gold} line=${line//+([ ])/ } trUnicode line badges="${line// badges}" if [[ -z "${badges//*reputation*}" ]] ;then repscor=${badges%% reputation*} repscor=${repscor#*, } badges=${badges##*reputation} ((++datacnt==3))&&break fi ((++datacnt==3))&&break ((i=startdiv-1)) ;; *"title=\"your reputation:"* ) line=${line#*reputation:}"${htbody[i+1]}" repscor="${line%%\"*}" ((++datacnt==3))&&break ;; *'label="Inbox'* ) line+="${htbody[i+1]//*([$'\n\r\t']}" line=${line#*unread-count=\"} line="${line%%\"*}" case $line in '' | *[!0-9]* ) ;; * ) inbox=$line; ((++datacnt==3)) && break ;; esac esac done if [ "$badges" ] && [ "$repscor" ] && [ "$inbox" ] ;then out="MBx: $inbox Rep: ${repscor// } $badges" if [ "$out" = "$last" ] ;then printf '\e[A' else notify-send -i "$notifyIcon" -t 120000 -h byte:urgency:$((inbox>0?1:0)) \ -h "string:sound-file:$notifySong" 'Stack Overflow' "$out" fi printf -v lne "%(%d %b %T)T %s" -1 "${out}" last="$out" printf '\r%s\e[K\e];%s\007\n' "$lne" "${lne//$bullet/*}" tosleep=$(( 1120000000 - ( ${EPOCHREALTIME/.} % 120000000 ) )) printf -v tosleep %.6f ${tosleep:1:-6}.${tosleep: -6} iSleep "$tosleep" ; (( $? & 2 )) && break penalty=0 else if (( penalty++ > 8 )) ;then for (( penalty=60;--penalty;)) ;do printf '\e[1m%(%d %b %T)T: No connection...\e[0m Sleep: (%d)\e[K\r' \ -1 $penalty iSleep 1 || break $? done openConnection penalty=0 else printf '%(%d %b %T)T: Bad data read... Retry: (%d)\e[K\r' -1 $penalty iSleep 2 ; (( $? & 2 )) && break fi unset cookie doReq /users/login POST "email=$user&password=$pass" fi true done || echo "Wrong password." ((osslpid)) && [ -d /proc/$osslpid ] && readlink /proc/$osslpid/exe | grep -q openssl && kill $osslpid