A command-line interface to the important portions of
libgammu
. Send and receive text
messages programmatically using a USB GSM or CDMA modem. Speaks JSON
and UTF-8 by default. Minimal dependence on external libraries.
This package is usable now, but still under active development. Please refrain from using it in production applications until we're sure that we've shaken all the bugs out. For more information, please review the documentation for Gammu directly.
If you want to skip all of this summary-level stuff and go straight to the examples, we won't be offended.
A simple command-line utility to send, retrieve, and delete SMS messages using
libgammu
and a supported phone and/or GSM/CDMA modem. In all cases, input is
accepted as UTF-8 encoded program arguments, and output is provided as UTF-8
encoded JSON.
Multi-part messages (sometimes referred to as "concatenated SMS") are supported.
In send mode, messages are automatically broken up in to multiple message parts when size limits require it. User-data headers (UDHs) are generated automatically to allow for message reassembly.
When sending messages, the utility automatically detects whether the message can be sent using the default GSM alphabet (described in GSM 03.38). If so, message parts may be up to 160 characters in length. If any character in the string cannot be represented in the default GSM alphabet, the entire message will be encoded as big endian UTF-16, reducing the number of characters available per message (or message part). This is a limitation of the underlying SMS protocol; it cannot be fixed without making changes to the protocol itself.
In receive mode, message parts are each returned as separate messages; however,
every part of a multipart message will have the udh
, segment
, and
total_segments
attributes set to meaningful values. The udh
value is
a unique 8-bit or 16-bit integer, generated by the sender, that differentiates
sets of concatenated messages from one-another -- that is, messages with the
same udh
value should be linked together.
This utility does not perform message reassembly in receive mode; robust
reassembly requires some form of off-modem persistent data storage, since each
message part could be delayed indefinitely and storage on the SIM and/or modem
is limited. Architecturally speaking, gammu-json
provides enough information
to reassemble messages, but the actual matching and concatenation will need to
be performed at a higher level. Take a look at node-gammu-json
on Github or
NPM for an example of this.
Character-encoding footnote: traditionally, the GSM standard specified
big-endian UCS-2 for SMS transmission of characters that cannot be represented
using the 7-bit GSM alphabet. UCS-2 is a 16-bit Unicode encoding with no support
for surrogate pairs or variable-size encodings, and is therefore limited to the
basic multilingual plane (the BMP, or codepoints 0x0000
to 0xFFFF
). As
characters outside of the BMP have come in to widespread use (Emoji, most
notably), phones have started switching away from UCS-2 and toward big-endian
UTF-16. UTF-16 is effectively a superset of UCS-2, does have support for
surrogate pairs (using pairs of Unicode-reserved 16-bit values in the 0xd800
to 0xdfff
range), and is capable of representing any Unicode character between
zero and 0x10ffff
. We've made the same decision in gammu-json
. Where it's
necessary, we provide our own character encoding/decoding routines, and don't
rely on Gammu functions like EncodeUTF8
and DecodeUTF8
that are restricted
to UCS-2 and the BMP.
Building gammu-json
from source can typically be accomplished by running
make
and make install
. The included Makefile
uses pkg-config
to locate
libgammu
. If you'd like to link with a libgammu
that isn't under /usr
,
try defining the PREFIX
variable when you run make
, like this:
make PREFIX=/srv/software/libgammu
or, alternatively, set the PKG_CONFIG_PATH
environment variable to point
directly to your preferred $prefix/lib/pkgconfig
directory.
By default, gammu-json
requires that (a) you have a valid /etc/gammurc
file (or symbolic link) present in your local filesystem, and (b) that
/etc/gammurc
provides a working phone/modem configuration in its gammu
section. Here's a simple example:
[gammu]
Connection = at
Device = /dev/ttyUSB0
If your gammu configuration file is located elsewhere, you may use the
-c
or --config
option to specify a custom configuration file path.
This software is released under the GNU General Public License (GPL) v3.
Executing and/or parsing the output of an unmodified gammu-json
from your
closed-source program does not create a derivative work of gammu-json
, nor
does it require you to release whatever source code it is that you're afraid of
other people seeing. Your secret's safe with us.
However: if you modify the gammu-json
software itself, and distribute a
compiled version containing your modifications to others (either as software,
as a software package, or as software preloaded on a piece of hardware), you
will be required to offer those modifications (in their original human-readable
source code form) to whomever obtains the modified software.
Please note that Gammu itself (including the libgammu
upon which gammu-json
relies) is licensed under the GPL v2 (or later, presumably at your option).
Note: JSON output is reformatted here (and in all other examples) to improve
readability. If you'd like the results of gammu-json
to be automatically
indented (i.e. "pretty-printed") for your application, you can pipe its output
to your favorite formatting utility.
$ gammu-json
Usage:
gammu-json { retrieve | send { phone text }... | delete N... }
Sending a single message is easy.
$ gammu-json send '+15035551212' 'This is a simple test message.'
[
{
"parts_sent": 1,
"index": 1,
"parts_total": 1,
"parts": [
{
"index": 1,
"reference": 250,
"status": 0,
"content": "This is a simple test message.",
"result": "success"
}
],
"result": "success"
}
]
Sending more than one message is also easy.
$ gammu-json send \
'+15035551212' 'This is a simple test message.' \
'+15035551212' 'This is another simple test message.'
[
{
"parts_sent": 1,
"index": 1,
"parts_total": 1,
"parts": [
{
"index": 1,
"reference": 250,
"status": 0,
"content": "This is a simple test message.",
"result": "success"
}
]
},
{
"parts_sent": 1,
"index": 2,
"parts_total": 1,
"parts": [
{
"index": 1,
"reference": 251,
"status": 0,
"content": "This is another simple test message.",
"result": "success"
}
],
"result": "success"
}
]
A message that is too long for a single SMS (160 characters for the 7-bit GSM default alphabet, or 80 for UTF-16 coding of Unicode symbols) will be split in to a concatenated/multipart message automatically. Information about how the message was split will be returned in the JSON output (see the parts array).
$ gammu-json send '+15035551212' 'This is a simple test message. This is only a test. Had this been an actual message, the authorities in your area (with cooperation from federal and state authorities) would have already read it for you.'
[
{
"parts_sent": 2,
"index": 1,
"parts_total": 2,
"parts": [
{
"index": 1,
"reference": 251,
"status": 0,
"content": "This is a simple test message. This is only a test. Had this been an actual message, the authorities in your area (with cooperation from federal and stat",
"result": "success"
},
{
"index": 2,
"reference": 252,
"status": 0,
"content": "e authorities) would have already read it for you.",
"result": "success"
}
],
"result": "success"
}
]
If a message contains any UTF-8 character that is not present in the 7-bit default GSM alphabet, the message will automatically be sent as a two byte per character UTF-16 SMS.
$ gammu-json send '+15035551212' 'This is a test message. الحروف عربية. ان شاء الله.'
[
{
"parts_sent": 1,
"index": 1,
"parts_total": 1,
"parts": [
{
"index": 1,
"reference": 254,
"status": 0,
"content": "This is a test message. الحروف عربية. ان شاء الله.",
"result": "success"
}
],
"result": "success"
}
]
For UTF-16 messages, messages will be sent in multiple parts after only 80 characters (rather than the usual limit of 160). To see the UTF-16 message size limitation in action, try this example again after removing the obvious non-Latin characters.
$ gammu-json send '+15035551212' 'The portion before this contains only Latin characters. Nepali text follows this. हो'
[
{
"parts_sent": 2,
"index": 1,
"parts_total": 2,
"parts": [
{
"index": 1,
"reference": 2,
"status": 0,
"content": "The portion before this contains only Latin characters. Nepali text",
"result": "success"
},
{
"index": 2,
"reference": 3,
"status": 0,
"content": " follows this. हो",
"result": "success"
}
],
"result": "success"
}
]
Retrieving messages from a newly-purchased SMS modem yields the empty JSON
array, and exits with zero status. The program will display an error message
on stderr
and exit with a non-zero status if something goes wrong.
$ gammu-json retrieve
[]
After running the retrieve
command, a JSON-encoded array of message objects
is returned on stdout
. The phone number for the sender and "short message
service center" (SMSC) are each included, along with a receive timestamp, an
SMSC receive timestamp (if available), location number (on the SMS modem), user
data header (UDH) value, and segment information (in this case, one of one).
$ gammu-json retrieve
[
{
"location" : 1,
"smsc" : "+12085552222",
"content" : "This is a test message.",
"segment" : 1,
"inbox" : true,
"smsc_timestamp" : false,
"folder" : 1,
"udh" : false,
"timestamp" : "2013-04-02 17:05:49",
"from" : "+15035551212",
"total_segments" : 1,
"encoding" : "utf-8"
},
{
"location" : 2,
"smsc" : "+12085552222",
"content" : "This is another test message.",
"segment" : 1,
"inbox" : true,
"smsc_timestamp" : false,
"folder" : 1,
"udh" : false,
"timestamp" : "2013-04-02 17:06:03",
"from" : "+15155551111",
"total_segments" : 1,
"encoding" : "utf-8"
}
]
Multipart messages are returned in multiple segments, tied together by
the sender's phone number in from
, and the user data header value in
udh
. Single-part messages will have a udh
value of false. Multipart
messages that are missing the proper header information will have a
udh
value of null
.
$ gammu-json retrieve
[
{
"location" : 1,
"smsc" : "+12085032222",
"content" : "This is a simple test message. This is only a test. Had this been an actual message, the authorities in your area (with cooperation from federal and stat",
"segment" : 1,
"inbox" : true,
"smsc_timestamp" : false,
"folder" : 1,
"udh" : 215,
"timestamp" : "2013-04-02 17:12:40",
"from" : "+15035551212",
"total_segments" : 3,
"encoding" : "utf-8"
},
{
"location" : 2,
"smsc" : "+12085032222",
"content" : "e authorities) would have already read it for you. This is a simple test message. This is only a test. Had this been an actual message, the authorities i",
"segment" : 2,
"inbox" : true,
"smsc_timestamp" : false,
"folder" : 1,
"udh" : 215,
"timestamp" : "2013-04-02 17:12:52",
"from" : "+15035551212",
"total_segments" : 3,
"encoding" : "utf-8"
},
{
"location" : 3,
"smsc" : "+12085032222",
"content" : "n your area (with cooperation from federal and state authorities) would have already read it for you.This is a simple test message. This is only a test.",
"segment" : 3,
"inbox" : true,
"smsc_timestamp" : false,
"folder" : 1,
"udh" : 215,
"timestamp" : "2013-04-02 17:12:59",
"from" : "+15035551212",
"total_segments" : 3,
"encoding" : "utf-8"
},
{
"location" : 4,
"smsc" : "+12085032222",
"content" : "This is a short message.",
"segment" : 1,
"inbox" : true,
"smsc_timestamp" : false,
"folder" : 1,
"udh" : false,
"timestamp" : "2013-04-02 17:13:56",
"from" : "+15035551212",
"total_segments" : 1,
"encoding" : "utf-8"
}
]
This example assumes there are seven messages stored on the SMS modem, numbered one through seven.
$ gammu-json delete all
{
"detail" : {
"1" : "ok",
"2" : "ok",
"3" : "ok",
"4" : "ok",
"5" : "ok",
"6" : "ok",
"7" : "ok"
},
"result" : "success",
"totals" : {
"errors" : 0,
"requested" : "all",
"deleted" : 7,
"attempted" : 7,
"examined" : 7,
"skipped" : 0
}
}
This example assumes that there are twelve messages (or message segments),
numbered one through twelve. Message numbers are one-based integer
identifiers, and are returned in the gammu-json retrieve
output as the
location
property. Currently, gammu-json
always deletes from folder zero,
which contains all available messages on the phone/modem.
$ gammu-json delete 3 1 4 5 9
{
"detail" : {
"1" : "ok",
"2" : "skip",
"3" : "ok",
"4" : "ok",
"5" : "ok",
"6" : "skip",
"7" : "skip",
"8" : "skip",
"9" : "ok",
"10" : "skip",
"11" : "skip",
"12" : "skip"
},
"result" : "success",
"totals" : {
"errors" : 0,
"requested" : 5,
"deleted" : 5,
"attempted" : 5,
"examined" : 12,
"skipped" : 7
}
}
This example assumes that there are four messages (or message segments),
numbered one to four. Deleting non-existent messages is not an error;
rather the nonexistent messages are noted in the totals.attempted
property, and the result
of the deletion is reported as partial
.
$ gammu-json delete 1 2 3 5
{
"detail" : {
"1" : "ok",
"2" : "ok",
"3" : "ok",
"4" : "skip"
},
"result" : "partial",
"totals" : {
"errors" : 0,
"requested" : 6,
"deleted" : 3,
"attempted" : 3,
"examined" : 4,
"skipped" : 1
}
}
Copyright © 2013 David Brown <hello at scri.pt>
Copyright © 2013 Medic Mobile, Inc. <david at medicmobile.org>
All rights reserved. Meticulously handcrafted with love in Portland, Oregon, USA.
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL DAVID BROWN BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.