I have (somewhat successfully) reworked my VoIP setup, and would like to share it with you.
I use a local VoIP provider, and a few months ago, I found out they have an API. At the time, I only had XMPP running on my server, so my problem was like a hammer. I set up XMPP triggers on it, so every time someone called me, I got a message. A few months ago, I set up a private ntfy.sh instance, and I’m using it to send notifications this way now.
If you don’t want to read the whole post, here is a list of what it does:
- Grab a CSV of incoming calls, grep only missed calls, grep out last call ID, grep out the headers.
- If the nextID matches lastID, exit
- If there is a new ID, save the new ID to file and perform other actions on only the new call line.
- Cut out the From and To numbers, save each to a variable
- Look up the incoming number in the FB leak (currently only local country, I don’t get international calls on these)
- Construct a NTFY message telling me what number called which of my lines, resolve the name if applicable, and send it
This all seems simple enough, let’s look at the lines in turn, because if you have Twilio or something with API access, you may want to implement your own.
After some templating, I found that there is a CSV output possible for my call log. The output of this log is saved in a variable, since it’s only one line, and password, user, and lastcall are declared at the top of the script as variables as well.
curl -s -X GET https://VOIPPROVIDER/calls.csv -d "password=$password" -d "user=$user" -d "status=missed" -d "since_id=$lastcall" | tail -n1 | grep -v $lastcall | grep -v "active_call")
Since this script will run every minute or so, I need to save the callID variable into a file. This will be stored next to the script and read at each run. The next pipes clean up the output so that only the last line gets published, and then I cut the headers out. This way, I will never get a message saying “You got a call from incoming_caller on incoming_line,” and I grep out the ID of the last call so that I don’t get a call report every minute about a call that happened 30 minutes ago.
If I have no incoming calls (which is, like, 99% of my life), the output of this command will be empty. Headers will be cut, as will the last call I already got, but then I would still get a message with all fields empty (trust me, it was a painful 15 minutes figuring that out).
The first if statement I have here is that if the curl command returns empty-handed, I can kill the process right there and save precious CPU.
if [$calllog == '']; then
I have no clue if this is the most efficient way, but it does stop the script halfway through, so it’s fine by me.
If this test fails, I can be sure that I have received a new call. Now we have a line which contains phone numbers, times and phone lines and… well, that’s it.
In my first implementation, I went straight to crafting a NTFY notification, with the call log variable being repeated several times and cut several times. This line alone was half the script, basically. In v2.0, I decided to cut each value into its own variable, so I can add new ones, edit the ones I have, and perform custom actions on each:
from=$(echo "$calllog" | cut -d',' -f5 | sed -s 's/00/+/')
Basically, I take the line three times and cut three variables out: Who called me (from), which phone number they dialed (to) and the line where the call was missed (line). The line variable is currently unimplemented, but since I have my shit named so nicely, I would like to include a list of line names and look them up, so I recognize the line by name.
This is the part where my call log comes in handy. If I have a phone number, and that number is in the Facebook leak for my country, the script will change the + notation (again) to a number with only a country code, perform a ripgrep on the FB leak, and save the name to a variable:
name=$(rg $numwoplus fb-leak.txt | cut -d":" -f2,3)
If a number is not found, I don’t want to have an ugly “()” hanging in my notification, so I replace it with a Not Found:
if [$name == '']; then
The last part is easy. I have my NTFY server set up, so I can send myself notifications on anything I’m interested in (spoiler alert, I’ll be getting RSS working soon).
The way I did it is, you guessed it… PRINTF. Echo could work, but printf handles some things better. I can then send a cURL command to my NTFY server, which will pop a notification on my phone.
printf "Call from $from ($name) to $to on *$line!" | curl -s -d @- -H ntfy.sh/phonecallloggrepper >/dev/null
NOTE: No, the URL does not work, you will not get my phone calls from this.
The >/dev/null part prevents me from getting my shell log full of stuff I don’t need. The NTFY notification comes through even without that.
This script works fine, and I set it into cron to run every minute. One future development I’d like is getting it to sub-minute response times, where I get a ping sooner than the next minute. That might eat up processing time, though, so I guess I’ll be happy with what I have.
If you read the title, you may ask what this script has to do with the movie Fight club. I didn’t realize it either, but my previous setup was that every call would be forwarded to my real phone number. If someone gets into my account, they could see 10 numbers forwarding to my real phone number, and I don’t trust this VoIP provider enough to have them keep my number. In the current situation, I never get bothered by an incoming phone call, except for specific numbers. I never pick up my phone anymore, except for people who have my real number.
A huge benefit is that I can quickly learn that someone hit my phone lines. I have two spam lines that I give out specifically to companies I don’t want bothering me, but I do want to see if anyone actually called my trademarked RickRoll line. It’s much better when I can have a giggle thinking “Yes, they heard it.”
After I get a ping, I also get a 6-digit line number I can then pick in my VoIP application and call back when I want to. As an introvert, I can now choose when I have to talk to people, I am no longer a slave to my phone and incoming calls. Plus, I get the name of a person (if found), and I can act all-knowing when I tell that person their name even if it’s the first time they’re calling me.
I have to tweak the script a bit to show me line names in addition to my line number. This is just a QoL improvement, but it may pay off if I include alias names for my lines in the future.
Next, it only shows me missed calls. If nothing forwards to me, it’s fine. If I set up an automatic “deny at once” for the number, it may not drop into the log, but that’s up to me to figure out.
Lastly, I want to figure out how to include a song or text while the call is ringing. I could include a simple “I will get back to you,” but it seems too rude. It’s much better to just have the call ring empty for a bit, and then deny it. Everyone will get the message better if it’s not a robotic voice telling them to fuck off.
I believe that everyone should have such a number. This setup gives me so much power. I can have parallel ring on multiple numbers (in case I have a “family emergency” number, it will ring for everyone in my family and whoever picks up will be able to help.)
The limit of VoIP is my imagination, but I want to get more organized in my usage of them. It’s useless to have 20+ numbers if I don’t use them in a controlled manner. For the few I use on a daily basis, I don’t have a list of all places where I gave out which number. I have vague categories, but I want to be more strict and keep a list of number recipients, so I know that I can safely burn a number if I don’t need it anymore.
Hope this opens you a little more up to VoIP strategies, and that some of you will perhaps implement it into your own life. If you do, let me know!