jeffrafter-rubygsm 0.3.2 → 0.5.0
Sign up to get free protection for your applications and to get access to all the features.
- data/bin/sms +38 -0
- data/lib/rubygsm/core.rb +215 -48
- data/lib/rubygsm/errors.rb +5 -1
- data/lib/rubygsm/log.rb +24 -0
- data/lib/rubygsm/msg/incoming.rb +5 -2
- data/lib/rubygsm/msg/outgoing.rb +7 -0
- data/rubygsm.gemspec +8 -6
- metadata +16 -4
data/bin/sms
ADDED
@@ -0,0 +1,38 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
# vim: noet
|
3
|
+
|
4
|
+
dir = File.dirname(__FILE__)
|
5
|
+
require "#{dir}/../lib/rubygsm.rb"
|
6
|
+
|
7
|
+
|
8
|
+
# expand args (TODO: optparser,
|
9
|
+
# which we need so very badly)
|
10
|
+
# or fail with USAGE message
|
11
|
+
if (ARGV.length == 2)
|
12
|
+
recipient, msg = *ARGV
|
13
|
+
port = :auto
|
14
|
+
|
15
|
+
elsif (ARGV.length == 3)
|
16
|
+
port, recipient, msg = *ARGV
|
17
|
+
|
18
|
+
else
|
19
|
+
puts "Usage: sms [PORT] RECIPIENT MESSAGE"
|
20
|
+
puts "(don't forget to quote the message)"
|
21
|
+
puts
|
22
|
+
puts "Examples:"
|
23
|
+
puts ' sms +13474201234 Hello'
|
24
|
+
puts ' sms /dev/ttyS0 +13474201234 "Hello from RubyGSM"'
|
25
|
+
exit
|
26
|
+
end
|
27
|
+
|
28
|
+
# initialize the modem, send the sms, and
|
29
|
+
# terminate. currently, rubygsm does a lot
|
30
|
+
# of things that aren't strictly required
|
31
|
+
# to get this done; maybe refactor
|
32
|
+
begin
|
33
|
+
modem = Gsm::Modem.new(port)
|
34
|
+
modem.send_sms!(recipient, msg)
|
35
|
+
|
36
|
+
rescue Gsm::Error => err
|
37
|
+
puts "Error: #{err.desc}"
|
38
|
+
end
|
data/lib/rubygsm/core.rb
CHANGED
@@ -18,8 +18,7 @@ module Gsm
|
|
18
18
|
class Modem
|
19
19
|
include Timeout
|
20
20
|
|
21
|
-
|
22
|
-
attr_accessor :verbosity, :read_timeout
|
21
|
+
attr_accessor :verbosity, :read_timeout, :keep_inbox_empty
|
23
22
|
attr_reader :device, :port
|
24
23
|
|
25
24
|
# call-seq:
|
@@ -56,16 +55,25 @@ class Modem
|
|
56
55
|
# tried all ports, nothing worked
|
57
56
|
raise AutoDetectError
|
58
57
|
end
|
59
|
-
|
60
|
-
|
58
|
+
|
59
|
+
# if the port was a port number or file
|
60
|
+
# name, initialize a serialport object
|
61
|
+
elsif port.is_a?(String) or port.is_a?(Fixnum)
|
61
62
|
@device = SerialPort.new(port, baud, 8, 1, SerialPort::NONE)
|
62
63
|
@port = port
|
64
|
+
|
65
|
+
# otherwise, we'll assume that the object passed
|
66
|
+
# was an object ready to quack like a serial modem
|
67
|
+
else
|
68
|
+
@device = port
|
69
|
+
@port = nil
|
63
70
|
end
|
64
71
|
|
65
72
|
@cmd_delay = cmd_delay
|
66
73
|
@verbosity = verbosity
|
67
74
|
@read_timeout = 10
|
68
75
|
@locked_to = false
|
76
|
+
@encoding = nil
|
69
77
|
|
70
78
|
# keep track of the depth which each
|
71
79
|
# thread is indented in the log
|
@@ -76,33 +84,35 @@ class Modem
|
|
76
84
|
# the last part is delivered
|
77
85
|
@multipart = {}
|
78
86
|
|
79
|
-
#
|
80
|
-
|
81
|
-
|
82
|
-
# initialization message (yes, it's underlined)
|
83
|
-
msg = "RubyGSM Initialized at: #{Time.now}"
|
84
|
-
log msg + "\n" + ("=" * msg.length), :file
|
87
|
+
# start logging to file
|
88
|
+
log_init
|
85
89
|
|
86
90
|
# to store incoming messages
|
87
91
|
# until they're dealt with by
|
88
92
|
# someone else, like a commander
|
89
93
|
@incoming = []
|
90
94
|
|
91
|
-
# initialize the modem
|
92
|
-
|
93
|
-
#
|
94
|
-
|
95
|
-
|
95
|
+
# initialize the modem; rubygsm is (supposed to be) robust enough to function
|
96
|
+
# without these working (hence the "try_"), but they make different modems more
|
97
|
+
# consistant, and the logs a bit more sane.
|
98
|
+
try_command "ATE0" # echo off
|
99
|
+
try_command "AT+CMEE=1" # useful errors
|
100
|
+
try_command "AT+WIND=0" # no notifications
|
101
|
+
|
102
|
+
# PDU mode isn't supported right now (although
|
103
|
+
# it should be, because it's quite simple), so
|
104
|
+
# switching to text mode (mode 1) is MANDATORY
|
105
|
+
command "AT+CMGF=1"
|
96
106
|
end
|
97
107
|
|
98
108
|
|
99
|
-
|
100
|
-
|
101
109
|
private
|
102
110
|
|
103
111
|
|
104
112
|
INCOMING_FMT = "%y/%m/%d,%H:%M:%S%Z" #:nodoc:
|
105
|
-
|
113
|
+
CMGL_STATUS = "REC UNREAD" #:nodoc:
|
114
|
+
|
115
|
+
|
106
116
|
def parse_incoming_timestamp(ts)
|
107
117
|
# extract the weirdo quarter-hour timezone,
|
108
118
|
# convert it into a regular hourly offset
|
@@ -129,17 +139,17 @@ class Modem
|
|
129
139
|
next
|
130
140
|
end
|
131
141
|
|
132
|
-
# since this line IS a CMT string (an
|
142
|
+
# since this line IS a CMT string (an incoming
|
133
143
|
# SMS), parse it and store it to deal with later
|
134
144
|
unless m = lines[n].match(/^\+CMT: "(.+?)",.*?,"(.+?)".*?$/)
|
135
|
-
err = "Couldn't parse CMT data: #{
|
145
|
+
err = "Couldn't parse CMT data: #{lines[n]}"
|
136
146
|
raise RuntimeError.new(err)
|
137
147
|
end
|
138
148
|
|
139
149
|
# extract the meta-info from the CMT line,
|
140
150
|
# and the message from the FOLLOWING line
|
141
151
|
from, timestamp = *m.captures
|
142
|
-
|
152
|
+
msg_text = lines[n+1].strip
|
143
153
|
|
144
154
|
# notify the network that we accepted
|
145
155
|
# the incoming message (for read receipt)
|
@@ -157,12 +167,13 @@ class Modem
|
|
157
167
|
log "Receipt acknowledgement (CNMA) was rejected"
|
158
168
|
end
|
159
169
|
|
160
|
-
# we might abort if this
|
170
|
+
# we might abort if this part of a
|
171
|
+
# multi-part message, but not the last
|
161
172
|
catch :skip_processing do
|
162
173
|
|
163
174
|
# multi-part messages begin with ASCII char 130
|
164
|
-
if (
|
165
|
-
text =
|
175
|
+
if (msg_text[0] == 130) and (msg_text[1].chr == "@")
|
176
|
+
text = msg_text[7,999]
|
166
177
|
|
167
178
|
# ensure we have a place for the incoming
|
168
179
|
# message part to live as they are delivered
|
@@ -178,24 +189,25 @@ class Modem
|
|
178
189
|
|
179
190
|
# abort if this is not the last part
|
180
191
|
throw :skip_processing\
|
181
|
-
unless (
|
192
|
+
unless (msg_text[5] == 173)
|
182
193
|
|
183
194
|
# last part, so switch out the received
|
184
195
|
# part with the whole message, to be processed
|
185
196
|
# below (the sender and timestamp are the same
|
186
197
|
# for all parts, so no change needed there)
|
187
|
-
|
198
|
+
msg_text = @multipart[from].join("")
|
188
199
|
@multipart.delete(from)
|
189
200
|
end
|
190
201
|
|
191
202
|
# just in case it wasn't already obvious...
|
192
|
-
log "Received message from #{from}: #{
|
203
|
+
log "Received message from #{from}: #{msg_text.inspect}"
|
193
204
|
|
194
205
|
# store the incoming data to be picked up
|
195
206
|
# from the attr_accessor as a tuple (this
|
196
207
|
# is kind of ghetto, and WILL change later)
|
197
208
|
sent = parse_incoming_timestamp(timestamp)
|
198
|
-
|
209
|
+
msg = Gsm::Incoming.new(self, from, sent, msg_text)
|
210
|
+
@incoming.push(msg)
|
199
211
|
end
|
200
212
|
|
201
213
|
# drop the two CMT lines (meta-info and message),
|
@@ -313,7 +325,7 @@ class Modem
|
|
313
325
|
# then automatically re-try the command after
|
314
326
|
# a short delay. for others, propagate
|
315
327
|
rescue Error => err
|
316
|
-
log "Rescued: #{err.desc}"
|
328
|
+
log "Rescued (in #command): #{err.desc}"
|
317
329
|
|
318
330
|
if (err.type == "CMS") and (err.code == 515)
|
319
331
|
sleep 2
|
@@ -326,6 +338,24 @@ class Modem
|
|
326
338
|
end
|
327
339
|
|
328
340
|
|
341
|
+
# proxy a single command to #command, but catch any
|
342
|
+
# Gsm::Error exceptions that are raised, and return
|
343
|
+
# nil. This should be used to issue commands which
|
344
|
+
# aren't vital - of which there are VERY FEW.
|
345
|
+
def try_command(cmd, *args)
|
346
|
+
begin
|
347
|
+
log_incr "Trying Command: #{cmd}"
|
348
|
+
out = command(cmd, *args)
|
349
|
+
log_decr "=#{out}"
|
350
|
+
return out
|
351
|
+
|
352
|
+
rescue Error => err
|
353
|
+
log_then_decr "Rescued (in #try_command): #{err.desc}"
|
354
|
+
return nil
|
355
|
+
end
|
356
|
+
end
|
357
|
+
|
358
|
+
|
329
359
|
def query(cmd)
|
330
360
|
log_incr "Query: #{cmd}"
|
331
361
|
out = command cmd
|
@@ -352,7 +382,7 @@ class Modem
|
|
352
382
|
while true do
|
353
383
|
buf = read(term)
|
354
384
|
buffer.push(buf)
|
355
|
-
|
385
|
+
|
356
386
|
# some errors contain useful error codes,
|
357
387
|
# so raise a proper error with a description
|
358
388
|
if m = buf.match(/^\+(CM[ES]) ERROR: (\d+)$/)
|
@@ -646,15 +676,38 @@ class Modem
|
|
646
676
|
# send_sms(message) => true or false
|
647
677
|
# send_sms(recipient, text) => true or false
|
648
678
|
#
|
679
|
+
# Sends an SMS message via _send_sms!_, but traps
|
680
|
+
# any exceptions raised, and returns false instead.
|
681
|
+
# Use this when you don't really care if the message
|
682
|
+
# was sent, which is... never.
|
683
|
+
def send_sms(*args)
|
684
|
+
begin
|
685
|
+
send_sms!(*args)
|
686
|
+
return true
|
687
|
+
|
688
|
+
# something went wrong
|
689
|
+
rescue Gsm::Error
|
690
|
+
return false
|
691
|
+
end
|
692
|
+
end
|
693
|
+
|
694
|
+
|
695
|
+
# call-seq:
|
696
|
+
# send_sms!(message) => true or raises Gsm::Error
|
697
|
+
# send_sms!(receipt, text) => true or raises Gsm::Error
|
698
|
+
#
|
649
699
|
# Sends an SMS message, and returns true if the network
|
650
700
|
# accepted it for delivery. We currently can't handle read
|
651
|
-
# receipts, so have no way of confirming delivery.
|
701
|
+
# receipts, so have no way of confirming delivery. If the
|
702
|
+
# device or network rejects the message, a Gsm::Error is
|
703
|
+
# raised containing (hopefully) information about what went
|
704
|
+
# wrong.
|
652
705
|
#
|
653
706
|
# Note: the recipient is passed directly to the modem, which
|
654
707
|
# in turn passes it straight to the SMSC (sms message center).
|
655
|
-
#
|
708
|
+
# For maximum compatibility, use phone numbers in international
|
656
709
|
# format, including the *plus* and *country code*.
|
657
|
-
def send_sms(*args)
|
710
|
+
def send_sms!(*args)
|
658
711
|
|
659
712
|
# extract values from Outgoing object.
|
660
713
|
# for now, this does not offer anything
|
@@ -699,6 +752,9 @@ class Modem
|
|
699
752
|
# the text prompt or an error message
|
700
753
|
command "AT+CMGS=\"#{to}\"", ["\r\n", "> "]
|
701
754
|
|
755
|
+
# encode the message using the setup encoding or the default
|
756
|
+
msg = encode(msg)
|
757
|
+
|
702
758
|
begin
|
703
759
|
# send the sms, and wait until
|
704
760
|
# it is accepted or rejected
|
@@ -712,26 +768,51 @@ class Modem
|
|
712
768
|
# an escpae, to... escape
|
713
769
|
rescue Exception, Timeout::Error => err
|
714
770
|
log "Rescued #{err.desc}"
|
715
|
-
|
716
|
-
|
717
|
-
#
|
771
|
+
write 27.chr
|
772
|
+
|
773
|
+
# allow the error to propagate,
|
774
|
+
# so the application can catch
|
775
|
+
# it for more useful info
|
776
|
+
raise
|
777
|
+
|
778
|
+
ensure
|
779
|
+
log_decr
|
718
780
|
end
|
719
|
-
|
720
|
-
log_decr
|
721
781
|
end
|
722
782
|
|
723
783
|
# if no error was raised,
|
724
784
|
# then the message was sent
|
725
785
|
return true
|
726
786
|
end
|
727
|
-
|
728
|
-
|
787
|
+
|
788
|
+
# Encodes the message using the set encoding or, if no encoding is specified
|
789
|
+
# returns the msg unchange
|
790
|
+
def encode(msg)
|
791
|
+
if (@encoding == :ascii)
|
792
|
+
# TODO, use lucky sneaks here
|
793
|
+
msg
|
794
|
+
elsif (@encoding == :utf8)
|
795
|
+
# Unpacking and repacking supposedly cleans out bad (non-UTF-8) stuff
|
796
|
+
utf8 = msg.unpack("U*");
|
797
|
+
packed = utf8.pack("U*");
|
798
|
+
packed
|
799
|
+
elsif (@encoding == :ucs2)
|
800
|
+
ucs2 = Iconv.iconv("UCS-2", "UTF-8", msg).first
|
801
|
+
ucs2 = ucs2.unpack("H*").join
|
802
|
+
ucs2
|
803
|
+
else
|
804
|
+
msg
|
805
|
+
end
|
806
|
+
end
|
807
|
+
|
729
808
|
# call-seq:
|
730
809
|
# receive(callback_method, interval=5, join_thread=false)
|
731
810
|
#
|
732
811
|
# Starts a new thread, which polls the device every _interval_
|
733
812
|
# seconds to capture incoming SMS and call _callback_method_
|
734
|
-
# for each
|
813
|
+
# for each, and polls the device's internal storage for incoming
|
814
|
+
# SMS that we weren't notified about (some modems don't support
|
815
|
+
# that).
|
735
816
|
#
|
736
817
|
# class Receiver
|
737
818
|
# def incoming(msg)
|
@@ -760,15 +841,25 @@ class Modem
|
|
760
841
|
# keep on receiving forever
|
761
842
|
while true
|
762
843
|
command "AT"
|
763
|
-
|
764
|
-
|
765
|
-
# enable new message notification mode
|
766
|
-
# every ten intevals, in case the
|
844
|
+
|
845
|
+
# enable new message notification mode every ten intevals, in case the
|
767
846
|
# modem "forgets" (power cycle, etc)
|
768
847
|
if (@polled % 10) == 0
|
769
|
-
|
848
|
+
try_command("AT+CNMI=2,2,0,0,0")
|
770
849
|
end
|
850
|
+
|
851
|
+
# check for messages in the default mailbox (wether read or not)
|
852
|
+
# read them and then delete them
|
853
|
+
if (@keep_inbox_empty)
|
854
|
+
fetch_and_delete_stored_messages
|
855
|
+
end
|
771
856
|
|
857
|
+
# check for new messages lurking in the device's
|
858
|
+
# memory (in case we missed them (yes, it happens))
|
859
|
+
if (@polled % 4) == 0
|
860
|
+
fetch_stored_messages
|
861
|
+
end
|
862
|
+
|
772
863
|
# if there are any new incoming messages,
|
773
864
|
# iterate, and pass each to the receiver
|
774
865
|
# in the same format that they were built
|
@@ -800,7 +891,32 @@ class Modem
|
|
800
891
|
# threaded (like debugging handsets)
|
801
892
|
@thr.join if join_thread
|
802
893
|
end
|
894
|
+
|
803
895
|
|
896
|
+
def encodings?
|
897
|
+
command "AT+CSCS=?"
|
898
|
+
end
|
899
|
+
|
900
|
+
def encoding
|
901
|
+
@encoding
|
902
|
+
end
|
903
|
+
|
904
|
+
def encoding=(enc)
|
905
|
+
@encoding = enc
|
906
|
+
case enc
|
907
|
+
when :ascii
|
908
|
+
command "AT+CSCS=\"ASCII\""
|
909
|
+
when :utf8
|
910
|
+
command "AT+CSCS=\"UTF8\""
|
911
|
+
when :ucs2
|
912
|
+
command "AT+CSCS=\"UCS2\""
|
913
|
+
when :gsm
|
914
|
+
command "AT+CSCS=\"GSM\""
|
915
|
+
when :iso88591
|
916
|
+
command "AT+CSCS=\"8859-1\""
|
917
|
+
end
|
918
|
+
end
|
919
|
+
|
804
920
|
def select_default_mailbox
|
805
921
|
# Eventually we will select the first mailbox as the default
|
806
922
|
result = command("AT+CPMS=?")
|
@@ -813,8 +929,8 @@ class Modem
|
|
813
929
|
nil
|
814
930
|
end
|
815
931
|
|
816
|
-
|
817
|
-
|
932
|
+
def fetch_and_delete_stored_messages
|
933
|
+
# If there is no way to select a default mailbox we can't continue
|
818
934
|
return unless select_default_mailbox
|
819
935
|
|
820
936
|
# Try to read the first message from the box (should this be 0?)
|
@@ -847,5 +963,56 @@ class Modem
|
|
847
963
|
@incoming.push Gsm::Incoming.new(self, from, sent, msg)
|
848
964
|
end
|
849
965
|
|
966
|
+
def fetch_stored_messages
|
967
|
+
|
968
|
+
# fetch all/unread (see constant) messages
|
969
|
+
lines = command('AT+CMGL="%s"' % CMGL_STATUS)
|
970
|
+
n = 0
|
971
|
+
|
972
|
+
# if the last line returned is OK
|
973
|
+
# (and it SHOULD BE), remove it
|
974
|
+
lines.pop if lines[-1] == "OK"
|
975
|
+
|
976
|
+
# keep on iterating the data we received,
|
977
|
+
# until there's none left. if there were no
|
978
|
+
# stored messages waiting, this done nothing!
|
979
|
+
while n < lines.length
|
980
|
+
|
981
|
+
# attempt to parse the CMGL line (we're skipping
|
982
|
+
# two lines at a time in this loop, so we will
|
983
|
+
# always land at a CMGL line here) - they look like:
|
984
|
+
# +CMGL: 0,"REC READ","+13364130840",,"09/03/04,21:59:31-20"
|
985
|
+
unless m = lines[n].match(/^\+CMGL: (\d+),"(.+?)","(.+?)",*?,"(.+?)".*?$/)
|
986
|
+
err = "Couldn't parse CMGL data: #{lines[n]}"
|
987
|
+
raise RuntimeError.new(err)
|
988
|
+
end
|
989
|
+
|
990
|
+
# find the index of the next
|
991
|
+
# CMGL line, or the end
|
992
|
+
nn = n+1
|
993
|
+
nn += 1 until\
|
994
|
+
nn >= lines.length ||\
|
995
|
+
lines[nn][0,6] == "+CMGL:"
|
996
|
+
|
997
|
+
# extract the meta-info from the CMGL line, and the
|
998
|
+
# message text from the lines between _n_ and _nn_
|
999
|
+
index, status, from, timestamp = *m.captures
|
1000
|
+
msg_text = lines[(n+1)..(nn-1)].join("\n").strip
|
1001
|
+
|
1002
|
+
# log the incoming message
|
1003
|
+
log "Fetched stored message from #{from}: #{msg_text.inspect}"
|
1004
|
+
|
1005
|
+
# store the incoming data to be picked up
|
1006
|
+
# from the attr_accessor as a tuple (this
|
1007
|
+
# is kind of ghetto, and WILL change later)
|
1008
|
+
sent = parse_incoming_timestamp(timestamp)
|
1009
|
+
msg = Gsm::Incoming.new(self, from, sent, msg_text)
|
1010
|
+
@incoming.push(msg)
|
1011
|
+
|
1012
|
+
# skip over the messge line(s),
|
1013
|
+
# on to the next CMGL line
|
1014
|
+
n = nn
|
1015
|
+
end
|
1016
|
+
end
|
850
1017
|
end # Modem
|
851
1018
|
end # Gsm
|
data/lib/rubygsm/errors.rb
CHANGED
data/lib/rubygsm/log.rb
CHANGED
@@ -15,7 +15,31 @@ class Modem
|
|
15
15
|
:warn => 2,
|
16
16
|
:error => 1 }
|
17
17
|
|
18
|
+
def log_init
|
19
|
+
fn_port = File.basename(@port)
|
20
|
+
fn_time = Time.now.strftime("%Y-%m-%d.%H-%M-%S")
|
21
|
+
|
22
|
+
# (re-) open the full log file
|
23
|
+
filename = "rubygsm.#{fn_port}.#{fn_time}"
|
24
|
+
@log = File.new filename, "w"
|
25
|
+
|
26
|
+
# dump some useful information
|
27
|
+
# at the top, for debugging
|
28
|
+
log "RUBYGSM"
|
29
|
+
log " port: #{@port}"
|
30
|
+
log " timeout: #{@read_timeout}"
|
31
|
+
log " verbosity: #{@verbosity}"
|
32
|
+
log " started at: #{Time.now}"
|
33
|
+
log "===="
|
34
|
+
end
|
35
|
+
|
18
36
|
def log(msg, level=:debug)
|
37
|
+
|
38
|
+
# abort if logging isn't
|
39
|
+
# enabled yet (or ever?)
|
40
|
+
return false if\
|
41
|
+
@log.nil?
|
42
|
+
|
19
43
|
ind = " " * (@log_indents[Thread.current] or 0)
|
20
44
|
|
21
45
|
# create a
|
data/lib/rubygsm/msg/incoming.rb
CHANGED
@@ -21,8 +21,11 @@ module Gsm
|
|
21
21
|
@received = Time.now
|
22
22
|
end
|
23
23
|
|
24
|
-
|
25
|
-
|
24
|
+
# Returns the sender of this message,
|
25
|
+
# so incoming and outgoing messages
|
26
|
+
# can be logged in the same way.
|
27
|
+
def number
|
28
|
+
sender
|
26
29
|
end
|
27
30
|
end
|
28
31
|
end
|
data/lib/rubygsm/msg/outgoing.rb
CHANGED
data/rubygsm.gemspec
CHANGED
@@ -1,11 +1,11 @@
|
|
1
1
|
Gem::Specification.new do |s|
|
2
2
|
s.name = "rubygsm"
|
3
|
-
s.version = "0.
|
4
|
-
s.date = "2009-
|
3
|
+
s.version = "0.5.0"
|
4
|
+
s.date = "2009-03-12"
|
5
5
|
s.summary = "Send and receive SMS with a GSM modem"
|
6
6
|
s.email = "adam.mckaig@gmail.com"
|
7
7
|
s.homepage = "http://github.com/adammck/rubygsm"
|
8
|
-
s.authors = ["Adam Mckaig"]
|
8
|
+
s.authors = ["Adam Mckaig", "Jeff Rafter"]
|
9
9
|
s.has_rdoc = true
|
10
10
|
|
11
11
|
s.files = [
|
@@ -17,12 +17,14 @@ Gem::Specification.new do |s|
|
|
17
17
|
"lib/rubygsm/log.rb",
|
18
18
|
"lib/rubygsm/msg/incoming.rb",
|
19
19
|
"lib/rubygsm/msg/outgoing.rb",
|
20
|
-
"bin/gsm-modem-band"
|
20
|
+
"bin/gsm-modem-band",
|
21
|
+
"bin/gsm-app-monitor"
|
21
22
|
]
|
22
23
|
|
23
24
|
s.executables = [
|
24
|
-
"gsm-modem-band"
|
25
|
+
"gsm-modem-band",
|
26
|
+
"sms"
|
25
27
|
]
|
26
28
|
|
27
|
-
|
29
|
+
s.add_dependency("toholio-serialport", ["> 0.7.1"])
|
28
30
|
end
|
metadata
CHANGED
@@ -1,22 +1,33 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: jeffrafter-rubygsm
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.5.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Adam Mckaig
|
8
|
+
- Jeff Rafter
|
8
9
|
autorequire:
|
9
10
|
bindir: bin
|
10
11
|
cert_chain: []
|
11
12
|
|
12
|
-
date: 2009-
|
13
|
+
date: 2009-03-12 00:00:00 -07:00
|
13
14
|
default_executable:
|
14
|
-
dependencies:
|
15
|
-
|
15
|
+
dependencies:
|
16
|
+
- !ruby/object:Gem::Dependency
|
17
|
+
name: toholio-serialport
|
18
|
+
type: :runtime
|
19
|
+
version_requirement:
|
20
|
+
version_requirements: !ruby/object:Gem::Requirement
|
21
|
+
requirements:
|
22
|
+
- - ">"
|
23
|
+
- !ruby/object:Gem::Version
|
24
|
+
version: 0.7.1
|
25
|
+
version:
|
16
26
|
description:
|
17
27
|
email: adam.mckaig@gmail.com
|
18
28
|
executables:
|
19
29
|
- gsm-modem-band
|
30
|
+
- sms
|
20
31
|
extensions: []
|
21
32
|
|
22
33
|
extra_rdoc_files: []
|
@@ -31,6 +42,7 @@ files:
|
|
31
42
|
- lib/rubygsm/msg/incoming.rb
|
32
43
|
- lib/rubygsm/msg/outgoing.rb
|
33
44
|
- bin/gsm-modem-band
|
45
|
+
- bin/gsm-app-monitor
|
34
46
|
has_rdoc: true
|
35
47
|
homepage: http://github.com/adammck/rubygsm
|
36
48
|
post_install_message:
|