nosy 0.0.3 → 0.0.4

Sign up to get free protection for your applications and to get access to all the features.
data/.gitignore ADDED
@@ -0,0 +1 @@
1
+ .DS_Store
data/.rspec ADDED
@@ -0,0 +1 @@
1
+ --color
data/README.md ADDED
@@ -0,0 +1,113 @@
1
+ # Nosy
2
+
3
+ **Output, backup, and read all your iPhone text messages.**
4
+
5
+ Nosy extracts text messages from the native iOS (iPhone, iPad) database stored on your computer after each backup and organizes it into an array of easily explorable messages.
6
+
7
+ Nosy returns an array of messages with the fields
8
+
9
+ * receiver
10
+ * sender
11
+ * message
12
+ * imessage (Boolean)
13
+ * date (contains a unix timestamp)
14
+
15
+
16
+ ## Install
17
+
18
+ $ gem install nosy
19
+
20
+ Or add Nosy to your Gemfile and run `bundle install`.
21
+
22
+ ## Find and Parse
23
+ If you are on a Mac OSX system, Nosy (is nosy, and) will try to grab your iOS message database and parse it.
24
+
25
+ all_texts = Nosy.hunt_and_parse
26
+
27
+ all_texts.each do |text|
28
+ text.receiver
29
+ text.sender
30
+ text.message
31
+ text.imessage
32
+ text.date
33
+ end
34
+
35
+
36
+ ## Location
37
+ The location of the folder storing the iOS message backups in Mac OSX is
38
+
39
+ $ ~/Library/Application Support/MobileSync/Backup/
40
+
41
+ Each of the folders will represent an Apple device. Within your desired device's folder, the iOS message database will be the file entitled `3d0d7e5fb2ce288813306e4d4636395e047a3d28`
42
+
43
+
44
+ ### Hunt
45
+
46
+ If you are on Mac OSX running Nosy.hunt will return a String with the location of the first parseable iOS message database if there is one.
47
+
48
+ require 'nosy'
49
+
50
+ new_text_backup_file_location = Nosy.hunt
51
+
52
+
53
+ ## Parsing
54
+
55
+ If you pass in an iOS message database, Nosy can detect if a file can be parsed as an iPhone database.
56
+
57
+ valid = Nosy.can_parse?(iphone_database_location)
58
+
59
+ Also, Nosy can parse the file and return an array of all available text messages.
60
+
61
+ all_texts = Nosy.parse(iphone_database_location)
62
+
63
+ all_texts.each do |text|
64
+ text.receiver
65
+ text.sender
66
+ text.message
67
+ text.imessage
68
+ text.date
69
+ end
70
+
71
+ ## Searching
72
+
73
+ Nosy can search through the texts in your iOS message database. Nosy searching supports any combination of the following keys:
74
+
75
+ * receiver
76
+ * sender
77
+ * message
78
+ * imessage
79
+ * date - supports a Unix timestamp and an optional leading operator [ < , > , <= , >= ]
80
+
81
+ #
82
+
83
+ nosty_texts = Nosy.new(iphone_database_location)
84
+
85
+ # Array of texts where I am the sender
86
+ my_sent_texts = nosty_texts.search(:sender => "me")
87
+
88
+ # Array of texts where the date is less than 1273175931
89
+ before_then_texts = nosty_texts.search(:date => "<1273175931")
90
+
91
+ # Array of texts where I am the sender and the date is less than 1273175931
92
+ before_then_texts = nosty_texts.search(:sender => "me", :date => "<1273175931")
93
+
94
+ ## Contributions
95
+ Contributions, improvements, and suggestions more than welcome! Please!
96
+
97
+ ### Some Ideas
98
+
99
+ Currently, Nosy is yet to...
100
+
101
+ * Properly handle MMS (group and media) messages.
102
+ * Let you search for two values in one key.
103
+ * Let you hunt for the iOS message database on systems other than Mac OSX.
104
+ * Support creating a backup file.
105
+ * Run on Heroku due to its dependency on Sqlite3.
106
+
107
+ ## Acknowledgment
108
+
109
+ * For a similar implementation in Python check out [iPhone SMS Backup](https://github.com/toffer/iphone-sms-backup/)
110
+ * Inspiration from Gabe Berke-Williams's [Chat Stew](https://github.com/gabebw/chat_stew)
111
+ * [Mike Coutermarsh](https://github.com/mscoutermarsh)
112
+ * [Sarah Canieso](https://github.com/scanieso)
113
+ * [Eric Kelly](https://github.com/HeroicEric) - Providing additional SMS Databases
data/lib/.DS_Store ADDED
Binary file
data/lib/nosy/hunter.rb CHANGED
@@ -1,16 +1,16 @@
1
- require 'fileutils'
2
-
3
1
  module Nosy
4
2
 
5
- class Hunter
6
-
7
- def hunt
8
- if RUBY_PLATFORM =~ /darwin/
9
- FileUtils.cp "#{Dir.home}/Library/Application Support/MobileSync/Backup/55e67384ae82dd8a317f29585e1d7b5884e43107/3d0d7e5fb2ce288813306e4d4636395e047a3d28", "#{FileUtils.pwd}/texts.sqlite"
10
- "#{FileUtils.pwd}/texts.sqlite"
11
- end
12
- end
13
-
14
- end
3
+ class Hunter
15
4
 
5
+ def hunt
6
+ if RUBY_PLATFORM =~ /darwin/
7
+ Dir[File.join("#{Dir.home}/Library/Application Support/MobileSync/Backup", "*")].select{|file| File.ftype(file) == "directory"}.each do |folder|
8
+ if Nosy.can_parse?(folder+"/3d0d7e5fb2ce288813306e4d4636395e047a3d28")
9
+ return "#{folder}/3d0d7e5fb2ce288813306e4d4636395e047a3d28"
10
+ end
11
+ end
12
+ end
13
+
14
+ end
15
+ end
16
16
  end
@@ -0,0 +1,24 @@
1
+ module Nosy
2
+
3
+ class Parser
4
+
5
+ module Imessage
6
+
7
+ def sent_imessage( parsed_message, message )
8
+ parsed_message.receiver = format_address(message[7])
9
+ parsed_message.sender = "me"
10
+ end
11
+
12
+ def received_imessage( parsed_message, message )
13
+ parsed_message.receiver = "me"
14
+ parsed_message.sender = format_address(message[7])
15
+ end
16
+
17
+ def sent_group_imessage( parsed_message, message )
18
+ parsed_message.sender = "me"
19
+ parsed_message.receiver = "group"
20
+ end
21
+ end
22
+ end
23
+
24
+ end
@@ -0,0 +1,50 @@
1
+ module Nosy
2
+
3
+ class Parser
4
+
5
+ module MessageSupport
6
+
7
+ def find_all_messages( file )
8
+ SQLite3::Database.new( file ).execute( "select rowid, date, address, text, flags, is_madrid, madrid_flags, madrid_handle from message" )
9
+ end
10
+
11
+ def parse_imessage( parsed_message, message )
12
+ parsed_message.imessage = true
13
+ parsed_message.date = imessage_time_to_unixtime(message[1])
14
+
15
+ if message[6] == 36869
16
+ sent_imessage( parsed_message, message )
17
+ elsif message[6] == 12289
18
+ received_imessage( parsed_message, message )
19
+ elsif message[6] == 32773
20
+ sent_group_imessage( parsed_message, message )
21
+ end
22
+ end
23
+
24
+ def parse_sms_message( parsed_message, message )
25
+ parsed_message.imessage = false
26
+ parsed_message.date = message[1]
27
+
28
+ if message[4] == 3 || message[4] == 35 || message[4] == 33 || message[4] == 16387
29
+ sent_sms_message( parsed_message, message )
30
+ elsif message[4] == 2
31
+ received_sms_message( parsed_message, message )
32
+ end
33
+ end
34
+
35
+ private
36
+
37
+ def imessage_time_to_unixtime( imessage_time )
38
+ imessage_time + 978307200
39
+ end
40
+
41
+ def format_address(address)
42
+ if !address.nil?
43
+ address = address.gsub(/\s+|[()-]/, "")
44
+ address =~ /^[0-9]+$/ ? "+"+address : address
45
+ end
46
+ end
47
+ end
48
+ end
49
+
50
+ end
@@ -0,0 +1,28 @@
1
+ module Nosy
2
+
3
+ class Parser
4
+
5
+ module ParseChecks
6
+
7
+ def has_messages_table( database )
8
+ begin
9
+ database.execute2( "select rowid, date, address, text, flags, is_madrid, madrid_flags, madrid_handle from message" )
10
+ rescue SQLite3::SQLException
11
+ return false
12
+ rescue SQLite3::NotADatabaseException
13
+ return false
14
+ end
15
+ end
16
+
17
+ def is_iphone_database( results )
18
+ if ( results[0][0] == "ROWID" && results[0][1] == "date" && results[0][2] == "address" && results[0][3] == "text" && results[0][4] == "flags" && results[0][5] == "is_madrid" && results[0][6] == "madrid_flags" && results[0][7] == "madrid_handle") && results.count > 1
19
+ return true
20
+ else
21
+ return false
22
+ end
23
+ end
24
+
25
+ end
26
+ end
27
+
28
+ end
@@ -0,0 +1,20 @@
1
+ module Nosy
2
+
3
+ class Parser
4
+
5
+ module Smsmessage
6
+
7
+ def sent_sms_message( parsed_message, message )
8
+ parsed_message.receiver = format_address(message[2])
9
+ parsed_message.sender = "me"
10
+ end
11
+
12
+ def received_sms_message( parsed_message, message )
13
+ parsed_message.receiver = "me"
14
+ parsed_message.sender = format_address(message[2])
15
+ end
16
+
17
+ end
18
+ end
19
+
20
+ end
data/lib/nosy/parser.rb CHANGED
@@ -1,110 +1,37 @@
1
1
  require 'sqlite3'
2
+ require 'nosy/parser/parse_checks'
3
+ require 'nosy/parser/message_support'
4
+ require 'nosy/parser/imessage'
5
+ require 'nosy/parser/smsmessage'
2
6
 
3
7
  Message = Struct.new(:receiver, :sender, :message, :imessage, :date)
4
8
 
5
9
  module Nosy
6
10
 
7
- class Parser
8
-
9
- def can_parse?(file)
10
- begin
11
- db = SQLite3::Database.new( file )
12
- begin
13
- results = db.execute2( "select * from message LIMIT 1" )
14
- results.map do |header|
15
- if ( header[0] == "ROWID" && header[1] == "address" && header[2] == "date" && header[3] == "text" && header[4] == "flags" && header[16] == "read")
16
- return true
17
- else
18
- return false
19
- end
20
- end
21
- rescue SQLite3::SQLException
22
- return false
23
- end
24
- rescue SQLite3::NotADatabaseException
25
- return false
26
- end
27
-
28
- end
29
-
30
- def parse(file)
31
- db = SQLite3::Database.new( file )
32
- all_messages = db.execute( "select * from message" )
33
-
34
- all_messages.map do |message|
35
-
36
- # http://www.slideshare.net/hrgeeks/iphone-forensics-without-the-iphone
37
- # http://www.scip.ch/?labs.20111103
38
-
39
- parsed_message = Message.new("", "", message[3], "", "")
40
-
41
- ## If it is an iMessage
42
- if message[29] == 1
43
- parsed_message.imessage = true
44
- parsed_message.date = message[2] + 978307200
45
-
46
- # Sent an iMessage
47
- if message[25] == 36869
48
- parsed_message.receiver = format_address(message[18])
49
- parsed_message.sender = "me"
50
-
51
- # Recieved an iMessage
52
- elsif message[25] == 12289
53
- parsed_message.receiver = "me"
54
- parsed_message.sender = format_address(message[18])
55
-
56
- # Sent a group iMessage
57
- elsif message[25] == 32773
58
- parsed_message.sender = "me"
59
- parsed_message.receiver = "group"
60
- end
61
-
62
- ## It is an SMS
63
- else
64
-
65
- parsed_message.imessage = false
66
- parsed_message.date = message[2]
67
-
68
- # Sent SMS
69
- if message[4] == 3
70
- parsed_message.receiver = format_address(message[1])
71
- parsed_message.sender = "me"
72
-
73
- # Recieved an SMS
74
- elsif message[4] == 2
75
- parsed_message.receiver = "me"
76
- parsed_message.sender = format_address(message[1])
77
-
78
- # Sent SMS on retry
79
- elsif message[4] == 35
80
- parsed_message.receiver = format_address(message[1])
81
- parsed_message.sender = "me"
82
-
83
- # SMS Failed
84
- elsif message[4] == 33
85
- parsed_message.receiver = format_address(message[1])
86
- parsed_message.sender = "me"
87
-
88
- # iMessage Failed and sent as SMS
89
- elsif message[4] == 16387
90
- parsed_message.receiver = format_address(message[1])
91
- parsed_message.sender = "me"
92
- end
93
-
94
- end
95
-
96
- parsed_message
97
- end
98
- end
99
-
100
- private
101
- def format_address(address)
102
- if !address.nil?
103
- address = address.gsub(/\s+|[()-]/, "")
104
- address =~ /^[0-9]+$/ ? "+"+address : address
105
- end
106
- end
107
-
108
- end
11
+ class Parser
12
+
13
+ include MessageSupport
14
+ include ParseChecks
15
+ include Imessage
16
+ include Smsmessage
17
+
18
+ def can_parse?(file)
19
+ db = SQLite3::Database.new( file )
20
+ results = has_messages_table(db)
21
+ db != false && results != false ? is_iphone_database( results ) : false
22
+ end
23
+
24
+ def parse(file)
25
+ find_all_messages( file ).map do |message|
26
+ parsed_message = Message.new("", "", message[3], "", "")
27
+ if message[5] == 1
28
+ parse_imessage( parsed_message, message)
29
+ else
30
+ parse_sms_message( parsed_message, message)
31
+ end
32
+ parsed_message
33
+ end
34
+ end
35
+ end
109
36
 
110
37
  end
data/lib/nosy/searcher.rb CHANGED
@@ -1,35 +1,35 @@
1
1
  module Nosy
2
2
 
3
- class Searcher
4
- attr_accessor :texts
3
+ class Searcher
4
+ attr_accessor :texts
5
5
 
6
- def initialize( file )
7
- @texts = Parser.new.parse( file )
8
- end
6
+ def initialize( file )
7
+ @texts = Parser.new.parse( file )
8
+ end
9
9
 
10
- def search(filters={})
10
+ def search(filters={})
11
11
 
12
- @texts.select do |text|
13
- filters.all?{ |key, value| key == :date ? filter_dates(key, value, text) : text[key] == value }
14
- end
15
- end
12
+ @texts.select do |text|
13
+ filters.all?{ |key, value| key == :date ? filter_dates(key, value, text) : text[key] == value }
14
+ end
15
+ end
16
16
 
17
- private
17
+ private
18
18
 
19
- def filter_dates( key, value, text )
20
- if value[1] == "="
21
- value[0] == ">" ? Time.at(text[key]) >= Time.at(value[2..-1].to_i) : Time.at(text[key]) <= Time.at(value[2..-1].to_i)
22
- else
23
- if value[0] == ">"
24
- Time.at(text[key]) > Time.at(value[1..-1].to_i)
25
- elsif value[0] == "<"
26
- Time.at(text[key]) < Time.at(value[1..-1].to_i)
27
- else
28
- Time.at(text[key]) == Time.at(value.to_i)
29
- end
30
- end
31
- end
32
-
33
- end
19
+ def filter_dates( key, value, text )
20
+ if value[1] == "="
21
+ value[0] == ">" ? Time.at(text[key]) >= Time.at(value[2..-1].to_i) : Time.at(text[key]) <= Time.at(value[2..-1].to_i)
22
+ else
23
+ if value[0] == ">"
24
+ Time.at(text[key]) > Time.at(value[1..-1].to_i)
25
+ elsif value[0] == "<"
26
+ Time.at(text[key]) < Time.at(value[1..-1].to_i)
27
+ else
28
+ Time.at(text[key]) == Time.at(value.to_i)
29
+ end
30
+ end
31
+ end
32
+
33
+ end
34
34
 
35
35
  end
data/lib/nosy.rb CHANGED
@@ -4,19 +4,23 @@ require "nosy/searcher"
4
4
 
5
5
  module Nosy
6
6
 
7
- def self.hunt
8
- Hunter.new.hunt
9
- end
7
+ def self.hunt
8
+ Hunter.new.hunt
9
+ end
10
10
 
11
- def self.new(file)
12
- Searcher.new(file)
13
- end
11
+ def self.hunt_and_parse
12
+ Parser.new.parse(Hunter.new.hunt)
13
+ end
14
14
 
15
- def self.can_parse?(file)
16
- Parser.new.can_parse?(file)
17
- end
15
+ def self.new(file)
16
+ Searcher.new(file)
17
+ end
18
18
 
19
- def self.parse(file)
20
- Parser.new.parse(file)
21
- end
19
+ def self.can_parse?(file)
20
+ Parser.new.can_parse?(file)
21
+ end
22
+
23
+ def self.parse(file)
24
+ Parser.new.parse(file)
25
+ end
22
26
  end
data/nosy.gemspec ADDED
@@ -0,0 +1,13 @@
1
+ Gem::Specification.new do |gem|
2
+ gem.name = 'nosy'
3
+ gem.version = '0.0.4'
4
+ gem.date = '2012-01-02'
5
+ gem.summary = "Output, backup, and read all your iPhone text messages"
6
+ gem.description = "Nosy fetches, parses and searches the iPhone's SMS database that is created on your machine each time you make a backup."
7
+ gem.authors = ["Philip Dudley"]
8
+ gem.homepage = "https://github.com/pdud/Nosy"
9
+ gem.email = 'pdudley89@gmail.com'
10
+ gem.files = `git ls-files`.split("\n")
11
+ gem.add_dependency("sqlite3", "~> 1.3.4")
12
+ gem.add_development_dependency("rspec", "~> 2.6.0")
13
+ end
data/spec/.DS_Store ADDED
Binary file
Binary file
@@ -0,0 +1,13 @@
1
+ require 'nosy'
2
+
3
+ describe Nosy::Hunter, "#hunt" do
4
+
5
+ context "Mac OSX" do
6
+
7
+ it "returns the location of a valid iphone database" do
8
+ location = subject.hunt
9
+ Nosy::Parser.new.can_parse?(location).should == true
10
+ end
11
+ end
12
+
13
+ end
@@ -0,0 +1,207 @@
1
+ require 'nosy'
2
+
3
+ describe Nosy::Parser, "#can_parse?" do
4
+
5
+ let(:acceptable_iphone_database) { File.join('spec', 'support', 'db', 'texts.sqlite') }
6
+ let(:invalid_file_type_iphone_database) { File.join('spec', 'support', 'db', 'invalid_file_type_texts.txt') }
7
+ let(:empty_iphone_database) { File.join('spec', 'support', 'db', 'empty_iphone_database.sqlite') }
8
+ let(:missing_table_iphone_database) { File.join('spec', 'support', 'db', 'missing_table_texts.sqlite') }
9
+ let(:incorrect_format_iphone_database) { File.join('spec', 'support', 'db', 'incorrect_format_texts.sqlite') }
10
+ let(:missing_iphone_database) { File.join('spec', 'support', 'db', 'this_file_does_not_exist.sqlite') }
11
+
12
+ it "returns true for an iPhone Database" do
13
+ subject.can_parse?(acceptable_iphone_database).should == true
14
+ end
15
+
16
+ it "returns false for a file that is not a database" do
17
+ subject.can_parse?(invalid_file_type_iphone_database).should == false
18
+ end
19
+
20
+ it "returns false for a file that is an empty database" do
21
+ subject.can_parse?(empty_iphone_database).should == false
22
+ end
23
+
24
+ it "returns false for a file that is missing the messages table" do
25
+ subject.can_parse?(missing_table_iphone_database).should == false
26
+ end
27
+
28
+ it "returns false for a file that is missing the necessary fields in the messages table" do
29
+ subject.can_parse?(incorrect_format_iphone_database).should == false
30
+ end
31
+
32
+ it "returns false for a file that is missing" do
33
+ subject.can_parse?(missing_iphone_database).should == false
34
+ end
35
+
36
+ end
37
+
38
+ describe Nosy::Parser, "#parse(file)" do
39
+
40
+ let(:iphone_database) { File.join('spec', 'support', 'db', 'texts.sqlite') }
41
+ let(:parsed) { subject.parse(iphone_database) }
42
+
43
+ it "should parse each texts as a Messages" do
44
+ parsed[0].should be_a_kind_of Message
45
+ end
46
+
47
+ it "should parse the collection of texts as an Array" do
48
+ parsed.should be_a_kind_of Array
49
+ end
50
+
51
+
52
+ it "correctly parses the text" do
53
+ parsed[0].message.should == "Hey it's Phil. I'm moving some stuff to next years apartment at the mo. But you left stuff here so you should come round later to grab it."
54
+ parsed[3].message.should == "Hi :)"
55
+ end
56
+
57
+ context "SMS Messages" do
58
+
59
+ it "correctly detects the message as an iMessage" do
60
+ parsed[0].imessage.should == false
61
+ parsed[1].imessage.should == false
62
+ parsed[2].imessage.should == false
63
+ end
64
+
65
+ it "correctly parses the date" do
66
+ parsed[0].date.should == 1273175931
67
+ end
68
+
69
+ describe "Sent from me" do
70
+
71
+ it "correctly parses the sender" do
72
+ parsed[0].sender.should == "me"
73
+ end
74
+
75
+ it "correctly parses the receiver" do
76
+ parsed[0].receiver.should == "+1234567890"
77
+ end
78
+
79
+ end
80
+
81
+ describe "Sent to me" do
82
+
83
+ it "correctly parses the sender" do
84
+ parsed[1].sender.should == "+1234567890"
85
+ end
86
+
87
+ it "correctly parses the receiver" do
88
+ parsed[1].receiver.should == "me"
89
+ end
90
+
91
+ end
92
+
93
+ describe "Sent from me, Failed, then Succeded" do
94
+
95
+ it "correctly parses the sender" do
96
+ parsed[2].sender.should == "me"
97
+ end
98
+
99
+ it "correctly parses the receiver" do
100
+ parsed[2].receiver.should == "+1234567890"
101
+ end
102
+
103
+ end
104
+
105
+ describe "Sent from me and Failed" do
106
+
107
+ it "correctly parses the sender" do
108
+ parsed[7].sender.should == "me"
109
+ end
110
+
111
+ it "correctly parses the receiver" do
112
+ parsed[7].receiver.should == "+1234567890"
113
+ end
114
+
115
+ end
116
+
117
+ describe "iMessage Failed and sent as SMS" do
118
+
119
+ it "correctly parses the sender" do
120
+ parsed[5].sender.should == "me"
121
+ end
122
+
123
+ it "correctly parses the receiver" do
124
+ parsed[5].receiver.should == "+1234567890"
125
+ end
126
+
127
+ end
128
+
129
+ end
130
+
131
+ context "iMessages" do
132
+
133
+ it "correctly detects the message as an iMessage" do
134
+ parsed[3].imessage.should == true
135
+ parsed[4].imessage.should == true
136
+ end
137
+
138
+ it "correctly parses the date" do
139
+ parsed[3].date.should == 1318524672
140
+ parsed[4].date.should == 1318524796
141
+ end
142
+
143
+ describe "Sent to me" do
144
+
145
+ it "correctly parses the sender" do
146
+ parsed[3].sender.should == "user@gmail.com"
147
+ end
148
+
149
+ it "correctly parses the receiver" do
150
+ parsed[3].receiver.should == "me"
151
+ end
152
+
153
+ end
154
+
155
+ describe "Sent from me" do
156
+
157
+ it "correctly parses the sender" do
158
+ parsed[4].sender.should == "me"
159
+ end
160
+
161
+ it "correctly parses the receiver" do
162
+ parsed[4].receiver.should == "user@gmail.com"
163
+ end
164
+
165
+ end
166
+
167
+ describe "Group message sent from me" do
168
+
169
+ it "correctly parses the sender" do
170
+ parsed[6].sender.should == "me"
171
+ end
172
+
173
+ it "correctly parses the receiver" do
174
+ parsed[6].receiver.should == "group"
175
+ end
176
+
177
+ end
178
+
179
+
180
+ end
181
+
182
+ describe Nosy::Parser, "#format_address" do
183
+
184
+ let(:parser) { subject }
185
+
186
+ it "does not format nil addresses" do
187
+ parser.send(:format_address, nil).should == nil
188
+ end
189
+
190
+ it "removes white space" do
191
+ parser.send(:format_address, "my address").should == "myaddress"
192
+ end
193
+
194
+ it "removes parenthesis" do
195
+ parser.send(:format_address, "my(address)").should == "myaddress"
196
+ end
197
+
198
+ it "removes seperators" do
199
+ parser.send(:format_address, "my-address").should == "myaddress"
200
+ end
201
+
202
+ it "adds a + if it consists of all numbers" do
203
+ parser.send(:format_address, "1 (234) 567-8901").should == "+12345678901"
204
+ end
205
+
206
+ end
207
+ end
@@ -0,0 +1,103 @@
1
+ require 'nosy'
2
+
3
+ describe Nosy::Searcher, "#new" do
4
+
5
+ let(:iphone_database) { File.join('spec', 'support', 'db', 'texts.sqlite') }
6
+ let(:texts) { Nosy::Searcher.new( iphone_database ) }
7
+
8
+ it "should create a Nosy::Searcher class" do
9
+ texts.should be_a_kind_of Nosy::Searcher
10
+ end
11
+
12
+ it "should fill texts" do
13
+ texts.texts.should_not be nil
14
+ end
15
+
16
+ it "should fill texts with Messages" do
17
+ texts.texts[0].should be_a_kind_of Message
18
+ end
19
+
20
+ end
21
+
22
+ describe Nosy::Searcher, "#search" do
23
+
24
+ let(:iphone_database) { File.join('spec', 'support', 'db', 'texts.sqlite') }
25
+ let(:texts) { Nosy::Searcher.new( iphone_database ) }
26
+
27
+ it "should return all texts if no filters are passed in" do
28
+ texts.search().count.should == 8
29
+ texts.search().should == Nosy::Parser.new.parse( iphone_database )
30
+ end
31
+
32
+ it "should be searchable by sender" do
33
+ search = texts.search(:sender => "me").each do |text|
34
+ text.sender.should == "me"
35
+ end
36
+ search.count.should_not == 0
37
+ end
38
+
39
+ it "should be searchable by receiver" do
40
+ search = texts.search(:receiver => "me").each do |text|
41
+ text.receiver.should == "me"
42
+ end
43
+ search.count.should_not == 0
44
+ end
45
+
46
+ it "should be searchable by type of imessage" do
47
+ search = texts.search(:imessage => true).each do |text|
48
+ text.imessage.should == true
49
+ end
50
+ search.count.should_not == 0
51
+ end
52
+
53
+ it "should be searchable by text of message (full text)" do
54
+ search = texts.search(:message => "Here :)").each do |text|
55
+ text.message.should == "Here :)"
56
+ end
57
+ search.count.should_not == 0
58
+ end
59
+
60
+ it "should be searchable by date of message" do
61
+ search = texts.search(:date => "1320880443").each do |text|
62
+ text.date.should == 1320880443
63
+ end
64
+ search.count.should_not == 0
65
+ end
66
+
67
+ it "should be searchable by more than one field" do
68
+ search = texts.search(:sender => "me", :message => "Here :)").each do |text|
69
+ text.sender.should == "me"
70
+ text.message.should == "Here :)"
71
+ end
72
+ search.count.should_not == 0
73
+ end
74
+
75
+ it "should be searchable after a given date" do
76
+ search = texts.search(:date => ">1318524672").each do |text|
77
+ Time.at(text.date).should > Time.at(1318524672)
78
+ end
79
+ search.count.should_not == 0
80
+ end
81
+
82
+ it "should be searchable before a given date" do
83
+ search = texts.search(:date => "<1320880443").each do |text|
84
+ Time.at(text.date).should < Time.at(1320880443)
85
+ end
86
+ search.count.should_not == 0
87
+ end
88
+
89
+ it "should be searchable after and equal to a given date" do
90
+ search = texts.search(:date => ">=1318524672").each do |text|
91
+ Time.at(text.date).should >= Time.at(1318524672)
92
+ end
93
+ search.count.should_not == 0
94
+ end
95
+
96
+ it "should be searchable before and equal to a given date" do
97
+ search = texts.search(:date => "<=1320880443").each do |text|
98
+ Time.at(text.date).should <= Time.at(1320880443)
99
+ end
100
+ search.count.should_not == 0
101
+ end
102
+
103
+ end
data/spec/nosy_spec.rb ADDED
@@ -0,0 +1,48 @@
1
+ require 'nosy'
2
+
3
+ describe Nosy do
4
+
5
+ let(:iphone_database) { File.join('spec', 'support', 'db', 'texts.sqlite') }
6
+ let(:texts) { subject.new(iphone_database) }
7
+
8
+ describe "#hunt" do
9
+
10
+ it "should return the same results as a hunt" do
11
+ Nosy.hunt.should == Nosy::Hunter.new.hunt
12
+ end
13
+
14
+ end
15
+
16
+ describe "#new" do
17
+
18
+ it "should return the same results as a search" do
19
+ Nosy.new(iphone_database).texts.should == Nosy::Searcher.new(iphone_database).texts
20
+ end
21
+
22
+ end
23
+
24
+ describe "#hunt_and_parse" do
25
+
26
+ it "should get the database and parse it" do
27
+ Nosy.hunt_and_parse.should == Nosy::Parser.new.parse(Nosy::Hunter.new.hunt)
28
+ end
29
+
30
+ end
31
+
32
+ describe "#parse" do
33
+
34
+ it "should return the same results as a parse" do
35
+ Nosy.parse(iphone_database).should == Nosy::Parser.new.parse(iphone_database)
36
+ end
37
+
38
+ end
39
+
40
+ describe "#can_parse?" do
41
+
42
+ it "should return the same results as a parse" do
43
+ Nosy.can_parse?(iphone_database).should == Nosy::Parser.new.can_parse?(iphone_database)
44
+ end
45
+
46
+ end
47
+
48
+ end
Binary file
Binary file
@@ -0,0 +1 @@
1
+ We can't have this working!
File without changes
File without changes
Binary file
File without changes
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: nosy
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.3
4
+ version: 0.0.4
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,11 +9,11 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2011-11-24 00:00:00.000000000Z
12
+ date: 2012-01-02 00:00:00.000000000Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: sqlite3
16
- requirement: &70300181810560 !ruby/object:Gem::Requirement
16
+ requirement: &70203490284220 !ruby/object:Gem::Requirement
17
17
  none: false
18
18
  requirements:
19
19
  - - ~>
@@ -21,21 +21,10 @@ dependencies:
21
21
  version: 1.3.4
22
22
  type: :runtime
23
23
  prerelease: false
24
- version_requirements: *70300181810560
25
- - !ruby/object:Gem::Dependency
26
- name: fileutils
27
- requirement: &70300181810080 !ruby/object:Gem::Requirement
28
- none: false
29
- requirements:
30
- - - ~>
31
- - !ruby/object:Gem::Version
32
- version: '0.7'
33
- type: :runtime
34
- prerelease: false
35
- version_requirements: *70300181810080
24
+ version_requirements: *70203490284220
36
25
  - !ruby/object:Gem::Dependency
37
26
  name: rspec
38
- requirement: &70300181809620 !ruby/object:Gem::Requirement
27
+ requirement: &70203490283740 !ruby/object:Gem::Requirement
39
28
  none: false
40
29
  requirements:
41
30
  - - ~>
@@ -43,7 +32,7 @@ dependencies:
43
32
  version: 2.6.0
44
33
  type: :development
45
34
  prerelease: false
46
- version_requirements: *70300181809620
35
+ version_requirements: *70203490283740
47
36
  description: Nosy fetches, parses and searches the iPhone's SMS database that is created
48
37
  on your machine each time you make a backup.
49
38
  email: pdudley89@gmail.com
@@ -51,11 +40,36 @@ executables: []
51
40
  extensions: []
52
41
  extra_rdoc_files: []
53
42
  files:
43
+ - .gitignore
44
+ - .rspec
45
+ - README.md
46
+ - lib/.DS_Store
54
47
  - lib/nosy.rb
55
48
  - lib/nosy/hunter.rb
56
49
  - lib/nosy/parser.rb
50
+ - lib/nosy/parser/imessage.rb
51
+ - lib/nosy/parser/message_support.rb
52
+ - lib/nosy/parser/parse_checks.rb
53
+ - lib/nosy/parser/smsmessage.rb
57
54
  - lib/nosy/searcher.rb
58
- homepage: http://phildudley.com
55
+ - nosy-0.0.4.gem
56
+ - nosy.gemspec
57
+ - spec/.DS_Store
58
+ - spec/nosy/.DS_Store
59
+ - spec/nosy/hunter_spec.rb
60
+ - spec/nosy/parser_spec.rb
61
+ - spec/nosy/searcher_spec.rb
62
+ - spec/nosy_spec.rb
63
+ - spec/support/.DS_Store
64
+ - spec/support/db/.DS_Store
65
+ - spec/support/db/empty_iphone_database.sqlite
66
+ - spec/support/db/incorrect_format_texts.sqlite
67
+ - spec/support/db/invalid_file_type_texts.txt
68
+ - spec/support/db/missing_table_texts.sqlite
69
+ - spec/support/db/texts.db
70
+ - spec/support/db/texts.sqlite
71
+ - spec/support/db/this_file_does_not_exist.sqlite
72
+ homepage: https://github.com/pdud/Nosy
59
73
  licenses: []
60
74
  post_install_message:
61
75
  rdoc_options: []
@@ -78,7 +92,5 @@ rubyforge_project:
78
92
  rubygems_version: 1.8.10
79
93
  signing_key:
80
94
  specification_version: 3
81
- summary: Nosy fetches, parses and searches the iPhone's SMS database that is created
82
- on your machine each time you make a backup.
95
+ summary: Output, backup, and read all your iPhone text messages
83
96
  test_files: []
84
- has_rdoc: