After much experimenting, the following is my best solution so far.
Solution: Use atinout to book via USSD menu
USSD is used by mobile network operators for responsive service menus – see Wikipedia on USSD. Booking via Ncell's *17123# USSD menu via the computer that has the SIM is the most comfortable option.
Since dedicated USSD client software did not work for me (see below), I use raw AT commands. For that, I will first install atinout, a small command line utility for using AT commands:
sudo apt-get install ruby-ronn;
git clone git://git.code.sf.net/p/atinout/code atinout;
cd atinout;
make;
checkinstall make install;
Then, I can use it with AT USSD commands to, for example, book a Daily Internet Pack 40 MB. Here's a full transcript. After the modem confirms your command with OK, wait a few seconds and press Enter to display the USSD answer (which should have arrived by then). Then press Ctrl+C to terminate atinout (^C in the transcript), and restart it again.
$ sudo stop modemmanager
stop: Unknown instance:
$ atinout - /dev/ttyUSB1 -
AT+CUSD=1,"*17123#",15
OK
+CUSD: 1,"1.) 1 day Pack
3.) Facebook Pack
4.) 7 Day Pack
6.) 30 Day Pack
8.) Unlimited Pack
Note:
Back:* Top:#",15
^C
$ atinout - /dev/ttyUSB1 -
AT+CUSD=1,"1",15
OK
+CUSD: 1,"1.Light 6 MB Rs 6
2.Light 12 MB Rs 9
3.Medium 18 MB Rs 12
4.Heavy 40 MB Rs 20
5.Deactivate
Note:
Back:* Top:#",15
^C
$ atinout - /dev/ttyUSB1 -
AT+CUSD=1,"4",15
OK
+CUSD: 1,"1.One time Activations
2.Auto Renewal Activations
Note:
Back:* Top:#",15
^C
$ atinout - /dev/ttyUSB1 -
AT+CUSD=1,"1",15
OK
+CUSD: 0,"Dear Customer, your 40 MB pack with 24 hours validity
is currently processing and will be activated within 10 min. ",15
^C
You can combine the above into one script (assuming for now you don't have to retry any command; the AT is just to display the USSD answer):
sudo stop modemmanager && \
atinout - /dev/ttyUSB1 - < <(echo "AT+CUSD=1,\"*17123#\",15") && sleep 4 && \
atinout - /dev/ttyUSB1 - < <(echo "AT") && \
atinout - /dev/ttyUSB1 - < <(echo "AT+CUSD=1,\"1\",15") && sleep 4 && \
atinout - /dev/ttyUSB1 - < <(echo "AT") && \
atinout - /dev/ttyUSB1 - < <(echo "AT+CUSD=1,\"4\",15") && sleep 4 && \
atinout - /dev/ttyUSB1 - < <(echo "AT") && \
atinout - /dev/ttyUSB1 - < <(echo "AT+CUSD=1,\"1\",15") && sleep 4 && \
atinout - /dev/ttyUSB1 - < <(echo "AT");
(Note, this script uses a technique to avoid pipe characters.)
Troubleshooting
Multiple AT+CUSD commands in a row. For some reason, with my 3G modem (Gobi 2000), in 90% of cases, only one AT+CUSD can be executed successfully, then atinout has to be restarted. To prevent difficulties, in the process above we restart atinout simply every time in the transcript above. This does not end the USSD session (an "open" USSD menu).
If the modem does not answer with OK. When going along the above transcript, take care that every command is confirmed with "OK" by the modem. If not, restart atinout and try again. If that does not help, start the whole process again. And if that does not help, your modem might be in a strange state. Reset it, or just let the computer go through a suspend / resume cycle.
Using AT commands in general. For more details about communicating with a modem using AT commands under Linux, see this answer.
When booking a Daily Internet Pack fails. The Ncell Ecare website would fail without an error message and show the list of services again, instead of a success message of a form to enter a SMS confirmation code. This condition happens if you still have an active monthly (or also weekly?) Internet pack. Even if no data balance is left of it. You can check that and if necessary cancel the pack here. However for me, even after cancelling the pack, a data balance query by SMS would return "Dear Customer, You have […] MB data left in your Monthly account which will expire […]." and it was still impossible to book a Daily Internet Pack. I would have to wait until the expiration date. Maybe try putting the SIM into a phone and book the first Daily Internet Pack via USSD code (dial *17123# and follow the on-screen menu.)
Future Improvements
Automation. With the above solution, we have to navigate the menu manually, and try again if something goes wrong. Could be better.
Automatic re-booking. Ideally, this solution would include automatic (re-)booking when the data balance runs low. This can be detected by the Ncell warning SMS and / or traffic monitoring. This would not book a new pack automatically when it expires naturally, but then notify the user with a status icon that she's browsing with the expensive rate.
Be notified when the data balance runs out. If so, we would not require transferring limited amounts to the SIM card, but could transfer a large amount and would be warned (for example by a big red icon in the task bar) when running into the expensive rate. There are at least two ways for this:
Getting the Ncell notification SMS during an active data connection. Ncell sends it when the data balance runs low. See the point above on wvdial etc. how this could work. It does not work with NetworkManager and gammu out of the box, since it grabs both modem control channels.
Limiting data traffic. NTM would be a candidate tool for this, but it currently does not have a feature to set one-time pack data limits with exact start time.
Alternative USSD client software (not working for me)
There are dedicated USSD clients under Ubuntu Linux, but they did not work for me for various reasons (my 3G modem hardware: Gobi 2000). However, with some debugging, you might get them to work. The usage of some is treated in more detail in this question and this question.
The list, with the most promising candidates first:
mmcli. ModemManager and its command line client mmcli seem to be great software and the best bet for this task. See this answer on StackOverflow for how to use mmcli to navigate USSD menus. However, after solving a problem with always-on PIN2 lock on Ncell SIM cards (solution similar to this), mmcli would still refuse sending USSD commands via the Gobi 2000 3G modem, due to a bug (because the modem uses USSD with other clients software successfully):
$ sudo apt-get install libqmi-utils
$ sudo qmicli -d /dev/cdc-wdm0 --dms-uim-verify-pin=PIN2,0000
$ sudo qmicli -d /dev/cdc-wdm0 --dms-uim-get-pin-status
$ mmcli -m 0 -e # Index as found via mmcli -L
$ mmcli -m 0 --3gpp-ussd-initiate="*100#"
error: Modem has nn USSD capabilities.
gsm-ussd. gsm-ussd is a command line utility exclusively for sending USSD codes, and it can operate USSD menus (see how in this answer). For Ncell though, I was able to send USSD codes and get answers, but not to operate USSD menus. There would be various inconsistent error messages, and I did not investigate if the problem is my hardware, gsm-ussd or Ncell's implementation of USSD.
gammu. gammu is a Linux command line utility that can send USSD codes, but according to this question, it cannot use USSD menus yet. python-gammu contains a script service_numbers.py that is meant to enable this. It did not work for me though.
ofono. ofono has a similar purpose and interface as ModemManager [source], just that it is made for Ubuntu Touch (which can run on mobile phones). Its main interface is DBus, but you can use its test case command line tools to send USSD commands and operate USSD menus (examples, more examples). However, it seems to need a rild (Radio Interface Layer Daemon) implementation to function, and that would only be available on actual mobile phones. When starting, ofonod would complain about not being able to connect to rild, and I could not find a rild to install on a normal Ubuntu Linux installation.
ussdq. ussdq is another small utility for Linux that includes a feature to operate USSD menus. However, it no longer in active development sincee 2013, and compiling it is a bit of an effort (it uses the Gambas2 framework, but recent Ubuntu Linux versions only include packages for Gambas3).