pony-express 0.6.1 → 0.6.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
data/README.rdoc ADDED
@@ -0,0 +1,54 @@
1
+ = Pony Express
2
+
3
+ A fast and lightweight ruby mailer based on http://github.com/benprew/pony. For a more
4
+ historical perspective read http://en.wikipedia.org/wiki/Pony_Express.
5
+
6
+ == Installation
7
+
8
+ sudo apt-get install libmimetic-dev
9
+ sudo apt-get install libpcre++-dev
10
+ sudo gem install pony-express
11
+
12
+ === Dependencies
13
+
14
+ * Ruby >= 1.9.1
15
+ * rubygems >= 1.3.5
16
+ * ruby development libraries (debian: ruby1.9.1-dev)
17
+ * mimetic >= 0.9.6 development libraries (debian: libmimetic-dev)
18
+ * pcre++ development libraries (debian: libpcre++-dev)
19
+
20
+ == Usage
21
+
22
+ require "pony-express"
23
+ mail = PonyExpress::Mail.new to: "burns@plant.local", from: "homer@home.local", via: "sendmail"
24
+ mail.add subject: "Hello Mr.Burns", text: "Can I have more donuts ?", html: "<strong>More Dooooonuuuuts!</strong>"
25
+ mail.add attachments: [ "/home/homer/donuts.png" ]
26
+ mail.dispatch
27
+
28
+ Don't want to create new mail objects ? Just pass in all options to PonyExpress.mail
29
+
30
+ PonyExpress.mail to: "burns@plant.local", from: "homer@home.local", ...
31
+
32
+ == Testing
33
+
34
+ require "pony-express"
35
+ require "pony-express/test"
36
+ mail = PonyExpress::Mail.new to: "burns@plant.local", from: "homer@home.local", via: "sendmail"
37
+ mail.add subject: "Hello Mr.Burns", text: "Can I have more donuts ?"
38
+ mail.dispatch
39
+ assert_equal 1, PonyExpress::Test.mailbox.length
40
+
41
+ == TODO
42
+
43
+ * Build a rainbow machine and rope in some unicorns.
44
+
45
+ == Won't Do
46
+
47
+ * Support for Ruby 1.8 or Rubinius or JRuby
48
+ * MIME parsing. If you need a full blown mail library have a look at the mail gem.
49
+
50
+ == License
51
+
52
+ GNU GPLv3, so its free and comes with no guarantees. If it brings down your website or burns down your house, I will
53
+ not be held responsible. Use it at your own risk. You can read all about GNU here: http://www.gnu.org and
54
+ GNU GPLv3 here: http://www.gnu.org/licenses/gpl.txt.
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.6.1
1
+ 0.6.5
data/ext/mimetic.cxx CHANGED
@@ -1,5 +1,7 @@
1
1
  #include <ruby.h>
2
- #include <ruby/encoding.h>
2
+ extern "C" {
3
+ #include <ruby/encoding.h>
4
+ }
3
5
  #include <iostream>
4
6
  #include <unistd.h>
5
7
  #include <sstream>
@@ -10,36 +12,57 @@
10
12
 
11
13
  #define ID_CONST_GET rb_intern("const_get")
12
14
  #define CONST_GET(scope, constant) (rb_funcall(scope, ID_CONST_GET, 1, rb_str_new2(constant)))
15
+ #define RUBY_ENCODING(str) string(rb_enc_get(str)->name)
16
+ #define VALUEFUNC(f) ((VALUE (*)(ANYARGS)) f)
17
+ #define FORCE_ENCODING(str,enc) rb_enc_associate(str, rb_to_encoding(enc)); ENC_CODERANGE_CLEAR(str);
13
18
 
14
19
  static VALUE rb_mMimetic;
15
20
  static VALUE eRuntimeError;
16
21
  static VALUE eArgumentError;
22
+ static VALUE rb_UTF8, rb_ASCII;
17
23
 
18
24
  using namespace std;
19
25
  using namespace mimetic;
20
26
  using namespace pcrepp;
21
27
 
22
- #define VALUEFUNC(f) ((VALUE (*)(ANYARGS)) f)
23
-
24
28
  map<string, string> MimeTypes;
25
29
 
