bounce_studio_ffi 0.0.1 → 0.1.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/LICENSE.txt +1 -1
- data/README.md +21 -3
- data/Rakefile +10 -0
- data/bounce_studio_ffi.gemspec +2 -2
- data/lib/bounce_studio_ffi/version.rb +1 -1
- data/lib/bounce_studio_ffi.rb +11 -33
- data/test/bouncestudio_test.rb +99 -0
- data/test/raw_message.txt +50 -0
- data/test/test_helper.rb +9 -0
- metadata +11 -5
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: a67c70ab38153699c64aacffa59e9650f9f1b0c9
|
4
|
+
data.tar.gz: 1cd49f1a70faff6ba40c9d609a2db6aad824339e
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 57ff9c4d8299b238f4ccd19a8eecb87def1e0b762a8311f0351113741927cc1b0b037349504160cdbd2bec624fffefcbe1e163cb444eb73ad1047df4fe404879
|
7
|
+
data.tar.gz: 43120b862f6f3110a2a748a2be5c8f64248f07b45d1b0b0c9f4f86b4ed137829b54fc89cdac03c39512a61c4294c12fc87e0d618e041a0fe42f35478166dcac2
|
data/LICENSE.txt
CHANGED
data/README.md
CHANGED
@@ -1,9 +1,17 @@
|
|
1
|
-
#
|
1
|
+
# bounce\_studio\_ffi
|
2
2
|
|
3
|
-
|
3
|
+
A Ruby FFI binding for the (commercial) [BounceStudio API 3.7 for Linux](http://www.boogietools.com/Products/Linux/). Designed to be compatible with the included native extension.
|
4
|
+
|
5
|
+
## Requirements
|
6
|
+
|
7
|
+
* FFI-supporting Ruby 1.9+ (MRI/JRuby)
|
8
|
+
* Linux
|
9
|
+
* BounceStudio API libs
|
4
10
|
|
5
11
|
## Installation
|
6
12
|
|
13
|
+
Follow [these installation instructions](http://www.boogietools.com/Products/Linux/BounceStudioAPI/help/files/installation.html) to install the C API library.
|
14
|
+
|
7
15
|
Add this line to your application's Gemfile:
|
8
16
|
|
9
17
|
gem 'bounce_studio_ffi'
|
@@ -18,7 +26,17 @@ Or install it yourself as:
|
|
18
26
|
|
19
27
|
## Usage
|
20
28
|
|
21
|
-
|
29
|
+
# 32-bit lib is used by default; set ENV['BOUNCE_STUDIO_MODE'] to 64 to use 64-bit lib before requiring
|
30
|
+
require 'bounce_studio_ffi'
|
31
|
+
BS_LICENSE = "Foobar/1234567890"
|
32
|
+
bs = BoogieTools::BounceStudio.new(BS_LICENSE)
|
33
|
+
bs.check(raw_message_text)
|
34
|
+
|
35
|
+
# all functions documented at http://www.boogietools.com/Products/Linux/BounceStudioAPI/help/help.html
|
36
|
+
# are supported, e.g.
|
37
|
+
bs.subject(raw_message_text)
|
38
|
+
bs.orig_custom_header(raw_message_text, 'x-subscriber')
|
39
|
+
|
22
40
|
|
23
41
|
## Contributing
|
24
42
|
|
data/Rakefile
CHANGED
data/bounce_studio_ffi.gemspec
CHANGED
@@ -20,6 +20,6 @@ Gem::Specification.new do |spec|
|
|
20
20
|
|
21
21
|
spec.add_development_dependency "bundler", "~> 1.3"
|
22
22
|
spec.add_development_dependency "rake"
|
23
|
-
spec.
|
24
|
-
spec.
|
23
|
+
spec.add_runtime_dependency "ffi"
|
24
|
+
spec.add_runtime_dependency "activesupport"
|
25
25
|
end
|
data/lib/bounce_studio_ffi.rb
CHANGED
@@ -6,23 +6,23 @@ module BoogieTools
|
|
6
6
|
class BounceStudio
|
7
7
|
module BounceStudioLib
|
8
8
|
extend FFI::Library
|
9
|
-
ffi_lib "
|
9
|
+
ffi_lib "libBounceStudio#{ENV['BOUNCE_STUDIO_MODE'] || '32'}.so"
|
10
10
|
attach_function :bsBounceStudio_init, [], :int
|
11
11
|
|
12
|
-
|
13
|
-
|
12
|
+
STRING_OUTPUT_METHODS = [:header, :subject, :body, :to_address, :to_friendly_name, :reply_to_address, :reply_to_friendly_name, :from_address, :from_friendly_name].freeze
|
13
|
+
STRING_OUTPUT_METHODS.each do |ruby_method_name|
|
14
14
|
attach_function :"bsGet#{ruby_method_name.to_s.camelize}", [:string, :pointer], :void
|
15
15
|
end
|
16
|
-
attach_function :bsBounceCheck, [:string, :pointer, :string, :string], :int
|
17
16
|
|
18
17
|
CUSTOM_HEADER_METHODS = [:custom_header, :orig_custom_header].freeze
|
19
18
|
CUSTOM_HEADER_METHODS.each do |ruby_method_name|
|
20
19
|
attach_function :"bsGet#{ruby_method_name.to_s.camelize}", [:string, :pointer, :string], :void
|
21
20
|
end
|
22
21
|
|
23
|
-
attach_function :
|
22
|
+
attach_function :bsBounceCheck, [:string, :pointer, :string, :string], :int
|
24
23
|
end
|
25
24
|
|
25
|
+
# gotta call this before we do anything
|
26
26
|
BounceStudioLib.bsBounceStudio_init
|
27
27
|
|
28
28
|
attr_accessor :license
|
@@ -30,7 +30,7 @@ module BoogieTools
|
|
30
30
|
self.license=license
|
31
31
|
end
|
32
32
|
|
33
|
-
BounceStudioLib::
|
33
|
+
BounceStudioLib::STRING_OUTPUT_METHODS.each do |ruby_method_name|
|
34
34
|
define_method ruby_method_name do |raw_message|
|
35
35
|
string_output do |ptr|
|
36
36
|
BounceStudioLib.send(:"bsGet#{ruby_method_name.to_s.camelize}", raw_message, ptr)
|
@@ -44,13 +44,13 @@ module BoogieTools
|
|
44
44
|
BounceStudioLib.send(:"bsGet#{ruby_method_name.to_s.camelize}", raw_message, ptr, header_name)
|
45
45
|
end
|
46
46
|
end
|
47
|
-
end
|
48
|
-
|
47
|
+
end
|
49
48
|
|
50
|
-
|
49
|
+
# ignore list is pipe-delimited string of email addresses
|
50
|
+
def check(raw_message, ignore_list='')
|
51
51
|
code = nil
|
52
52
|
string_output do |ptr|
|
53
|
-
code = BounceStudioLib.bsBounceCheck(raw_message, ptr,
|
53
|
+
code = BounceStudioLib.bsBounceCheck(raw_message, ptr, ignore_list, self.license)
|
54
54
|
end
|
55
55
|
return code
|
56
56
|
end
|
@@ -66,26 +66,4 @@ module BoogieTools
|
|
66
66
|
end
|
67
67
|
end
|
68
68
|
|
69
|
-
end
|
70
|
-
|
71
|
-
|
72
|
-
{
|
73
|
-
:BS_UNDETERMINED => 0, # Undetermined
|
74
|
-
:BS_HARD => 10, # HARD BOUNCE
|
75
|
-
:BS_SOFT_GENERAL => 20, # SOFT BOUNCE - General
|
76
|
-
:BS_SOFT_DNSFAILURE => 21, # SOFT BOUNCE - Dns Failure
|
77
|
-
:BS_SOFT_MAILBOXFULL => 22, # SOFT BOUNCE - Mailbox Full
|
78
|
-
:BS_SOFT_MESSAGETOBIG => 23, # SOFT BOUNCE - Message Size Too Large
|
79
|
-
:BS_NOEMAIL => 30, # BOUNCE - email address could not be retrieved.
|
80
|
-
:BS_GENERAL => 40, # GENERAL BOUNCE
|
81
|
-
:BS_MAILBLOCK_GENERAL => 50, # MAIL BLOCK - General
|
82
|
-
:BS_MAILBLOCK_SPAMMER => 51, # MAIL BLOCK - Known Spammer
|
83
|
-
:BS_MAILBLOCK_SPAMDETECTED => 52, # MAIL BLOCK - Spam Content Detected
|
84
|
-
:BS_MAILBLOCK_ATTACHMENT => 53, # MAIL BLOCK - Attachment Detected
|
85
|
-
:BS_MAILBLOCK_RELAYDENIED => 54, # MAIL BLOCK - Relay Denied
|
86
|
-
:BS_AUTOREPLY => 60, # AUTO REPLY
|
87
|
-
:BS_TRANSIENT => 70, # TRANSIENT BOUNCE
|
88
|
-
:BS_SUBSCRIBE => 80, # SUBSCRIBE REQUEST
|
89
|
-
:BS_UNSUBSCRIBE => 90, # UNSUBSCRIBE REQUEST
|
90
|
-
:BS_CHALLENGERESPONSE =>100, # CHALLENGE-RESPONSE MESSAGE
|
91
|
-
}
|
69
|
+
end
|
@@ -0,0 +1,99 @@
|
|
1
|
+
require 'test_helper'
|
2
|
+
|
3
|
+
class BounceStudioTest < Test::Unit::TestCase
|
4
|
+
|
5
|
+
def setup
|
6
|
+
license_code = BS_LICENSE
|
7
|
+
@studio = BoogieTools::BounceStudio.new license_code
|
8
|
+
@raw = IO.read File.join(File.dirname(__FILE__), "raw_message.txt")
|
9
|
+
end
|
10
|
+
|
11
|
+
def test_truth
|
12
|
+
assert true
|
13
|
+
end
|
14
|
+
|
15
|
+
def test_studio_type
|
16
|
+
assert_equal Object, BoogieTools::BounceStudio.superclass
|
17
|
+
assert_equal BoogieTools::BounceStudio, @studio.class
|
18
|
+
end
|
19
|
+
|
20
|
+
def test_check
|
21
|
+
bounce_code = @studio.check(@raw)
|
22
|
+
assert bounce_code.is_a?(Fixnum)
|
23
|
+
assert_equal bounce_code, 10
|
24
|
+
end
|
25
|
+
|
26
|
+
def test_body
|
27
|
+
body = @studio.body(@raw)
|
28
|
+
assert body.is_a?(String)
|
29
|
+
end
|
30
|
+
|
31
|
+
def test_from_address
|
32
|
+
from_address = @studio.from_address(@raw)
|
33
|
+
assert from_address.is_a?(String)
|
34
|
+
assert !from_address.empty?
|
35
|
+
assert_equal from_address, "MAILER-DAEMON@mail.coinet.com".downcase
|
36
|
+
end
|
37
|
+
|
38
|
+
def test_from_friendly_name
|
39
|
+
from_friendly_name = @studio.from_friendly_name(@raw)
|
40
|
+
assert from_friendly_name.is_a?(String)
|
41
|
+
assert from_friendly_name.empty?
|
42
|
+
end
|
43
|
+
|
44
|
+
def test_header
|
45
|
+
header = @studio.header(@raw)
|
46
|
+
assert header.is_a?(String)
|
47
|
+
assert !header.empty?
|
48
|
+
end
|
49
|
+
|
50
|
+
def test_reply_to_address
|
51
|
+
reply_to_address = @studio.reply_to_address(@raw)
|
52
|
+
assert reply_to_address.is_a?(String)
|
53
|
+
assert reply_to_address.empty?
|
54
|
+
end
|
55
|
+
|
56
|
+
def test_reply_to_friendly_name
|
57
|
+
reply_to_friendly_name = @studio.reply_to_friendly_name(@raw)
|
58
|
+
assert reply_to_friendly_name.is_a?(String)
|
59
|
+
assert reply_to_friendly_name.empty?
|
60
|
+
end
|
61
|
+
|
62
|
+
def test_subject
|
63
|
+
subject = @studio.subject(@raw)
|
64
|
+
assert subject.is_a?(String)
|
65
|
+
assert !subject.empty?
|
66
|
+
assert_equal subject.chomp, "failure notice"
|
67
|
+
end
|
68
|
+
|
69
|
+
def test_to_address
|
70
|
+
to_address = @studio.to_address(@raw)
|
71
|
+
assert to_address.is_a?(String)
|
72
|
+
assert !to_address.empty?
|
73
|
+
assert_equal to_address, "joebob@joe.net"
|
74
|
+
end
|
75
|
+
|
76
|
+
def test_to_friendly_name
|
77
|
+
to_friendly_name = @studio.to_friendly_name(@raw)
|
78
|
+
assert to_friendly_name.is_a?(String)
|
79
|
+
assert to_friendly_name.empty?
|
80
|
+
end
|
81
|
+
|
82
|
+
def test_custom_header
|
83
|
+
custom_header = @studio.custom_header(@raw, "X-OriginalArrivalTime".downcase)
|
84
|
+
assert custom_header.is_a?(String)
|
85
|
+
assert custom_header.empty?
|
86
|
+
|
87
|
+
date_header = @studio.custom_header(@raw, "Date".downcase)
|
88
|
+
assert date_header.is_a?(String)
|
89
|
+
assert !date_header.empty?
|
90
|
+
assert_equal date_header.chomp, "21 Aug 2000 21:08:21 -0000"
|
91
|
+
end
|
92
|
+
|
93
|
+
def test_orig_custom_header
|
94
|
+
orig_custom_header = @studio.orig_custom_header(@raw, "X-OriginalArrivalTime".downcase)
|
95
|
+
assert orig_custom_header.is_a?(String)
|
96
|
+
assert !orig_custom_header.empty?
|
97
|
+
assert_equal orig_custom_header.chomp, "21 Aug 2000 21:08:20.0944 (UTC) FILETIME=[EF5F8500:01C00BB3]"
|
98
|
+
end
|
99
|
+
end
|
@@ -0,0 +1,50 @@
|
|
1
|
+
|
2
|
+
Return-Path: <>
|
3
|
+
Received: from defiant.coinet.com ([204.245.234.17])
|
4
|
+
by detmail.somedomain.net (Post.Office MTA v3.5.3 release 223
|
5
|
+
ID# 0-65382U1000L100S0V35) with SMTP id net
|
6
|
+
for <joebob@joe.net>; Mon, 21 Aug 2000 14:07:48 -0700
|
7
|
+
Received: (qmail 849 invoked for bounce); 21 Aug 2000 21:08:21 -0000
|
8
|
+
Date: 21 Aug 2000 21:08:21 -0000
|
9
|
+
From: MAILER-DAEMON@mail.coinet.com
|
10
|
+
To: joebob@joe.net
|
11
|
+
Subject: failure notice
|
12
|
+
|
13
|
+
Hi. This is the mail transport agent at mail.coinet.com.
|
14
|
+
I'm afraid I wasn't able to deliver your message to the following addresses.
|
15
|
+
This is a permanent error; I've given up. If you have questions about this
|
16
|
+
notice, please forward it to postmaster@coinet.com along with your comments.
|
17
|
+
|
18
|
+
<wolfden@coinet.com>:
|
19
|
+
Sorry, this account has been deactivated. (#5.2.1)
|
20
|
+
|
21
|
+
--- Below this line is a copy of the message.
|
22
|
+
|
23
|
+
Return-Path: <joebob@joe.net>
|
24
|
+
Received: (qmail 841 invoked from network); 21 Aug 2000 21:08:21 -0000
|
25
|
+
Received: from pool104.somedomain.com (HELO detcmail02.somedomain.net) (1.2.3.4)
|
26
|
+
by coinet.com with SMTP; 21 Aug 2000 21:08:21 -0000
|
27
|
+
Received: from detcmail02 ([2.3.4.5]) by detcmail02.somedomain.net with Microsoft SMTPSVC(5.0.2172.1);
|
28
|
+
Mon, 21 Aug 2000 14:08:20 -0700
|
29
|
+
From: "JOE.NET" <joebob@joe.net>
|
30
|
+
Reply-To: "JOE.NET" <some_reply@joe.net>
|
31
|
+
To: <wolfden@coinet.com>
|
32
|
+
Date: Mon, 21 Aug 00 14:08:20 -0700
|
33
|
+
Subject: JOE.NET NEWS!
|
34
|
+
MIME-Version: 1.0
|
35
|
+
Content-Type: multipart/alternative; boundary="----_=_Send_NextPart_180_03281976"
|
36
|
+
Return-Path: joebob@joe.net
|
37
|
+
Message-ID: <DETCMAIL02agW2wx6Di000110f7@DETcmail02.somedomain.net>
|
38
|
+
X-OriginalArrivalTime: 21 Aug 2000 21:08:20.0944 (UTC) FILETIME=[EF5F8500:01C00BB3]
|
39
|
+
|
40
|
+
This is a multi-part message in MIME format.
|
41
|
+
|
42
|
+
|
43
|
+
------_=_Send_NextPart_180_03281976
|
44
|
+
Content-Type: text/plain; charset=us-ascii
|
45
|
+
|
46
|
+
Here's my test message. This is the body of the message.... Cool.... Okay, bye!
|
47
|
+
|
48
|
+
.
|
49
|
+
|
50
|
+
|
data/test/test_helper.rb
ADDED
@@ -0,0 +1,9 @@
|
|
1
|
+
require 'test/unit'
|
2
|
+
require File.dirname(__FILE__) + '/../lib/bounce_studio_ffi'
|
3
|
+
if ENV['BS_LICENSE']
|
4
|
+
BS_LICENSE = ENV['BS_LICENSE']
|
5
|
+
else
|
6
|
+
puts "Set the environment variable BS_LICENSE with your BoogieTools license code to avoid tarpit"
|
7
|
+
BS_LICENSE = "nolicense"
|
8
|
+
end
|
9
|
+
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: bounce_studio_ffi
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.1.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Benjamin Ortega
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2013-
|
11
|
+
date: 2013-10-18 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|
@@ -45,7 +45,7 @@ dependencies:
|
|
45
45
|
- - '>='
|
46
46
|
- !ruby/object:Gem::Version
|
47
47
|
version: '0'
|
48
|
-
type: :
|
48
|
+
type: :runtime
|
49
49
|
prerelease: false
|
50
50
|
version_requirements: !ruby/object:Gem::Requirement
|
51
51
|
requirements:
|
@@ -59,7 +59,7 @@ dependencies:
|
|
59
59
|
- - '>='
|
60
60
|
- !ruby/object:Gem::Version
|
61
61
|
version: '0'
|
62
|
-
type: :
|
62
|
+
type: :runtime
|
63
63
|
prerelease: false
|
64
64
|
version_requirements: !ruby/object:Gem::Requirement
|
65
65
|
requirements:
|
@@ -81,6 +81,9 @@ files:
|
|
81
81
|
- bounce_studio_ffi.gemspec
|
82
82
|
- lib/bounce_studio_ffi.rb
|
83
83
|
- lib/bounce_studio_ffi/version.rb
|
84
|
+
- test/bouncestudio_test.rb
|
85
|
+
- test/raw_message.txt
|
86
|
+
- test/test_helper.rb
|
84
87
|
homepage: ''
|
85
88
|
licenses:
|
86
89
|
- MIT
|
@@ -105,4 +108,7 @@ rubygems_version: 2.0.3
|
|
105
108
|
signing_key:
|
106
109
|
specification_version: 4
|
107
110
|
summary: FFI wrapper for Ruby BounceStudio API for Linux
|
108
|
-
test_files:
|
111
|
+
test_files:
|
112
|
+
- test/bouncestudio_test.rb
|
113
|
+
- test/raw_message.txt
|
114
|
+
- test/test_helper.rb
|