installed_progs.t: Python checks stdout too, 150 ok
[sunny256-utils.git] / telenorsms
blobcda9419469c5685ec425df55b328ea78b479359a
1 #!/usr/bin/env bash
3 # This program is free software; you can redistribute it and/or modify
4 # it under the terms of the GNU General Public License version 2, June 1991.
6 # This program is distributed in the hope that it will be useful,
7 # but WITHOUT ANY WARRANTY; without even the implied warranty of
8 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
9 # GNU General Public License for more details.
11 # You should have received a copy of the GNU General Public License
12 # along with this program. If not, see <https://www.gnu.org/licenses/gpl-2.0.html>,
13 # or in pdf format at <http://www.dhampir.no/stuff/private/gpl-2.0.pdf>
15 # Copyright 2012-2014 - Øyvind 'bolt' Hvidsten <bolt@dhampir.no>
17 # Description:
19 # telenorsms is a script that connects to the Norwegian cell operator Telenor and sends SMS messages
21 # It requires curl or wget, xxd, tr, cat and sed. "tempfile" is also recommended, though the script should manage
22 # to generate tempfiles itself.
24 # Your username (email) and password for your Telenor account need to be stored in ~/.telenorsms on two
25 # separate lines:
26 # ------------------------------------------
27 # username=me@provider.com
28 # password=awesome1
29 # grabber=/home/me/bin/grabber
30 # ------------------------------------------
31 # As shown above, it is also strongly recommended to indicate the path to the "grabber" library,
32 # which should be available where this script was downloaded from. Grabber does not need to be executable.
34 # You must have sent at least one message through the online interface, as it will ask you to verify your
35 # cell phone number by entering a code received by SMS, the first time you use it.
37 # telenorsms supports using numbers and names stored in your online address book in the SMS section of
38 # Telenor's pages. Messages can be sent to stored numbers using complete names or partial numbers.
40 # Examples:
41 # ./telenorsms Joe Hey man, how's it going?
42 # ./telenorsms +4711223344 This is a message.
43 # ./telenorsms 1122 This is a message.
45 # Comments welcome, improvements/patches twice as welcome.
48 # Version history:
50 # 2009-02-03: Initial version - ivc
51 # 2009-08-19: Support for local phonebook and various bug fixes - Håvard Gulldahl
52 # 2012-07-29: Rewrite for Bash 4 with support for new "MineSider" setup and online phonebook - Øyvind 'bolt' Hvidsten
53 # 2013-04-07: Minor style changes and comment cleanup - Øyvind 'bolt' Hvidsten
54 # 2013-04-20: Updated to comply with changes on Telenor's website
55 # 2013-06-15: Retry 3 times because of random cases of Ubuntu bug #965371 occuring on Telenor's server:
56 # GnuTLS: A TLS packet with unexpected length was received.
57 # Unable to establish SSL connection.
58 # 2014-04-04: Updated to comply with changes on Telenor's website
59 # 2014-08-26: Support for complaining about "technical error" on Telenor's website
60 # 2014-08-27: Support for the -d (dry run) option, testing most of the script without sending a message
61 # 2014-08-28: Support for the -a (force address book) option, used during debugging
62 # 2014-10-01: Spelling error fix
63 # 2014-10-18: Rewrote URL grabbing to use curl, as Telenor screwed up their TLS negotiation
64 # Use of wget can still be forced by adding [-w]
65 # Added several debugging features
66 # Note from debugging: URL encoding the "+" sign in "Logg+inn" breaks Telenor's form
67 # 2014-10-19: Pushed the HTTP grabbing functionality to a separate file in order to unify the methods used
68 # across several scripts I'm maintaining that all have similar functionality.
69 # Deeply sorry for any inconvenience caused.
70 # 2014-10-24: They changed the text "gjenstående SMS" to "gjenstående gratis SMS" for no reason. OK.
71 # 2015-01-04: Added detection of the SMS counter breaking - no longer exiting with non-zero unless debugging
72 # 2015-05-01: Minimal fix to support new link format for the login page
73 # 2015-05-16: Updated to comply with changes to grabber
74 # 2016-01-16: Updated to comply with changes to grabber (again)
78 _scriptname="telenorsms"
79 set -e
80 set -u
83 # Options
84 dryrun=false
85 DEBUG=false
86 forceaddressbook=false
87 GRABBER="curl"
88 OPTIND=1
89 while getopts ":adDw" opt; do
90 case "$opt" in
91 a) forceaddressbook=true ;;
92 d) dryrun=true ;;
93 D) DEBUG=true ;;
94 w) GRABBER="wget" ;;
95 [?])
96 echo "Unknown option -${OPTARG}" >&2
97 exit 1
99 :)
100 echo "Option -${OPTARG} requires an argument" >&2
101 exit 1
103 esac
104 done
105 shift $((OPTIND-1))
106 if [[ "${1:-}" = "--" ]]; then shift; fi
109 # Settings
110 config="$HOME/.${_scriptname}"
113 # Smart Sourcing
114 function ssource {
115 while (( $# )); do
116 if [[ -f "$1" ]] && [[ -r "$1" ]]; then
117 source "$1"
118 return
120 shift
121 done
122 return 1
126 # Grabber
127 grabber=$(grep -m 1 "^grabber=" $config 2>/dev/null | cut -d = -f 2)
128 if ! ssource /cathedral/src/lib/grabber "${grabber:-"$HOME/.grabber"}" "$(dirname "${BASH_SOURCE[0]}")/grabber"; then
129 echo "grabber library was not found" >&2
130 echo "Please download \"grabber\" from the same place you got this script," >&2
131 echo "Put it at $grabber or point at it in $config." >&2
132 exit 2
136 # Config
137 username=$(grep -m 1 "^username=" $config 2>/dev/null | cut -d = -f 2 | sf_urlencode)
138 password=$(grep -m 1 "^password=" $config 2>/dev/null | cut -d = -f 2 | sf_urlencode)
139 [[ -z "${1:-}" ]] || { recipient=$1 && shift; }
140 [[ -z "${1:-}" ]] || { message=$(sf_urlencode "$@"); }
143 # Sanity
144 if [[ -z "${username:-}" ]] || [[ -z "${password:-}" ]]; then
145 echo "Username or password unset. please put both in $config!" >&2
146 exit 1
148 if [[ -z "${recipient:-}" ]] || [[ -z "${message:-}" ]]; then
149 echo -e "Missing required arguments!\nUsage: $_scriptname [-d] <name|number> <text message>" >&2
150 exit 0
154 # Get cookie
155 grabber_task "Getting cookie"
156 grab "https://www.telenor.no/privat/minesider/logginnfelles.cms"
157 assert 'action="/privat/minesider/logginnfelles.cms'
160 # Login
161 grabber_task "Logging in"
162 up=false
163 while true; do
164 grab_data="usr_name=$username&usr_password=$password&lbAction=Logg+inn" \
165 grab_ref="https://www.telenor.no/privat/minesider/logginnfelles.cms" \
166 grab "https://www.telenor.no/privat/minesider/logginnfelles.cms"
167 if found 'SEND_SMS'; then
168 echo "OK"
169 break
170 elif found 'action="/privat/minesider/minprofil/oppdatereMinProfil.cms"'; then
171 if ! $up; then
172 echo "Profile update needed!"
173 grabber_task "Updating profile"
174 grab_data="confirmProfile=true&lbAction=Bekreft" \
175 grab_ref="https://www.telenor.no/privat/minesider/minprofil/oppdatereMinProfil.cms" \
176 grab "https://www.telenor.no/privat/minesider/minprofil/oppdatereMinProfil.cms"
177 up=true
178 else
179 grabber_fail
181 else
182 grabber_fail
184 done
187 # Mandatory SMS page get...
188 grabber_task "SMS page get"
189 grab_ref="https://www.telenor.no/privat/minesider/minside/minSidePage.cms" \
190 grab "https://www.telenor.no/privat/minesider/norm/win/sms/send.do"
191 if found '<h1>Teknisk feil</h1>'; then
192 grabber_fail '"Teknisk feil" - Have you activated SMS from Web yet?'
194 assert 'action="/norm/win/sms/send/process.do"'
197 # Get the address list
198 grabber_task "Getting address list"
199 grab_ref="https://www.telenor.no/privat/minesider/minside/minSidePage.cms" \
200 grab "https://telenormobil.no/norm/sms/async/addresslist.do"
201 grabber_ok
202 grabber_task "Parsing..."
203 names=()
204 numbers=()
206 while read -r line; do
207 # begin stupid address book format
208 [[ "$line" = *'<option value="'* ]] || continue
209 line=${line#*'<option value="'}
210 number=${line%%\"*}
211 line=${line#*'>'}
212 name=${line%(*}
213 # end stupid address book format
214 read -r number <<<"$number"
215 read -r name <<<"$name"
216 if [[ -n "$name" ]] && [[ -n "$number" ]]; then
217 names[i]=$name
218 numbers[i]=$number
219 (( ++i ))
221 done <"$f_stdout"
222 grabber_ok
223 echo "Read ${#names[@]:-} entries from address list."
226 # Translate recipients given as names to numbers in the address list
227 for (( i=0; i<${#names[@]:-}; i++ )); do
228 if [[ "${recipient,,}" = "${names[i],,}" ]]; then
229 recipient=${numbers[i]}
230 break
232 done
235 # Translate recipients given as partial numbers (or translated above) to full numbers and announce
236 match=false
237 for (( i=0; i<${#numbers[@]:-}; i++ )); do
239 [[ "$recipient" = *"${numbers[i]}"* ]] ||
240 [[ "${numbers[i]}" = *"$recipient"* ]]
241 then
242 recipient=${numbers[i]}
243 echo "Recipient recognized as ${names[i]} (${numbers[i]})"
244 match=true
245 break
247 done
248 if ! $match; then
249 echo "Recipient not in address book: $recipient"
250 if $forceaddressbook; then
251 grabber_fail "Address book broken?"
256 # Send SMS
257 if ! $dryrun; then
258 grabber_task "Sending SMS"
259 grab_head="Content-Type: application/x-www-form-urlencoded; charset=utf-8" \
260 grab_data="toAddress=$(sf_urlencode "$recipient")&message=$message&b_send=b_send" \
261 grab "https://telenormobil.no/norm/win/sms/send/process.do"
262 if found '<td>Sendt</td>'; then
263 echo "Sent!"
264 else
265 grabber_fail
270 # SMS left count
271 grabber_task "Getting number of free messages remaining"
272 grab_ref="https://www.telenor.no/privat/minesider/minside/minSidePage.cms" \
273 grab "https://telenormobil.no/norm/win/sms/send/popup/counter.do"
275 free=$(grep 'Antall gjenstående gratis SMS: ' "$f_stdout") &&
276 free=${free#*'Antall gjenstående gratis SMS: '} &&
277 free=${free%% *} &&
278 [[ -n "$free" ]]
279 then
280 echo "$free"
281 echo "Telenor updates the number of free messages remaining every 10 minutes."
282 elif
283 found "Klarte ikke å hente antall gjenstående gratis SMS"
284 then
285 echo "Telenor broke the SMS counter again."
286 ! $DEBUG || exit 1
287 else
288 grabber_fail