26
30
  /* RFC References
27
31
 
28
32
  http://www.ietf.org/rfc/rfc2822.txt Internet Message Format.
29
- http://www.ietf.org/rfc/rfc1341.txt MIME Extensions - Multipart related.
33
+ http://www.ietf.org/rfc/rfc2045.txt MIME Extensions - Multipart related (Part One).
34
+ http://www.ietf.org/rfc/rfc2046.txt MIME Extensions - Multipart related (Part Deux).
30
35
  http://www.ietf.org/rfc/rfc2392.txt Content-ID and Message-ID.
31
36
 
32
37
  */
33
38
 
34
- // TODO: CHECK FOR MEMORY LEAKS - not sure if mimetic releases mime parts.
39
+ // TODO
40
+ // angle brackets enclosing content and message ids should be part of libmimetic.
41
+ string content_id() {
42
+ string cid = ContentId().str();
43
+ return cid[0] == '<' ? cid : "<" + cid + ">";
44
+ }
45
+
46
+ string message_id(int n) {
47
+ string mid = MessageId(n).str();
48
+ return mid[0] == '<' ? mid : "<" + mid + ">";
49
+ }
50
+
51
+ string file_mime_type(string file) {
52
+ Pcre regex("\\.");
53
+ string extn = regex.split(file).back();
54
+ transform(extn.begin(), extn.end(), extn.begin(), ::tolower);
55
+ string mime = MimeTypes[extn];
56
+ return mime.length() > 0 ? mime : "application/octet-stream";
57
+ }
35
58
 
