-
Notifications
You must be signed in to change notification settings - Fork 0
/
cashtrack
375 lines (267 loc) · 13.6 KB
/
cashtrack
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
#!/bin/bash
# This program 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 3 of the License, or
# (at your option) any later version.
# This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
#---------------------------------------------------------------------------
# Requirements:
# signal-cli: https://github.com/AsamK/signal-cli
# sqlite3: $ apt install sqlite3
# dedicated VM highly recommended :)
# Make sure you have started the daemon in your start up scripts using
# declare -r USERNAME="+xxxxxxxxxxx"
# signal-cli -u "$USERNAME" daemon &> "/dev/null" &
#---------------------------------------------------------------------------
# Declare user defined variables
# Signal user names
perA="EXAMPLE USER A"
perB="EXAMPLE USER B"
# Signal user phone numbers
Aphone=15555555555
Bphone=15555555555
# flag to turn off emoji numbers
emoji=True
#---------------------------------------------------------------------------
s="int64"
ms="string "
me="array ["
c="string \"contentType\""
f="string \"remoteId\""
v="variant"
l="string \"expiresInSeconds\""
# dbus interface and member
intfc="org.asamk.Signal"
mmbr="MessageReceivedV2"
# check if signalbot database exists; if it doesnt
# use && to create a new database table and append initilization line
[ ! -f signalbot.db ] && {
# create a table with the specified columns
sqlite3 signalbot.db "CREATE TABLE IF NOT EXISTS cashtrack
(date TEXT, amount REAL, type TEXT, perA REAL, balanceA REAL, perB REAL, balanceB REAL, note TEXT);" ;
# insert a row with the initial values
sqlite3 signalbot.db "INSERT INTO cashtrack (date, amount, type, perA, balanceA, perB, balanceB, note)
VALUES ('1/1/1999', '0.00', 'send', '$perA', '0.00', '$perB', '0.00', 'new db');" ;
}
errorOut() {
printf "%s\n" "$*" 1>&2
[[ $1 == True ]] && printf "%s %s" "$2" "$3"
}
cashtrack() {
cashTrackSend() { # Define a function to send a message using signal-cli
# Use the first argument as the recipient and the second argument as the message
signal-cli --dbus send -m "$2" "$1" &> /dev/null
# Print date + "MESSAGE OUT" to standard output
printf "%s --- MESSAGE OUT --- " $td
}
emo() { # Define a function that picks a random emoji to use within the response message to user
# Declare an array of emojis
emojiarr=("💵" "💰" "💸" "🤑" "🤩" "👽" "🥰" "😮")
# Print the element at a random index of the array
echo "${emojiarr[$(( RANDOM % ${#emojiarr[@]} ))]}"
}
emoNum() { # Define a function to convert a number to emoji format
# Assign the first argument to a local variable num
# Initialize an a variable for an empty string for the local result
# Initialize a variable for the digit local digit
local num=$1 ; local result="" ; local digit
# Check if the input is negative
if (( $(echo "$num < 0" | bc -l) )); then
# multiply $num by by -1 if it is negative to convert it into a positive
num=$(echo "$num * -1" | bc -l)
# then append '(-) ' to $result
result="(-) "
else
# else add (+) instead
result="(+) "
fi
case $emoji in
True)
# Loop through each digit of the input and append the corresponding emoji to the output
while [ ${#num} -gt 0 ]; do
digit="${num:0:1}"
case "$digit" in
# replace '.' character with ' . ' for better formatting
".") result+=" . " ;;
# Use a unicode variation selector' }️⃣ 'to make the digit an emoji
*) result+="${digit}️⃣}" ; result=${result%?} ;;
esac
num="${num:1}"
done ;;
*) result="${result}$num" ;; esac
# Print the result to standard output
printf "$result"
}
updatePER() { # Define a function to update the message with emoji and balances
# Assign the first argument to a local variable for manipulation
local txemo=$1
# If the fifth argument is True, replace the brackets and contents with emoji numbers
if [[ $5 == True ]]; then
# remove everything before and after the brackets-leaving only the number
txemo=${txemo#*[}; txemo=${txemo%]*}
# Convert the number to emoji by calling function emoNum
txemo=$(emoNum $txemo)
# Replace the brackets with the new emoji number
txemo=$(sed -e "s/\[\([^]]*\)\]/$txemo/g" <<< "$1")
fi
# Print a message with emoji and the arguments to standard output
printf "$(emo) cashTrack updated! $(emo)\n\n"
printf "$txemo\n\n$(emoNum $2) : New Balance\n\n"
printf "$(emoNum $3) : Previous Balance\n\nnote:\n$4\n"
}
txRem() { # Define a function to remove the last transaction which is called when the user uses XX command
# Assign a message to txmsg variable
txmsg="$PER has removed the last entry!"
# Query the database for the last result and assign the result to lastTx variable
lastTx=$(sqlite3 signalbot.db "SELECT perA, balanceA, perB, balanceB
FROM cashtrack ORDER BY rowid DESC LIMIT 1;" ;)
# Split the result by | and assign the values to four variables
IFS='|' read -r dbNameA dbAMNTa dbNameB dbAMNTb <<< "$lastTx" ; wait
# Check if dbNameA matches perA and assign the corresponding balances to last and olast variables
if [[ "$dbNameA" == "$perA" ]]; then
last="$dbAMNTa" ; olast="$dbAMNTb"
else
last="$dbAMNTb" ; olast="$dbAMNTa"
fi
# Delete the last row from the database
sqlite3 signalbot.db "DELETE FROM cashtrack WHERE rowid = (SELECT max(rowid) FROM cashtrack);"
# Query the database again and assign the result to lastTx variable
lastTx=$(sqlite3 signalbot.db "SELECT perA, balanceA, perB, balanceB
FROM cashtrack ORDER BY rowid DESC LIMIT 1;" ;)
# Split the result by | and assign the values to four variables
IFS='|' read -r dbNameA dbAMNTa dbNameB dbAMNTb <<< "$lastTx" ; wait
# Check if dbNameA matches perA and assign the corresponding balances to new and onew variables
if [[ "$dbNameA" == "$perA" ]]; then
new="$dbAMNTa" ; onew="$dbAMNTb"
else
new="$dbAMNTb" ; onew="$dbAMNTa"
fi
# Call cashTrackSend function with arguments for the user who used the XX command
cashTrackSend "$1" "$(updatePER "$txmsg" "$new" "$last" "$msgNote" False)"
wait; sleep 1
# Call cashTrackSend function with arguments to alert the other user that XX command was used
cashTrackSend "$ophone" "$(updatePER "$txmsg" "$onew" "$olast" "$msgNote" False)"
}
# Use case to assign PER and oPER names based on phone number creating tx
case "$1" in
"+$Aphone") PER="$perA" ; oPER="$perB" ophone="+$Bphone" ;;
"+$Bphone") PER="$perB" ; oPER="$perA" ; ophone="+$Aphone" ;;
*) errorOut True "$1" "err 2" ; return ;;
esac
# Check if the second argument is XX and call txRem function with the user phone number as argument
[[ $2 == "XX" ]] && { txmsg="$PER removed the previous entry!"; txRem "+$1"; return; } ;
# Use parameter expansion to remove commas, newlines and quotes from the third argument
msgBody=${3//[$'\n",']/}
# Use read to split msgBody into AMNT and msgNote by the first whitespace
read AMNT msgNote <<< "$msgBody" ;
# Use a case statement to set OP, oOP, txType and txmsg based on the second argument
# OP and oOP will be used as the operator of the calculation which adds or subtracts the AMNT from the user balance
case $2 in
"R ") OP="+"; oOP="-"; txType="request"; txmsg="$PER has requested [$AMNT] from $oPER" ;;
"S ") OP="-"; oOP="+"; txType="send"; txmsg="$PER has sent [$AMNT] to $oPER" ;;
*) errorOut True "$1"; return ;;
esac
# Validate AMNT as a number or call errorOut
[[ $AMNT =~ [0-9]+ ]] || errorOut True "$1"
# Use printf and bc to format AMNT as a decimal number
AMNT=$(printf %.3f $(bc <<< "$AMNT")) ; AMNT=${AMNT%0}
# Get the last transaction from the database
lastTx=$(sqlite3 signalbot.db "SELECT perA, balanceA, perB, balanceB FROM cashtrack ORDER BY rowid DESC LIMIT 1;")
# Split the result by | and assign the values to four variables
IFS='|' read -r dbNameA dbAMNTa dbNameB dbAMNTb <<< "$lastTx" ; wait
# Check if dbNameA matches perA and assign the corresponding balances to last and olast variables
if [[ "$dbNameA" == "$perA" ]]; then
last="$dbAMNTa" ; olast="$dbAMNTb"
else
last="$dbAMNTb" ; olast="$dbAMNTa"
fi
# Calculate new and onew balances for the users
new=$(echo "$last $OP $AMNT" | bc)
onew=$(echo "$olast $oOP $AMNT" | bc)
# Set td as date
td=$(date)
# set sql INSERT INTO string with the new balance data for both users and message note
sql="INSERT INTO cashtrack (date, amount, type, perA, balanceA, perB, balanceB, note)
VALUES ('$td', '$AMNT', '$txType', '$PER', '$new', '$oPER', '$onew', '$msgNote')" ;
# insert the transaction data into a database table
sqlite3 signalbot.db "$sql"; wait
#Use cashTrackSend and updatePER to send messages to both parties
cashTrackSend "$1" "$(updatePER "$txmsg" "$new" "$last" "$msgNote" True)" ; wait; sleep 1
cashTrackSend "$ophone" "$(updatePER "$txmsg" "$onew" "$olast" "$msgNote" True)" ; wait
}
examineMsg() {
printf "TIME: %s\\nSENDER: %s\\nMSG: %b\\nCONTENT TYPE: %s\\nFILE NAME: %s\\n" "$@"
# Check if the sender is a valid phone number, otherwise exit with an error
[[ "$2" != "+$Aphone" || "$2" != "+$Aphone" ]] && { errorOut False; return; }
# Put the message into a 'read' status
signal-cli --dbus sendReceipt -t "$1" --type read "$2" &> /dev/null
wait ; printf '%s\n' " --- message read --- "
# then send the typing animation to user
signal-cli --dbus sendTyping "$2" &> /dev/null
wait ; printf '%s\n' " --- typing --- "
# Extract the first two characters of the message body and convert them to uppercase
tx="${3:0:2}" ; tx="${tx^^}"
case $tx in
R\ |S\ |XX) echo "cashtrack invoked" ; cashtrack "$2" "$tx" "${3:2}" ;;
*) errorOut True "$1" "Err #1: tx value of $tx" ;;
esac
}
# Update the global variables that store the message information by
# searching for the dbus substrings defined above. Then manipulate the strings.
readMsg() {
# use a case statement to check which line of dbus output is being read
case $1 in
# set TIMESTAMP by removing the first 6 characters of 'int64' string
0) t="${2:6}" ;;
# set SENDER by removing everything before and after the quotes
1) a="${2#*\"}" ; a="${a%\"*}" ;;
2) case "$2" in
# set first line of MSG by removing the first 8 characters of $2 and adding a newline
"$ms"*) b="${2:8}\n" ;;
# if not the begining of the MSG-decrement j to skip this line
*) j=$((j-1)) ;; esac ;;
# if needed, used to add multiple lines to MSG
3) case "$2" in
# if "array [" is found, remove everything after the last quote from MSG
"$me"*) b="${b%\"*}"
# reset msgFlag once msg has completed
msgFlag=false ;;
# otherwise, append the line to MSG and decrement j until "array [" is found
*) b+="$2\n" && j=$((j-1)) ;; esac ;;
# if needed, set CONTENT TYPE
4) case "$d $2" in
# if contentType is found and d is false, set d to true and decrement j
"false $c"*) d=true && j=$((j-1)) ;;
# if variant is found and d is true, set e to the value between quotes
"true $v"*) e="${2#*\"}" ; e="${e%\"*}" ;;
# otherwise, decrement j
*) j=$((j-1)) ;; esac ;;
# if needed, set FILE NAME
5) case "$g $2" in
# if remoteId is found and g is false, set g to true and decrement j
"false $f"*) g=true && j=$((j-1)) ;;
# if variant is found and g is true, set h to the value between quotes
"true $v"*) h="${2#*\"}" ; h="${h%\"*}" ;;
# otherwise, decrement j
*) j=$((j-1)) ;; esac ;;
# if expiresInSeconds is found, call examineMsg with the global variables as arguments
esac; [[ "$2" == "$l"* && "$msgFlag" == "false" ]] && examineMsg "$t" "$a" "$b" "$e" "$h"
}
# Clear the terminal screen and then run a dbus-monitor command that listens for
# new signal messages. Pipe the output to a while loop that reads each
# line of the dbus and pass it to the readMsg function.
clear; printf '%s\n' " --- cashtrack --- " ; msgFlag=false
dbus-monitor --session "type='signal',interface='$intfc', member='$mmbr'" |
while read -r dbus; do
# reset variables when new message starting with "int64" is received and
# set msgFlag to true to avoid restarting on message body with 'int64'
[[ "$dbus" == "$s"* && "$msgFlag" == "false" ]] && { j=0; b=""; e=""; h=""; d=false; g=false; msgFlag=true; }
# call readMsg with j and the current dbus line as arguments
readMsg $j "$dbus"
((j++))
done