36
- bool mimetic_attach_file(MimeEntity *m, char* filename, const char *mimetype) {
59
+ bool mimetic_attach_file(MimeEntity *m, char* filename) {
37
60
  filebuf ifile;
38
61
  ostringstream encoded;
39
62
  ifile.open(filename, ios::in);
40
63
  if (ifile.is_open()) {
41
64
  istream is(&ifile);
42
- Attachment *at = new Attachment(filename, ContentType(mimetype));
65
+ Attachment *at = new Attachment(filename, ContentType(file_mime_type(filename)));
43
66
  Base64::Encoder b64;
44
67
  ostreambuf_iterator<char> oi(encoded);
45
68
  istreambuf_iterator<char> ibegin(is), iend;
@@ -55,14 +78,36 @@ bool mimetic_attach_file(MimeEntity *m, char* filename, const char *mimetype) {
55
78
  return false;
56
79
  }
57
80
 
58
- string get_mime_type(string file) {
59
- Pcre regex("\\.");
60
- string extn = regex.split(file).back();
61
- transform(extn.begin(), extn.end(), extn.begin(), ::tolower);
62
- string mime = MimeTypes[extn];
63
- return mime.length() > 0 ? mime : MimeTypes["bin"];
81
+ string safe_rfc2047(string v) {
82
+ Pcre re1("\\?");
83
+ Pcre re2("_");
84
+ Pcre re3(" ");
85
+ v = re1.replace(v, "=3F");
86
+ v = re2.replace(v, "=5F");
87
+ v = re3.replace(v, "_");
88
+ return v;
64
89
  }
65
90
 
91
+ string quoted_printable(VALUE str) {
92
+ VALUE ascii = rb_str_new2(RSTRING_PTR(str));
93
+ FORCE_ENCODING(ascii, rb_ASCII);
94
+ if (rb_str_cmp(ascii, str) != 0) {
95
+ string raw = RSTRING_PTR(str);
96
+ QP::Encoder qp;
97
+ istringstream is(raw);
98
+ ostringstream encoded;
99
+ istreambuf_iterator<char> ibeg(is), iend;
100
+ ostreambuf_iterator<char> oi(encoded);
101
+ encode(ibeg, iend, qp, oi);
102
+ return "=?" + RUBY_ENCODING(str) + "?Q?" + safe_rfc2047(encoded.str()) + "?=";
103
+ }
104
+ else {
105
+ return string(RSTRING_PTR(str));
106
+ }
107
+ }
108
+
109
+ // Exposed API
110
+
66
111
  void rb_load_mime_types(VALUE self, VALUE filename) {
67
112
  char buffer[4096];
68
113
  vector<string> data;
@@ -96,6 +141,7 @@ VALUE rb_mimetic_build(VALUE self, VALUE options) {
96
141
  if (subject == Qnil) rb_raise(eArgumentError, "Mimetic.build called without :subject");
97
142
 
98
143
  // optional fields
144
+ VALUE mid = rb_hash_aref(options, ID2SYM(rb_intern("message_id")));
99
145
  VALUE html = rb_hash_aref(options, ID2SYM(rb_intern("html")));
100
146
  VALUE tcid = rb_hash_aref(options, ID2SYM(rb_intern("text_content_id")));
101
147
  VALUE hcid = rb_hash_aref(options, ID2SYM(rb_intern("html_content_id")));
@@ -104,6 +150,15 @@ VALUE rb_mimetic_build(VALUE self, VALUE options) {
104
150
  VALUE bcc = rb_hash_aref(options, ID2SYM(rb_intern("bcc")));
105
151
  VALUE files = rb_hash_aref(options, ID2SYM(rb_intern("attachments")));
106
152
 
153
+ if (mid != Qnil && TYPE(mid) != T_STRING)
154
+ rb_raise(eArgumentError, "Mimetic.build expects :message_id to be a string");
155
+
156
+ if (tcid != Qnil && TYPE(tcid) != T_STRING)
157
+ rb_raise(eArgumentError, "Mimetic.build expects :text_content_id to be a string");
158
+
159
+ if (hcid != Qnil && TYPE(hcid) != T_STRING)
160
+ rb_raise(eArgumentError, "Mimetic.build expects :html_content_id to be a string");
161
+
107
162
  if (files != Qnil && TYPE(files) != T_ARRAY)
108
163
  rb_raise(eArgumentError, "Mimetic.build expects :attachments to be an array");
109
164
 
@@ -122,20 +177,20 @@ VALUE rb_mimetic_build(VALUE self, VALUE options) {
122
177
  text_part = new MimeEntity;
123
178
  message->body().parts().push_back(text_part);
124
179
  message->body().parts().push_back(html_part);
125
- text_part->header().contentType("text/plain; charset=UTF-8");
180
+ text_part->header().contentType("text/plain; charset=" + RUBY_ENCODING(text));
126
181
  text_part->header().contentTransferEncoding("8bit");
127
- text_part->header().contentId(tcid == Qnil ? ContentId() : ContentId(RSTRING_PTR(tcid)));
182
+ text_part->header().contentId(tcid == Qnil ? content_id() + ">" : ContentId(RSTRING_PTR(tcid)));
128
183
  text_part->header().mimeVersion(v1);
129
184
  text_part->body().assign(RSTRING_PTR(text));
130
- html_part->header().contentType("text/html; charset=UTF-8");
185
+ html_part->header().contentType("text/html; charset=" + RUBY_ENCODING(html));
131
186
  html_part->header().contentTransferEncoding("7bit");
132
- html_part->header().contentId(hcid == Qnil ? ContentId() : ContentId(RSTRING_PTR(hcid)));
187
+ html_part->header().contentId(hcid == Qnil ? content_id() + ">" : ContentId(RSTRING_PTR(hcid)));
133
188
  html_part->header().mimeVersion(v1);
134
189
  html_part->body().assign(RSTRING_PTR(html));
135
190
  }
136
191
  else {
137
192
  message->body().assign(RSTRING_PTR(text));
138
- message->header().contentType("text/plain; charset=UTF-8");
193
+ message->header().contentType("text/plain; charset=" + RUBY_ENCODING(text));
139
194
  message->header().contentTransferEncoding("8bit");
140
195
  message->header().mimeVersion(v1);
141
196
  }
@@ -148,14 +203,14 @@ VALUE rb_mimetic_build(VALUE self, VALUE options) {
148
203
  for (long i = 0; i < RARRAY_LEN(files); i++) {
149
204
  attachment = rb_ary_entry(files, i);
150
205
  if (attachment != Qnil && TYPE(attachment) == T_STRING)
151
- mimetic_attach_file(message, RSTRING_PTR(attachment), get_mime_type(RSTRING_PTR(attachment)).c_str());
206
+ mimetic_attach_file(message, RSTRING_PTR(attachment));
152
207
  }
153
208
  }
154
209
 
155
210
  message->header().from(RSTRING_PTR(from));
156
211
  message->header().to(RSTRING_PTR(to));
157
- message->header().subject(RSTRING_PTR(subject));
158
- message->header().messageid(1);
212
+ message->header().subject(quoted_printable(subject));
213
+ message->header().messageid(mid != Qnil ? RSTRING_PTR(mid) : message_id(1));
159
214
 
160
215
  if (replyto != Qnil) message->header().replyto(RSTRING_PTR(replyto));
161
216
  if (cc != Qnil) message->header().cc(RSTRING_PTR(cc));
@@ -184,5 +239,7 @@ extern "C" {
184
239
  rb_mMimetic = rb_define_module("Mimetic");
185
240
  rb_define_module_function(rb_mMimetic, "build", VALUEFUNC(rb_mimetic_build), 1);
186
241
  rb_define_module_function(rb_mMimetic, "load_mime_types", VALUEFUNC(rb_load_mime_types), 1);
242
+ rb_UTF8 = rb_str_new2("UTF-8");
243
+ rb_ASCII = rb_str_new2("US-ASCII");
187
244
  }
188
245
  }
@@ -0,0 +1,19 @@
1
+ module PonyExpress
2
+ module Test
3
+ def mailbox
4
+ PonyExpress::Test.mailbox
5
+ end
6
+
7
+ def self.mailbox
8
+ @@mailbox ||= []
9
+ end
10
+ end
11
+
12
+ def self.transport_via_sendmail content, *rest
13
+ PonyExpress::Test.mailbox << content
14
+ end
15
+
16
+ def self.transport_via_smtp content, *rest
17
+ PonyExpress::Test.mailbox << content
18
+ end
19
+ end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: pony-express
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.6.1
4
+ version: 0.6.5
5
5
  platform: ruby
6
6
  authors:
7
7
  - Bharanee Rathna
@@ -9,7 +9,7 @@ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
11
 
12
- date: 2010-06-03 00:00:00 +10:00
12
+ date: 2010-06-08 00:00:00 +10:00
13
13
  default_executable:
14
14
  dependencies: []
15
15
 
@@ -21,14 +21,15 @@ extensions:
21
21
  - ext/extconf.rb
22
22
  extra_rdoc_files:
23
23
  - LICENSE
24
- - README
24
+ - README.rdoc
25
25
  files:
26
26
  - LICENSE
27
- - README
28
27
  - VERSION
29
28
  - ext/mimetic.cxx
30
29
  - lib/pony-express.rb
30
+ - lib/pony-express/test.rb
31
31
  - mime.types
32
+ - README.rdoc
32
33
  has_rdoc: true
33
34
  homepage: http://github.com/deepfryed/pony-express
34
35
  licenses: []
data/README DELETED
@@ -1,43 +0,0 @@
1
- A fast and lightweight ruby mailer based on http://github.com/benprew/pony. For a more
2
- historical perspective read http://en.wikipedia.org/wiki/Pony_Express.
3
-
4
- INSTALL:
5
-
6
- sudo apt-get install libmimetic-dev
7
- sudo gem install pony-express
8
-
9
- REQUIREMENT:
10
-
11
- * Ruby >= 1.9.1
12
- * rubygems >= 1.3.5
13
- * ruby development libraries (debian: ruby1.9.1-dev)
14
- * mimetic >= 0.9.6 development libraries (debian: libmimetic-dev)
15
- * pcre++ development libraries (debian: libpcre++-dev)
16
-
17
- USAGE:
18
-
19
- >> require "pony-express"
20
- >> mail = PonyExpress::Mail.new to: "burns@plant.local", from: "homer@home.local", via: "sendmail"
21
- >> mail.add subject: "Hello Mr.Burns", text: "Can I have more donuts", html: "<strong>More Dooooonuuuuts!</strong>"
22
- >> mail.add attachments: [ "/home/homer/donuts.png" ]
23
- >> mail.dispatch
24
-
25
- Don't want to create new mail objects ? Just pass in all options to PonyExpress.mail
26
-
27
- >> PonyExpress.mail to: "burns@plant.local", from: "homer@home.local", ...
28
-
29
- TODO:
30
-
31
- * Check for Memory Leaks, build a Rainbow machine and rope in some Unicorns.
32
-
33
- DON'T ASK:
34
-
35
- * Support for Ruby 1.8 or Rubinius or JRuby
36
- * MIME parsing. If you need a full blown mail library have a look at the mail gem.
37
-
38
-
39
- LICENSE:
40
-
41
- GNU GPLv3, so its free and comes with no guarantees. If it brings down your website or burns down your house, I will
42
- not be held responsible. Use it at your own risk. You can read all about GNU here: http://www.gnu.org and
43
- GNU GPLv3 here: http://www.gnu.org/licenses/gpl.txt.