\ No newline at end of file
diff --git a/vendor/erusev/parsedown/test/data/automatic_link.md b/vendor/erusev/parsedown/test/data/automatic_link.md
new file mode 100644
index 00000000..08d3bf46
--- /dev/null
+++ b/vendor/erusev/parsedown/test/data/automatic_link.md
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/vendor/erusev/parsedown/test/data/block-level_html.html b/vendor/erusev/parsedown/test/data/block-level_html.html
new file mode 100644
index 00000000..86ff8655
--- /dev/null
+++ b/vendor/erusev/parsedown/test/data/block-level_html.html
@@ -0,0 +1,13 @@
+
_content_
+
sparse:
+
+
+_content_
+
+
+
paragraph
+
\ No newline at end of file
diff --git a/vendor/erusev/parsedown/test/data/block-level_html.md b/vendor/erusev/parsedown/test/data/block-level_html.md
new file mode 100644
index 00000000..679832cd
--- /dev/null
+++ b/vendor/erusev/parsedown/test/data/block-level_html.md
@@ -0,0 +1,17 @@
+
> not a quote
+- not a list item
+[not a reference]: http://foo.com
\ No newline at end of file
diff --git a/vendor/erusev/parsedown/test/data/code_block.md b/vendor/erusev/parsedown/test/data/code_block.md
new file mode 100644
index 00000000..2cfc953c
--- /dev/null
+++ b/vendor/erusev/parsedown/test/data/code_block.md
@@ -0,0 +1,10 @@
+ not a quote
+ - not a list item
+ [not a reference]: http://foo.com
\ No newline at end of file
diff --git a/vendor/erusev/parsedown/test/data/code_span.html b/vendor/erusev/parsedown/test/data/code_span.html
new file mode 100644
index 00000000..5c4c231e
--- /dev/null
+++ b/vendor/erusev/parsedown/test/data/code_span.html
@@ -0,0 +1,6 @@
+
a code span
+
this is also a codespan trailing text
+
and look at this one!
+
single backtick in a code span: `
+
backtick-delimited string in a code span: `foo`
+
sth `` sth
\ No newline at end of file
diff --git a/vendor/erusev/parsedown/test/data/code_span.md b/vendor/erusev/parsedown/test/data/code_span.md
new file mode 100644
index 00000000..c2f1a744
--- /dev/null
+++ b/vendor/erusev/parsedown/test/data/code_span.md
@@ -0,0 +1,11 @@
+a `code span`
+
+`this is also a codespan` trailing text
+
+`and look at this one!`
+
+single backtick in a code span: `` ` ``
+
+backtick-delimited string in a code span: `` `foo` ``
+
+`sth `` sth`
\ No newline at end of file
diff --git a/vendor/erusev/parsedown/test/data/compound_blockquote.html b/vendor/erusev/parsedown/test/data/compound_blockquote.html
new file mode 100644
index 00000000..37afb57a
--- /dev/null
+++ b/vendor/erusev/parsedown/test/data/compound_blockquote.html
@@ -0,0 +1,9 @@
+
+
header
+
paragraph
+
+
li
+
+
+
paragraph
+
\ No newline at end of file
diff --git a/vendor/erusev/parsedown/test/data/compound_blockquote.md b/vendor/erusev/parsedown/test/data/compound_blockquote.md
new file mode 100644
index 00000000..80c4aed1
--- /dev/null
+++ b/vendor/erusev/parsedown/test/data/compound_blockquote.md
@@ -0,0 +1,10 @@
+> header
+> ------
+>
+> paragraph
+>
+> - li
+>
+> ---
+>
+> paragraph
\ No newline at end of file
diff --git a/vendor/erusev/parsedown/test/data/compound_emphasis.html b/vendor/erusev/parsedown/test/data/compound_emphasis.html
new file mode 100644
index 00000000..178dd54b
--- /dev/null
+++ b/vendor/erusev/parsedown/test/data/compound_emphasis.html
@@ -0,0 +1,2 @@
+
codecode
+
codecodecode
\ No newline at end of file
diff --git a/vendor/erusev/parsedown/test/data/compound_emphasis.md b/vendor/erusev/parsedown/test/data/compound_emphasis.md
new file mode 100644
index 00000000..6fe07f26
--- /dev/null
+++ b/vendor/erusev/parsedown/test/data/compound_emphasis.md
@@ -0,0 +1,4 @@
+_`code`_ __`code`__
+
+*`code`**`code`**`code`*
+
diff --git a/vendor/erusev/parsedown/test/data/compound_list.html b/vendor/erusev/parsedown/test/data/compound_list.html
new file mode 100644
index 00000000..f5593c14
--- /dev/null
+++ b/vendor/erusev/parsedown/test/data/compound_list.html
@@ -0,0 +1,12 @@
+
+
+
paragraph
+
paragraph
+
+
+
paragraph
+
+
quote
+
+
+
\ No newline at end of file
diff --git a/vendor/erusev/parsedown/test/data/compound_list.md b/vendor/erusev/parsedown/test/data/compound_list.md
new file mode 100644
index 00000000..ed7f0c60
--- /dev/null
+++ b/vendor/erusev/parsedown/test/data/compound_list.md
@@ -0,0 +1,7 @@
+- paragraph
+
+ paragraph
+
+- paragraph
+
+ > quote
\ No newline at end of file
diff --git a/vendor/erusev/parsedown/test/data/deeply_nested_list.html b/vendor/erusev/parsedown/test/data/deeply_nested_list.html
new file mode 100644
index 00000000..d2c7e5ac
--- /dev/null
+++ b/vendor/erusev/parsedown/test/data/deeply_nested_list.html
@@ -0,0 +1,12 @@
+
+
li
+
+
li
+
+
li
+
li
+
+
li
+
+
li
+
\ No newline at end of file
diff --git a/vendor/erusev/parsedown/test/data/deeply_nested_list.md b/vendor/erusev/parsedown/test/data/deeply_nested_list.md
new file mode 100644
index 00000000..76b7552d
--- /dev/null
+++ b/vendor/erusev/parsedown/test/data/deeply_nested_list.md
@@ -0,0 +1,6 @@
+- li
+ - li
+ - li
+ - li
+ - li
+- li
\ No newline at end of file
diff --git a/vendor/erusev/parsedown/test/data/em_strong.html b/vendor/erusev/parsedown/test/data/em_strong.html
new file mode 100644
index 00000000..323d60ae
--- /dev/null
+++ b/vendor/erusev/parsedown/test/data/em_strong.html
@@ -0,0 +1,8 @@
+
em strong
+
em strong strong
+
strong em strong
+
strong em strong strong
+
em strong
+
em strong strong
+
strong em strong
+
strong em strong strong
\ No newline at end of file
diff --git a/vendor/erusev/parsedown/test/data/em_strong.md b/vendor/erusev/parsedown/test/data/em_strong.md
new file mode 100644
index 00000000..9abeb3fd
--- /dev/null
+++ b/vendor/erusev/parsedown/test/data/em_strong.md
@@ -0,0 +1,15 @@
+___em strong___
+
+___em strong_ strong__
+
+__strong _em strong___
+
+__strong _em strong_ strong__
+
+***em strong***
+
+***em strong* strong**
+
+**strong *em strong***
+
+**strong *em strong* strong**
\ No newline at end of file
diff --git a/vendor/erusev/parsedown/test/data/email.html b/vendor/erusev/parsedown/test/data/email.html
new file mode 100644
index 00000000..c40759c9
--- /dev/null
+++ b/vendor/erusev/parsedown/test/data/email.html
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/vendor/erusev/parsedown/test/data/email.md b/vendor/erusev/parsedown/test/data/email.md
new file mode 100644
index 00000000..26b7b6cc
--- /dev/null
+++ b/vendor/erusev/parsedown/test/data/email.md
@@ -0,0 +1 @@
+my email is
\ No newline at end of file
diff --git a/vendor/erusev/parsedown/test/data/emphasis.html b/vendor/erusev/parsedown/test/data/emphasis.html
new file mode 100644
index 00000000..60ff4bd8
--- /dev/null
+++ b/vendor/erusev/parsedown/test/data/emphasis.html
@@ -0,0 +1,8 @@
+
underscore, asterisk, one two, three four, a, b
+
strong and em and strong and em
+
line
+line
+line
+
this_is_not_an_emphasis
+
an empty emphasis __ ** is not an emphasis
+
*mixed *double and single asterisk** spans
\ No newline at end of file
diff --git a/vendor/erusev/parsedown/test/data/emphasis.md b/vendor/erusev/parsedown/test/data/emphasis.md
new file mode 100644
index 00000000..85b9d229
--- /dev/null
+++ b/vendor/erusev/parsedown/test/data/emphasis.md
@@ -0,0 +1,13 @@
+_underscore_, *asterisk*, _one two_, *three four*, _a_, *b*
+
+**strong** and *em* and **strong** and *em*
+
+_line
+line
+line_
+
+this_is_not_an_emphasis
+
+an empty emphasis __ ** is not an emphasis
+
+*mixed **double and* single asterisk** spans
\ No newline at end of file
diff --git a/vendor/erusev/parsedown/test/data/escaping.html b/vendor/erusev/parsedown/test/data/escaping.html
new file mode 100644
index 00000000..64676cb1
--- /dev/null
+++ b/vendor/erusev/parsedown/test/data/escaping.html
@@ -0,0 +1,4 @@
+
escaped *emphasis*.
+
escaped \*emphasis\* in a code span
+
escaped \*emphasis\* in a code block
+
\ ` * _ { } [ ] ( ) > # + - . !
\ No newline at end of file
diff --git a/vendor/erusev/parsedown/test/data/escaping.md b/vendor/erusev/parsedown/test/data/escaping.md
new file mode 100644
index 00000000..164039f8
--- /dev/null
+++ b/vendor/erusev/parsedown/test/data/escaping.md
@@ -0,0 +1,7 @@
+escaped \*emphasis\*.
+
+`escaped \*emphasis\* in a code span`
+
+ escaped \*emphasis\* in a code block
+
+\\ \` \* \_ \{ \} \[ \] \( \) \> \# \+ \- \. \!
\ No newline at end of file
diff --git a/vendor/erusev/parsedown/test/data/fenced_code_block.html b/vendor/erusev/parsedown/test/data/fenced_code_block.html
new file mode 100644
index 00000000..8bdabba9
--- /dev/null
+++ b/vendor/erusev/parsedown/test/data/fenced_code_block.html
@@ -0,0 +1,6 @@
+
\ No newline at end of file
diff --git a/vendor/erusev/parsedown/test/data/fenced_code_block.md b/vendor/erusev/parsedown/test/data/fenced_code_block.md
new file mode 100644
index 00000000..cbed8ebb
--- /dev/null
+++ b/vendor/erusev/parsedown/test/data/fenced_code_block.md
@@ -0,0 +1,14 @@
+```
+
+
+
+
+
\ No newline at end of file
diff --git a/vendor/erusev/parsedown/test/data/horizontal_rule.md b/vendor/erusev/parsedown/test/data/horizontal_rule.md
new file mode 100644
index 00000000..bf461a92
--- /dev/null
+++ b/vendor/erusev/parsedown/test/data/horizontal_rule.md
@@ -0,0 +1,9 @@
+---
+
+- - -
+
+ - - -
+
+***
+
+___
\ No newline at end of file
diff --git a/vendor/erusev/parsedown/test/data/html_comment.html b/vendor/erusev/parsedown/test/data/html_comment.html
new file mode 100644
index 00000000..566dc3ad
--- /dev/null
+++ b/vendor/erusev/parsedown/test/data/html_comment.html
@@ -0,0 +1,5 @@
+
+
paragraph
+
+
paragraph
\ No newline at end of file
diff --git a/vendor/erusev/parsedown/test/data/html_comment.md b/vendor/erusev/parsedown/test/data/html_comment.md
new file mode 100644
index 00000000..6ddfdb44
--- /dev/null
+++ b/vendor/erusev/parsedown/test/data/html_comment.md
@@ -0,0 +1,8 @@
+
+
+paragraph
+
+
+
+paragraph
\ No newline at end of file
diff --git a/vendor/erusev/parsedown/test/data/html_entity.html b/vendor/erusev/parsedown/test/data/html_entity.html
new file mode 100644
index 00000000..4d23e3cd
--- /dev/null
+++ b/vendor/erusev/parsedown/test/data/html_entity.html
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/vendor/erusev/parsedown/test/data/implicit_reference.md b/vendor/erusev/parsedown/test/data/implicit_reference.md
new file mode 100644
index 00000000..f850df96
--- /dev/null
+++ b/vendor/erusev/parsedown/test/data/implicit_reference.md
@@ -0,0 +1,13 @@
+an [implicit] reference link
+
+[implicit]: http://example.com
+
+an [implicit][] reference link with an empty link definition
+
+an [implicit][] reference link followed by [another][]
+
+[another]: http://cnn.com
+
+an [explicit][example] reference link with a title
+
+[example]: http://example.com "Example"
\ No newline at end of file
diff --git a/vendor/erusev/parsedown/test/data/inline_link.html b/vendor/erusev/parsedown/test/data/inline_link.html
new file mode 100644
index 00000000..2b9e649d
--- /dev/null
+++ b/vendor/erusev/parsedown/test/data/inline_link.html
@@ -0,0 +1,4 @@
+
\ No newline at end of file
diff --git a/vendor/erusev/parsedown/test/data/inline_link.md b/vendor/erusev/parsedown/test/data/inline_link.md
new file mode 100644
index 00000000..cd8e5a63
--- /dev/null
+++ b/vendor/erusev/parsedown/test/data/inline_link.md
@@ -0,0 +1,7 @@
+[link](http://example.com) and [another link](/tests/)
+
+[`link`](http://example.com)
+
+[![MD Logo](http://parsedown.org/md.png)](http://example.com)
+
+[![MD Logo](http://parsedown.org/md.png) and text](http://example.com)
\ No newline at end of file
diff --git a/vendor/erusev/parsedown/test/data/inline_link_title.html b/vendor/erusev/parsedown/test/data/inline_link_title.html
new file mode 100644
index 00000000..70e589aa
--- /dev/null
+++ b/vendor/erusev/parsedown/test/data/inline_link_title.html
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/vendor/erusev/parsedown/test/data/inline_link_title.md b/vendor/erusev/parsedown/test/data/inline_link_title.md
new file mode 100644
index 00000000..162b832a
--- /dev/null
+++ b/vendor/erusev/parsedown/test/data/inline_link_title.md
@@ -0,0 +1 @@
+[single quotes](http://example.com 'Title') and [double quotes](http://example.com "Title")
\ No newline at end of file
diff --git a/vendor/erusev/parsedown/test/data/inline_title.html b/vendor/erusev/parsedown/test/data/inline_title.html
new file mode 100644
index 00000000..bbab93b6
--- /dev/null
+++ b/vendor/erusev/parsedown/test/data/inline_title.html
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/vendor/erusev/parsedown/test/data/inline_title.md b/vendor/erusev/parsedown/test/data/inline_title.md
new file mode 100644
index 00000000..cb09344a
--- /dev/null
+++ b/vendor/erusev/parsedown/test/data/inline_title.md
@@ -0,0 +1 @@
+[single quotes](http://example.com 'Example') and [double quotes](http://example.com "Example")
\ No newline at end of file
diff --git a/vendor/erusev/parsedown/test/data/lazy_blockquote.html b/vendor/erusev/parsedown/test/data/lazy_blockquote.html
new file mode 100644
index 00000000..0a2a2aaf
--- /dev/null
+++ b/vendor/erusev/parsedown/test/data/lazy_blockquote.html
@@ -0,0 +1,6 @@
+
+
quote
+the rest of it
+
another paragraph
+the rest of it
+
\ No newline at end of file
diff --git a/vendor/erusev/parsedown/test/data/lazy_blockquote.md b/vendor/erusev/parsedown/test/data/lazy_blockquote.md
new file mode 100644
index 00000000..48f645f9
--- /dev/null
+++ b/vendor/erusev/parsedown/test/data/lazy_blockquote.md
@@ -0,0 +1,5 @@
+> quote
+the rest of it
+
+> another paragraph
+the rest of it
\ No newline at end of file
diff --git a/vendor/erusev/parsedown/test/data/lazy_list.html b/vendor/erusev/parsedown/test/data/lazy_list.html
new file mode 100644
index 00000000..1a519924
--- /dev/null
+++ b/vendor/erusev/parsedown/test/data/lazy_list.html
@@ -0,0 +1,4 @@
+
+
li
+the rest of it
+
\ No newline at end of file
diff --git a/vendor/erusev/parsedown/test/data/lazy_list.md b/vendor/erusev/parsedown/test/data/lazy_list.md
new file mode 100644
index 00000000..62ad9d71
--- /dev/null
+++ b/vendor/erusev/parsedown/test/data/lazy_list.md
@@ -0,0 +1,2 @@
+- li
+the rest of it
\ No newline at end of file
diff --git a/vendor/erusev/parsedown/test/data/line_break.html b/vendor/erusev/parsedown/test/data/line_break.html
new file mode 100644
index 00000000..5f37d854
--- /dev/null
+++ b/vendor/erusev/parsedown/test/data/line_break.html
@@ -0,0 +1,2 @@
+
line
+line
\ No newline at end of file
diff --git a/vendor/erusev/parsedown/test/data/line_break.md b/vendor/erusev/parsedown/test/data/line_break.md
new file mode 100644
index 00000000..04dff43e
--- /dev/null
+++ b/vendor/erusev/parsedown/test/data/line_break.md
@@ -0,0 +1,2 @@
+line
+line
\ No newline at end of file
diff --git a/vendor/erusev/parsedown/test/data/multiline_list_paragraph.html b/vendor/erusev/parsedown/test/data/multiline_list_paragraph.html
new file mode 100644
index 00000000..3247bd22
--- /dev/null
+++ b/vendor/erusev/parsedown/test/data/multiline_list_paragraph.html
@@ -0,0 +1,7 @@
+
+
+
li
+
line
+line
+
+
\ No newline at end of file
diff --git a/vendor/erusev/parsedown/test/data/multiline_list_paragraph.md b/vendor/erusev/parsedown/test/data/multiline_list_paragraph.md
new file mode 100644
index 00000000..f5b42729
--- /dev/null
+++ b/vendor/erusev/parsedown/test/data/multiline_list_paragraph.md
@@ -0,0 +1,4 @@
+- li
+
+ line
+ line
\ No newline at end of file
diff --git a/vendor/erusev/parsedown/test/data/nested_block-level_html.html b/vendor/erusev/parsedown/test/data/nested_block-level_html.html
new file mode 100644
index 00000000..bfbef54d
--- /dev/null
+++ b/vendor/erusev/parsedown/test/data/nested_block-level_html.html
@@ -0,0 +1,10 @@
+
+_parent_
+
+_child_
+
+
+_adopted child_
+
+
+
outside
\ No newline at end of file
diff --git a/vendor/erusev/parsedown/test/data/nested_block-level_html.md b/vendor/erusev/parsedown/test/data/nested_block-level_html.md
new file mode 100644
index 00000000..5e01e109
--- /dev/null
+++ b/vendor/erusev/parsedown/test/data/nested_block-level_html.md
@@ -0,0 +1,11 @@
+
+_parent_
+
+_child_
+
+
+_adopted child_
+
+
+
+_outside_
\ No newline at end of file
diff --git a/vendor/erusev/parsedown/test/data/ordered_list.html b/vendor/erusev/parsedown/test/data/ordered_list.html
new file mode 100644
index 00000000..b6c5216c
--- /dev/null
+++ b/vendor/erusev/parsedown/test/data/ordered_list.html
@@ -0,0 +1,13 @@
+
+
one
+
two
+
+
repeating numbers:
+
+
one
+
two
+
+
large numbers:
+
+
one
+
\ No newline at end of file
diff --git a/vendor/erusev/parsedown/test/data/ordered_list.md b/vendor/erusev/parsedown/test/data/ordered_list.md
new file mode 100644
index 00000000..b307032c
--- /dev/null
+++ b/vendor/erusev/parsedown/test/data/ordered_list.md
@@ -0,0 +1,11 @@
+1. one
+2. two
+
+repeating numbers:
+
+1. one
+1. two
+
+large numbers:
+
+123. one
\ No newline at end of file
diff --git a/vendor/erusev/parsedown/test/data/paragraph_list.html b/vendor/erusev/parsedown/test/data/paragraph_list.html
new file mode 100644
index 00000000..ced1c43e
--- /dev/null
+++ b/vendor/erusev/parsedown/test/data/paragraph_list.html
@@ -0,0 +1,12 @@
+
paragraph
+
+
li
+
li
+
+
paragraph
+
+
+
li
+
+
li
+
\ No newline at end of file
diff --git a/vendor/erusev/parsedown/test/data/paragraph_list.md b/vendor/erusev/parsedown/test/data/paragraph_list.md
new file mode 100644
index 00000000..b973908c
--- /dev/null
+++ b/vendor/erusev/parsedown/test/data/paragraph_list.md
@@ -0,0 +1,9 @@
+paragraph
+- li
+- li
+
+paragraph
+
+ * li
+
+ * li
\ No newline at end of file
diff --git a/vendor/erusev/parsedown/test/data/reference_title.html b/vendor/erusev/parsedown/test/data/reference_title.html
new file mode 100644
index 00000000..8f2be944
--- /dev/null
+++ b/vendor/erusev/parsedown/test/data/reference_title.html
@@ -0,0 +1,2 @@
+
\ No newline at end of file
diff --git a/vendor/erusev/parsedown/test/data/reference_title.md b/vendor/erusev/parsedown/test/data/reference_title.md
new file mode 100644
index 00000000..43cb2170
--- /dev/null
+++ b/vendor/erusev/parsedown/test/data/reference_title.md
@@ -0,0 +1,6 @@
+[double quotes] and [single quotes] and [parentheses]
+
+[double quotes]: http://example.com "example title"
+[single quotes]: http://example.com 'example title'
+[parentheses]: http://example.com (example title)
+[invalid title]: http://example.com example title
\ No newline at end of file
diff --git a/vendor/erusev/parsedown/test/data/self-closing_html.html b/vendor/erusev/parsedown/test/data/self-closing_html.html
new file mode 100644
index 00000000..4d072b43
--- /dev/null
+++ b/vendor/erusev/parsedown/test/data/self-closing_html.html
@@ -0,0 +1,12 @@
+
+
paragraph
+
+
paragraph
+
+
paragraph
+
+
paragraph
+
+
paragraph
+
+
paragraph
\ No newline at end of file
diff --git a/vendor/erusev/parsedown/test/data/self-closing_html.md b/vendor/erusev/parsedown/test/data/self-closing_html.md
new file mode 100644
index 00000000..acb20327
--- /dev/null
+++ b/vendor/erusev/parsedown/test/data/self-closing_html.md
@@ -0,0 +1,12 @@
+
+paragraph
+
+paragraph
+
+paragraph
+
+paragraph
+
+paragraph
+
+paragraph
\ No newline at end of file
diff --git a/vendor/erusev/parsedown/test/data/separated_nested_list.html b/vendor/erusev/parsedown/test/data/separated_nested_list.html
new file mode 100644
index 00000000..80a5cae2
--- /dev/null
+++ b/vendor/erusev/parsedown/test/data/separated_nested_list.html
@@ -0,0 +1,9 @@
+
+
+
li
+
+
li
+
li
+
+
+
\ No newline at end of file
diff --git a/vendor/erusev/parsedown/test/data/separated_nested_list.md b/vendor/erusev/parsedown/test/data/separated_nested_list.md
new file mode 100644
index 00000000..d7cd1af7
--- /dev/null
+++ b/vendor/erusev/parsedown/test/data/separated_nested_list.md
@@ -0,0 +1,4 @@
+- li
+
+ - li
+ - li
\ No newline at end of file
diff --git a/vendor/erusev/parsedown/test/data/setext_header.html b/vendor/erusev/parsedown/test/data/setext_header.html
new file mode 100644
index 00000000..60aac081
--- /dev/null
+++ b/vendor/erusev/parsedown/test/data/setext_header.html
@@ -0,0 +1,5 @@
+
h1
+
h2
+
single character
+
not a header
+
\ No newline at end of file
diff --git a/vendor/erusev/parsedown/test/data/setext_header.md b/vendor/erusev/parsedown/test/data/setext_header.md
new file mode 100644
index 00000000..c43b52c3
--- /dev/null
+++ b/vendor/erusev/parsedown/test/data/setext_header.md
@@ -0,0 +1,12 @@
+h1
+==
+
+h2
+--
+
+single character
+-
+
+not a header
+
+------------
\ No newline at end of file
diff --git a/vendor/erusev/parsedown/test/data/simple_blockquote.html b/vendor/erusev/parsedown/test/data/simple_blockquote.html
new file mode 100644
index 00000000..8225d57c
--- /dev/null
+++ b/vendor/erusev/parsedown/test/data/simple_blockquote.html
@@ -0,0 +1,11 @@
+
+
quote
+
+
indented:
+
+
quote
+
+
no space after >:
+
+
quote
+
\ No newline at end of file
diff --git a/vendor/erusev/parsedown/test/data/simple_blockquote.md b/vendor/erusev/parsedown/test/data/simple_blockquote.md
new file mode 100644
index 00000000..22b6b11a
--- /dev/null
+++ b/vendor/erusev/parsedown/test/data/simple_blockquote.md
@@ -0,0 +1,7 @@
+> quote
+
+indented:
+ > quote
+
+no space after `>`:
+>quote
\ No newline at end of file
diff --git a/vendor/erusev/parsedown/test/data/simple_table.html b/vendor/erusev/parsedown/test/data/simple_table.html
new file mode 100644
index 00000000..64b7a9a2
--- /dev/null
+++ b/vendor/erusev/parsedown/test/data/simple_table.html
@@ -0,0 +1,37 @@
+
+
+
+
header 1
+
header 2
+
+
+
+
+
cell 1.1
+
cell 1.2
+
+
+
cell 2.1
+
cell 2.2
+
+
+
+
+
+
+
+
header 1
+
header 2
+
+
+
+
+
cell 1.1
+
cell 1.2
+
+
+
cell 2.1
+
cell 2.2
+
+
+
\ No newline at end of file
diff --git a/vendor/erusev/parsedown/test/data/simple_table.md b/vendor/erusev/parsedown/test/data/simple_table.md
new file mode 100644
index 00000000..466d140e
--- /dev/null
+++ b/vendor/erusev/parsedown/test/data/simple_table.md
@@ -0,0 +1,11 @@
+header 1 | header 2
+-------- | --------
+cell 1.1 | cell 1.2
+cell 2.1 | cell 2.2
+
+---
+
+header 1 | header 2
+:------- | --------
+cell 1.1 | cell 1.2
+cell 2.1 | cell 2.2
\ No newline at end of file
diff --git a/vendor/erusev/parsedown/test/data/span-level_html.html b/vendor/erusev/parsedown/test/data/span-level_html.html
new file mode 100644
index 00000000..f852a25a
--- /dev/null
+++ b/vendor/erusev/parsedown/test/data/span-level_html.html
@@ -0,0 +1,5 @@
+
\ No newline at end of file
diff --git a/vendor/erusev/parsedown/test/data/span-level_html.md b/vendor/erusev/parsedown/test/data/span-level_html.md
new file mode 100644
index 00000000..f2219655
--- /dev/null
+++ b/vendor/erusev/parsedown/test/data/span-level_html.md
@@ -0,0 +1,8 @@
+an importantlink
+
+broken
+line
+
+inline tag at the beginning
+
+http://example.com
\ No newline at end of file
diff --git a/vendor/erusev/parsedown/test/data/sparse_dense_list.html b/vendor/erusev/parsedown/test/data/sparse_dense_list.html
new file mode 100644
index 00000000..095bc739
--- /dev/null
+++ b/vendor/erusev/parsedown/test/data/sparse_dense_list.html
@@ -0,0 +1,7 @@
+
+
+
li
+
+
li
+
li
+
\ No newline at end of file
diff --git a/vendor/erusev/parsedown/test/data/sparse_dense_list.md b/vendor/erusev/parsedown/test/data/sparse_dense_list.md
new file mode 100644
index 00000000..57684227
--- /dev/null
+++ b/vendor/erusev/parsedown/test/data/sparse_dense_list.md
@@ -0,0 +1,4 @@
+- li
+
+- li
+- li
\ No newline at end of file
diff --git a/vendor/erusev/parsedown/test/data/sparse_list.html b/vendor/erusev/parsedown/test/data/sparse_list.html
new file mode 100644
index 00000000..452b2b86
--- /dev/null
+++ b/vendor/erusev/parsedown/test/data/sparse_list.html
@@ -0,0 +1,15 @@
+
+
+
li
+
+
li
+
+
+
+
+
li
+
+
indented li
+
+
+
\ No newline at end of file
diff --git a/vendor/erusev/parsedown/test/data/sparse_list.md b/vendor/erusev/parsedown/test/data/sparse_list.md
new file mode 100644
index 00000000..362a35f5
--- /dev/null
+++ b/vendor/erusev/parsedown/test/data/sparse_list.md
@@ -0,0 +1,9 @@
+- li
+
+- li
+
+---
+
+- li
+
+ - indented li
\ No newline at end of file
diff --git a/vendor/erusev/parsedown/test/data/special_characters.html b/vendor/erusev/parsedown/test/data/special_characters.html
new file mode 100644
index 00000000..8199abc1
--- /dev/null
+++ b/vendor/erusev/parsedown/test/data/special_characters.html
@@ -0,0 +1,6 @@
+
\ No newline at end of file
diff --git a/vendor/erusev/parsedown/test/data/special_characters.md b/vendor/erusev/parsedown/test/data/special_characters.md
new file mode 100644
index 00000000..111b03b6
--- /dev/null
+++ b/vendor/erusev/parsedown/test/data/special_characters.md
@@ -0,0 +1,13 @@
+AT&T has an ampersand in their name
+
+this & that
+
+4 < 5 and 6 > 5
+
+
+
+[inline link](/script?a=1&b=2)
+
+[reference link][1]
+
+[1]: http://example.com/?a=1&b=2
\ No newline at end of file
diff --git a/vendor/erusev/parsedown/test/data/strikethrough.html b/vendor/erusev/parsedown/test/data/strikethrough.html
new file mode 100644
index 00000000..2a9da982
--- /dev/null
+++ b/vendor/erusev/parsedown/test/data/strikethrough.html
@@ -0,0 +1,3 @@
+
strikethrough
+
here's one followed by another one
+
~~ this ~~ is not one neither is ~this~
\ No newline at end of file
diff --git a/vendor/erusev/parsedown/test/data/strikethrough.md b/vendor/erusev/parsedown/test/data/strikethrough.md
new file mode 100644
index 00000000..d169144d
--- /dev/null
+++ b/vendor/erusev/parsedown/test/data/strikethrough.md
@@ -0,0 +1,5 @@
+~~strikethrough~~
+
+here's ~~one~~ followed by ~~another one~~
+
+~~ this ~~ is not one neither is ~this~
\ No newline at end of file
diff --git a/vendor/erusev/parsedown/test/data/strong_em.html b/vendor/erusev/parsedown/test/data/strong_em.html
new file mode 100644
index 00000000..b709c991
--- /dev/null
+++ b/vendor/erusev/parsedown/test/data/strong_em.html
@@ -0,0 +1,6 @@
+
em strong em
+
strong em em
+
em strong em em
+
em strong em
+
strong em em
+
em strong em em
\ No newline at end of file
diff --git a/vendor/erusev/parsedown/test/data/strong_em.md b/vendor/erusev/parsedown/test/data/strong_em.md
new file mode 100644
index 00000000..f2aa3c78
--- /dev/null
+++ b/vendor/erusev/parsedown/test/data/strong_em.md
@@ -0,0 +1,11 @@
+*em **strong em***
+
+***strong em** em*
+
+*em **strong em** em*
+
+_em __strong em___
+
+___strong em__ em_
+
+_em __strong em__ em_
\ No newline at end of file
diff --git a/vendor/erusev/parsedown/test/data/tab-indented_code_block.html b/vendor/erusev/parsedown/test/data/tab-indented_code_block.html
new file mode 100644
index 00000000..7c140de7
--- /dev/null
+++ b/vendor/erusev/parsedown/test/data/tab-indented_code_block.html
@@ -0,0 +1,6 @@
+
\ No newline at end of file
diff --git a/vendor/erusev/parsedown/test/data/tab-indented_code_block.md b/vendor/erusev/parsedown/test/data/tab-indented_code_block.md
new file mode 100644
index 00000000..a405a160
--- /dev/null
+++ b/vendor/erusev/parsedown/test/data/tab-indented_code_block.md
@@ -0,0 +1,6 @@
+
+
+
+
header 1
+
header 2
+
+
+
+
+
cell 1.1
+
cell 1.2
+
+
+
cell 2.1
+
cell 2.2
+
+
+
\ No newline at end of file
diff --git a/vendor/erusev/parsedown/test/data/table_inline_markdown.md b/vendor/erusev/parsedown/test/data/table_inline_markdown.md
new file mode 100644
index 00000000..c2fe1080
--- /dev/null
+++ b/vendor/erusev/parsedown/test/data/table_inline_markdown.md
@@ -0,0 +1,4 @@
+| _header_ 1 | header 2 |
+| ------------ | ------------ |
+| _cell_ 1.1 | ~~cell~~ 1.2 |
+| `cell` 2.1 | cell 2.2 |
\ No newline at end of file
diff --git a/vendor/erusev/parsedown/test/data/text_reference.html b/vendor/erusev/parsedown/test/data/text_reference.html
new file mode 100644
index 00000000..11e4d37f
--- /dev/null
+++ b/vendor/erusev/parsedown/test/data/text_reference.html
@@ -0,0 +1,8 @@
+
\ No newline at end of file
diff --git a/vendor/erusev/parsedown/test/data/text_reference.md b/vendor/erusev/parsedown/test/data/text_reference.md
new file mode 100644
index 00000000..1a66a5cf
--- /dev/null
+++ b/vendor/erusev/parsedown/test/data/text_reference.md
@@ -0,0 +1,21 @@
+[reference link][1]
+
+[1]: http://example.com
+
+[one][website] with a semantic name
+
+[website]: http://example.com
+
+[one][404] with no definition
+
+[multiline
+one][website] defined on 2 lines
+
+[one][Label] with a mixed case label and an upper case definition
+
+[LABEL]: http://example.com
+
+[one]
+[1] with the a label on the next line
+
+[`link`][website]
\ No newline at end of file
diff --git a/vendor/erusev/parsedown/test/data/unordered_list.html b/vendor/erusev/parsedown/test/data/unordered_list.html
new file mode 100644
index 00000000..cd95567b
--- /dev/null
+++ b/vendor/erusev/parsedown/test/data/unordered_list.html
@@ -0,0 +1,10 @@
+
+
li
+
li
+
+
mixed markers:
+
+
li
+
li
+
li
+
\ No newline at end of file
diff --git a/vendor/erusev/parsedown/test/data/unordered_list.md b/vendor/erusev/parsedown/test/data/unordered_list.md
new file mode 100644
index 00000000..cf62c99f
--- /dev/null
+++ b/vendor/erusev/parsedown/test/data/unordered_list.md
@@ -0,0 +1,8 @@
+- li
+- li
+
+mixed markers:
+
+* li
++ li
+- li
\ No newline at end of file
diff --git a/vendor/erusev/parsedown/test/data/untidy_table.html b/vendor/erusev/parsedown/test/data/untidy_table.html
new file mode 100644
index 00000000..88e1c2bd
--- /dev/null
+++ b/vendor/erusev/parsedown/test/data/untidy_table.html
@@ -0,0 +1,18 @@
+
+
+
+
header 1
+
header 2
+
+
+
+
+
cell 1.1
+
cell 1.2
+
+
+
cell 2.1
+
cell 2.2
+
+
+
\ No newline at end of file
diff --git a/vendor/erusev/parsedown/test/data/untidy_table.md b/vendor/erusev/parsedown/test/data/untidy_table.md
new file mode 100644
index 00000000..8524eb18
--- /dev/null
+++ b/vendor/erusev/parsedown/test/data/untidy_table.md
@@ -0,0 +1,4 @@
+| header 1 | header 2 |
+| ------------- | ----------- |
+| cell 1.1 | cell 1.2 |
+| cell 2.1 | cell 2.2 |
\ No newline at end of file
diff --git a/vendor/erusev/parsedown/test/data/url_autolinking.html b/vendor/erusev/parsedown/test/data/url_autolinking.html
new file mode 100644
index 00000000..58ca94c6
--- /dev/null
+++ b/vendor/erusev/parsedown/test/data/url_autolinking.html
@@ -0,0 +1,3 @@
+
\ No newline at end of file
diff --git a/vendor/erusev/parsedown/test/data/url_autolinking.md b/vendor/erusev/parsedown/test/data/url_autolinking.md
new file mode 100644
index 00000000..840f3540
--- /dev/null
+++ b/vendor/erusev/parsedown/test/data/url_autolinking.md
@@ -0,0 +1,5 @@
+an autolink http://example.com
+
+inside of brackets [http://example.com], inside of braces {http://example.com}, inside of parentheses (http://example.com)
+
+trailing slash http://example.com/ and http://example.com/path/
\ No newline at end of file
diff --git a/vendor/erusev/parsedown/test/data/whitespace.html b/vendor/erusev/parsedown/test/data/whitespace.html
new file mode 100644
index 00000000..f2dd7a00
--- /dev/null
+++ b/vendor/erusev/parsedown/test/data/whitespace.html
@@ -0,0 +1 @@
+
code
\ No newline at end of file
diff --git a/vendor/erusev/parsedown/test/data/whitespace.md b/vendor/erusev/parsedown/test/data/whitespace.md
new file mode 100644
index 00000000..4cf926a8
--- /dev/null
+++ b/vendor/erusev/parsedown/test/data/whitespace.md
@@ -0,0 +1,5 @@
+
+
+ code
+
+
\ No newline at end of file
diff --git a/vendor/fguillot/json-rpc b/vendor/fguillot/json-rpc
new file mode 160000
index 00000000..66db4093
--- /dev/null
+++ b/vendor/fguillot/json-rpc
@@ -0,0 +1 @@
+Subproject commit 66db4093984790c34577c0ba0e17f2e3d2dc14a0
diff --git a/vendor/fguillot/picodb b/vendor/fguillot/picodb
new file mode 160000
index 00000000..dbf15938
--- /dev/null
+++ b/vendor/fguillot/picodb
@@ -0,0 +1 @@
+Subproject commit dbf15938687ca800abfccc424390add33dd95181
diff --git a/vendor/fguillot/simple-validator b/vendor/fguillot/simple-validator
new file mode 160000
index 00000000..14f7c0b1
--- /dev/null
+++ b/vendor/fguillot/simple-validator
@@ -0,0 +1 @@
+Subproject commit 14f7c0b111444a5b26ce447ef5f0de655279b5f1
diff --git a/vendor/ircmaxell/password-compat/.travis.yml b/vendor/ircmaxell/password-compat/.travis.yml
new file mode 100644
index 00000000..a960061c
--- /dev/null
+++ b/vendor/ircmaxell/password-compat/.travis.yml
@@ -0,0 +1,8 @@
+language: php
+
+php:
+ - 5.5
+ - 5.4
+ - 5.3
+
+script: phpunit --configuration phpunit.xml.dist
\ No newline at end of file
diff --git a/vendor/ircmaxell/password-compat/LICENSE.md b/vendor/ircmaxell/password-compat/LICENSE.md
new file mode 100644
index 00000000..1efc565f
--- /dev/null
+++ b/vendor/ircmaxell/password-compat/LICENSE.md
@@ -0,0 +1,7 @@
+Copyright (c) 2012 Anthony Ferrara
+
+Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
\ No newline at end of file
diff --git a/vendor/ircmaxell/password-compat/README.md b/vendor/ircmaxell/password-compat/README.md
new file mode 100644
index 00000000..e158f7d0
--- /dev/null
+++ b/vendor/ircmaxell/password-compat/README.md
@@ -0,0 +1,75 @@
+password_compat
+===============
+
+[![Build Status](https://travis-ci.org/ircmaxell/password_compat.png?branch=master)](https://travis-ci.org/ircmaxell/password_compat)
+
+This library is intended to provide forward compatibility with the password_* functions being worked on for PHP 5.5.
+
+See [the RFC](https://wiki.php.net/rfc/password_hash) for more detailed information.
+
+
+Requirements
+============
+
+This library requires `PHP >= 5.3.7` OR a version that has the `$2y` fix backported into it (such as Debian provides).
+
+The runtime checks have been removed due to this version issue. To see if password_compat is available for your system, run the included `version-test.php`. If it outputs "Pass", you can safely use the library. If not, you cannot.
+
+If you attempt to use password-compat on an unsupported version, attempts to create or verify hashes will return `false`. You have been warned!
+
+The reason for this is that PHP prior to 5.3.7 contains a security issue with its BCRYPT implementation. Therefore, it's highly recommended that you upgrade to a newer version of PHP prior to using this layer.
+
+Installation
+============
+
+To install, simply `require` the `password.php` file under `lib`.
+
+You can also install it via `Composer` by using the [Packagist archive](http://packagist.org/packages/ircmaxell/password-compat).
+
+Usage
+=====
+
+**Creating Password Hashes**
+
+To create a password hash from a password, simply use the `password_hash` function.
+
+ $hash = password_hash($password, PASSWORD_BCRYPT);
+
+Note that the algorithm that we chose is `PASSWORD_BCRYPT`. That's the current strongest algorithm supported. This is the `BCRYPT` crypt algorithm. It produces a 60 character hash as the result.
+
+`BCRYPT` also allows for you to define a `cost` parameter in the options array. This allows for you to change the CPU cost of the algorithm:
+
+ $hash = password_hash($password, PASSWORD_BCRYPT, ["cost" => 10]);
+
+That's the same as the default. The cost can range from `4` to `31`. I would suggest that you use the highest cost that you can, while keeping response time reasonable (I target between 0.1 and 0.5 seconds for a hash, depending on use-case).
+
+Another algorithm name is supported:
+
+ PASSWORD_DEFAULT
+
+This will use the strongest algorithm available to PHP at the current time. Presently, this is the same as specifying `PASSWORD_BCRYPT`. But in future versions of PHP, it may be updated to use a stronger algorithm if one is introduced. It can also be changed if a problem is identified with the BCRYPT algorithm. Note that if you use this option, you are **strongly** encouraged to store it in a `VARCHAR(255)` column to avoid truncation issues if a future algorithm increases the length of the generated hash.
+
+It is very important that you should check the return value of `password_hash` prior to storing it, because a `false` may be returned if it encountered an error.
+
+**Verifying Password Hashes**
+
+To verify a hash created by `password_hash`, simply call:
+
+ if (password_verify($password, $hash)) {
+ /* Valid */
+ } else {
+ /* Invalid */
+ }
+
+That's all there is to it.
+
+**Rehashing Passwords**
+
+From time to time you may update your hashing parameters (algorithm, cost, etc). So a function to determine if rehashing is necessary is available:
+
+ if (password_verify($password, $hash)) {
+ if (password_needs_rehash($hash, $algorithm, $options)) {
+ $hash = password_hash($password, $algorithm, $options);
+ /* Store new hash in db */
+ }
+ }
diff --git a/vendor/ircmaxell/password-compat/composer.json b/vendor/ircmaxell/password-compat/composer.json
new file mode 100644
index 00000000..e0d4f14c
--- /dev/null
+++ b/vendor/ircmaxell/password-compat/composer.json
@@ -0,0 +1,18 @@
+{
+ "name": "ircmaxell/password-compat",
+ "description": "A compatibility library for the proposed simplified password hashing algorithm: https://wiki.php.net/rfc/password_hash",
+ "version": "1.0.3",
+ "keywords": ["password", "hashing"],
+ "homepage": "https://github.com/ircmaxell/password_compat",
+ "license": "MIT",
+ "authors": [
+ {
+ "name": "Anthony Ferrara",
+ "email": "ircmaxell@php.net",
+ "homepage": "http://blog.ircmaxell.com"
+ }
+ ],
+ "autoload": {
+ "files": ["lib/password.php"]
+ }
+}
\ No newline at end of file
diff --git a/vendor/ircmaxell/password-compat/lib/password.php b/vendor/ircmaxell/password-compat/lib/password.php
new file mode 100644
index 00000000..4d0e8b7a
--- /dev/null
+++ b/vendor/ircmaxell/password-compat/lib/password.php
@@ -0,0 +1,222 @@
+
+ * @license http://www.opensource.org/licenses/mit-license.html MIT License
+ * @copyright 2012 The Authors
+ */
+
+if (!defined('PASSWORD_BCRYPT')) {
+
+ define('PASSWORD_BCRYPT', 1);
+ define('PASSWORD_DEFAULT', PASSWORD_BCRYPT);
+
+ /**
+ * Hash the password using the specified algorithm
+ *
+ * @param string $password The password to hash
+ * @param int $algo The algorithm to use (Defined by PASSWORD_* constants)
+ * @param array $options The options for the algorithm to use
+ *
+ * @return string|false The hashed password, or false on error.
+ */
+ function password_hash($password, $algo, array $options = array()) {
+ if (!function_exists('crypt')) {
+ trigger_error("Crypt must be loaded for password_hash to function", E_USER_WARNING);
+ return null;
+ }
+ if (!is_string($password)) {
+ trigger_error("password_hash(): Password must be a string", E_USER_WARNING);
+ return null;
+ }
+ if (!is_int($algo)) {
+ trigger_error("password_hash() expects parameter 2 to be long, " . gettype($algo) . " given", E_USER_WARNING);
+ return null;
+ }
+ switch ($algo) {
+ case PASSWORD_BCRYPT:
+ // Note that this is a C constant, but not exposed to PHP, so we don't define it here.
+ $cost = 10;
+ if (isset($options['cost'])) {
+ $cost = $options['cost'];
+ if ($cost < 4 || $cost > 31) {
+ trigger_error(sprintf("password_hash(): Invalid bcrypt cost parameter specified: %d", $cost), E_USER_WARNING);
+ return null;
+ }
+ }
+ // The length of salt to generate
+ $raw_salt_len = 16;
+ // The length required in the final serialization
+ $required_salt_len = 22;
+ $hash_format = sprintf("$2y$%02d$", $cost);
+ break;
+ default:
+ trigger_error(sprintf("password_hash(): Unknown password hashing algorithm: %s", $algo), E_USER_WARNING);
+ return null;
+ }
+ if (isset($options['salt'])) {
+ switch (gettype($options['salt'])) {
+ case 'NULL':
+ case 'boolean':
+ case 'integer':
+ case 'double':
+ case 'string':
+ $salt = (string) $options['salt'];
+ break;
+ case 'object':
+ if (method_exists($options['salt'], '__tostring')) {
+ $salt = (string) $options['salt'];
+ break;
+ }
+ case 'array':
+ case 'resource':
+ default:
+ trigger_error('password_hash(): Non-string salt parameter supplied', E_USER_WARNING);
+ return null;
+ }
+ if (strlen($salt) < $required_salt_len) {
+ trigger_error(sprintf("password_hash(): Provided salt is too short: %d expecting %d", strlen($salt), $required_salt_len), E_USER_WARNING);
+ return null;
+ } elseif (0 == preg_match('#^[a-zA-Z0-9./]+$#D', $salt)) {
+ $salt = str_replace('+', '.', base64_encode($salt));
+ }
+ } else {
+ $buffer = '';
+ $buffer_valid = false;
+ if (function_exists('mcrypt_create_iv') && !defined('PHALANGER')) {
+ $buffer = mcrypt_create_iv($raw_salt_len, MCRYPT_DEV_URANDOM);
+ if ($buffer) {
+ $buffer_valid = true;
+ }
+ }
+ if (!$buffer_valid && function_exists('openssl_random_pseudo_bytes')) {
+ $buffer = openssl_random_pseudo_bytes($raw_salt_len);
+ if ($buffer) {
+ $buffer_valid = true;
+ }
+ }
+ if (!$buffer_valid && is_readable('/dev/urandom')) {
+ $f = fopen('/dev/urandom', 'r');
+ $read = strlen($buffer);
+ while ($read < $raw_salt_len) {
+ $buffer .= fread($f, $raw_salt_len - $read);
+ $read = strlen($buffer);
+ }
+ fclose($f);
+ if ($read >= $raw_salt_len) {
+ $buffer_valid = true;
+ }
+ }
+ if (!$buffer_valid || strlen($buffer) < $raw_salt_len) {
+ $bl = strlen($buffer);
+ for ($i = 0; $i < $raw_salt_len; $i++) {
+ if ($i < $bl) {
+ $buffer[$i] = $buffer[$i] ^ chr(mt_rand(0, 255));
+ } else {
+ $buffer .= chr(mt_rand(0, 255));
+ }
+ }
+ }
+ $salt = str_replace('+', '.', base64_encode($buffer));
+ }
+ $salt = substr($salt, 0, $required_salt_len);
+
+ $hash = $hash_format . $salt;
+
+ $ret = crypt($password, $hash);
+
+ if (!is_string($ret) || strlen($ret) <= 13) {
+ return false;
+ }
+
+ return $ret;
+ }
+
+ /**
+ * Get information about the password hash. Returns an array of the information
+ * that was used to generate the password hash.
+ *
+ * array(
+ * 'algo' => 1,
+ * 'algoName' => 'bcrypt',
+ * 'options' => array(
+ * 'cost' => 10,
+ * ),
+ * )
+ *
+ * @param string $hash The password hash to extract info from
+ *
+ * @return array The array of information about the hash.
+ */
+ function password_get_info($hash) {
+ $return = array(
+ 'algo' => 0,
+ 'algoName' => 'unknown',
+ 'options' => array(),
+ );
+ if (substr($hash, 0, 4) == '$2y$' && strlen($hash) == 60) {
+ $return['algo'] = PASSWORD_BCRYPT;
+ $return['algoName'] = 'bcrypt';
+ list($cost) = sscanf($hash, "$2y$%d$");
+ $return['options']['cost'] = $cost;
+ }
+ return $return;
+ }
+
+ /**
+ * Determine if the password hash needs to be rehashed according to the options provided
+ *
+ * If the answer is true, after validating the password using password_verify, rehash it.
+ *
+ * @param string $hash The hash to test
+ * @param int $algo The algorithm used for new password hashes
+ * @param array $options The options array passed to password_hash
+ *
+ * @return boolean True if the password needs to be rehashed.
+ */
+ function password_needs_rehash($hash, $algo, array $options = array()) {
+ $info = password_get_info($hash);
+ if ($info['algo'] != $algo) {
+ return true;
+ }
+ switch ($algo) {
+ case PASSWORD_BCRYPT:
+ $cost = isset($options['cost']) ? $options['cost'] : 10;
+ if ($cost != $info['options']['cost']) {
+ return true;
+ }
+ break;
+ }
+ return false;
+ }
+
+ /**
+ * Verify a password against a hash using a timing attack resistant approach
+ *
+ * @param string $password The password to verify
+ * @param string $hash The hash to verify against
+ *
+ * @return boolean If the password matches the hash
+ */
+ function password_verify($password, $hash) {
+ if (!function_exists('crypt')) {
+ trigger_error("Crypt must be loaded for password_verify to function", E_USER_WARNING);
+ return false;
+ }
+ $ret = crypt($password, $hash);
+ if (!is_string($ret) || strlen($ret) != strlen($hash) || strlen($ret) <= 13) {
+ return false;
+ }
+
+ $status = 0;
+ for ($i = 0; $i < strlen($ret); $i++) {
+ $status |= (ord($ret[$i]) ^ ord($hash[$i]));
+ }
+
+ return $status === 0;
+ }
+}
+
+
+
diff --git a/vendor/ircmaxell/password-compat/phpunit.xml.dist b/vendor/ircmaxell/password-compat/phpunit.xml.dist
new file mode 100644
index 00000000..b2b3afbd
--- /dev/null
+++ b/vendor/ircmaxell/password-compat/phpunit.xml.dist
@@ -0,0 +1,29 @@
+
+
+
+
+ test/Unit
+
+
+
+
+ lib/
+
+
+
diff --git a/vendor/ircmaxell/password-compat/test/Unit/PasswordGetInfoTest.php b/vendor/ircmaxell/password-compat/test/Unit/PasswordGetInfoTest.php
new file mode 100644
index 00000000..6aab976a
--- /dev/null
+++ b/vendor/ircmaxell/password-compat/test/Unit/PasswordGetInfoTest.php
@@ -0,0 +1,26 @@
+ 0, 'algoName' => 'unknown', 'options' => array())),
+ array('$2y$', array('algo' => 0, 'algoName' => 'unknown', 'options' => array())),
+ array('$2y$07$usesomesillystringfore2uDLvp1Ii2e./U9C8sBjqp8I90dH6hi', array('algo' => PASSWORD_BCRYPT, 'algoName' => 'bcrypt', 'options' => array('cost' => 7))),
+ array('$2y$10$usesomesillystringfore2uDLvp1Ii2e./U9C8sBjqp8I90dH6hi', array('algo' => PASSWORD_BCRYPT, 'algoName' => 'bcrypt', 'options' => array('cost' => 10))),
+
+ );
+ }
+
+ public function testFuncExists() {
+ $this->assertTrue(function_exists('password_get_info'));
+ }
+
+ /**
+ * @dataProvider provideInfo
+ */
+ public function testInfo($hash, $info) {
+ $this->assertEquals($info, password_get_info($hash));
+ }
+
+}
\ No newline at end of file
diff --git a/vendor/ircmaxell/password-compat/test/Unit/PasswordHashTest.php b/vendor/ircmaxell/password-compat/test/Unit/PasswordHashTest.php
new file mode 100644
index 00000000..9e5e9ec6
--- /dev/null
+++ b/vendor/ircmaxell/password-compat/test/Unit/PasswordHashTest.php
@@ -0,0 +1,84 @@
+assertTrue(function_exists('password_hash'));
+ }
+
+ public function testStringLength() {
+ $this->assertEquals(60, strlen(password_hash('foo', PASSWORD_BCRYPT)));
+ }
+
+ public function testHash() {
+ $hash = password_hash('foo', PASSWORD_BCRYPT);
+ $this->assertEquals($hash, crypt('foo', $hash));
+ }
+
+ public function testKnownSalt() {
+ $hash = password_hash("rasmuslerdorf", PASSWORD_BCRYPT, array("cost" => 7, "salt" => "usesomesillystringforsalt"));
+ $this->assertEquals('$2y$07$usesomesillystringfore2uDLvp1Ii2e./U9C8sBjqp8I90dH6hi', $hash);
+ }
+
+ public function testRawSalt() {
+ $hash = password_hash("test", PASSWORD_BCRYPT, array("salt" => "123456789012345678901" . chr(0)));
+ $this->assertEquals('$2y$10$MTIzNDU2Nzg5MDEyMzQ1Nej0NmcAWSLR.oP7XOR9HD/vjUuOj100y', $hash);
+ }
+
+ /**
+ * @expectedException PHPUnit_Framework_Error
+ */
+ public function testInvalidAlgo() {
+ password_hash('foo', array());
+ }
+
+ /**
+ * @expectedException PHPUnit_Framework_Error
+ */
+ public function testInvalidAlgo2() {
+ password_hash('foo', 2);
+ }
+
+ /**
+ * @expectedException PHPUnit_Framework_Error
+ */
+ public function testInvalidPassword() {
+ password_hash(array(), 1);
+ }
+
+ /**
+ * @expectedException PHPUnit_Framework_Error
+ */
+ public function testInvalidSalt() {
+ password_hash('foo', PASSWORD_BCRYPT, array('salt' => array()));
+ }
+
+ /**
+ * @expectedException PHPUnit_Framework_Error
+ */
+ public function testInvalidBcryptCostLow() {
+ password_hash('foo', PASSWORD_BCRYPT, array('cost' => 3));
+ }
+
+ /**
+ * @expectedException PHPUnit_Framework_Error
+ */
+ public function testInvalidBcryptCostHigh() {
+ password_hash('foo', PASSWORD_BCRYPT, array('cost' => 32));
+ }
+
+ /**
+ * @expectedException PHPUnit_Framework_Error
+ */
+ public function testInvalidBcryptCostInvalid() {
+ password_hash('foo', PASSWORD_BCRYPT, array('cost' => 'foo'));
+ }
+
+ /**
+ * @expectedException PHPUnit_Framework_Error
+ */
+ public function testInvalidBcryptSaltShort() {
+ password_hash('foo', PASSWORD_BCRYPT, array('salt' => 'abc'));
+ }
+
+}
\ No newline at end of file
diff --git a/vendor/ircmaxell/password-compat/test/Unit/PasswordNeedsRehashTest.php b/vendor/ircmaxell/password-compat/test/Unit/PasswordNeedsRehashTest.php
new file mode 100644
index 00000000..c2932dc6
--- /dev/null
+++ b/vendor/ircmaxell/password-compat/test/Unit/PasswordNeedsRehashTest.php
@@ -0,0 +1,26 @@
+ 7), false),
+ array('$2y$07$usesomesillystringfore2udlvp1ii2e./u9c8sbjqp8i90dh6hi', PASSWORD_BCRYPT, array('cost' => 5), true),
+ );
+ }
+
+ public function testFuncExists() {
+ $this->assertTrue(function_exists('password_needs_rehash'));
+ }
+
+ /**
+ * @dataProvider provideCases
+ */
+ public function testCases($hash, $algo, $options, $valid) {
+ $this->assertEquals($valid, password_needs_rehash($hash, $algo, $options));
+ }
+
+}
\ No newline at end of file
diff --git a/vendor/ircmaxell/password-compat/test/Unit/PasswordVerifyTest.php b/vendor/ircmaxell/password-compat/test/Unit/PasswordVerifyTest.php
new file mode 100644
index 00000000..9f67bb9f
--- /dev/null
+++ b/vendor/ircmaxell/password-compat/test/Unit/PasswordVerifyTest.php
@@ -0,0 +1,29 @@
+assertTrue(function_exists('password_verify'));
+ }
+
+ public function testFailedType() {
+ $this->assertFalse(password_verify(123, 123));
+ }
+
+ public function testSaltOnly() {
+ $this->assertFalse(password_verify('foo', '$2a$07$usesomesillystringforsalt$'));
+ }
+
+ public function testInvalidPassword() {
+ $this->assertFalse(password_verify('rasmusler', '$2a$07$usesomesillystringfore2uDLvp1Ii2e./U9C8sBjqp8I90dH6hi'));
+ }
+
+ public function testValidPassword() {
+ $this->assertTrue(password_verify('rasmuslerdorf', '$2a$07$usesomesillystringfore2uDLvp1Ii2e./U9C8sBjqp8I90dH6hi'));
+ }
+
+ public function testInValidHash() {
+ $this->assertFalse(password_verify('rasmuslerdorf', '$2a$07$usesomesillystringfore2uDLvp1Ii2e./U9C8sBjqp8I90dH6hj'));
+ }
+
+}
\ No newline at end of file
diff --git a/vendor/ircmaxell/password-compat/version-test.php b/vendor/ircmaxell/password-compat/version-test.php
new file mode 100644
index 00000000..f527e30f
--- /dev/null
+++ b/vendor/ircmaxell/password-compat/version-test.php
@@ -0,0 +1,8 @@
+
+Contributions (c) 2013 Pieter Hordijk
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is furnished
+to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
diff --git a/vendor/lusitanian/oauth/README.md b/vendor/lusitanian/oauth/README.md
new file mode 100644
index 00000000..e7c2f792
--- /dev/null
+++ b/vendor/lusitanian/oauth/README.md
@@ -0,0 +1,102 @@
+PHPoAuthLib
+===========
+PHPoAuthLib provides oAuth support in PHP 5.3+ and is very easy to integrate with any project which requires an oAuth client.
+
+[![Build Status](https://travis-ci.org/Lusitanian/PHPoAuthLib.png?branch=master)](https://travis-ci.org/Lusitanian/PHPoAuthLib)
+[![Code Coverage](https://scrutinizer-ci.com/g/Lusitanian/PHPoAuthLib/badges/coverage.png?s=a0a15bebfda49e79f9ce289b00c6dfebd18fc98e)](https://scrutinizer-ci.com/g/Lusitanian/PHPoAuthLib/)
+[![Scrutinizer Quality Score](https://scrutinizer-ci.com/g/Lusitanian/PHPoAuthLib/badges/quality-score.png?s=c5976d2fefceb501f0d886c1a5bf087e69b44533)](https://scrutinizer-ci.com/g/Lusitanian/PHPoAuthLib/)
+[![Latest Stable Version](https://poser.pugx.org/lusitanian/oauth/v/stable.png)](https://packagist.org/packages/lusitanian/oauth)
+[![Total Downloads](https://poser.pugx.org/lusitanian/oauth/downloads.png)](https://packagist.org/packages/lusitanian/oauth)
+
+Installation
+------------
+This library can be found on [Packagist](https://packagist.org/packages/lusitanian/oauth).
+The recommended way to install this is through [composer](http://getcomposer.org).
+
+Edit your `composer.json` and add:
+
+```json
+{
+ "require": {
+ "lusitanian/oauth": "~0.3"
+ }
+}
+```
+
+And install dependencies:
+
+```bash
+$ curl -sS https://getcomposer.org/installer | php
+$ php composer.phar install
+```
+
+Features
+--------
+- PSR-0 compliant for easy interoperability
+- Fully extensible in every facet.
+ - You can implement any service with any custom requirements by extending the protocol version's `AbstractService` implementation.
+ - You can use any HTTP client you desire, just create a class utilizing it which implements `OAuth\Common\Http\ClientInterface` (two implementations are included)
+ - You can use any storage mechanism for tokens. By default, session, in-memory and Redis.io (requires PHPRedis) storage mechanisms are included. Implement additional mechanisms by implementing `OAuth\Common\Token\TokenStorageInterface`.
+
+Service support
+---------------
+The library supports both oAuth 1.x and oAuth 2.0 compliant services. A list of currently implemented services can be found below.
+
+Included service implementations
+--------------------------------
+- OAuth1
+ - BitBucket
+ - Etsy
+ - FitBit
+ - Flickr
+ - Scoop.it!
+ - Tumblr
+ - Twitter
+ - Xing
+ - Yahoo
+- OAuth2
+ - Amazon
+ - BitLy
+ - Box
+ - Dailymotion
+ - Dropbox
+ - Facebook
+ - Foursquare
+ - GitHub
+ - Google
+ - Harvest
+ - Heroku
+ - Instagram
+ - LinkedIn
+ - Mailchimp
+ - Microsoft
+ - PayPal
+ - Pocket
+ - Reddit
+ - RunKeeper
+ - SoundCloud
+ - Ustream
+ - Vkontakte
+ - Yammer
+- more to come!
+
+Examples
+--------
+Examples of basic usage are located in the examples/ directory.
+
+Usage
+------
+For usage with complete auth flow, please see the examples. More in-depth documentation will come with release 1.0.
+
+Framework Integration
+---------------------
+* Lithium: Sébastien Charrier has written [an adapter](https://github.com/scharrier/li3_socialauth) for the library.
+* Laravel 4: Dariusz Prząda has written [a service provider](https://github.com/artdarek/oauth-4-laravel) for the library.
+
+Extensions
+----------
+* Extract normalized user data from OAuth Services with the library [PHPoAuthUserData](https://github.com/Oryzone/PHPoAuthUserData) by Luciano Mammino
+
+Tests
+------
+To run the tests, you must install dependencies with `composer install --dev`
diff --git a/vendor/lusitanian/oauth/composer.json b/vendor/lusitanian/oauth/composer.json
new file mode 100644
index 00000000..cc0bdcf2
--- /dev/null
+++ b/vendor/lusitanian/oauth/composer.json
@@ -0,0 +1,40 @@
+{
+ "name": "lusitanian/oauth",
+ "description": "PHP 5.3+ oAuth 1/2 Library",
+ "keywords": ["oauth", "authentication", "authorization", "security"],
+ "license": "MIT",
+ "authors": [
+ {
+ "name": "David Desberg",
+ "email": "david@daviddesberg.com"
+ },
+ {
+ "name": "Pieter Hordijk",
+ "email": "info@pieterhordijk.com"
+ }
+ ],
+ "require": {
+ "php": ">=5.3.0"
+ },
+ "require-dev": {
+ "symfony/http-foundation": "~2.1",
+ "predis/predis": "0.8.*@dev",
+ "phpunit/phpunit": "3.7.*"
+ },
+ "suggest": {
+ "symfony/http-foundation": "Allows using the Symfony Session storage backend.",
+ "predis/predis": "Allows using the Redis storage backend.",
+ "ext-openssl": "Allows for usage of secure connections with the stream-based HTTP client."
+ },
+ "autoload": {
+ "psr-0": {
+ "OAuth": "src",
+ "OAuth\\Unit": "tests"
+ }
+ },
+ "extra": {
+ "branch-alias": {
+ "dev-master": "0.1-dev"
+ }
+ }
+}
diff --git a/vendor/lusitanian/oauth/examples/amazon.php b/vendor/lusitanian/oauth/examples/amazon.php
new file mode 100644
index 00000000..0798eafc
--- /dev/null
+++ b/vendor/lusitanian/oauth/examples/amazon.php
@@ -0,0 +1,52 @@
+
+ * @copyright Copyright (c) 2012 The authors
+ * @license http://www.opensource.org/licenses/mit-license.html MIT License
+ */
+
+use OAuth\OAuth2\Service\Amazon;
+use OAuth\Common\Storage\Session;
+use OAuth\Common\Consumer\Credentials;
+
+/**
+ * Bootstrap the example
+ */
+require_once __DIR__ . '/bootstrap.php';
+
+// Session storage
+$storage = new Session();
+
+// Setup the credentials for the requests
+$credentials = new Credentials(
+ $servicesCredentials['amazon']['key'],
+ $servicesCredentials['amazon']['secret'],
+ $currentUri->getAbsoluteUri()
+);
+
+// Instantiate the Amazon service using the credentials, http client, storage mechanism for the token and profile scope
+/** @var $amazonService Amazon */
+$amazonService = $serviceFactory->createService('amazon', $credentials, $storage, array('profile'));
+
+if (!empty($_GET['code'])) {
+ // This was a callback request from Amazon, get the token
+ $token = $amazonService->requestAccessToken($_GET['code']);
+
+ // Send a request with it
+ $result = json_decode($amazonService->request('/user/profile'), true);
+
+ // Show some of the resultant data
+ echo 'Your unique Amazon user id is: ' . $result['user_id'] . ' and your name is ' . $result['name'];
+
+} elseif (!empty($_GET['go']) && $_GET['go'] === 'go') {
+ $url = $amazonService->getAuthorizationUri();
+ header('Location: ' . $url);
+} else {
+ $url = $currentUri->getRelativeUri() . '?go=go';
+ echo "Login with Amazon!";
+}
diff --git a/vendor/lusitanian/oauth/examples/bitbucket.php b/vendor/lusitanian/oauth/examples/bitbucket.php
new file mode 100644
index 00000000..d9330961
--- /dev/null
+++ b/vendor/lusitanian/oauth/examples/bitbucket.php
@@ -0,0 +1,64 @@
+
+ *
+ * Shamelessly cribbed from work by:
+ * @author David Desberg
+ * @author Pieter Hordijk
+ * @copyright Copyright (c) 2012 The authors
+ * @license http://www.opensource.org/licenses/mit-license.html MIT License
+ */
+
+use OAuth\OAuth1\Service\BitBucket;
+use OAuth\Common\Storage\Session;
+use OAuth\Common\Consumer\Credentials;
+
+/**
+ * Bootstrap the example
+ */
+require_once __DIR__ . '/bootstrap.php';
+
+// We need to use a persistent storage to save the token, because oauth1 requires the token secret received before'
+// the redirect (request token request) in the access token request.
+$storage = new Session();
+
+// Setup the credentials for the requests
+$credentials = new Credentials(
+ $servicesCredentials['bitbucket']['key'],
+ $servicesCredentials['bitbucket']['secret'],
+ $currentUri->getAbsoluteUri()
+);
+
+// Instantiate the BitBucket service using the credentials, http client and storage mechanism for the token
+/** @var $bbService BitBucket */
+$bbService = $serviceFactory->createService('BitBucket', $credentials, $storage);
+
+if (!empty($_GET['oauth_token'])) {
+ $token = $storage->retrieveAccessToken('BitBucket');
+
+ // This was a callback request from BitBucket, get the token
+ $bbService->requestAccessToken(
+ $_GET['oauth_token'],
+ $_GET['oauth_verifier'],
+ $token->getRequestTokenSecret()
+ );
+
+ // Send a request now that we have access token
+ $result = json_decode($bbService->request('user/repositories'));
+
+ echo('The first repo in the list is ' . $result[0]->name);
+
+} elseif (!empty($_GET['go']) && $_GET['go'] === 'go') {
+ // extra request needed for oauth1 to request a request token :-)
+ $token = $bbService->requestRequestToken();
+
+ $url = $bbService->getAuthorizationUri(array('oauth_token' => $token->getRequestToken()));
+ header('Location: ' . $url);
+} else {
+ $url = $currentUri->getRelativeUri() . '?go=go';
+ echo "Login with BitBucket!";
+}
diff --git a/vendor/lusitanian/oauth/examples/bitly.php b/vendor/lusitanian/oauth/examples/bitly.php
new file mode 100644
index 00000000..9cd27e34
--- /dev/null
+++ b/vendor/lusitanian/oauth/examples/bitly.php
@@ -0,0 +1,53 @@
+
+ * @author Pieter Hordijk
+ * @copyright Copyright (c) 2012 The authors
+ * @license http://www.opensource.org/licenses/mit-license.html MIT License
+ */
+
+use OAuth\OAuth2\Service\Bitly;
+use OAuth\Common\Storage\Session;
+use OAuth\Common\Consumer\Credentials;
+
+/**
+ * Bootstrap the example
+ */
+require_once __DIR__ . '/bootstrap.php';
+
+// Session storage
+$storage = new Session();
+
+// Setup the credentials for the requests
+$credentials = new Credentials(
+ $servicesCredentials['bitly']['key'],
+ $servicesCredentials['bitly']['secret'],
+ $currentUri->getAbsoluteUri()
+);
+
+// Instantiate the Bitly service using the credentials, http client and storage mechanism for the token
+/** @var $bitlyService Bitly */
+$bitlyService = $serviceFactory->createService('bitly', $credentials, $storage);
+
+if (!empty($_GET['code'])) {
+ // This was a callback request from bitly, get the token
+ $bitlyService->requestAccessToken($_GET['code']);
+
+ // Send a request with it
+ $result = json_decode($bitlyService->request('user/info'), true);
+
+ // Show some of the resultant data
+ echo 'Your unique user id is: ' . $result['data']['login'] . ' and your name is ' . $result['data']['display_name'];
+
+} elseif (!empty($_GET['go']) && $_GET['go'] === 'go') {
+ $url = $bitlyService->getAuthorizationUri();
+ header('Location: ' . $url);
+} else {
+ $url = $currentUri->getRelativeUri() . '?go=go';
+ echo "Login with Bitly!";
+}
diff --git a/vendor/lusitanian/oauth/examples/bootstrap.php b/vendor/lusitanian/oauth/examples/bootstrap.php
new file mode 100644
index 00000000..f02da414
--- /dev/null
+++ b/vendor/lusitanian/oauth/examples/bootstrap.php
@@ -0,0 +1,29 @@
+createFromSuperGlobalArray($_SERVER);
+$currentUri->setQuery('');
+
+/**
+ * Load the credential for the different services
+ */
+require_once __DIR__ . '/init.php';
diff --git a/vendor/lusitanian/oauth/examples/box.php b/vendor/lusitanian/oauth/examples/box.php
new file mode 100644
index 00000000..f1b06443
--- /dev/null
+++ b/vendor/lusitanian/oauth/examples/box.php
@@ -0,0 +1,58 @@
+
+ * @author Pieter Hordijk
+ * @author Antoine Corcy
+ * @copyright Copyright (c) 2012 The authors
+ * @license http://www.opensource.org/licenses/mit-license.html MIT License
+ */
+
+use OAuth\OAuth2\Service\Box;
+use OAuth\Common\Storage\Session;
+use OAuth\Common\Consumer\Credentials;
+
+/**
+ * Bootstrap the example
+ */
+require_once __DIR__ . '/bootstrap.php';
+
+// Session storage
+$storage = new Session();
+
+// Setup the credentials for the requests
+$credentials = new Credentials(
+ $servicesCredentials['box']['key'],
+ $servicesCredentials['box']['secret'],
+ $currentUri->getAbsoluteUri()
+);
+
+// Instantiate the Box service using the credentials, http client and storage mechanism for the token
+/** @var $boxService Box */
+$boxService = $serviceFactory->createService('box', $credentials, $storage);
+
+if (!empty($_GET['code'])) {
+ // retrieve the CSRF state parameter
+ $state = isset($_GET['state']) ? $_GET['state'] : null;
+
+ // This was a callback request from box, get the token
+ $token = $boxService->requestAccessToken($_GET['code'], $state);
+
+ // Send a request with it
+ $result = json_decode($boxService->request('/users/me'), true);
+
+ // Show some of the resultant data
+ echo 'Your Box name is ' . $result['name'] . ' and your email is ' . $result['login'];
+
+} elseif (!empty($_GET['go']) && $_GET['go'] === 'go') {
+ $url = $boxService->getAuthorizationUri();
+ // var_dump($url);
+ header('Location: ' . $url);
+} else {
+ $url = $currentUri->getRelativeUri() . '?go=go';
+ echo "Login with Box!";
+}
diff --git a/vendor/lusitanian/oauth/examples/buffer.php b/vendor/lusitanian/oauth/examples/buffer.php
new file mode 100644
index 00000000..c1b9ddde
--- /dev/null
+++ b/vendor/lusitanian/oauth/examples/buffer.php
@@ -0,0 +1,53 @@
+
+ * @author Pieter Hordijk
+ * @copyright Copyright (c) 2012 The authors
+ * @license http://www.opensource.org/licenses/mit-license.html MIT License
+ */
+
+use OAuth\OAuth2\Service\Buffer;
+use OAuth\Common\Storage\Session;
+use OAuth\Common\Consumer\Credentials;
+
+/**
+ * Bootstrap the example
+ */
+require_once __DIR__ . '/bootstrap.php';
+
+// Session storage
+$storage = new Session();
+
+// Setup the credentials for the requests
+$credentials = new Credentials(
+ $servicesCredentials['buffer']['key'],
+ $servicesCredentials['buffer']['secret'],
+ $currentUri->getAbsoluteUri()
+);
+
+// Instantiate the buffer service using the credentials, http client and storage mechanism for the token
+/** @var $bufferService buffer */
+$bufferService = $serviceFactory->createService('buffer', $credentials, $storage);
+
+if (!empty($_GET['code'])) {
+ // This was a callback request from buffer, get the token
+ $bufferService->requestAccessToken($_GET['code']);
+
+ // Send a request with it
+ $result = json_decode($bufferService->request('user.json'), true);
+
+ // Show some of the resultant data
+ echo 'Your unique user id is: ' . $result['id'] . ' and your plan is ' . $result['plan'];
+
+} elseif (!empty($_GET['go']) && $_GET['go'] === 'go') {
+ $url = $bufferService->getAuthorizationUri();
+ header('Location: ' . $url);
+} else {
+ $url = $currentUri->getRelativeUri() . '?go=go';
+ echo "Login with buffer!";
+}
diff --git a/vendor/lusitanian/oauth/examples/dailymotion.php b/vendor/lusitanian/oauth/examples/dailymotion.php
new file mode 100644
index 00000000..53f0878a
--- /dev/null
+++ b/vendor/lusitanian/oauth/examples/dailymotion.php
@@ -0,0 +1,52 @@
+
+ * @copyright Copyright (c) 2012 The authors
+ * @license http://www.opensource.org/licenses/mit-license.html MIT License
+ */
+
+use OAuth\OAuth2\Service\Dailymotion;
+use OAuth\Common\Storage\Session;
+use OAuth\Common\Consumer\Credentials;
+
+/**
+ * Bootstrap the example
+ */
+require_once __DIR__ . '/bootstrap.php';
+
+// Session storage
+$storage = new Session();
+
+// Setup the credentials for the requests
+$credentials = new Credentials(
+ $servicesCredentials['dailymotion']['key'],
+ $servicesCredentials['dailymotion']['secret'],
+ $currentUri->getAbsoluteUri()
+);
+
+// Instantiate the Dailymotion service using the credentials, http client, storage mechanism for the token and email scope
+/** @var $dailymotionService Dailymotion */
+$dailymotionService = $serviceFactory->createService('dailymotion', $credentials, $storage, array('email'));
+
+if (!empty($_GET['code'])) {
+ // This was a callback request from Dailymotion, get the token
+ $token = $dailymotionService->requestAccessToken($_GET['code']);
+
+ // Send a request with it
+ $result = json_decode($dailymotionService->request('/me?fields=email,id'), true);
+
+ // Show some of the resultant data
+ echo 'Your unique Dailymotion user id is: ' . $result['id'] . ' and your email is ' . $result['email'];
+
+} elseif (!empty($_GET['go']) && $_GET['go'] === 'go') {
+ $url = $dailymotionService->getAuthorizationUri();
+ header('Location: ' . $url);
+} else {
+ $url = $currentUri->getRelativeUri() . '?go=go';
+ echo "Login with Dailymotion!";
+}
diff --git a/vendor/lusitanian/oauth/examples/dropbox.php b/vendor/lusitanian/oauth/examples/dropbox.php
new file mode 100644
index 00000000..0d60551c
--- /dev/null
+++ b/vendor/lusitanian/oauth/examples/dropbox.php
@@ -0,0 +1,52 @@
+
+ * @copyright Copyright (c) 2012 The authors
+ * @license http://www.opensource.org/licenses/mit-license.html MIT License
+ */
+
+use OAuth\OAuth2\Service\Dropbox;
+use OAuth\Common\Storage\Session;
+use OAuth\Common\Consumer\Credentials;
+
+/**
+ * Bootstrap the example
+ */
+require_once __DIR__ . '/bootstrap.php';
+
+// Session storage
+$storage = new Session();
+
+// Setup the credentials for the requests
+$credentials = new Credentials(
+ $servicesCredentials['dropbox']['key'],
+ $servicesCredentials['dropbox']['secret'],
+ $currentUri->getAbsoluteUri()
+);
+
+// Instantiate the Dropbox service using the credentials, http client and storage mechanism for the token
+/** @var $dropboxService Dropbox */
+$dropboxService = $serviceFactory->createService('dropbox', $credentials, $storage, array());
+
+if (!empty($_GET['code'])) {
+ // This was a callback request from Dropbox, get the token
+ $token = $dropboxService->requestAccessToken($_GET['code']);
+
+ // Send a request with it
+ $result = json_decode($dropboxService->request('/account/info'), true);
+
+ // Show some of the resultant data
+ echo 'Your unique Dropbox user id is: ' . $result['uid'] . ' and your name is ' . $result['display_name'];
+
+} elseif (!empty($_GET['go']) && $_GET['go'] === 'go') {
+ $url = $dropboxService->getAuthorizationUri();
+ header('Location: ' . $url);
+} else {
+ $url = $currentUri->getRelativeUri() . '?go=go';
+ echo "Login with Dropbox!";
+}
diff --git a/vendor/lusitanian/oauth/examples/etsy.php b/vendor/lusitanian/oauth/examples/etsy.php
new file mode 100644
index 00000000..0c0b79b7
--- /dev/null
+++ b/vendor/lusitanian/oauth/examples/etsy.php
@@ -0,0 +1,59 @@
+
+ * @copyright Copyright (c) 2013 The authors
+ * @license http://www.opensource.org/licenses/mit-license.html MIT License
+ */
+
+use OAuth\OAuth1\Service\Etsy;
+use OAuth\Common\Storage\Session;
+use OAuth\Common\Consumer\Credentials;
+
+/**
+ * Bootstrap the example
+ */
+require_once __DIR__ . '/bootstrap.php';
+
+// Session storage
+$storage = new Session();
+
+// Setup the credentials for the requests
+$credentials = new Credentials(
+ $servicesCredentials['etsy']['key'],
+ $servicesCredentials['etsy']['secret'],
+ $currentUri->getAbsoluteUri()
+);
+
+// Instantiate the Etsy service using the credentials, http client and storage mechanism for the token
+/** @var $etsyService Etsy */
+$etsyService = $serviceFactory->createService('Etsy', $credentials, $storage);
+
+if (!empty($_GET['oauth_token'])) {
+ $token = $storage->retrieveAccessToken('Etsy');
+
+ // This was a callback request from Etsy, get the token
+ $etsyService->requestAccessToken(
+ $_GET['oauth_token'],
+ $_GET['oauth_verifier'],
+ $token->getRequestTokenSecret()
+ );
+
+ // Send a request now that we have access token
+ $result = json_decode($etsyService->request('/private/users/__SELF__'));
+
+ echo 'result:
' . print_r($result, true) . '
';
+
+} elseif (!empty($_GET['go']) && $_GET['go'] === 'go') {
+ $response = $etsyService->requestRequestToken();
+ $extra = $response->getExtraParams();
+ $url = $extra['login_url'];
+ header('Location: ' . $url);
+} else {
+ $url = $currentUri->getRelativeUri() . '?go=go';
+ echo "Login with Etsy!";
+}
diff --git a/vendor/lusitanian/oauth/examples/facebook.php b/vendor/lusitanian/oauth/examples/facebook.php
new file mode 100644
index 00000000..b6426721
--- /dev/null
+++ b/vendor/lusitanian/oauth/examples/facebook.php
@@ -0,0 +1,54 @@
+
+ * @author David Desberg
+ * @author Pieter Hordijk
+ * @copyright Copyright (c) 2012 The authors
+ * @license http://www.opensource.org/licenses/mit-license.html MIT License
+ */
+
+use OAuth\OAuth2\Service\Facebook;
+use OAuth\Common\Storage\Session;
+use OAuth\Common\Consumer\Credentials;
+
+/**
+ * Bootstrap the example
+ */
+require_once __DIR__ . '/bootstrap.php';
+
+// Session storage
+$storage = new Session();
+
+// Setup the credentials for the requests
+$credentials = new Credentials(
+ $servicesCredentials['facebook']['key'],
+ $servicesCredentials['facebook']['secret'],
+ $currentUri->getAbsoluteUri()
+);
+
+// Instantiate the Facebook service using the credentials, http client and storage mechanism for the token
+/** @var $facebookService Facebook */
+$facebookService = $serviceFactory->createService('facebook', $credentials, $storage, array());
+
+if (!empty($_GET['code'])) {
+ // This was a callback request from facebook, get the token
+ $token = $facebookService->requestAccessToken($_GET['code']);
+
+ // Send a request with it
+ $result = json_decode($facebookService->request('/me'), true);
+
+ // Show some of the resultant data
+ echo 'Your unique facebook user id is: ' . $result['id'] . ' and your name is ' . $result['name'];
+
+} elseif (!empty($_GET['go']) && $_GET['go'] === 'go') {
+ $url = $facebookService->getAuthorizationUri();
+ header('Location: ' . $url);
+} else {
+ $url = $currentUri->getRelativeUri() . '?go=go';
+ echo "Login with Facebook!";
+}
diff --git a/vendor/lusitanian/oauth/examples/fitbit.php b/vendor/lusitanian/oauth/examples/fitbit.php
new file mode 100644
index 00000000..35b3d09f
--- /dev/null
+++ b/vendor/lusitanian/oauth/examples/fitbit.php
@@ -0,0 +1,61 @@
+
+ * @author Pieter Hordijk
+ * @copyright Copyright (c) 2012 The authors
+ * @license http://www.opensource.org/licenses/mit-license.html MIT License
+ */
+
+use OAuth\OAuth1\Service\FitBit;
+use OAuth\Common\Storage\Session;
+use OAuth\Common\Consumer\Credentials;
+
+/**
+ * Bootstrap the example
+ */
+require_once __DIR__ . '/bootstrap.php';
+
+// Session storage
+$storage = new Session();
+
+// Setup the credentials for the requests
+$credentials = new Credentials(
+ $servicesCredentials['fitbit']['key'],
+ $servicesCredentials['fitbit']['secret'],
+ $currentUri->getAbsoluteUri()
+);
+
+// Instantiate the FitBit service using the credentials, http client and storage mechanism for the token
+/** @var $fitbitService FitBit */
+$fitbitService = $serviceFactory->createService('FitBit', $credentials, $storage);
+
+if (!empty($_GET['oauth_token'])) {
+ $token = $storage->retrieveAccessToken('FitBit');
+
+ // This was a callback request from fitbit, get the token
+ $fitbitService->requestAccessToken(
+ $_GET['oauth_token'],
+ $_GET['oauth_verifier'],
+ $token->getRequestTokenSecret()
+ );
+
+ // Send a request now that we have access token
+ $result = json_decode($fitbitService->request('user/-/profile.json'));
+
+ echo 'result:
' . print_r($result, true) . '
';
+
+} elseif (!empty($_GET['go']) && $_GET['go'] === 'go') {
+ // extra request needed for oauth1 to request a request token :-)
+ $token = $fitbitService->requestRequestToken();
+
+ $url = $fitbitService->getAuthorizationUri(array('oauth_token' => $token->getRequestToken()));
+ header('Location: ' . $url);
+} else {
+ $url = $currentUri->getRelativeUri() . '?go=go';
+ echo "Login with FitBit!";
+}
diff --git a/vendor/lusitanian/oauth/examples/flickr.php b/vendor/lusitanian/oauth/examples/flickr.php
new file mode 100644
index 00000000..f7a80f67
--- /dev/null
+++ b/vendor/lusitanian/oauth/examples/flickr.php
@@ -0,0 +1,80 @@
+
+ * @copyright Copyright (c) 2013 The authors
+ * @license http://www.opensource.org/licenses/mit-license.html MIT License
+ */
+
+use OAuth\OAuth1\Service\Flickr;
+use OAuth\Common\Storage\Session;
+use OAuth\Common\Consumer\Credentials;
+use OAuth\Common\Http\Client\CurlClient;
+
+/**
+ * Bootstrap the example
+ */
+require_once __DIR__.'/bootstrap.php';
+
+// Session storage
+$storage = new Session();
+
+// Setup the credentials for the requests
+$credentials = new Credentials(
+ $servicesCredentials['flickr']['key'],
+ $servicesCredentials['flickr']['secret'],
+ $currentUri->getAbsoluteUri()
+);
+
+// Instantiate the Flickr service using the credentials, http client and storage mechanism for the token
+$flickrService = $serviceFactory->createService('Flickr', $credentials, $storage);
+
+$step = isset($_GET['step']) ? (int)$_GET['step'] : null;
+
+$oauth_token = isset($_GET['oauth_token']) ? $_GET['oauth_token'] : null;
+$oauth_verifier = isset($_GET['oauth_verifier']) ? $_GET['oauth_verifier'] : null;
+
+if($oauth_token && $oauth_verifier){
+ $step = 2;
+}
+
+switch($step){
+ default:
+ print "Login with Flickr!";
+ break;
+
+ case 1:
+
+ if($token = $flickrService->requestRequestToken()){
+ $oauth_token = $token->getAccessToken();
+ $secret = $token->getAccessTokenSecret();
+
+ if($oauth_token && $secret){
+ $url = $flickrService->getAuthorizationUri(array('oauth_token' => $oauth_token, 'perms' => 'write'));
+ header('Location: '.$url);
+ }
+ }
+
+ break;
+
+ case 2:
+ $token = $storage->retrieveAccessToken('Flickr');
+ $secret = $token->getAccessTokenSecret();
+
+ if($token = $flickrService->requestAccessToken($oauth_token, $oauth_verifier, $secret)){
+ $oauth_token = $token->getAccessToken();
+ $secret = $token->getAccessTokenSecret();
+
+ $storage->storeAccessToken('Flickr', $token);
+
+ header('Location: '.$currentUri->getAbsoluteUri().'?step=3');
+ }
+ break;
+
+ case 3:
+ $xml = simplexml_load_string($flickrService->request('flickr.test.login'));
+ print "status: ".(string)$xml->attributes()->stat."\n";
+ break;
+}
diff --git a/vendor/lusitanian/oauth/examples/foursquare.php b/vendor/lusitanian/oauth/examples/foursquare.php
new file mode 100644
index 00000000..f7920724
--- /dev/null
+++ b/vendor/lusitanian/oauth/examples/foursquare.php
@@ -0,0 +1,53 @@
+
+ * @author Pieter Hordijk
+ * @copyright Copyright (c) 2012 The authors
+ * @license http://www.opensource.org/licenses/mit-license.html MIT License
+ */
+
+use OAuth\OAuth2\Service\Foursquare;
+use OAuth\Common\Storage\Session;
+use OAuth\Common\Consumer\Credentials;
+
+/**
+ * Bootstrap the example
+ */
+require_once __DIR__ . '/bootstrap.php';
+
+// Session storage
+$storage = new Session();
+
+// Setup the credentials for the requests
+$credentials = new Credentials(
+ $servicesCredentials['foursquare']['key'],
+ $servicesCredentials['foursquare']['secret'],
+ $currentUri->getAbsoluteUri()
+);
+
+// Instantiate the Foursquare service using the credentials, http client and storage mechanism for the token
+/** @var $foursquareService Foursquare */
+$foursquareService = $serviceFactory->createService('foursquare', $credentials, $storage);
+
+if (!empty($_GET['code'])) {
+ // This was a callback request from foursquare, get the token
+ $foursquareService->requestAccessToken($_GET['code']);
+
+ // Send a request with it
+ $result = json_decode($foursquareService->request('users/self'), true);
+
+ // Show some of the resultant data
+ echo 'Your unique foursquare user id is: ' . $result['response']['user']['id'] . ' and your name is ' . $result['response']['user']['firstName'] . $result['response']['user']['lastName'];
+
+} elseif (!empty($_GET['go']) && $_GET['go'] === 'go') {
+ $url = $foursquareService->getAuthorizationUri();
+ header('Location: ' . $url);
+} else {
+ $url = $currentUri->getRelativeUri() . '?go=go';
+ echo "Login with Foursquare!";
+}
diff --git a/vendor/lusitanian/oauth/examples/github.php b/vendor/lusitanian/oauth/examples/github.php
new file mode 100644
index 00000000..23e971f8
--- /dev/null
+++ b/vendor/lusitanian/oauth/examples/github.php
@@ -0,0 +1,52 @@
+
+ * @author Pieter Hordijk
+ * @copyright Copyright (c) 2012 The authors
+ * @license http://www.opensource.org/licenses/mit-license.html MIT License
+ */
+
+use OAuth\OAuth2\Service\GitHub;
+use OAuth\Common\Storage\Session;
+use OAuth\Common\Consumer\Credentials;
+
+/**
+ * Bootstrap the example
+ */
+require_once __DIR__ . '/bootstrap.php';
+
+// Session storage
+$storage = new Session();
+
+// Setup the credentials for the requests
+$credentials = new Credentials(
+ $servicesCredentials['github']['key'],
+ $servicesCredentials['github']['secret'],
+ $currentUri->getAbsoluteUri()
+);
+
+// Instantiate the GitHub service using the credentials, http client and storage mechanism for the token
+/** @var $gitHub GitHub */
+$gitHub = $serviceFactory->createService('GitHub', $credentials, $storage, array('user'));
+
+if (!empty($_GET['code'])) {
+ // This was a callback request from github, get the token
+ $gitHub->requestAccessToken($_GET['code']);
+
+ $result = json_decode($gitHub->request('user/emails'), true);
+
+ echo 'The first email on your github account is ' . $result[0];
+
+} elseif (!empty($_GET['go']) && $_GET['go'] === 'go') {
+ $url = $gitHub->getAuthorizationUri();
+ header('Location: ' . $url);
+
+} else {
+ $url = $currentUri->getRelativeUri() . '?go=go';
+ echo "Login with Github!";
+}
diff --git a/vendor/lusitanian/oauth/examples/google.php b/vendor/lusitanian/oauth/examples/google.php
new file mode 100644
index 00000000..f05a03e0
--- /dev/null
+++ b/vendor/lusitanian/oauth/examples/google.php
@@ -0,0 +1,53 @@
+
+ * @author Pieter Hordijk
+ * @copyright Copyright (c) 2012 The authors
+ * @license http://www.opensource.org/licenses/mit-license.html MIT License
+ */
+
+use OAuth\OAuth2\Service\Google;
+use OAuth\Common\Storage\Session;
+use OAuth\Common\Consumer\Credentials;
+
+/**
+ * Bootstrap the example
+ */
+require_once __DIR__ . '/bootstrap.php';
+
+// Session storage
+$storage = new Session();
+
+// Setup the credentials for the requests
+$credentials = new Credentials(
+ $servicesCredentials['google']['key'],
+ $servicesCredentials['google']['secret'],
+ $currentUri->getAbsoluteUri()
+);
+
+// Instantiate the Google service using the credentials, http client and storage mechanism for the token
+/** @var $googleService Google */
+$googleService = $serviceFactory->createService('google', $credentials, $storage, array('userinfo_email', 'userinfo_profile'));
+
+if (!empty($_GET['code'])) {
+ // This was a callback request from google, get the token
+ $googleService->requestAccessToken($_GET['code']);
+
+ // Send a request with it
+ $result = json_decode($googleService->request('https://www.googleapis.com/oauth2/v1/userinfo'), true);
+
+ // Show some of the resultant data
+ echo 'Your unique google user id is: ' . $result['id'] . ' and your name is ' . $result['name'];
+
+} elseif (!empty($_GET['go']) && $_GET['go'] === 'go') {
+ $url = $googleService->getAuthorizationUri();
+ header('Location: ' . $url);
+} else {
+ $url = $currentUri->getRelativeUri() . '?go=go';
+ echo "Login with Google!";
+}
diff --git a/vendor/lusitanian/oauth/examples/harvest.php b/vendor/lusitanian/oauth/examples/harvest.php
new file mode 100644
index 00000000..1d11584a
--- /dev/null
+++ b/vendor/lusitanian/oauth/examples/harvest.php
@@ -0,0 +1,74 @@
+
+ * @author Pieter Hordijk
+ * @copyright Copyright (c) 2012 The authors
+ * @license http://www.opensource.org/licenses/mit-license.html MIT License
+ */
+
+use OAuth\Common\Consumer\Credentials;
+use OAuth\Common\Storage\Session;
+use OAuth\Common\Token\Exception\ExpiredTokenException;
+use OAuth\OAuth2\Service\Harvest;
+
+/**
+ * Bootstrap the example
+ */
+require_once __DIR__ . '/bootstrap.php';
+
+$serviceName = 'Harvest';
+$scopes = array();
+
+// Session storage
+$storage = new Session();
+
+// Setup the credentials for the requests
+$credentials = new Credentials(
+ $servicesCredentials['harvest']['key'],
+ $servicesCredentials['harvest']['secret'],
+ $currentUri->getAbsoluteUri()
+);
+
+// Instantiate the Harvest service using the credentials, http client and storage mechanism for the token
+/** @var $harves Harves */
+$harvest = $serviceFactory->createService($serviceName, $credentials, $storage, $scopes);
+
+if (!empty($_GET['clearToken'])) {
+ // Clear the current AccessToken and go back to the Beginning.
+ $storage->clearToken($serviceName);
+ header('Location: ' . $currentUri->getAbsoluteUri());
+
+} elseif ($storage->hasAccessToken($serviceName)) {
+ // fetch the accessToken for the service
+ $accessToken = $storage->retrieveAccessToken($serviceName);
+
+ // is the accessToken expired? then let's refesh it!
+ if ($accessToken->isExpired() === TRUE) {
+ $harvest->refreshAccessToken($accessToken);
+ }
+
+ // use the service with the valid access token to fetch my email
+ $result = json_decode($harvest->request('account/who_am_i'), true);
+ echo 'The email on your harvest account is ' . $result['user']['email'];
+
+ $url = $currentUri->getRelativeUri() . '?clearToken=1';
+ echo " Click here to clear the current access token";
+
+} elseif (!empty($_GET['code'])) {
+ // This was a callback request from harvest, get the token
+ $harvest->requestAccessToken($_GET['code']);
+ header('Location: ' . $currentUri->getAbsoluteUri());
+
+} elseif (!empty($_GET['go']) && $_GET['go'] === 'go') {
+ // Redirect to the Authorization uri
+ $url = $harvest->getAuthorizationUri();
+ header('Location: ' . $url);
+} else {
+ $url = $currentUri->getRelativeUri() . '?go=go';
+ echo "Login with Harvest!";
+}
diff --git a/vendor/lusitanian/oauth/examples/init.example.php b/vendor/lusitanian/oauth/examples/init.example.php
new file mode 100644
index 00000000..fb6aee40
--- /dev/null
+++ b/vendor/lusitanian/oauth/examples/init.example.php
@@ -0,0 +1,136 @@
+
+ * @author Pieter Hordijk
+ * @copyright Copyright (c) 2012 The authors
+ * @license http://www.opensource.org/licenses/mit-license.html MIT License
+ */
+
+/**
+ * @var array A list of all the credentials to be used by the different services in the examples
+ */
+$servicesCredentials = array(
+ 'amazon' => array(
+ 'key' => '',
+ 'secret' => '',
+ ),
+ 'bitbucket' => array(
+ 'key' => '',
+ 'secret' => '',
+ ),
+ 'bitly' => array(
+ 'key' => '',
+ 'secret' => '',
+ ),
+ 'box' => array(
+ 'key' => '',
+ 'secret' => '',
+ ),
+ 'buffer' => array(
+ 'key' => '',
+ 'secret' => '',
+ ),
+ 'dailymotion' => array(
+ 'key' => '',
+ 'secret' => '',
+ ),
+ 'dropbox' => array(
+ 'key' => '',
+ 'secret' => '',
+ ),
+ 'etsy' => array(
+ 'key' => '',
+ 'secret' => '',
+ ),
+ 'facebook' => array(
+ 'key' => '',
+ 'secret' => '',
+ ),
+ 'fitbit' => array(
+ 'key' => '',
+ 'secret' => '',
+ ),
+ 'flickr' => array(
+ 'key' => '',
+ 'secret' => '',
+ ),
+ 'foursquare' => array(
+ 'key' => '',
+ 'secret' => '',
+ ),
+ 'github' => array(
+ 'key' => '',
+ 'secret' => '',
+ ),
+ 'google' => array(
+ 'key' => '',
+ 'secret' => '',
+ ),
+ 'instagram' => array(
+ 'key' => '',
+ 'secret' => '',
+ ),
+ 'linkedin' => array(
+ 'key' => '',
+ 'secret' => '',
+ ),
+ 'mailchimp' => array(
+ 'key' => '',
+ 'secret' => '',
+ ),
+ 'microsoft' => array(
+ 'key' => '',
+ 'secret' => '',
+ ),
+ 'paypal' => array(
+ 'key' => '',
+ 'secret' => '',
+ ),
+ 'pocket' => array(
+ 'key' => '',
+ ),
+ 'reddit' => array(
+ 'key' => '',
+ 'secret' => '',
+ ),
+ 'runkeeper' => array(
+ 'key' => '',
+ 'secret' => '',
+ ),
+ 'scoopit' => array(
+ 'key' => '',
+ 'secret' => ''
+ ),
+ 'soundcloud' => array(
+ 'key' => '',
+ 'secret' => '',
+ ),
+ 'tumblr' => array(
+ 'key' => '',
+ 'secret' => '',
+ ),
+ 'twitter' => array(
+ 'key' => '',
+ 'secret' => '',
+ ),
+ 'ustream' => array(
+ 'key' => '',
+ 'secret' => '',
+ ),
+ 'yahoo' => array(
+ 'key' => '',
+ 'secret' => ''
+ ),
+ 'yammer' => array(
+ 'key' => '',
+ 'secret' => ''
+ ),
+);
+
+/** @var $serviceFactory \OAuth\ServiceFactory An OAuth service factory. */
+$serviceFactory = new \OAuth\ServiceFactory();
diff --git a/vendor/lusitanian/oauth/examples/instagram.php b/vendor/lusitanian/oauth/examples/instagram.php
new file mode 100644
index 00000000..2e44094c
--- /dev/null
+++ b/vendor/lusitanian/oauth/examples/instagram.php
@@ -0,0 +1,56 @@
+
+ * @author Pieter Hordijk
+ * @author Hannes Van De Vreken
+ * @copyright Copyright (c) 2012 The authors
+ * @license http://www.opensource.org/licenses/mit-license.html MIT License
+ */
+
+use OAuth\OAuth2\Service\Instagram;
+use OAuth\Common\Storage\Session;
+use OAuth\Common\Consumer\Credentials;
+
+/**
+ * Bootstrap the example
+ */
+require_once __DIR__ . '/bootstrap.php';
+
+// Session storage
+$storage = new Session();
+
+// Setup the credentials for the requests
+$credentials = new Credentials(
+ $servicesCredentials['instagram']['key'],
+ $servicesCredentials['instagram']['secret'],
+ $currentUri->getAbsoluteUri()
+);
+
+$scopes = array('basic', 'comments', 'relationships', 'likes');
+
+// Instantiate the Instagram service using the credentials, http client and storage mechanism for the token
+/** @var $instagramService Instagram */
+$instagramService = $serviceFactory->createService('instagram', $credentials, $storage, $scopes);
+
+if (!empty($_GET['code'])) {
+ // This was a callback request from Instagram, get the token
+ $instagramService->requestAccessToken($_GET['code']);
+
+ // Send a request with it
+ $result = json_decode($instagramService->request('users/self'), true);
+
+ // Show some of the resultant data
+ echo 'Your unique instagram user id is: ' . $result['data']['id'] . ' and your name is ' . $result['data']['full_name'];
+
+} elseif (!empty($_GET['go']) && $_GET['go'] === 'go') {
+ $url = $instagramService->getAuthorizationUri();
+ header('Location: ' . $url);
+} else {
+ $url = $currentUri->getRelativeUri() . '?go=go';
+ echo "Login with Instagram!";
+}
diff --git a/vendor/lusitanian/oauth/examples/linkedin.php b/vendor/lusitanian/oauth/examples/linkedin.php
new file mode 100644
index 00000000..db14ab25
--- /dev/null
+++ b/vendor/lusitanian/oauth/examples/linkedin.php
@@ -0,0 +1,57 @@
+
+ * @author Pieter Hordijk
+ * @author Antoine Corcy
+ * @copyright Copyright (c) 2012 The authors
+ * @license http://www.opensource.org/licenses/mit-license.html MIT License
+ */
+
+use OAuth\OAuth2\Service\Linkedin;
+use OAuth\Common\Storage\Session;
+use OAuth\Common\Consumer\Credentials;
+
+/**
+ * Bootstrap the example
+ */
+require_once __DIR__ . '/bootstrap.php';
+
+// Session storage
+$storage = new Session();
+
+// Setup the credentials for the requests
+$credentials = new Credentials(
+ $servicesCredentials['linkedin']['key'],
+ $servicesCredentials['linkedin']['secret'],
+ $currentUri->getAbsoluteUri()
+);
+
+// Instantiate the Linkedin service using the credentials, http client and storage mechanism for the token
+/** @var $linkedinService Linkedin */
+$linkedinService = $serviceFactory->createService('linkedin', $credentials, $storage, array('r_basicprofile'));
+
+if (!empty($_GET['code'])) {
+ // retrieve the CSRF state parameter
+ $state = isset($_GET['state']) ? $_GET['state'] : null;
+
+ // This was a callback request from linkedin, get the token
+ $token = $linkedinService->requestAccessToken($_GET['code'], $state);
+
+ // Send a request with it. Please note that XML is the default format.
+ $result = json_decode($linkedinService->request('/people/~?format=json'), true);
+
+ // Show some of the resultant data
+ echo 'Your linkedin first name is ' . $result['firstName'] . ' and your last name is ' . $result['lastName'];
+
+} elseif (!empty($_GET['go']) && $_GET['go'] === 'go') {
+ $url = $linkedinService->getAuthorizationUri();
+ header('Location: ' . $url);
+} else {
+ $url = $currentUri->getRelativeUri() . '?go=go';
+ echo "Login with Linkedin!";
+}
diff --git a/vendor/lusitanian/oauth/examples/mailchimp.php b/vendor/lusitanian/oauth/examples/mailchimp.php
new file mode 100644
index 00000000..dd7e12bd
--- /dev/null
+++ b/vendor/lusitanian/oauth/examples/mailchimp.php
@@ -0,0 +1,55 @@
+
+ * @author Hannes Van De Vreken
+ * @copyright Copyright (c) 2012 The authors
+ * @license http://www.opensource.org/licenses/mit-license.html MIT License
+ */
+
+use OAuth\OAuth2\Service\Mailchimp;
+use OAuth\Common\Storage\Session;
+use OAuth\Common\Consumer\Credentials;
+
+$_SERVER['SERVER_PORT'] = 80;
+
+/**
+ * Bootstrap the example
+ */
+require_once __DIR__ . '/bootstrap.php';
+
+// Session storage
+$storage = new Session();
+
+// Setup the credentials for the requests
+$credentials = new Credentials(
+ $servicesCredentials['mailchimp']['key'],
+ $servicesCredentials['mailchimp']['secret'],
+ $currentUri->getAbsoluteUri()
+);
+
+// Instantiate the Mailchimp service using the credentials, http client and storage mechanism for the token
+/** @var $mailchimpService Mailchimp */
+$mailchimpService = $serviceFactory->createService('mailchimp', $credentials, $storage, array());
+
+if (!empty($_GET['code'])) {
+ // This was a callback request from mailchimp, get the token
+ $token = $mailchimpService->requestAccessToken($_GET['code']);
+
+ // Send a request with it
+ $result = $mailchimpService->request('/users/profile.json');
+
+ header('Content-Type: application/json');
+ echo $result; exit;
+
+} elseif (!empty($_GET['go']) && $_GET['go'] === 'go') {
+ $url = $mailchimpService->getAuthorizationUri();
+ header('Location: ' . $url);
+} else {
+ $url = $currentUri->getRelativeUri() . '?go=go';
+ echo "Login with Mailchimp!";
+}
diff --git a/vendor/lusitanian/oauth/examples/microsoft.php b/vendor/lusitanian/oauth/examples/microsoft.php
new file mode 100644
index 00000000..1edb13f1
--- /dev/null
+++ b/vendor/lusitanian/oauth/examples/microsoft.php
@@ -0,0 +1,49 @@
+
+ * @author Pieter Hordijk
+ * @copyright Copyright (c) 2012 The authors
+ * @license http://www.opensource.org/licenses/mit-license.html MIT License
+ */
+
+use OAuth\OAuth2\Service\Microsoft;
+use OAuth\Common\Storage\Session;
+use OAuth\Common\Consumer\Credentials;
+
+/**
+ * Bootstrap the example
+ */
+require_once __DIR__ . '/bootstrap.php';
+
+// Session storage
+$storage = new Session();
+
+// Setup the credentials for the requests
+$credentials = new Credentials(
+ $servicesCredentials['microsoft']['key'],
+ $servicesCredentials['microsoft']['secret'],
+ $currentUri->getAbsoluteUri()
+);
+
+// Instantiate the Microsoft service using the credentials, http client and storage mechanism for the token
+/** @var $microsoft Microsoft */
+$microsoft = $serviceFactory->createService('microsoft', $credentials, $storage, array('basic'));
+
+if (!empty($_GET['code'])) {
+ // This was a callback request from Microsoft, get the token
+ $token = $microsoft->requestAccessToken($_GET['code']);
+
+ var_dump($token);
+
+} elseif (!empty($_GET['go']) && $_GET['go'] === 'go') {
+ $url = $microsoft->getAuthorizationUri();
+ header('Location: ' . $url);
+} else {
+ $url = $currentUri->getRelativeUri() . '?go=go';
+ echo "Login with Microsoft!";
+}
diff --git a/vendor/lusitanian/oauth/examples/paypal.php b/vendor/lusitanian/oauth/examples/paypal.php
new file mode 100644
index 00000000..207357f2
--- /dev/null
+++ b/vendor/lusitanian/oauth/examples/paypal.php
@@ -0,0 +1,52 @@
+
+ * @copyright Copyright (c) 2012 The authors
+ * @license http://www.opensource.org/licenses/mit-license.html MIT License
+ */
+
+use OAuth\OAuth2\Service\Paypal;
+use OAuth\Common\Storage\Session;
+use OAuth\Common\Consumer\Credentials;
+
+/**
+ * Bootstrap the example
+ */
+require_once __DIR__ . '/bootstrap.php';
+
+// Session storage
+$storage = new Session();
+
+// Setup the credentials for the requests
+$credentials = new Credentials(
+ $servicesCredentials['paypal']['key'],
+ $servicesCredentials['paypal']['secret'],
+ $currentUri->getAbsoluteUri()
+);
+
+// Instantiate the PayPal service using the credentials, http client, storage mechanism for the token and profile/openid scopes
+/** @var $paypalService PayPal */
+$paypalService = $serviceFactory->createService('paypal', $credentials, $storage, array('profile', 'openid'));
+
+if (!empty($_GET['code'])) {
+ // This was a callback request from PayPal, get the token
+ $token = $paypalService->requestAccessToken($_GET['code']);
+
+ // Send a request with it
+ $result = json_decode($paypalService->request('/identity/openidconnect/userinfo/?schema=openid'), true);
+
+ // Show some of the resultant data
+ echo 'Your unique PayPal user id is: ' . $result['user_id'] . ' and your name is ' . $result['name'];
+
+} elseif (!empty($_GET['go']) && $_GET['go'] === 'go') {
+ $url = $paypalService->getAuthorizationUri();
+ header('Location: ' . $url);
+} else {
+ $url = $currentUri->getRelativeUri() . '?go=go';
+ echo "Login with PayPal!";
+}
diff --git a/vendor/lusitanian/oauth/examples/pocket.php b/vendor/lusitanian/oauth/examples/pocket.php
new file mode 100644
index 00000000..b96d2ace
--- /dev/null
+++ b/vendor/lusitanian/oauth/examples/pocket.php
@@ -0,0 +1,63 @@
+
+ * @copyright Copyright (c) 2014 Christian Mayer
+ * @license http://www.opensource.org/licenses/mit-license.html MIT License
+ */
+
+use OAuth\OAuth2\Service\Pocket;
+use OAuth\Common\Storage\Session;
+use OAuth\Common\Consumer\Credentials;
+use OAuth\Common\Http\Client\CurlClient;
+
+/**
+ * Bootstrap the example
+ */
+require_once __DIR__.'/bootstrap.php';
+
+$step = isset($_GET['step']) ? (int)$_GET['step'] : null;
+$code = isset($_GET['code']) ? $_GET['code'] : null;
+
+// Session storage
+$storage = new Session();
+
+// Setup the credentials for the requests
+$credentials = new Credentials(
+ $servicesCredentials['pocket']['key'],
+ null, // Pocket API doesn't have a secret key. :S
+ $currentUri->getAbsoluteUri().($code ? '?step=3&code='.$code : '')
+);
+
+// Instantiate the Pocket service using the credentials, http client and storage mechanism for the token
+$pocketService = $serviceFactory->createService('Pocket', $credentials, $storage);
+
+switch($step){
+ default:
+ print 'Login with Pocket';
+
+ break;
+
+ case 1:
+ $code = $pocketService->requestRequestToken();
+ header('Location: '.$currentUri->getRelativeUri().'?step=2&code='.$code);
+
+ break;
+
+ case 2:
+ $url = $pocketService->getAuthorizationUri(array('request_token' => $code));
+ header('Location: '.$url);
+
+ break;
+
+ case 3:
+ $token = $pocketService->requestAccessToken($code);
+ $accessToken = $token->getAccessToken();
+ $extraParams = $token->getExtraParams();
+
+ print 'User: '.$extraParams['username'].' ';
+ print 'Access Token: '.$accessToken;
+ break;
+}
diff --git a/vendor/lusitanian/oauth/examples/reddit.php b/vendor/lusitanian/oauth/examples/reddit.php
new file mode 100644
index 00000000..7363d840
--- /dev/null
+++ b/vendor/lusitanian/oauth/examples/reddit.php
@@ -0,0 +1,54 @@
+
+ * @copyright Copyright (c) 2012 The authors
+ * @license http://www.opensource.org/licenses/mit-license.html MIT License
+ */
+
+use OAuth\OAuth2\Service\Reddit;
+use OAuth\Common\Storage\Session;
+use OAuth\Common\Consumer\Credentials;
+
+/**
+ * Bootstrap the example
+ */
+require_once __DIR__ . '/bootstrap.php';
+
+// Session storage
+$storage = new Session();
+
+// Setup the credentials for the requests
+$credentials = new Credentials(
+ $servicesCredentials['reddit']['key'],
+ $servicesCredentials['reddit']['secret'],
+ $currentUri->getAbsoluteUri()
+);
+
+// Instantiate the Reddit service using the credentials, http client and storage mechanism for the token
+/** @var $reddit Reddit */
+$reddit = $serviceFactory->createService('Reddit', $credentials, $storage, array('identity'));
+
+if (!empty($_GET['code'])) {
+ // retrieve the CSRF state parameter
+ $state = isset($_GET['state']) ? $_GET['state'] : null;
+
+ // This was a callback request from reddit, get the token
+ $reddit->requestAccessToken($_GET['code'], $state);
+
+ $result = json_decode($reddit->request('api/v1/me.json'), true);
+
+ echo 'Your unique reddit user id is: ' . $result['id'] . ' and your username is ' . $result['name'];
+
+} elseif (!empty($_GET['go']) && $_GET['go'] === 'go') {
+ $url = $reddit->getAuthorizationUri();
+ header('Location: ' . $url);
+
+} else {
+ $url = $currentUri->getRelativeUri() . '?go=go';
+ echo "Login with Reddit!";
+}
diff --git a/vendor/lusitanian/oauth/examples/runkeeper.php b/vendor/lusitanian/oauth/examples/runkeeper.php
new file mode 100644
index 00000000..61a203f9
--- /dev/null
+++ b/vendor/lusitanian/oauth/examples/runkeeper.php
@@ -0,0 +1,51 @@
+getAbsoluteUri()
+);
+
+// Instantiate the Runkeeper service using the credentials, http client and storage mechanism for the token
+/** @var $runkeeperService RunKeeper */
+$runkeeperService = $serviceFactory->createService('RunKeeper', $credentials, $storage, array());
+
+if (!empty($_GET['code'])) {
+ // This was a callback request from RunKeeper, get the token
+ $token = $runkeeperService->requestAccessToken($_GET['code']);
+
+ // Send a request with it
+ $result = json_decode($runkeeperService->request('/user'), true);
+
+ // Show some of the resultant data
+ echo 'Your unique RunKeeper user id is: ' . $result['userID'];
+
+} elseif (!empty($_GET['go']) && $_GET['go'] === 'go') {
+ $url = $runkeeperService->getAuthorizationUri();
+ header('Location: ' . $url);
+} else {
+ $url = $currentUri->getRelativeUri() . '?go=go';
+ echo "Login with RunKeeper!";
+}
diff --git a/vendor/lusitanian/oauth/examples/scoopit.php b/vendor/lusitanian/oauth/examples/scoopit.php
new file mode 100644
index 00000000..cc1c103b
--- /dev/null
+++ b/vendor/lusitanian/oauth/examples/scoopit.php
@@ -0,0 +1,57 @@
+
+ * @copyright Copyright (c) 2013 The authors
+ * @license http://www.opensource.org/licenses/mit-license.html MIT License
+ */
+
+use OAuth\OAuth1\Service\ScoopIt;
+use OAuth\Common\Storage\Session;
+use OAuth\Common\Consumer\Credentials;
+
+/**
+ * Bootstrap the example
+ */
+require_once __DIR__.'/bootstrap.php';
+
+// Session storage
+$storage = new Session();
+
+// Setup the credentials for the requests
+$credentials = new Credentials(
+ $servicesCredentials['scoopit']['key'],
+ $servicesCredentials['scoopit']['secret'],
+ $currentUri->getAbsoluteUri()
+);
+
+// Instantiate the ScoopIt service using the credentials, http client and storage mechanism for the token
+$scoopItService = $serviceFactory->createService('ScoopIt', $credentials, $storage);
+
+if (!empty($_GET['oauth_token'])) {
+ $token = $storage->retrieveAccessToken('ScoopIt');
+
+ // This was a callback request from ScoopIt, get the token
+ $scoopItService->requestAccessToken(
+ $_GET['oauth_token'],
+ $_GET['oauth_verifier'],
+ $token->getRequestTokenSecret()
+ );
+
+ // Send a request now that we have access token
+ $result = json_decode($scoopItService->request('profile'));
+
+ echo 'result:
' . print_r($result, true) . '
';
+
+} elseif (!empty($_GET['go']) && $_GET['go'] === 'go') {
+ // extra request needed for oauth1 to request a request token :-)
+ $token = $scoopItService->requestRequestToken();
+
+ $url = $scoopItService->getAuthorizationUri(array('oauth_token' => $token->getRequestToken()));
+ header('Location: ' . $url);
+} else {
+ $url = $currentUri->getRelativeUri() . '?go=go';
+ echo "Login with ScoopIt!";
+}
diff --git a/vendor/lusitanian/oauth/examples/soundcloud.php b/vendor/lusitanian/oauth/examples/soundcloud.php
new file mode 100644
index 00000000..2629490b
--- /dev/null
+++ b/vendor/lusitanian/oauth/examples/soundcloud.php
@@ -0,0 +1,53 @@
+
+ * @author Pieter Hordijk
+ * @copyright Copyright (c) 2012 The authors
+ * @license http://www.opensource.org/licenses/mit-license.html MIT License
+ */
+
+use OAuth\OAuth2\Service\SoundCloud;
+use OAuth\Common\Storage\Session;
+use OAuth\Common\Consumer\Credentials;
+
+/**
+ * Bootstrap the example
+ */
+require_once __DIR__ . '/bootstrap.php';
+
+// Session storage
+$storage = new Session();
+
+// Setup the credentials for the requests
+$credentials = new Credentials(
+ $servicesCredentials['soundcloud']['key'],
+ $servicesCredentials['soundcloud']['secret'],
+ $currentUri->getAbsoluteUri()
+);
+
+// Instantiate the SoundCloud service using the credentials, http client and storage mechanism for the token
+/** @var $soundcloudService SoundCloud */
+$soundcloudService = $serviceFactory->createService('soundCloud', $credentials, $storage);
+
+if (!empty($_GET['code'])) {
+ // This was a callback request from SoundCloud, get the token
+ $soundcloudService->requestAccessToken($_GET['code']);
+
+ // Send a request with it
+ $result = json_decode($soundcloudService->request('me.json'), true);
+
+ // Show some of the resultant data
+ echo 'Your unique user id is: ' . $result['id'] . ' and your name is ' . $result['username'];
+
+} elseif (!empty($_GET['go']) && $_GET['go'] === 'go') {
+ $url = $soundcloudService->getAuthorizationUri();
+ header('Location: ' . $url);
+} else {
+ $url = $currentUri->getRelativeUri() . '?go=go';
+ echo "Login with SoundCloud!";
+}
diff --git a/vendor/lusitanian/oauth/examples/tumblr.php b/vendor/lusitanian/oauth/examples/tumblr.php
new file mode 100644
index 00000000..bde0521b
--- /dev/null
+++ b/vendor/lusitanian/oauth/examples/tumblr.php
@@ -0,0 +1,62 @@
+
+ * @author Pieter Hordijk
+ * @copyright Copyright (c) 2012 The authors
+ * @license http://www.opensource.org/licenses/mit-license.html MIT License
+ */
+
+use OAuth\OAuth1\Service\Tumblr;
+use OAuth\Common\Storage\Session;
+use OAuth\Common\Consumer\Credentials;
+
+/**
+ * Bootstrap the example
+ */
+require_once __DIR__ . '/bootstrap.php';
+
+// We need to use a persistent storage to save the token, because oauth1 requires the token secret received before'
+// the redirect (request token request) in the access token request.
+$storage = new Session();
+
+// Setup the credentials for the requests
+$credentials = new Credentials(
+ $servicesCredentials['tumblr']['key'],
+ $servicesCredentials['tumblr']['secret'],
+ $currentUri->getAbsoluteUri()
+);
+
+// Instantiate the tumblr service using the credentials, http client and storage mechanism for the token
+/** @var $tumblrService Tumblr */
+$tumblrService = $serviceFactory->createService('tumblr', $credentials, $storage);
+
+if (!empty($_GET['oauth_token'])) {
+ $token = $storage->retrieveAccessToken('Tumblr');
+
+ // This was a callback request from tumblr, get the token
+ $tumblrService->requestAccessToken(
+ $_GET['oauth_token'],
+ $_GET['oauth_verifier'],
+ $token->getRequestTokenSecret()
+ );
+
+ // Send a request now that we have access token
+ $result = json_decode($tumblrService->request('user/info'));
+
+ echo 'result:
' . print_r($result, true) . '
';
+
+} elseif (!empty($_GET['go']) && $_GET['go'] === 'go') {
+ // extra request needed for oauth1 to request a request token :-)
+ $token = $tumblrService->requestRequestToken();
+
+ $url = $tumblrService->getAuthorizationUri(array('oauth_token' => $token->getRequestToken()));
+ header('Location: ' . $url);
+} else {
+ $url = $currentUri->getRelativeUri() . '?go=go';
+ echo "Login with Tumblr!";
+}
diff --git a/vendor/lusitanian/oauth/examples/twitter.php b/vendor/lusitanian/oauth/examples/twitter.php
new file mode 100644
index 00000000..6b14a222
--- /dev/null
+++ b/vendor/lusitanian/oauth/examples/twitter.php
@@ -0,0 +1,62 @@
+
+ * @author Pieter Hordijk
+ * @copyright Copyright (c) 2012 The authors
+ * @license http://www.opensource.org/licenses/mit-license.html MIT License
+ */
+
+use OAuth\OAuth1\Service\Twitter;
+use OAuth\Common\Storage\Session;
+use OAuth\Common\Consumer\Credentials;
+
+/**
+ * Bootstrap the example
+ */
+require_once __DIR__ . '/bootstrap.php';
+
+// We need to use a persistent storage to save the token, because oauth1 requires the token secret received before'
+// the redirect (request token request) in the access token request.
+$storage = new Session();
+
+// Setup the credentials for the requests
+$credentials = new Credentials(
+ $servicesCredentials['twitter']['key'],
+ $servicesCredentials['twitter']['secret'],
+ $currentUri->getAbsoluteUri()
+);
+
+// Instantiate the twitter service using the credentials, http client and storage mechanism for the token
+/** @var $twitterService Twitter */
+$twitterService = $serviceFactory->createService('twitter', $credentials, $storage);
+
+if (!empty($_GET['oauth_token'])) {
+ $token = $storage->retrieveAccessToken('Twitter');
+
+ // This was a callback request from twitter, get the token
+ $twitterService->requestAccessToken(
+ $_GET['oauth_token'],
+ $_GET['oauth_verifier'],
+ $token->getRequestTokenSecret()
+ );
+
+ // Send a request now that we have access token
+ $result = json_decode($twitterService->request('account/verify_credentials.json'));
+
+ echo 'result:
' . print_r($result, true) . '
';
+
+} elseif (!empty($_GET['go']) && $_GET['go'] === 'go') {
+ // extra request needed for oauth1 to request a request token :-)
+ $token = $twitterService->requestRequestToken();
+
+ $url = $twitterService->getAuthorizationUri(array('oauth_token' => $token->getRequestToken()));
+ header('Location: ' . $url);
+} else {
+ $url = $currentUri->getRelativeUri() . '?go=go';
+ echo "Login with Twitter!";
+}
diff --git a/vendor/lusitanian/oauth/examples/ustream.php b/vendor/lusitanian/oauth/examples/ustream.php
new file mode 100644
index 00000000..e3ca0bb4
--- /dev/null
+++ b/vendor/lusitanian/oauth/examples/ustream.php
@@ -0,0 +1,54 @@
+
+ * @copyright Copyright (c) 2014 The authors
+ * @license http://www.opensource.org/licenses/mit-license.html MIT License
+ */
+
+use OAuth\OAuth2\Service\Ustream;
+use OAuth\Common\Storage\Session;
+use OAuth\Common\Consumer\Credentials;
+
+/**
+ * Bootstrap the example
+ */
+require_once __DIR__ . '/bootstrap.php';
+
+// Session storage
+$storage = new Session();
+
+// Setup the credentials for the requests
+$credentials = new Credentials(
+ $servicesCredentials['ustream']['key'],
+ $servicesCredentials['ustream']['secret'],
+ $currentUri->getAbsoluteUri()
+);
+
+// Instantiate the Ustream service using the credentials, http client and storage mechanism for the token
+/** @var $ustream Ustream */
+$ustream = $serviceFactory->createService('Ustream', $credentials, $storage, array('identity'));
+
+if (!empty($_GET['code'])) {
+ // retrieve the CSRF state parameter
+ $state = isset($_GET['state']) ? $_GET['state'] : null;
+
+ // This was a callback request from Ustream, get the token
+ $ustream->requestAccessToken($_GET['code'], $state);
+
+ $result = json_decode($ustream->request('users/self.json'), true);
+
+ echo 'Your unique Ustream user id is: ' . $result['id'] . ' and your username is ' . $result['username'];
+
+} elseif (!empty($_GET['go']) && $_GET['go'] === 'go') {
+ $url = $ustream->getAuthorizationUri();
+ header('Location: ' . $url);
+
+} else {
+ $url = $currentUri->getRelativeUri() . '?go=go';
+ echo "Login with Ustream!";
+}
diff --git a/vendor/lusitanian/oauth/examples/yahoo.php b/vendor/lusitanian/oauth/examples/yahoo.php
new file mode 100644
index 00000000..549332e9
--- /dev/null
+++ b/vendor/lusitanian/oauth/examples/yahoo.php
@@ -0,0 +1,57 @@
+
+ * @copyright Copyright (c) 2014 The authors
+ * @license http://www.opensource.org/licenses/mit-license.html MIT License
+ */
+
+use OAuth\OAuth1\Service\Yahoo;
+use OAuth\Common\Storage\Session;
+use OAuth\Common\Consumer\Credentials;
+
+/**
+ * Bootstrap the example
+ */
+require_once __DIR__.'/bootstrap.php';
+
+// Session storage
+$storage = new Session();
+
+// Setup the credentials for the requests
+$credentials = new Credentials(
+ $servicesCredentials['yahoo']['key'],
+ $servicesCredentials['yahoo']['secret'],
+ $currentUri->getAbsoluteUri()
+);
+
+// Instantiate the Yahoo service using the credentials, http client and storage mechanism for the token
+$yahooService = $serviceFactory->createService('Yahoo', $credentials, $storage);
+
+if (!empty($_GET['oauth_token'])) {
+ $token = $storage->retrieveAccessToken('Yahoo');
+
+ // This was a callback request from Yahoo, get the token
+ $yahooService->requestAccessToken(
+ $_GET['oauth_token'],
+ $_GET['oauth_verifier'],
+ $token->getRequestTokenSecret()
+ );
+
+ // Send a request now that we have access token
+ $result = json_decode($yahooService->request('profile'));
+
+ echo 'result:
' . print_r($result, true) . '
';
+
+} elseif (!empty($_GET['go']) && $_GET['go'] === 'go') {
+ // extra request needed for oauth1 to request a request token :-)
+ $token = $yahooService->requestRequestToken();
+
+ $url = $yahooService->getAuthorizationUri(array('oauth_token' => $token->getRequestToken()));
+ header('Location: ' . $url);
+} else {
+ $url = $currentUri->getRelativeUri() . '?go=go';
+ echo "Login with Yahoo!";
+}
diff --git a/vendor/lusitanian/oauth/phpunit.xml.dist b/vendor/lusitanian/oauth/phpunit.xml.dist
new file mode 100644
index 00000000..ee281953
--- /dev/null
+++ b/vendor/lusitanian/oauth/phpunit.xml.dist
@@ -0,0 +1,45 @@
+
+
+
+
+ tests/Unit
+
+
+
+
+ src/
+
+ src/OAuth/bootstrap.php
+ src/OAuth/Common/Exception/Exception.php
+ src/OAuth/Common/Http/Exception/TokenResponseException.php
+ src/OAuth/Common/Storage/Exception/StorageException.php
+ src/OAuth/Common/Storage/Exception/TokenNotFoundException.php
+ src/OAuth/Common/Token/Exception/ExpiredTokenException.php
+ src/OAuth/OAuth1/Signature/Exception/UnsupportedHashAlgorithmException.php
+ src/OAuth/OAuth2/Service/Exception/InvalidScopeException.php
+ src/OAuth/OAuth2/Service/Exception/MissingRefreshTokenException.php
+ src/OAuth/OAuth2/Token/StdOAuth2Token.php
+
+
+
+
+
+
+
+
diff --git a/vendor/lusitanian/oauth/src/OAuth/Common/AutoLoader.php b/vendor/lusitanian/oauth/src/OAuth/Common/AutoLoader.php
new file mode 100644
index 00000000..9fe7951c
--- /dev/null
+++ b/vendor/lusitanian/oauth/src/OAuth/Common/AutoLoader.php
@@ -0,0 +1,81 @@
+
+ */
+class AutoLoader
+{
+ /**
+ * @var string The namespace prefix for this instance.
+ */
+ protected $namespace = '';
+
+ /**
+ * @var string The filesystem prefix to use for this instance
+ */
+ protected $path = '';
+
+ /**
+ * Build the instance of the autoloader
+ *
+ * @param string $namespace The prefixed namespace this instance will load
+ * @param string $path The filesystem path to the root of the namespace
+ */
+ public function __construct($namespace, $path)
+ {
+ $this->namespace = ltrim($namespace, '\\');
+ $this->path = rtrim($path, '/\\') . DIRECTORY_SEPARATOR;
+ }
+
+ /**
+ * Try to load a class
+ *
+ * @param string $class The class name to load
+ *
+ * @return boolean If the loading was successful
+ */
+ public function load($class)
+ {
+ $class = ltrim($class, '\\');
+
+ if (strpos($class, $this->namespace) === 0) {
+ $nsparts = explode('\\', $class);
+ $class = array_pop($nsparts);
+ $nsparts[] = '';
+ $path = $this->path . implode(DIRECTORY_SEPARATOR, $nsparts);
+ $path .= str_replace('_', DIRECTORY_SEPARATOR, $class) . '.php';
+
+ if (file_exists($path)) {
+ require $path;
+
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+ /**
+ * Register the autoloader to PHP
+ *
+ * @return boolean The status of the registration
+ */
+ public function register()
+ {
+ return spl_autoload_register(array($this, 'load'));
+ }
+
+ /**
+ * Unregister the autoloader to PHP
+ *
+ * @return boolean The status of the unregistration
+ */
+ public function unregister()
+ {
+ return spl_autoload_unregister(array($this, 'load'));
+ }
+}
diff --git a/vendor/lusitanian/oauth/src/OAuth/Common/Consumer/Credentials.php b/vendor/lusitanian/oauth/src/OAuth/Common/Consumer/Credentials.php
new file mode 100644
index 00000000..8e98e9fa
--- /dev/null
+++ b/vendor/lusitanian/oauth/src/OAuth/Common/Consumer/Credentials.php
@@ -0,0 +1,60 @@
+consumerId = $consumerId;
+ $this->consumerSecret = $consumerSecret;
+ $this->callbackUrl = $callbackUrl;
+ }
+
+ /**
+ * @return string
+ */
+ public function getCallbackUrl()
+ {
+ return $this->callbackUrl;
+ }
+
+ /**
+ * @return string
+ */
+ public function getConsumerId()
+ {
+ return $this->consumerId;
+ }
+
+ /**
+ * @return string
+ */
+ public function getConsumerSecret()
+ {
+ return $this->consumerSecret;
+ }
+}
diff --git a/vendor/lusitanian/oauth/src/OAuth/Common/Consumer/CredentialsInterface.php b/vendor/lusitanian/oauth/src/OAuth/Common/Consumer/CredentialsInterface.php
new file mode 100644
index 00000000..a33e54e9
--- /dev/null
+++ b/vendor/lusitanian/oauth/src/OAuth/Common/Consumer/CredentialsInterface.php
@@ -0,0 +1,24 @@
+userAgent = $userAgent;
+ }
+
+ /**
+ * @param int $redirects Maximum redirects for client
+ *
+ * @return ClientInterface
+ */
+ public function setMaxRedirects($redirects)
+ {
+ $this->maxRedirects = $redirects;
+
+ return $this;
+ }
+
+ /**
+ * @param int $timeout Request timeout time for client in seconds
+ *
+ * @return ClientInterface
+ */
+ public function setTimeout($timeout)
+ {
+ $this->timeout = $timeout;
+
+ return $this;
+ }
+
+ /**
+ * @param array $headers
+ */
+ public function normalizeHeaders(&$headers)
+ {
+ // Normalize headers
+ array_walk(
+ $headers,
+ function (&$val, &$key) {
+ $key = ucfirst(strtolower($key));
+ $val = ucfirst(strtolower($key)) . ': ' . $val;
+ }
+ );
+ }
+}
diff --git a/vendor/lusitanian/oauth/src/OAuth/Common/Http/Client/ClientInterface.php b/vendor/lusitanian/oauth/src/OAuth/Common/Http/Client/ClientInterface.php
new file mode 100644
index 00000000..f9c20226
--- /dev/null
+++ b/vendor/lusitanian/oauth/src/OAuth/Common/Http/Client/ClientInterface.php
@@ -0,0 +1,32 @@
+ value` pairs) to be passed to `curl_setopt`
+ *
+ * @var array
+ */
+ private $parameters = array();
+
+ /**
+ * Additional `curl_setopt` parameters
+ *
+ * @param array $parameters
+ */
+ public function setCurlParameters(array $parameters)
+ {
+ $this->parameters = $parameters;
+ }
+
+ /**
+ * @param bool $force
+ *
+ * @return CurlClient
+ */
+ public function setForceSSL3($force)
+ {
+ $this->forceSSL3 = $force;
+
+ return $this;
+ }
+
+ /**
+ * Any implementing HTTP providers should send a request to the provided endpoint with the parameters.
+ * They should return, in string form, the response body and throw an exception on error.
+ *
+ * @param UriInterface $endpoint
+ * @param mixed $requestBody
+ * @param array $extraHeaders
+ * @param string $method
+ *
+ * @return string
+ *
+ * @throws TokenResponseException
+ * @throws \InvalidArgumentException
+ */
+ public function retrieveResponse(
+ UriInterface $endpoint,
+ $requestBody,
+ array $extraHeaders = array(),
+ $method = 'POST'
+ ) {
+ // Normalize method name
+ $method = strtoupper($method);
+
+ $this->normalizeHeaders($extraHeaders);
+
+ if ($method === 'GET' && !empty($requestBody)) {
+ throw new \InvalidArgumentException('No body expected for "GET" request.');
+ }
+
+ if (!isset($extraHeaders['Content-Type']) && $method === 'POST' && is_array($requestBody)) {
+ $extraHeaders['Content-Type'] = 'Content-Type: application/x-www-form-urlencoded';
+ }
+
+ $extraHeaders['Host'] = 'Host: '.$endpoint->getHost();
+ $extraHeaders['Connection'] = 'Connection: close';
+
+ $ch = curl_init();
+
+ curl_setopt($ch, CURLOPT_URL, $endpoint->getAbsoluteUri());
+
+ if ($method === 'POST' || $method === 'PUT') {
+ if ($requestBody && is_array($requestBody)) {
+ $requestBody = http_build_query($requestBody, '', '&');
+ }
+
+ if ($method === 'PUT') {
+ curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'PUT');
+ } else {
+ curl_setopt($ch, CURLOPT_POST, true);
+ }
+
+ curl_setopt($ch, CURLOPT_POSTFIELDS, $requestBody);
+ } else {
+ curl_setopt($ch, CURLOPT_CUSTOMREQUEST, $method);
+ }
+
+ if ($this->maxRedirects > 0) {
+ curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);
+ curl_setopt($ch, CURLOPT_MAXREDIRS, $this->maxRedirects);
+ }
+
+ curl_setopt($ch, CURLOPT_TIMEOUT, $this->timeout);
+ curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
+ curl_setopt($ch, CURLOPT_HEADER, false);
+ curl_setopt($ch, CURLOPT_HTTPHEADER, $extraHeaders);
+ curl_setopt($ch, CURLOPT_USERAGENT, $this->userAgent);
+
+ foreach ($this->parameters as $key => $value) {
+ curl_setopt($ch, $key, $value);
+ }
+
+ if ($this->forceSSL3) {
+ curl_setopt($ch, CURLOPT_SSLVERSION, 3);
+ }
+
+ $response = curl_exec($ch);
+ $responseCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
+
+ if (false === $response) {
+ $errNo = curl_errno($ch);
+ $errStr = curl_error($ch);
+ curl_close($ch);
+ if (empty($errStr)) {
+ throw new TokenResponseException('Failed to request resource.', $responseCode);
+ }
+ throw new TokenResponseException('cURL Error # '.$errNo.': '.$errStr, $responseCode);
+ }
+
+ curl_close($ch);
+
+ return $response;
+ }
+}
diff --git a/vendor/lusitanian/oauth/src/OAuth/Common/Http/Client/StreamClient.php b/vendor/lusitanian/oauth/src/OAuth/Common/Http/Client/StreamClient.php
new file mode 100644
index 00000000..7f3c5249
--- /dev/null
+++ b/vendor/lusitanian/oauth/src/OAuth/Common/Http/Client/StreamClient.php
@@ -0,0 +1,92 @@
+normalizeHeaders($extraHeaders);
+
+ if ($method === 'GET' && !empty($requestBody)) {
+ throw new \InvalidArgumentException('No body expected for "GET" request.');
+ }
+
+ if (!isset($extraHeaders['Content-Type']) && $method === 'POST' && is_array($requestBody)) {
+ $extraHeaders['Content-Type'] = 'Content-Type: application/x-www-form-urlencoded';
+ }
+
+ $host = 'Host: '.$endpoint->getHost();
+ // Append port to Host if it has been specified
+ if ($endpoint->hasExplicitPortSpecified()) {
+ $host .= ':'.$endpoint->getPort();
+ }
+
+ $extraHeaders['Host'] = $host;
+ $extraHeaders['Connection'] = 'Connection: close';
+
+ if (is_array($requestBody)) {
+ $requestBody = http_build_query($requestBody, '', '&');
+ }
+ $extraHeaders['Content-length'] = 'Content-length: '.strlen($requestBody);
+
+ $context = $this->generateStreamContext($requestBody, $extraHeaders, $method);
+
+ $level = error_reporting(0);
+ $response = file_get_contents($endpoint->getAbsoluteUri(), false, $context);
+ error_reporting($level);
+ if (false === $response) {
+ $lastError = error_get_last();
+ if (is_null($lastError)) {
+ throw new TokenResponseException('Failed to request resource.');
+ }
+ throw new TokenResponseException($lastError['message']);
+ }
+
+ return $response;
+ }
+
+ private function generateStreamContext($body, $headers, $method)
+ {
+ return stream_context_create(
+ array(
+ 'http' => array(
+ 'method' => $method,
+ 'header' => implode("\r\n", array_values($headers)),
+ 'content' => $body,
+ 'protocol_version' => '1.1',
+ 'user_agent' => $this->userAgent,
+ 'max_redirects' => $this->maxRedirects,
+ 'timeout' => $this->timeout
+ ),
+ )
+ );
+ }
+}
diff --git a/vendor/lusitanian/oauth/src/OAuth/Common/Http/Exception/TokenResponseException.php b/vendor/lusitanian/oauth/src/OAuth/Common/Http/Exception/TokenResponseException.php
new file mode 100644
index 00000000..c519a223
--- /dev/null
+++ b/vendor/lusitanian/oauth/src/OAuth/Common/Http/Exception/TokenResponseException.php
@@ -0,0 +1,12 @@
+parseUri($uri);
+ }
+ }
+
+ /**
+ * @param string $uri
+ *
+ * @throws \InvalidArgumentException
+ */
+ protected function parseUri($uri)
+ {
+ if (false === ($uriParts = parse_url($uri))) {
+ // congratulations if you've managed to get parse_url to fail,
+ // it seems to always return some semblance of a parsed url no matter what
+ throw new InvalidArgumentException("Invalid URI: $uri");
+ }
+
+ if (!isset($uriParts['scheme'])) {
+ throw new InvalidArgumentException('Invalid URI: http|https scheme required');
+ }
+
+ $this->scheme = $uriParts['scheme'];
+ $this->host = $uriParts['host'];
+
+ if (isset($uriParts['port'])) {
+ $this->port = $uriParts['port'];
+ $this->explicitPortSpecified = true;
+ } else {
+ $this->port = strcmp('https', $uriParts['scheme']) ? 80 : 443;
+ $this->explicitPortSpecified = false;
+ }
+
+ if (isset($uriParts['path'])) {
+ $this->path = $uriParts['path'];
+ if ('/' === $uriParts['path']) {
+ $this->explicitTrailingHostSlash = true;
+ }
+ } else {
+ $this->path = '/';
+ }
+
+ $this->query = isset($uriParts['query']) ? $uriParts['query'] : '';
+ $this->fragment = isset($uriParts['fragment']) ? $uriParts['fragment'] : '';
+
+ $userInfo = '';
+ if (!empty($uriParts['user'])) {
+ $userInfo .= $uriParts['user'];
+ }
+ if ($userInfo && !empty($uriParts['pass'])) {
+ $userInfo .= ':' . $uriParts['pass'];
+ }
+
+ $this->setUserInfo($userInfo);
+ }
+
+ /**
+ * @param string $rawUserInfo
+ *
+ * @return string
+ */
+ protected function protectUserInfo($rawUserInfo)
+ {
+ $colonPos = strpos($rawUserInfo, ':');
+
+ // rfc3986-3.2.1 | http://tools.ietf.org/html/rfc3986#section-3.2
+ // "Applications should not render as clear text any data
+ // after the first colon (":") character found within a userinfo
+ // subcomponent unless the data after the colon is the empty string
+ // (indicating no password)"
+ if ($colonPos !== false && strlen($rawUserInfo)-1 > $colonPos) {
+ return substr($rawUserInfo, 0, $colonPos) . ':********';
+ } else {
+ return $rawUserInfo;
+ }
+ }
+
+ /**
+ * @return string
+ */
+ public function getScheme()
+ {
+ return $this->scheme;
+ }
+
+ /**
+ * @return string
+ */
+ public function getUserInfo()
+ {
+ return $this->userInfo;
+ }
+
+ /**
+ * @return string
+ */
+ public function getRawUserInfo()
+ {
+ return $this->rawUserInfo;
+ }
+
+ /**
+ * @return string
+ */
+ public function getHost()
+ {
+ return $this->host;
+ }
+
+ /**
+ * @return int
+ */
+ public function getPort()
+ {
+ return $this->port;
+ }
+
+ /**
+ * @return string
+ */
+ public function getPath()
+ {
+ return $this->path;
+ }
+
+ /**
+ * @return string
+ */
+ public function getQuery()
+ {
+ return $this->query;
+ }
+
+ /**
+ * @return string
+ */
+ public function getFragment()
+ {
+ return $this->fragment;
+ }
+
+ /**
+ * Uses protected user info by default as per rfc3986-3.2.1
+ * Uri::getRawAuthority() is available if plain-text password information is desirable.
+ *
+ * @return string
+ */
+ public function getAuthority()
+ {
+ $authority = $this->userInfo ? $this->userInfo.'@' : '';
+ $authority .= $this->host;
+
+ if ($this->explicitPortSpecified) {
+ $authority .= ":{$this->port}";
+ }
+
+ return $authority;
+ }
+
+ /**
+ * @return string
+ */
+ public function getRawAuthority()
+ {
+ $authority = $this->rawUserInfo ? $this->rawUserInfo.'@' : '';
+ $authority .= $this->host;
+
+ if ($this->explicitPortSpecified) {
+ $authority .= ":{$this->port}";
+ }
+
+ return $authority;
+ }
+
+ /**
+ * @return string
+ */
+ public function getAbsoluteUri()
+ {
+ $uri = $this->scheme . '://' . $this->getRawAuthority();
+
+ if ('/' === $this->path) {
+ $uri .= $this->explicitTrailingHostSlash ? '/' : '';
+ } else {
+ $uri .= $this->path;
+ }
+
+ if (!empty($this->query)) {
+ $uri .= "?{$this->query}";
+ }
+
+ if (!empty($this->fragment)) {
+ $uri .= "#{$this->fragment}";
+ }
+
+ return $uri;
+ }
+
+ /**
+ * @return string
+ */
+ public function getRelativeUri()
+ {
+ $uri = '';
+
+ if ('/' === $this->path) {
+ $uri .= $this->explicitTrailingHostSlash ? '/' : '';
+ } else {
+ $uri .= $this->path;
+ }
+
+ return $uri;
+ }
+
+ /**
+ * Uses protected user info by default as per rfc3986-3.2.1
+ * Uri::getAbsoluteUri() is available if plain-text password information is desirable.
+ *
+ * @return string
+ */
+ public function __toString()
+ {
+ $uri = $this->scheme . '://' . $this->getAuthority();
+
+ if ('/' === $this->path) {
+ $uri .= $this->explicitTrailingHostSlash ? '/' : '';
+ } else {
+ $uri .= $this->path;
+ }
+
+ if (!empty($this->query)) {
+ $uri .= "?{$this->query}";
+ }
+
+ if (!empty($this->fragment)) {
+ $uri .= "#{$this->fragment}";
+ }
+
+ return $uri;
+ }
+
+ /**
+ * @param $path
+ */
+ public function setPath($path)
+ {
+ if (empty($path)) {
+ $this->path = '/';
+ $this->explicitTrailingHostSlash = false;
+ } else {
+ $this->path = $path;
+ if ('/' === $this->path) {
+ $this->explicitTrailingHostSlash = true;
+ }
+ }
+ }
+
+ /**
+ * @param string $query
+ */
+ public function setQuery($query)
+ {
+ $this->query = $query;
+ }
+
+ /**
+ * @param string $var
+ * @param string $val
+ */
+ public function addToQuery($var, $val)
+ {
+ if (strlen($this->query) > 0) {
+ $this->query .= '&';
+ }
+ $this->query .= http_build_query(array($var => $val), '', '&');
+ }
+
+ /**
+ * @param string $fragment
+ */
+ public function setFragment($fragment)
+ {
+ $this->fragment = $fragment;
+ }
+
+ /**
+ * @param string $scheme
+ */
+ public function setScheme($scheme)
+ {
+ $this->scheme = $scheme;
+ }
+
+
+ /**
+ * @param string $userInfo
+ */
+ public function setUserInfo($userInfo)
+ {
+ $this->userInfo = $userInfo ? $this->protectUserInfo($userInfo) : '';
+ $this->rawUserInfo = $userInfo;
+ }
+
+
+ /**
+ * @param int $port
+ */
+ public function setPort($port)
+ {
+ $this->port = intval($port);
+
+ if (('https' === $this->scheme && $this->port === 443) || ('http' === $this->scheme && $this->port === 80)) {
+ $this->explicitPortSpecified = false;
+ } else {
+ $this->explicitPortSpecified = true;
+ }
+ }
+
+ /**
+ * @param string $host
+ */
+ public function setHost($host)
+ {
+ $this->host = $host;
+ }
+
+ /**
+ * @return bool
+ */
+ public function hasExplicitTrailingHostSlash()
+ {
+ return $this->explicitTrailingHostSlash;
+ }
+
+ /**
+ * @return bool
+ */
+ public function hasExplicitPortSpecified()
+ {
+ return $this->explicitPortSpecified;
+ }
+}
diff --git a/vendor/lusitanian/oauth/src/OAuth/Common/Http/Uri/UriFactory.php b/vendor/lusitanian/oauth/src/OAuth/Common/Http/Uri/UriFactory.php
new file mode 100644
index 00000000..127aa203
--- /dev/null
+++ b/vendor/lusitanian/oauth/src/OAuth/Common/Http/Uri/UriFactory.php
@@ -0,0 +1,168 @@
+attemptProxyStyleParse($_server)) {
+ return $uri;
+ }
+
+ $scheme = $this->detectScheme($_server);
+ $host = $this->detectHost($_server);
+ $port = $this->detectPort($_server);
+ $path = $this->detectPath($_server);
+ $query = $this->detectQuery($_server);
+
+ return $this->createFromParts($scheme, '', $host, $port, $path, $query);
+ }
+
+ /**
+ * @param string $absoluteUri
+ *
+ * @return UriInterface
+ */
+ public function createFromAbsolute($absoluteUri)
+ {
+ return new Uri($absoluteUri);
+ }
+
+ /**
+ * Factory method to build a URI from parts
+ *
+ * @param string $scheme
+ * @param string $userInfo
+ * @param string $host
+ * @param string $port
+ * @param string $path
+ * @param string $query
+ * @param string $fragment
+ *
+ * @return UriInterface
+ */
+ public function createFromParts($scheme, $userInfo, $host, $port, $path = '', $query = '', $fragment = '')
+ {
+ $uri = new Uri();
+ $uri->setScheme($scheme);
+ $uri->setUserInfo($userInfo);
+ $uri->setHost($host);
+ $uri->setPort($port);
+ $uri->setPath($path);
+ $uri->setQuery($query);
+ $uri->setFragment($fragment);
+
+ return $uri;
+ }
+
+ /**
+ * @param array $_server
+ *
+ * @return UriInterface|null
+ */
+ private function attemptProxyStyleParse($_server)
+ {
+ // If the raw HTTP request message arrives with a proxy-style absolute URI in the
+ // initial request line, the absolute URI is stored in $_SERVER['REQUEST_URI'] and
+ // we only need to parse that.
+ if (isset($_server['REQUEST_URI']) && parse_url($_server['REQUEST_URI'], PHP_URL_SCHEME)) {
+ return new Uri($_server['REQUEST_URI']);
+ }
+
+ return null;
+ }
+
+ /**
+ * @param array $_server
+ *
+ * @return string
+ *
+ * @throws RuntimeException
+ */
+ private function detectPath($_server)
+ {
+ if (isset($_server['REQUEST_URI'])) {
+ $uri = $_server['REQUEST_URI'];
+ } elseif (isset($_server['REDIRECT_URL'])) {
+ $uri = $_server['REDIRECT_URL'];
+ } else {
+ throw new RuntimeException('Could not detect URI path from superglobal');
+ }
+
+ $queryStr = strpos($uri, '?');
+ if ($queryStr !== false) {
+ $uri = substr($uri, 0, $queryStr);
+ }
+
+ return $uri;
+ }
+
+ /**
+ * @param array $_server
+ *
+ * @return string
+ */
+ private function detectHost(array $_server)
+ {
+ $host = isset($_server['HTTP_HOST']) ? $_server['HTTP_HOST'] : '';
+
+ if (strstr($host, ':')) {
+ $host = parse_url($host, PHP_URL_HOST);
+ }
+
+ return $host;
+ }
+
+ /**
+ * @param array $_server
+ *
+ * @return string
+ */
+ private function detectPort(array $_server)
+ {
+ return isset($_server['SERVER_PORT']) ? $_server['SERVER_PORT'] : 80;
+ }
+
+ /**
+ * @param array $_server
+ *
+ * @return string
+ */
+ private function detectQuery(array $_server)
+ {
+ return isset($_server['QUERY_STRING']) ? $_server['QUERY_STRING'] : '';
+ }
+
+ /**
+ * Determine URI scheme component from superglobal array
+ *
+ * When using ISAPI with IIS, the value will be "off" if the request was
+ * not made through the HTTPS protocol. As a result, we filter the
+ * value to a bool.
+ *
+ * @param array $_server A super-global $_SERVER array
+ *
+ * @return string Returns http or https depending on the URI scheme
+ */
+ private function detectScheme(array $_server)
+ {
+ if (isset($_server['HTTPS']) && filter_var($_server['HTTPS'], FILTER_VALIDATE_BOOLEAN)) {
+ return 'https';
+ } else {
+ return 'http';
+ }
+ }
+}
diff --git a/vendor/lusitanian/oauth/src/OAuth/Common/Http/Uri/UriFactoryInterface.php b/vendor/lusitanian/oauth/src/OAuth/Common/Http/Uri/UriFactoryInterface.php
new file mode 100644
index 00000000..2b157d84
--- /dev/null
+++ b/vendor/lusitanian/oauth/src/OAuth/Common/Http/Uri/UriFactoryInterface.php
@@ -0,0 +1,42 @@
+credentials = $credentials;
+ $this->httpClient = $httpClient;
+ $this->storage = $storage;
+ }
+
+ /**
+ * @param UriInterface|string $path
+ * @param UriInterface $baseApiUri
+ *
+ * @return UriInterface
+ *
+ * @throws Exception
+ */
+ protected function determineRequestUriFromPath($path, UriInterface $baseApiUri = null)
+ {
+ if ($path instanceof UriInterface) {
+ $uri = $path;
+ } elseif (stripos($path, 'http://') === 0 || stripos($path, 'https://') === 0) {
+ $uri = new Uri($path);
+ } else {
+ if (null === $baseApiUri) {
+ throw new Exception(
+ 'An absolute URI must be passed to ServiceInterface::request as no baseApiUri is set.'
+ );
+ }
+
+ $uri = clone $baseApiUri;
+ if (false !== strpos($path, '?')) {
+ $parts = explode('?', $path, 2);
+ $path = $parts[0];
+ $query = $parts[1];
+ $uri->setQuery($query);
+ }
+
+ if ($path[0] === '/') {
+ $path = substr($path, 1);
+ }
+
+ $uri->setPath($uri->getPath() . $path);
+ }
+
+ return $uri;
+ }
+
+ /**
+ * Accessor to the storage adapter to be able to retrieve tokens
+ *
+ * @return TokenStorageInterface
+ */
+ public function getStorage()
+ {
+ return $this->storage;
+ }
+
+ /**
+ * @return string
+ */
+ public function service()
+ {
+ // get class name without backslashes
+ $classname = get_class($this);
+
+ return preg_replace('/^.*\\\\/', '', $classname);
+ }
+}
diff --git a/vendor/lusitanian/oauth/src/OAuth/Common/Service/ServiceInterface.php b/vendor/lusitanian/oauth/src/OAuth/Common/Service/ServiceInterface.php
new file mode 100644
index 00000000..5856a039
--- /dev/null
+++ b/vendor/lusitanian/oauth/src/OAuth/Common/Service/ServiceInterface.php
@@ -0,0 +1,49 @@
+tokens = array();
+ $this->states = array();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public function retrieveAccessToken($service)
+ {
+ if ($this->hasAccessToken($service)) {
+ return $this->tokens[$service];
+ }
+
+ throw new TokenNotFoundException('Token not stored');
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public function storeAccessToken($service, TokenInterface $token)
+ {
+ $this->tokens[$service] = $token;
+
+ // allow chaining
+ return $this;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public function hasAccessToken($service)
+ {
+ return isset($this->tokens[$service]) && $this->tokens[$service] instanceof TokenInterface;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public function clearToken($service)
+ {
+ if (array_key_exists($service, $this->tokens)) {
+ unset($this->tokens[$service]);
+ }
+
+ // allow chaining
+ return $this;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public function clearAllTokens()
+ {
+ $this->tokens = array();
+
+ // allow chaining
+ return $this;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public function retrieveAuthorizationState($service)
+ {
+ if ($this->hasAuthorizationState($service)) {
+ return $this->states[$service];
+ }
+
+ throw new AuthorizationStateNotFoundException('State not stored');
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public function storeAuthorizationState($service, $state)
+ {
+ $this->states[$service] = $state;
+
+ // allow chaining
+ return $this;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public function hasAuthorizationState($service)
+ {
+ return isset($this->states[$service]) && null !== $this->states[$service];
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public function clearAuthorizationState($service)
+ {
+ if (array_key_exists($service, $this->states)) {
+ unset($this->states[$service]);
+ }
+
+ // allow chaining
+ return $this;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public function clearAllAuthorizationStates()
+ {
+ $this->states = array();
+
+ // allow chaining
+ return $this;
+ }
+}
diff --git a/vendor/lusitanian/oauth/src/OAuth/Common/Storage/Redis.php b/vendor/lusitanian/oauth/src/OAuth/Common/Storage/Redis.php
new file mode 100644
index 00000000..77318bd6
--- /dev/null
+++ b/vendor/lusitanian/oauth/src/OAuth/Common/Storage/Redis.php
@@ -0,0 +1,230 @@
+redis = $redis;
+ $this->key = $key;
+ $this->stateKey = $stateKey;
+ $this->cachedTokens = array();
+ $this->cachedStates = array();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public function retrieveAccessToken($service)
+ {
+ if (!$this->hasAccessToken($service)) {
+ throw new TokenNotFoundException('Token not found in redis');
+ }
+
+ if (isset($this->cachedTokens[$service])) {
+ return $this->cachedTokens[$service];
+ }
+
+ $val = $this->redis->hget($this->key, $service);
+
+ return $this->cachedTokens[$service] = unserialize($val);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public function storeAccessToken($service, TokenInterface $token)
+ {
+ // (over)write the token
+ $this->redis->hset($this->key, $service, serialize($token));
+ $this->cachedTokens[$service] = $token;
+
+ // allow chaining
+ return $this;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public function hasAccessToken($service)
+ {
+ if (isset($this->cachedTokens[$service])
+ && $this->cachedTokens[$service] instanceof TokenInterface
+ ) {
+ return true;
+ }
+
+ return $this->redis->hexists($this->key, $service);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public function clearToken($service)
+ {
+ $this->redis->hdel($this->key, $service);
+ unset($this->cachedTokens[$service]);
+
+ // allow chaining
+ return $this;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public function clearAllTokens()
+ {
+ // memory
+ $this->cachedTokens = array();
+
+ // redis
+ $keys = $this->redis->hkeys($this->key);
+ $me = $this; // 5.3 compat
+
+ // pipeline for performance
+ $this->redis->pipeline(
+ function ($pipe) use ($keys, $me) {
+ foreach ($keys as $k) {
+ $pipe->hdel($me->getKey(), $k);
+ }
+ }
+ );
+
+ // allow chaining
+ return $this;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public function retrieveAuthorizationState($service)
+ {
+ if (!$this->hasAuthorizationState($service)) {
+ throw new AuthorizationStateNotFoundException('State not found in redis');
+ }
+
+ if (isset($this->cachedStates[$service])) {
+ return $this->cachedStates[$service];
+ }
+
+ $val = $this->redis->hget($this->stateKey, $service);
+
+ return $this->cachedStates[$service] = unserialize($val);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public function storeAuthorizationState($service, $state)
+ {
+ // (over)write the token
+ $this->redis->hset($this->stateKey, $service, $state);
+ $this->cachedStates[$service] = $state;
+
+ // allow chaining
+ return $this;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public function hasAuthorizationState($service)
+ {
+ if (isset($this->cachedStates[$service])
+ && null !== $this->cachedStates[$service]
+ ) {
+ return true;
+ }
+
+ return $this->redis->hexists($this->stateKey, $service);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public function clearAuthorizationState($service)
+ {
+ $this->redis->hdel($this->stateKey, $service);
+ unset($this->cachedStates[$service]);
+
+ // allow chaining
+ return $this;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public function clearAllAuthorizationStates()
+ {
+ // memory
+ $this->cachedStates = array();
+
+ // redis
+ $keys = $this->redis->hkeys($this->stateKey);
+ $me = $this; // 5.3 compat
+
+ // pipeline for performance
+ $this->redis->pipeline(
+ function ($pipe) use ($keys, $me) {
+ foreach ($keys as $k) {
+ $pipe->hdel($me->getKey(), $k);
+ }
+ }
+ );
+
+ // allow chaining
+ return $this;
+ }
+
+ /**
+ * @return Predis $redis
+ */
+ public function getRedis()
+ {
+ return $this->redis;
+ }
+
+ /**
+ * @return string $key
+ */
+ public function getKey()
+ {
+ return $this->key;
+ }
+}
diff --git a/vendor/lusitanian/oauth/src/OAuth/Common/Storage/Session.php b/vendor/lusitanian/oauth/src/OAuth/Common/Storage/Session.php
new file mode 100644
index 00000000..e908a67e
--- /dev/null
+++ b/vendor/lusitanian/oauth/src/OAuth/Common/Storage/Session.php
@@ -0,0 +1,188 @@
+startSession = $startSession;
+ $this->sessionVariableName = $sessionVariableName;
+ $this->stateVariableName = $stateVariableName;
+ if (!isset($_SESSION[$sessionVariableName])) {
+ $_SESSION[$sessionVariableName] = array();
+ }
+ if (!isset($_SESSION[$stateVariableName])) {
+ $_SESSION[$stateVariableName] = array();
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public function retrieveAccessToken($service)
+ {
+ if ($this->hasAccessToken($service)) {
+ return unserialize($_SESSION[$this->sessionVariableName][$service]);
+ }
+
+ throw new TokenNotFoundException('Token not found in session, are you sure you stored it?');
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public function storeAccessToken($service, TokenInterface $token)
+ {
+ $serializedToken = serialize($token);
+
+ if (isset($_SESSION[$this->sessionVariableName])
+ && is_array($_SESSION[$this->sessionVariableName])
+ ) {
+ $_SESSION[$this->sessionVariableName][$service] = $serializedToken;
+ } else {
+ $_SESSION[$this->sessionVariableName] = array(
+ $service => $serializedToken,
+ );
+ }
+
+ // allow chaining
+ return $this;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public function hasAccessToken($service)
+ {
+ return isset($_SESSION[$this->sessionVariableName], $_SESSION[$this->sessionVariableName][$service]);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public function clearToken($service)
+ {
+ if (array_key_exists($service, $_SESSION[$this->sessionVariableName])) {
+ unset($_SESSION[$this->sessionVariableName][$service]);
+ }
+
+ // allow chaining
+ return $this;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public function clearAllTokens()
+ {
+ unset($_SESSION[$this->sessionVariableName]);
+
+ // allow chaining
+ return $this;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public function storeAuthorizationState($service, $state)
+ {
+ if (isset($_SESSION[$this->stateVariableName])
+ && is_array($_SESSION[$this->stateVariableName])
+ ) {
+ $_SESSION[$this->stateVariableName][$service] = $state;
+ } else {
+ $_SESSION[$this->stateVariableName] = array(
+ $service => $state,
+ );
+ }
+
+ // allow chaining
+ return $this;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public function hasAuthorizationState($service)
+ {
+ return isset($_SESSION[$this->stateVariableName], $_SESSION[$this->stateVariableName][$service]);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public function retrieveAuthorizationState($service)
+ {
+ if ($this->hasAuthorizationState($service)) {
+ return $_SESSION[$this->stateVariableName][$service];
+ }
+
+ throw new AuthorizationStateNotFoundException('State not found in session, are you sure you stored it?');
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public function clearAuthorizationState($service)
+ {
+ if (array_key_exists($service, $_SESSION[$this->stateVariableName])) {
+ unset($_SESSION[$this->stateVariableName][$service]);
+ }
+
+ // allow chaining
+ return $this;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public function clearAllAuthorizationStates()
+ {
+ unset($_SESSION[$this->stateVariableName]);
+
+ // allow chaining
+ return $this;
+ }
+
+ public function __destruct()
+ {
+ if ($this->startSession) {
+ session_write_close();
+ }
+ }
+}
diff --git a/vendor/lusitanian/oauth/src/OAuth/Common/Storage/SymfonySession.php b/vendor/lusitanian/oauth/src/OAuth/Common/Storage/SymfonySession.php
new file mode 100644
index 00000000..6c5fbf60
--- /dev/null
+++ b/vendor/lusitanian/oauth/src/OAuth/Common/Storage/SymfonySession.php
@@ -0,0 +1,200 @@
+session = $session;
+ $this->sessionVariableName = $sessionVariableName;
+ $this->stateVariableName = $stateVariableName;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public function retrieveAccessToken($service)
+ {
+ if ($this->hasAccessToken($service)) {
+ // get from session
+ $tokens = $this->session->get($this->sessionVariableName);
+
+ // one item
+ return $tokens[$service];
+ }
+
+ throw new TokenNotFoundException('Token not found in session, are you sure you stored it?');
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public function storeAccessToken($service, TokenInterface $token)
+ {
+ // get previously saved tokens
+ $tokens = $this->session->get($this->sessionVariableName);
+
+ if (!is_array($tokens)) {
+ $tokens = array();
+ }
+
+ $tokens[$service] = $token;
+
+ // save
+ $this->session->set($this->sessionVariableName, $tokens);
+
+ // allow chaining
+ return $this;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public function hasAccessToken($service)
+ {
+ // get from session
+ $tokens = $this->session->get($this->sessionVariableName);
+
+ return is_array($tokens)
+ && isset($tokens[$service])
+ && $tokens[$service] instanceof TokenInterface;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public function clearToken($service)
+ {
+ // get previously saved tokens
+ $tokens = $this->session->get($this->sessionVariableName);
+
+ if (is_array($tokens) && array_key_exists($service, $tokens)) {
+ unset($tokens[$service]);
+
+ // Replace the stored tokens array
+ $this->session->set($this->sessionVariableName, $tokens);
+ }
+
+ // allow chaining
+ return $this;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public function clearAllTokens()
+ {
+ $this->session->remove($this->sessionVariableName);
+
+ // allow chaining
+ return $this;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public function retrieveAuthorizationState($service)
+ {
+ if ($this->hasAuthorizationState($service)) {
+ // get from session
+ $states = $this->session->get($this->stateVariableName);
+
+ // one item
+ return $states[$service];
+ }
+
+ throw new AuthorizationStateNotFoundException('State not found in session, are you sure you stored it?');
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public function storeAuthorizationState($service, $state)
+ {
+ // get previously saved tokens
+ $states = $this->session->get($this->stateVariableName);
+
+ if (!is_array($states)) {
+ $states = array();
+ }
+
+ $states[$service] = $state;
+
+ // save
+ $this->session->set($this->stateVariableName, $states);
+
+ // allow chaining
+ return $this;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public function hasAuthorizationState($service)
+ {
+ // get from session
+ $states = $this->session->get($this->stateVariableName);
+
+ return is_array($states)
+ && isset($states[$service])
+ && null !== $states[$service];
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public function clearAuthorizationState($service)
+ {
+ // get previously saved tokens
+ $states = $this->session->get($this->stateVariableName);
+
+ if (is_array($states) && array_key_exists($service, $states)) {
+ unset($states[$service]);
+
+ // Replace the stored tokens array
+ $this->session->set($this->stateVariableName, $states);
+ }
+
+ // allow chaining
+ return $this;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public function clearAllAuthorizationStates()
+ {
+ $this->session->remove($this->stateVariableName);
+
+ // allow chaining
+ return $this;
+ }
+
+ /**
+ * @return Session
+ */
+ public function getSession()
+ {
+ return $this->session;
+ }
+}
diff --git a/vendor/lusitanian/oauth/src/OAuth/Common/Storage/TokenStorageInterface.php b/vendor/lusitanian/oauth/src/OAuth/Common/Storage/TokenStorageInterface.php
new file mode 100644
index 00000000..46552cee
--- /dev/null
+++ b/vendor/lusitanian/oauth/src/OAuth/Common/Storage/TokenStorageInterface.php
@@ -0,0 +1,98 @@
+accessToken = $accessToken;
+ $this->refreshToken = $refreshToken;
+ $this->setLifetime($lifetime);
+ $this->extraParams = $extraParams;
+ }
+
+ /**
+ * @return string
+ */
+ public function getAccessToken()
+ {
+ return $this->accessToken;
+ }
+
+ /**
+ * @return string
+ */
+ public function getRefreshToken()
+ {
+ return $this->refreshToken;
+ }
+
+ /**
+ * @return int
+ */
+ public function getEndOfLife()
+ {
+ return $this->endOfLife;
+ }
+
+ /**
+ * @param array $extraParams
+ */
+ public function setExtraParams(array $extraParams)
+ {
+ $this->extraParams = $extraParams;
+ }
+
+ /**
+ * @return array
+ */
+ public function getExtraParams()
+ {
+ return $this->extraParams;
+ }
+
+ /**
+ * @param string $accessToken
+ */
+ public function setAccessToken($accessToken)
+ {
+ $this->accessToken = $accessToken;
+ }
+
+ /**
+ * @param int $endOfLife
+ */
+ public function setEndOfLife($endOfLife)
+ {
+ $this->endOfLife = $endOfLife;
+ }
+
+ /**
+ * @param int $lifetime
+ */
+ public function setLifetime($lifetime)
+ {
+ if (0 === $lifetime || static::EOL_NEVER_EXPIRES === $lifetime) {
+ $this->endOfLife = static::EOL_NEVER_EXPIRES;
+ } elseif (null !== $lifetime) {
+ $this->endOfLife = intval($lifetime) + time();
+ } else {
+ $this->endOfLife = static::EOL_UNKNOWN;
+ }
+ }
+
+ /**
+ * @param string $refreshToken
+ */
+ public function setRefreshToken($refreshToken)
+ {
+ $this->refreshToken = $refreshToken;
+ }
+
+ public function isExpired()
+ {
+ return ($this->getEndOfLife() !== TokenInterface::EOL_NEVER_EXPIRES
+ && $this->getEndOfLife() !== TokenInterface::EOL_UNKNOWN
+ && time() > $this->getEndOfLife());
+ }
+}
diff --git a/vendor/lusitanian/oauth/src/OAuth/Common/Token/Exception/ExpiredTokenException.php b/vendor/lusitanian/oauth/src/OAuth/Common/Token/Exception/ExpiredTokenException.php
new file mode 100644
index 00000000..26ad6cc5
--- /dev/null
+++ b/vendor/lusitanian/oauth/src/OAuth/Common/Token/Exception/ExpiredTokenException.php
@@ -0,0 +1,12 @@
+signature = $signature;
+ $this->baseApiUri = $baseApiUri;
+
+ $this->signature->setHashingAlgorithm($this->getSignatureMethod());
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public function requestRequestToken()
+ {
+ $authorizationHeader = array('Authorization' => $this->buildAuthorizationHeaderForTokenRequest());
+ $headers = array_merge($authorizationHeader, $this->getExtraOAuthHeaders());
+
+ $responseBody = $this->httpClient->retrieveResponse($this->getRequestTokenEndpoint(), array(), $headers);
+
+ $token = $this->parseRequestTokenResponse($responseBody);
+ $this->storage->storeAccessToken($this->service(), $token);
+
+ return $token;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function getAuthorizationUri(array $additionalParameters = array())
+ {
+ // Build the url
+ $url = clone $this->getAuthorizationEndpoint();
+ foreach ($additionalParameters as $key => $val) {
+ $url->addToQuery($key, $val);
+ }
+
+ return $url;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public function requestAccessToken($token, $verifier, $tokenSecret = null)
+ {
+ if (is_null($tokenSecret)) {
+ $storedRequestToken = $this->storage->retrieveAccessToken($this->service());
+ $tokenSecret = $storedRequestToken->getRequestTokenSecret();
+ }
+ $this->signature->setTokenSecret($tokenSecret);
+
+ $bodyParams = array(
+ 'oauth_verifier' => $verifier,
+ );
+
+ $authorizationHeader = array(
+ 'Authorization' => $this->buildAuthorizationHeaderForAPIRequest(
+ 'POST',
+ $this->getAccessTokenEndpoint(),
+ $this->storage->retrieveAccessToken($this->service()),
+ $bodyParams
+ )
+ );
+
+ $headers = array_merge($authorizationHeader, $this->getExtraOAuthHeaders());
+
+ $responseBody = $this->httpClient->retrieveResponse($this->getAccessTokenEndpoint(), $bodyParams, $headers);
+
+ $token = $this->parseAccessTokenResponse($responseBody);
+ $this->storage->storeAccessToken($this->service(), $token);
+
+ return $token;
+ }
+
+ /**
+ * Sends an authenticated API request to the path provided.
+ * If the path provided is not an absolute URI, the base API Uri (must be passed into constructor) will be used.
+ *
+ * @param string|UriInterface $path
+ * @param string $method HTTP method
+ * @param array $body Request body if applicable (key/value pairs)
+ * @param array $extraHeaders Extra headers if applicable.
+ * These will override service-specific any defaults.
+ *
+ * @return string
+ */
+ public function request($path, $method = 'GET', $body = null, array $extraHeaders = array())
+ {
+ $uri = $this->determineRequestUriFromPath($path, $this->baseApiUri);
+
+ /** @var $token StdOAuth1Token */
+ $token = $this->storage->retrieveAccessToken($this->service());
+ $extraHeaders = array_merge($this->getExtraApiHeaders(), $extraHeaders);
+ $authorizationHeader = array(
+ 'Authorization' => $this->buildAuthorizationHeaderForAPIRequest($method, $uri, $token, $body)
+ );
+ $headers = array_merge($authorizationHeader, $extraHeaders);
+
+ return $this->httpClient->retrieveResponse($uri, $body, $headers, $method);
+ }
+
+ /**
+ * Return any additional headers always needed for this service implementation's OAuth calls.
+ *
+ * @return array
+ */
+ protected function getExtraOAuthHeaders()
+ {
+ return array();
+ }
+
+ /**
+ * Return any additional headers always needed for this service implementation's API calls.
+ *
+ * @return array
+ */
+ protected function getExtraApiHeaders()
+ {
+ return array();
+ }
+
+ /**
+ * Builds the authorization header for getting an access or request token.
+ *
+ * @param array $extraParameters
+ *
+ * @return string
+ */
+ protected function buildAuthorizationHeaderForTokenRequest(array $extraParameters = array())
+ {
+ $parameters = $this->getBasicAuthorizationHeaderInfo();
+ $parameters = array_merge($parameters, $extraParameters);
+ $parameters['oauth_signature'] = $this->signature->getSignature(
+ $this->getRequestTokenEndpoint(),
+ $parameters,
+ 'POST'
+ );
+
+ $authorizationHeader = 'OAuth ';
+ $delimiter = '';
+ foreach ($parameters as $key => $value) {
+ $authorizationHeader .= $delimiter . rawurlencode($key) . '="' . rawurlencode($value) . '"';
+
+ $delimiter = ', ';
+ }
+
+ return $authorizationHeader;
+ }
+
+ /**
+ * Builds the authorization header for an authenticated API request
+ *
+ * @param string $method
+ * @param UriInterface $uri The uri the request is headed
+ * @param TokenInterface $token
+ * @param array $bodyParams Request body if applicable (key/value pairs)
+ *
+ * @return string
+ */
+ protected function buildAuthorizationHeaderForAPIRequest(
+ $method,
+ UriInterface $uri,
+ TokenInterface $token,
+ $bodyParams = null
+ ) {
+ $this->signature->setTokenSecret($token->getAccessTokenSecret());
+ $parameters = $this->getBasicAuthorizationHeaderInfo();
+ if (isset($parameters['oauth_callback'])) {
+ unset($parameters['oauth_callback']);
+ }
+
+ $parameters = array_merge($parameters, array('oauth_token' => $token->getAccessToken()));
+ $parameters = (is_array($bodyParams)) ? array_merge($parameters, $bodyParams) : $parameters;
+ $parameters['oauth_signature'] = $this->signature->getSignature($uri, $parameters, $method);
+
+ $authorizationHeader = 'OAuth ';
+ $delimiter = '';
+
+ foreach ($parameters as $key => $value) {
+ $authorizationHeader .= $delimiter . rawurlencode($key) . '="' . rawurlencode($value) . '"';
+ $delimiter = ', ';
+ }
+
+ return $authorizationHeader;
+ }
+
+ /**
+ * Builds the authorization header array.
+ *
+ * @return array
+ */
+ protected function getBasicAuthorizationHeaderInfo()
+ {
+ $dateTime = new \DateTime();
+ $headerParameters = array(
+ 'oauth_callback' => $this->credentials->getCallbackUrl(),
+ 'oauth_consumer_key' => $this->credentials->getConsumerId(),
+ 'oauth_nonce' => $this->generateNonce(),
+ 'oauth_signature_method' => $this->getSignatureMethod(),
+ 'oauth_timestamp' => $dateTime->format('U'),
+ 'oauth_version' => $this->getVersion(),
+ );
+
+ return $headerParameters;
+ }
+
+ /**
+ * Pseudo random string generator used to build a unique string to sign each request
+ *
+ * @param int $length
+ *
+ * @return string
+ */
+ protected function generateNonce($length = 32)
+ {
+ $characters = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890';
+
+ $nonce = '';
+ $maxRand = strlen($characters)-1;
+ for ($i = 0; $i < $length; $i++) {
+ $nonce.= $characters[rand(0, $maxRand)];
+ }
+
+ return $nonce;
+ }
+
+ /**
+ * @return string
+ */
+ protected function getSignatureMethod()
+ {
+ return 'HMAC-SHA1';
+ }
+
+ /**
+ * This returns the version used in the authorization header of the requests
+ *
+ * @return string
+ */
+ protected function getVersion()
+ {
+ return '1.0';
+ }
+
+ /**
+ * Parses the request token response and returns a TokenInterface.
+ * This is only needed to verify the `oauth_callback_confirmed` parameter. The actual
+ * parsing logic is contained in the access token parser.
+ *
+ * @abstract
+ *
+ * @param string $responseBody
+ *
+ * @return TokenInterface
+ *
+ * @throws TokenResponseException
+ */
+ abstract protected function parseRequestTokenResponse($responseBody);
+
+ /**
+ * Parses the access token response and returns a TokenInterface.
+ *
+ * @abstract
+ *
+ * @param string $responseBody
+ *
+ * @return TokenInterface
+ *
+ * @throws TokenResponseException
+ */
+ abstract protected function parseAccessTokenResponse($responseBody);
+}
diff --git a/vendor/lusitanian/oauth/src/OAuth/OAuth1/Service/BitBucket.php b/vendor/lusitanian/oauth/src/OAuth/OAuth1/Service/BitBucket.php
new file mode 100644
index 00000000..f6d8edfe
--- /dev/null
+++ b/vendor/lusitanian/oauth/src/OAuth/OAuth1/Service/BitBucket.php
@@ -0,0 +1,96 @@
+baseApiUri = new Uri('https://bitbucket.org/api/1.0/');
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public function getRequestTokenEndpoint()
+ {
+ return new Uri('https://bitbucket.org/!api/1.0/oauth/request_token');
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function getAuthorizationEndpoint()
+ {
+ return new Uri('https://bitbucket.org/!api/1.0/oauth/authenticate');
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function getAccessTokenEndpoint()
+ {
+ return new Uri('https://bitbucket.org/!api/1.0/oauth/access_token');
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ protected function parseRequestTokenResponse($responseBody)
+ {
+ parse_str($responseBody, $data);
+
+ if (null === $data || !is_array($data)) {
+ throw new TokenResponseException('Unable to parse response.');
+ } elseif (!isset($data['oauth_callback_confirmed']) || $data['oauth_callback_confirmed'] !== 'true') {
+ throw new TokenResponseException('Error in retrieving token.');
+ }
+
+ return $this->parseAccessTokenResponse($responseBody);
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ protected function parseAccessTokenResponse($responseBody)
+ {
+ parse_str($responseBody, $data);
+
+ if (null === $data || !is_array($data)) {
+ throw new TokenResponseException('Unable to parse response.');
+ } elseif (isset($data['error'])) {
+ throw new TokenResponseException('Error in retrieving token: "' . $data['error'] . '"');
+ }
+
+ $token = new StdOAuth1Token();
+
+ $token->setRequestToken($data['oauth_token']);
+ $token->setRequestTokenSecret($data['oauth_token_secret']);
+ $token->setAccessToken($data['oauth_token']);
+ $token->setAccessTokenSecret($data['oauth_token_secret']);
+
+ $token->setEndOfLife(StdOAuth1Token::EOL_NEVER_EXPIRES);
+ unset($data['oauth_token'], $data['oauth_token_secret']);
+ $token->setExtraParams($data);
+
+ return $token;
+ }
+}
diff --git a/vendor/lusitanian/oauth/src/OAuth/OAuth1/Service/Etsy.php b/vendor/lusitanian/oauth/src/OAuth/OAuth1/Service/Etsy.php
new file mode 100644
index 00000000..30dc331c
--- /dev/null
+++ b/vendor/lusitanian/oauth/src/OAuth/OAuth1/Service/Etsy.php
@@ -0,0 +1,132 @@
+baseApiUri = new Uri('https://openapi.etsy.com/v2/');
+ }
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function getRequestTokenEndpoint()
+ {
+ $uri = new Uri($this->baseApiUri . 'oauth/request_token');
+ $scopes = $this->getScopes();
+
+ if (count($scopes)) {
+ $uri->setQuery('scope=' . implode('%20', $scopes));
+ }
+
+ return $uri;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function getAuthorizationEndpoint()
+ {
+ return new Uri($this->baseApiUri);
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function getAccessTokenEndpoint()
+ {
+ return new Uri($this->baseApiUri . 'oauth/access_token');
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ protected function parseRequestTokenResponse($responseBody)
+ {
+ parse_str($responseBody, $data);
+
+ if (null === $data || !is_array($data)) {
+ throw new TokenResponseException('Unable to parse response.');
+ } elseif (!isset($data['oauth_callback_confirmed']) || $data['oauth_callback_confirmed'] !== 'true') {
+ throw new TokenResponseException('Error in retrieving token.');
+ }
+
+ return $this->parseAccessTokenResponse($responseBody);
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ protected function parseAccessTokenResponse($responseBody)
+ {
+ parse_str($responseBody, $data);
+
+ if (null === $data || !is_array($data)) {
+ throw new TokenResponseException('Unable to parse response.');
+ } elseif (isset($data['error'])) {
+ throw new TokenResponseException('Error in retrieving token: "' . $data['error'] . '"');
+ }
+
+ $token = new StdOAuth1Token();
+
+ $token->setRequestToken($data['oauth_token']);
+ $token->setRequestTokenSecret($data['oauth_token_secret']);
+ $token->setAccessToken($data['oauth_token']);
+ $token->setAccessTokenSecret($data['oauth_token_secret']);
+
+ $token->setEndOfLife(StdOAuth1Token::EOL_NEVER_EXPIRES);
+ unset($data['oauth_token'], $data['oauth_token_secret']);
+ $token->setExtraParams($data);
+
+ return $token;
+ }
+
+ /**
+ * Set the scopes for permissions
+ * @see https://www.etsy.com/developers/documentation/getting_started/oauth#section_permission_scopes
+ * @param array $scopes
+ *
+ * @return $this
+ */
+ public function setScopes(array $scopes)
+ {
+ if (!is_array($scopes)) {
+ $scopes = array();
+ }
+
+ $this->scopes = $scopes;
+ return $this;
+ }
+
+ /**
+ * Return the defined scopes
+ * @return array
+ */
+ public function getScopes()
+ {
+ return $this->scopes;
+ }
+}
diff --git a/vendor/lusitanian/oauth/src/OAuth/OAuth1/Service/FitBit.php b/vendor/lusitanian/oauth/src/OAuth/OAuth1/Service/FitBit.php
new file mode 100644
index 00000000..78032d75
--- /dev/null
+++ b/vendor/lusitanian/oauth/src/OAuth/OAuth1/Service/FitBit.php
@@ -0,0 +1,96 @@
+baseApiUri = new Uri('https://api.fitbit.com/1/');
+ }
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function getRequestTokenEndpoint()
+ {
+ return new Uri('https://api.fitbit.com/oauth/request_token');
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function getAuthorizationEndpoint()
+ {
+ return new Uri('https://www.fitbit.com/oauth/authorize');
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function getAccessTokenEndpoint()
+ {
+ return new Uri('https://api.fitbit.com/oauth/access_token');
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ protected function parseRequestTokenResponse($responseBody)
+ {
+ parse_str($responseBody, $data);
+
+ if (null === $data || !is_array($data)) {
+ throw new TokenResponseException('Unable to parse response.');
+ } elseif (!isset($data['oauth_callback_confirmed']) || $data['oauth_callback_confirmed'] !== 'true') {
+ throw new TokenResponseException('Error in retrieving token.');
+ }
+
+ return $this->parseAccessTokenResponse($responseBody);
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ protected function parseAccessTokenResponse($responseBody)
+ {
+ parse_str($responseBody, $data);
+
+ if (null === $data || !is_array($data)) {
+ throw new TokenResponseException('Unable to parse response.');
+ } elseif (isset($data['error'])) {
+ throw new TokenResponseException('Error in retrieving token: "' . $data['error'] . '"');
+ }
+
+ $token = new StdOAuth1Token();
+
+ $token->setRequestToken($data['oauth_token']);
+ $token->setRequestTokenSecret($data['oauth_token_secret']);
+ $token->setAccessToken($data['oauth_token']);
+ $token->setAccessTokenSecret($data['oauth_token_secret']);
+
+ $token->setEndOfLife(StdOAuth1Token::EOL_NEVER_EXPIRES);
+ unset($data['oauth_token'], $data['oauth_token_secret']);
+ $token->setExtraParams($data);
+
+ return $token;
+ }
+}
diff --git a/vendor/lusitanian/oauth/src/OAuth/OAuth1/Service/Flickr.php b/vendor/lusitanian/oauth/src/OAuth/OAuth1/Service/Flickr.php
new file mode 100644
index 00000000..f06d282a
--- /dev/null
+++ b/vendor/lusitanian/oauth/src/OAuth/OAuth1/Service/Flickr.php
@@ -0,0 +1,91 @@
+baseApiUri = new Uri('https://api.flickr.com/services/rest/');
+ }
+ }
+
+ public function getRequestTokenEndpoint()
+ {
+ return new Uri('https://www.flickr.com/services/oauth/request_token');
+ }
+
+ public function getAuthorizationEndpoint()
+ {
+ return new Uri('https://www.flickr.com/services/oauth/authorize');
+ }
+
+ public function getAccessTokenEndpoint()
+ {
+ return new Uri('https://www.flickr.com/services/oauth/access_token');
+ }
+
+ protected function parseRequestTokenResponse($responseBody)
+ {
+ parse_str($responseBody, $data);
+ if (null === $data || !is_array($data)) {
+ throw new TokenResponseException('Unable to parse response.');
+ } elseif (!isset($data['oauth_callback_confirmed']) || $data['oauth_callback_confirmed'] != 'true') {
+ throw new TokenResponseException('Error in retrieving token.');
+ }
+ return $this->parseAccessTokenResponse($responseBody);
+ }
+
+ protected function parseAccessTokenResponse($responseBody)
+ {
+ parse_str($responseBody, $data);
+ if ($data === null || !is_array($data)) {
+ throw new TokenResponseException('Unable to parse response.');
+ } elseif (isset($data['error'])) {
+ throw new TokenResponseException('Error in retrieving token: "' . $data['error'] . '"');
+ }
+
+ $token = new StdOAuth1Token();
+ $token->setRequestToken($data['oauth_token']);
+ $token->setRequestTokenSecret($data['oauth_token_secret']);
+ $token->setAccessToken($data['oauth_token']);
+ $token->setAccessTokenSecret($data['oauth_token_secret']);
+ $token->setEndOfLife(StdOAuth1Token::EOL_NEVER_EXPIRES);
+ unset($data['oauth_token'], $data['oauth_token_secret']);
+ $token->setExtraParams($data);
+
+ return $token;
+ }
+
+ public function request($path, $method = 'GET', $body = null, array $extraHeaders = array())
+ {
+ $uri = $this->determineRequestUriFromPath('/', $this->baseApiUri);
+ $uri->addToQuery('method', $path);
+
+ $token = $this->storage->retrieveAccessToken($this->service());
+ $extraHeaders = array_merge($this->getExtraApiHeaders(), $extraHeaders);
+ $authorizationHeader = array(
+ 'Authorization' => $this->buildAuthorizationHeaderForAPIRequest($method, $uri, $token, $body)
+ );
+ $headers = array_merge($authorizationHeader, $extraHeaders);
+
+ return $this->httpClient->retrieveResponse($uri, $body, $headers, $method);
+ }
+}
diff --git a/vendor/lusitanian/oauth/src/OAuth/OAuth1/Service/ScoopIt.php b/vendor/lusitanian/oauth/src/OAuth/OAuth1/Service/ScoopIt.php
new file mode 100644
index 00000000..28bd250b
--- /dev/null
+++ b/vendor/lusitanian/oauth/src/OAuth/OAuth1/Service/ScoopIt.php
@@ -0,0 +1,96 @@
+baseApiUri = new Uri('https://www.scoop.it/api/1/');
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public function getRequestTokenEndpoint()
+ {
+ return new Uri('https://www.scoop.it/oauth/request');
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function getAuthorizationEndpoint()
+ {
+ return new Uri('https://www.scoop.it/oauth/authorize');
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function getAccessTokenEndpoint()
+ {
+ return new Uri('https://www.scoop.it/oauth/access');
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ protected function parseRequestTokenResponse($responseBody)
+ {
+ parse_str($responseBody, $data);
+
+ if (null === $data || !is_array($data)) {
+ throw new TokenResponseException('Unable to parse response.');
+ } elseif (!isset($data['oauth_callback_confirmed']) || $data['oauth_callback_confirmed'] !== 'true') {
+ throw new TokenResponseException('Error in retrieving token.');
+ }
+
+ return $this->parseAccessTokenResponse($responseBody);
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ protected function parseAccessTokenResponse($responseBody)
+ {
+ parse_str($responseBody, $data);
+
+ if (null === $data || !is_array($data)) {
+ throw new TokenResponseException('Unable to parse response.');
+ } elseif (isset($data['error'])) {
+ throw new TokenResponseException('Error in retrieving token: "' . $data['error'] . '"');
+ }
+
+ $token = new StdOAuth1Token();
+
+ $token->setRequestToken($data['oauth_token']);
+ $token->setRequestTokenSecret($data['oauth_token_secret']);
+ $token->setAccessToken($data['oauth_token']);
+ $token->setAccessTokenSecret($data['oauth_token_secret']);
+
+ $token->setEndOfLife(StdOAuth1Token::EOL_NEVER_EXPIRES);
+ unset($data['oauth_token'], $data['oauth_token_secret']);
+ $token->setExtraParams($data);
+
+ return $token;
+ }
+}
diff --git a/vendor/lusitanian/oauth/src/OAuth/OAuth1/Service/ServiceInterface.php b/vendor/lusitanian/oauth/src/OAuth/OAuth1/Service/ServiceInterface.php
new file mode 100644
index 00000000..3f91fbf2
--- /dev/null
+++ b/vendor/lusitanian/oauth/src/OAuth/OAuth1/Service/ServiceInterface.php
@@ -0,0 +1,45 @@
+baseApiUri = new Uri('https://api.tumblr.com/v2/');
+ }
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function getRequestTokenEndpoint()
+ {
+ return new Uri('https://www.tumblr.com/oauth/request_token');
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function getAuthorizationEndpoint()
+ {
+ return new Uri('https://www.tumblr.com/oauth/authorize');
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function getAccessTokenEndpoint()
+ {
+ return new Uri('https://www.tumblr.com/oauth/access_token');
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ protected function parseRequestTokenResponse($responseBody)
+ {
+ parse_str($responseBody, $data);
+
+ if (null === $data || !is_array($data)) {
+ throw new TokenResponseException('Unable to parse response.');
+ } elseif (!isset($data['oauth_callback_confirmed']) || $data['oauth_callback_confirmed'] !== 'true') {
+ throw new TokenResponseException('Error in retrieving token.');
+ }
+
+ return $this->parseAccessTokenResponse($responseBody);
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ protected function parseAccessTokenResponse($responseBody)
+ {
+ parse_str($responseBody, $data);
+
+ if (null === $data || !is_array($data)) {
+ throw new TokenResponseException('Unable to parse response.');
+ } elseif (isset($data['error'])) {
+ throw new TokenResponseException('Error in retrieving token: "' . $data['error'] . '"');
+ }
+
+ $token = new StdOAuth1Token();
+
+ $token->setRequestToken($data['oauth_token']);
+ $token->setRequestTokenSecret($data['oauth_token_secret']);
+ $token->setAccessToken($data['oauth_token']);
+ $token->setAccessTokenSecret($data['oauth_token_secret']);
+
+ $token->setEndOfLife(StdOAuth1Token::EOL_NEVER_EXPIRES);
+ unset($data['oauth_token'], $data['oauth_token_secret']);
+ $token->setExtraParams($data);
+
+ return $token;
+ }
+}
diff --git a/vendor/lusitanian/oauth/src/OAuth/OAuth1/Service/Twitter.php b/vendor/lusitanian/oauth/src/OAuth/OAuth1/Service/Twitter.php
new file mode 100644
index 00000000..f46c34e4
--- /dev/null
+++ b/vendor/lusitanian/oauth/src/OAuth/OAuth1/Service/Twitter.php
@@ -0,0 +1,121 @@
+baseApiUri = new Uri('https://api.twitter.com/1.1/');
+ }
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function getRequestTokenEndpoint()
+ {
+ return new Uri('https://api.twitter.com/oauth/request_token');
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function getAuthorizationEndpoint()
+ {
+ if ($this->authorizationEndpoint != self::ENDPOINT_AUTHENTICATE
+ && $this->authorizationEndpoint != self::ENDPOINT_AUTHORIZE) {
+ $this->authorizationEndpoint = self::ENDPOINT_AUTHENTICATE;
+ }
+ return new Uri($this->authorizationEndpoint);
+ }
+
+ /**
+ * @param string $authorizationEndpoint
+ *
+ * @throws Exception
+ */
+ public function setAuthorizationEndpoint($endpoint)
+ {
+ if ($endpoint != self::ENDPOINT_AUTHENTICATE && $endpoint != self::ENDPOINT_AUTHORIZE) {
+ throw new Exception(
+ sprintf("'%s' is not a correct Twitter authorization endpoint.", $endpoint)
+ );
+ }
+ $this->authorizationEndpoint = $endpoint;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function getAccessTokenEndpoint()
+ {
+ return new Uri('https://api.twitter.com/oauth/access_token');
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ protected function parseRequestTokenResponse($responseBody)
+ {
+ parse_str($responseBody, $data);
+
+ if (null === $data || !is_array($data)) {
+ throw new TokenResponseException('Unable to parse response.');
+ } elseif (!isset($data['oauth_callback_confirmed']) || $data['oauth_callback_confirmed'] !== 'true') {
+ throw new TokenResponseException('Error in retrieving token.');
+ }
+
+ return $this->parseAccessTokenResponse($responseBody);
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ protected function parseAccessTokenResponse($responseBody)
+ {
+ parse_str($responseBody, $data);
+
+ if (null === $data || !is_array($data)) {
+ throw new TokenResponseException('Unable to parse response.');
+ } elseif (isset($data['error'])) {
+ throw new TokenResponseException('Error in retrieving token: "' . $data['error'] . '"');
+ }
+
+ $token = new StdOAuth1Token();
+
+ $token->setRequestToken($data['oauth_token']);
+ $token->setRequestTokenSecret($data['oauth_token_secret']);
+ $token->setAccessToken($data['oauth_token']);
+ $token->setAccessTokenSecret($data['oauth_token_secret']);
+
+ $token->setEndOfLife(StdOAuth1Token::EOL_NEVER_EXPIRES);
+ unset($data['oauth_token'], $data['oauth_token_secret']);
+ $token->setExtraParams($data);
+
+ return $token;
+ }
+}
diff --git a/vendor/lusitanian/oauth/src/OAuth/OAuth1/Service/Xing.php b/vendor/lusitanian/oauth/src/OAuth/OAuth1/Service/Xing.php
new file mode 100644
index 00000000..03e3357f
--- /dev/null
+++ b/vendor/lusitanian/oauth/src/OAuth/OAuth1/Service/Xing.php
@@ -0,0 +1,96 @@
+baseApiUri = new Uri('https://api.xing.com/v1/');
+ }
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function getAuthorizationEndpoint()
+ {
+ return new Uri('https://api.xing.com/v1/authorize');
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function getAccessTokenEndpoint()
+ {
+ return new Uri('https://api.xing.com/v1/access_token');
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function getRequestTokenEndpoint()
+ {
+ return new Uri('https://api.xing.com/v1/request_token');
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ protected function parseRequestTokenResponse($responseBody)
+ {
+ parse_str($responseBody, $data);
+
+ if (null === $data || !is_array($data)) {
+ throw new TokenResponseException('Unable to parse response.');
+ } elseif (!isset($data['oauth_callback_confirmed']) || $data['oauth_callback_confirmed'] !== 'true') {
+ throw new TokenResponseException('Error in retrieving token.');
+ }
+
+ return $this->parseAccessTokenResponse($responseBody);
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ protected function parseAccessTokenResponse($responseBody)
+ {
+ parse_str($responseBody, $data);
+
+ if (null === $data || !is_array($data)) {
+ throw new TokenResponseException('Unable to parse response.');
+ } elseif (isset($data['error'])) {
+ throw new TokenResponseException('Error in retrieving token: "' . $data['error'] . '"');
+ }
+
+ $token = new StdOAuth1Token();
+
+ $token->setRequestToken($data['oauth_token']);
+ $token->setRequestTokenSecret($data['oauth_token_secret']);
+ $token->setAccessToken($data['oauth_token']);
+ $token->setAccessTokenSecret($data['oauth_token_secret']);
+
+ $token->setEndOfLife(StdOAuth1Token::EOL_NEVER_EXPIRES);
+ unset($data['oauth_token'], $data['oauth_token_secret']);
+ $token->setExtraParams($data);
+
+ return $token;
+ }
+}
diff --git a/vendor/lusitanian/oauth/src/OAuth/OAuth1/Service/Yahoo.php b/vendor/lusitanian/oauth/src/OAuth/OAuth1/Service/Yahoo.php
new file mode 100644
index 00000000..cff291d4
--- /dev/null
+++ b/vendor/lusitanian/oauth/src/OAuth/OAuth1/Service/Yahoo.php
@@ -0,0 +1,96 @@
+baseApiUri = new Uri('https://social.yahooapis.com/v1/');
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public function getRequestTokenEndpoint()
+ {
+ return new Uri('https://api.login.yahoo.com/oauth/v2/get_request_token');
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function getAuthorizationEndpoint()
+ {
+ return new Uri('https://api.login.yahoo.com/oauth/v2/request_auth');
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function getAccessTokenEndpoint()
+ {
+ return new Uri('https://api.login.yahoo.com/oauth/v2/get_token');
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ protected function parseRequestTokenResponse($responseBody)
+ {
+ parse_str($responseBody, $data);
+
+ if (null === $data || !is_array($data)) {
+ throw new TokenResponseException('Unable to parse response.');
+ } elseif (!isset($data['oauth_callback_confirmed']) || $data['oauth_callback_confirmed'] !== 'true') {
+ throw new TokenResponseException('Error in retrieving token.');
+ }
+
+ return $this->parseAccessTokenResponse($responseBody);
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ protected function parseAccessTokenResponse($responseBody)
+ {
+ parse_str($responseBody, $data);
+
+ if (null === $data || !is_array($data)) {
+ throw new TokenResponseException('Unable to parse response.');
+ } elseif (isset($data['error'])) {
+ throw new TokenResponseException('Error in retrieving token: "' . $data['error'] . '"');
+ }
+
+ $token = new StdOAuth1Token();
+
+ $token->setRequestToken($data['oauth_token']);
+ $token->setRequestTokenSecret($data['oauth_token_secret']);
+ $token->setAccessToken($data['oauth_token']);
+ $token->setAccessTokenSecret($data['oauth_token_secret']);
+
+ $token->setEndOfLife(StdOAuth1Token::EOL_NEVER_EXPIRES);
+ unset($data['oauth_token'], $data['oauth_token_secret']);
+ $token->setExtraParams($data);
+
+ return $token;
+ }
+}
diff --git a/vendor/lusitanian/oauth/src/OAuth/OAuth1/Signature/Exception/UnsupportedHashAlgorithmException.php b/vendor/lusitanian/oauth/src/OAuth/OAuth1/Signature/Exception/UnsupportedHashAlgorithmException.php
new file mode 100644
index 00000000..44c36ce7
--- /dev/null
+++ b/vendor/lusitanian/oauth/src/OAuth/OAuth1/Signature/Exception/UnsupportedHashAlgorithmException.php
@@ -0,0 +1,12 @@
+credentials = $credentials;
+ }
+
+ /**
+ * @param string $algorithm
+ */
+ public function setHashingAlgorithm($algorithm)
+ {
+ $this->algorithm = $algorithm;
+ }
+
+ /**
+ * @param string $token
+ */
+ public function setTokenSecret($token)
+ {
+ $this->tokenSecret = $token;
+ }
+
+ /**
+ * @param UriInterface $uri
+ * @param array $params
+ * @param string $method
+ *
+ * @return string
+ */
+ public function getSignature(UriInterface $uri, array $params, $method = 'POST')
+ {
+ parse_str($uri->getQuery(), $queryStringData);
+
+ foreach (array_merge($queryStringData, $params) as $key => $value) {
+ $signatureData[rawurlencode($key)] = rawurlencode($value);
+ }
+
+ ksort($signatureData);
+
+ // determine base uri
+ $baseUri = $uri->getScheme() . '://' . $uri->getRawAuthority();
+
+ if ('/' === $uri->getPath()) {
+ $baseUri .= $uri->hasExplicitTrailingHostSlash() ? '/' : '';
+ } else {
+ $baseUri .= $uri->getPath();
+ }
+
+ $baseString = strtoupper($method) . '&';
+ $baseString .= rawurlencode($baseUri) . '&';
+ $baseString .= rawurlencode($this->buildSignatureDataString($signatureData));
+
+ return base64_encode($this->hash($baseString));
+ }
+
+ /**
+ * @param array $signatureData
+ *
+ * @return string
+ */
+ protected function buildSignatureDataString(array $signatureData)
+ {
+ $signatureString = '';
+ $delimiter = '';
+ foreach ($signatureData as $key => $value) {
+ $signatureString .= $delimiter . $key . '=' . $value;
+
+ $delimiter = '&';
+ }
+
+ return $signatureString;
+ }
+
+ /**
+ * @return string
+ */
+ protected function getSigningKey()
+ {
+ $signingKey = rawurlencode($this->credentials->getConsumerSecret()) . '&';
+ if ($this->tokenSecret !== null) {
+ $signingKey .= rawurlencode($this->tokenSecret);
+ }
+
+ return $signingKey;
+ }
+
+ /**
+ * @param string $data
+ *
+ * @return string
+ *
+ * @throws UnsupportedHashAlgorithmException
+ */
+ protected function hash($data)
+ {
+ switch (strtoupper($this->algorithm)) {
+ case 'HMAC-SHA1':
+ return hash_hmac('sha1', $data, $this->getSigningKey(), true);
+ default:
+ throw new UnsupportedHashAlgorithmException(
+ 'Unsupported hashing algorithm (' . $this->algorithm . ') used.'
+ );
+ }
+ }
+}
diff --git a/vendor/lusitanian/oauth/src/OAuth/OAuth1/Signature/SignatureInterface.php b/vendor/lusitanian/oauth/src/OAuth/OAuth1/Signature/SignatureInterface.php
new file mode 100644
index 00000000..da50ddb6
--- /dev/null
+++ b/vendor/lusitanian/oauth/src/OAuth/OAuth1/Signature/SignatureInterface.php
@@ -0,0 +1,28 @@
+requestToken = $requestToken;
+ }
+
+ /**
+ * @return string
+ */
+ public function getRequestToken()
+ {
+ return $this->requestToken;
+ }
+
+ /**
+ * @param string $requestTokenSecret
+ */
+ public function setRequestTokenSecret($requestTokenSecret)
+ {
+ $this->requestTokenSecret = $requestTokenSecret;
+ }
+
+ /**
+ * @return string
+ */
+ public function getRequestTokenSecret()
+ {
+ return $this->requestTokenSecret;
+ }
+
+ /**
+ * @param string $accessTokenSecret
+ */
+ public function setAccessTokenSecret($accessTokenSecret)
+ {
+ $this->accessTokenSecret = $accessTokenSecret;
+ }
+
+ /**
+ * @return string
+ */
+ public function getAccessTokenSecret()
+ {
+ return $this->accessTokenSecret;
+ }
+}
diff --git a/vendor/lusitanian/oauth/src/OAuth/OAuth1/Token/TokenInterface.php b/vendor/lusitanian/oauth/src/OAuth/OAuth1/Token/TokenInterface.php
new file mode 100644
index 00000000..0bc3f739
--- /dev/null
+++ b/vendor/lusitanian/oauth/src/OAuth/OAuth1/Token/TokenInterface.php
@@ -0,0 +1,41 @@
+stateParameterInAuthUrl = $stateParameterInAutUrl;
+
+ foreach ($scopes as $scope) {
+ if (!$this->isValidScope($scope)) {
+ throw new InvalidScopeException('Scope ' . $scope . ' is not valid for service ' . get_class($this));
+ }
+ }
+
+ $this->scopes = $scopes;
+
+ $this->baseApiUri = $baseApiUri;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function getAuthorizationUri(array $additionalParameters = array())
+ {
+ $parameters = array_merge(
+ $additionalParameters,
+ array(
+ 'type' => 'web_server',
+ 'client_id' => $this->credentials->getConsumerId(),
+ 'redirect_uri' => $this->credentials->getCallbackUrl(),
+ 'response_type' => 'code',
+ )
+ );
+
+ $parameters['scope'] = implode(' ', $this->scopes);
+
+ if ($this->needsStateParameterInAuthUrl()) {
+ if (!isset($parameters['state'])) {
+ $parameters['state'] = $this->generateAuthorizationState();
+ }
+ $this->storeAuthorizationState($parameters['state']);
+ }
+
+ // Build the url
+ $url = clone $this->getAuthorizationEndpoint();
+ foreach ($parameters as $key => $val) {
+ $url->addToQuery($key, $val);
+ }
+
+ return $url;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function requestAccessToken($code, $state = null)
+ {
+ if (null !== $state) {
+ $this->validateAuthorizationState($state);
+ }
+
+ $bodyParams = array(
+ 'code' => $code,
+ 'client_id' => $this->credentials->getConsumerId(),
+ 'client_secret' => $this->credentials->getConsumerSecret(),
+ 'redirect_uri' => $this->credentials->getCallbackUrl(),
+ 'grant_type' => 'authorization_code',
+ );
+
+ $responseBody = $this->httpClient->retrieveResponse(
+ $this->getAccessTokenEndpoint(),
+ $bodyParams,
+ $this->getExtraOAuthHeaders()
+ );
+
+ $token = $this->parseAccessTokenResponse($responseBody);
+ $this->storage->storeAccessToken($this->service(), $token);
+
+ return $token;
+ }
+
+ /**
+ * Sends an authenticated API request to the path provided.
+ * If the path provided is not an absolute URI, the base API Uri (must be passed into constructor) will be used.
+ *
+ * @param string|UriInterface $path
+ * @param string $method HTTP method
+ * @param array $body Request body if applicable.
+ * @param array $extraHeaders Extra headers if applicable. These will override service-specific
+ * any defaults.
+ *
+ * @return string
+ *
+ * @throws ExpiredTokenException
+ * @throws Exception
+ */
+ public function request($path, $method = 'GET', $body = null, array $extraHeaders = array())
+ {
+ $uri = $this->determineRequestUriFromPath($path, $this->baseApiUri);
+ $token = $this->storage->retrieveAccessToken($this->service());
+
+ if ($token->getEndOfLife() !== TokenInterface::EOL_NEVER_EXPIRES
+ && $token->getEndOfLife() !== TokenInterface::EOL_UNKNOWN
+ && time() > $token->getEndOfLife()
+ ) {
+ throw new ExpiredTokenException(
+ sprintf(
+ 'Token expired on %s at %s',
+ date('m/d/Y', $token->getEndOfLife()),
+ date('h:i:s A', $token->getEndOfLife())
+ )
+ );
+ }
+
+ // add the token where it may be needed
+ if (static::AUTHORIZATION_METHOD_HEADER_OAUTH === $this->getAuthorizationMethod()) {
+ $extraHeaders = array_merge(array('Authorization' => 'OAuth ' . $token->getAccessToken()), $extraHeaders);
+ } elseif (static::AUTHORIZATION_METHOD_QUERY_STRING === $this->getAuthorizationMethod()) {
+ $uri->addToQuery('access_token', $token->getAccessToken());
+ } elseif (static::AUTHORIZATION_METHOD_QUERY_STRING_V2 === $this->getAuthorizationMethod()) {
+ $uri->addToQuery('oauth2_access_token', $token->getAccessToken());
+ } elseif (static::AUTHORIZATION_METHOD_QUERY_STRING_V3 === $this->getAuthorizationMethod()) {
+ $uri->addToQuery('apikey', $token->getAccessToken());
+ } elseif (static::AUTHORIZATION_METHOD_HEADER_BEARER === $this->getAuthorizationMethod()) {
+ $extraHeaders = array_merge(array('Authorization' => 'Bearer ' . $token->getAccessToken()), $extraHeaders);
+ }
+
+ $extraHeaders = array_merge($this->getExtraApiHeaders(), $extraHeaders);
+
+ return $this->httpClient->retrieveResponse($uri, $body, $extraHeaders, $method);
+ }
+
+ /**
+ * Accessor to the storage adapter to be able to retrieve tokens
+ *
+ * @return TokenStorageInterface
+ */
+ public function getStorage()
+ {
+ return $this->storage;
+ }
+
+ /**
+ * Refreshes an OAuth2 access token.
+ *
+ * @param TokenInterface $token
+ *
+ * @return TokenInterface $token
+ *
+ * @throws MissingRefreshTokenException
+ */
+ public function refreshAccessToken(TokenInterface $token)
+ {
+ $refreshToken = $token->getRefreshToken();
+
+ if (empty($refreshToken)) {
+ throw new MissingRefreshTokenException();
+ }
+
+ $parameters = array(
+ 'grant_type' => 'refresh_token',
+ 'type' => 'web_server',
+ 'client_id' => $this->credentials->getConsumerId(),
+ 'client_secret' => $this->credentials->getConsumerSecret(),
+ 'refresh_token' => $refreshToken,
+ );
+
+ $responseBody = $this->httpClient->retrieveResponse(
+ $this->getAccessTokenEndpoint(),
+ $parameters,
+ $this->getExtraOAuthHeaders()
+ );
+ $token = $this->parseAccessTokenResponse($responseBody);
+ $this->storage->storeAccessToken($this->service(), $token);
+
+ return $token;
+ }
+
+ /**
+ * Return whether or not the passed scope value is valid.
+ *
+ * @param string $scope
+ *
+ * @return bool
+ */
+ public function isValidScope($scope)
+ {
+ $reflectionClass = new \ReflectionClass(get_class($this));
+
+ return in_array($scope, $reflectionClass->getConstants(), true);
+ }
+
+ /**
+ * Check if the given service need to generate a unique state token to build the authorization url
+ *
+ * @return bool
+ */
+ public function needsStateParameterInAuthUrl()
+ {
+ return $this->stateParameterInAuthUrl;
+ }
+
+ /**
+ * Validates the authorization state against a given one
+ *
+ * @param string $state
+ * @throws InvalidAuthorizationStateException
+ */
+ protected function validateAuthorizationState($state)
+ {
+ if ($this->retrieveAuthorizationState() !== $state) {
+ throw new InvalidAuthorizationStateException();
+ }
+ }
+
+ /**
+ * Generates a random string to be used as state
+ *
+ * @return string
+ */
+ protected function generateAuthorizationState()
+ {
+ return md5(rand());
+ }
+
+ /**
+ * Retrieves the authorization state for the current service
+ *
+ * @return string
+ */
+ protected function retrieveAuthorizationState()
+ {
+ return $this->storage->retrieveAuthorizationState($this->service());
+ }
+
+ /**
+ * Stores a given authorization state into the storage
+ *
+ * @param string $state
+ */
+ protected function storeAuthorizationState($state)
+ {
+ $this->storage->storeAuthorizationState($this->service(), $state);
+ }
+
+ /**
+ * Return any additional headers always needed for this service implementation's OAuth calls.
+ *
+ * @return array
+ */
+ protected function getExtraOAuthHeaders()
+ {
+ return array();
+ }
+
+ /**
+ * Return any additional headers always needed for this service implementation's API calls.
+ *
+ * @return array
+ */
+ protected function getExtraApiHeaders()
+ {
+ return array();
+ }
+
+ /**
+ * Parses the access token response and returns a TokenInterface.
+ *
+ * @abstract
+ *
+ * @param string $responseBody
+ *
+ * @return TokenInterface
+ *
+ * @throws TokenResponseException
+ */
+ abstract protected function parseAccessTokenResponse($responseBody);
+
+ /**
+ * Returns a class constant from ServiceInterface defining the authorization method used for the API
+ * Header is the sane default.
+ *
+ * @return int
+ */
+ protected function getAuthorizationMethod()
+ {
+ return static::AUTHORIZATION_METHOD_HEADER_OAUTH;
+ }
+}
diff --git a/vendor/lusitanian/oauth/src/OAuth/OAuth2/Service/Amazon.php b/vendor/lusitanian/oauth/src/OAuth/OAuth2/Service/Amazon.php
new file mode 100644
index 00000000..035d1a55
--- /dev/null
+++ b/vendor/lusitanian/oauth/src/OAuth/OAuth2/Service/Amazon.php
@@ -0,0 +1,97 @@
+
+ * @link https://images-na.ssl-images-amazon.com/images/G/01/lwa/dev/docs/website-developer-guide._TTH_.pdf
+ */
+class Amazon extends AbstractService
+{
+ /**
+ * Defined scopes
+ * @link https://images-na.ssl-images-amazon.com/images/G/01/lwa/dev/docs/website-developer-guide._TTH_.pdf
+ */
+ const SCOPE_PROFILE = 'profile';
+ const SCOPE_POSTAL_CODE = 'postal_code';
+
+ public function __construct(
+ CredentialsInterface $credentials,
+ ClientInterface $httpClient,
+ TokenStorageInterface $storage,
+ $scopes = array(),
+ UriInterface $baseApiUri = null
+ ) {
+ parent::__construct($credentials, $httpClient, $storage, $scopes, $baseApiUri);
+
+ if (null === $baseApiUri) {
+ $this->baseApiUri = new Uri('https://api.amazon.com/');
+ }
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function getAuthorizationEndpoint()
+ {
+ return new Uri('https://www.amazon.com/ap/oa');
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function getAccessTokenEndpoint()
+ {
+ return new Uri('https://www.amazon.com/ap/oatoken');
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ protected function getAuthorizationMethod()
+ {
+ return static::AUTHORIZATION_METHOD_HEADER_BEARER;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ protected function parseAccessTokenResponse($responseBody)
+ {
+ $data = json_decode($responseBody, true);
+
+ if (null === $data || !is_array($data)) {
+ throw new TokenResponseException('Unable to parse response.');
+ } elseif (isset($data['error_description'])) {
+ throw new TokenResponseException('Error in retrieving token: "' . $data['error_description'] . '"');
+ } elseif (isset($data['error'])) {
+ throw new TokenResponseException('Error in retrieving token: "' . $data['error'] . '"');
+ }
+
+ $token = new StdOAuth2Token();
+ $token->setAccessToken($data['access_token']);
+ $token->setLifeTime($data['expires_in']);
+
+ if (isset($data['refresh_token'])) {
+ $token->setRefreshToken($data['refresh_token']);
+ unset($data['refresh_token']);
+ }
+
+ unset($data['access_token']);
+ unset($data['expires_in']);
+
+ $token->setExtraParams($data);
+
+ return $token;
+ }
+}
diff --git a/vendor/lusitanian/oauth/src/OAuth/OAuth2/Service/Bitly.php b/vendor/lusitanian/oauth/src/OAuth/OAuth2/Service/Bitly.php
new file mode 100644
index 00000000..e01cbc42
--- /dev/null
+++ b/vendor/lusitanian/oauth/src/OAuth/OAuth2/Service/Bitly.php
@@ -0,0 +1,111 @@
+baseApiUri = new Uri('https://api-ssl.bitly.com/v3/');
+ }
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function getAuthorizationEndpoint()
+ {
+ return new Uri('https://bitly.com/oauth/authorize');
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function getAccessTokenEndpoint()
+ {
+ return new Uri('https://api-ssl.bitly.com/oauth/access_token');
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ protected function getAuthorizationMethod()
+ {
+ return static::AUTHORIZATION_METHOD_QUERY_STRING;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ protected function parseAccessTokenResponse($responseBody)
+ {
+ $data = json_decode($responseBody, true);
+
+ if (null === $data || !is_array($data)) {
+ throw new TokenResponseException('Unable to parse response.');
+ } elseif (isset($data['error'])) {
+ throw new TokenResponseException('Error in retrieving token: "' . $data['error'] . '"');
+ }
+
+ $token = new StdOAuth2Token();
+ $token->setAccessToken($data['access_token']);
+ // I'm invincible!!!
+ $token->setEndOfLife(StdOAuth2Token::EOL_NEVER_EXPIRES);
+ unset($data['access_token']);
+
+ $token->setExtraParams($data);
+
+ return $token;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function requestAccessToken($code, $state = null)
+ {
+ if (null !== $state) {
+ $this->validateAuthorizationState($state);
+ }
+
+ $bodyParams = array(
+ 'code' => $code,
+ 'client_id' => $this->credentials->getConsumerId(),
+ 'client_secret' => $this->credentials->getConsumerSecret(),
+ 'redirect_uri' => $this->credentials->getCallbackUrl(),
+ 'grant_type' => 'authorization_code',
+ );
+
+ $responseBody = $this->httpClient->retrieveResponse(
+ $this->getAccessTokenEndpoint(),
+ $bodyParams,
+ $this->getExtraOAuthHeaders()
+ );
+
+ // we can scream what we want that we want bitly to return a json encoded string (format=json), but the
+ // WOAH WATCH YOUR LANGUAGE ;) service doesn't seem to like screaming, hence we need to manually
+ // parse the result
+ $parsedResult = array();
+ parse_str($responseBody, $parsedResult);
+
+ $token = $this->parseAccessTokenResponse(json_encode($parsedResult));
+ $this->storage->storeAccessToken($this->service(), $token);
+
+ return $token;
+ }
+}
diff --git a/vendor/lusitanian/oauth/src/OAuth/OAuth2/Service/Box.php b/vendor/lusitanian/oauth/src/OAuth/OAuth2/Service/Box.php
new file mode 100644
index 00000000..14696c59
--- /dev/null
+++ b/vendor/lusitanian/oauth/src/OAuth/OAuth2/Service/Box.php
@@ -0,0 +1,88 @@
+
+ * @link https://developers.box.com/oauth/
+ */
+class Box extends AbstractService
+{
+ public function __construct(
+ CredentialsInterface $credentials,
+ ClientInterface $httpClient,
+ TokenStorageInterface $storage,
+ $scopes = array(),
+ UriInterface $baseApiUri = null
+ ) {
+ parent::__construct($credentials, $httpClient, $storage, $scopes, $baseApiUri, true);
+
+ if (null === $baseApiUri) {
+ $this->baseApiUri = new Uri('https://api.box.com/2.0/');
+ }
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function getAuthorizationEndpoint()
+ {
+ return new Uri('https://www.box.com/api/oauth2/authorize');
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function getAccessTokenEndpoint()
+ {
+ return new Uri('https://www.box.com/api/oauth2/token');
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ protected function getAuthorizationMethod()
+ {
+ return static::AUTHORIZATION_METHOD_HEADER_BEARER;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ protected function parseAccessTokenResponse($responseBody)
+ {
+ $data = json_decode($responseBody, true);
+
+ if (null === $data || !is_array($data)) {
+ throw new TokenResponseException('Unable to parse response.');
+ } elseif (isset($data['error'])) {
+ throw new TokenResponseException('Error in retrieving token: "' . $data['error'] . '"');
+ }
+
+ $token = new StdOAuth2Token();
+ $token->setAccessToken($data['access_token']);
+ $token->setLifeTime($data['expires_in']);
+
+ if (isset($data['refresh_token'])) {
+ $token->setRefreshToken($data['refresh_token']);
+ unset($data['refresh_token']);
+ }
+
+ unset($data['access_token']);
+ unset($data['expires_in']);
+
+ $token->setExtraParams($data);
+
+ return $token;
+ }
+}
diff --git a/vendor/lusitanian/oauth/src/OAuth/OAuth2/Service/Buffer.php b/vendor/lusitanian/oauth/src/OAuth/OAuth2/Service/Buffer.php
new file mode 100644
index 00000000..5905678e
--- /dev/null
+++ b/vendor/lusitanian/oauth/src/OAuth/OAuth2/Service/Buffer.php
@@ -0,0 +1,151 @@
+
+ * @link https://bufferapp.com/developers/api
+ */
+class Buffer extends AbstractService
+{
+ public function __construct(
+ CredentialsInterface $credentials,
+ ClientInterface $httpClient,
+ TokenStorageInterface $storage,
+ $scopes = array(),
+ UriInterface $baseApiUri = null
+ ) {
+ parent::__construct($credentials, $httpClient, $storage, $scopes, $baseApiUri);
+ if ($baseApiUri === null) {
+ $this->baseApiUri = new Uri('https://api.bufferapp.com/1/');
+ }
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function getAuthorizationEndpoint()
+ {
+ return new Uri('https://bufferapp.com/oauth2/authorize');
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function getAccessTokenEndpoint()
+ {
+ return new Uri('https://api.bufferapp.com/1/oauth2/token.json');
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ protected function getAuthorizationMethod()
+ {
+ return static::AUTHORIZATION_METHOD_QUERY_STRING;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function getAuthorizationUri(array $additionalParameters = array())
+ {
+ $parameters = array_merge(
+ $additionalParameters,
+ array(
+ 'client_id' => $this->credentials->getConsumerId(),
+ 'redirect_uri' => $this->credentials->getCallbackUrl(),
+ 'response_type' => 'code',
+ )
+ );
+
+ // Build the url
+ $url = clone $this->getAuthorizationEndpoint();
+ foreach ($parameters as $key => $val) {
+ $url->addToQuery($key, $val);
+ }
+
+ return $url;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function requestRequestToken()
+ {
+ $responseBody = $this->httpClient->retrieveResponse(
+ $this->getRequestTokenEndpoint(),
+ array(
+ 'client_key' => $this->credentials->getConsumerId(),
+ 'redirect_uri' => $this->credentials->getCallbackUrl(),
+ 'response_type' => 'code',
+ )
+ );
+
+ $code = $this->parseRequestTokenResponse($responseBody);
+
+ return $code;
+ }
+
+ protected function parseRequestTokenResponse($responseBody)
+ {
+ parse_str($responseBody, $data);
+
+ if (null === $data || !is_array($data)) {
+ throw new TokenResponseException('Unable to parse response.');
+ } elseif (!isset($data['code'])) {
+ throw new TokenResponseException('Error in retrieving code.');
+ }
+ return $data['code'];
+ }
+
+ public function requestAccessToken($code)
+ {
+ $bodyParams = array(
+ 'client_id' => $this->credentials->getConsumerId(),
+ 'client_secret' => $this->credentials->getConsumerSecret(),
+ 'redirect_uri' => $this->credentials->getCallbackUrl(),
+ 'code' => $code,
+ 'grant_type' => 'authorization_code',
+ );
+
+ $responseBody = $this->httpClient->retrieveResponse(
+ $this->getAccessTokenEndpoint(),
+ $bodyParams,
+ $this->getExtraOAuthHeaders()
+ );
+ $token = $this->parseAccessTokenResponse($responseBody);
+ $this->storage->storeAccessToken($this->service(), $token);
+
+ return $token;
+ }
+
+ protected function parseAccessTokenResponse($responseBody)
+ {
+ $data = json_decode($responseBody, true);
+
+ if ($data === null || !is_array($data)) {
+ throw new TokenResponseException('Unable to parse response.');
+ } elseif (isset($data['error'])) {
+ throw new TokenResponseException('Error in retrieving token: "' . $data['error'] . '"');
+ }
+
+ $token = new StdOAuth2Token();
+ $token->setAccessToken($data['access_token']);
+
+ $token->setEndOfLife(StdOAuth2Token::EOL_NEVER_EXPIRES);
+ unset($data['access_token']);
+ $token->setExtraParams($data);
+
+ return $token;
+ }
+}
diff --git a/vendor/lusitanian/oauth/src/OAuth/OAuth2/Service/Dailymotion.php b/vendor/lusitanian/oauth/src/OAuth/OAuth2/Service/Dailymotion.php
new file mode 100644
index 00000000..095a467f
--- /dev/null
+++ b/vendor/lusitanian/oauth/src/OAuth/OAuth2/Service/Dailymotion.php
@@ -0,0 +1,129 @@
+
+ * @link http://www.dailymotion.com/doc/api/authentication.html
+ */
+class Dailymotion extends AbstractService
+{
+ /**
+ * Scopes
+ *
+ * @var string
+ */
+ const SCOPE_EMAIL = 'email',
+ SCOPE_PROFILE = 'userinfo',
+ SCOPE_VIDEOS = 'manage_videos',
+ SCOPE_COMMENTS = 'manage_comments',
+ SCOPE_PLAYLIST = 'manage_playlists',
+ SCOPE_TILES = 'manage_tiles',
+ SCOPE_SUBSCRIPTIONS = 'manage_subscriptions',
+ SCOPE_FRIENDS = 'manage_friends',
+ SCOPE_FAVORITES = 'manage_favorites',
+ SCOPE_GROUPS = 'manage_groups';
+
+ /**
+ * Dialog form factors
+ *
+ * @var string
+ */
+ const DISPLAY_PAGE = 'page',
+ DISPLAY_POPUP = 'popup',
+ DISPLAY_MOBILE = 'mobile';
+
+ /**
+ * {@inheritdoc}
+ */
+ public function __construct(
+ CredentialsInterface $credentials,
+ ClientInterface $httpClient,
+ TokenStorageInterface $storage,
+ $scopes = array(),
+ UriInterface $baseApiUri = null
+ ) {
+ parent::__construct($credentials, $httpClient, $storage, $scopes, $baseApiUri);
+
+ if (null === $baseApiUri) {
+ $this->baseApiUri = new Uri('https://api.dailymotion.com/');
+ }
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function getAuthorizationEndpoint()
+ {
+ return new Uri('https://api.dailymotion.com/oauth/authorize');
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function getAccessTokenEndpoint()
+ {
+ return new Uri('https://api.dailymotion.com/oauth/token');
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ protected function getAuthorizationMethod()
+ {
+ return static::AUTHORIZATION_METHOD_HEADER_OAUTH;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ protected function parseAccessTokenResponse($responseBody)
+ {
+ $data = json_decode($responseBody, true);
+
+ if (null === $data || !is_array($data)) {
+ throw new TokenResponseException('Unable to parse response.');
+ } elseif (isset($data['error_description']) || isset($data['error'])) {
+ throw new TokenResponseException(
+ sprintf(
+ 'Error in retrieving token: "%s"',
+ isset($data['error_description']) ? $data['error_description'] : $data['error']
+ )
+ );
+ }
+
+ $token = new StdOAuth2Token();
+ $token->setAccessToken($data['access_token']);
+ $token->setLifeTime($data['expires_in']);
+
+ if (isset($data['refresh_token'])) {
+ $token->setRefreshToken($data['refresh_token']);
+ unset($data['refresh_token']);
+ }
+
+ unset($data['access_token']);
+ unset($data['expires_in']);
+
+ $token->setExtraParams($data);
+
+ return $token;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ protected function getExtraOAuthHeaders()
+ {
+ return array('Accept' => 'application/json');
+ }
+}
diff --git a/vendor/lusitanian/oauth/src/OAuth/OAuth2/Service/Dropbox.php b/vendor/lusitanian/oauth/src/OAuth/OAuth2/Service/Dropbox.php
new file mode 100644
index 00000000..43ec6c7f
--- /dev/null
+++ b/vendor/lusitanian/oauth/src/OAuth/OAuth2/Service/Dropbox.php
@@ -0,0 +1,111 @@
+
+ * @link https://www.dropbox.com/developers/core/docs
+ */
+class Dropbox extends AbstractService
+{
+ public function __construct(
+ CredentialsInterface $credentials,
+ ClientInterface $httpClient,
+ TokenStorageInterface $storage,
+ $scopes = array(),
+ UriInterface $baseApiUri = null
+ ) {
+ parent::__construct($credentials, $httpClient, $storage, $scopes, $baseApiUri);
+
+ if (null === $baseApiUri) {
+ $this->baseApiUri = new Uri('https://api.dropbox.com/1/');
+ }
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function getAuthorizationUri(array $additionalParameters = array())
+ {
+ $parameters = array_merge(
+ $additionalParameters,
+ array(
+ 'client_id' => $this->credentials->getConsumerId(),
+ 'redirect_uri' => $this->credentials->getCallbackUrl(),
+ 'response_type' => 'code',
+ )
+ );
+
+ $parameters['scope'] = implode(' ', $this->scopes);
+
+ // Build the url
+ $url = clone $this->getAuthorizationEndpoint();
+ foreach ($parameters as $key => $val) {
+ $url->addToQuery($key, $val);
+ }
+
+ return $url;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function getAuthorizationEndpoint()
+ {
+ return new Uri('https://www.dropbox.com/1/oauth2/authorize');
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function getAccessTokenEndpoint()
+ {
+ return new Uri('https://api.dropbox.com/1/oauth2/token');
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ protected function getAuthorizationMethod()
+ {
+ return static::AUTHORIZATION_METHOD_QUERY_STRING;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ protected function parseAccessTokenResponse($responseBody)
+ {
+ $data = json_decode($responseBody, true);
+
+ if (null === $data || !is_array($data)) {
+ throw new TokenResponseException('Unable to parse response.');
+ } elseif (isset($data['error'])) {
+ throw new TokenResponseException('Error in retrieving token: "' . $data['error'] . '"');
+ }
+
+ $token = new StdOAuth2Token();
+ $token->setAccessToken($data['access_token']);
+
+ if (isset($data['refresh_token'])) {
+ $token->setRefreshToken($data['refresh_token']);
+ unset($data['refresh_token']);
+ }
+
+ unset($data['access_token']);
+
+ $token->setExtraParams($data);
+
+ return $token;
+ }
+}
diff --git a/vendor/lusitanian/oauth/src/OAuth/OAuth2/Service/Exception/InvalidAccessTypeException.php b/vendor/lusitanian/oauth/src/OAuth/OAuth2/Service/Exception/InvalidAccessTypeException.php
new file mode 100644
index 00000000..398df2fd
--- /dev/null
+++ b/vendor/lusitanian/oauth/src/OAuth/OAuth2/Service/Exception/InvalidAccessTypeException.php
@@ -0,0 +1,12 @@
+
+ * Released under the MIT license.
+ */
+
+namespace OAuth\OAuth2\Service\Exception;
+
+use OAuth\Common\Exception\Exception;
+
+/**
+ * Exception thrown when a scope provided to a service is invalid.
+ */
+class InvalidScopeException extends Exception
+{
+}
diff --git a/vendor/lusitanian/oauth/src/OAuth/OAuth2/Service/Exception/MissingRefreshTokenException.php b/vendor/lusitanian/oauth/src/OAuth/OAuth2/Service/Exception/MissingRefreshTokenException.php
new file mode 100644
index 00000000..21eece6a
--- /dev/null
+++ b/vendor/lusitanian/oauth/src/OAuth/OAuth2/Service/Exception/MissingRefreshTokenException.php
@@ -0,0 +1,17 @@
+
+ * Released under the MIT license.
+ */
+
+namespace OAuth\OAuth2\Service\Exception;
+
+use OAuth\Common\Exception\Exception;
+
+/**
+ * Exception thrown when service is requested to refresh the access token but no refresh token can be found.
+ */
+class MissingRefreshTokenException extends Exception
+{
+}
diff --git a/vendor/lusitanian/oauth/src/OAuth/OAuth2/Service/Facebook.php b/vendor/lusitanian/oauth/src/OAuth/OAuth2/Service/Facebook.php
new file mode 100644
index 00000000..80b25c05
--- /dev/null
+++ b/vendor/lusitanian/oauth/src/OAuth/OAuth2/Service/Facebook.php
@@ -0,0 +1,193 @@
+baseApiUri = new Uri('https://graph.facebook.com/');
+ }
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function getAuthorizationEndpoint()
+ {
+ return new Uri('https://www.facebook.com/dialog/oauth');
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function getAccessTokenEndpoint()
+ {
+ return new Uri('https://graph.facebook.com/oauth/access_token');
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ protected function parseAccessTokenResponse($responseBody)
+ {
+ // Facebook gives us a query string ... Oh wait. JSON is too simple, understand ?
+ parse_str($responseBody, $data);
+
+ if (null === $data || !is_array($data)) {
+ throw new TokenResponseException('Unable to parse response.');
+ } elseif (isset($data['error'])) {
+ throw new TokenResponseException('Error in retrieving token: "' . $data['error'] . '"');
+ }
+
+ $token = new StdOAuth2Token();
+ $token->setAccessToken($data['access_token']);
+
+ if (isset($data['expires'])) {
+ $token->setLifeTime($data['expires']);
+ }
+
+ if (isset($data['refresh_token'])) {
+ $token->setRefreshToken($data['refresh_token']);
+ unset($data['refresh_token']);
+ }
+
+ unset($data['access_token']);
+ unset($data['expires']);
+
+ $token->setExtraParams($data);
+
+ return $token;
+ }
+
+ public function getDialogUri($dialogPath, array $parameters)
+ {
+ if (!isset($parameters['redirect_uri'])) {
+ throw new Exception("Redirect uri is mandatory for this request");
+ }
+ $parameters['app_id'] = $this->credentials->getConsumerId();
+ $baseUrl = self::WWW_URL . 'dialog/' . $dialogPath;
+ $query = http_build_query($parameters);
+ return new Uri($baseUrl . '?' . $query);
+ }
+}
diff --git a/vendor/lusitanian/oauth/src/OAuth/OAuth2/Service/Foursquare.php b/vendor/lusitanian/oauth/src/OAuth/OAuth2/Service/Foursquare.php
new file mode 100644
index 00000000..fdbabf98
--- /dev/null
+++ b/vendor/lusitanian/oauth/src/OAuth/OAuth2/Service/Foursquare.php
@@ -0,0 +1,81 @@
+baseApiUri = new Uri('https://api.foursquare.com/v2/');
+ }
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function getAuthorizationEndpoint()
+ {
+ return new Uri('https://foursquare.com/oauth2/authenticate');
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function getAccessTokenEndpoint()
+ {
+ return new Uri('https://foursquare.com/oauth2/access_token');
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ protected function parseAccessTokenResponse($responseBody)
+ {
+ $data = json_decode($responseBody, true);
+
+ if (null === $data || !is_array($data)) {
+ throw new TokenResponseException('Unable to parse response.');
+ } elseif (isset($data['error'])) {
+ throw new TokenResponseException('Error in retrieving token: "' . $data['error'] . '"');
+ }
+
+ $token = new StdOAuth2Token();
+ $token->setAccessToken($data['access_token']);
+ // Foursquare tokens evidently never expire...
+ $token->setEndOfLife(StdOAuth2Token::EOL_NEVER_EXPIRES);
+ unset($data['access_token']);
+
+ $token->setExtraParams($data);
+
+ return $token;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function request($path, $method = 'GET', $body = null, array $extraHeaders = array())
+ {
+ $uri = new Uri($this->baseApiUri . $path);
+ $uri->addToQuery('v', $this->apiVersionDate);
+
+ return parent::request($uri, $method, $body, $extraHeaders);
+ }
+}
diff --git a/vendor/lusitanian/oauth/src/OAuth/OAuth2/Service/GitHub.php b/vendor/lusitanian/oauth/src/OAuth/OAuth2/Service/GitHub.php
new file mode 100644
index 00000000..9fee2ba0
--- /dev/null
+++ b/vendor/lusitanian/oauth/src/OAuth/OAuth2/Service/GitHub.php
@@ -0,0 +1,208 @@
+baseApiUri = new Uri('https://api.github.com/');
+ }
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function getAuthorizationEndpoint()
+ {
+ return new Uri('https://github.com/login/oauth/authorize');
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function getAccessTokenEndpoint()
+ {
+ return new Uri('https://github.com/login/oauth/access_token');
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ protected function getAuthorizationMethod()
+ {
+ return static::AUTHORIZATION_METHOD_QUERY_STRING;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ protected function parseAccessTokenResponse($responseBody)
+ {
+ $data = json_decode($responseBody, true);
+
+ if (null === $data || !is_array($data)) {
+ throw new TokenResponseException('Unable to parse response.');
+ } elseif (isset($data['error'])) {
+ throw new TokenResponseException('Error in retrieving token: "' . $data['error'] . '"');
+ }
+
+ $token = new StdOAuth2Token();
+ $token->setAccessToken($data['access_token']);
+ // Github tokens evidently never expire...
+ $token->setEndOfLife(StdOAuth2Token::EOL_NEVER_EXPIRES);
+ unset($data['access_token']);
+
+ $token->setExtraParams($data);
+
+ return $token;
+ }
+
+ /**
+ * Used to configure response type -- we want JSON from github, default is query string format
+ *
+ * @return array
+ */
+ protected function getExtraOAuthHeaders()
+ {
+ return array('Accept' => 'application/json');
+ }
+
+ /**
+ * Required for GitHub API calls.
+ *
+ * @return array
+ */
+ protected function getExtraApiHeaders()
+ {
+ return array('Accept' => 'application/vnd.github.beta+json');
+ }
+}
diff --git a/vendor/lusitanian/oauth/src/OAuth/OAuth2/Service/Google.php b/vendor/lusitanian/oauth/src/OAuth/OAuth2/Service/Google.php
new file mode 100644
index 00000000..096876b6
--- /dev/null
+++ b/vendor/lusitanian/oauth/src/OAuth/OAuth2/Service/Google.php
@@ -0,0 +1,158 @@
+accessType = $accessType;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function getAuthorizationEndpoint()
+ {
+ return new Uri('https://accounts.google.com/o/oauth2/auth?access_type=' . $this->accessType);
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function getAccessTokenEndpoint()
+ {
+ return new Uri('https://accounts.google.com/o/oauth2/token');
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ protected function parseAccessTokenResponse($responseBody)
+ {
+ $data = json_decode($responseBody, true);
+
+ if (null === $data || !is_array($data)) {
+ throw new TokenResponseException('Unable to parse response.');
+ } elseif (isset($data['error'])) {
+ throw new TokenResponseException('Error in retrieving token: "' . $data['error'] . '"');
+ }
+
+ $token = new StdOAuth2Token();
+ $token->setAccessToken($data['access_token']);
+ $token->setLifetime($data['expires_in']);
+
+ if (isset($data['refresh_token'])) {
+ $token->setRefreshToken($data['refresh_token']);
+ unset($data['refresh_token']);
+ }
+
+ unset($data['access_token']);
+ unset($data['expires_in']);
+
+ $token->setExtraParams($data);
+
+ return $token;
+ }
+}
diff --git a/vendor/lusitanian/oauth/src/OAuth/OAuth2/Service/Harvest.php b/vendor/lusitanian/oauth/src/OAuth/OAuth2/Service/Harvest.php
new file mode 100644
index 00000000..96fb0f2d
--- /dev/null
+++ b/vendor/lusitanian/oauth/src/OAuth/OAuth2/Service/Harvest.php
@@ -0,0 +1,157 @@
+baseApiUri = new Uri('https://api.harvestapp.com/');
+ }
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function getAuthorizationUri(array $additionalParameters = array())
+ {
+ $parameters = array_merge(
+ $additionalParameters,
+ array(
+ 'client_id' => $this->credentials->getConsumerId(),
+ 'redirect_uri' => $this->credentials->getCallbackUrl(),
+ 'state' => 'optional-csrf-token',
+ 'response_type' => 'code',
+ )
+ );
+
+ // Build the url
+ $url = clone $this->getAuthorizationEndpoint();
+ foreach ($parameters as $key => $val) {
+ $url->addToQuery($key, $val);
+ }
+
+ return $url;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function getAuthorizationEndpoint()
+ {
+ return new Uri('https://api.harvestapp.com/oauth2/authorize');
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function getAccessTokenEndpoint()
+ {
+ return new Uri('https://api.harvestapp.com/oauth2/token');
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ protected function getAuthorizationMethod()
+ {
+ return static::AUTHORIZATION_METHOD_QUERY_STRING;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ protected function parseAccessTokenResponse($responseBody)
+ {
+ $data = json_decode($responseBody, true);
+
+ if (null === $data || ! is_array($data)) {
+ throw new TokenResponseException('Unable to parse response.');
+ } elseif (isset($data['error'])) {
+ throw new TokenResponseException('Error in retrieving token: "' . $data['error'] . '"');
+ }
+
+ $token = new StdOAuth2Token();
+ $token->setAccessToken($data['access_token']);
+ $token->setLifetime($data['expires_in']);
+ $token->setRefreshToken($data['refresh_token']);
+
+ unset($data['access_token']);
+
+ $token->setExtraParams($data);
+
+ return $token;
+ }
+
+ /**
+ * Refreshes an OAuth2 access token.
+ *
+ * @param TokenInterface $token
+ *
+ * @return TokenInterface $token
+ *
+ * @throws MissingRefreshTokenException
+ */
+ public function refreshAccessToken(TokenInterface $token)
+ {
+ $refreshToken = $token->getRefreshToken();
+
+ if (empty($refreshToken)) {
+ throw new MissingRefreshTokenException();
+ }
+
+ $parameters = array(
+ 'grant_type' => 'refresh_token',
+ 'type' => 'web_server',
+ 'client_id' => $this->credentials->getConsumerId(),
+ 'client_secret' => $this->credentials->getConsumerSecret(),
+ 'refresh_token' => $refreshToken,
+ );
+
+ $responseBody = $this->httpClient->retrieveResponse(
+ $this->getAccessTokenEndpoint(),
+ $parameters,
+ $this->getExtraOAuthHeaders()
+ );
+ $token = $this->parseAccessTokenResponse($responseBody);
+ $this->storage->storeAccessToken($this->service(), $token);
+
+ return $token;
+ }
+
+ /**
+ * @return array
+ */
+ protected function getExtraOAuthHeaders()
+ {
+ return array('Accept' => 'application/json');
+ }
+
+ /**
+ * Return any additional headers always needed for this service implementation's API calls.
+ *
+ * @return array
+ */
+ protected function getExtraApiHeaders()
+ {
+ return array('Accept' => 'application/json');
+ }
+}
diff --git a/vendor/lusitanian/oauth/src/OAuth/OAuth2/Service/Heroku.php b/vendor/lusitanian/oauth/src/OAuth/OAuth2/Service/Heroku.php
new file mode 100644
index 00000000..470cedc3
--- /dev/null
+++ b/vendor/lusitanian/oauth/src/OAuth/OAuth2/Service/Heroku.php
@@ -0,0 +1,123 @@
+
+ * @link https://devcenter.heroku.com/articles/oauth
+ */
+class Heroku extends AbstractService
+{
+ /**
+ * Defined scopes
+ * @link https://devcenter.heroku.com/articles/oauth#scopes
+ */
+ const SCOPE_GLOBAL = 'global';
+ const SCOPE_IDENTITY = 'identity';
+ const SCOPE_READ = 'read';
+ const SCOPE_WRITE = 'write';
+ const SCOPE_READ_PROTECTED = 'read-protected';
+ const SCOPE_WRITE_PROTECTED = 'write-protected';
+
+ /**
+ * {@inheritdoc}
+ */
+ public function __construct(
+ CredentialsInterface $credentials,
+ ClientInterface $httpClient,
+ TokenStorageInterface $storage,
+ $scopes = array(),
+ UriInterface $baseApiUri = null
+ ) {
+ parent::__construct($credentials, $httpClient, $storage, $scopes, $baseApiUri);
+
+ if (null === $baseApiUri) {
+ $this->baseApiUri = new Uri('https://api.heroku.com/');
+ }
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function getAuthorizationEndpoint()
+ {
+ return new Uri('https://id.heroku.com/oauth/authorize');
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function getAccessTokenEndpoint()
+ {
+ return new Uri('https://id.heroku.com/oauth/token');
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ protected function getAuthorizationMethod()
+ {
+ return static::AUTHORIZATION_METHOD_HEADER_BEARER;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ protected function parseAccessTokenResponse($responseBody)
+ {
+ $data = json_decode($responseBody, true);
+
+ if (null === $data || !is_array($data)) {
+ throw new TokenResponseException('Unable to parse response.');
+ } elseif (isset($data['error_description']) || isset($data['error'])) {
+ throw new TokenResponseException(
+ sprintf(
+ 'Error in retrieving token: "%s"',
+ isset($data['error_description']) ? $data['error_description'] : $data['error']
+ )
+ );
+ }
+
+ $token = new StdOAuth2Token();
+ $token->setAccessToken($data['access_token']);
+ $token->setLifeTime($data['expires_in']);
+
+ if (isset($data['refresh_token'])) {
+ $token->setRefreshToken($data['refresh_token']);
+ unset($data['refresh_token']);
+ }
+
+ unset($data['access_token']);
+ unset($data['expires_in']);
+
+ $token->setExtraParams($data);
+
+ return $token;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ protected function getExtraOAuthHeaders()
+ {
+ return array('Accept' => 'application/vnd.heroku+json; version=3');
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ protected function getExtraApiHeaders()
+ {
+ return array('Accept' => 'application/vnd.heroku+json; version=3', 'Content-Type' => 'application/json');
+ }
+}
diff --git a/vendor/lusitanian/oauth/src/OAuth/OAuth2/Service/Instagram.php b/vendor/lusitanian/oauth/src/OAuth/OAuth2/Service/Instagram.php
new file mode 100644
index 00000000..49e9c8c9
--- /dev/null
+++ b/vendor/lusitanian/oauth/src/OAuth/OAuth2/Service/Instagram.php
@@ -0,0 +1,85 @@
+baseApiUri = new Uri('https://api.instagram.com/v1/');
+ }
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function getAuthorizationEndpoint()
+ {
+ return new Uri('https://api.instagram.com/oauth/authorize/');
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function getAccessTokenEndpoint()
+ {
+ return new Uri('https://api.instagram.com/oauth/access_token');
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ protected function getAuthorizationMethod()
+ {
+ return static::AUTHORIZATION_METHOD_QUERY_STRING;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ protected function parseAccessTokenResponse($responseBody)
+ {
+ $data = json_decode($responseBody, true);
+
+ if (null === $data || !is_array($data)) {
+ throw new TokenResponseException('Unable to parse response.');
+ } elseif (isset($data['error'])) {
+ throw new TokenResponseException('Error in retrieving token: "' . $data['error'] . '"');
+ }
+
+ $token = new StdOAuth2Token();
+ $token->setAccessToken($data['access_token']);
+ // Instagram tokens evidently never expire...
+ $token->setEndOfLife(StdOAuth2Token::EOL_NEVER_EXPIRES);
+ unset($data['access_token']);
+
+ $token->setExtraParams($data);
+
+ return $token;
+ }
+}
diff --git a/vendor/lusitanian/oauth/src/OAuth/OAuth2/Service/Linkedin.php b/vendor/lusitanian/oauth/src/OAuth/OAuth2/Service/Linkedin.php
new file mode 100644
index 00000000..bb801e6a
--- /dev/null
+++ b/vendor/lusitanian/oauth/src/OAuth/OAuth2/Service/Linkedin.php
@@ -0,0 +1,102 @@
+
+ * @link http://developer.linkedin.com/documents/authentication
+ */
+class Linkedin extends AbstractService
+{
+ /**
+ * Defined scopes
+ * @link http://developer.linkedin.com/documents/authentication#granting
+ */
+ const SCOPE_R_BASICPROFILE = 'r_basicprofile';
+ const SCOPE_R_FULLPROFILE = 'r_fullprofile';
+ const SCOPE_R_EMAILADDRESS = 'r_emailaddress';
+ const SCOPE_R_NETWORK = 'r_network';
+ const SCOPE_R_CONTACTINFO = 'r_contactinfo';
+ const SCOPE_RW_NUS = 'rw_nus';
+ const SCOPE_RW_COMPANY_ADMIN = 'rw_company_admin';
+ const SCOPE_RW_GROUPS = 'rw_groups';
+ const SCOPE_W_MESSAGES = 'w_messages';
+
+ public function __construct(
+ CredentialsInterface $credentials,
+ ClientInterface $httpClient,
+ TokenStorageInterface $storage,
+ $scopes = array(),
+ UriInterface $baseApiUri = null
+ ) {
+ parent::__construct($credentials, $httpClient, $storage, $scopes, $baseApiUri, true);
+
+ if (null === $baseApiUri) {
+ $this->baseApiUri = new Uri('https://api.linkedin.com/v1/');
+ }
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function getAuthorizationEndpoint()
+ {
+ return new Uri('https://www.linkedin.com/uas/oauth2/authorization');
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function getAccessTokenEndpoint()
+ {
+ return new Uri('https://www.linkedin.com/uas/oauth2/accessToken');
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ protected function getAuthorizationMethod()
+ {
+ return static::AUTHORIZATION_METHOD_QUERY_STRING_V2;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ protected function parseAccessTokenResponse($responseBody)
+ {
+ $data = json_decode($responseBody, true);
+
+ if (null === $data || !is_array($data)) {
+ throw new TokenResponseException('Unable to parse response.');
+ } elseif (isset($data['error'])) {
+ throw new TokenResponseException('Error in retrieving token: "' . $data['error'] . '"');
+ }
+
+ $token = new StdOAuth2Token();
+ $token->setAccessToken($data['access_token']);
+ $token->setLifeTime($data['expires_in']);
+
+ if (isset($data['refresh_token'])) {
+ $token->setRefreshToken($data['refresh_token']);
+ unset($data['refresh_token']);
+ }
+
+ unset($data['access_token']);
+ unset($data['expires_in']);
+
+ $token->setExtraParams($data);
+
+ return $token;
+ }
+}
diff --git a/vendor/lusitanian/oauth/src/OAuth/OAuth2/Service/Mailchimp.php b/vendor/lusitanian/oauth/src/OAuth/OAuth2/Service/Mailchimp.php
new file mode 100644
index 00000000..42abd3c1
--- /dev/null
+++ b/vendor/lusitanian/oauth/src/OAuth/OAuth2/Service/Mailchimp.php
@@ -0,0 +1,115 @@
+baseApiUri) && $storage->hasAccessToken($this->service())) {
+ $this->setBaseApiUri($storage->retrieveAccessToken($this->service()));
+ }
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ protected function getAuthorizationMethod()
+ {
+ return static::AUTHORIZATION_METHOD_QUERY_STRING_V3;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function getAuthorizationEndpoint()
+ {
+ return new Uri('https://login.mailchimp.com/oauth2/authorize');
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function getAccessTokenEndpoint()
+ {
+ return new Uri('https://login.mailchimp.com/oauth2/token');
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ protected function parseAccessTokenResponse($responseBody)
+ {
+ // Parse JSON
+ $data = json_decode($responseBody, true);
+
+ // Do validation.
+ if (null === $data || !is_array($data)) {
+ throw new TokenResponseException('Unable to parse response.');
+ } elseif (isset($data['error'])) {
+ throw new TokenResponseException('Error in retrieving token: "' . $data['error'] . '"');
+ }
+
+ // Create token object.
+ $token = new StdOAuth2Token($data['access_token']);
+
+ // Set the right API endpoint.
+ $this->setBaseApiUri($token);
+
+ // Mailchimp tokens evidently never expire...
+ $token->setEndOfLife(StdOAuth2Token::EOL_NEVER_EXPIRES);
+
+ return $token;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function request($path, $method = 'GET', $body = null, array $extraHeaders = array())
+ {
+ if (is_null($this->baseApiUri)) {
+ $this->setBaseApiUri($this->storage->retrieveAccessToken($this->service()));
+ }
+
+ return parent::request($path, $method, $body, $extraHeaders);
+ }
+
+ /**
+ * Set the right base endpoint.
+ *
+ * @param StdOAuth2Token $token
+ */
+ protected function setBaseApiUri(StdOAuth2Token $token)
+ {
+ // Make request uri.
+ $endpoint = 'https://login.mailchimp.com/oauth2/metadata?oauth_token='. $token->getAccessToken();
+
+ // Grab meta data about the token.
+ $response = $this->httpClient->retrieveResponse(new Uri($endpoint), array(), array(), 'GET');
+
+ // Parse JSON.
+ $meta = json_decode($response, true);
+
+ // Set base api uri.
+ $this->baseApiUri = new Uri('https://'. $meta['dc'] .'.api.mailchimp.com/2.0/');
+
+ // Allow chaining.
+ return $this;
+ }
+}
diff --git a/vendor/lusitanian/oauth/src/OAuth/OAuth2/Service/Microsoft.php b/vendor/lusitanian/oauth/src/OAuth/OAuth2/Service/Microsoft.php
new file mode 100644
index 00000000..183ef452
--- /dev/null
+++ b/vendor/lusitanian/oauth/src/OAuth/OAuth2/Service/Microsoft.php
@@ -0,0 +1,119 @@
+baseApiUri = new Uri('https://apis.live.net/v5.0/');
+ }
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function getAuthorizationEndpoint()
+ {
+ return new Uri('https://login.live.com/oauth20_authorize.srf');
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function getAccessTokenEndpoint()
+ {
+ return new Uri('https://login.live.com/oauth20_token.srf');
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function getAuthorizationMethod()
+ {
+ return static::AUTHORIZATION_METHOD_QUERY_STRING;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ protected function parseAccessTokenResponse($responseBody)
+ {
+ $data = json_decode($responseBody, true);
+
+ if (null === $data || !is_array($data)) {
+ throw new TokenResponseException('Unable to parse response.');
+ } elseif (isset($data['error'])) {
+ throw new TokenResponseException('Error in retrieving token: "' . $data['error'] . '"');
+ }
+
+ $token = new StdOAuth2Token();
+ $token->setAccessToken($data['access_token']);
+ $token->setLifetime($data['expires_in']);
+
+ if (isset($data['refresh_token'])) {
+ $token->setRefreshToken($data['refresh_token']);
+ unset($data['refresh_token']);
+ }
+
+ unset($data['access_token']);
+ unset($data['expires_in']);
+
+ $token->setExtraParams($data);
+
+ return $token;
+ }
+}
diff --git a/vendor/lusitanian/oauth/src/OAuth/OAuth2/Service/Paypal.php b/vendor/lusitanian/oauth/src/OAuth/OAuth2/Service/Paypal.php
new file mode 100644
index 00000000..761c09d6
--- /dev/null
+++ b/vendor/lusitanian/oauth/src/OAuth/OAuth2/Service/Paypal.php
@@ -0,0 +1,103 @@
+
+ * @link https://developer.paypal.com/webapps/developer/docs/integration/direct/log-in-with-paypal/detailed/
+ */
+class Paypal extends AbstractService
+{
+ /**
+ * Defined scopes
+ * @link https://developer.paypal.com/webapps/developer/docs/integration/direct/log-in-with-paypal/detailed/
+ * @see #attributes
+ */
+ const SCOPE_OPENID = 'openid';
+ const SCOPE_PROFILE = 'profile';
+ const SCOPE_PAYPALATTRIBUTES = 'https://uri.paypal.com/services/paypalattributes';
+ const SCOPE_EMAIL = 'email';
+ const SCOPE_ADDRESS = 'address';
+ const SCOPE_PHONE = 'phone';
+ const SCOPE_EXPRESSCHECKOUT = 'https://uri.paypal.com/services/expresscheckout';
+
+ public function __construct(
+ CredentialsInterface $credentials,
+ ClientInterface $httpClient,
+ TokenStorageInterface $storage,
+ $scopes = array(),
+ UriInterface $baseApiUri = null
+ ) {
+ parent::__construct($credentials, $httpClient, $storage, $scopes, $baseApiUri);
+
+ if (null === $baseApiUri) {
+ $this->baseApiUri = new Uri('https://api.paypal.com/v1/');
+ }
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function getAuthorizationEndpoint()
+ {
+ return new Uri('https://www.paypal.com/webapps/auth/protocol/openidconnect/v1/authorize');
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function getAccessTokenEndpoint()
+ {
+ return new Uri('https://api.paypal.com/v1/identity/openidconnect/tokenservice');
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ protected function getAuthorizationMethod()
+ {
+ return static::AUTHORIZATION_METHOD_HEADER_BEARER;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ protected function parseAccessTokenResponse($responseBody)
+ {
+ $data = json_decode($responseBody, true);
+
+ if (null === $data || !is_array($data)) {
+ throw new TokenResponseException('Unable to parse response.');
+ } elseif (isset($data['message'])) {
+ throw new TokenResponseException('Error in retrieving token: "' . $data['message'] . '"');
+ } elseif (isset($data['name'])) {
+ throw new TokenResponseException('Error in retrieving token: "' . $data['name'] . '"');
+ }
+
+ $token = new StdOAuth2Token();
+ $token->setAccessToken($data['access_token']);
+ $token->setLifeTime($data['expires_in']);
+
+ if (isset($data['refresh_token'])) {
+ $token->setRefreshToken($data['refresh_token']);
+ unset($data['refresh_token']);
+ }
+
+ unset($data['access_token']);
+ unset($data['expires_in']);
+
+ $token->setExtraParams($data);
+
+ return $token;
+ }
+}
diff --git a/vendor/lusitanian/oauth/src/OAuth/OAuth2/Service/Pocket.php b/vendor/lusitanian/oauth/src/OAuth/OAuth2/Service/Pocket.php
new file mode 100644
index 00000000..8c955440
--- /dev/null
+++ b/vendor/lusitanian/oauth/src/OAuth/OAuth2/Service/Pocket.php
@@ -0,0 +1,125 @@
+baseApiUri = new Uri('https://getpocket.com/v3/');
+ }
+ }
+
+ public function getRequestTokenEndpoint()
+ {
+ return new Uri('https://getpocket.com/v3/oauth/request');
+ }
+
+ public function getAuthorizationEndpoint()
+ {
+ return new Uri('https://getpocket.com/auth/authorize');
+ }
+
+ public function getAccessTokenEndpoint()
+ {
+ return new Uri('https://getpocket.com/v3/oauth/authorize');
+ }
+
+ public function getAuthorizationUri(array $additionalParameters = array())
+ {
+ $parameters = array_merge(
+ $additionalParameters,
+ array(
+ 'redirect_uri' => $this->credentials->getCallbackUrl(),
+ )
+ );
+
+ // Build the url
+ $url = clone $this->getAuthorizationEndpoint();
+ foreach ($parameters as $key => $val) {
+ $url->addToQuery($key, $val);
+ }
+
+ return $url;
+ }
+
+ public function requestRequestToken()
+ {
+ $responseBody = $this->httpClient->retrieveResponse(
+ $this->getRequestTokenEndpoint(),
+ array(
+ 'consumer_key' => $this->credentials->getConsumerId(),
+ 'redirect_uri' => $this->credentials->getCallbackUrl(),
+ )
+ );
+
+ $code = $this->parseRequestTokenResponse($responseBody);
+
+ return $code;
+ }
+
+ protected function parseRequestTokenResponse($responseBody)
+ {
+ parse_str($responseBody, $data);
+
+ if (null === $data || !is_array($data)) {
+ throw new TokenResponseException('Unable to parse response.');
+ } elseif (!isset($data['code'])) {
+ throw new TokenResponseException('Error in retrieving code.');
+ }
+ return $data['code'];
+ }
+
+ public function requestAccessToken($code)
+ {
+ $bodyParams = array(
+ 'consumer_key' => $this->credentials->getConsumerId(),
+ 'code' => $code,
+ );
+
+ $responseBody = $this->httpClient->retrieveResponse(
+ $this->getAccessTokenEndpoint(),
+ $bodyParams,
+ $this->getExtraOAuthHeaders()
+ );
+ $token = $this->parseAccessTokenResponse($responseBody);
+ $this->storage->storeAccessToken($this->service(), $token);
+
+ return $token;
+ }
+
+ protected function parseAccessTokenResponse($responseBody)
+ {
+ parse_str($responseBody, $data);
+
+ if ($data === null || !is_array($data)) {
+ throw new TokenResponseException('Unable to parse response.');
+ } elseif (isset($data['error'])) {
+ throw new TokenResponseException('Error in retrieving token: "' . $data['error'] . '"');
+ }
+
+ $token = new StdOAuth2Token();
+ #$token->setRequestToken($data['access_token']);
+ $token->setAccessToken($data['access_token']);
+ $token->setEndOfLife(StdOAuth2Token::EOL_NEVER_EXPIRES);
+ unset($data['access_token']);
+ $token->setExtraParams($data);
+
+ return $token;
+ }
+}
diff --git a/vendor/lusitanian/oauth/src/OAuth/OAuth2/Service/Reddit.php b/vendor/lusitanian/oauth/src/OAuth/OAuth2/Service/Reddit.php
new file mode 100644
index 00000000..9e524d12
--- /dev/null
+++ b/vendor/lusitanian/oauth/src/OAuth/OAuth2/Service/Reddit.php
@@ -0,0 +1,114 @@
+baseApiUri = new Uri('https://oauth.reddit.com');
+ }
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function getAuthorizationEndpoint()
+ {
+ return new Uri('https://ssl.reddit.com/api/v1/authorize');
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function getAccessTokenEndpoint()
+ {
+ return new Uri('https://ssl.reddit.com/api/v1/access_token');
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ protected function getAuthorizationMethod()
+ {
+ return static::AUTHORIZATION_METHOD_HEADER_BEARER;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ protected function parseAccessTokenResponse($responseBody)
+ {
+ $data = json_decode($responseBody, true);
+
+ if (null === $data || !is_array($data)) {
+ throw new TokenResponseException('Unable to parse response.');
+ } elseif (isset($data['error'])) {
+ throw new TokenResponseException('Error in retrieving token: "' . $data['error'] . '"');
+ }
+
+ $token = new StdOAuth2Token();
+ $token->setAccessToken($data['access_token']);
+ $token->setLifeTime($data['expires_in']);
+
+ if (isset($data['refresh_token'])) {
+ $token->setRefreshToken($data['refresh_token']);
+ unset($data['refresh_token']);
+ }
+
+ unset($data['access_token']);
+ unset($data['expires_in']);
+
+ $token->setExtraParams($data);
+
+ return $token;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ protected function getExtraOAuthHeaders()
+ {
+ // Reddit uses a Basic OAuth header
+ return array('Authorization' => 'Basic ' .
+ base64_encode($this->credentials->getConsumerId() . ':' . $this->credentials->getConsumerSecret()));
+ }
+}
diff --git a/vendor/lusitanian/oauth/src/OAuth/OAuth2/Service/RunKeeper.php b/vendor/lusitanian/oauth/src/OAuth/OAuth2/Service/RunKeeper.php
new file mode 100644
index 00000000..71584076
--- /dev/null
+++ b/vendor/lusitanian/oauth/src/OAuth/OAuth2/Service/RunKeeper.php
@@ -0,0 +1,105 @@
+baseApiUri = new Uri('https://api.runkeeper.com/');
+ }
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function getAuthorizationUri(array $additionalParameters = array())
+ {
+ $parameters = array_merge(
+ $additionalParameters,
+ array(
+ 'client_id' => $this->credentials->getConsumerId(),
+ 'redirect_uri' => $this->credentials->getCallbackUrl(),
+ 'response_type' => 'code',
+ )
+ );
+
+ $parameters['scope'] = implode(' ', $this->scopes);
+
+ // Build the url
+ $url = clone $this->getAuthorizationEndpoint();
+ foreach ($parameters as $key => $val) {
+ $url->addToQuery($key, $val);
+ }
+
+ return $url;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function getAuthorizationEndpoint()
+ {
+ return new Uri('https://runkeeper.com/apps/authorize');
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function getAccessTokenEndpoint()
+ {
+ return new Uri('https://runkeeper.com/apps/token');
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ protected function getAuthorizationMethod()
+ {
+ return static::AUTHORIZATION_METHOD_HEADER_BEARER;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ protected function parseAccessTokenResponse($responseBody)
+ {
+ $data = json_decode($responseBody, true);
+
+ if (null === $data || !is_array($data)) {
+ throw new TokenResponseException('Unable to parse response.');
+ } elseif (isset($data['error'])) {
+ throw new TokenResponseException('Error in retrieving token: "' . $data['error'] . '"');
+ }
+
+ $token = new StdOAuth2Token();
+ $token->setAccessToken($data['access_token']);
+
+ unset($data['access_token']);
+
+ $token->setExtraParams($data);
+
+ return $token;
+ }
+}
diff --git a/vendor/lusitanian/oauth/src/OAuth/OAuth2/Service/Salesforce.php b/vendor/lusitanian/oauth/src/OAuth/OAuth2/Service/Salesforce.php
new file mode 100644
index 00000000..583e4347
--- /dev/null
+++ b/vendor/lusitanian/oauth/src/OAuth/OAuth2/Service/Salesforce.php
@@ -0,0 +1,92 @@
+parseAccessTokenResponse($responseBody);
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ protected function parseAccessTokenResponse($responseBody)
+ {
+ $data = json_decode($responseBody, true);
+
+ if (null === $data || !is_array($data)) {
+ throw new TokenResponseException('Unable to parse response.');
+ } elseif (isset($data['error'])) {
+ throw new TokenResponseException('Error in retrieving token: "' . $data['error'] . '"');
+ }
+
+ $token = new StdOAuth2Token();
+ $token->setAccessToken($data['access_token']);
+ // Salesforce tokens evidently never expire...
+ $token->setEndOfLife(StdOAuth2Token::EOL_NEVER_EXPIRES);
+ unset($data['access_token']);
+
+ if (isset($data['refresh_token'])) {
+ $token->setRefreshToken($data['refresh_token']);
+ unset($data['refresh_token']);
+ }
+
+ $token->setExtraParams($data);
+
+ return $token;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ protected function getExtraOAuthHeaders()
+ {
+ return array('Accept' => 'application/json');
+ }
+}
diff --git a/vendor/lusitanian/oauth/src/OAuth/OAuth2/Service/ServiceInterface.php b/vendor/lusitanian/oauth/src/OAuth/OAuth2/Service/ServiceInterface.php
new file mode 100644
index 00000000..f3d1bdad
--- /dev/null
+++ b/vendor/lusitanian/oauth/src/OAuth/OAuth2/Service/ServiceInterface.php
@@ -0,0 +1,37 @@
+baseApiUri = new Uri('https://api.soundcloud.com/');
+ }
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function getAuthorizationEndpoint()
+ {
+ return new Uri('https://soundcloud.com/connect');
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function getAccessTokenEndpoint()
+ {
+ return new Uri('https://api.soundcloud.com/oauth2/token');
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ protected function parseAccessTokenResponse($responseBody)
+ {
+ $data = json_decode($responseBody, true);
+
+ if (null === $data || !is_array($data)) {
+ throw new TokenResponseException('Unable to parse response.');
+ } elseif (isset($data['error'])) {
+ throw new TokenResponseException('Error in retrieving token: "' . $data['error'] . '"');
+ }
+
+ $token = new StdOAuth2Token();
+ $token->setAccessToken($data['access_token']);
+
+ if (isset($data['expires_in'])) {
+ $token->setLifetime($data['expires_in']);
+ unset($data['expires_in']);
+ }
+
+ if (isset($data['refresh_token'])) {
+ $token->setRefreshToken($data['refresh_token']);
+ unset($data['refresh_token']);
+ }
+
+ unset($data['access_token']);
+
+ $token->setExtraParams($data);
+
+ return $token;
+ }
+}
diff --git a/vendor/lusitanian/oauth/src/OAuth/OAuth2/Service/Ustream.php b/vendor/lusitanian/oauth/src/OAuth/OAuth2/Service/Ustream.php
new file mode 100644
index 00000000..7e558153
--- /dev/null
+++ b/vendor/lusitanian/oauth/src/OAuth/OAuth2/Service/Ustream.php
@@ -0,0 +1,98 @@
+baseApiUri = new Uri('https://api.ustream.tv/');
+ }
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function getAuthorizationEndpoint()
+ {
+ return new Uri('https://www.ustream.tv/oauth2/authorize');
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function getAccessTokenEndpoint()
+ {
+ return new Uri('https://www.ustream.tv/oauth2/token');
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ protected function getAuthorizationMethod()
+ {
+ return static::AUTHORIZATION_METHOD_HEADER_BEARER;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ protected function parseAccessTokenResponse($responseBody)
+ {
+ $data = json_decode($responseBody, true);
+
+ if (null === $data || !is_array($data)) {
+ throw new TokenResponseException('Unable to parse response.');
+ } elseif (isset($data['error'])) {
+ throw new TokenResponseException('Error in retrieving token: "' . $data['error'] . '"');
+ }
+
+ $token = new StdOAuth2Token();
+ $token->setAccessToken($data['access_token']);
+ $token->setLifeTime($data['expires_in']);
+
+ if (isset($data['refresh_token'])) {
+ $token->setRefreshToken($data['refresh_token']);
+ unset($data['refresh_token']);
+ }
+
+ unset($data['access_token']);
+ unset($data['expires_in']);
+
+ $token->setExtraParams($data);
+
+ return $token;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ protected function getExtraOAuthHeaders()
+ {
+ return array('Authorization' => 'Basic ' . $this->credentials->getConsumerSecret());
+ }
+}
diff --git a/vendor/lusitanian/oauth/src/OAuth/OAuth2/Service/Vkontakte.php b/vendor/lusitanian/oauth/src/OAuth/OAuth2/Service/Vkontakte.php
new file mode 100644
index 00000000..4a7744ec
--- /dev/null
+++ b/vendor/lusitanian/oauth/src/OAuth/OAuth2/Service/Vkontakte.php
@@ -0,0 +1,109 @@
+baseApiUri = new Uri('https://api.vk.com/method/');
+ }
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function getAuthorizationEndpoint()
+ {
+ return new Uri('https://oauth.vk.com/authorize');
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function getAccessTokenEndpoint()
+ {
+ return new Uri('https://oauth.vk.com/access_token');
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ protected function parseAccessTokenResponse($responseBody)
+ {
+ $data = json_decode($responseBody, true);
+
+ if (null === $data || !is_array($data)) {
+ throw new TokenResponseException('Unable to parse response.');
+ } elseif (isset($data['error'])) {
+ throw new TokenResponseException('Error in retrieving token: "' . $data['error'] . '"');
+ }
+
+ $token = new StdOAuth2Token();
+ $token->setAccessToken($data['access_token']);
+ $token->setLifeTime($data['expires_in']);
+
+ if (isset($data['refresh_token'])) {
+ $token->setRefreshToken($data['refresh_token']);
+ unset($data['refresh_token']);
+ }
+
+ unset($data['access_token']);
+ unset($data['expires_in']);
+
+ $token->setExtraParams($data);
+
+ return $token;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ protected function getAuthorizationMethod()
+ {
+ return static::AUTHORIZATION_METHOD_QUERY_STRING;
+ }
+}
diff --git a/vendor/lusitanian/oauth/src/OAuth/OAuth2/Service/Yammer.php b/vendor/lusitanian/oauth/src/OAuth/OAuth2/Service/Yammer.php
new file mode 100644
index 00000000..994a2935
--- /dev/null
+++ b/vendor/lusitanian/oauth/src/OAuth/OAuth2/Service/Yammer.php
@@ -0,0 +1,82 @@
+baseApiUri = new Uri('https://www.yammer.com/api/v1/');
+ }
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function getAuthorizationEndpoint()
+ {
+ return new Uri('https://www.yammer.com/dialog/oauth');
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function getAccessTokenEndpoint()
+ {
+ return new Uri('https://www.yammer.com/oauth2/access_token.json');
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function getAuthorizationMethod()
+ {
+ return static::AUTHORIZATION_METHOD_HEADER_BEARER;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ protected function parseAccessTokenResponse($responseBody)
+ {
+ $data = json_decode($responseBody, true);
+
+ if (null === $data || !is_array($data)) {
+ throw new TokenResponseException('Unable to parse response.');
+ } elseif (isset($data['error'])) {
+ throw new TokenResponseException('Error in retrieving token: "' . $data['error'] . '"');
+ }
+
+ $token = new StdOAuth2Token();
+ $token->setAccessToken($data['access_token']['token']);
+ $token->setLifetime($data['access_token']['expires_at']);
+
+ if (isset($data['refresh_token'])) {
+ $token->setRefreshToken($data['refresh_token']);
+ unset($data['refresh_token']);
+ }
+
+ unset($data['access_token']);
+ unset($data['expires_in']);
+
+ $token->setExtraParams($data);
+
+ return $token;
+ }
+}
diff --git a/vendor/lusitanian/oauth/src/OAuth/OAuth2/Token/StdOAuth2Token.php b/vendor/lusitanian/oauth/src/OAuth/OAuth2/Token/StdOAuth2Token.php
new file mode 100644
index 00000000..eaaacac7
--- /dev/null
+++ b/vendor/lusitanian/oauth/src/OAuth/OAuth2/Token/StdOAuth2Token.php
@@ -0,0 +1,13 @@
+
+ * @author Pieter Hordijk
+ * @copyright Copyright (c) 2013 The authors
+ * @license http://www.opensource.org/licenses/mit-license.html MIT License
+ */
+
+namespace OAuth;
+
+use OAuth\Common\Service\ServiceInterface;
+use OAuth\Common\Consumer\CredentialsInterface;
+use OAuth\Common\Storage\TokenStorageInterface;
+use OAuth\Common\Http\Client\ClientInterface;
+use OAuth\Common\Http\Client\StreamClient;
+use OAuth\Common\Http\Uri\UriInterface;
+use OAuth\Common\Exception\Exception;
+use OAuth\OAuth1\Signature\Signature;
+
+class ServiceFactory
+{
+ /**
+ *@var ClientInterface
+ */
+ protected $httpClient;
+
+ /**
+ * @var array
+ */
+ protected $serviceClassMap = array(
+ 'OAuth1' => array(),
+ 'OAuth2' => array()
+ );
+
+ /**
+ * @var array
+ */
+ protected $serviceBuilders = array(
+ 'OAuth2' => 'buildV2Service',
+ 'OAuth1' => 'buildV1Service',
+ );
+
+ /**
+ * @param ClientInterface $httpClient
+ *
+ * @return ServiceFactory
+ */
+ public function setHttpClient(ClientInterface $httpClient)
+ {
+ $this->httpClient = $httpClient;
+
+ return $this;
+ }
+
+ /**
+ * Register a custom service to classname mapping.
+ *
+ * @param string $serviceName Name of the service
+ * @param string $className Class to instantiate
+ *
+ * @return ServiceFactory
+ *
+ * @throws Exception If the class is nonexistent or does not implement a valid ServiceInterface
+ */
+ public function registerService($serviceName, $className)
+ {
+ if (!class_exists($className)) {
+ throw new Exception(sprintf('Service class %s does not exist.', $className));
+ }
+
+ $reflClass = new \ReflectionClass($className);
+
+ foreach (array('OAuth2', 'OAuth1') as $version) {
+ if ($reflClass->implementsInterface('OAuth\\' . $version . '\\Service\\ServiceInterface')) {
+ $this->serviceClassMap[$version][ucfirst($serviceName)] = $className;
+
+ return $this;
+ }
+ }
+
+ throw new Exception(sprintf('Service class %s must implement ServiceInterface.', $className));
+ }
+
+ /**
+ * Builds and returns oauth services
+ *
+ * It will first try to build an OAuth2 service and if none found it will try to build an OAuth1 service
+ *
+ * @param string $serviceName Name of service to create
+ * @param CredentialsInterface $credentials
+ * @param TokenStorageInterface $storage
+ * @param array|null $scopes If creating an oauth2 service, array of scopes
+ * @param UriInterface|null $baseApiUri
+ *
+ * @return ServiceInterface
+ */
+ public function createService(
+ $serviceName,
+ CredentialsInterface $credentials,
+ TokenStorageInterface $storage,
+ $scopes = array(),
+ UriInterface $baseApiUri = null
+ ) {
+ if (!$this->httpClient) {
+ // for backwards compatibility.
+ $this->httpClient = new StreamClient();
+ }
+
+ foreach ($this->serviceBuilders as $version => $buildMethod) {
+ $fullyQualifiedServiceName = $this->getFullyQualifiedServiceName($serviceName, $version);
+
+ if (class_exists($fullyQualifiedServiceName)) {
+ return $this->$buildMethod($fullyQualifiedServiceName, $credentials, $storage, $scopes, $baseApiUri);
+ }
+ }
+
+ return null;
+ }
+
+ /**
+ * Gets the fully qualified name of the service
+ *
+ * @param string $serviceName The name of the service of which to get the fully qualified name
+ * @param string $type The type of the service to get (either OAuth1 or OAuth2)
+ *
+ * @return string The fully qualified name of the service
+ */
+ private function getFullyQualifiedServiceName($serviceName, $type)
+ {
+ $serviceName = ucfirst($serviceName);
+
+ if (isset($this->serviceClassMap[$type][$serviceName])) {
+ return $this->serviceClassMap[$type][$serviceName];
+ }
+
+ return '\\OAuth\\' . $type . '\\Service\\' . $serviceName;
+ }
+
+ /**
+ * Builds v2 services
+ *
+ * @param string $serviceName The fully qualified service name
+ * @param CredentialsInterface $credentials
+ * @param TokenStorageInterface $storage
+ * @param array|null $scopes Array of scopes for the service
+ * @param UriInterface|null $baseApiUri
+ *
+ * @return ServiceInterface
+ *
+ * @throws Exception
+ */
+ private function buildV2Service(
+ $serviceName,
+ CredentialsInterface $credentials,
+ TokenStorageInterface $storage,
+ array $scopes,
+ UriInterface $baseApiUri = null
+ ) {
+ return new $serviceName(
+ $credentials,
+ $this->httpClient,
+ $storage,
+ $this->resolveScopes($serviceName, $scopes),
+ $baseApiUri
+ );
+ }
+
+ /**
+ * Resolves scopes for v2 services
+ *
+ * @param string $serviceName The fully qualified service name
+ * @param array $scopes List of scopes for the service
+ *
+ * @return array List of resolved scopes
+ */
+ private function resolveScopes($serviceName, array $scopes)
+ {
+ $reflClass = new \ReflectionClass($serviceName);
+ $constants = $reflClass->getConstants();
+
+ $resolvedScopes = array();
+ foreach ($scopes as $scope) {
+ $key = strtoupper('SCOPE_' . $scope);
+
+ if (array_key_exists($key, $constants)) {
+ $resolvedScopes[] = $constants[$key];
+ } else {
+ $resolvedScopes[] = $scope;
+ }
+ }
+
+ return $resolvedScopes;
+ }
+
+ /**
+ * Builds v1 services
+ *
+ * @param string $serviceName The fully qualified service name
+ * @param CredentialsInterface $credentials
+ * @param TokenStorageInterface $storage
+ * @param array $scopes
+ * @param UriInterface $baseApiUri
+ *
+ * @return ServiceInterface
+ *
+ * @throws Exception
+ */
+ private function buildV1Service(
+ $serviceName,
+ CredentialsInterface $credentials,
+ TokenStorageInterface $storage,
+ $scopes,
+ UriInterface $baseApiUri = null
+ ) {
+ if (!empty($scopes)) {
+ throw new Exception(
+ 'Scopes passed to ServiceFactory::createService but an OAuth1 service was requested.'
+ );
+ }
+
+ return new $serviceName($credentials, $this->httpClient, $storage, new Signature($credentials), $baseApiUri);
+ }
+}
diff --git a/vendor/lusitanian/oauth/src/OAuth/bootstrap.php b/vendor/lusitanian/oauth/src/OAuth/bootstrap.php
new file mode 100644
index 00000000..548678aa
--- /dev/null
+++ b/vendor/lusitanian/oauth/src/OAuth/bootstrap.php
@@ -0,0 +1,13 @@
+register();
diff --git a/vendor/lusitanian/oauth/tests/Mocks/Common/FakeProject/NS/SomeClass.php b/vendor/lusitanian/oauth/tests/Mocks/Common/FakeProject/NS/SomeClass.php
new file mode 100644
index 00000000..c033c4e2
--- /dev/null
+++ b/vendor/lusitanian/oauth/tests/Mocks/Common/FakeProject/NS/SomeClass.php
@@ -0,0 +1,11 @@
+determineRequestUriFromPath($path, $baseApiUri);
+ }
+}
diff --git a/vendor/lusitanian/oauth/tests/Mocks/OAuth1/Service/Fake.php b/vendor/lusitanian/oauth/tests/Mocks/OAuth1/Service/Fake.php
new file mode 100644
index 00000000..5dac52e7
--- /dev/null
+++ b/vendor/lusitanian/oauth/tests/Mocks/OAuth1/Service/Fake.php
@@ -0,0 +1,57 @@
+authorizationMethod = $method;
+ }
+
+ /**
+ * Returns a class constant from ServiceInterface defining the authorization method used for the API
+ * Header is the sane default.
+ *
+ * @return int
+ */
+ protected function getAuthorizationMethod()
+ {
+ switch($this->authorizationMethod) {
+ case 'querystring':
+ return static::AUTHORIZATION_METHOD_QUERY_STRING;
+
+ case 'querystring2':
+ return static::AUTHORIZATION_METHOD_QUERY_STRING_V2;
+
+ case 'bearer':
+ return static::AUTHORIZATION_METHOD_HEADER_BEARER;
+ }
+
+ return parent::getAuthorizationMethod();
+ }
+}
diff --git a/vendor/lusitanian/oauth/tests/Unit/Common/AutoloaderTest.php b/vendor/lusitanian/oauth/tests/Unit/Common/AutoloaderTest.php
new file mode 100644
index 00000000..eebc3408
--- /dev/null
+++ b/vendor/lusitanian/oauth/tests/Unit/Common/AutoloaderTest.php
@@ -0,0 +1,126 @@
+assertTrue($autoloader->register());
+ }
+
+ /**
+ * @covers OAuth\Common\AutoLoader::__construct
+ * @covers OAuth\Common\AutoLoader::register
+ * @covers OAuth\Common\AutoLoader::unregister
+ */
+ public function testUnregister()
+ {
+ $autoloader = new AutoLoader('Test', '/');
+
+ $this->assertTrue($autoloader->register());
+ $this->assertTrue($autoloader->unregister());
+ }
+
+ /**
+ * @covers OAuth\Common\AutoLoader::__construct
+ * @covers OAuth\Common\AutoLoader::register
+ * @covers OAuth\Common\AutoLoader::load
+ */
+ public function testLoadSuccess()
+ {
+ $autoloader = new AutoLoader('FakeProject', dirname(__DIR__) . '/../Mocks/Common');
+
+ $this->assertTrue($autoloader->register());
+
+ $someClass = new \FakeProject\NS\SomeClass();
+
+ $this->assertTrue($someClass->isLoaded());
+ }
+
+ /**
+ * @covers OAuth\Common\AutoLoader::__construct
+ * @covers OAuth\Common\AutoLoader::register
+ * @covers OAuth\Common\AutoLoader::load
+ */
+ public function testLoadSuccessExtraSlashedNamespace()
+ {
+ $autoloader = new AutoLoader('\\\\FakeProject', dirname(__DIR__) . '/../Mocks/Common');
+
+ $this->assertTrue($autoloader->register());
+
+ $someClass = new \FakeProject\NS\SomeClass();
+
+ $this->assertTrue($someClass->isLoaded());
+ }
+
+ /**
+ * @covers OAuth\Common\AutoLoader::__construct
+ * @covers OAuth\Common\AutoLoader::register
+ * @covers OAuth\Common\AutoLoader::load
+ */
+ public function testLoadSuccessExtraForwardSlashedPath()
+ {
+ $autoloader = new AutoLoader('FakeProject', dirname(__DIR__) . '/../Mocks/Common//');
+
+ $this->assertTrue($autoloader->register());
+
+ $someClass = new \FakeProject\NS\SomeClass();
+
+ $this->assertTrue($someClass->isLoaded());
+ }
+
+ /**
+ * @covers OAuth\Common\AutoLoader::__construct
+ * @covers OAuth\Common\AutoLoader::register
+ * @covers OAuth\Common\AutoLoader::load
+ */
+ public function testLoadSuccessExtraBackwardSlashedPath()
+ {
+ $autoloader = new AutoLoader('FakeProject', dirname(__DIR__) . '/../Mocks/Common\\');
+
+ $this->assertTrue($autoloader->register());
+
+ $someClass = new \FakeProject\NS\SomeClass();
+
+ $this->assertTrue($someClass->isLoaded());
+ }
+
+ /**
+ * @covers OAuth\Common\AutoLoader::__construct
+ * @covers OAuth\Common\AutoLoader::register
+ * @covers OAuth\Common\AutoLoader::load
+ */
+ public function testLoadSuccessExtraMixedSlashedPath()
+ {
+ $autoloader = new AutoLoader('FakeProject', dirname(__DIR__) . '/../Mocks/Common\\\\/\\//');
+
+ $this->assertTrue($autoloader->register());
+
+ $someClass = new \FakeProject\NS\SomeClass();
+
+ $this->assertTrue($someClass->isLoaded());
+ }
+
+ /**
+ * @covers OAuth\Common\AutoLoader::__construct
+ * @covers OAuth\Common\AutoLoader::register
+ * @covers OAuth\Common\AutoLoader::load
+ */
+ public function testLoadUnknownClass()
+ {
+ $autoloader = new AutoLoader('FakeProject', dirname(__DIR__) . '/../Mocks/Common\\\\/\\//');
+
+ $this->assertTrue($autoloader->register());
+
+ $this->assertFalse($autoloader->load('IDontExistClass'));
+ }
+}
diff --git a/vendor/lusitanian/oauth/tests/Unit/Common/Consumer/CredentialsTest.php b/vendor/lusitanian/oauth/tests/Unit/Common/Consumer/CredentialsTest.php
new file mode 100644
index 00000000..1a895fbc
--- /dev/null
+++ b/vendor/lusitanian/oauth/tests/Unit/Common/Consumer/CredentialsTest.php
@@ -0,0 +1,51 @@
+assertInstanceOf('\\OAuth\\Common\\Consumer\\CredentialsInterface', $credentials);
+ }
+
+ /**
+ * @covers OAuth\Common\Consumer\Credentials::__construct
+ * @covers OAuth\Common\Consumer\Credentials::getConsumerId
+ */
+ public function testGetConsumerId()
+ {
+ $credentials = new Credentials('foo', 'bar', 'baz');
+
+ $this->assertSame('foo', $credentials->getConsumerId());
+ }
+
+ /**
+ * @covers OAuth\Common\Consumer\Credentials::__construct
+ * @covers OAuth\Common\Consumer\Credentials::getConsumerSecret
+ */
+ public function testGetConsumerSecret()
+ {
+ $credentials = new Credentials('foo', 'bar', 'baz');
+
+ $this->assertSame('bar', $credentials->getConsumerSecret());
+ }
+
+ /**
+ * @covers OAuth\Common\Consumer\Credentials::__construct
+ * @covers OAuth\Common\Consumer\Credentials::getCallbackUrl
+ */
+ public function testGetCallbackUrl()
+ {
+ $credentials = new Credentials('foo', 'bar', 'baz');
+
+ $this->assertSame('baz', $credentials->getCallbackUrl());
+ }
+}
diff --git a/vendor/lusitanian/oauth/tests/Unit/Common/Http/Client/AbstractClientTest.php b/vendor/lusitanian/oauth/tests/Unit/Common/Http/Client/AbstractClientTest.php
new file mode 100644
index 00000000..b3531527
--- /dev/null
+++ b/vendor/lusitanian/oauth/tests/Unit/Common/Http/Client/AbstractClientTest.php
@@ -0,0 +1,67 @@
+getMockForAbstractClass('\\OAuth\\Common\\Http\\Client\\AbstractClient');
+
+ $this->assertInstanceOf('\\OAuth\\Common\\Http\\Client\\ClientInterface', $client);
+ }
+
+ /**
+ * @covers OAuth\Common\Http\Client\AbstractClient::__construct
+ * @covers OAuth\Common\Http\Client\AbstractClient::setMaxRedirects
+ */
+ public function testSetMaxRedirects()
+ {
+ $client = $this->getMockForAbstractClass('\\OAuth\\Common\\Http\\Client\\AbstractClient');
+
+ $this->assertInstanceOf('\\OAuth\\Common\\Http\\Client\\AbstractClient', $client->setMaxRedirects(10));
+ $this->assertInstanceOf('\\OAuth\\Common\\Http\\Client\\ClientInterface', $client->setMaxRedirects(10));
+ }
+
+ /**
+ * @covers OAuth\Common\Http\Client\AbstractClient::__construct
+ * @covers OAuth\Common\Http\Client\AbstractClient::setTimeout
+ */
+ public function testSetTimeout()
+ {
+ $client = $this->getMockForAbstractClass('\\OAuth\\Common\\Http\\Client\\AbstractClient');
+
+ $this->assertInstanceOf('\\OAuth\\Common\\Http\\Client\\AbstractClient', $client->setTimeout(25));
+ $this->assertInstanceOf('\\OAuth\\Common\\Http\\Client\\ClientInterface', $client->setTimeout(25));
+ }
+
+ /**
+ * @covers OAuth\Common\Http\Client\AbstractClient::__construct
+ * @covers OAuth\Common\Http\Client\AbstractClient::normalizeHeaders
+ */
+ public function testNormalizeHeaders()
+ {
+ $client = $this->getMockForAbstractClass('\\OAuth\\Common\\Http\\Client\\AbstractClient');
+
+ $original = array(
+ 'lowercasekey' => 'lowercasevalue',
+ 'UPPERCASEKEY' => 'UPPERCASEVALUE',
+ 'mIxEdCaSeKey' => 'MiXeDcAsEvAlUe',
+ '31i71casekey' => '31i71casevalue',
+ );
+
+ $goal = array(
+ 'lowercasekey' => 'Lowercasekey: lowercasevalue',
+ 'UPPERCASEKEY' => 'Uppercasekey: UPPERCASEVALUE',
+ 'mIxEdCaSeKey' => 'Mixedcasekey: MiXeDcAsEvAlUe',
+ '31i71casekey' => '31i71casekey: 31i71casevalue',
+ );
+
+ $client->normalizeHeaders($original);
+
+ $this->assertSame($goal, $original);
+ }
+}
diff --git a/vendor/lusitanian/oauth/tests/Unit/Common/Http/Client/CurlClientTest.php b/vendor/lusitanian/oauth/tests/Unit/Common/Http/Client/CurlClientTest.php
new file mode 100644
index 00000000..f635ce89
--- /dev/null
+++ b/vendor/lusitanian/oauth/tests/Unit/Common/Http/Client/CurlClientTest.php
@@ -0,0 +1,378 @@
+assertInstanceOf('\\OAuth\\Common\\Http\\Client\\AbstractClient', $client);
+ }
+
+ /**
+ * @covers OAuth\Common\Http\Client\CurlClient::setForceSSL3
+ */
+ public function testSetForceSSL3()
+ {
+ $client = new CurlClient();
+
+ $this->assertInstanceOf('\\OAuth\\Common\\Http\\Client\\CurlClient', $client->setForceSSL3(true));
+ }
+
+ /**
+ * @covers OAuth\Common\Http\Client\CurlClient::retrieveResponse
+ */
+ public function testRetrieveResponseThrowsExceptionOnGetRequestWithBody()
+ {
+ $this->setExpectedException('\\InvalidArgumentException');
+
+ $client = new CurlClient();
+
+ $client->retrieveResponse(
+ $this->getMock('\\OAuth\\Common\\Http\\Uri\\UriInterface'),
+ 'foo',
+ array(),
+ 'GET'
+ );
+ }
+
+ /**
+ * @covers OAuth\Common\Http\Client\CurlClient::retrieveResponse
+ */
+ public function testRetrieveResponseThrowsExceptionOnGetRequestWithBodyMethodConvertedToUpper()
+ {
+ $this->setExpectedException('\\InvalidArgumentException');
+
+ $client = new CurlClient();
+
+ $client->retrieveResponse(
+ $this->getMock('\\OAuth\\Common\\Http\\Uri\\UriInterface'),
+ 'foo',
+ array(),
+ 'get'
+ );
+ }
+
+ /**
+ * @covers OAuth\Common\Http\Client\StreamClient::retrieveResponse
+ * @covers OAuth\Common\Http\Client\StreamClient::generateStreamContext
+ */
+ public function testRetrieveResponseDefaultUserAgent()
+ {
+ $endPoint = $this->getMock('\\OAuth\\Common\\Http\\Uri\\UriInterface');
+ $endPoint->expects($this->any())
+ ->method('getHost')
+ ->will($this->returnValue('httpbin.org'));
+ $endPoint->expects($this->any())
+ ->method('getAbsoluteUri')
+ ->will($this->returnValue('http://httpbin.org/get'));
+
+ $client = new CurlClient();
+
+ $response = $client->retrieveResponse(
+ $endPoint,
+ '',
+ array(),
+ 'get'
+ );
+
+ $response = json_decode($response, true);
+
+ $this->assertSame('PHPoAuthLib', $response['headers']['User-Agent']);
+ }
+
+ /**
+ * @covers OAuth\Common\Http\Client\StreamClient::retrieveResponse
+ * @covers OAuth\Common\Http\Client\StreamClient::generateStreamContext
+ */
+ public function testRetrieveResponseCustomUserAgent()
+ {
+ $endPoint = $this->getMock('\\OAuth\\Common\\Http\\Uri\\UriInterface');
+ $endPoint->expects($this->any())
+ ->method('getHost')
+ ->will($this->returnValue('httpbin.org'));
+ $endPoint->expects($this->any())
+ ->method('getAbsoluteUri')
+ ->will($this->returnValue('http://httpbin.org/get'));
+
+ $client = new CurlClient('My Super Awesome Http Client');
+
+ $response = $client->retrieveResponse(
+ $endPoint,
+ '',
+ array(),
+ 'get'
+ );
+
+ $response = json_decode($response, true);
+
+ $this->assertSame('My Super Awesome Http Client', $response['headers']['User-Agent']);
+ }
+
+ /**
+ * @covers OAuth\Common\Http\Client\CurlClient::retrieveResponse
+ */
+ public function testRetrieveResponseWithCustomContentType()
+ {
+ $endPoint = $this->getMock('\\OAuth\\Common\\Http\\Uri\\UriInterface');
+ $endPoint->expects($this->any())
+ ->method('getHost')
+ ->will($this->returnValue('httpbin.org'));
+ $endPoint->expects($this->any())
+ ->method('getAbsoluteUri')
+ ->will($this->returnValue('http://httpbin.org/get'));
+
+ $client = new CurlClient();
+
+ $response = $client->retrieveResponse(
+ $endPoint,
+ '',
+ array('Content-Type' => 'foo/bar'),
+ 'get'
+ );
+
+ $response = json_decode($response, true);
+
+ $this->assertSame('foo/bar', $response['headers']['Content-Type']);
+ }
+
+ /**
+ * @covers OAuth\Common\Http\Client\CurlClient::retrieveResponse
+ */
+ public function testRetrieveResponseWithFormUrlEncodedContentType()
+ {
+ $endPoint = $this->getMock('\\OAuth\\Common\\Http\\Uri\\UriInterface');
+ $endPoint->expects($this->any())
+ ->method('getHost')
+ ->will($this->returnValue('httpbin.org'));
+ $endPoint->expects($this->any())
+ ->method('getAbsoluteUri')
+ ->will($this->returnValue('http://httpbin.org/post'));
+
+ $client = new CurlClient();
+
+ $response = $client->retrieveResponse(
+ $endPoint,
+ array('foo' => 'bar', 'baz' => 'fab'),
+ array(),
+ 'POST'
+ );
+
+ $response = json_decode($response, true);
+
+ $this->assertSame('application/x-www-form-urlencoded', $response['headers']['Content-Type']);
+ $this->assertEquals(array('foo' => 'bar', 'baz' => 'fab'), $response['form']);
+ }
+
+ /**
+ * @covers OAuth\Common\Http\Client\CurlClient::retrieveResponse
+ */
+ public function testRetrieveResponseHost()
+ {
+ $endPoint = $this->getMock('\\OAuth\\Common\\Http\\Uri\\UriInterface');
+ $endPoint->expects($this->any())
+ ->method('getHost')
+ ->will($this->returnValue('httpbin.org'));
+ $endPoint->expects($this->any())
+ ->method('getAbsoluteUri')
+ ->will($this->returnValue('http://httpbin.org/post'));
+
+ $client = new CurlClient();
+
+ $response = $client->retrieveResponse(
+ $endPoint,
+ array('foo' => 'bar', 'baz' => 'fab'),
+ array(),
+ 'POST'
+ );
+
+ $response = json_decode($response, true);
+
+ $this->assertSame('httpbin.org', $response['headers']['Host']);
+ }
+
+ /**
+ * @covers OAuth\Common\Http\Client\CurlClient::retrieveResponse
+ */
+ public function testRetrieveResponsePostRequestWithRequestBodyAsString()
+ {
+ $endPoint = $this->getMock('\\OAuth\\Common\\Http\\Uri\\UriInterface');
+ $endPoint->expects($this->any())
+ ->method('getHost')
+ ->will($this->returnValue('httpbin.org'));
+ $endPoint->expects($this->any())
+ ->method('getAbsoluteUri')
+ ->will($this->returnValue('http://httpbin.org/post'));
+
+ $formData = array('baz' => 'fab', 'foo' => 'bar');
+
+ $client = new CurlClient();
+
+ $response = $client->retrieveResponse(
+ $endPoint,
+ $formData,
+ array(),
+ 'POST'
+ );
+
+ $response = json_decode($response, true);
+
+ $this->assertSame($formData, $response['form']);
+ }
+
+ /**
+ * @covers OAuth\Common\Http\Client\CurlClient::retrieveResponse
+ */
+ public function testRetrieveResponsePutRequestWithRequestBodyAsString()
+ {
+ $endPoint = $this->getMock('\\OAuth\\Common\\Http\\Uri\\UriInterface');
+ $endPoint->expects($this->any())
+ ->method('getHost')
+ ->will($this->returnValue('httpbin.org'));
+ $endPoint->expects($this->any())
+ ->method('getAbsoluteUri')
+ ->will($this->returnValue('http://httpbin.org/put'));
+
+ $formData = array('baz' => 'fab', 'foo' => 'bar');
+
+ $client = new CurlClient();
+
+ $response = $client->retrieveResponse(
+ $endPoint,
+ $formData,
+ array(),
+ 'PUT'
+ );
+
+ $response = json_decode($response, true);
+
+ $this->assertSame($formData, $response['form']);
+ }
+
+ /**
+ * @covers OAuth\Common\Http\Client\CurlClient::retrieveResponse
+ */
+ public function testRetrieveResponsePutRequestWithRequestBodyAsStringNoRedirects()
+ {
+ $endPoint = $this->getMock('\\OAuth\\Common\\Http\\Uri\\UriInterface');
+ $endPoint->expects($this->any())
+ ->method('getHost')
+ ->will($this->returnValue('httpbin.org'));
+ $endPoint->expects($this->any())
+ ->method('getAbsoluteUri')
+ ->will($this->returnValue('http://httpbin.org/put'));
+
+ $formData = array('baz' => 'fab', 'foo' => 'bar');
+
+ $client = new CurlClient();
+
+ $client->setMaxRedirects(0);
+
+ $response = $client->retrieveResponse(
+ $endPoint,
+ $formData,
+ array(),
+ 'PUT'
+ );
+
+ $response = json_decode($response, true);
+
+ $this->assertSame($formData, $response['form']);
+ }
+
+ /**
+ * @covers OAuth\Common\Http\Client\CurlClient::retrieveResponse
+ */
+ public function testRetrieveResponseWithForcedSsl3()
+ {
+ $endPoint = $this->getMock('\\OAuth\\Common\\Http\\Uri\\UriInterface');
+ $endPoint->expects($this->any())
+ ->method('getHost')
+ ->will($this->returnValue('httpbin.org'));
+ $endPoint->expects($this->any())
+ ->method('getAbsoluteUri')
+ ->will($this->returnValue('https://httpbin.org/get'));
+
+ $client = new CurlClient();
+
+ $client->setForceSSL3(true);
+
+ $response = $client->retrieveResponse(
+ $endPoint,
+ '',
+ array('Content-Type' => 'foo/bar'),
+ 'get'
+ );
+
+ $response = json_decode($response, true);
+
+ $this->assertSame('foo/bar', $response['headers']['Content-Type']);
+ }
+
+ /**
+ * @covers OAuth\Common\Http\Client\CurlClient::retrieveResponse
+ */
+ public function testRetrieveResponseThrowsExceptionOnInvalidUrl()
+ {
+ $this->setExpectedException('\\OAuth\\Common\\Http\\Exception\\TokenResponseException');
+
+ $endPoint = $this->getMock('\\OAuth\\Common\\Http\\Uri\\UriInterface');
+ $endPoint->expects($this->any())
+ ->method('getHost')
+ ->will($this->returnValue('jkehfkefcmekjhcnkerjh'));
+ $endPoint->expects($this->any())
+ ->method('getAbsoluteUri')
+ ->will($this->returnValue('jkehfkefcmekjhcnkerjh'));
+
+ $client = new CurlClient();
+
+ $client->setForceSSL3(true);
+
+ $response = $client->retrieveResponse(
+ $endPoint,
+ '',
+ array('Content-Type' => 'foo/bar'),
+ 'get'
+ );
+
+ $response = json_decode($response, true);
+
+ $this->assertSame('foo/bar', $response['headers']['Content-Type']);
+ }
+
+ public function testAdditionalParameters()
+ {
+ $endPoint = $this->getMock('\\OAuth\\Common\\Http\\Uri\\UriInterface');
+ $endPoint->expects($this->any())
+ ->method('getHost')
+ ->will($this->returnValue('httpbin.org'));
+ $endPoint->expects($this->any())
+ ->method('getAbsoluteUri')
+ ->will($this->returnValue('http://httpbin.org/gzip'));
+
+ $client = new CurlClient();
+ $client->setCurlParameters(array(
+ CURLOPT_ENCODING => 'gzip',
+ ));
+
+ $response = $client->retrieveResponse(
+ $endPoint,
+ '',
+ array(),
+ 'get'
+ );
+
+ $response = json_decode($response, true);
+
+ $this->assertNotNull($response);
+ $this->assertSame('gzip', $response['headers']['Accept-Encoding']);
+ $this->assertTrue($response['gzipped']);
+ }
+}
diff --git a/vendor/lusitanian/oauth/tests/Unit/Common/Http/Client/StreamClientTest.php b/vendor/lusitanian/oauth/tests/Unit/Common/Http/Client/StreamClientTest.php
new file mode 100644
index 00000000..f634f406
--- /dev/null
+++ b/vendor/lusitanian/oauth/tests/Unit/Common/Http/Client/StreamClientTest.php
@@ -0,0 +1,283 @@
+assertInstanceOf('\\OAuth\\Common\\Http\\Client\\AbstractClient', $client);
+ }
+
+ /**
+ * @covers OAuth\Common\Http\Client\StreamClient::retrieveResponse
+ */
+ public function testRetrieveResponseThrowsExceptionOnGetRequestWithBody()
+ {
+ $this->setExpectedException('\\InvalidArgumentException');
+
+ $client = new StreamClient();
+
+ $client->retrieveResponse(
+ $this->getMock('\\OAuth\\Common\\Http\\Uri\\UriInterface'),
+ 'foo',
+ array(),
+ 'GET'
+ );
+ }
+
+ /**
+ * @covers OAuth\Common\Http\Client\StreamClient::retrieveResponse
+ */
+ public function testRetrieveResponseThrowsExceptionOnGetRequestWithBodyMethodConvertedToUpper()
+ {
+ $this->setExpectedException('\\InvalidArgumentException');
+
+ $client = new StreamClient();
+
+ $client->retrieveResponse(
+ $this->getMock('\\OAuth\\Common\\Http\\Uri\\UriInterface'),
+ 'foo',
+ array(),
+ 'get'
+ );
+ }
+
+ /**
+ * @covers OAuth\Common\Http\Client\StreamClient::retrieveResponse
+ * @covers OAuth\Common\Http\Client\StreamClient::generateStreamContext
+ */
+ public function testRetrieveResponseDefaultUserAgent()
+ {
+ $endPoint = $this->getMock('\\OAuth\\Common\\Http\\Uri\\UriInterface');
+ $endPoint->expects($this->any())
+ ->method('getHost')
+ ->will($this->returnValue('httpbin.org'));
+ $endPoint->expects($this->any())
+ ->method('getAbsoluteUri')
+ ->will($this->returnValue('http://httpbin.org/get'));
+
+ $client = new StreamClient();
+
+ $response = $client->retrieveResponse(
+ $endPoint,
+ '',
+ array(),
+ 'get'
+ );
+
+ $response = json_decode($response, true);
+
+ $this->assertSame('PHPoAuthLib', $response['headers']['User-Agent']);
+ }
+
+ /**
+ * @covers OAuth\Common\Http\Client\StreamClient::retrieveResponse
+ * @covers OAuth\Common\Http\Client\StreamClient::generateStreamContext
+ */
+ public function testRetrieveResponseCustomUserAgent()
+ {
+ $endPoint = $this->getMock('\\OAuth\\Common\\Http\\Uri\\UriInterface');
+ $endPoint->expects($this->any())
+ ->method('getHost')
+ ->will($this->returnValue('httpbin.org'));
+ $endPoint->expects($this->any())
+ ->method('getAbsoluteUri')
+ ->will($this->returnValue('http://httpbin.org/get'));
+
+ $client = new StreamClient('My Super Awesome Http Client');
+
+ $response = $client->retrieveResponse(
+ $endPoint,
+ '',
+ array(),
+ 'get'
+ );
+
+ $response = json_decode($response, true);
+
+ $this->assertSame('My Super Awesome Http Client', $response['headers']['User-Agent']);
+ }
+
+ /**
+ * @covers OAuth\Common\Http\Client\StreamClient::retrieveResponse
+ * @covers OAuth\Common\Http\Client\StreamClient::generateStreamContext
+ */
+ public function testRetrieveResponseWithCustomContentType()
+ {
+ $endPoint = $this->getMock('\\OAuth\\Common\\Http\\Uri\\UriInterface');
+ $endPoint->expects($this->any())
+ ->method('getHost')
+ ->will($this->returnValue('httpbin.org'));
+ $endPoint->expects($this->any())
+ ->method('getAbsoluteUri')
+ ->will($this->returnValue('http://httpbin.org/get'));
+
+ $client = new StreamClient();
+
+ $response = $client->retrieveResponse(
+ $endPoint,
+ '',
+ array('Content-Type' => 'foo/bar'),
+ 'get'
+ );
+
+ $response = json_decode($response, true);
+
+ $this->assertSame('foo/bar', $response['headers']['Content-Type']);
+ }
+
+ /**
+ * @covers OAuth\Common\Http\Client\StreamClient::retrieveResponse
+ * @covers OAuth\Common\Http\Client\StreamClient::generateStreamContext
+ */
+ public function testRetrieveResponseWithFormUrlEncodedContentType()
+ {
+ $endPoint = $this->getMock('\\OAuth\\Common\\Http\\Uri\\UriInterface');
+ $endPoint->expects($this->any())
+ ->method('getHost')
+ ->will($this->returnValue('httpbin.org'));
+ $endPoint->expects($this->any())
+ ->method('getAbsoluteUri')
+ ->will($this->returnValue('http://httpbin.org/post'));
+
+ $client = new StreamClient();
+
+ $response = $client->retrieveResponse(
+ $endPoint,
+ array('foo' => 'bar', 'baz' => 'fab'),
+ array(),
+ 'POST'
+ );
+
+ $response = json_decode($response, true);
+
+ $this->assertSame('application/x-www-form-urlencoded', $response['headers']['Content-Type']);
+ $this->assertEquals(array('foo' => 'bar', 'baz' => 'fab'), $response['form']);
+ }
+
+ /**
+ * @covers OAuth\Common\Http\Client\StreamClient::retrieveResponse
+ * @covers OAuth\Common\Http\Client\StreamClient::generateStreamContext
+ */
+ public function testRetrieveResponseHost()
+ {
+ $endPoint = $this->getMock('\\OAuth\\Common\\Http\\Uri\\UriInterface');
+ $endPoint->expects($this->any())
+ ->method('getHost')
+ ->will($this->returnValue('httpbin.org'));
+ $endPoint->expects($this->any())
+ ->method('getAbsoluteUri')
+ ->will($this->returnValue('http://httpbin.org/post'));
+
+ $client = new StreamClient();
+
+ $response = $client->retrieveResponse(
+ $endPoint,
+ array('foo' => 'bar', 'baz' => 'fab'),
+ array(),
+ 'POST'
+ );
+
+ $response = json_decode($response, true);
+
+ $this->assertSame('httpbin.org', $response['headers']['Host']);
+ }
+
+ /**
+ * @covers OAuth\Common\Http\Client\StreamClient::retrieveResponse
+ * @covers OAuth\Common\Http\Client\StreamClient::generateStreamContext
+ */
+ public function testRetrieveResponsePostRequestWithRequestBodyAsString()
+ {
+ $endPoint = $this->getMock('\\OAuth\\Common\\Http\\Uri\\UriInterface');
+ $endPoint->expects($this->any())
+ ->method('getHost')
+ ->will($this->returnValue('httpbin.org'));
+ $endPoint->expects($this->any())
+ ->method('getAbsoluteUri')
+ ->will($this->returnValue('http://httpbin.org/post'));
+
+ $formData = array('baz' => 'fab', 'foo' => 'bar');
+
+ $client = new StreamClient();
+
+ $response = $client->retrieveResponse(
+ $endPoint,
+ $formData,
+ array(),
+ 'POST'
+ );
+
+ $response = json_decode($response, true);
+
+ $this->assertSame($formData, $response['form']);
+ }
+
+ /**
+ * @covers OAuth\Common\Http\Client\StreamClient::retrieveResponse
+ * @covers OAuth\Common\Http\Client\StreamClient::generateStreamContext
+ */
+ public function testRetrieveResponsePutRequestWithRequestBodyAsString()
+ {
+ $endPoint = $this->getMock('\\OAuth\\Common\\Http\\Uri\\UriInterface');
+ $endPoint->expects($this->any())
+ ->method('getHost')
+ ->will($this->returnValue('httpbin.org'));
+ $endPoint->expects($this->any())
+ ->method('getAbsoluteUri')
+ ->will($this->returnValue('http://httpbin.org/put'));
+
+ $formData = array('baz' => 'fab', 'foo' => 'bar');
+
+ $client = new StreamClient();
+
+ $response = $client->retrieveResponse(
+ $endPoint,
+ $formData,
+ array(),
+ 'PUT'
+ );
+
+ $response = json_decode($response, true);
+
+ $this->assertSame($formData, $response['form']);
+ }
+
+ /**
+ * @covers OAuth\Common\Http\Client\StreamClient::retrieveResponse
+ * @covers OAuth\Common\Http\Client\StreamClient::generateStreamContext
+ */
+ public function testRetrieveResponseThrowsExceptionOnInvalidRequest()
+ {
+ $this->setExpectedException('\\OAuth\\Common\\Http\\Exception\\TokenResponseException');
+
+ $endPoint = $this->getMock('\\OAuth\\Common\\Http\\Uri\\UriInterface');
+ $endPoint->expects($this->any())
+ ->method('getHost')
+ ->will($this->returnValue('dskjhfckjhekrsfhkehfkreljfrekljfkre'));
+ $endPoint->expects($this->any())
+ ->method('getAbsoluteUri')
+ ->will($this->returnValue('dskjhfckjhekrsfhkehfkreljfrekljfkre'));
+
+ $client = new StreamClient();
+
+ $response = $client->retrieveResponse(
+ $endPoint,
+ '',
+ array('Content-Type' => 'foo/bar'),
+ 'get'
+ );
+
+ $response = json_decode($response, true);
+
+ $this->assertSame('foo/bar', $response['headers']['Content-Type']);
+ }
+}
diff --git a/vendor/lusitanian/oauth/tests/Unit/Common/Http/HttpClientsTest.php b/vendor/lusitanian/oauth/tests/Unit/Common/Http/HttpClientsTest.php
new file mode 100644
index 00000000..6fa9eace
--- /dev/null
+++ b/vendor/lusitanian/oauth/tests/Unit/Common/Http/HttpClientsTest.php
@@ -0,0 +1,171 @@
+
+ * @copyright Copyright (c) 2012 The authors
+ * @license http://www.opensource.org/licenses/mit-license.html MIT License
+ */
+
+namespace OAuth\Unit\Common\Http;
+
+use OAuth\Common\Http\Uri\Uri;
+use OAuth\Common\Http\Uri\UriInterface;
+use OAuth\Common\Http\Client;
+
+class HttpClientsTest extends \PHPUnit_Framework_TestCase
+{
+ /**
+ * @var object|\OAuth\Common\Http\Client\ClientInterface[]
+ */
+ protected $clients;
+
+ public function setUp()
+ {
+ $streamClient = new Client\StreamClient();
+ $streamClient->setTimeout(3);
+
+ $curlClient = new Client\CurlClient();
+ $curlClient->setTimeout(3);
+
+ $this->clients[] = $streamClient;
+ $this->clients[] = $curlClient;
+ }
+
+ public function tearDown()
+ {
+ foreach ($this->clients as $client) {
+ unset($client);
+ }
+ }
+
+ /**
+ * Test that extra headers are passed properly
+ */
+ public function testHeaders()
+ {
+ $testUri = new Uri('http://httpbin.org/get');
+
+ $me = $this;
+ $headerCb = function ($response) use ($me) {
+ $data = json_decode($response, true);
+ $me->assertEquals('extraheadertest', $data['headers']['Testingheader']);
+ };
+
+ $this->__doTestRetrieveResponse($testUri, array(), array('Testingheader' => 'extraheadertest'), 'GET', $headerCb);
+ }
+
+ /**
+ * Tests that we get an exception for a >= 400 status code
+ */
+ public function testException()
+ {
+ // sending a post here should get us a 405 which should trigger an exception
+ $testUri = new Uri('http://httpbin.org/delete');
+ foreach ($this->clients as $client) {
+ $this->setExpectedException('OAuth\Common\Http\Exception\TokenResponseException');
+ $client->retrieveResponse($testUri, array('blah' => 'blih'));
+ }
+ }
+
+ /**
+ * Tests the DELETE method
+ */
+ public function testDelete()
+ {
+ $testUri = new Uri('http://httpbin.org/delete');
+
+ $me = $this;
+ $deleteTestCb = function ($response) use ($me) {
+ $data = json_decode($response, true);
+ $me->assertEquals('', $data['data']);
+ };
+
+ $this->__doTestRetrieveResponse($testUri, array(), array(), 'DELETE', $deleteTestCb);
+ }
+
+ /**
+ * Tests the PUT method
+ */
+ public function testPut()
+ {
+ $testUri = new Uri('http://httpbin.org/put');
+
+ $me = $this;
+ $putTestCb = function ($response) use ($me) {
+ // verify the put response
+ $data = json_decode($response, true);
+ $me->assertEquals(json_encode(array('testKey' => 'testValue')), $data['data']);
+ };
+
+ $this->__doTestRetrieveResponse($testUri, json_encode(array('testKey' => 'testValue')), array('Content-Type' => 'application/json'), 'PUT', $putTestCb);
+ }
+
+ /**
+ * Tests the POST method
+ */
+ public function testPost()
+ {
+ // http test server
+ $testUri = new Uri('http://httpbin.org/post');
+
+ $me = $this;
+ $postTestCb = function ($response) use ($me) {
+ // verify the post response
+ $data = json_decode($response, true);
+ // note that we check this because the retrieveResponse wrapper function automatically adds a content-type
+ // if there isn't one and it
+ $me->assertEquals('testValue', $data['form']['testKey']);
+ };
+
+ $this->__doTestRetrieveResponse($testUri, array('testKey' => 'testValue'), array(), 'POST', $postTestCb);
+ }
+
+ /**
+ * Expect exception when we try to send a GET request with a body
+ */
+ public function testInvalidGet()
+ {
+ $testUri = new Uri('http://site.net');
+
+ foreach ($this->clients as $client) {
+ $this->setExpectedException('InvalidArgumentException');
+ $client->retrieveResponse($testUri, array('blah' => 'blih'), array(), 'GET');
+ }
+ }
+
+ /**
+ * Tests the GET method
+ */
+ public function testGet()
+ {
+ // test uri
+ $testUri = new Uri('http://httpbin.org/get?testKey=testValue');
+
+ $me = $this;
+ $getTestCb = function ($response) use ($me) {
+ $data = json_decode($response, true);
+ $me->assertEquals('testValue', $data['args']['testKey']);
+ };
+
+ $this->__doTestRetrieveResponse($testUri, array(), array(), 'GET', $getTestCb);
+ }
+
+ /**
+ * Test on all HTTP clients.
+ *
+ * @param UriInterface $uri
+ * @param array $param
+ * @param array $header
+ * @param string $method
+ * @param \Closure $responseCallback
+ */
+ protected function __doTestRetrieveResponse(UriInterface $uri, $param, array $header, $method, $responseCallback)
+ {
+ foreach ($this->clients as $client) {
+ $response = $client->retrieveResponse($uri, $param, $header, $method);
+ $responseCallback($response, $client);
+ }
+ }
+}
diff --git a/vendor/lusitanian/oauth/tests/Unit/Common/Http/Uri/UriFactoryTest.php b/vendor/lusitanian/oauth/tests/Unit/Common/Http/Uri/UriFactoryTest.php
new file mode 100644
index 00000000..ea743509
--- /dev/null
+++ b/vendor/lusitanian/oauth/tests/Unit/Common/Http/Uri/UriFactoryTest.php
@@ -0,0 +1,331 @@
+assertInstanceOf('\\OAuth\\Common\\Http\\Uri\\UriFactoryInterface', $factory);
+ }
+
+ /**
+ * @covers OAuth\Common\Http\Uri\UriFactory::createFromSuperGlobalArray
+ * @covers OAuth\Common\Http\Uri\UriFactory::attemptProxyStyleParse
+ */
+ public function testCreateFromSuperGlobalArrayUsingProxyStyle()
+ {
+ $factory = new UriFactory();
+
+ $uri = $factory->createFromSuperGlobalArray(array('REQUEST_URI' => 'http://example.com'));
+
+ $this->assertInstanceOf(
+ '\\OAuth\\Common\\Http\\Uri\\UriInterface',
+ $uri
+ );
+
+ $this->assertSame('http://example.com', $uri->getAbsoluteUri());
+ }
+
+ /**
+ * @covers OAuth\Common\Http\Uri\UriFactory::createFromSuperGlobalArray
+ * @covers OAuth\Common\Http\Uri\UriFactory::attemptProxyStyleParse
+ * @covers OAuth\Common\Http\Uri\UriFactory::detectScheme
+ * @covers OAuth\Common\Http\Uri\UriFactory::detectHost
+ * @covers OAuth\Common\Http\Uri\UriFactory::detectPort
+ * @covers OAuth\Common\Http\Uri\UriFactory::detectPath
+ * @covers OAuth\Common\Http\Uri\UriFactory::detectQuery
+ * @covers OAuth\Common\Http\Uri\UriFactory::createFromParts
+ */
+ public function testCreateFromSuperGlobalArrayHttp()
+ {
+ $factory = new UriFactory();
+
+ $uri = $factory->createFromSuperGlobalArray(array(
+ 'HTTPS' => 'off',
+ 'HTTP_HOST' => 'example.com',
+ 'REQUEST_URI' => '/foo',
+ 'QUERY_STRING' => 'param1=value1',
+ ));
+
+ $this->assertInstanceOf(
+ '\\OAuth\\Common\\Http\\Uri\\UriInterface',
+ $uri
+ );
+
+ $this->assertSame('http://example.com/foo?param1=value1', $uri->getAbsoluteUri());
+ }
+
+ /**
+ * This looks wonky David. Should the port really fallback to 80 even when supplying https as scheme?
+ *
+ * @covers OAuth\Common\Http\Uri\UriFactory::createFromSuperGlobalArray
+ * @covers OAuth\Common\Http\Uri\UriFactory::attemptProxyStyleParse
+ * @covers OAuth\Common\Http\Uri\UriFactory::detectScheme
+ * @covers OAuth\Common\Http\Uri\UriFactory::detectHost
+ * @covers OAuth\Common\Http\Uri\UriFactory::detectPort
+ * @covers OAuth\Common\Http\Uri\UriFactory::detectPath
+ * @covers OAuth\Common\Http\Uri\UriFactory::detectQuery
+ * @covers OAuth\Common\Http\Uri\UriFactory::createFromParts
+ */
+ public function testCreateFromSuperGlobalArrayHttps()
+ {
+ $factory = new UriFactory();
+
+ $uri = $factory->createFromSuperGlobalArray(array(
+ 'HTTPS' => 'on',
+ 'HTTP_HOST' => 'example.com',
+ 'REQUEST_URI' => '/foo',
+ 'QUERY_STRING' => 'param1=value1',
+ ));
+
+ $this->assertInstanceOf(
+ '\\OAuth\\Common\\Http\\Uri\\UriInterface',
+ $uri
+ );
+
+ $this->assertSame('https://example.com:80/foo?param1=value1', $uri->getAbsoluteUri());
+ }
+
+ /**
+ * @covers OAuth\Common\Http\Uri\UriFactory::createFromSuperGlobalArray
+ * @covers OAuth\Common\Http\Uri\UriFactory::attemptProxyStyleParse
+ * @covers OAuth\Common\Http\Uri\UriFactory::detectScheme
+ * @covers OAuth\Common\Http\Uri\UriFactory::detectHost
+ * @covers OAuth\Common\Http\Uri\UriFactory::detectPort
+ * @covers OAuth\Common\Http\Uri\UriFactory::detectPath
+ * @covers OAuth\Common\Http\Uri\UriFactory::detectQuery
+ * @covers OAuth\Common\Http\Uri\UriFactory::createFromParts
+ */
+ public function testCreateFromSuperGlobalArrayPortSupplied()
+ {
+ $factory = new UriFactory();
+
+ $uri = $factory->createFromSuperGlobalArray(array(
+ 'HTTP_HOST' => 'example.com',
+ 'SERVER_PORT' => 21,
+ 'REQUEST_URI' => '/foo',
+ 'QUERY_STRING' => 'param1=value1',
+ ));
+
+ $this->assertInstanceOf(
+ '\\OAuth\\Common\\Http\\Uri\\UriInterface',
+ $uri
+ );
+
+ $this->assertSame('http://example.com:21/foo?param1=value1', $uri->getAbsoluteUri());
+ }
+
+ /**
+ * @covers OAuth\Common\Http\Uri\UriFactory::createFromSuperGlobalArray
+ * @covers OAuth\Common\Http\Uri\UriFactory::attemptProxyStyleParse
+ * @covers OAuth\Common\Http\Uri\UriFactory::detectScheme
+ * @covers OAuth\Common\Http\Uri\UriFactory::detectHost
+ * @covers OAuth\Common\Http\Uri\UriFactory::detectPort
+ * @covers OAuth\Common\Http\Uri\UriFactory::detectPath
+ * @covers OAuth\Common\Http\Uri\UriFactory::detectQuery
+ * @covers OAuth\Common\Http\Uri\UriFactory::createFromParts
+ */
+ public function testCreateFromSuperGlobalArrayPortNotSet()
+ {
+ $factory = new UriFactory();
+
+ $uri = $factory->createFromSuperGlobalArray(array(
+ 'HTTP_HOST' => 'example.com',
+ 'REQUEST_URI' => '/foo',
+ 'QUERY_STRING' => 'param1=value1',
+ ));
+
+ $this->assertInstanceOf(
+ '\\OAuth\\Common\\Http\\Uri\\UriInterface',
+ $uri
+ );
+
+ $this->assertSame('http://example.com/foo?param1=value1', $uri->getAbsoluteUri());
+ }
+
+ /**
+ * @covers OAuth\Common\Http\Uri\UriFactory::createFromSuperGlobalArray
+ * @covers OAuth\Common\Http\Uri\UriFactory::attemptProxyStyleParse
+ * @covers OAuth\Common\Http\Uri\UriFactory::detectScheme
+ * @covers OAuth\Common\Http\Uri\UriFactory::detectHost
+ * @covers OAuth\Common\Http\Uri\UriFactory::detectPort
+ * @covers OAuth\Common\Http\Uri\UriFactory::detectPath
+ * @covers OAuth\Common\Http\Uri\UriFactory::detectQuery
+ * @covers OAuth\Common\Http\Uri\UriFactory::createFromParts
+ */
+ public function testCreateFromSuperGlobalArrayRequestUriSet()
+ {
+ $factory = new UriFactory();
+
+ $uri = $factory->createFromSuperGlobalArray(array(
+ 'HTTP_HOST' => 'example.com',
+ 'REQUEST_URI' => '/foo',
+ 'QUERY_STRING' => 'param1=value1',
+ ));
+
+ $this->assertInstanceOf(
+ '\\OAuth\\Common\\Http\\Uri\\UriInterface',
+ $uri
+ );
+
+ $this->assertSame('http://example.com/foo?param1=value1', $uri->getAbsoluteUri());
+ }
+
+ /**
+ * @covers OAuth\Common\Http\Uri\UriFactory::createFromSuperGlobalArray
+ * @covers OAuth\Common\Http\Uri\UriFactory::attemptProxyStyleParse
+ * @covers OAuth\Common\Http\Uri\UriFactory::detectScheme
+ * @covers OAuth\Common\Http\Uri\UriFactory::detectHost
+ * @covers OAuth\Common\Http\Uri\UriFactory::detectPort
+ * @covers OAuth\Common\Http\Uri\UriFactory::detectPath
+ * @covers OAuth\Common\Http\Uri\UriFactory::detectQuery
+ * @covers OAuth\Common\Http\Uri\UriFactory::createFromParts
+ */
+ public function testCreateFromSuperGlobalArrayRedirectUrlSet()
+ {
+ $factory = new UriFactory();
+
+ $uri = $factory->createFromSuperGlobalArray(array(
+ 'HTTP_HOST' => 'example.com',
+ 'REDIRECT_URL' => '/foo',
+ 'QUERY_STRING' => 'param1=value1',
+ ));
+
+ $this->assertInstanceOf(
+ '\\OAuth\\Common\\Http\\Uri\\UriInterface',
+ $uri
+ );
+
+ $this->assertSame('http://example.com/foo?param1=value1', $uri->getAbsoluteUri());
+ }
+
+ /**
+ * @covers OAuth\Common\Http\Uri\UriFactory::createFromSuperGlobalArray
+ * @covers OAuth\Common\Http\Uri\UriFactory::attemptProxyStyleParse
+ * @covers OAuth\Common\Http\Uri\UriFactory::detectScheme
+ * @covers OAuth\Common\Http\Uri\UriFactory::detectHost
+ * @covers OAuth\Common\Http\Uri\UriFactory::detectPort
+ * @covers OAuth\Common\Http\Uri\UriFactory::detectPath
+ * @covers OAuth\Common\Http\Uri\UriFactory::detectQuery
+ * @covers OAuth\Common\Http\Uri\UriFactory::createFromParts
+ */
+ public function testCreateFromSuperGlobalArrayThrowsExceptionOnDetectingPathMissingIndices()
+ {
+ $factory = new UriFactory();
+
+ $this->setExpectedException('\\RuntimeException');
+
+ $uri = $factory->createFromSuperGlobalArray(array(
+ 'HTTP_HOST' => 'example.com',
+ 'QUERY_STRING' => 'param1=value1',
+ ));
+ }
+
+ /**
+ * @covers OAuth\Common\Http\Uri\UriFactory::createFromSuperGlobalArray
+ * @covers OAuth\Common\Http\Uri\UriFactory::attemptProxyStyleParse
+ * @covers OAuth\Common\Http\Uri\UriFactory::detectScheme
+ * @covers OAuth\Common\Http\Uri\UriFactory::detectHost
+ * @covers OAuth\Common\Http\Uri\UriFactory::detectPort
+ * @covers OAuth\Common\Http\Uri\UriFactory::detectPath
+ * @covers OAuth\Common\Http\Uri\UriFactory::detectQuery
+ * @covers OAuth\Common\Http\Uri\UriFactory::createFromParts
+ */
+ public function testCreateFromSuperGlobalArrayWithQueryString()
+ {
+ $factory = new UriFactory();
+
+ $uri = $factory->createFromSuperGlobalArray(array(
+ 'HTTP_HOST' => 'example.com',
+ 'REQUEST_URI' => '/foo?param1=value1',
+ 'QUERY_STRING' => 'param1=value1',
+ ));
+
+ $this->assertInstanceOf(
+ '\\OAuth\\Common\\Http\\Uri\\UriInterface',
+ $uri
+ );
+
+ $this->assertSame('http://example.com/foo?param1=value1', $uri->getAbsoluteUri());
+ }
+
+ /**
+ * @covers OAuth\Common\Http\Uri\UriFactory::createFromSuperGlobalArray
+ * @covers OAuth\Common\Http\Uri\UriFactory::attemptProxyStyleParse
+ * @covers OAuth\Common\Http\Uri\UriFactory::detectScheme
+ * @covers OAuth\Common\Http\Uri\UriFactory::detectHost
+ * @covers OAuth\Common\Http\Uri\UriFactory::detectPort
+ * @covers OAuth\Common\Http\Uri\UriFactory::detectPath
+ * @covers OAuth\Common\Http\Uri\UriFactory::detectQuery
+ * @covers OAuth\Common\Http\Uri\UriFactory::createFromParts
+ */
+ public function testCreateFromSuperGlobalArrayWithoutQueryString()
+ {
+ $factory = new UriFactory();
+
+ $uri = $factory->createFromSuperGlobalArray(array(
+ 'HTTP_HOST' => 'example.com',
+ 'REQUEST_URI' => '/foo',
+ ));
+
+ $this->assertInstanceOf(
+ '\\OAuth\\Common\\Http\\Uri\\UriInterface',
+ $uri
+ );
+
+ $this->assertSame('http://example.com/foo', $uri->getAbsoluteUri());
+ }
+
+ /**
+ * @covers OAuth\Common\Http\Uri\UriFactory::createFromSuperGlobalArray
+ * @covers OAuth\Common\Http\Uri\UriFactory::attemptProxyStyleParse
+ * @covers OAuth\Common\Http\Uri\UriFactory::detectScheme
+ * @covers OAuth\Common\Http\Uri\UriFactory::detectHost
+ * @covers OAuth\Common\Http\Uri\UriFactory::detectPort
+ * @covers OAuth\Common\Http\Uri\UriFactory::detectPath
+ * @covers OAuth\Common\Http\Uri\UriFactory::detectQuery
+ * @covers OAuth\Common\Http\Uri\UriFactory::createFromParts
+ */
+ public function testCreateFromSuperGlobalArrayHostWithColon()
+ {
+ $factory = new UriFactory();
+
+ $uri = $factory->createFromSuperGlobalArray(array(
+ 'HTTP_HOST' => 'example.com:80',
+ 'REQUEST_URI' => '/foo',
+ ));
+
+ $this->assertInstanceOf(
+ '\\OAuth\\Common\\Http\\Uri\\UriInterface',
+ $uri
+ );
+
+ $this->assertSame('http://example.com/foo', $uri->getAbsoluteUri());
+ }
+
+ /**
+ * @covers OAuth\Common\Http\Uri\UriFactory::createFromAbsolute
+ */
+ public function testCreateFromAbsolute()
+ {
+ $factory = new UriFactory();
+
+ $uri = $factory->createFromAbsolute('http://example.com');
+
+ $this->assertInstanceOf(
+ '\\OAuth\\Common\\Http\\Uri\\UriInterface',
+ $uri
+ );
+
+ $this->assertSame('http://example.com', $uri->getAbsoluteUri());
+ }
+}
diff --git a/vendor/lusitanian/oauth/tests/Unit/Common/Http/Uri/UriTest.php b/vendor/lusitanian/oauth/tests/Unit/Common/Http/Uri/UriTest.php
new file mode 100644
index 00000000..bc158ffa
--- /dev/null
+++ b/vendor/lusitanian/oauth/tests/Unit/Common/Http/Uri/UriTest.php
@@ -0,0 +1,898 @@
+assertInstanceOf('\\OAuth\\Common\\Http\\Uri\\UriInterface', $uri);
+ }
+
+ /**
+ * @covers OAuth\Common\Http\Uri\Uri::__construct
+ * @covers OAuth\Common\Http\Uri\Uri::parseUri
+ */
+ public function testConstructThrowsExceptionOnInvalidUri()
+ {
+ $this->setExpectedException('\\InvalidArgumentException');
+
+ // http://lxr.php.net/xref/PHP_5_4/ext/standard/tests/url/urls.inc#92
+ $uri = new Uri('http://@:/');
+ }
+
+ /**
+ * @covers OAuth\Common\Http\Uri\Uri::__construct
+ * @covers OAuth\Common\Http\Uri\Uri::parseUri
+ */
+ public function testConstructThrowsExceptionOnUriWithoutScheme()
+ {
+ $this->setExpectedException('\\InvalidArgumentException');
+
+ $uri = new Uri('www.pieterhordijk.com');
+ }
+
+ /**
+ * @covers OAuth\Common\Http\Uri\Uri::__construct
+ * @covers OAuth\Common\Http\Uri\Uri::parseUri
+ * @covers OAuth\Common\Http\Uri\Uri::getScheme
+ */
+ public function testGetScheme()
+ {
+ $uri = new Uri('http://example.com');
+
+ $this->assertSame('http', $uri->getScheme());
+ }
+
+ /**
+ * @covers OAuth\Common\Http\Uri\Uri::__construct
+ * @covers OAuth\Common\Http\Uri\Uri::parseUri
+ * @covers OAuth\Common\Http\Uri\Uri::setUserInfo
+ * @covers OAuth\Common\Http\Uri\Uri::protectUserInfo
+ * @covers OAuth\Common\Http\Uri\Uri::getUserInfo
+ */
+ public function testGetUserInfo()
+ {
+ $uri = new Uri('http://peehaa@example.com');
+
+ $this->assertSame('peehaa', $uri->getUserInfo());
+ }
+
+ /**
+ * @covers OAuth\Common\Http\Uri\Uri::__construct
+ * @covers OAuth\Common\Http\Uri\Uri::parseUri
+ * @covers OAuth\Common\Http\Uri\Uri::setUserInfo
+ * @covers OAuth\Common\Http\Uri\Uri::protectUserInfo
+ * @covers OAuth\Common\Http\Uri\Uri::getUserInfo
+ */
+ public function testGetUserInfoWithPass()
+ {
+ $uri = new Uri('http://peehaa:pass@example.com');
+
+ $this->assertSame('peehaa:********', $uri->getUserInfo());
+ }
+
+ /**
+ * @covers OAuth\Common\Http\Uri\Uri::__construct
+ * @covers OAuth\Common\Http\Uri\Uri::parseUri
+ * @covers OAuth\Common\Http\Uri\Uri::setUserInfo
+ * @covers OAuth\Common\Http\Uri\Uri::protectUserInfo
+ * @covers OAuth\Common\Http\Uri\Uri::getRawUserInfo
+ */
+ public function testGetRawUserInfo()
+ {
+ $uri = new Uri('http://peehaa@example.com');
+
+ $this->assertSame('peehaa', $uri->getRawUserInfo());
+ }
+
+ /**
+ * @covers OAuth\Common\Http\Uri\Uri::__construct
+ * @covers OAuth\Common\Http\Uri\Uri::parseUri
+ * @covers OAuth\Common\Http\Uri\Uri::setUserInfo
+ * @covers OAuth\Common\Http\Uri\Uri::protectUserInfo
+ * @covers OAuth\Common\Http\Uri\Uri::getRawUserInfo
+ */
+ public function testGetRawUserInfoWithPass()
+ {
+ $uri = new Uri('http://peehaa:pass@example.com');
+
+ $this->assertSame('peehaa:pass', $uri->getRawUserInfo());
+ }
+
+ /**
+ * @covers OAuth\Common\Http\Uri\Uri::__construct
+ * @covers OAuth\Common\Http\Uri\Uri::parseUri
+ * @covers OAuth\Common\Http\Uri\Uri::getHost
+ */
+ public function testGetHost()
+ {
+ $uri = new Uri('http://example.com');
+
+ $this->assertSame('example.com', $uri->getHost());
+ }
+
+ /**
+ * @covers OAuth\Common\Http\Uri\Uri::__construct
+ * @covers OAuth\Common\Http\Uri\Uri::parseUri
+ * @covers OAuth\Common\Http\Uri\Uri::getPort
+ */
+ public function testGetPortImplicitHttp()
+ {
+ $uri = new Uri('http://example.com');
+
+ $this->assertSame(80, $uri->getPort());
+ }
+
+ /**
+ * @covers OAuth\Common\Http\Uri\Uri::__construct
+ * @covers OAuth\Common\Http\Uri\Uri::parseUri
+ * @covers OAuth\Common\Http\Uri\Uri::getPort
+ */
+ public function testGetPortImplicitHttps()
+ {
+ $uri = new Uri('https://example.com');
+
+ $this->assertSame(443, $uri->getPort());
+ }
+
+ /**
+ * @covers OAuth\Common\Http\Uri\Uri::__construct
+ * @covers OAuth\Common\Http\Uri\Uri::parseUri
+ * @covers OAuth\Common\Http\Uri\Uri::getPort
+ */
+ public function testGetPortExplicit()
+ {
+ $uri = new Uri('http://example.com:21');
+
+ $this->assertSame(21, $uri->getPort());
+ }
+
+ /**
+ * @covers OAuth\Common\Http\Uri\Uri::__construct
+ * @covers OAuth\Common\Http\Uri\Uri::parseUri
+ * @covers OAuth\Common\Http\Uri\Uri::getPath
+ */
+ public function testGetPathNotSupplied()
+ {
+ $uri = new Uri('http://example.com');
+
+ $this->assertSame('/', $uri->getPath());
+ }
+
+ /**
+ * @covers OAuth\Common\Http\Uri\Uri::__construct
+ * @covers OAuth\Common\Http\Uri\Uri::parseUri
+ * @covers OAuth\Common\Http\Uri\Uri::getPath
+ */
+ public function testGetPathSlash()
+ {
+ $uri = new Uri('http://example.com/');
+
+ $this->assertSame('/', $uri->getPath());
+ }
+
+ /**
+ * @covers OAuth\Common\Http\Uri\Uri::__construct
+ * @covers OAuth\Common\Http\Uri\Uri::parseUri
+ * @covers OAuth\Common\Http\Uri\Uri::getPath
+ */
+ public function testGetPath()
+ {
+ $uri = new Uri('http://example.com/foo');
+
+ $this->assertSame('/foo', $uri->getPath());
+ }
+
+ /**
+ * @covers OAuth\Common\Http\Uri\Uri::__construct
+ * @covers OAuth\Common\Http\Uri\Uri::parseUri
+ * @covers OAuth\Common\Http\Uri\Uri::getQuery
+ */
+ public function testGetQueryWithParams()
+ {
+ $uri = new Uri('http://example.com?param1=first¶m2=second');
+
+ $this->assertSame('param1=first¶m2=second', $uri->getQuery());
+ }
+
+ /**
+ * @covers OAuth\Common\Http\Uri\Uri::__construct
+ * @covers OAuth\Common\Http\Uri\Uri::parseUri
+ * @covers OAuth\Common\Http\Uri\Uri::getQuery
+ */
+ public function testGetQueryWithoutParams()
+ {
+ $uri = new Uri('http://example.com');
+
+ $this->assertSame('', $uri->getQuery());
+ }
+
+ /**
+ * @covers OAuth\Common\Http\Uri\Uri::__construct
+ * @covers OAuth\Common\Http\Uri\Uri::parseUri
+ * @covers OAuth\Common\Http\Uri\Uri::getFragment
+ */
+ public function testGetFragmentExists()
+ {
+ $uri = new Uri('http://example.com#foo');
+
+ $this->assertSame('foo', $uri->getFragment());
+ }
+
+ /**
+ * @covers OAuth\Common\Http\Uri\Uri::__construct
+ * @covers OAuth\Common\Http\Uri\Uri::parseUri
+ * @covers OAuth\Common\Http\Uri\Uri::getFragment
+ */
+ public function testGetFragmentNotExists()
+ {
+ $uri = new Uri('http://example.com');
+
+ $this->assertSame('', $uri->getFragment());
+ }
+
+ /**
+ * @covers OAuth\Common\Http\Uri\Uri::__construct
+ * @covers OAuth\Common\Http\Uri\Uri::parseUri
+ * @covers OAuth\Common\Http\Uri\Uri::getAuthority
+ */
+ public function testGetAuthorityWithoutUserInfo()
+ {
+ $uri = new Uri('http://example.com');
+
+ $this->assertSame('example.com', $uri->getAuthority());
+ }
+
+ /**
+ * @covers OAuth\Common\Http\Uri\Uri::__construct
+ * @covers OAuth\Common\Http\Uri\Uri::parseUri
+ * @covers OAuth\Common\Http\Uri\Uri::getAuthority
+ */
+ public function testGetAuthorityWithoutUserInfoWithExplicitPort()
+ {
+ $uri = new Uri('http://example.com:21');
+
+ $this->assertSame('example.com:21', $uri->getAuthority());
+ }
+
+ /**
+ * @covers OAuth\Common\Http\Uri\Uri::__construct
+ * @covers OAuth\Common\Http\Uri\Uri::parseUri
+ * @covers OAuth\Common\Http\Uri\Uri::setUserInfo
+ * @covers OAuth\Common\Http\Uri\Uri::protectUserInfo
+ * @covers OAuth\Common\Http\Uri\Uri::getAuthority
+ */
+ public function testGetAuthorityWithUsernameWithExplicitPort()
+ {
+ $uri = new Uri('http://peehaa@example.com:21');
+
+ $this->assertSame('peehaa@example.com:21', $uri->getAuthority());
+ }
+
+ /**
+ * @covers OAuth\Common\Http\Uri\Uri::__construct
+ * @covers OAuth\Common\Http\Uri\Uri::parseUri
+ * @covers OAuth\Common\Http\Uri\Uri::setUserInfo
+ * @covers OAuth\Common\Http\Uri\Uri::protectUserInfo
+ * @covers OAuth\Common\Http\Uri\Uri::getAuthority
+ */
+ public function testGetAuthorityWithUsernameAndPassWithExplicitPort()
+ {
+ $uri = new Uri('http://peehaa:pass@example.com:21');
+
+ $this->assertSame('peehaa:********@example.com:21', $uri->getAuthority());
+ }
+
+ /**
+ * @covers OAuth\Common\Http\Uri\Uri::__construct
+ * @covers OAuth\Common\Http\Uri\Uri::parseUri
+ * @covers OAuth\Common\Http\Uri\Uri::setUserInfo
+ * @covers OAuth\Common\Http\Uri\Uri::protectUserInfo
+ * @covers OAuth\Common\Http\Uri\Uri::getAuthority
+ */
+ public function testGetAuthorityWithUsernameAndPassWithoutExplicitPort()
+ {
+ $uri = new Uri('http://peehaa:pass@example.com');
+
+ $this->assertSame('peehaa:********@example.com', $uri->getAuthority());
+ }
+
+ /**
+ * @covers OAuth\Common\Http\Uri\Uri::__construct
+ * @covers OAuth\Common\Http\Uri\Uri::parseUri
+ * @covers OAuth\Common\Http\Uri\Uri::getRawAuthority
+ */
+ public function testGetRawAuthorityWithoutUserInfo()
+ {
+ $uri = new Uri('http://example.com');
+
+ $this->assertSame('example.com', $uri->getRawAuthority());
+ }
+
+ /**
+ * @covers OAuth\Common\Http\Uri\Uri::__construct
+ * @covers OAuth\Common\Http\Uri\Uri::parseUri
+ * @covers OAuth\Common\Http\Uri\Uri::getRawAuthority
+ */
+ public function testGetRawAuthorityWithoutUserInfoWithExplicitPort()
+ {
+ $uri = new Uri('http://example.com:21');
+
+ $this->assertSame('example.com:21', $uri->getRawAuthority());
+ }
+
+ /**
+ * @covers OAuth\Common\Http\Uri\Uri::__construct
+ * @covers OAuth\Common\Http\Uri\Uri::parseUri
+ * @covers OAuth\Common\Http\Uri\Uri::setUserInfo
+ * @covers OAuth\Common\Http\Uri\Uri::protectUserInfo
+ * @covers OAuth\Common\Http\Uri\Uri::getRawAuthority
+ */
+ public function testGetRawAuthorityWithUsernameWithExplicitPort()
+ {
+ $uri = new Uri('http://peehaa@example.com:21');
+
+ $this->assertSame('peehaa@example.com:21', $uri->getRawAuthority());
+ }
+
+ /**
+ * @covers OAuth\Common\Http\Uri\Uri::__construct
+ * @covers OAuth\Common\Http\Uri\Uri::parseUri
+ * @covers OAuth\Common\Http\Uri\Uri::setUserInfo
+ * @covers OAuth\Common\Http\Uri\Uri::protectUserInfo
+ * @covers OAuth\Common\Http\Uri\Uri::getRawAuthority
+ */
+ public function testGetRawAuthorityWithUsernameAndPassWithExplicitPort()
+ {
+ $uri = new Uri('http://peehaa:pass@example.com:21');
+
+ $this->assertSame('peehaa:pass@example.com:21', $uri->getRawAuthority());
+ }
+
+ /**
+ * @covers OAuth\Common\Http\Uri\Uri::__construct
+ * @covers OAuth\Common\Http\Uri\Uri::parseUri
+ * @covers OAuth\Common\Http\Uri\Uri::setUserInfo
+ * @covers OAuth\Common\Http\Uri\Uri::protectUserInfo
+ * @covers OAuth\Common\Http\Uri\Uri::getRawAuthority
+ */
+ public function testGetRawAuthorityWithUsernameAndPassWithoutExplicitPort()
+ {
+ $uri = new Uri('http://peehaa:pass@example.com');
+
+ $this->assertSame('peehaa:pass@example.com', $uri->getRawAuthority());
+ }
+
+ /**
+ * @covers OAuth\Common\Http\Uri\Uri::__construct
+ * @covers OAuth\Common\Http\Uri\Uri::parseUri
+ * @covers OAuth\Common\Http\Uri\Uri::getAbsoluteUri
+ */
+ public function testGetAbsoluteUriBare()
+ {
+ $uri = new Uri('http://example.com');
+
+ $this->assertSame('http://example.com', $uri->getAbsoluteUri());
+ }
+
+ /**
+ * @covers OAuth\Common\Http\Uri\Uri::__construct
+ * @covers OAuth\Common\Http\Uri\Uri::parseUri
+ * @covers OAuth\Common\Http\Uri\Uri::setUserInfo
+ * @covers OAuth\Common\Http\Uri\Uri::protectUserInfo
+ * @covers OAuth\Common\Http\Uri\Uri::getRawAuthority
+ * @covers OAuth\Common\Http\Uri\Uri::getAbsoluteUri
+ */
+ public function testGetAbsoluteUriWithAuthority()
+ {
+ $uri = new Uri('http://peehaa:pass@example.com');
+
+ $this->assertSame('http://peehaa:pass@example.com', $uri->getAbsoluteUri());
+ }
+
+ /**
+ * @covers OAuth\Common\Http\Uri\Uri::__construct
+ * @covers OAuth\Common\Http\Uri\Uri::parseUri
+ * @covers OAuth\Common\Http\Uri\Uri::getAbsoluteUri
+ */
+ public function testGetAbsoluteUriWithPath()
+ {
+ $uri = new Uri('http://example.com/foo');
+
+ $this->assertSame('http://example.com/foo', $uri->getAbsoluteUri());
+ }
+
+ /**
+ * @covers OAuth\Common\Http\Uri\Uri::__construct
+ * @covers OAuth\Common\Http\Uri\Uri::parseUri
+ * @covers OAuth\Common\Http\Uri\Uri::getAbsoluteUri
+ */
+ public function testGetAbsoluteUriWithoutPath()
+ {
+ $uri = new Uri('http://example.com');
+
+ $this->assertSame('http://example.com', $uri->getAbsoluteUri());
+ }
+
+ /**
+ * @covers OAuth\Common\Http\Uri\Uri::__construct
+ * @covers OAuth\Common\Http\Uri\Uri::parseUri
+ * @covers OAuth\Common\Http\Uri\Uri::getAbsoluteUri
+ */
+ public function testGetAbsoluteUriWithoutPathExplicitTrailingSlash()
+ {
+ $uri = new Uri('http://example.com/');
+
+ $this->assertSame('http://example.com/', $uri->getAbsoluteUri());
+ }
+
+ /**
+ * @covers OAuth\Common\Http\Uri\Uri::__construct
+ * @covers OAuth\Common\Http\Uri\Uri::parseUri
+ * @covers OAuth\Common\Http\Uri\Uri::getAbsoluteUri
+ */
+ public function testGetAbsoluteUriWithQuery()
+ {
+ $uri = new Uri('http://example.com?param1=value1');
+
+ $this->assertSame('http://example.com?param1=value1', $uri->getAbsoluteUri());
+ }
+
+ /**
+ * @covers OAuth\Common\Http\Uri\Uri::__construct
+ * @covers OAuth\Common\Http\Uri\Uri::parseUri
+ * @covers OAuth\Common\Http\Uri\Uri::getAbsoluteUri
+ */
+ public function testGetAbsoluteUriWithFragment()
+ {
+ $uri = new Uri('http://example.com#foo');
+
+ $this->assertSame('http://example.com#foo', $uri->getAbsoluteUri());
+ }
+
+ /**
+ * @covers OAuth\Common\Http\Uri\Uri::__construct
+ * @covers OAuth\Common\Http\Uri\Uri::parseUri
+ * @covers OAuth\Common\Http\Uri\Uri::getRelativeUri
+ */
+ public function testGetRelativeUriWithoutPath()
+ {
+ $uri = new Uri('http://example.com');
+
+ $this->assertSame('', $uri->getRelativeUri());
+ }
+
+ /**
+ * @covers OAuth\Common\Http\Uri\Uri::__construct
+ * @covers OAuth\Common\Http\Uri\Uri::parseUri
+ * @covers OAuth\Common\Http\Uri\Uri::getRelativeUri
+ */
+ public function testGetRelativeUriWithPath()
+ {
+ $uri = new Uri('http://example.com/foo');
+
+ $this->assertSame('/foo', $uri->getRelativeUri());
+ }
+
+ /**
+ * @covers OAuth\Common\Http\Uri\Uri::__construct
+ * @covers OAuth\Common\Http\Uri\Uri::parseUri
+ * @covers OAuth\Common\Http\Uri\Uri::getRelativeUri
+ */
+ public function testGetRelativeUriWithExplicitTrailingSlash()
+ {
+ $uri = new Uri('http://example.com/');
+
+ $this->assertSame('/', $uri->getRelativeUri());
+ }
+
+ /**
+ * @covers OAuth\Common\Http\Uri\Uri::__construct
+ * @covers OAuth\Common\Http\Uri\Uri::parseUri
+ * @covers OAuth\Common\Http\Uri\Uri::__toString
+ */
+ public function testToStringBare()
+ {
+ $uri = new Uri('http://example.com');
+
+ $this->assertSame('http://example.com', (string) $uri);
+ }
+
+ /**
+ * @covers OAuth\Common\Http\Uri\Uri::__construct
+ * @covers OAuth\Common\Http\Uri\Uri::parseUri
+ * @covers OAuth\Common\Http\Uri\Uri::setUserInfo
+ * @covers OAuth\Common\Http\Uri\Uri::protectUserInfo
+ * @covers OAuth\Common\Http\Uri\Uri::getRawAuthority
+ * @covers OAuth\Common\Http\Uri\Uri::__toString
+ */
+ public function testToStringWithAuthority()
+ {
+ $uri = new Uri('http://peehaa:pass@example.com');
+
+ $this->assertSame('http://peehaa:********@example.com', (string) $uri);
+ }
+
+ /**
+ * @covers OAuth\Common\Http\Uri\Uri::__construct
+ * @covers OAuth\Common\Http\Uri\Uri::parseUri
+ * @covers OAuth\Common\Http\Uri\Uri::__toString
+ */
+ public function testToStringWithPath()
+ {
+ $uri = new Uri('http://example.com/foo');
+
+ $this->assertSame('http://example.com/foo', (string) $uri);
+ }
+
+ /**
+ * @covers OAuth\Common\Http\Uri\Uri::__construct
+ * @covers OAuth\Common\Http\Uri\Uri::parseUri
+ * @covers OAuth\Common\Http\Uri\Uri::__toString
+ */
+ public function testToStringWithoutPath()
+ {
+ $uri = new Uri('http://example.com');
+
+ $this->assertSame('http://example.com', (string) $uri);
+ }
+
+ /**
+ * @covers OAuth\Common\Http\Uri\Uri::__construct
+ * @covers OAuth\Common\Http\Uri\Uri::parseUri
+ * @covers OAuth\Common\Http\Uri\Uri::__toString
+ */
+ public function testToStringWithoutPathExplicitTrailingSlash()
+ {
+ $uri = new Uri('http://example.com/');
+
+ $this->assertSame('http://example.com/', (string) $uri);
+ }
+
+ /**
+ * @covers OAuth\Common\Http\Uri\Uri::__construct
+ * @covers OAuth\Common\Http\Uri\Uri::parseUri
+ * @covers OAuth\Common\Http\Uri\Uri::__toString
+ */
+ public function testToStringWithQuery()
+ {
+ $uri = new Uri('http://example.com?param1=value1');
+
+ $this->assertSame('http://example.com?param1=value1', (string) $uri);
+ }
+
+ /**
+ * @covers OAuth\Common\Http\Uri\Uri::__construct
+ * @covers OAuth\Common\Http\Uri\Uri::parseUri
+ * @covers OAuth\Common\Http\Uri\Uri::__toString
+ */
+ public function testToStringWithFragment()
+ {
+ $uri = new Uri('http://example.com#foo');
+
+ $this->assertSame('http://example.com#foo', (string) $uri);
+ }
+
+ /**
+ * @covers OAuth\Common\Http\Uri\Uri::__construct
+ * @covers OAuth\Common\Http\Uri\Uri::parseUri
+ * @covers OAuth\Common\Http\Uri\Uri::setPath
+ * @covers OAuth\Common\Http\Uri\Uri::getAbsoluteUri
+ */
+ public function testSetPathEmpty()
+ {
+ $uri = new Uri('http://example.com');
+ $uri->setPath('');
+
+ $this->assertSame('http://example.com', $uri->getAbsoluteUri());
+ }
+
+ /**
+ * @covers OAuth\Common\Http\Uri\Uri::__construct
+ * @covers OAuth\Common\Http\Uri\Uri::parseUri
+ * @covers OAuth\Common\Http\Uri\Uri::setPath
+ * @covers OAuth\Common\Http\Uri\Uri::getAbsoluteUri
+ */
+ public function testSetPathWithPath()
+ {
+ $uri = new Uri('http://example.com');
+ $uri->setPath('/foo');
+
+ $this->assertSame('http://example.com/foo', $uri->getAbsoluteUri());
+ }
+
+ /**
+ * @covers OAuth\Common\Http\Uri\Uri::__construct
+ * @covers OAuth\Common\Http\Uri\Uri::parseUri
+ * @covers OAuth\Common\Http\Uri\Uri::setPath
+ * @covers OAuth\Common\Http\Uri\Uri::getAbsoluteUri
+ */
+ public function testSetPathWithOnlySlash()
+ {
+ $uri = new Uri('http://example.com');
+ $uri->setPath('/');
+
+ $this->assertSame('http://example.com/', $uri->getAbsoluteUri());
+ }
+
+ /**
+ * @covers OAuth\Common\Http\Uri\Uri::__construct
+ * @covers OAuth\Common\Http\Uri\Uri::parseUri
+ * @covers OAuth\Common\Http\Uri\Uri::setQuery
+ * @covers OAuth\Common\Http\Uri\Uri::getAbsoluteUri
+ */
+ public function testSetQueryEmpty()
+ {
+ $uri = new Uri('http://example.com');
+ $uri->setQuery('');
+
+ $this->assertSame('http://example.com', $uri->getAbsoluteUri());
+ }
+
+ /**
+ * @covers OAuth\Common\Http\Uri\Uri::__construct
+ * @covers OAuth\Common\Http\Uri\Uri::parseUri
+ * @covers OAuth\Common\Http\Uri\Uri::setQuery
+ * @covers OAuth\Common\Http\Uri\Uri::getAbsoluteUri
+ */
+ public function testSetQueryFilled()
+ {
+ $uri = new Uri('http://example.com');
+ $uri->setQuery('param1=value1¶m2=value2');
+
+ $this->assertSame('http://example.com?param1=value1¶m2=value2', $uri->getAbsoluteUri());
+ }
+
+ /**
+ * @covers OAuth\Common\Http\Uri\Uri::__construct
+ * @covers OAuth\Common\Http\Uri\Uri::parseUri
+ * @covers OAuth\Common\Http\Uri\Uri::addToQuery
+ * @covers OAuth\Common\Http\Uri\Uri::getAbsoluteUri
+ */
+ public function testAddToQueryAppend()
+ {
+ $uri = new Uri('http://example.com?param1=value1');
+ $uri->addToQuery('param2', 'value2');
+
+ $this->assertSame('http://example.com?param1=value1¶m2=value2', $uri->getAbsoluteUri());
+ }
+
+ /**
+ * @covers OAuth\Common\Http\Uri\Uri::__construct
+ * @covers OAuth\Common\Http\Uri\Uri::parseUri
+ * @covers OAuth\Common\Http\Uri\Uri::addToQuery
+ * @covers OAuth\Common\Http\Uri\Uri::getAbsoluteUri
+ */
+ public function testAddToQueryCreate()
+ {
+ $uri = new Uri('http://example.com');
+ $uri->addToQuery('param1', 'value1');
+
+ $this->assertSame('http://example.com?param1=value1', $uri->getAbsoluteUri());
+ }
+
+ /**
+ * @covers OAuth\Common\Http\Uri\Uri::__construct
+ * @covers OAuth\Common\Http\Uri\Uri::parseUri
+ * @covers OAuth\Common\Http\Uri\Uri::setFragment
+ * @covers OAuth\Common\Http\Uri\Uri::getAbsoluteUri
+ */
+ public function testSetFragmentEmpty()
+ {
+ $uri = new Uri('http://example.com');
+ $uri->setFragment('');
+
+ $this->assertSame('http://example.com', $uri->getAbsoluteUri());
+ }
+
+ /**
+ * @covers OAuth\Common\Http\Uri\Uri::__construct
+ * @covers OAuth\Common\Http\Uri\Uri::parseUri
+ * @covers OAuth\Common\Http\Uri\Uri::setFragment
+ * @covers OAuth\Common\Http\Uri\Uri::getAbsoluteUri
+ */
+ public function testSetFragmentWithData()
+ {
+ $uri = new Uri('http://example.com');
+ $uri->setFragment('foo');
+
+ $this->assertSame('http://example.com#foo', $uri->getAbsoluteUri());
+ }
+
+ /**
+ * @covers OAuth\Common\Http\Uri\Uri::__construct
+ * @covers OAuth\Common\Http\Uri\Uri::parseUri
+ * @covers OAuth\Common\Http\Uri\Uri::setScheme
+ * @covers OAuth\Common\Http\Uri\Uri::getAbsoluteUri
+ */
+ public function testSetSchemeWithEmpty()
+ {
+ $uri = new Uri('http://example.com');
+ $uri->setScheme('');
+
+ $this->assertSame('://example.com', $uri->getAbsoluteUri());
+ }
+
+ /**
+ * @covers OAuth\Common\Http\Uri\Uri::__construct
+ * @covers OAuth\Common\Http\Uri\Uri::parseUri
+ * @covers OAuth\Common\Http\Uri\Uri::setScheme
+ * @covers OAuth\Common\Http\Uri\Uri::getAbsoluteUri
+ */
+ public function testSetSchemeWithData()
+ {
+ $uri = new Uri('http://example.com');
+ $uri->setScheme('foo');
+
+ $this->assertSame('foo://example.com', $uri->getAbsoluteUri());
+ }
+
+ /**
+ * @covers OAuth\Common\Http\Uri\Uri::__construct
+ * @covers OAuth\Common\Http\Uri\Uri::parseUri
+ * @covers OAuth\Common\Http\Uri\Uri::setUserInfo
+ * @covers OAuth\Common\Http\Uri\Uri::getAbsoluteUri
+ */
+ public function testSetUserInfoEmpty()
+ {
+ $uri = new Uri('http://example.com');
+ $uri->setUserInfo('');
+
+ $this->assertSame('http://example.com', $uri->getAbsoluteUri());
+ }
+
+ /**
+ * @covers OAuth\Common\Http\Uri\Uri::__construct
+ * @covers OAuth\Common\Http\Uri\Uri::parseUri
+ * @covers OAuth\Common\Http\Uri\Uri::setUserInfo
+ * @covers OAuth\Common\Http\Uri\Uri::protectUserInfo
+ * @covers OAuth\Common\Http\Uri\Uri::getAbsoluteUri
+ */
+ public function testSetUserInfoWithData()
+ {
+ $uri = new Uri('http://example.com');
+ $uri->setUserInfo('foo:bar');
+
+ $this->assertSame('http://foo:bar@example.com', $uri->getAbsoluteUri());
+ }
+
+ /**
+ * @covers OAuth\Common\Http\Uri\Uri::__construct
+ * @covers OAuth\Common\Http\Uri\Uri::parseUri
+ * @covers OAuth\Common\Http\Uri\Uri::setPort
+ * @covers OAuth\Common\Http\Uri\Uri::getAbsoluteUri
+ */
+ public function testSetPortCustom()
+ {
+ $uri = new Uri('http://example.com');
+ $uri->setPort('21');
+
+ $this->assertSame('http://example.com:21', $uri->getAbsoluteUri());
+ }
+
+ /**
+ * @covers OAuth\Common\Http\Uri\Uri::__construct
+ * @covers OAuth\Common\Http\Uri\Uri::parseUri
+ * @covers OAuth\Common\Http\Uri\Uri::setPort
+ * @covers OAuth\Common\Http\Uri\Uri::getAbsoluteUri
+ */
+ public function testSetPortHttpImplicit()
+ {
+ $uri = new Uri('http://example.com');
+ $uri->setPort(80);
+
+ $this->assertSame('http://example.com', $uri->getAbsoluteUri());
+ }
+
+ /**
+ * @covers OAuth\Common\Http\Uri\Uri::__construct
+ * @covers OAuth\Common\Http\Uri\Uri::parseUri
+ * @covers OAuth\Common\Http\Uri\Uri::setPort
+ * @covers OAuth\Common\Http\Uri\Uri::getAbsoluteUri
+ */
+ public function testSetPortHttpsImplicit()
+ {
+ $uri = new Uri('https://example.com');
+ $uri->setPort(443);
+
+ $this->assertSame('https://example.com', $uri->getAbsoluteUri());
+ }
+
+ /**
+ * @covers OAuth\Common\Http\Uri\Uri::__construct
+ * @covers OAuth\Common\Http\Uri\Uri::parseUri
+ * @covers OAuth\Common\Http\Uri\Uri::setPort
+ * @covers OAuth\Common\Http\Uri\Uri::getAbsoluteUri
+ */
+ public function testSetPortHttpExplicit()
+ {
+ $uri = new Uri('http://example.com');
+ $uri->setPort(443);
+
+ $this->assertSame('http://example.com:443', $uri->getAbsoluteUri());
+ }
+
+ /**
+ * @covers OAuth\Common\Http\Uri\Uri::__construct
+ * @covers OAuth\Common\Http\Uri\Uri::parseUri
+ * @covers OAuth\Common\Http\Uri\Uri::setPort
+ * @covers OAuth\Common\Http\Uri\Uri::getAbsoluteUri
+ */
+ public function testSetPortHttpsExplicit()
+ {
+ $uri = new Uri('https://example.com');
+ $uri->setPort(80);
+
+ $this->assertSame('https://example.com:80', $uri->getAbsoluteUri());
+ }
+
+ /**
+ * @covers OAuth\Common\Http\Uri\Uri::__construct
+ * @covers OAuth\Common\Http\Uri\Uri::parseUri
+ * @covers OAuth\Common\Http\Uri\Uri::setHost
+ * @covers OAuth\Common\Http\Uri\Uri::getAbsoluteUri
+ */
+ public function testSetHost()
+ {
+ $uri = new Uri('http://example.com');
+ $uri->setHost('pieterhordijk.com');
+
+ $this->assertSame('http://pieterhordijk.com', $uri->getAbsoluteUri());
+ }
+
+ /**
+ * @covers OAuth\Common\Http\Uri\Uri::__construct
+ * @covers OAuth\Common\Http\Uri\Uri::parseUri
+ * @covers OAuth\Common\Http\Uri\Uri::hasExplicitTrailingHostSlash
+ */
+ public function testHasExplicitTrailingHostSlashTrue()
+ {
+ $uri = new Uri('http://example.com/');
+
+ $this->assertTrue($uri->hasExplicitTrailingHostSlash());
+ }
+
+ /**
+ * @covers OAuth\Common\Http\Uri\Uri::__construct
+ * @covers OAuth\Common\Http\Uri\Uri::parseUri
+ * @covers OAuth\Common\Http\Uri\Uri::hasExplicitTrailingHostSlash
+ */
+ public function testHasExplicitTrailingHostSlashFalse()
+ {
+ $uri = new Uri('http://example.com/foo');
+
+ $this->assertFalse($uri->hasExplicitTrailingHostSlash());
+ }
+
+ /**
+ * @covers OAuth\Common\Http\Uri\Uri::__construct
+ * @covers OAuth\Common\Http\Uri\Uri::parseUri
+ * @covers OAuth\Common\Http\Uri\Uri::hasExplicitPortSpecified
+ */
+ public function testHasExplicitPortSpecifiedTrue()
+ {
+ $uri = new Uri('http://example.com:8080');
+
+ $this->assertTrue($uri->hasExplicitPortSpecified());
+ }
+
+ /**
+ * @covers OAuth\Common\Http\Uri\Uri::__construct
+ * @covers OAuth\Common\Http\Uri\Uri::parseUri
+ * @covers OAuth\Common\Http\Uri\Uri::hasExplicitPortSpecified
+ */
+ public function testHasExplicitPortSpecifiedFalse()
+ {
+ $uri = new Uri('http://example.com');
+
+ $this->assertFalse($uri->hasExplicitPortSpecified());
+ }
+}
diff --git a/vendor/lusitanian/oauth/tests/Unit/Common/Service/AbstractServiceTest.php b/vendor/lusitanian/oauth/tests/Unit/Common/Service/AbstractServiceTest.php
new file mode 100644
index 00000000..2d8bff46
--- /dev/null
+++ b/vendor/lusitanian/oauth/tests/Unit/Common/Service/AbstractServiceTest.php
@@ -0,0 +1,171 @@
+getMockForAbstractClass(
+ '\\OAuth\\Common\\Service\\AbstractService',
+ array(
+ $this->getMock('\\OAuth\\Common\\Consumer\\CredentialsInterface'),
+ $this->getMock('\\OAuth\\Common\\Http\\Client\\ClientInterface'),
+ $this->getMock('\\OAuth\\Common\\Storage\\TokenStorageInterface')
+ )
+ );
+
+ $this->assertInstanceOf('\\OAuth\\Common\\Service\\ServiceInterface', $service);
+ }
+
+ /**
+ * @covers OAuth\Common\Service\AbstractService::__construct
+ * @covers OAuth\Common\Service\AbstractService::getStorage
+ */
+ public function testGetStorage()
+ {
+ $service = $this->getMockForAbstractClass(
+ '\\OAuth\\Common\\Service\\AbstractService',
+ array(
+ $this->getMock('\\OAuth\\Common\\Consumer\\CredentialsInterface'),
+ $this->getMock('\\OAuth\\Common\\Http\\Client\\ClientInterface'),
+ $this->getMock('\\OAuth\\Common\\Storage\\TokenStorageInterface')
+ )
+ );
+
+ $this->assertInstanceOf('\\OAuth\\Common\\Storage\\TokenStorageInterface', $service->getStorage());
+ }
+
+ /**
+ * @covers OAuth\Common\Service\AbstractService::__construct
+ * @covers OAuth\Common\Service\AbstractService::service
+ */
+ public function testService()
+ {
+ $service = new Mock(
+ $this->getMock('\\OAuth\\Common\\Consumer\\CredentialsInterface'),
+ $this->getMock('\\OAuth\\Common\\Http\\Client\\ClientInterface'),
+ $this->getMock('\\OAuth\\Common\\Storage\\TokenStorageInterface')
+ );
+
+ $this->assertSame('Mock', $service->service());
+ }
+
+ /**
+ * @covers OAuth\Common\Service\AbstractService::__construct
+ * @covers OAuth\Common\Service\AbstractService::determineRequestUriFromPath
+ */
+ public function testDetermineRequestUriFromPathUsingUriObject()
+ {
+ $service = new Mock(
+ $this->getMock('\\OAuth\\Common\\Consumer\\CredentialsInterface'),
+ $this->getMock('\\OAuth\\Common\\Http\\Client\\ClientInterface'),
+ $this->getMock('\\OAuth\\Common\\Storage\\TokenStorageInterface')
+ );
+
+ $this->assertInstanceOf(
+ '\\OAuth\\Common\\Http\\Uri\\UriInterface',
+ $service->testDetermineRequestUriFromPath($this->getMock('\\OAuth\\Common\\Http\\Uri\\UriInterface'))
+ );
+ }
+
+ /**
+ * @covers OAuth\Common\Service\AbstractService::__construct
+ * @covers OAuth\Common\Service\AbstractService::determineRequestUriFromPath
+ */
+ public function testDetermineRequestUriFromPathUsingHttpPath()
+ {
+ $service = new Mock(
+ $this->getMock('\\OAuth\\Common\\Consumer\\CredentialsInterface'),
+ $this->getMock('\\OAuth\\Common\\Http\\Client\\ClientInterface'),
+ $this->getMock('\\OAuth\\Common\\Storage\\TokenStorageInterface')
+ );
+
+ $uri = $service->testDetermineRequestUriFromPath('http://example.com');
+
+ $this->assertInstanceOf('\\OAuth\\Common\\Http\\Uri\\UriInterface', $uri);
+ $this->assertSame('http://example.com', $uri->getAbsoluteUri());
+ }
+
+ /**
+ * @covers OAuth\Common\Service\AbstractService::__construct
+ * @covers OAuth\Common\Service\AbstractService::determineRequestUriFromPath
+ */
+ public function testDetermineRequestUriFromPathUsingHttpsPath()
+ {
+ $service = new Mock(
+ $this->getMock('\\OAuth\\Common\\Consumer\\CredentialsInterface'),
+ $this->getMock('\\OAuth\\Common\\Http\\Client\\ClientInterface'),
+ $this->getMock('\\OAuth\\Common\\Storage\\TokenStorageInterface')
+ );
+
+ $uri = $service->testDetermineRequestUriFromPath('https://example.com');
+
+ $this->assertInstanceOf('\\OAuth\\Common\\Http\\Uri\\UriInterface', $uri);
+ $this->assertSame('https://example.com', $uri->getAbsoluteUri());
+ }
+
+ /**
+ * @covers OAuth\Common\Service\AbstractService::__construct
+ * @covers OAuth\Common\Service\AbstractService::determineRequestUriFromPath
+ */
+ public function testDetermineRequestUriFromPathThrowsExceptionOnInvalidUri()
+ {
+ $this->setExpectedException('\\OAuth\\Common\\Exception\\Exception');
+
+ $service = new Mock(
+ $this->getMock('\\OAuth\\Common\\Consumer\\CredentialsInterface'),
+ $this->getMock('\\OAuth\\Common\\Http\\Client\\ClientInterface'),
+ $this->getMock('\\OAuth\\Common\\Storage\\TokenStorageInterface')
+ );
+
+ $uri = $service->testDetermineRequestUriFromPath('example.com');
+ }
+
+ /**
+ * @covers OAuth\Common\Service\AbstractService::__construct
+ * @covers OAuth\Common\Service\AbstractService::determineRequestUriFromPath
+ */
+ public function testDetermineRequestUriFromPathWithQueryString()
+ {
+ $service = new Mock(
+ $this->getMock('\\OAuth\\Common\\Consumer\\CredentialsInterface'),
+ $this->getMock('\\OAuth\\Common\\Http\\Client\\ClientInterface'),
+ $this->getMock('\\OAuth\\Common\\Storage\\TokenStorageInterface')
+ );
+
+ $uri = $service->testDetermineRequestUriFromPath(
+ 'path?param1=value1',
+ new \OAuth\Common\Http\Uri\Uri('https://example.com')
+ );
+
+ $this->assertInstanceOf('\\OAuth\\Common\\Http\\Uri\\UriInterface', $uri);
+ $this->assertSame('https://example.com/path?param1=value1', $uri->getAbsoluteUri());
+ }
+
+ /**
+ * @covers OAuth\Common\Service\AbstractService::__construct
+ * @covers OAuth\Common\Service\AbstractService::determineRequestUriFromPath
+ */
+ public function testDetermineRequestUriFromPathWithLeadingSlashInPath()
+ {
+ $service = new Mock(
+ $this->getMock('\\OAuth\\Common\\Consumer\\CredentialsInterface'),
+ $this->getMock('\\OAuth\\Common\\Http\\Client\\ClientInterface'),
+ $this->getMock('\\OAuth\\Common\\Storage\\TokenStorageInterface')
+ );
+
+ $uri = $service->testDetermineRequestUriFromPath(
+ '/path',
+ new \OAuth\Common\Http\Uri\Uri('https://example.com')
+ );
+
+ $this->assertInstanceOf('\\OAuth\\Common\\Http\\Uri\\UriInterface', $uri);
+ $this->assertSame('https://example.com/path', $uri->getAbsoluteUri());
+ }
+}
diff --git a/vendor/lusitanian/oauth/tests/Unit/Common/Storage/MemoryTest.php b/vendor/lusitanian/oauth/tests/Unit/Common/Storage/MemoryTest.php
new file mode 100644
index 00000000..93a01a79
--- /dev/null
+++ b/vendor/lusitanian/oauth/tests/Unit/Common/Storage/MemoryTest.php
@@ -0,0 +1,132 @@
+assertInstanceOf('\\OAuth\\Common\\Storage\\TokenStorageInterface', $storage);
+ }
+
+ /**
+ * @covers OAuth\Common\Storage\Memory::__construct
+ * @covers OAuth\Common\Storage\Memory::storeAccessToken
+ */
+ public function testStoreAccessToken()
+ {
+ $storage = new Memory();
+
+ $this->assertInstanceOf(
+ '\\OAuth\\Common\\Storage\\Memory',
+ $storage->storeAccessToken('foo', $this->getMock('\\OAuth\\Common\\Token\\TokenInterface'))
+ );
+ }
+
+ /**
+ * @covers OAuth\Common\Storage\Memory::__construct
+ * @covers OAuth\Common\Storage\Memory::storeAccessToken
+ * @covers OAuth\Common\Storage\Memory::retrieveAccessToken
+ * @covers OAuth\Common\Storage\Memory::hasAccessToken
+ */
+ public function testRetrieveAccessTokenValid()
+ {
+ $storage = new Memory();
+
+ $storage->storeAccessToken('foo', $this->getMock('\\OAuth\\Common\\Token\\TokenInterface'));
+
+ $this->assertInstanceOf('\\OAuth\\Common\\Token\\TokenInterface', $storage->retrieveAccessToken('foo'));
+ }
+
+ /**
+ * @covers OAuth\Common\Storage\Memory::__construct
+ * @covers OAuth\Common\Storage\Memory::retrieveAccessToken
+ * @covers OAuth\Common\Storage\Memory::hasAccessToken
+ */
+ public function testRetrieveAccessTokenThrowsExceptionWhenTokenIsNotFound()
+ {
+ $this->setExpectedException('\\OAuth\\Common\\Storage\\Exception\\TokenNotFoundException');
+
+ $storage = new Memory();
+
+ $storage->retrieveAccessToken('foo');
+ }
+
+ /**
+ * @covers OAuth\Common\Storage\Memory::__construct
+ * @covers OAuth\Common\Storage\Memory::storeAccessToken
+ * @covers OAuth\Common\Storage\Memory::hasAccessToken
+ */
+ public function testHasAccessTokenTrue()
+ {
+ $storage = new Memory();
+
+ $storage->storeAccessToken('foo', $this->getMock('\\OAuth\\Common\\Token\\TokenInterface'));
+
+ $this->assertTrue($storage->hasAccessToken('foo'));
+ }
+
+ /**
+ * @covers OAuth\Common\Storage\Memory::__construct
+ * @covers OAuth\Common\Storage\Memory::hasAccessToken
+ */
+ public function testHasAccessTokenFalse()
+ {
+ $storage = new Memory();
+
+ $this->assertFalse($storage->hasAccessToken('foo'));
+ }
+
+ /**
+ * @covers OAuth\Common\Storage\Memory::__construct
+ * @covers OAuth\Common\Storage\Memory::clearToken
+ */
+ public function testClearTokenIsNotSet()
+ {
+ $storage = new Memory();
+
+ $this->assertInstanceOf('\\OAuth\\Common\\Storage\\Memory', $storage->clearToken('foo'));
+ }
+
+ /**
+ * @covers OAuth\Common\Storage\Memory::__construct
+ * @covers OAuth\Common\Storage\Memory::storeAccessToken
+ * @covers OAuth\Common\Storage\Memory::clearToken
+ */
+ public function testClearTokenSet()
+ {
+ $storage = new Memory();
+
+ $storage->storeAccessToken('foo', $this->getMock('\\OAuth\\Common\\Token\\TokenInterface'));
+
+ $this->assertTrue($storage->hasAccessToken('foo'));
+ $this->assertInstanceOf('\\OAuth\\Common\\Storage\\Memory', $storage->clearToken('foo'));
+ $this->assertFalse($storage->hasAccessToken('foo'));
+ }
+
+ /**
+ * @covers OAuth\Common\Storage\Memory::__construct
+ * @covers OAuth\Common\Storage\Memory::storeAccessToken
+ * @covers OAuth\Common\Storage\Memory::clearAllTokens
+ */
+ public function testClearAllTokens()
+ {
+ $storage = new Memory();
+
+ $storage->storeAccessToken('foo', $this->getMock('\\OAuth\\Common\\Token\\TokenInterface'));
+ $storage->storeAccessToken('bar', $this->getMock('\\OAuth\\Common\\Token\\TokenInterface'));
+
+ $this->assertTrue($storage->hasAccessToken('foo'));
+ $this->assertTrue($storage->hasAccessToken('bar'));
+ $this->assertInstanceOf('\\OAuth\\Common\\Storage\\Memory', $storage->clearAllTokens());
+ $this->assertFalse($storage->hasAccessToken('foo'));
+ $this->assertFalse($storage->hasAccessToken('bar'));
+ }
+}
diff --git a/vendor/lusitanian/oauth/tests/Unit/Common/Storage/RedisTest.php b/vendor/lusitanian/oauth/tests/Unit/Common/Storage/RedisTest.php
new file mode 100644
index 00000000..83e7a284
--- /dev/null
+++ b/vendor/lusitanian/oauth/tests/Unit/Common/Storage/RedisTest.php
@@ -0,0 +1,102 @@
+
+ * @copyright Copyright (c) 2012 The authors
+ * @license http://www.opensource.org/licenses/mit-license.html MIT License
+ */
+
+namespace OAuth\Unit\Common\Storage;
+
+use OAuth\Common\Storage\Redis;
+use Predis\Client as Predis;
+use OAuth\OAuth2\Token\StdOAuth2Token;
+
+class RedisTest extends \PHPUnit_Framework_TestCase
+{
+ protected $storage;
+
+ public function setUp()
+ {
+ // connect to a redis daemon
+ $predis = new Predis(array(
+ 'host' => $_ENV['redis_host'],
+ 'port' => $_ENV['redis_port'],
+ ));
+
+ // set it
+ $this->storage = new Redis($predis, 'test_user_token', 'test_user_state');
+
+ try {
+ $predis->connect();
+ } catch (\Predis\Connection\ConnectionException $e) {
+ $this->markTestSkipped('No redis instance available: ' . $e->getMessage());
+ }
+ }
+
+ public function tearDown()
+ {
+ // delete
+ $this->storage->clearAllTokens();
+
+ // close connection
+ $this->storage->getRedis()->quit();
+ }
+
+ /**
+ * Check that the token gets properly stored.
+ */
+ public function testStorage()
+ {
+ // arrange
+ $service_1 = 'Facebook';
+ $service_2 = 'Foursquare';
+
+ $token_1 = new StdOAuth2Token('access_1', 'refresh_1', StdOAuth2Token::EOL_NEVER_EXPIRES, array('extra' => 'param'));
+ $token_2 = new StdOAuth2Token('access_2', 'refresh_2', StdOAuth2Token::EOL_NEVER_EXPIRES, array('extra' => 'param'));
+
+ // act
+ $this->storage->storeAccessToken($service_1, $token_1);
+ $this->storage->storeAccessToken($service_2, $token_2);
+
+ // assert
+ $extraParams = $this->storage->retrieveAccessToken($service_1)->getExtraParams();
+ $this->assertEquals('param', $extraParams['extra']);
+ $this->assertEquals($token_1, $this->storage->retrieveAccessToken($service_1));
+ $this->assertEquals($token_2, $this->storage->retrieveAccessToken($service_2));
+ }
+
+ /**
+ * Test hasAccessToken.
+ */
+ public function testHasAccessToken()
+ {
+ // arrange
+ $service = 'Facebook';
+ $this->storage->clearToken($service);
+
+ // act
+ // assert
+ $this->assertFalse($this->storage->hasAccessToken($service));
+ }
+
+ /**
+ * Check that the token gets properly deleted.
+ */
+ public function testStorageClears()
+ {
+ // arrange
+ $service = 'Facebook';
+ $token = new StdOAuth2Token('access', 'refresh', StdOAuth2Token::EOL_NEVER_EXPIRES, array('extra' => 'param'));
+
+ // act
+ $this->storage->storeAccessToken($service, $token);
+ $this->storage->clearToken($service);
+
+ // assert
+ $this->setExpectedException('OAuth\Common\Storage\Exception\TokenNotFoundException');
+ $this->storage->retrieveAccessToken($service);
+ }
+}
diff --git a/vendor/lusitanian/oauth/tests/Unit/Common/Storage/SessionTest.php b/vendor/lusitanian/oauth/tests/Unit/Common/Storage/SessionTest.php
new file mode 100644
index 00000000..72f38b1a
--- /dev/null
+++ b/vendor/lusitanian/oauth/tests/Unit/Common/Storage/SessionTest.php
@@ -0,0 +1,245 @@
+assertInstanceOf('\\OAuth\\Common\\Storage\\TokenStorageInterface', $storage);
+ }
+
+ /**
+ * @covers OAuth\Common\Storage\Session::__construct
+ *
+ * @runInSeparateProcess
+ */
+ public function testConstructWithoutStartingSession()
+ {
+ session_start();
+
+ $storage = new Session(false);
+
+ $this->assertInstanceOf('\\OAuth\\Common\\Storage\\TokenStorageInterface', $storage);
+ }
+
+ /**
+ * @covers OAuth\Common\Storage\Session::__construct
+ *
+ * @runInSeparateProcess
+ */
+ public function testConstructTryingToStartWhileSessionAlreadyExists()
+ {
+ session_start();
+
+ $storage = new Session();
+
+ $this->assertInstanceOf('\\OAuth\\Common\\Storage\\TokenStorageInterface', $storage);
+ }
+
+ /**
+ * @covers OAuth\Common\Storage\Session::__construct
+ *
+ * @runInSeparateProcess
+ */
+ public function testConstructWithExistingSessionKey()
+ {
+ session_start();
+
+ $_SESSION['lusitanian_oauth_token'] = array();
+
+ $storage = new Session();
+
+ $this->assertInstanceOf('\\OAuth\\Common\\Storage\\TokenStorageInterface', $storage);
+ }
+
+ /**
+ * @covers OAuth\Common\Storage\Session::__construct
+ * @covers OAuth\Common\Storage\Session::storeAccessToken
+ *
+ * @runInSeparateProcess
+ */
+ public function testStoreAccessTokenIsAlreadyArray()
+ {
+ $storage = new Session();
+
+ $this->assertInstanceOf(
+ '\\OAuth\\Common\\Storage\\Session',
+ $storage->storeAccessToken('foo', $this->getMock('\\OAuth\\Common\\Token\\TokenInterface'))
+ );
+ }
+
+ /**
+ * @covers OAuth\Common\Storage\Session::__construct
+ * @covers OAuth\Common\Storage\Session::storeAccessToken
+ *
+ * @runInSeparateProcess
+ */
+ public function testStoreAccessTokenIsNotArray()
+ {
+ $storage = new Session();
+
+ $_SESSION['lusitanian_oauth_token'] = 'foo';
+
+ $this->assertInstanceOf(
+ '\\OAuth\\Common\\Storage\\Session',
+ $storage->storeAccessToken('foo', $this->getMock('\\OAuth\\Common\\Token\\TokenInterface'))
+ );
+ }
+
+ /**
+ * @covers OAuth\Common\Storage\Session::__construct
+ * @covers OAuth\Common\Storage\Session::storeAccessToken
+ * @covers OAuth\Common\Storage\Session::retrieveAccessToken
+ * @covers OAuth\Common\Storage\Session::hasAccessToken
+ *
+ * @runInSeparateProcess
+ */
+ public function testRetrieveAccessTokenValid()
+ {
+ $storage = new Session();
+
+ $storage->storeAccessToken('foo', $this->getMock('\\OAuth\\Common\\Token\\TokenInterface'));
+
+ $this->assertInstanceOf('\\OAuth\\Common\\Token\\TokenInterface', $storage->retrieveAccessToken('foo'));
+ }
+
+ /**
+ * @covers OAuth\Common\Storage\Session::__construct
+ * @covers OAuth\Common\Storage\Session::retrieveAccessToken
+ * @covers OAuth\Common\Storage\Session::hasAccessToken
+ *
+ * @runInSeparateProcess
+ */
+ public function testRetrieveAccessTokenThrowsExceptionWhenTokenIsNotFound()
+ {
+ $this->setExpectedException('\\OAuth\\Common\\Storage\\Exception\\TokenNotFoundException');
+
+ $storage = new Session();
+
+ $storage->retrieveAccessToken('foo');
+ }
+
+ /**
+ * @covers OAuth\Common\Storage\Session::__construct
+ * @covers OAuth\Common\Storage\Session::storeAccessToken
+ * @covers OAuth\Common\Storage\Session::hasAccessToken
+ *
+ * @runInSeparateProcess
+ */
+ public function testHasAccessTokenTrue()
+ {
+ $storage = new Session();
+
+ $storage->storeAccessToken('foo', $this->getMock('\\OAuth\\Common\\Token\\TokenInterface'));
+
+ $this->assertTrue($storage->hasAccessToken('foo'));
+ }
+
+ /**
+ * @covers OAuth\Common\Storage\Session::__construct
+ * @covers OAuth\Common\Storage\Session::hasAccessToken
+ *
+ * @runInSeparateProcess
+ */
+ public function testHasAccessTokenFalse()
+ {
+ $storage = new Session();
+
+ $this->assertFalse($storage->hasAccessToken('foo'));
+ }
+
+ /**
+ * @covers OAuth\Common\Storage\Session::__construct
+ * @covers OAuth\Common\Storage\Session::clearToken
+ *
+ * @runInSeparateProcess
+ */
+ public function testClearTokenIsNotSet()
+ {
+ $storage = new Session();
+
+ $this->assertInstanceOf('\\OAuth\\Common\\Storage\\Session', $storage->clearToken('foo'));
+ }
+
+ /**
+ * @covers OAuth\Common\Storage\Session::__construct
+ * @covers OAuth\Common\Storage\Session::storeAccessToken
+ * @covers OAuth\Common\Storage\Session::clearToken
+ *
+ * @runInSeparateProcess
+ */
+ public function testClearTokenSet()
+ {
+ $storage = new Session();
+
+ $storage->storeAccessToken('foo', $this->getMock('\\OAuth\\Common\\Token\\TokenInterface'));
+
+ $this->assertTrue($storage->hasAccessToken('foo'));
+ $this->assertInstanceOf('\\OAuth\\Common\\Storage\\Session', $storage->clearToken('foo'));
+ $this->assertFalse($storage->hasAccessToken('foo'));
+ }
+
+ /**
+ * @covers OAuth\Common\Storage\Session::__construct
+ * @covers OAuth\Common\Storage\Session::storeAccessToken
+ * @covers OAuth\Common\Storage\Session::clearAllTokens
+ *
+ * @runInSeparateProcess
+ */
+ public function testClearAllTokens()
+ {
+ $storage = new Session();
+
+ $storage->storeAccessToken('foo', $this->getMock('\\OAuth\\Common\\Token\\TokenInterface'));
+ $storage->storeAccessToken('bar', $this->getMock('\\OAuth\\Common\\Token\\TokenInterface'));
+
+ $this->assertTrue($storage->hasAccessToken('foo'));
+ $this->assertTrue($storage->hasAccessToken('bar'));
+ $this->assertInstanceOf('\\OAuth\\Common\\Storage\\Session', $storage->clearAllTokens());
+ $this->assertFalse($storage->hasAccessToken('foo'));
+ $this->assertFalse($storage->hasAccessToken('bar'));
+ }
+
+ /**
+ * @covers OAuth\Common\Storage\Session::__construct
+ * @covers OAuth\Common\Storage\Session::__destruct
+ *
+ * @runInSeparateProcess
+ */
+ public function testDestruct()
+ {
+ $storage = new Session();
+
+ unset($storage);
+ }
+
+ /**
+ * @covers OAuth\Common\Storage\Session::storeAccessToken
+ * @covers OAuth\Common\Storage\Session::retrieveAccessToken
+ *
+ * @runInSeparateProcess
+ */
+ public function testSerializeUnserialize()
+ {
+ $mock = $this->getMock('\\OAuth\\Common\\Token\\AbstractToken', array('__sleep'));
+ $mock->expects($this->once())
+ ->method('__sleep')
+ ->will($this->returnValue(array('accessToken')));
+
+ $storage = new Session();
+ $storage->storeAccessToken('foo', $mock);
+ $retrievedToken = $storage->retrieveAccessToken('foo');
+
+ $this->assertInstanceOf('\\OAuth\\Common\\Token\\AbstractToken', $retrievedToken);
+ }
+}
diff --git a/vendor/lusitanian/oauth/tests/Unit/Common/Storage/StorageTest.php b/vendor/lusitanian/oauth/tests/Unit/Common/Storage/StorageTest.php
new file mode 100644
index 00000000..3fe19906
--- /dev/null
+++ b/vendor/lusitanian/oauth/tests/Unit/Common/Storage/StorageTest.php
@@ -0,0 +1,74 @@
+
+ * @author Hannes Van De Vreken
+ * @copyright Copyright (c) 2012 The authors
+ * @license http://www.opensource.org/licenses/mit-license.html MIT License
+ */
+
+namespace OAuth\Unit\Common\Storage;
+
+use \OAuth\OAuth2\Token\StdOAuth2Token;
+
+abstract class StorageTest extends \PHPUnit_Framework_TestCase
+{
+ protected $storage;
+
+ /**
+ * Check that the token gets properly stored.
+ */
+ public function testStorage()
+ {
+ // arrange
+ $service_1 = 'Facebook';
+ $service_2 = 'Foursquare';
+
+ $token_1 = new StdOAuth2Token('access_1', 'refresh_1', StdOAuth2Token::EOL_NEVER_EXPIRES, array('extra' => 'param'));
+ $token_2 = new StdOAuth2Token('access_2', 'refresh_2', StdOAuth2Token::EOL_NEVER_EXPIRES, array('extra' => 'param'));
+
+ // act
+ $this->storage->storeAccessToken($service_1, $token_1);
+ $this->storage->storeAccessToken($service_2, $token_2);
+
+ // assert
+ $extraParams = $this->storage->retrieveAccessToken($service_1)->getExtraParams();
+ $this->assertEquals('param', $extraParams['extra']);
+ $this->assertEquals($token_1, $this->storage->retrieveAccessToken($service_1));
+ $this->assertEquals($token_2, $this->storage->retrieveAccessToken($service_2));
+ }
+
+ /**
+ * Test hasAccessToken.
+ */
+ public function testHasAccessToken()
+ {
+ // arrange
+ $service = 'Facebook';
+ $this->storage->clearToken($service);
+
+ // act
+ // assert
+ $this->assertFalse($this->storage->hasAccessToken($service));
+ }
+
+ /**
+ * Check that the token gets properly deleted.
+ */
+ public function testStorageClears()
+ {
+ // arrange
+ $service = 'Facebook';
+ $token = new StdOAuth2Token('access', 'refresh', StdOAuth2Token::EOL_NEVER_EXPIRES, array('extra' => 'param'));
+
+ // act
+ $this->storage->storeAccessToken($service, $token);
+ $this->storage->clearToken($service);
+
+ // assert
+ $this->setExpectedException('OAuth\Common\Storage\Exception\TokenNotFoundException');
+ $this->storage->retrieveAccessToken($service);
+ }
+}
diff --git a/vendor/lusitanian/oauth/tests/Unit/Common/Storage/SymfonySessionTest.php b/vendor/lusitanian/oauth/tests/Unit/Common/Storage/SymfonySessionTest.php
new file mode 100644
index 00000000..c6434612
--- /dev/null
+++ b/vendor/lusitanian/oauth/tests/Unit/Common/Storage/SymfonySessionTest.php
@@ -0,0 +1,111 @@
+
+ * @copyright Copyright (c) 2012 The authors
+ * @license http://www.opensource.org/licenses/mit-license.html MIT License
+ */
+
+namespace OAuth\Unit\Common\Storage;
+
+use OAuth\Common\Storage\SymfonySession;
+use OAuth\OAuth2\Token\StdOAuth2Token;
+use Symfony\Component\HttpFoundation\Session\Session;
+use Symfony\Component\HttpFoundation\Session\Storage\MockArraySessionStorage;
+
+class SymfonySessionTest extends \PHPUnit_Framework_TestCase
+{
+ protected $session;
+
+ protected $storage;
+
+ public function setUp()
+ {
+ // set it
+ $this->session = new Session(new MockArraySessionStorage());
+ $this->storage = new SymfonySession($this->session);
+ }
+
+ public function tearDown()
+ {
+ // delete
+ $this->storage->getSession()->clear();
+ unset($this->storage);
+ }
+
+ /**
+ * Check that the token survives the constructor
+ */
+ public function testStorageSurvivesConstructor()
+ {
+ $service = 'Facebook';
+ $token = new StdOAuth2Token('access', 'refresh', StdOAuth2Token::EOL_NEVER_EXPIRES, array('extra' => 'param'));
+
+ // act
+ $this->storage->storeAccessToken($service, $token);
+ $this->storage = null;
+ $this->storage = new SymfonySession($this->session);
+
+ // assert
+ $extraParams = $this->storage->retrieveAccessToken($service)->getExtraParams();
+ $this->assertEquals('param', $extraParams['extra']);
+ $this->assertEquals($token, $this->storage->retrieveAccessToken($service));
+ }
+
+ /**
+ * Check that the token gets properly stored.
+ */
+ public function testStorage()
+ {
+ // arrange
+ $service_1 = 'Facebook';
+ $service_2 = 'Foursquare';
+
+ $token_1 = new StdOAuth2Token('access_1', 'refresh_1', StdOAuth2Token::EOL_NEVER_EXPIRES, array('extra' => 'param'));
+ $token_2 = new StdOAuth2Token('access_2', 'refresh_2', StdOAuth2Token::EOL_NEVER_EXPIRES, array('extra' => 'param'));
+
+ // act
+ $this->storage->storeAccessToken($service_1, $token_1);
+ $this->storage->storeAccessToken($service_2, $token_2);
+
+ // assert
+ $extraParams = $this->storage->retrieveAccessToken($service_1)->getExtraParams();
+ $this->assertEquals('param', $extraParams['extra']);
+ $this->assertEquals($token_1, $this->storage->retrieveAccessToken($service_1));
+ $this->assertEquals($token_2, $this->storage->retrieveAccessToken($service_2));
+ }
+
+ /**
+ * Test hasAccessToken.
+ */
+ public function testHasAccessToken()
+ {
+ // arrange
+ $service = 'Facebook';
+ $this->storage->clearToken($service);
+
+ // act
+ // assert
+ $this->assertFalse($this->storage->hasAccessToken($service));
+ }
+
+ /**
+ * Check that the token gets properly deleted.
+ */
+ public function testStorageClears()
+ {
+ // arrange
+ $service = 'Facebook';
+ $token = new StdOAuth2Token('access', 'refresh', StdOAuth2Token::EOL_NEVER_EXPIRES, array('extra' => 'param'));
+
+ // act
+ $this->storage->storeAccessToken($service, $token);
+ $this->storage->clearToken($service);
+
+ // assert
+ $this->setExpectedException('OAuth\Common\Storage\Exception\TokenNotFoundException');
+ $this->storage->retrieveAccessToken($service);
+ }
+}
diff --git a/vendor/lusitanian/oauth/tests/Unit/Common/Token/AbstractTokenTest.php b/vendor/lusitanian/oauth/tests/Unit/Common/Token/AbstractTokenTest.php
new file mode 100644
index 00000000..54b3bb63
--- /dev/null
+++ b/vendor/lusitanian/oauth/tests/Unit/Common/Token/AbstractTokenTest.php
@@ -0,0 +1,189 @@
+getMockForAbstractClass('\\OAuth\\Common\\Token\\AbstractToken');
+
+ $this->assertInstanceOf('\\OAuth\\Common\\Token\\TokenInterface', $token);
+ }
+
+ /**
+ * @covers OAuth\Common\Token\AbstractToken::__construct
+ * @covers OAuth\Common\Token\AbstractToken::getAccessToken
+ */
+ public function testGetAccessTokenNotSet()
+ {
+ $token = $this->getMockForAbstractClass('\\OAuth\\Common\\Token\\AbstractToken');
+
+ $this->assertNull($token->getAccessToken());
+ }
+
+ /**
+ * @covers OAuth\Common\Token\AbstractToken::__construct
+ * @covers OAuth\Common\Token\AbstractToken::getAccessToken
+ */
+ public function testGetAccessTokenSet()
+ {
+ $token = $this->getMockForAbstractClass('\\OAuth\\Common\\Token\\AbstractToken', array('foo'));
+
+ $this->assertSame('foo', $token->getAccessToken());
+ }
+
+ /**
+ * @covers OAuth\Common\Token\AbstractToken::__construct
+ * @covers OAuth\Common\Token\AbstractToken::getAccessToken
+ * @covers OAuth\Common\Token\AbstractToken::setAccessToken
+ */
+ public function testSetAccessToken()
+ {
+ $token = $this->getMockForAbstractClass('\\OAuth\\Common\\Token\\AbstractToken');
+
+ $token->setAccessToken('foo');
+
+ $this->assertSame('foo', $token->getAccessToken());
+ }
+
+ /**
+ * @covers OAuth\Common\Token\AbstractToken::__construct
+ * @covers OAuth\Common\Token\AbstractToken::getRefreshToken
+ */
+ public function testGetRefreshToken()
+ {
+ $token = $this->getMockForAbstractClass('\\OAuth\\Common\\Token\\AbstractToken');
+
+ $this->assertNull($token->getRefreshToken());
+ }
+
+ /**
+ * @covers OAuth\Common\Token\AbstractToken::__construct
+ * @covers OAuth\Common\Token\AbstractToken::getRefreshToken
+ */
+ public function testGetRefreshTokenSet()
+ {
+ $token = $this->getMockForAbstractClass('\\OAuth\\Common\\Token\\AbstractToken', array('foo', 'bar'));
+
+ $this->assertSame('bar', $token->getRefreshToken());
+ }
+
+ /**
+ * @covers OAuth\Common\Token\AbstractToken::__construct
+ * @covers OAuth\Common\Token\AbstractToken::getRefreshToken
+ * @covers OAuth\Common\Token\AbstractToken::setRefreshToken
+ */
+ public function testSetRefreshToken()
+ {
+ $token = $this->getMockForAbstractClass('\\OAuth\\Common\\Token\\AbstractToken');
+
+ $token->setRefreshToken('foo');
+
+ $this->assertSame('foo', $token->getRefreshToken());
+ }
+
+ /**
+ * @covers OAuth\Common\Token\AbstractToken::__construct
+ * @covers OAuth\Common\Token\AbstractToken::getExtraParams
+ */
+ public function testGetExtraParamsNotSet()
+ {
+ $token = $this->getMockForAbstractClass('\\OAuth\\Common\\Token\\AbstractToken');
+
+ $this->assertSame(array(), $token->getExtraParams());
+ }
+
+ /**
+ * @covers OAuth\Common\Token\AbstractToken::__construct
+ * @covers OAuth\Common\Token\AbstractToken::getExtraParams
+ */
+ public function testGetExtraParamsSet()
+ {
+ $token = $this->getMockForAbstractClass('\\OAuth\\Common\\Token\\AbstractToken', array('foo', 'bar', null, array('foo', 'bar')));
+
+ $this->assertEquals(array('foo', 'bar'), $token->getExtraParams());
+ }
+
+ /**
+ * @covers OAuth\Common\Token\AbstractToken::__construct
+ * @covers OAuth\Common\Token\AbstractToken::setExtraParams
+ * @covers OAuth\Common\Token\AbstractToken::getExtraParams
+ */
+ public function testSetExtraParams()
+ {
+ $token = $this->getMockForAbstractClass('\\OAuth\\Common\\Token\\AbstractToken');
+
+ $token->setExtraParams(array('foo', 'bar'));
+
+ $this->assertSame(array('foo', 'bar'), $token->getExtraParams());
+ }
+
+ /**
+ * @covers OAuth\Common\Token\AbstractToken::__construct
+ * @covers OAuth\Common\Token\AbstractToken::setLifetime
+ * @covers OAuth\Common\Token\AbstractToken::getEndOfLife
+ */
+ public function testGetEndOfLifeNotSet()
+ {
+ $token = $this->getMockForAbstractClass('\\OAuth\\Common\\Token\\AbstractToken');
+
+ $this->assertSame(AbstractToken::EOL_UNKNOWN, $token->getEndOfLife());
+ }
+
+ /**
+ * @covers OAuth\Common\Token\AbstractToken::__construct
+ * @covers OAuth\Common\Token\AbstractToken::setLifetime
+ * @covers OAuth\Common\Token\AbstractToken::getEndOfLife
+ */
+ public function testGetEndOfLifeZero()
+ {
+ $token = $this->getMockForAbstractClass('\\OAuth\\Common\\Token\\AbstractToken', array('foo', 'bar', 0));
+
+ $this->assertSame(AbstractToken::EOL_NEVER_EXPIRES, $token->getEndOfLife());
+ }
+
+ /**
+ * @covers OAuth\Common\Token\AbstractToken::__construct
+ * @covers OAuth\Common\Token\AbstractToken::setLifetime
+ * @covers OAuth\Common\Token\AbstractToken::getEndOfLife
+ */
+ public function testGetEndOfLifeNeverExpires()
+ {
+ $token = $this->getMockForAbstractClass('\\OAuth\\Common\\Token\\AbstractToken', array('foo', 'bar', AbstractToken::EOL_NEVER_EXPIRES));
+
+ $this->assertSame(AbstractToken::EOL_NEVER_EXPIRES, $token->getEndOfLife());
+ }
+
+ /**
+ * @covers OAuth\Common\Token\AbstractToken::__construct
+ * @covers OAuth\Common\Token\AbstractToken::setLifetime
+ * @covers OAuth\Common\Token\AbstractToken::getEndOfLife
+ */
+ public function testGetEndOfLifeNeverExpiresFiveMinutes()
+ {
+ $token = $this->getMockForAbstractClass('\\OAuth\\Common\\Token\\AbstractToken', array('foo', 'bar', 5 * 60));
+
+ $this->assertSame(time() + (5*60), $token->getEndOfLife());
+ }
+
+ /**
+ * @covers OAuth\Common\Token\AbstractToken::__construct
+ * @covers OAuth\Common\Token\AbstractToken::setLifetime
+ * @covers OAuth\Common\Token\AbstractToken::getEndOfLife
+ * @covers OAuth\Common\Token\AbstractToken::setEndOfLife
+ */
+ public function testSetEndOfLife()
+ {
+ $token = $this->getMockForAbstractClass('\\OAuth\\Common\\Token\\AbstractToken');
+
+ $token->setEndOfLife(10);
+
+ $this->assertSame(10, $token->getEndOfLife());
+ }
+}
diff --git a/vendor/lusitanian/oauth/tests/Unit/OAuth1/Service/AbstractServiceTest.php b/vendor/lusitanian/oauth/tests/Unit/OAuth1/Service/AbstractServiceTest.php
new file mode 100644
index 00000000..ab5417b2
--- /dev/null
+++ b/vendor/lusitanian/oauth/tests/Unit/OAuth1/Service/AbstractServiceTest.php
@@ -0,0 +1,215 @@
+getMockForAbstractClass(
+ '\\OAuth\\OAuth1\\Service\\AbstractService',
+ array(
+ $this->getMock('\\OAuth\\Common\\Consumer\\CredentialsInterface'),
+ $this->getMock('\\OAuth\\Common\\Http\\Client\\ClientInterface'),
+ $this->getMock('\\OAuth\\Common\\Storage\\TokenStorageInterface'),
+ $this->getMock('\\OAuth\\OAuth1\\Signature\\SignatureInterface'),
+ $this->getMock('\\OAuth\\Common\\Http\\Uri\\UriInterface'),
+ )
+ );
+
+ $this->assertInstanceOf('\\OAuth\\OAuth1\\Service\\ServiceInterface', $service);
+ }
+
+ /**
+ * @covers OAuth\OAuth1\Service\AbstractService::__construct
+ */
+ public function testConstructCorrectParent()
+ {
+ $service = $this->getMockForAbstractClass(
+ '\\OAuth\\OAuth1\\Service\\AbstractService',
+ array(
+ $this->getMock('\\OAuth\\Common\\Consumer\\CredentialsInterface'),
+ $this->getMock('\\OAuth\\Common\\Http\\Client\\ClientInterface'),
+ $this->getMock('\\OAuth\\Common\\Storage\\TokenStorageInterface'),
+ $this->getMock('\\OAuth\\OAuth1\\Signature\\SignatureInterface'),
+ $this->getMock('\\OAuth\\Common\\Http\\Uri\\UriInterface'),
+ )
+ );
+
+ $this->assertInstanceOf('\\OAuth\\Common\\Service\\AbstractService', $service);
+ }
+
+ /**
+ * @covers OAuth\OAuth1\Service\AbstractService::requestRequestToken
+ * @covers OAuth\OAuth1\Service\AbstractService::buildAuthorizationHeaderForTokenRequest
+ * @covers OAuth\OAuth1\Service\AbstractService::getBasicAuthorizationHeaderInfo
+ * @covers OAuth\OAuth1\Service\AbstractService::generateNonce
+ * @covers OAuth\OAuth1\Service\AbstractService::getSignatureMethod
+ * @covers OAuth\OAuth1\Service\AbstractService::getVersion
+ * @covers OAuth\OAuth1\Service\AbstractService::getExtraOAuthHeaders
+ * @covers OAuth\OAuth1\Service\AbstractService::parseRequestTokenResponse
+ */
+ public function testRequestRequestTokenBuildAuthHeaderTokenRequestWithoutParams()
+ {
+ $client = $this->getMock('\\OAuth\\Common\\Http\\Client\\ClientInterface');
+ $client->expects($this->once())->method('retrieveResponse')->will($this->returnCallback(function($endpoint, $array, $headers) {
+ \PHPUnit_Framework_Assert::assertSame('http://pieterhordijk.com/token', $endpoint->getAbsoluteUri());
+ }));
+
+ $service = new Mock(
+ $this->getMock('\\OAuth\\Common\\Consumer\\CredentialsInterface'),
+ $client,
+ $this->getMock('\\OAuth\\Common\\Storage\\TokenStorageInterface'),
+ $this->getMock('\\OAuth\\OAuth1\\Signature\\SignatureInterface'),
+ $this->getMock('\\OAuth\\Common\\Http\\Uri\\UriInterface')
+ );
+
+ $this->assertInstanceOf('\\OAuth\\OAuth1\\Token\\StdOAuth1Token', $service->requestRequestToken());
+ }
+
+ /**
+ * @covers OAuth\OAuth1\Service\AbstractService::getAuthorizationUri
+ * @covers OAuth\OAuth1\Service\AbstractService::getAuthorizationEndpoint
+ */
+ public function testGetAuthorizationUriWithoutParameters()
+ {
+ $service = new Mock(
+ $this->getMock('\\OAuth\\Common\\Consumer\\CredentialsInterface'),
+ $this->getMock('\\OAuth\\Common\\Http\\Client\\ClientInterface'),
+ $this->getMock('\\OAuth\\Common\\Storage\\TokenStorageInterface'),
+ $this->getMock('\\OAuth\\OAuth1\\Signature\\SignatureInterface'),
+ $this->getMock('\\OAuth\\Common\\Http\\Uri\\UriInterface')
+ );
+
+ $this->assertSame('http://pieterhordijk.com/auth', $service->getAuthorizationUri()->getAbsoluteUri());
+ }
+
+ /**
+ * @covers OAuth\OAuth1\Service\AbstractService::getAuthorizationUri
+ * @covers OAuth\OAuth1\Service\AbstractService::getAuthorizationEndpoint
+ */
+ public function testGetAuthorizationUriWithParameters()
+ {
+ $service = new Mock(
+ $this->getMock('\\OAuth\\Common\\Consumer\\CredentialsInterface'),
+ $this->getMock('\\OAuth\\Common\\Http\\Client\\ClientInterface'),
+ $this->getMock('\\OAuth\\Common\\Storage\\TokenStorageInterface'),
+ $this->getMock('\\OAuth\\OAuth1\\Signature\\SignatureInterface'),
+ $this->getMock('\\OAuth\\Common\\Http\\Uri\\UriInterface')
+ );
+
+ $this->assertSame('http://pieterhordijk.com/auth?foo=bar&baz=beer', $service->getAuthorizationUri(array(
+ 'foo' => 'bar',
+ 'baz' => 'beer',
+ ))->getAbsoluteUri());
+ }
+
+ /**
+ * @covers OAuth\OAuth1\Service\AbstractService::requestAccessToken
+ * @covers OAuth\OAuth1\Service\AbstractService::service
+ * @covers OAuth\OAuth1\Service\AbstractService::buildAuthorizationHeaderForAPIRequest
+ * @covers OAuth\OAuth1\Service\AbstractService::getBasicAuthorizationHeaderInfo
+ * @covers OAuth\OAuth1\Service\AbstractService::generateNonce
+ * @covers OAuth\OAuth1\Service\AbstractService::getSignatureMethod
+ * @covers OAuth\OAuth1\Service\AbstractService::getVersion
+ * @covers OAuth\OAuth1\Service\AbstractService::getAccessTokenEndpoint
+ * @covers OAuth\OAuth1\Service\AbstractService::getExtraOAuthHeaders
+ * @covers OAuth\OAuth1\Service\AbstractService::parseAccessTokenResponse
+ */
+ public function testRequestAccessTokenWithoutSecret()
+ {
+ $client = $this->getMock('\\OAuth\\Common\\Http\\Client\\ClientInterface');
+ $client->expects($this->once())->method('retrieveResponse')->will($this->returnCallback(function($endpoint, $array, $headers) {
+ \PHPUnit_Framework_Assert::assertSame('http://pieterhordijk.com/access', $endpoint->getAbsoluteUri());
+ }));
+
+ $token = $this->getMock('\\OAuth\\OAuth1\\Token\\TokenInterface');
+ $token->expects($this->once())->method('getRequestTokenSecret')->will($this->returnValue('baz'));
+
+ $storage = $this->getMock('\\OAuth\\Common\\Storage\\TokenStorageInterface');
+ $storage->expects($this->any())->method('retrieveAccessToken')->will($this->returnValue($token));
+
+ $service = new Mock(
+ $this->getMock('\\OAuth\\Common\\Consumer\\CredentialsInterface'),
+ $client,
+ $storage,
+ $this->getMock('\\OAuth\\OAuth1\\Signature\\SignatureInterface'),
+ $this->getMock('\\OAuth\\Common\\Http\\Uri\\UriInterface')
+ );
+
+ $this->assertInstanceOf('\\OAuth\\OAuth1\\Token\\StdOAuth1Token', $service->requestAccessToken('foo', 'bar'));
+ }
+
+ /**
+ * @covers OAuth\OAuth1\Service\AbstractService::requestAccessToken
+ * @covers OAuth\OAuth1\Service\AbstractService::service
+ * @covers OAuth\OAuth1\Service\AbstractService::buildAuthorizationHeaderForAPIRequest
+ * @covers OAuth\OAuth1\Service\AbstractService::getBasicAuthorizationHeaderInfo
+ * @covers OAuth\OAuth1\Service\AbstractService::generateNonce
+ * @covers OAuth\OAuth1\Service\AbstractService::getSignatureMethod
+ * @covers OAuth\OAuth1\Service\AbstractService::getVersion
+ * @covers OAuth\OAuth1\Service\AbstractService::getAccessTokenEndpoint
+ * @covers OAuth\OAuth1\Service\AbstractService::getExtraOAuthHeaders
+ * @covers OAuth\OAuth1\Service\AbstractService::parseAccessTokenResponse
+ */
+ public function testRequestAccessTokenWithSecret()
+ {
+ $client = $this->getMock('\\OAuth\\Common\\Http\\Client\\ClientInterface');
+ $client->expects($this->once())->method('retrieveResponse')->will($this->returnCallback(function($endpoint, $array, $headers) {
+ \PHPUnit_Framework_Assert::assertSame('http://pieterhordijk.com/access', $endpoint->getAbsoluteUri());
+ }));
+
+ $token = $this->getMock('\\OAuth\\OAuth1\\Token\\TokenInterface');
+
+ $storage = $this->getMock('\\OAuth\\Common\\Storage\\TokenStorageInterface');
+ $storage->expects($this->any())->method('retrieveAccessToken')->will($this->returnValue($token));
+
+ $service = new Mock(
+ $this->getMock('\\OAuth\\Common\\Consumer\\CredentialsInterface'),
+ $client,
+ $storage,
+ $this->getMock('\\OAuth\\OAuth1\\Signature\\SignatureInterface'),
+ $this->getMock('\\OAuth\\Common\\Http\\Uri\\UriInterface')
+ );
+
+ $this->assertInstanceOf('\\OAuth\\OAuth1\\Token\\StdOAuth1Token', $service->requestAccessToken('foo', 'bar', $token));
+ }
+
+ /**
+ * @covers OAuth\OAuth1\Service\AbstractService::request
+ * @covers OAuth\OAuth1\Service\AbstractService::determineRequestUriFromPath
+ * @covers OAuth\OAuth1\Service\AbstractService::service
+ * @covers OAuth\OAuth1\Service\AbstractService::getExtraApiHeaders
+ * @covers OAuth\OAuth1\Service\AbstractService::buildAuthorizationHeaderForAPIRequest
+ * @covers OAuth\OAuth1\Service\AbstractService::getBasicAuthorizationHeaderInfo
+ * @covers OAuth\OAuth1\Service\AbstractService::generateNonce
+ * @covers OAuth\OAuth1\Service\AbstractService::getSignatureMethod
+ * @covers OAuth\OAuth1\Service\AbstractService::getVersion
+ */
+ public function testRequest()
+ {
+ $client = $this->getMock('\\OAuth\\Common\\Http\\Client\\ClientInterface');
+ $client->expects($this->once())->method('retrieveResponse')->will($this->returnValue('response!'));
+
+ $token = $this->getMock('\\OAuth\\OAuth1\\Token\\TokenInterface');
+ //$token->expects($this->once())->method('getRequestTokenSecret')->will($this->returnValue('baz'));
+
+ $storage = $this->getMock('\\OAuth\\Common\\Storage\\TokenStorageInterface');
+ $storage->expects($this->any())->method('retrieveAccessToken')->will($this->returnValue($token));
+
+ $service = new Mock(
+ $this->getMock('\\OAuth\\Common\\Consumer\\CredentialsInterface'),
+ $client,
+ $storage,
+ $this->getMock('\\OAuth\\OAuth1\\Signature\\SignatureInterface'),
+ $this->getMock('\\OAuth\\Common\\Http\\Uri\\UriInterface')
+ );
+
+ $this->assertSame('response!', $service->request('/my/awesome/path'));
+ }
+}
diff --git a/vendor/lusitanian/oauth/tests/Unit/OAuth1/Service/BitBucketTest.php b/vendor/lusitanian/oauth/tests/Unit/OAuth1/Service/BitBucketTest.php
new file mode 100644
index 00000000..87be98b1
--- /dev/null
+++ b/vendor/lusitanian/oauth/tests/Unit/OAuth1/Service/BitBucketTest.php
@@ -0,0 +1,278 @@
+getMock('\\OAuth\\Common\\Consumer\\CredentialsInterface'),
+ $this->getMock('\\OAuth\\Common\\Http\\Client\\ClientInterface'),
+ $this->getMock('\\OAuth\\Common\\Storage\\TokenStorageInterface'),
+ $this->getMock('\\OAuth\\OAuth1\\Signature\\SignatureInterface')
+ );
+
+ $this->assertInstanceOf('\\OAuth\\OAuth1\\Service\\ServiceInterface', $service);
+ }
+
+ /**
+ * @covers OAuth\OAuth1\Service\BitBucket::__construct
+ */
+ public function testConstructCorrectInstanceWithoutCustomUri()
+ {
+ $service = new BitBucket(
+ $this->getMock('\\OAuth\\Common\\Consumer\\CredentialsInterface'),
+ $this->getMock('\\OAuth\\Common\\Http\\Client\\ClientInterface'),
+ $this->getMock('\\OAuth\\Common\\Storage\\TokenStorageInterface'),
+ $this->getMock('\\OAuth\\OAuth1\\Signature\\SignatureInterface')
+ );
+
+ $this->assertInstanceOf('\\OAuth\\OAuth1\\Service\\AbstractService', $service);
+ }
+
+ /**
+ * @covers OAuth\OAuth1\Service\BitBucket::__construct
+ */
+ public function testConstructCorrectInstanceWithCustomUri()
+ {
+ $service = new BitBucket(
+ $this->getMock('\\OAuth\\Common\\Consumer\\CredentialsInterface'),
+ $this->getMock('\\OAuth\\Common\\Http\\Client\\ClientInterface'),
+ $this->getMock('\\OAuth\\Common\\Storage\\TokenStorageInterface'),
+ $this->getMock('\\OAuth\\OAuth1\\Signature\\SignatureInterface'),
+ $this->getMock('\\OAuth\\Common\\Http\\Uri\\UriInterface')
+ );
+
+ $this->assertInstanceOf('\\OAuth\\OAuth1\\Service\\AbstractService', $service);
+ }
+
+ /**
+ * @covers OAuth\OAuth1\Service\BitBucket::__construct
+ * @covers OAuth\OAuth1\Service\BitBucket::getRequestTokenEndpoint
+ */
+ public function testGetRequestTokenEndpoint()
+ {
+ $service = new BitBucket(
+ $this->getMock('\\OAuth\\Common\\Consumer\\CredentialsInterface'),
+ $this->getMock('\\OAuth\\Common\\Http\\Client\\ClientInterface'),
+ $this->getMock('\\OAuth\\Common\\Storage\\TokenStorageInterface'),
+ $this->getMock('\\OAuth\\OAuth1\\Signature\\SignatureInterface')
+ );
+
+ $this->assertSame(
+ 'https://bitbucket.org/!api/1.0/oauth/request_token',
+ $service->getRequestTokenEndpoint()->getAbsoluteUri()
+ );
+ }
+
+ /**
+ * @covers OAuth\OAuth1\Service\BitBucket::__construct
+ * @covers OAuth\OAuth1\Service\BitBucket::getAuthorizationEndpoint
+ */
+ public function testGetAuthorizationEndpoint()
+ {
+ $service = new BitBucket(
+ $this->getMock('\\OAuth\\Common\\Consumer\\CredentialsInterface'),
+ $this->getMock('\\OAuth\\Common\\Http\\Client\\ClientInterface'),
+ $this->getMock('\\OAuth\\Common\\Storage\\TokenStorageInterface'),
+ $this->getMock('\\OAuth\\OAuth1\\Signature\\SignatureInterface')
+ );
+
+ $this->assertSame(
+ 'https://bitbucket.org/!api/1.0/oauth/authenticate',
+ $service->getAuthorizationEndpoint()->getAbsoluteUri()
+ );
+ }
+
+ /**
+ * @covers OAuth\OAuth1\Service\BitBucket::__construct
+ * @covers OAuth\OAuth1\Service\BitBucket::getAccessTokenEndpoint
+ */
+ public function testGetAccessTokenEndpoint()
+ {
+ $service = new BitBucket(
+ $this->getMock('\\OAuth\\Common\\Consumer\\CredentialsInterface'),
+ $this->getMock('\\OAuth\\Common\\Http\\Client\\ClientInterface'),
+ $this->getMock('\\OAuth\\Common\\Storage\\TokenStorageInterface'),
+ $this->getMock('\\OAuth\\OAuth1\\Signature\\SignatureInterface')
+ );
+
+ $this->assertSame(
+ 'https://bitbucket.org/!api/1.0/oauth/access_token',
+ $service->getAccessTokenEndpoint()->getAbsoluteUri()
+ );
+ }
+
+ /**
+ * @covers OAuth\OAuth1\Service\BitBucket::__construct
+ * @covers OAuth\OAuth1\Service\BitBucket::getRequestTokenEndpoint
+ * @covers OAuth\OAuth1\Service\BitBucket::parseRequestTokenResponse
+ */
+ public function testParseRequestTokenResponseThrowsExceptionOnNulledResponse()
+ {
+ $client = $this->getMock('\\OAuth\\Common\\Http\\Client\\ClientInterface');
+ $client->expects($this->once())->method('retrieveResponse')->will($this->returnValue(null));
+
+ $service = new BitBucket(
+ $this->getMock('\\OAuth\\Common\\Consumer\\CredentialsInterface'),
+ $client,
+ $this->getMock('\\OAuth\\Common\\Storage\\TokenStorageInterface'),
+ $this->getMock('\\OAuth\\OAuth1\\Signature\\SignatureInterface')
+ );
+
+ $this->setExpectedException('\\OAuth\\Common\\Http\\Exception\\TokenResponseException');
+
+ $service->requestRequestToken();
+ }
+
+ /**
+ * @covers OAuth\OAuth1\Service\BitBucket::__construct
+ * @covers OAuth\OAuth1\Service\BitBucket::getRequestTokenEndpoint
+ * @covers OAuth\OAuth1\Service\BitBucket::parseRequestTokenResponse
+ */
+ public function testParseRequestTokenResponseThrowsExceptionOnResponseNotAnArray()
+ {
+ $client = $this->getMock('\\OAuth\\Common\\Http\\Client\\ClientInterface');
+ $client->expects($this->once())->method('retrieveResponse')->will($this->returnValue('notanarray'));
+
+ $service = new BitBucket(
+ $this->getMock('\\OAuth\\Common\\Consumer\\CredentialsInterface'),
+ $client,
+ $this->getMock('\\OAuth\\Common\\Storage\\TokenStorageInterface'),
+ $this->getMock('\\OAuth\\OAuth1\\Signature\\SignatureInterface')
+ );
+
+ $this->setExpectedException('\\OAuth\\Common\\Http\\Exception\\TokenResponseException');
+
+ $service->requestRequestToken();
+ }
+
+ /**
+ * @covers OAuth\OAuth1\Service\BitBucket::__construct
+ * @covers OAuth\OAuth1\Service\BitBucket::getRequestTokenEndpoint
+ * @covers OAuth\OAuth1\Service\BitBucket::parseRequestTokenResponse
+ */
+ public function testParseRequestTokenResponseThrowsExceptionOnResponseCallbackNotSet()
+ {
+ $client = $this->getMock('\\OAuth\\Common\\Http\\Client\\ClientInterface');
+ $client->expects($this->once())->method('retrieveResponse')->will($this->returnValue('foo=bar'));
+
+ $service = new BitBucket(
+ $this->getMock('\\OAuth\\Common\\Consumer\\CredentialsInterface'),
+ $client,
+ $this->getMock('\\OAuth\\Common\\Storage\\TokenStorageInterface'),
+ $this->getMock('\\OAuth\\OAuth1\\Signature\\SignatureInterface')
+ );
+
+ $this->setExpectedException('\\OAuth\\Common\\Http\\Exception\\TokenResponseException');
+
+ $service->requestRequestToken();
+ }
+
+ /**
+ * @covers OAuth\OAuth1\Service\BitBucket::__construct
+ * @covers OAuth\OAuth1\Service\BitBucket::getRequestTokenEndpoint
+ * @covers OAuth\OAuth1\Service\BitBucket::parseRequestTokenResponse
+ */
+ public function testParseRequestTokenResponseThrowsExceptionOnResponseCallbackNotTrue()
+ {
+ $client = $this->getMock('\\OAuth\\Common\\Http\\Client\\ClientInterface');
+ $client->expects($this->once())->method('retrieveResponse')->will($this->returnValue(
+ 'oauth_callback_confirmed=false'
+ ));
+
+ $service = new BitBucket(
+ $this->getMock('\\OAuth\\Common\\Consumer\\CredentialsInterface'),
+ $client,
+ $this->getMock('\\OAuth\\Common\\Storage\\TokenStorageInterface'),
+ $this->getMock('\\OAuth\\OAuth1\\Signature\\SignatureInterface')
+ );
+
+ $this->setExpectedException('\\OAuth\\Common\\Http\\Exception\\TokenResponseException');
+
+ $service->requestRequestToken();
+ }
+
+ /**
+ * @covers OAuth\OAuth1\Service\BitBucket::__construct
+ * @covers OAuth\OAuth1\Service\BitBucket::getRequestTokenEndpoint
+ * @covers OAuth\OAuth1\Service\BitBucket::parseRequestTokenResponse
+ * @covers OAuth\OAuth1\Service\BitBucket::parseAccessTokenResponse
+ */
+ public function testParseRequestTokenResponseValid()
+ {
+ $client = $this->getMock('\\OAuth\\Common\\Http\\Client\\ClientInterface');
+ $client->expects($this->once())->method('retrieveResponse')->will($this->returnValue(
+ 'oauth_callback_confirmed=true&oauth_token=foo&oauth_token_secret=bar'
+ ));
+
+ $service = new BitBucket(
+ $this->getMock('\\OAuth\\Common\\Consumer\\CredentialsInterface'),
+ $client,
+ $this->getMock('\\OAuth\\Common\\Storage\\TokenStorageInterface'),
+ $this->getMock('\\OAuth\\OAuth1\\Signature\\SignatureInterface')
+ );
+
+ $this->assertInstanceOf('\\OAuth\\OAuth1\\Token\\StdOAuth1Token', $service->requestRequestToken());
+ }
+
+ /**
+ * @covers OAuth\OAuth1\Service\BitBucket::__construct
+ * @covers OAuth\OAuth1\Service\BitBucket::getRequestTokenEndpoint
+ * @covers OAuth\OAuth1\Service\BitBucket::parseAccessTokenResponse
+ */
+ public function testParseAccessTokenResponseThrowsExceptionOnError()
+ {
+ $client = $this->getMock('\\OAuth\\Common\\Http\\Client\\ClientInterface');
+ $client->expects($this->once())->method('retrieveResponse')->will($this->returnValue('error=bar'));
+
+ $token = $this->getMock('\\OAuth\\OAuth1\\Token\\TokenInterface');
+
+ $storage = $this->getMock('\\OAuth\\Common\\Storage\\TokenStorageInterface');
+ $storage->expects($this->any())->method('retrieveAccessToken')->will($this->returnValue($token));
+
+ $service = new BitBucket(
+ $this->getMock('\\OAuth\\Common\\Consumer\\CredentialsInterface'),
+ $client,
+ $storage,
+ $this->getMock('\\OAuth\\OAuth1\\Signature\\SignatureInterface')
+ );
+
+ $this->setExpectedException('\\OAuth\\Common\\Http\\Exception\\TokenResponseException');
+
+ $service->requestAccessToken('foo', 'bar', $token);
+ }
+
+ /**
+ * @covers OAuth\OAuth1\Service\BitBucket::__construct
+ * @covers OAuth\OAuth1\Service\BitBucket::getRequestTokenEndpoint
+ * @covers OAuth\OAuth1\Service\BitBucket::parseAccessTokenResponse
+ */
+ public function testParseAccessTokenResponseValid()
+ {
+ $client = $this->getMock('\\OAuth\\Common\\Http\\Client\\ClientInterface');
+ $client->expects($this->once())->method('retrieveResponse')->will($this->returnValue(
+ 'oauth_token=foo&oauth_token_secret=bar'
+ ));
+
+ $token = $this->getMock('\\OAuth\\OAuth1\\Token\\TokenInterface');
+
+ $storage = $this->getMock('\\OAuth\\Common\\Storage\\TokenStorageInterface');
+ $storage->expects($this->any())->method('retrieveAccessToken')->will($this->returnValue($token));
+
+ $service = new BitBucket(
+ $this->getMock('\\OAuth\\Common\\Consumer\\CredentialsInterface'),
+ $client,
+ $storage,
+ $this->getMock('\\OAuth\\OAuth1\\Signature\\SignatureInterface')
+ );
+
+ $this->assertInstanceOf('\\OAuth\\OAuth1\\Token\\StdOAuth1Token', $service->requestAccessToken('foo', 'bar', $token));
+ }
+}
diff --git a/vendor/lusitanian/oauth/tests/Unit/OAuth1/Service/EtsyTest.php b/vendor/lusitanian/oauth/tests/Unit/OAuth1/Service/EtsyTest.php
new file mode 100644
index 00000000..97ad3cdd
--- /dev/null
+++ b/vendor/lusitanian/oauth/tests/Unit/OAuth1/Service/EtsyTest.php
@@ -0,0 +1,286 @@
+getMock('\\OAuth\\Common\\Consumer\\CredentialsInterface'),
+ $this->getMock('\\OAuth\\Common\\Http\\Client\\ClientInterface'),
+ $this->getMock('\\OAuth\\Common\\Storage\\TokenStorageInterface'),
+ $this->getMock('\\OAuth\\OAuth1\\Signature\\SignatureInterface')
+ );
+
+ $this->assertInstanceOf('\\OAuth\\OAuth1\\Service\\ServiceInterface', $service);
+ }
+
+ /**
+ * @covers OAuth\OAuth1\Service\Etsy::__construct
+ */
+ public function testConstructCorrectInstanceWithoutCustomUri()
+ {
+ $service = new Etsy(
+ $this->getMock('\\OAuth\\Common\\Consumer\\CredentialsInterface'),
+ $this->getMock('\\OAuth\\Common\\Http\\Client\\ClientInterface'),
+ $this->getMock('\\OAuth\\Common\\Storage\\TokenStorageInterface'),
+ $this->getMock('\\OAuth\\OAuth1\\Signature\\SignatureInterface')
+ );
+
+ $this->assertInstanceOf('\\OAuth\\OAuth1\\Service\\AbstractService', $service);
+ }
+
+ /**
+ * @covers OAuth\OAuth1\Service\Etsy::__construct
+ */
+ public function testConstructCorrectInstanceWithCustomUri()
+ {
+ $service = new Etsy(
+ $this->getMock('\\OAuth\\Common\\Consumer\\CredentialsInterface'),
+ $this->getMock('\\OAuth\\Common\\Http\\Client\\ClientInterface'),
+ $this->getMock('\\OAuth\\Common\\Storage\\TokenStorageInterface'),
+ $this->getMock('\\OAuth\\OAuth1\\Signature\\SignatureInterface'),
+ $this->getMock('\\OAuth\\Common\\Http\\Uri\\UriInterface')
+ );
+
+ $this->assertInstanceOf('\\OAuth\\OAuth1\\Service\\AbstractService', $service);
+ }
+
+ /**
+ * @covers OAuth\OAuth1\Service\Etsy::__construct
+ * @covers OAuth\OAuth1\Service\Etsy::getRequestTokenEndpoint
+ */
+ public function testGetRequestTokenEndpoint()
+ {
+ $service = new Etsy(
+ $this->getMock('\\OAuth\\Common\\Consumer\\CredentialsInterface'),
+ $this->getMock('\\OAuth\\Common\\Http\\Client\\ClientInterface'),
+ $this->getMock('\\OAuth\\Common\\Storage\\TokenStorageInterface'),
+ $this->getMock('\\OAuth\\OAuth1\\Signature\\SignatureInterface')
+ );
+
+ $this->assertSame(
+ 'https://openapi.etsy.com/v2/oauth/request_token',
+ $service->getRequestTokenEndpoint()->getAbsoluteUri()
+ );
+
+ $service->setScopes(array('email_r', 'cart_rw'));
+
+ $this->assertSame(
+ 'https://openapi.etsy.com/v2/oauth/request_token?scope=email_r%20cart_rw',
+ $service->getRequestTokenEndpoint()->getAbsoluteUri()
+ );
+
+ }
+
+ /**
+ * @covers OAuth\OAuth1\Service\Etsy::__construct
+ * @covers OAuth\OAuth1\Service\Etsy::getAuthorizationEndpoint
+ */
+ public function testGetAuthorizationEndpoint()
+ {
+ $service = new Etsy(
+ $this->getMock('\\OAuth\\Common\\Consumer\\CredentialsInterface'),
+ $this->getMock('\\OAuth\\Common\\Http\\Client\\ClientInterface'),
+ $this->getMock('\\OAuth\\Common\\Storage\\TokenStorageInterface'),
+ $this->getMock('\\OAuth\\OAuth1\\Signature\\SignatureInterface')
+ );
+
+ $this->assertSame(
+ 'https://openapi.etsy.com/v2/',
+ $service->getAuthorizationEndpoint()->getAbsoluteUri()
+ );
+ }
+
+ /**
+ * @covers OAuth\OAuth1\Service\Etsy::__construct
+ * @covers OAuth\OAuth1\Service\Etsy::getAccessTokenEndpoint
+ */
+ public function testGetAccessTokenEndpoint()
+ {
+ $service = new Etsy(
+ $this->getMock('\\OAuth\\Common\\Consumer\\CredentialsInterface'),
+ $this->getMock('\\OAuth\\Common\\Http\\Client\\ClientInterface'),
+ $this->getMock('\\OAuth\\Common\\Storage\\TokenStorageInterface'),
+ $this->getMock('\\OAuth\\OAuth1\\Signature\\SignatureInterface')
+ );
+
+ $this->assertSame(
+ 'https://openapi.etsy.com/v2/oauth/access_token',
+ $service->getAccessTokenEndpoint()->getAbsoluteUri()
+ );
+ }
+
+ /**
+ * @covers OAuth\OAuth1\Service\Etsy::__construct
+ * @covers OAuth\OAuth1\Service\Etsy::getRequestTokenEndpoint
+ * @covers OAuth\OAuth1\Service\Etsy::parseRequestTokenResponse
+ */
+ public function testParseRequestTokenResponseThrowsExceptionOnNulledResponse()
+ {
+ $client = $this->getMock('\\OAuth\\Common\\Http\\Client\\ClientInterface');
+ $client->expects($this->once())->method('retrieveResponse')->will($this->returnValue(null));
+
+ $service = new Etsy(
+ $this->getMock('\\OAuth\\Common\\Consumer\\CredentialsInterface'),
+ $client,
+ $this->getMock('\\OAuth\\Common\\Storage\\TokenStorageInterface'),
+ $this->getMock('\\OAuth\\OAuth1\\Signature\\SignatureInterface')
+ );
+
+ $this->setExpectedException('\\OAuth\\Common\\Http\\Exception\\TokenResponseException');
+
+ $service->requestRequestToken();
+ }
+
+ /**
+ * @covers OAuth\OAuth1\Service\Etsy::__construct
+ * @covers OAuth\OAuth1\Service\Etsy::getRequestTokenEndpoint
+ * @covers OAuth\OAuth1\Service\Etsy::parseRequestTokenResponse
+ */
+ public function testParseRequestTokenResponseThrowsExceptionOnResponseNotAnArray()
+ {
+ $client = $this->getMock('\\OAuth\\Common\\Http\\Client\\ClientInterface');
+ $client->expects($this->once())->method('retrieveResponse')->will($this->returnValue('notanarray'));
+
+ $service = new Etsy(
+ $this->getMock('\\OAuth\\Common\\Consumer\\CredentialsInterface'),
+ $client,
+ $this->getMock('\\OAuth\\Common\\Storage\\TokenStorageInterface'),
+ $this->getMock('\\OAuth\\OAuth1\\Signature\\SignatureInterface')
+ );
+
+ $this->setExpectedException('\\OAuth\\Common\\Http\\Exception\\TokenResponseException');
+
+ $service->requestRequestToken();
+ }
+
+ /**
+ * @covers OAuth\OAuth1\Service\Etsy::__construct
+ * @covers OAuth\OAuth1\Service\Etsy::getRequestTokenEndpoint
+ * @covers OAuth\OAuth1\Service\Etsy::parseRequestTokenResponse
+ */
+ public function testParseRequestTokenResponseThrowsExceptionOnResponseCallbackNotSet()
+ {
+ $client = $this->getMock('\\OAuth\\Common\\Http\\Client\\ClientInterface');
+ $client->expects($this->once())->method('retrieveResponse')->will($this->returnValue('foo=bar'));
+
+ $service = new Etsy(
+ $this->getMock('\\OAuth\\Common\\Consumer\\CredentialsInterface'),
+ $client,
+ $this->getMock('\\OAuth\\Common\\Storage\\TokenStorageInterface'),
+ $this->getMock('\\OAuth\\OAuth1\\Signature\\SignatureInterface')
+ );
+
+ $this->setExpectedException('\\OAuth\\Common\\Http\\Exception\\TokenResponseException');
+
+ $service->requestRequestToken();
+ }
+
+ /**
+ * @covers OAuth\OAuth1\Service\Etsy::__construct
+ * @covers OAuth\OAuth1\Service\Etsy::getRequestTokenEndpoint
+ * @covers OAuth\OAuth1\Service\Etsy::parseRequestTokenResponse
+ */
+ public function testParseRequestTokenResponseThrowsExceptionOnResponseCallbackNotTrue()
+ {
+ $client = $this->getMock('\\OAuth\\Common\\Http\\Client\\ClientInterface');
+ $client->expects($this->once())->method('retrieveResponse')->will($this->returnValue(
+ 'oauth_callback_confirmed=false'
+ ));
+
+ $service = new Etsy(
+ $this->getMock('\\OAuth\\Common\\Consumer\\CredentialsInterface'),
+ $client,
+ $this->getMock('\\OAuth\\Common\\Storage\\TokenStorageInterface'),
+ $this->getMock('\\OAuth\\OAuth1\\Signature\\SignatureInterface')
+ );
+
+ $this->setExpectedException('\\OAuth\\Common\\Http\\Exception\\TokenResponseException');
+
+ $service->requestRequestToken();
+ }
+
+ /**
+ * @covers OAuth\OAuth1\Service\Etsy::__construct
+ * @covers OAuth\OAuth1\Service\Etsy::getRequestTokenEndpoint
+ * @covers OAuth\OAuth1\Service\Etsy::parseRequestTokenResponse
+ * @covers OAuth\OAuth1\Service\Etsy::parseAccessTokenResponse
+ */
+ public function testParseRequestTokenResponseValid()
+ {
+ $client = $this->getMock('\\OAuth\\Common\\Http\\Client\\ClientInterface');
+ $client->expects($this->once())->method('retrieveResponse')->will($this->returnValue(
+ 'oauth_callback_confirmed=true&oauth_token=foo&oauth_token_secret=bar'
+ ));
+
+ $service = new Etsy(
+ $this->getMock('\\OAuth\\Common\\Consumer\\CredentialsInterface'),
+ $client,
+ $this->getMock('\\OAuth\\Common\\Storage\\TokenStorageInterface'),
+ $this->getMock('\\OAuth\\OAuth1\\Signature\\SignatureInterface')
+ );
+
+ $this->assertInstanceOf('\\OAuth\\OAuth1\\Token\\StdOAuth1Token', $service->requestRequestToken());
+ }
+
+ /**
+ * @covers OAuth\OAuth1\Service\Etsy::__construct
+ * @covers OAuth\OAuth1\Service\Etsy::getRequestTokenEndpoint
+ * @covers OAuth\OAuth1\Service\Etsy::parseAccessTokenResponse
+ */
+ public function testParseAccessTokenResponseThrowsExceptionOnError()
+ {
+ $client = $this->getMock('\\OAuth\\Common\\Http\\Client\\ClientInterface');
+ $client->expects($this->once())->method('retrieveResponse')->will($this->returnValue('error=bar'));
+
+ $token = $this->getMock('\\OAuth\\OAuth1\\Token\\TokenInterface');
+
+ $storage = $this->getMock('\\OAuth\\Common\\Storage\\TokenStorageInterface');
+ $storage->expects($this->any())->method('retrieveAccessToken')->will($this->returnValue($token));
+
+ $service = new Etsy(
+ $this->getMock('\\OAuth\\Common\\Consumer\\CredentialsInterface'),
+ $client,
+ $storage,
+ $this->getMock('\\OAuth\\OAuth1\\Signature\\SignatureInterface')
+ );
+
+ $this->setExpectedException('\\OAuth\\Common\\Http\\Exception\\TokenResponseException');
+
+ $service->requestAccessToken('foo', 'bar', $token);
+ }
+
+ /**
+ * @covers OAuth\OAuth1\Service\Etsy::__construct
+ * @covers OAuth\OAuth1\Service\Etsy::getRequestTokenEndpoint
+ * @covers OAuth\OAuth1\Service\Etsy::parseAccessTokenResponse
+ */
+ public function testParseAccessTokenResponseValid()
+ {
+ $client = $this->getMock('\\OAuth\\Common\\Http\\Client\\ClientInterface');
+ $client->expects($this->once())->method('retrieveResponse')->will($this->returnValue(
+ 'oauth_token=foo&oauth_token_secret=bar'
+ ));
+
+ $token = $this->getMock('\\OAuth\\OAuth1\\Token\\TokenInterface');
+
+ $storage = $this->getMock('\\OAuth\\Common\\Storage\\TokenStorageInterface');
+ $storage->expects($this->any())->method('retrieveAccessToken')->will($this->returnValue($token));
+
+ $service = new Etsy(
+ $this->getMock('\\OAuth\\Common\\Consumer\\CredentialsInterface'),
+ $client,
+ $storage,
+ $this->getMock('\\OAuth\\OAuth1\\Signature\\SignatureInterface')
+ );
+
+ $this->assertInstanceOf('\\OAuth\\OAuth1\\Token\\StdOAuth1Token', $service->requestAccessToken('foo', 'bar', $token));
+ }
+}
diff --git a/vendor/lusitanian/oauth/tests/Unit/OAuth1/Service/FitBitTest.php b/vendor/lusitanian/oauth/tests/Unit/OAuth1/Service/FitBitTest.php
new file mode 100644
index 00000000..a8b7ae2d
--- /dev/null
+++ b/vendor/lusitanian/oauth/tests/Unit/OAuth1/Service/FitBitTest.php
@@ -0,0 +1,278 @@
+getMock('\\OAuth\\Common\\Consumer\\CredentialsInterface'),
+ $this->getMock('\\OAuth\\Common\\Http\\Client\\ClientInterface'),
+ $this->getMock('\\OAuth\\Common\\Storage\\TokenStorageInterface'),
+ $this->getMock('\\OAuth\\OAuth1\\Signature\\SignatureInterface')
+ );
+
+ $this->assertInstanceOf('\\OAuth\\OAuth1\\Service\\ServiceInterface', $service);
+ }
+
+ /**
+ * @covers OAuth\OAuth1\Service\FitBit::__construct
+ */
+ public function testConstructCorrectInstanceWithoutCustomUri()
+ {
+ $service = new FitBit(
+ $this->getMock('\\OAuth\\Common\\Consumer\\CredentialsInterface'),
+ $this->getMock('\\OAuth\\Common\\Http\\Client\\ClientInterface'),
+ $this->getMock('\\OAuth\\Common\\Storage\\TokenStorageInterface'),
+ $this->getMock('\\OAuth\\OAuth1\\Signature\\SignatureInterface')
+ );
+
+ $this->assertInstanceOf('\\OAuth\\OAuth1\\Service\\AbstractService', $service);
+ }
+
+ /**
+ * @covers OAuth\OAuth1\Service\FitBit::__construct
+ */
+ public function testConstructCorrectInstanceWithCustomUri()
+ {
+ $service = new FitBit(
+ $this->getMock('\\OAuth\\Common\\Consumer\\CredentialsInterface'),
+ $this->getMock('\\OAuth\\Common\\Http\\Client\\ClientInterface'),
+ $this->getMock('\\OAuth\\Common\\Storage\\TokenStorageInterface'),
+ $this->getMock('\\OAuth\\OAuth1\\Signature\\SignatureInterface'),
+ $this->getMock('\\OAuth\\Common\\Http\\Uri\\UriInterface')
+ );
+
+ $this->assertInstanceOf('\\OAuth\\OAuth1\\Service\\AbstractService', $service);
+ }
+
+ /**
+ * @covers OAuth\OAuth1\Service\FitBit::__construct
+ * @covers OAuth\OAuth1\Service\FitBit::getRequestTokenEndpoint
+ */
+ public function testGetRequestTokenEndpoint()
+ {
+ $service = new FitBit(
+ $this->getMock('\\OAuth\\Common\\Consumer\\CredentialsInterface'),
+ $this->getMock('\\OAuth\\Common\\Http\\Client\\ClientInterface'),
+ $this->getMock('\\OAuth\\Common\\Storage\\TokenStorageInterface'),
+ $this->getMock('\\OAuth\\OAuth1\\Signature\\SignatureInterface')
+ );
+
+ $this->assertSame(
+ 'https://api.fitbit.com/oauth/request_token',
+ $service->getRequestTokenEndpoint()->getAbsoluteUri()
+ );
+ }
+
+ /**
+ * @covers OAuth\OAuth1\Service\FitBit::__construct
+ * @covers OAuth\OAuth1\Service\FitBit::getAuthorizationEndpoint
+ */
+ public function testGetAuthorizationEndpoint()
+ {
+ $service = new FitBit(
+ $this->getMock('\\OAuth\\Common\\Consumer\\CredentialsInterface'),
+ $this->getMock('\\OAuth\\Common\\Http\\Client\\ClientInterface'),
+ $this->getMock('\\OAuth\\Common\\Storage\\TokenStorageInterface'),
+ $this->getMock('\\OAuth\\OAuth1\\Signature\\SignatureInterface')
+ );
+
+ $this->assertSame(
+ 'https://www.fitbit.com/oauth/authorize',
+ $service->getAuthorizationEndpoint()->getAbsoluteUri()
+ );
+ }
+
+ /**
+ * @covers OAuth\OAuth1\Service\FitBit::__construct
+ * @covers OAuth\OAuth1\Service\FitBit::getAccessTokenEndpoint
+ */
+ public function testGetAccessTokenEndpoint()
+ {
+ $service = new FitBit(
+ $this->getMock('\\OAuth\\Common\\Consumer\\CredentialsInterface'),
+ $this->getMock('\\OAuth\\Common\\Http\\Client\\ClientInterface'),
+ $this->getMock('\\OAuth\\Common\\Storage\\TokenStorageInterface'),
+ $this->getMock('\\OAuth\\OAuth1\\Signature\\SignatureInterface')
+ );
+
+ $this->assertSame(
+ 'https://api.fitbit.com/oauth/access_token',
+ $service->getAccessTokenEndpoint()->getAbsoluteUri()
+ );
+ }
+
+ /**
+ * @covers OAuth\OAuth1\Service\FitBit::__construct
+ * @covers OAuth\OAuth1\Service\FitBit::getRequestTokenEndpoint
+ * @covers OAuth\OAuth1\Service\FitBit::parseRequestTokenResponse
+ */
+ public function testParseRequestTokenResponseThrowsExceptionOnNulledResponse()
+ {
+ $client = $this->getMock('\\OAuth\\Common\\Http\\Client\\ClientInterface');
+ $client->expects($this->once())->method('retrieveResponse')->will($this->returnValue(null));
+
+ $service = new FitBit(
+ $this->getMock('\\OAuth\\Common\\Consumer\\CredentialsInterface'),
+ $client,
+ $this->getMock('\\OAuth\\Common\\Storage\\TokenStorageInterface'),
+ $this->getMock('\\OAuth\\OAuth1\\Signature\\SignatureInterface')
+ );
+
+ $this->setExpectedException('\\OAuth\\Common\\Http\\Exception\\TokenResponseException');
+
+ $service->requestRequestToken();
+ }
+
+ /**
+ * @covers OAuth\OAuth1\Service\FitBit::__construct
+ * @covers OAuth\OAuth1\Service\FitBit::getRequestTokenEndpoint
+ * @covers OAuth\OAuth1\Service\FitBit::parseRequestTokenResponse
+ */
+ public function testParseRequestTokenResponseThrowsExceptionOnResponseNotAnArray()
+ {
+ $client = $this->getMock('\\OAuth\\Common\\Http\\Client\\ClientInterface');
+ $client->expects($this->once())->method('retrieveResponse')->will($this->returnValue('notanarray'));
+
+ $service = new FitBit(
+ $this->getMock('\\OAuth\\Common\\Consumer\\CredentialsInterface'),
+ $client,
+ $this->getMock('\\OAuth\\Common\\Storage\\TokenStorageInterface'),
+ $this->getMock('\\OAuth\\OAuth1\\Signature\\SignatureInterface')
+ );
+
+ $this->setExpectedException('\\OAuth\\Common\\Http\\Exception\\TokenResponseException');
+
+ $service->requestRequestToken();
+ }
+
+ /**
+ * @covers OAuth\OAuth1\Service\FitBit::__construct
+ * @covers OAuth\OAuth1\Service\FitBit::getRequestTokenEndpoint
+ * @covers OAuth\OAuth1\Service\FitBit::parseRequestTokenResponse
+ */
+ public function testParseRequestTokenResponseThrowsExceptionOnResponseCallbackNotSet()
+ {
+ $client = $this->getMock('\\OAuth\\Common\\Http\\Client\\ClientInterface');
+ $client->expects($this->once())->method('retrieveResponse')->will($this->returnValue('foo=bar'));
+
+ $service = new FitBit(
+ $this->getMock('\\OAuth\\Common\\Consumer\\CredentialsInterface'),
+ $client,
+ $this->getMock('\\OAuth\\Common\\Storage\\TokenStorageInterface'),
+ $this->getMock('\\OAuth\\OAuth1\\Signature\\SignatureInterface')
+ );
+
+ $this->setExpectedException('\\OAuth\\Common\\Http\\Exception\\TokenResponseException');
+
+ $service->requestRequestToken();
+ }
+
+ /**
+ * @covers OAuth\OAuth1\Service\FitBit::__construct
+ * @covers OAuth\OAuth1\Service\FitBit::getRequestTokenEndpoint
+ * @covers OAuth\OAuth1\Service\FitBit::parseRequestTokenResponse
+ */
+ public function testParseRequestTokenResponseThrowsExceptionOnResponseCallbackNotTrue()
+ {
+ $client = $this->getMock('\\OAuth\\Common\\Http\\Client\\ClientInterface');
+ $client->expects($this->once())->method('retrieveResponse')->will($this->returnValue(
+ 'oauth_callback_confirmed=false'
+ ));
+
+ $service = new FitBit(
+ $this->getMock('\\OAuth\\Common\\Consumer\\CredentialsInterface'),
+ $client,
+ $this->getMock('\\OAuth\\Common\\Storage\\TokenStorageInterface'),
+ $this->getMock('\\OAuth\\OAuth1\\Signature\\SignatureInterface')
+ );
+
+ $this->setExpectedException('\\OAuth\\Common\\Http\\Exception\\TokenResponseException');
+
+ $service->requestRequestToken();
+ }
+
+ /**
+ * @covers OAuth\OAuth1\Service\FitBit::__construct
+ * @covers OAuth\OAuth1\Service\FitBit::getRequestTokenEndpoint
+ * @covers OAuth\OAuth1\Service\FitBit::parseRequestTokenResponse
+ * @covers OAuth\OAuth1\Service\FitBit::parseAccessTokenResponse
+ */
+ public function testParseRequestTokenResponseValid()
+ {
+ $client = $this->getMock('\\OAuth\\Common\\Http\\Client\\ClientInterface');
+ $client->expects($this->once())->method('retrieveResponse')->will($this->returnValue(
+ 'oauth_callback_confirmed=true&oauth_token=foo&oauth_token_secret=bar'
+ ));
+
+ $service = new FitBit(
+ $this->getMock('\\OAuth\\Common\\Consumer\\CredentialsInterface'),
+ $client,
+ $this->getMock('\\OAuth\\Common\\Storage\\TokenStorageInterface'),
+ $this->getMock('\\OAuth\\OAuth1\\Signature\\SignatureInterface')
+ );
+
+ $this->assertInstanceOf('\\OAuth\\OAuth1\\Token\\StdOAuth1Token', $service->requestRequestToken());
+ }
+
+ /**
+ * @covers OAuth\OAuth1\Service\FitBit::__construct
+ * @covers OAuth\OAuth1\Service\FitBit::getRequestTokenEndpoint
+ * @covers OAuth\OAuth1\Service\FitBit::parseAccessTokenResponse
+ */
+ public function testParseAccessTokenResponseThrowsExceptionOnError()
+ {
+ $client = $this->getMock('\\OAuth\\Common\\Http\\Client\\ClientInterface');
+ $client->expects($this->once())->method('retrieveResponse')->will($this->returnValue('error=bar'));
+
+ $token = $this->getMock('\\OAuth\\OAuth1\\Token\\TokenInterface');
+
+ $storage = $this->getMock('\\OAuth\\Common\\Storage\\TokenStorageInterface');
+ $storage->expects($this->any())->method('retrieveAccessToken')->will($this->returnValue($token));
+
+ $service = new FitBit(
+ $this->getMock('\\OAuth\\Common\\Consumer\\CredentialsInterface'),
+ $client,
+ $storage,
+ $this->getMock('\\OAuth\\OAuth1\\Signature\\SignatureInterface')
+ );
+
+ $this->setExpectedException('\\OAuth\\Common\\Http\\Exception\\TokenResponseException');
+
+ $service->requestAccessToken('foo', 'bar', $token);
+ }
+
+ /**
+ * @covers OAuth\OAuth1\Service\FitBit::__construct
+ * @covers OAuth\OAuth1\Service\FitBit::getRequestTokenEndpoint
+ * @covers OAuth\OAuth1\Service\FitBit::parseAccessTokenResponse
+ */
+ public function testParseAccessTokenResponseValid()
+ {
+ $client = $this->getMock('\\OAuth\\Common\\Http\\Client\\ClientInterface');
+ $client->expects($this->once())->method('retrieveResponse')->will($this->returnValue(
+ 'oauth_token=foo&oauth_token_secret=bar'
+ ));
+
+ $token = $this->getMock('\\OAuth\\OAuth1\\Token\\TokenInterface');
+
+ $storage = $this->getMock('\\OAuth\\Common\\Storage\\TokenStorageInterface');
+ $storage->expects($this->any())->method('retrieveAccessToken')->will($this->returnValue($token));
+
+ $service = new FitBit(
+ $this->getMock('\\OAuth\\Common\\Consumer\\CredentialsInterface'),
+ $client,
+ $storage,
+ $this->getMock('\\OAuth\\OAuth1\\Signature\\SignatureInterface')
+ );
+
+ $this->assertInstanceOf('\\OAuth\\OAuth1\\Token\\StdOAuth1Token', $service->requestAccessToken('foo', 'bar', $token));
+ }
+}
diff --git a/vendor/lusitanian/oauth/tests/Unit/OAuth1/Service/FlickrTest.php b/vendor/lusitanian/oauth/tests/Unit/OAuth1/Service/FlickrTest.php
new file mode 100644
index 00000000..ee88f714
--- /dev/null
+++ b/vendor/lusitanian/oauth/tests/Unit/OAuth1/Service/FlickrTest.php
@@ -0,0 +1,302 @@
+getMock('\\OAuth\\Common\\Consumer\\CredentialsInterface'),
+ $this->getMock('\\OAuth\\Common\\Http\\Client\\ClientInterface'),
+ $this->getMock('\\OAuth\\Common\\Storage\\TokenStorageInterface'),
+ $this->getMock('\\OAuth\\OAuth1\\Signature\\SignatureInterface')
+ );
+
+ $this->assertInstanceOf('\\OAuth\\OAuth1\\Service\\ServiceInterface', $service);
+ }
+
+ /**
+ * @covers OAuth\OAuth1\Service\Flickr::__construct
+ */
+ public function testConstructCorrectInstanceWithoutCustomUri()
+ {
+ $service = new Flickr(
+ $this->getMock('\\OAuth\\Common\\Consumer\\CredentialsInterface'),
+ $this->getMock('\\OAuth\\Common\\Http\\Client\\ClientInterface'),
+ $this->getMock('\\OAuth\\Common\\Storage\\TokenStorageInterface'),
+ $this->getMock('\\OAuth\\OAuth1\\Signature\\SignatureInterface')
+ );
+
+ $this->assertInstanceOf('\\OAuth\\OAuth1\\Service\\AbstractService', $service);
+ }
+
+ /**
+ * @covers OAuth\OAuth1\Service\Flickr::__construct
+ */
+ public function testConstructCorrectInstanceWithCustomUri()
+ {
+ $service = new Flickr(
+ $this->getMock('\\OAuth\\Common\\Consumer\\CredentialsInterface'),
+ $this->getMock('\\OAuth\\Common\\Http\\Client\\ClientInterface'),
+ $this->getMock('\\OAuth\\Common\\Storage\\TokenStorageInterface'),
+ $this->getMock('\\OAuth\\OAuth1\\Signature\\SignatureInterface'),
+ $this->getMock('\\OAuth\\Common\\Http\\Uri\\UriInterface')
+ );
+
+ $this->assertInstanceOf('\\OAuth\\OAuth1\\Service\\AbstractService', $service);
+ }
+
+ /**
+ * @covers OAuth\OAuth1\Service\Flickr::__construct
+ * @covers OAuth\OAuth1\Service\Flickr::getRequestTokenEndpoint
+ */
+ public function testGetRequestTokenEndpoint()
+ {
+ $service = new Flickr(
+ $this->getMock('\\OAuth\\Common\\Consumer\\CredentialsInterface'),
+ $this->getMock('\\OAuth\\Common\\Http\\Client\\ClientInterface'),
+ $this->getMock('\\OAuth\\Common\\Storage\\TokenStorageInterface'),
+ $this->getMock('\\OAuth\\OAuth1\\Signature\\SignatureInterface')
+ );
+
+ $this->assertSame(
+ 'https://www.flickr.com/services/oauth/request_token',
+ $service->getRequestTokenEndpoint()->getAbsoluteUri()
+ );
+ }
+
+ /**
+ * @covers OAuth\OAuth1\Service\Flickr::__construct
+ * @covers OAuth\OAuth1\Service\Flickr::getAuthorizationEndpoint
+ */
+ public function testGetAuthorizationEndpoint()
+ {
+ $service = new Flickr(
+ $this->getMock('\\OAuth\\Common\\Consumer\\CredentialsInterface'),
+ $this->getMock('\\OAuth\\Common\\Http\\Client\\ClientInterface'),
+ $this->getMock('\\OAuth\\Common\\Storage\\TokenStorageInterface'),
+ $this->getMock('\\OAuth\\OAuth1\\Signature\\SignatureInterface')
+ );
+
+ $this->assertSame(
+ 'https://www.flickr.com/services/oauth/authorize',
+ $service->getAuthorizationEndpoint()->getAbsoluteUri()
+ );
+ }
+
+ /**
+ * @covers OAuth\OAuth1\Service\Flickr::__construct
+ * @covers OAuth\OAuth1\Service\Flickr::getAccessTokenEndpoint
+ */
+ public function testGetAccessTokenEndpoint()
+ {
+ $service = new Flickr(
+ $this->getMock('\\OAuth\\Common\\Consumer\\CredentialsInterface'),
+ $this->getMock('\\OAuth\\Common\\Http\\Client\\ClientInterface'),
+ $this->getMock('\\OAuth\\Common\\Storage\\TokenStorageInterface'),
+ $this->getMock('\\OAuth\\OAuth1\\Signature\\SignatureInterface')
+ );
+
+ $this->assertSame(
+ 'https://www.flickr.com/services/oauth/access_token',
+ $service->getAccessTokenEndpoint()->getAbsoluteUri()
+ );
+ }
+
+ /**
+ * @covers OAuth\OAuth1\Service\Flickr::__construct
+ * @covers OAuth\OAuth1\Service\Flickr::getRequestTokenEndpoint
+ * @covers OAuth\OAuth1\Service\Flickr::parseRequestTokenResponse
+ */
+ public function testParseRequestTokenResponseThrowsExceptionOnNulledResponse()
+ {
+ $client = $this->getMock('\\OAuth\\Common\\Http\\Client\\ClientInterface');
+ $client->expects($this->once())->method('retrieveResponse')->will($this->returnValue(null));
+
+ $service = new Flickr(
+ $this->getMock('\\OAuth\\Common\\Consumer\\CredentialsInterface'),
+ $client,
+ $this->getMock('\\OAuth\\Common\\Storage\\TokenStorageInterface'),
+ $this->getMock('\\OAuth\\OAuth1\\Signature\\SignatureInterface')
+ );
+
+ $this->setExpectedException('\\OAuth\\Common\\Http\\Exception\\TokenResponseException');
+
+ $service->requestRequestToken();
+ }
+
+ /**
+ * @covers OAuth\OAuth1\Service\Flickr::__construct
+ * @covers OAuth\OAuth1\Service\Flickr::getRequestTokenEndpoint
+ * @covers OAuth\OAuth1\Service\Flickr::parseRequestTokenResponse
+ */
+ public function testParseRequestTokenResponseThrowsExceptionOnResponseNotAnArray()
+ {
+ $client = $this->getMock('\\OAuth\\Common\\Http\\Client\\ClientInterface');
+ $client->expects($this->once())->method('retrieveResponse')->will($this->returnValue('notanarray'));
+
+ $service = new Flickr(
+ $this->getMock('\\OAuth\\Common\\Consumer\\CredentialsInterface'),
+ $client,
+ $this->getMock('\\OAuth\\Common\\Storage\\TokenStorageInterface'),
+ $this->getMock('\\OAuth\\OAuth1\\Signature\\SignatureInterface')
+ );
+
+ $this->setExpectedException('\\OAuth\\Common\\Http\\Exception\\TokenResponseException');
+
+ $service->requestRequestToken();
+ }
+
+ /**
+ * @covers OAuth\OAuth1\Service\Flickr::__construct
+ * @covers OAuth\OAuth1\Service\Flickr::getRequestTokenEndpoint
+ * @covers OAuth\OAuth1\Service\Flickr::parseRequestTokenResponse
+ */
+ public function testParseRequestTokenResponseThrowsExceptionOnResponseCallbackNotSet()
+ {
+ $client = $this->getMock('\\OAuth\\Common\\Http\\Client\\ClientInterface');
+ $client->expects($this->once())->method('retrieveResponse')->will($this->returnValue('foo=bar'));
+
+ $service = new Flickr(
+ $this->getMock('\\OAuth\\Common\\Consumer\\CredentialsInterface'),
+ $client,
+ $this->getMock('\\OAuth\\Common\\Storage\\TokenStorageInterface'),
+ $this->getMock('\\OAuth\\OAuth1\\Signature\\SignatureInterface')
+ );
+
+ $this->setExpectedException('\\OAuth\\Common\\Http\\Exception\\TokenResponseException');
+
+ $service->requestRequestToken();
+ }
+
+ /**
+ * @covers OAuth\OAuth1\Service\Flickr::__construct
+ * @covers OAuth\OAuth1\Service\Flickr::getRequestTokenEndpoint
+ * @covers OAuth\OAuth1\Service\Flickr::parseRequestTokenResponse
+ */
+ public function testParseRequestTokenResponseThrowsExceptionOnResponseCallbackNotTrue()
+ {
+ $client = $this->getMock('\\OAuth\\Common\\Http\\Client\\ClientInterface');
+ $client->expects($this->once())->method('retrieveResponse')->will($this->returnValue(
+ 'oauth_callback_confirmed=false'
+ ));
+
+ $service = new Flickr(
+ $this->getMock('\\OAuth\\Common\\Consumer\\CredentialsInterface'),
+ $client,
+ $this->getMock('\\OAuth\\Common\\Storage\\TokenStorageInterface'),
+ $this->getMock('\\OAuth\\OAuth1\\Signature\\SignatureInterface')
+ );
+
+ $this->setExpectedException('\\OAuth\\Common\\Http\\Exception\\TokenResponseException');
+
+ $service->requestRequestToken();
+ }
+
+ /**
+ * @covers OAuth\OAuth1\Service\Flickr::__construct
+ * @covers OAuth\OAuth1\Service\Flickr::getRequestTokenEndpoint
+ * @covers OAuth\OAuth1\Service\Flickr::parseRequestTokenResponse
+ * @covers OAuth\OAuth1\Service\Flickr::parseAccessTokenResponse
+ */
+ public function testParseRequestTokenResponseValid()
+ {
+ $client = $this->getMock('\\OAuth\\Common\\Http\\Client\\ClientInterface');
+ $client->expects($this->once())->method('retrieveResponse')->will($this->returnValue(
+ 'oauth_callback_confirmed=true&oauth_token=foo&oauth_token_secret=bar'
+ ));
+
+ $service = new Flickr(
+ $this->getMock('\\OAuth\\Common\\Consumer\\CredentialsInterface'),
+ $client,
+ $this->getMock('\\OAuth\\Common\\Storage\\TokenStorageInterface'),
+ $this->getMock('\\OAuth\\OAuth1\\Signature\\SignatureInterface')
+ );
+
+ $this->assertInstanceOf('\\OAuth\\OAuth1\\Token\\StdOAuth1Token', $service->requestRequestToken());
+ }
+
+ /**
+ * @covers OAuth\OAuth1\Service\Flickr::__construct
+ * @covers OAuth\OAuth1\Service\Flickr::getRequestTokenEndpoint
+ * @covers OAuth\OAuth1\Service\Flickr::parseAccessTokenResponse
+ */
+ public function testParseAccessTokenResponseThrowsExceptionOnError()
+ {
+ $client = $this->getMock('\\OAuth\\Common\\Http\\Client\\ClientInterface');
+ $client->expects($this->once())->method('retrieveResponse')->will($this->returnValue('error=bar'));
+
+ $token = $this->getMock('\\OAuth\\OAuth1\\Token\\TokenInterface');
+
+ $storage = $this->getMock('\\OAuth\\Common\\Storage\\TokenStorageInterface');
+ $storage->expects($this->any())->method('retrieveAccessToken')->will($this->returnValue($token));
+
+ $service = new Flickr(
+ $this->getMock('\\OAuth\\Common\\Consumer\\CredentialsInterface'),
+ $client,
+ $storage,
+ $this->getMock('\\OAuth\\OAuth1\\Signature\\SignatureInterface')
+ );
+
+ $this->setExpectedException('\\OAuth\\Common\\Http\\Exception\\TokenResponseException');
+
+ $service->requestAccessToken('foo', 'bar', $token);
+ }
+
+ /**
+ * @covers OAuth\OAuth1\Service\Flickr::__construct
+ * @covers OAuth\OAuth1\Service\Flickr::getRequestTokenEndpoint
+ * @covers OAuth\OAuth1\Service\Flickr::parseAccessTokenResponse
+ */
+ public function testParseAccessTokenResponseValid()
+ {
+ $client = $this->getMock('\\OAuth\\Common\\Http\\Client\\ClientInterface');
+ $client->expects($this->once())->method('retrieveResponse')->will($this->returnValue(
+ 'oauth_token=foo&oauth_token_secret=bar'
+ ));
+
+ $token = $this->getMock('\\OAuth\\OAuth1\\Token\\TokenInterface');
+
+ $storage = $this->getMock('\\OAuth\\Common\\Storage\\TokenStorageInterface');
+ $storage->expects($this->any())->method('retrieveAccessToken')->will($this->returnValue($token));
+
+ $service = new Flickr(
+ $this->getMock('\\OAuth\\Common\\Consumer\\CredentialsInterface'),
+ $client,
+ $storage,
+ $this->getMock('\\OAuth\\OAuth1\\Signature\\SignatureInterface')
+ );
+
+ $this->assertInstanceOf('\\OAuth\\OAuth1\\Token\\StdOAuth1Token', $service->requestAccessToken('foo', 'bar', $token));
+ }
+
+ /**
+ * @covers OAuth\OAuth1\Service\Flickr::request
+ */
+ public function testRequest()
+ {
+ $client = $this->getMock('\\OAuth\\Common\\Http\\Client\\ClientInterface');
+ $client->expects($this->once())->method('retrieveResponse')->will($this->returnValue('response!'));
+
+ $token = $this->getMock('\\OAuth\\OAuth1\\Token\\TokenInterface');
+
+ $storage = $this->getMock('\\OAuth\\Common\\Storage\\TokenStorageInterface');
+ $storage->expects($this->any())->method('retrieveAccessToken')->will($this->returnValue($token));
+
+ $service = new Flickr(
+ $this->getMock('\\OAuth\\Common\\Consumer\\CredentialsInterface'),
+ $client,
+ $storage,
+ $this->getMock('\\OAuth\\OAuth1\\Signature\\SignatureInterface'),
+ $this->getMock('\\OAuth\\Common\\Http\\Uri\\UriInterface')
+ );
+
+ $this->assertSame('response!', $service->request('/my/awesome/path'));
+ }
+}
diff --git a/vendor/lusitanian/oauth/tests/Unit/OAuth1/Service/ScoopItTest.php b/vendor/lusitanian/oauth/tests/Unit/OAuth1/Service/ScoopItTest.php
new file mode 100644
index 00000000..4ba83fa6
--- /dev/null
+++ b/vendor/lusitanian/oauth/tests/Unit/OAuth1/Service/ScoopItTest.php
@@ -0,0 +1,302 @@
+getMock('\\OAuth\\Common\\Consumer\\CredentialsInterface'),
+ $this->getMock('\\OAuth\\Common\\Http\\Client\\ClientInterface'),
+ $this->getMock('\\OAuth\\Common\\Storage\\TokenStorageInterface'),
+ $this->getMock('\\OAuth\\OAuth1\\Signature\\SignatureInterface')
+ );
+
+ $this->assertInstanceOf('\\OAuth\\OAuth1\\Service\\ServiceInterface', $service);
+ }
+
+ /**
+ * @covers OAuth\OAuth1\Service\ScoopIt::__construct
+ */
+ public function testConstructCorrectInstanceWithoutCustomUri()
+ {
+ $service = new ScoopIt(
+ $this->getMock('\\OAuth\\Common\\Consumer\\CredentialsInterface'),
+ $this->getMock('\\OAuth\\Common\\Http\\Client\\ClientInterface'),
+ $this->getMock('\\OAuth\\Common\\Storage\\TokenStorageInterface'),
+ $this->getMock('\\OAuth\\OAuth1\\Signature\\SignatureInterface')
+ );
+
+ $this->assertInstanceOf('\\OAuth\\OAuth1\\Service\\AbstractService', $service);
+ }
+
+ /**
+ * @covers OAuth\OAuth1\Service\ScoopIt::__construct
+ */
+ public function testConstructCorrectInstanceWithCustomUri()
+ {
+ $service = new ScoopIt(
+ $this->getMock('\\OAuth\\Common\\Consumer\\CredentialsInterface'),
+ $this->getMock('\\OAuth\\Common\\Http\\Client\\ClientInterface'),
+ $this->getMock('\\OAuth\\Common\\Storage\\TokenStorageInterface'),
+ $this->getMock('\\OAuth\\OAuth1\\Signature\\SignatureInterface'),
+ $this->getMock('\\OAuth\\Common\\Http\\Uri\\UriInterface')
+ );
+
+ $this->assertInstanceOf('\\OAuth\\OAuth1\\Service\\AbstractService', $service);
+ }
+
+ /**
+ * @covers OAuth\OAuth1\Service\ScoopIt::__construct
+ * @covers OAuth\OAuth1\Service\ScoopIt::getRequestTokenEndpoint
+ */
+ public function testGetRequestTokenEndpoint()
+ {
+ $service = new ScoopIt(
+ $this->getMock('\\OAuth\\Common\\Consumer\\CredentialsInterface'),
+ $this->getMock('\\OAuth\\Common\\Http\\Client\\ClientInterface'),
+ $this->getMock('\\OAuth\\Common\\Storage\\TokenStorageInterface'),
+ $this->getMock('\\OAuth\\OAuth1\\Signature\\SignatureInterface')
+ );
+
+ $this->assertSame(
+ 'https://www.scoop.it/oauth/request',
+ $service->getRequestTokenEndpoint()->getAbsoluteUri()
+ );
+ }
+
+ /**
+ * @covers OAuth\OAuth1\Service\ScoopIt::__construct
+ * @covers OAuth\OAuth1\Service\ScoopIt::getAuthorizationEndpoint
+ */
+ public function testGetAuthorizationEndpoint()
+ {
+ $service = new ScoopIt(
+ $this->getMock('\\OAuth\\Common\\Consumer\\CredentialsInterface'),
+ $this->getMock('\\OAuth\\Common\\Http\\Client\\ClientInterface'),
+ $this->getMock('\\OAuth\\Common\\Storage\\TokenStorageInterface'),
+ $this->getMock('\\OAuth\\OAuth1\\Signature\\SignatureInterface')
+ );
+
+ $this->assertSame(
+ 'https://www.scoop.it/oauth/authorize',
+ $service->getAuthorizationEndpoint()->getAbsoluteUri()
+ );
+ }
+
+ /**
+ * @covers OAuth\OAuth1\Service\ScoopIt::__construct
+ * @covers OAuth\OAuth1\Service\ScoopIt::getAccessTokenEndpoint
+ */
+ public function testGetAccessTokenEndpoint()
+ {
+ $service = new ScoopIt(
+ $this->getMock('\\OAuth\\Common\\Consumer\\CredentialsInterface'),
+ $this->getMock('\\OAuth\\Common\\Http\\Client\\ClientInterface'),
+ $this->getMock('\\OAuth\\Common\\Storage\\TokenStorageInterface'),
+ $this->getMock('\\OAuth\\OAuth1\\Signature\\SignatureInterface')
+ );
+
+ $this->assertSame(
+ 'https://www.scoop.it/oauth/access',
+ $service->getAccessTokenEndpoint()->getAbsoluteUri()
+ );
+ }
+
+ /**
+ * @covers OAuth\OAuth1\Service\ScoopIt::__construct
+ * @covers OAuth\OAuth1\Service\ScoopIt::getRequestTokenEndpoint
+ * @covers OAuth\OAuth1\Service\ScoopIt::parseRequestTokenResponse
+ */
+ public function testParseRequestTokenResponseThrowsExceptionOnNulledResponse()
+ {
+ $client = $this->getMock('\\OAuth\\Common\\Http\\Client\\ClientInterface');
+ $client->expects($this->once())->method('retrieveResponse')->will($this->returnValue(null));
+
+ $service = new ScoopIt(
+ $this->getMock('\\OAuth\\Common\\Consumer\\CredentialsInterface'),
+ $client,
+ $this->getMock('\\OAuth\\Common\\Storage\\TokenStorageInterface'),
+ $this->getMock('\\OAuth\\OAuth1\\Signature\\SignatureInterface')
+ );
+
+ $this->setExpectedException('\\OAuth\\Common\\Http\\Exception\\TokenResponseException');
+
+ $service->requestRequestToken();
+ }
+
+ /**
+ * @covers OAuth\OAuth1\Service\ScoopIt::__construct
+ * @covers OAuth\OAuth1\Service\ScoopIt::getRequestTokenEndpoint
+ * @covers OAuth\OAuth1\Service\ScoopIt::parseRequestTokenResponse
+ */
+ public function testParseRequestTokenResponseThrowsExceptionOnResponseNotAnArray()
+ {
+ $client = $this->getMock('\\OAuth\\Common\\Http\\Client\\ClientInterface');
+ $client->expects($this->once())->method('retrieveResponse')->will($this->returnValue('notanarray'));
+
+ $service = new ScoopIt(
+ $this->getMock('\\OAuth\\Common\\Consumer\\CredentialsInterface'),
+ $client,
+ $this->getMock('\\OAuth\\Common\\Storage\\TokenStorageInterface'),
+ $this->getMock('\\OAuth\\OAuth1\\Signature\\SignatureInterface')
+ );
+
+ $this->setExpectedException('\\OAuth\\Common\\Http\\Exception\\TokenResponseException');
+
+ $service->requestRequestToken();
+ }
+
+ /**
+ * @covers OAuth\OAuth1\Service\ScoopIt::__construct
+ * @covers OAuth\OAuth1\Service\ScoopIt::getRequestTokenEndpoint
+ * @covers OAuth\OAuth1\Service\ScoopIt::parseRequestTokenResponse
+ */
+ public function testParseRequestTokenResponseThrowsExceptionOnResponseCallbackNotSet()
+ {
+ $client = $this->getMock('\\OAuth\\Common\\Http\\Client\\ClientInterface');
+ $client->expects($this->once())->method('retrieveResponse')->will($this->returnValue('foo=bar'));
+
+ $service = new ScoopIt(
+ $this->getMock('\\OAuth\\Common\\Consumer\\CredentialsInterface'),
+ $client,
+ $this->getMock('\\OAuth\\Common\\Storage\\TokenStorageInterface'),
+ $this->getMock('\\OAuth\\OAuth1\\Signature\\SignatureInterface')
+ );
+
+ $this->setExpectedException('\\OAuth\\Common\\Http\\Exception\\TokenResponseException');
+
+ $service->requestRequestToken();
+ }
+
+ /**
+ * @covers OAuth\OAuth1\Service\ScoopIt::__construct
+ * @covers OAuth\OAuth1\Service\ScoopIt::getRequestTokenEndpoint
+ * @covers OAuth\OAuth1\Service\ScoopIt::parseRequestTokenResponse
+ */
+ public function testParseRequestTokenResponseThrowsExceptionOnResponseCallbackNotTrue()
+ {
+ $client = $this->getMock('\\OAuth\\Common\\Http\\Client\\ClientInterface');
+ $client->expects($this->once())->method('retrieveResponse')->will($this->returnValue(
+ 'oauth_callback_confirmed=false'
+ ));
+
+ $service = new ScoopIt(
+ $this->getMock('\\OAuth\\Common\\Consumer\\CredentialsInterface'),
+ $client,
+ $this->getMock('\\OAuth\\Common\\Storage\\TokenStorageInterface'),
+ $this->getMock('\\OAuth\\OAuth1\\Signature\\SignatureInterface')
+ );
+
+ $this->setExpectedException('\\OAuth\\Common\\Http\\Exception\\TokenResponseException');
+
+ $service->requestRequestToken();
+ }
+
+ /**
+ * @covers OAuth\OAuth1\Service\ScoopIt::__construct
+ * @covers OAuth\OAuth1\Service\ScoopIt::getRequestTokenEndpoint
+ * @covers OAuth\OAuth1\Service\ScoopIt::parseRequestTokenResponse
+ * @covers OAuth\OAuth1\Service\ScoopIt::parseAccessTokenResponse
+ */
+ public function testParseRequestTokenResponseValid()
+ {
+ $client = $this->getMock('\\OAuth\\Common\\Http\\Client\\ClientInterface');
+ $client->expects($this->once())->method('retrieveResponse')->will($this->returnValue(
+ 'oauth_callback_confirmed=true&oauth_token=foo&oauth_token_secret=bar'
+ ));
+
+ $service = new ScoopIt(
+ $this->getMock('\\OAuth\\Common\\Consumer\\CredentialsInterface'),
+ $client,
+ $this->getMock('\\OAuth\\Common\\Storage\\TokenStorageInterface'),
+ $this->getMock('\\OAuth\\OAuth1\\Signature\\SignatureInterface')
+ );
+
+ $this->assertInstanceOf('\\OAuth\\OAuth1\\Token\\StdOAuth1Token', $service->requestRequestToken());
+ }
+
+ /**
+ * @covers OAuth\OAuth1\Service\ScoopIt::__construct
+ * @covers OAuth\OAuth1\Service\ScoopIt::getRequestTokenEndpoint
+ * @covers OAuth\OAuth1\Service\ScoopIt::parseAccessTokenResponse
+ */
+ public function testParseAccessTokenResponseThrowsExceptionOnError()
+ {
+ $client = $this->getMock('\\OAuth\\Common\\Http\\Client\\ClientInterface');
+ $client->expects($this->once())->method('retrieveResponse')->will($this->returnValue('error=bar'));
+
+ $token = $this->getMock('\\OAuth\\OAuth1\\Token\\TokenInterface');
+
+ $storage = $this->getMock('\\OAuth\\Common\\Storage\\TokenStorageInterface');
+ $storage->expects($this->any())->method('retrieveAccessToken')->will($this->returnValue($token));
+
+ $service = new ScoopIt(
+ $this->getMock('\\OAuth\\Common\\Consumer\\CredentialsInterface'),
+ $client,
+ $storage,
+ $this->getMock('\\OAuth\\OAuth1\\Signature\\SignatureInterface')
+ );
+
+ $this->setExpectedException('\\OAuth\\Common\\Http\\Exception\\TokenResponseException');
+
+ $service->requestAccessToken('foo', 'bar', $token);
+ }
+
+ /**
+ * @covers OAuth\OAuth1\Service\ScoopIt::__construct
+ * @covers OAuth\OAuth1\Service\ScoopIt::getRequestTokenEndpoint
+ * @covers OAuth\OAuth1\Service\ScoopIt::parseAccessTokenResponse
+ */
+ public function testParseAccessTokenResponseValid()
+ {
+ $client = $this->getMock('\\OAuth\\Common\\Http\\Client\\ClientInterface');
+ $client->expects($this->once())->method('retrieveResponse')->will($this->returnValue(
+ 'oauth_token=foo&oauth_token_secret=bar'
+ ));
+
+ $token = $this->getMock('\\OAuth\\OAuth1\\Token\\TokenInterface');
+
+ $storage = $this->getMock('\\OAuth\\Common\\Storage\\TokenStorageInterface');
+ $storage->expects($this->any())->method('retrieveAccessToken')->will($this->returnValue($token));
+
+ $service = new ScoopIt(
+ $this->getMock('\\OAuth\\Common\\Consumer\\CredentialsInterface'),
+ $client,
+ $storage,
+ $this->getMock('\\OAuth\\OAuth1\\Signature\\SignatureInterface')
+ );
+
+ $this->assertInstanceOf('\\OAuth\\OAuth1\\Token\\StdOAuth1Token', $service->requestAccessToken('foo', 'bar', $token));
+ }
+
+ /**
+ * @covers OAuth\OAuth1\Service\ScoopIt::request
+ */
+ public function testRequest()
+ {
+ $client = $this->getMock('\\OAuth\\Common\\Http\\Client\\ClientInterface');
+ $client->expects($this->once())->method('retrieveResponse')->will($this->returnValue('response!'));
+
+ $token = $this->getMock('\\OAuth\\OAuth1\\Token\\TokenInterface');
+
+ $storage = $this->getMock('\\OAuth\\Common\\Storage\\TokenStorageInterface');
+ $storage->expects($this->any())->method('retrieveAccessToken')->will($this->returnValue($token));
+
+ $service = new ScoopIt(
+ $this->getMock('\\OAuth\\Common\\Consumer\\CredentialsInterface'),
+ $client,
+ $storage,
+ $this->getMock('\\OAuth\\OAuth1\\Signature\\SignatureInterface'),
+ $this->getMock('\\OAuth\\Common\\Http\\Uri\\UriInterface')
+ );
+
+ $this->assertSame('response!', $service->request('/my/awesome/path'));
+ }
+}
diff --git a/vendor/lusitanian/oauth/tests/Unit/OAuth1/Service/TumblrTest.php b/vendor/lusitanian/oauth/tests/Unit/OAuth1/Service/TumblrTest.php
new file mode 100644
index 00000000..f1467ad6
--- /dev/null
+++ b/vendor/lusitanian/oauth/tests/Unit/OAuth1/Service/TumblrTest.php
@@ -0,0 +1,278 @@
+getMock('\\OAuth\\Common\\Consumer\\CredentialsInterface'),
+ $this->getMock('\\OAuth\\Common\\Http\\Client\\ClientInterface'),
+ $this->getMock('\\OAuth\\Common\\Storage\\TokenStorageInterface'),
+ $this->getMock('\\OAuth\\OAuth1\\Signature\\SignatureInterface')
+ );
+
+ $this->assertInstanceOf('\\OAuth\\OAuth1\\Service\\ServiceInterface', $service);
+ }
+
+ /**
+ * @covers OAuth\OAuth1\Service\Tumblr::__construct
+ */
+ public function testConstructCorrectInstanceWithoutCustomUri()
+ {
+ $service = new Tumblr(
+ $this->getMock('\\OAuth\\Common\\Consumer\\CredentialsInterface'),
+ $this->getMock('\\OAuth\\Common\\Http\\Client\\ClientInterface'),
+ $this->getMock('\\OAuth\\Common\\Storage\\TokenStorageInterface'),
+ $this->getMock('\\OAuth\\OAuth1\\Signature\\SignatureInterface')
+ );
+
+ $this->assertInstanceOf('\\OAuth\\OAuth1\\Service\\AbstractService', $service);
+ }
+
+ /**
+ * @covers OAuth\OAuth1\Service\Tumblr::__construct
+ */
+ public function testConstructCorrectInstanceWithCustomUri()
+ {
+ $service = new Tumblr(
+ $this->getMock('\\OAuth\\Common\\Consumer\\CredentialsInterface'),
+ $this->getMock('\\OAuth\\Common\\Http\\Client\\ClientInterface'),
+ $this->getMock('\\OAuth\\Common\\Storage\\TokenStorageInterface'),
+ $this->getMock('\\OAuth\\OAuth1\\Signature\\SignatureInterface'),
+ $this->getMock('\\OAuth\\Common\\Http\\Uri\\UriInterface')
+ );
+
+ $this->assertInstanceOf('\\OAuth\\OAuth1\\Service\\AbstractService', $service);
+ }
+
+ /**
+ * @covers OAuth\OAuth1\Service\Tumblr::__construct
+ * @covers OAuth\OAuth1\Service\Tumblr::getRequestTokenEndpoint
+ */
+ public function testGetRequestTokenEndpoint()
+ {
+ $service = new Tumblr(
+ $this->getMock('\\OAuth\\Common\\Consumer\\CredentialsInterface'),
+ $this->getMock('\\OAuth\\Common\\Http\\Client\\ClientInterface'),
+ $this->getMock('\\OAuth\\Common\\Storage\\TokenStorageInterface'),
+ $this->getMock('\\OAuth\\OAuth1\\Signature\\SignatureInterface')
+ );
+
+ $this->assertSame(
+ 'https://www.tumblr.com/oauth/request_token',
+ $service->getRequestTokenEndpoint()->getAbsoluteUri()
+ );
+ }
+
+ /**
+ * @covers OAuth\OAuth1\Service\Tumblr::__construct
+ * @covers OAuth\OAuth1\Service\Tumblr::getAuthorizationEndpoint
+ */
+ public function testGetAuthorizationEndpoint()
+ {
+ $service = new Tumblr(
+ $this->getMock('\\OAuth\\Common\\Consumer\\CredentialsInterface'),
+ $this->getMock('\\OAuth\\Common\\Http\\Client\\ClientInterface'),
+ $this->getMock('\\OAuth\\Common\\Storage\\TokenStorageInterface'),
+ $this->getMock('\\OAuth\\OAuth1\\Signature\\SignatureInterface')
+ );
+
+ $this->assertSame(
+ 'https://www.tumblr.com/oauth/authorize',
+ $service->getAuthorizationEndpoint()->getAbsoluteUri()
+ );
+ }
+
+ /**
+ * @covers OAuth\OAuth1\Service\Tumblr::__construct
+ * @covers OAuth\OAuth1\Service\Tumblr::getAccessTokenEndpoint
+ */
+ public function testGetAccessTokenEndpoint()
+ {
+ $service = new Tumblr(
+ $this->getMock('\\OAuth\\Common\\Consumer\\CredentialsInterface'),
+ $this->getMock('\\OAuth\\Common\\Http\\Client\\ClientInterface'),
+ $this->getMock('\\OAuth\\Common\\Storage\\TokenStorageInterface'),
+ $this->getMock('\\OAuth\\OAuth1\\Signature\\SignatureInterface')
+ );
+
+ $this->assertSame(
+ 'https://www.tumblr.com/oauth/access_token',
+ $service->getAccessTokenEndpoint()->getAbsoluteUri()
+ );
+ }
+
+ /**
+ * @covers OAuth\OAuth1\Service\Tumblr::__construct
+ * @covers OAuth\OAuth1\Service\Tumblr::getRequestTokenEndpoint
+ * @covers OAuth\OAuth1\Service\Tumblr::parseRequestTokenResponse
+ */
+ public function testParseRequestTokenResponseThrowsExceptionOnNulledResponse()
+ {
+ $client = $this->getMock('\\OAuth\\Common\\Http\\Client\\ClientInterface');
+ $client->expects($this->once())->method('retrieveResponse')->will($this->returnValue(null));
+
+ $service = new Tumblr(
+ $this->getMock('\\OAuth\\Common\\Consumer\\CredentialsInterface'),
+ $client,
+ $this->getMock('\\OAuth\\Common\\Storage\\TokenStorageInterface'),
+ $this->getMock('\\OAuth\\OAuth1\\Signature\\SignatureInterface')
+ );
+
+ $this->setExpectedException('\\OAuth\\Common\\Http\\Exception\\TokenResponseException');
+
+ $service->requestRequestToken();
+ }
+
+ /**
+ * @covers OAuth\OAuth1\Service\Tumblr::__construct
+ * @covers OAuth\OAuth1\Service\Tumblr::getRequestTokenEndpoint
+ * @covers OAuth\OAuth1\Service\Tumblr::parseRequestTokenResponse
+ */
+ public function testParseRequestTokenResponseThrowsExceptionOnResponseNotAnArray()
+ {
+ $client = $this->getMock('\\OAuth\\Common\\Http\\Client\\ClientInterface');
+ $client->expects($this->once())->method('retrieveResponse')->will($this->returnValue('notanarray'));
+
+ $service = new Tumblr(
+ $this->getMock('\\OAuth\\Common\\Consumer\\CredentialsInterface'),
+ $client,
+ $this->getMock('\\OAuth\\Common\\Storage\\TokenStorageInterface'),
+ $this->getMock('\\OAuth\\OAuth1\\Signature\\SignatureInterface')
+ );
+
+ $this->setExpectedException('\\OAuth\\Common\\Http\\Exception\\TokenResponseException');
+
+ $service->requestRequestToken();
+ }
+
+ /**
+ * @covers OAuth\OAuth1\Service\Tumblr::__construct
+ * @covers OAuth\OAuth1\Service\Tumblr::getRequestTokenEndpoint
+ * @covers OAuth\OAuth1\Service\Tumblr::parseRequestTokenResponse
+ */
+ public function testParseRequestTokenResponseThrowsExceptionOnResponseCallbackNotSet()
+ {
+ $client = $this->getMock('\\OAuth\\Common\\Http\\Client\\ClientInterface');
+ $client->expects($this->once())->method('retrieveResponse')->will($this->returnValue('foo=bar'));
+
+ $service = new Tumblr(
+ $this->getMock('\\OAuth\\Common\\Consumer\\CredentialsInterface'),
+ $client,
+ $this->getMock('\\OAuth\\Common\\Storage\\TokenStorageInterface'),
+ $this->getMock('\\OAuth\\OAuth1\\Signature\\SignatureInterface')
+ );
+
+ $this->setExpectedException('\\OAuth\\Common\\Http\\Exception\\TokenResponseException');
+
+ $service->requestRequestToken();
+ }
+
+ /**
+ * @covers OAuth\OAuth1\Service\Tumblr::__construct
+ * @covers OAuth\OAuth1\Service\Tumblr::getRequestTokenEndpoint
+ * @covers OAuth\OAuth1\Service\Tumblr::parseRequestTokenResponse
+ */
+ public function testParseRequestTokenResponseThrowsExceptionOnResponseCallbackNotTrue()
+ {
+ $client = $this->getMock('\\OAuth\\Common\\Http\\Client\\ClientInterface');
+ $client->expects($this->once())->method('retrieveResponse')->will($this->returnValue(
+ 'oauth_callback_confirmed=false'
+ ));
+
+ $service = new Tumblr(
+ $this->getMock('\\OAuth\\Common\\Consumer\\CredentialsInterface'),
+ $client,
+ $this->getMock('\\OAuth\\Common\\Storage\\TokenStorageInterface'),
+ $this->getMock('\\OAuth\\OAuth1\\Signature\\SignatureInterface')
+ );
+
+ $this->setExpectedException('\\OAuth\\Common\\Http\\Exception\\TokenResponseException');
+
+ $service->requestRequestToken();
+ }
+
+ /**
+ * @covers OAuth\OAuth1\Service\Tumblr::__construct
+ * @covers OAuth\OAuth1\Service\Tumblr::getRequestTokenEndpoint
+ * @covers OAuth\OAuth1\Service\Tumblr::parseRequestTokenResponse
+ * @covers OAuth\OAuth1\Service\Tumblr::parseAccessTokenResponse
+ */
+ public function testParseRequestTokenResponseValid()
+ {
+ $client = $this->getMock('\\OAuth\\Common\\Http\\Client\\ClientInterface');
+ $client->expects($this->once())->method('retrieveResponse')->will($this->returnValue(
+ 'oauth_callback_confirmed=true&oauth_token=foo&oauth_token_secret=bar'
+ ));
+
+ $service = new Tumblr(
+ $this->getMock('\\OAuth\\Common\\Consumer\\CredentialsInterface'),
+ $client,
+ $this->getMock('\\OAuth\\Common\\Storage\\TokenStorageInterface'),
+ $this->getMock('\\OAuth\\OAuth1\\Signature\\SignatureInterface')
+ );
+
+ $this->assertInstanceOf('\\OAuth\\OAuth1\\Token\\StdOAuth1Token', $service->requestRequestToken());
+ }
+
+ /**
+ * @covers OAuth\OAuth1\Service\Tumblr::__construct
+ * @covers OAuth\OAuth1\Service\Tumblr::getRequestTokenEndpoint
+ * @covers OAuth\OAuth1\Service\Tumblr::parseAccessTokenResponse
+ */
+ public function testParseAccessTokenResponseThrowsExceptionOnError()
+ {
+ $client = $this->getMock('\\OAuth\\Common\\Http\\Client\\ClientInterface');
+ $client->expects($this->once())->method('retrieveResponse')->will($this->returnValue('error=bar'));
+
+ $token = $this->getMock('\\OAuth\\OAuth1\\Token\\TokenInterface');
+
+ $storage = $this->getMock('\\OAuth\\Common\\Storage\\TokenStorageInterface');
+ $storage->expects($this->any())->method('retrieveAccessToken')->will($this->returnValue($token));
+
+ $service = new Tumblr(
+ $this->getMock('\\OAuth\\Common\\Consumer\\CredentialsInterface'),
+ $client,
+ $storage,
+ $this->getMock('\\OAuth\\OAuth1\\Signature\\SignatureInterface')
+ );
+
+ $this->setExpectedException('\\OAuth\\Common\\Http\\Exception\\TokenResponseException');
+
+ $service->requestAccessToken('foo', 'bar', $token);
+ }
+
+ /**
+ * @covers OAuth\OAuth1\Service\Tumblr::__construct
+ * @covers OAuth\OAuth1\Service\Tumblr::getRequestTokenEndpoint
+ * @covers OAuth\OAuth1\Service\Tumblr::parseAccessTokenResponse
+ */
+ public function testParseAccessTokenResponseValid()
+ {
+ $client = $this->getMock('\\OAuth\\Common\\Http\\Client\\ClientInterface');
+ $client->expects($this->once())->method('retrieveResponse')->will($this->returnValue(
+ 'oauth_token=foo&oauth_token_secret=bar'
+ ));
+
+ $token = $this->getMock('\\OAuth\\OAuth1\\Token\\TokenInterface');
+
+ $storage = $this->getMock('\\OAuth\\Common\\Storage\\TokenStorageInterface');
+ $storage->expects($this->any())->method('retrieveAccessToken')->will($this->returnValue($token));
+
+ $service = new Tumblr(
+ $this->getMock('\\OAuth\\Common\\Consumer\\CredentialsInterface'),
+ $client,
+ $storage,
+ $this->getMock('\\OAuth\\OAuth1\\Signature\\SignatureInterface')
+ );
+
+ $this->assertInstanceOf('\\OAuth\\OAuth1\\Token\\StdOAuth1Token', $service->requestAccessToken('foo', 'bar', $token));
+ }
+}
diff --git a/vendor/lusitanian/oauth/tests/Unit/OAuth1/Service/TwitterTest.php b/vendor/lusitanian/oauth/tests/Unit/OAuth1/Service/TwitterTest.php
new file mode 100644
index 00000000..bb31fa29
--- /dev/null
+++ b/vendor/lusitanian/oauth/tests/Unit/OAuth1/Service/TwitterTest.php
@@ -0,0 +1,307 @@
+getMock('\\OAuth\\Common\\Consumer\\CredentialsInterface'),
+ $this->getMock('\\OAuth\\Common\\Http\\Client\\ClientInterface'),
+ $this->getMock('\\OAuth\\Common\\Storage\\TokenStorageInterface'),
+ $this->getMock('\\OAuth\\OAuth1\\Signature\\SignatureInterface')
+ );
+
+ $this->assertInstanceOf('\\OAuth\\OAuth1\\Service\\ServiceInterface', $service);
+ }
+
+ /**
+ * @covers OAuth\OAuth1\Service\Twitter::__construct
+ */
+ public function testConstructCorrectInstanceWithoutCustomUri()
+ {
+ $service = new Twitter(
+ $this->getMock('\\OAuth\\Common\\Consumer\\CredentialsInterface'),
+ $this->getMock('\\OAuth\\Common\\Http\\Client\\ClientInterface'),
+ $this->getMock('\\OAuth\\Common\\Storage\\TokenStorageInterface'),
+ $this->getMock('\\OAuth\\OAuth1\\Signature\\SignatureInterface')
+ );
+
+ $this->assertInstanceOf('\\OAuth\\OAuth1\\Service\\AbstractService', $service);
+ }
+
+ /**
+ * @covers OAuth\OAuth1\Service\Twitter::__construct
+ */
+ public function testConstructCorrectInstanceWithCustomUri()
+ {
+ $service = new Twitter(
+ $this->getMock('\\OAuth\\Common\\Consumer\\CredentialsInterface'),
+ $this->getMock('\\OAuth\\Common\\Http\\Client\\ClientInterface'),
+ $this->getMock('\\OAuth\\Common\\Storage\\TokenStorageInterface'),
+ $this->getMock('\\OAuth\\OAuth1\\Signature\\SignatureInterface'),
+ $this->getMock('\\OAuth\\Common\\Http\\Uri\\UriInterface')
+ );
+
+ $this->assertInstanceOf('\\OAuth\\OAuth1\\Service\\AbstractService', $service);
+ }
+
+ /**
+ * @covers OAuth\OAuth1\Service\Twitter::__construct
+ * @covers OAuth\OAuth1\Service\Twitter::getRequestTokenEndpoint
+ */
+ public function testGetRequestTokenEndpoint()
+ {
+ $service = new Twitter(
+ $this->getMock('\\OAuth\\Common\\Consumer\\CredentialsInterface'),
+ $this->getMock('\\OAuth\\Common\\Http\\Client\\ClientInterface'),
+ $this->getMock('\\OAuth\\Common\\Storage\\TokenStorageInterface'),
+ $this->getMock('\\OAuth\\OAuth1\\Signature\\SignatureInterface')
+ );
+
+ $this->assertSame(
+ 'https://api.twitter.com/oauth/request_token',
+ $service->getRequestTokenEndpoint()->getAbsoluteUri()
+ );
+ }
+
+ /**
+ * @covers OAuth\OAuth1\Service\Twitter::__construct
+ * @covers OAuth\OAuth1\Service\Twitter::getAuthorizationEndpoint
+ */
+ public function testGetAuthorizationEndpoint()
+ {
+ $service = new Twitter(
+ $this->getMock('\\OAuth\\Common\\Consumer\\CredentialsInterface'),
+ $this->getMock('\\OAuth\\Common\\Http\\Client\\ClientInterface'),
+ $this->getMock('\\OAuth\\Common\\Storage\\TokenStorageInterface'),
+ $this->getMock('\\OAuth\\OAuth1\\Signature\\SignatureInterface')
+ );
+
+ $this->assertTrue(
+ in_array(
+ strtolower($service->getAuthorizationEndpoint()->getAbsoluteUri()),
+ array(\OAuth\OAuth1\Service\Twitter::ENDPOINT_AUTHENTICATE, \OAuth\OAuth1\Service\Twitter::ENDPOINT_AUTHORIZE)
+ )
+ );
+
+ $service->setAuthorizationEndpoint( \OAuth\OAuth1\Service\Twitter::ENDPOINT_AUTHORIZE );
+
+ $this->assertTrue(
+ in_array(
+ strtolower($service->getAuthorizationEndpoint()->getAbsoluteUri()),
+ array(\OAuth\OAuth1\Service\Twitter::ENDPOINT_AUTHENTICATE, \OAuth\OAuth1\Service\Twitter::ENDPOINT_AUTHORIZE)
+ )
+ );
+ }
+
+ /**
+ * @covers OAuth\OAuth1\Service\Twitter::__construct
+ * @covers OAuth\OAuth1\Service\Twitter::setAuthorizationEndpoint
+ */
+ public function testSetAuthorizationEndpoint()
+ {
+ $service = new Twitter(
+ $this->getMock('\\OAuth\\Common\\Consumer\\CredentialsInterface'),
+ $this->getMock('\\OAuth\\Common\\Http\\Client\\ClientInterface'),
+ $this->getMock('\\OAuth\\Common\\Storage\\TokenStorageInterface'),
+ $this->getMock('\\OAuth\\OAuth1\\Signature\\SignatureInterface')
+ );
+
+ $this->setExpectedException('\\OAuth\\Common\\Exception\\Exception');
+
+ $service->setAuthorizationEndpoint('foo');
+ }
+
+ /**
+ * @covers OAuth\OAuth1\Service\Twitter::__construct
+ * @covers OAuth\OAuth1\Service\Twitter::getAccessTokenEndpoint
+ */
+ public function testGetAccessTokenEndpoint()
+ {
+ $service = new Twitter(
+ $this->getMock('\\OAuth\\Common\\Consumer\\CredentialsInterface'),
+ $this->getMock('\\OAuth\\Common\\Http\\Client\\ClientInterface'),
+ $this->getMock('\\OAuth\\Common\\Storage\\TokenStorageInterface'),
+ $this->getMock('\\OAuth\\OAuth1\\Signature\\SignatureInterface')
+ );
+
+ $this->assertSame(
+ 'https://api.twitter.com/oauth/access_token',
+ $service->getAccessTokenEndpoint()->getAbsoluteUri()
+ );
+ }
+
+ /**
+ * @covers OAuth\OAuth1\Service\Twitter::__construct
+ * @covers OAuth\OAuth1\Service\Twitter::getRequestTokenEndpoint
+ * @covers OAuth\OAuth1\Service\Twitter::parseRequestTokenResponse
+ */
+ public function testParseRequestTokenResponseThrowsExceptionOnNulledResponse()
+ {
+ $client = $this->getMock('\\OAuth\\Common\\Http\\Client\\ClientInterface');
+ $client->expects($this->once())->method('retrieveResponse')->will($this->returnValue(null));
+
+ $service = new Twitter(
+ $this->getMock('\\OAuth\\Common\\Consumer\\CredentialsInterface'),
+ $client,
+ $this->getMock('\\OAuth\\Common\\Storage\\TokenStorageInterface'),
+ $this->getMock('\\OAuth\\OAuth1\\Signature\\SignatureInterface')
+ );
+
+ $this->setExpectedException('\\OAuth\\Common\\Http\\Exception\\TokenResponseException');
+
+ $service->requestRequestToken();
+ }
+
+ /**
+ * @covers OAuth\OAuth1\Service\Twitter::__construct
+ * @covers OAuth\OAuth1\Service\Twitter::getRequestTokenEndpoint
+ * @covers OAuth\OAuth1\Service\Twitter::parseRequestTokenResponse
+ */
+ public function testParseRequestTokenResponseThrowsExceptionOnResponseNotAnArray()
+ {
+ $client = $this->getMock('\\OAuth\\Common\\Http\\Client\\ClientInterface');
+ $client->expects($this->once())->method('retrieveResponse')->will($this->returnValue('notanarray'));
+
+ $service = new Twitter(
+ $this->getMock('\\OAuth\\Common\\Consumer\\CredentialsInterface'),
+ $client,
+ $this->getMock('\\OAuth\\Common\\Storage\\TokenStorageInterface'),
+ $this->getMock('\\OAuth\\OAuth1\\Signature\\SignatureInterface')
+ );
+
+ $this->setExpectedException('\\OAuth\\Common\\Http\\Exception\\TokenResponseException');
+
+ $service->requestRequestToken();
+ }
+
+ /**
+ * @covers OAuth\OAuth1\Service\Twitter::__construct
+ * @covers OAuth\OAuth1\Service\Twitter::getRequestTokenEndpoint
+ * @covers OAuth\OAuth1\Service\Twitter::parseRequestTokenResponse
+ */
+ public function testParseRequestTokenResponseThrowsExceptionOnResponseCallbackNotSet()
+ {
+ $client = $this->getMock('\\OAuth\\Common\\Http\\Client\\ClientInterface');
+ $client->expects($this->once())->method('retrieveResponse')->will($this->returnValue('foo=bar'));
+
+ $service = new Twitter(
+ $this->getMock('\\OAuth\\Common\\Consumer\\CredentialsInterface'),
+ $client,
+ $this->getMock('\\OAuth\\Common\\Storage\\TokenStorageInterface'),
+ $this->getMock('\\OAuth\\OAuth1\\Signature\\SignatureInterface')
+ );
+
+ $this->setExpectedException('\\OAuth\\Common\\Http\\Exception\\TokenResponseException');
+
+ $service->requestRequestToken();
+ }
+
+ /**
+ * @covers OAuth\OAuth1\Service\Twitter::__construct
+ * @covers OAuth\OAuth1\Service\Twitter::getRequestTokenEndpoint
+ * @covers OAuth\OAuth1\Service\Twitter::parseRequestTokenResponse
+ */
+ public function testParseRequestTokenResponseThrowsExceptionOnResponseCallbackNotTrue()
+ {
+ $client = $this->getMock('\\OAuth\\Common\\Http\\Client\\ClientInterface');
+ $client->expects($this->once())->method('retrieveResponse')->will($this->returnValue(
+ 'oauth_callback_confirmed=false'
+ ));
+
+ $service = new Twitter(
+ $this->getMock('\\OAuth\\Common\\Consumer\\CredentialsInterface'),
+ $client,
+ $this->getMock('\\OAuth\\Common\\Storage\\TokenStorageInterface'),
+ $this->getMock('\\OAuth\\OAuth1\\Signature\\SignatureInterface')
+ );
+
+ $this->setExpectedException('\\OAuth\\Common\\Http\\Exception\\TokenResponseException');
+
+ $service->requestRequestToken();
+ }
+
+ /**
+ * @covers OAuth\OAuth1\Service\Twitter::__construct
+ * @covers OAuth\OAuth1\Service\Twitter::getRequestTokenEndpoint
+ * @covers OAuth\OAuth1\Service\Twitter::parseRequestTokenResponse
+ * @covers OAuth\OAuth1\Service\Twitter::parseAccessTokenResponse
+ */
+ public function testParseRequestTokenResponseValid()
+ {
+ $client = $this->getMock('\\OAuth\\Common\\Http\\Client\\ClientInterface');
+ $client->expects($this->once())->method('retrieveResponse')->will($this->returnValue(
+ 'oauth_callback_confirmed=true&oauth_token=foo&oauth_token_secret=bar'
+ ));
+
+ $service = new Twitter(
+ $this->getMock('\\OAuth\\Common\\Consumer\\CredentialsInterface'),
+ $client,
+ $this->getMock('\\OAuth\\Common\\Storage\\TokenStorageInterface'),
+ $this->getMock('\\OAuth\\OAuth1\\Signature\\SignatureInterface')
+ );
+
+ $this->assertInstanceOf('\\OAuth\\OAuth1\\Token\\StdOAuth1Token', $service->requestRequestToken());
+ }
+
+ /**
+ * @covers OAuth\OAuth1\Service\Twitter::__construct
+ * @covers OAuth\OAuth1\Service\Twitter::getRequestTokenEndpoint
+ * @covers OAuth\OAuth1\Service\Twitter::parseAccessTokenResponse
+ */
+ public function testParseAccessTokenResponseThrowsExceptionOnError()
+ {
+ $client = $this->getMock('\\OAuth\\Common\\Http\\Client\\ClientInterface');
+ $client->expects($this->once())->method('retrieveResponse')->will($this->returnValue('error=bar'));
+
+ $token = $this->getMock('\\OAuth\\OAuth1\\Token\\TokenInterface');
+
+ $storage = $this->getMock('\\OAuth\\Common\\Storage\\TokenStorageInterface');
+ $storage->expects($this->any())->method('retrieveAccessToken')->will($this->returnValue($token));
+
+ $service = new Twitter(
+ $this->getMock('\\OAuth\\Common\\Consumer\\CredentialsInterface'),
+ $client,
+ $storage,
+ $this->getMock('\\OAuth\\OAuth1\\Signature\\SignatureInterface')
+ );
+
+ $this->setExpectedException('\\OAuth\\Common\\Http\\Exception\\TokenResponseException');
+
+ $service->requestAccessToken('foo', 'bar', $token);
+ }
+
+ /**
+ * @covers OAuth\OAuth1\Service\Twitter::__construct
+ * @covers OAuth\OAuth1\Service\Twitter::getRequestTokenEndpoint
+ * @covers OAuth\OAuth1\Service\Twitter::parseAccessTokenResponse
+ */
+ public function testParseAccessTokenResponseValid()
+ {
+ $client = $this->getMock('\\OAuth\\Common\\Http\\Client\\ClientInterface');
+ $client->expects($this->once())->method('retrieveResponse')->will($this->returnValue(
+ 'oauth_token=foo&oauth_token_secret=bar'
+ ));
+
+ $token = $this->getMock('\\OAuth\\OAuth1\\Token\\TokenInterface');
+
+ $storage = $this->getMock('\\OAuth\\Common\\Storage\\TokenStorageInterface');
+ $storage->expects($this->any())->method('retrieveAccessToken')->will($this->returnValue($token));
+
+ $service = new Twitter(
+ $this->getMock('\\OAuth\\Common\\Consumer\\CredentialsInterface'),
+ $client,
+ $storage,
+ $this->getMock('\\OAuth\\OAuth1\\Signature\\SignatureInterface')
+ );
+
+ $this->assertInstanceOf('\\OAuth\\OAuth1\\Token\\StdOAuth1Token', $service->requestAccessToken('foo', 'bar', $token));
+ }
+}
diff --git a/vendor/lusitanian/oauth/tests/Unit/OAuth1/Service/XingTest.php b/vendor/lusitanian/oauth/tests/Unit/OAuth1/Service/XingTest.php
new file mode 100644
index 00000000..d3a5f4ae
--- /dev/null
+++ b/vendor/lusitanian/oauth/tests/Unit/OAuth1/Service/XingTest.php
@@ -0,0 +1,239 @@
+client = $this->getMock('\\OAuth\\Common\\Http\\Client\\ClientInterface');
+ $this->storage = $this->getMock('\\OAuth\\Common\\Storage\\TokenStorageInterface');
+
+ $this->xing = new Xing(
+ $this->getMock('\\OAuth\\Common\\Consumer\\CredentialsInterface'),
+ $this->client,
+ $this->storage,
+ $this->getMock('\\OAuth\\OAuth1\\Signature\\SignatureInterface')
+ );
+ }
+
+ /**
+ * @covers OAuth\OAuth1\Service\Xing::__construct
+ */
+ public function testConstructCorrectInterfaceWithoutCustomUri()
+ {
+ $this->assertInstanceOf(
+ '\\OAuth\\OAuth1\\Service\\ServiceInterface', $this->xing
+ );
+ }
+
+ /**
+ * @covers OAuth\OAuth1\Service\Xing::__construct
+ */
+ public function testConstructCorrectInstanceWithoutCustomUri()
+ {
+ $this->assertInstanceOf(
+ '\\OAuth\\OAuth1\\Service\\AbstractService', $this->xing
+ );
+ }
+
+ /**
+ * @covers OAuth\OAuth1\Service\Xing::__construct
+ */
+ public function testConstructCorrectInstanceWithCustomUri()
+ {
+ $service = new Xing(
+ $this->getMock('\\OAuth\\Common\\Consumer\\CredentialsInterface'),
+ $this->client,
+ $this->storage,
+ $this->getMock('\\OAuth\\OAuth1\\Signature\\SignatureInterface'),
+ $this->getMock('\\OAuth\\Common\\Http\\Uri\\UriInterface')
+ );
+
+ $this->assertInstanceOf('\\OAuth\\OAuth1\\Service\\AbstractService', $service);
+ }
+
+ /**
+ * @covers OAuth\OAuth1\Service\Xing::__construct
+ * @covers OAuth\OAuth1\Service\Xing::getRequestTokenEndpoint
+ */
+ public function testGetRequestTokenEndpoint()
+ {
+ $this->assertSame(
+ 'https://api.xing.com/v1/request_token',
+ $this->xing->getRequestTokenEndpoint()->getAbsoluteUri()
+ );
+ }
+
+ /**
+ * @covers OAuth\OAuth1\Service\Xing::__construct
+ * @covers OAuth\OAuth1\Service\Xing::getAuthorizationEndpoint
+ */
+ public function testGetAuthorizationEndpoint()
+ {
+ $this->assertSame(
+ 'https://api.xing.com/v1/authorize',
+ $this->xing->getAuthorizationEndpoint()->getAbsoluteUri()
+ );
+ }
+
+ /**
+ * @covers OAuth\OAuth1\Service\Xing::__construct
+ * @covers OAuth\OAuth1\Service\Xing::getAccessTokenEndpoint
+ */
+ public function testGetAccessTokenEndpoint()
+ {
+ $this->assertSame(
+ 'https://api.xing.com/v1/access_token',
+ $this->xing->getAccessTokenEndpoint()->getAbsoluteUri()
+ );
+ }
+
+ /**
+ * @covers OAuth\OAuth1\Service\Xing::__construct
+ * @covers OAuth\OAuth1\Service\Xing::getRequestTokenEndpoint
+ * @covers OAuth\OAuth1\Service\Xing::parseRequestTokenResponse
+ */
+ public function testParseRequestTokenResponseThrowsExceptionOnNulledResponse()
+ {
+ $this->client
+ ->expects($this->once())
+ ->method('retrieveResponse')
+ ->will($this->returnValue(null));
+
+ $this->setExpectedException('\\OAuth\\Common\\Http\\Exception\\TokenResponseException');
+
+ $this->xing->requestRequestToken();
+ }
+
+ /**
+ * @covers OAuth\OAuth1\Service\Xing::__construct
+ * @covers OAuth\OAuth1\Service\Xing::getRequestTokenEndpoint
+ * @covers OAuth\OAuth1\Service\Xing::parseRequestTokenResponse
+ */
+ public function testParseRequestTokenResponseThrowsExceptionOnResponseNotAnArray()
+ {
+ $this->client
+ ->expects($this->once())
+ ->method('retrieveResponse')
+ ->will($this->returnValue('notanarray'));
+
+ $this->setExpectedException('\\OAuth\\Common\\Http\\Exception\\TokenResponseException');
+
+ $this->xing->requestRequestToken();
+ }
+
+ /**
+ * @covers OAuth\OAuth1\Service\Xing::__construct
+ * @covers OAuth\OAuth1\Service\Xing::getRequestTokenEndpoint
+ * @covers OAuth\OAuth1\Service\Xing::parseRequestTokenResponse
+ */
+ public function testParseRequestTokenResponseThrowsExceptionOnResponseCallbackNotSet()
+ {
+ $this->client
+ ->expects($this->once())
+ ->method('retrieveResponse')
+ ->will($this->returnValue('foo=bar'));
+
+ $this->setExpectedException('\\OAuth\\Common\\Http\\Exception\\TokenResponseException');
+
+ $this->xing->requestRequestToken();
+ }
+
+ /**
+ * @covers OAuth\OAuth1\Service\Xing::__construct
+ * @covers OAuth\OAuth1\Service\Xing::getRequestTokenEndpoint
+ * @covers OAuth\OAuth1\Service\Xing::parseRequestTokenResponse
+ */
+ public function testParseRequestTokenResponseThrowsExceptionOnResponseCallbackNotTrue()
+ {
+ $this->client
+ ->expects($this->once())
+ ->method('retrieveResponse')
+ ->will($this->returnValue('oauth_callback_confirmed=false'));
+
+ $this->setExpectedException('\\OAuth\\Common\\Http\\Exception\\TokenResponseException');
+
+ $this->xing->requestRequestToken();
+ }
+
+ /**
+ * @covers OAuth\OAuth1\Service\Xing::__construct
+ * @covers OAuth\OAuth1\Service\Xing::getRequestTokenEndpoint
+ * @covers OAuth\OAuth1\Service\Xing::parseRequestTokenResponse
+ * @covers OAuth\OAuth1\Service\Xing::parseAccessTokenResponse
+ */
+ public function testParseRequestTokenResponseValid()
+ {
+ $this->client
+ ->expects($this->once())
+ ->method('retrieveResponse')
+ ->will($this->returnValue(
+ 'oauth_callback_confirmed=true&oauth_token=foo&oauth_token_secret=bar'
+ ));
+
+ $this->assertInstanceOf(
+ '\\OAuth\\OAuth1\\Token\\StdOAuth1Token',
+ $this->xing->requestRequestToken()
+ );
+ }
+
+ /**
+ * @covers OAuth\OAuth1\Service\Xing::__construct
+ * @covers OAuth\OAuth1\Service\Xing::getRequestTokenEndpoint
+ * @covers OAuth\OAuth1\Service\Xing::parseAccessTokenResponse
+ */
+ public function testParseAccessTokenResponseThrowsExceptionOnError()
+ {
+ $this->client
+ ->expects($this->once())
+ ->method('retrieveResponse')
+ ->will($this->returnValue('error=bar'));
+
+ $token = $this->getMock('\\OAuth\\OAuth1\\Token\\TokenInterface');
+
+ $this->storage
+ ->expects($this->any())
+ ->method('retrieveAccessToken')
+ ->will($this->returnValue($token));
+
+ $this->setExpectedException('\\OAuth\\Common\\Http\\Exception\\TokenResponseException');
+
+ $this->xing->requestAccessToken('foo', 'bar', $token);
+ }
+
+ /**
+ * @covers OAuth\OAuth1\Service\Xing::__construct
+ * @covers OAuth\OAuth1\Service\Xing::getRequestTokenEndpoint
+ * @covers OAuth\OAuth1\Service\Xing::parseAccessTokenResponse
+ */
+ public function testParseAccessTokenResponseValid()
+ {
+ $this->client
+ ->expects($this->once())
+ ->method('retrieveResponse')
+ ->will($this->returnValue('oauth_token=foo&oauth_token_secret=bar'));
+
+ $token = $this->getMock('\\OAuth\\OAuth1\\Token\\TokenInterface');
+
+ $this->storage
+ ->expects($this->any())
+ ->method('retrieveAccessToken')
+ ->will($this->returnValue($token));
+
+
+ $this->assertInstanceOf(
+ '\\OAuth\\OAuth1\\Token\\StdOAuth1Token',
+ $this->xing->requestAccessToken('foo', 'bar', $token)
+ );
+ }
+}
diff --git a/vendor/lusitanian/oauth/tests/Unit/OAuth1/Service/YahooTest.php b/vendor/lusitanian/oauth/tests/Unit/OAuth1/Service/YahooTest.php
new file mode 100644
index 00000000..e8feb5dc
--- /dev/null
+++ b/vendor/lusitanian/oauth/tests/Unit/OAuth1/Service/YahooTest.php
@@ -0,0 +1,302 @@
+getMock('\\OAuth\\Common\\Consumer\\CredentialsInterface'),
+ $this->getMock('\\OAuth\\Common\\Http\\Client\\ClientInterface'),
+ $this->getMock('\\OAuth\\Common\\Storage\\TokenStorageInterface'),
+ $this->getMock('\\OAuth\\OAuth1\\Signature\\SignatureInterface')
+ );
+
+ $this->assertInstanceOf('\\OAuth\\OAuth1\\Service\\ServiceInterface', $service);
+ }
+
+ /**
+ * @covers OAuth\OAuth1\Service\Yahoo::__construct
+ */
+ public function testConstructCorrectInstanceWithoutCustomUri()
+ {
+ $service = new Yahoo(
+ $this->getMock('\\OAuth\\Common\\Consumer\\CredentialsInterface'),
+ $this->getMock('\\OAuth\\Common\\Http\\Client\\ClientInterface'),
+ $this->getMock('\\OAuth\\Common\\Storage\\TokenStorageInterface'),
+ $this->getMock('\\OAuth\\OAuth1\\Signature\\SignatureInterface')
+ );
+
+ $this->assertInstanceOf('\\OAuth\\OAuth1\\Service\\AbstractService', $service);
+ }
+
+ /**
+ * @covers OAuth\OAuth1\Service\Yahoo::__construct
+ */
+ public function testConstructCorrectInstanceWithCustomUri()
+ {
+ $service = new Yahoo(
+ $this->getMock('\\OAuth\\Common\\Consumer\\CredentialsInterface'),
+ $this->getMock('\\OAuth\\Common\\Http\\Client\\ClientInterface'),
+ $this->getMock('\\OAuth\\Common\\Storage\\TokenStorageInterface'),
+ $this->getMock('\\OAuth\\OAuth1\\Signature\\SignatureInterface'),
+ $this->getMock('\\OAuth\\Common\\Http\\Uri\\UriInterface')
+ );
+
+ $this->assertInstanceOf('\\OAuth\\OAuth1\\Service\\AbstractService', $service);
+ }
+
+ /**
+ * @covers OAuth\OAuth1\Service\Yahoo::__construct
+ * @covers OAuth\OAuth1\Service\Yahoo::getRequestTokenEndpoint
+ */
+ public function testGetRequestTokenEndpoint()
+ {
+ $service = new Yahoo(
+ $this->getMock('\\OAuth\\Common\\Consumer\\CredentialsInterface'),
+ $this->getMock('\\OAuth\\Common\\Http\\Client\\ClientInterface'),
+ $this->getMock('\\OAuth\\Common\\Storage\\TokenStorageInterface'),
+ $this->getMock('\\OAuth\\OAuth1\\Signature\\SignatureInterface')
+ );
+
+ $this->assertSame(
+ 'https://api.login.yahoo.com/oauth/v2/get_request_token',
+ $service->getRequestTokenEndpoint()->getAbsoluteUri()
+ );
+ }
+
+ /**
+ * @covers OAuth\OAuth1\Service\Yahoo::__construct
+ * @covers OAuth\OAuth1\Service\Yahoo::getAuthorizationEndpoint
+ */
+ public function testGetAuthorizationEndpoint()
+ {
+ $service = new Yahoo(
+ $this->getMock('\\OAuth\\Common\\Consumer\\CredentialsInterface'),
+ $this->getMock('\\OAuth\\Common\\Http\\Client\\ClientInterface'),
+ $this->getMock('\\OAuth\\Common\\Storage\\TokenStorageInterface'),
+ $this->getMock('\\OAuth\\OAuth1\\Signature\\SignatureInterface')
+ );
+
+ $this->assertSame(
+ 'https://api.login.yahoo.com/oauth/v2/request_auth',
+ $service->getAuthorizationEndpoint()->getAbsoluteUri()
+ );
+ }
+
+ /**
+ * @covers OAuth\OAuth1\Service\Yahoo::__construct
+ * @covers OAuth\OAuth1\Service\Yahoo::getAccessTokenEndpoint
+ */
+ public function testGetAccessTokenEndpoint()
+ {
+ $service = new Yahoo(
+ $this->getMock('\\OAuth\\Common\\Consumer\\CredentialsInterface'),
+ $this->getMock('\\OAuth\\Common\\Http\\Client\\ClientInterface'),
+ $this->getMock('\\OAuth\\Common\\Storage\\TokenStorageInterface'),
+ $this->getMock('\\OAuth\\OAuth1\\Signature\\SignatureInterface')
+ );
+
+ $this->assertSame(
+ 'https://api.login.yahoo.com/oauth/v2/get_token',
+ $service->getAccessTokenEndpoint()->getAbsoluteUri()
+ );
+ }
+
+ /**
+ * @covers OAuth\OAuth1\Service\Yahoo::__construct
+ * @covers OAuth\OAuth1\Service\Yahoo::getRequestTokenEndpoint
+ * @covers OAuth\OAuth1\Service\Yahoo::parseRequestTokenResponse
+ */
+ public function testParseRequestTokenResponseThrowsExceptionOnNulledResponse()
+ {
+ $client = $this->getMock('\\OAuth\\Common\\Http\\Client\\ClientInterface');
+ $client->expects($this->once())->method('retrieveResponse')->will($this->returnValue(null));
+
+ $service = new Yahoo(
+ $this->getMock('\\OAuth\\Common\\Consumer\\CredentialsInterface'),
+ $client,
+ $this->getMock('\\OAuth\\Common\\Storage\\TokenStorageInterface'),
+ $this->getMock('\\OAuth\\OAuth1\\Signature\\SignatureInterface')
+ );
+
+ $this->setExpectedException('\\OAuth\\Common\\Http\\Exception\\TokenResponseException');
+
+ $service->requestRequestToken();
+ }
+
+ /**
+ * @covers OAuth\OAuth1\Service\Yahoo::__construct
+ * @covers OAuth\OAuth1\Service\Yahoo::getRequestTokenEndpoint
+ * @covers OAuth\OAuth1\Service\Yahoo::parseRequestTokenResponse
+ */
+ public function testParseRequestTokenResponseThrowsExceptionOnResponseNotAnArray()
+ {
+ $client = $this->getMock('\\OAuth\\Common\\Http\\Client\\ClientInterface');
+ $client->expects($this->once())->method('retrieveResponse')->will($this->returnValue('notanarray'));
+
+ $service = new Yahoo(
+ $this->getMock('\\OAuth\\Common\\Consumer\\CredentialsInterface'),
+ $client,
+ $this->getMock('\\OAuth\\Common\\Storage\\TokenStorageInterface'),
+ $this->getMock('\\OAuth\\OAuth1\\Signature\\SignatureInterface')
+ );
+
+ $this->setExpectedException('\\OAuth\\Common\\Http\\Exception\\TokenResponseException');
+
+ $service->requestRequestToken();
+ }
+
+ /**
+ * @covers OAuth\OAuth1\Service\Yahoo::__construct
+ * @covers OAuth\OAuth1\Service\Yahoo::getRequestTokenEndpoint
+ * @covers OAuth\OAuth1\Service\Yahoo::parseRequestTokenResponse
+ */
+ public function testParseRequestTokenResponseThrowsExceptionOnResponseCallbackNotSet()
+ {
+ $client = $this->getMock('\\OAuth\\Common\\Http\\Client\\ClientInterface');
+ $client->expects($this->once())->method('retrieveResponse')->will($this->returnValue('foo=bar'));
+
+ $service = new Yahoo(
+ $this->getMock('\\OAuth\\Common\\Consumer\\CredentialsInterface'),
+ $client,
+ $this->getMock('\\OAuth\\Common\\Storage\\TokenStorageInterface'),
+ $this->getMock('\\OAuth\\OAuth1\\Signature\\SignatureInterface')
+ );
+
+ $this->setExpectedException('\\OAuth\\Common\\Http\\Exception\\TokenResponseException');
+
+ $service->requestRequestToken();
+ }
+
+ /**
+ * @covers OAuth\OAuth1\Service\Yahoo::__construct
+ * @covers OAuth\OAuth1\Service\Yahoo::getRequestTokenEndpoint
+ * @covers OAuth\OAuth1\Service\Yahoo::parseRequestTokenResponse
+ */
+ public function testParseRequestTokenResponseThrowsExceptionOnResponseCallbackNotTrue()
+ {
+ $client = $this->getMock('\\OAuth\\Common\\Http\\Client\\ClientInterface');
+ $client->expects($this->once())->method('retrieveResponse')->will($this->returnValue(
+ 'oauth_callback_confirmed=false'
+ ));
+
+ $service = new Yahoo(
+ $this->getMock('\\OAuth\\Common\\Consumer\\CredentialsInterface'),
+ $client,
+ $this->getMock('\\OAuth\\Common\\Storage\\TokenStorageInterface'),
+ $this->getMock('\\OAuth\\OAuth1\\Signature\\SignatureInterface')
+ );
+
+ $this->setExpectedException('\\OAuth\\Common\\Http\\Exception\\TokenResponseException');
+
+ $service->requestRequestToken();
+ }
+
+ /**
+ * @covers OAuth\OAuth1\Service\Yahoo::__construct
+ * @covers OAuth\OAuth1\Service\Yahoo::getRequestTokenEndpoint
+ * @covers OAuth\OAuth1\Service\Yahoo::parseRequestTokenResponse
+ * @covers OAuth\OAuth1\Service\Yahoo::parseAccessTokenResponse
+ */
+ public function testParseRequestTokenResponseValid()
+ {
+ $client = $this->getMock('\\OAuth\\Common\\Http\\Client\\ClientInterface');
+ $client->expects($this->once())->method('retrieveResponse')->will($this->returnValue(
+ 'oauth_callback_confirmed=true&oauth_token=foo&oauth_token_secret=bar'
+ ));
+
+ $service = new Yahoo(
+ $this->getMock('\\OAuth\\Common\\Consumer\\CredentialsInterface'),
+ $client,
+ $this->getMock('\\OAuth\\Common\\Storage\\TokenStorageInterface'),
+ $this->getMock('\\OAuth\\OAuth1\\Signature\\SignatureInterface')
+ );
+
+ $this->assertInstanceOf('\\OAuth\\OAuth1\\Token\\StdOAuth1Token', $service->requestRequestToken());
+ }
+
+ /**
+ * @covers OAuth\OAuth1\Service\Yahoo::__construct
+ * @covers OAuth\OAuth1\Service\Yahoo::getRequestTokenEndpoint
+ * @covers OAuth\OAuth1\Service\Yahoo::parseAccessTokenResponse
+ */
+ public function testParseAccessTokenResponseThrowsExceptionOnError()
+ {
+ $client = $this->getMock('\\OAuth\\Common\\Http\\Client\\ClientInterface');
+ $client->expects($this->once())->method('retrieveResponse')->will($this->returnValue('error=bar'));
+
+ $token = $this->getMock('\\OAuth\\OAuth1\\Token\\TokenInterface');
+
+ $storage = $this->getMock('\\OAuth\\Common\\Storage\\TokenStorageInterface');
+ $storage->expects($this->any())->method('retrieveAccessToken')->will($this->returnValue($token));
+
+ $service = new Yahoo(
+ $this->getMock('\\OAuth\\Common\\Consumer\\CredentialsInterface'),
+ $client,
+ $storage,
+ $this->getMock('\\OAuth\\OAuth1\\Signature\\SignatureInterface')
+ );
+
+ $this->setExpectedException('\\OAuth\\Common\\Http\\Exception\\TokenResponseException');
+
+ $service->requestAccessToken('foo', 'bar', $token);
+ }
+
+ /**
+ * @covers OAuth\OAuth1\Service\Yahoo::__construct
+ * @covers OAuth\OAuth1\Service\Yahoo::getRequestTokenEndpoint
+ * @covers OAuth\OAuth1\Service\Yahoo::parseAccessTokenResponse
+ */
+ public function testParseAccessTokenResponseValid()
+ {
+ $client = $this->getMock('\\OAuth\\Common\\Http\\Client\\ClientInterface');
+ $client->expects($this->once())->method('retrieveResponse')->will($this->returnValue(
+ 'oauth_token=foo&oauth_token_secret=bar'
+ ));
+
+ $token = $this->getMock('\\OAuth\\OAuth1\\Token\\TokenInterface');
+
+ $storage = $this->getMock('\\OAuth\\Common\\Storage\\TokenStorageInterface');
+ $storage->expects($this->any())->method('retrieveAccessToken')->will($this->returnValue($token));
+
+ $service = new Yahoo(
+ $this->getMock('\\OAuth\\Common\\Consumer\\CredentialsInterface'),
+ $client,
+ $storage,
+ $this->getMock('\\OAuth\\OAuth1\\Signature\\SignatureInterface')
+ );
+
+ $this->assertInstanceOf('\\OAuth\\OAuth1\\Token\\StdOAuth1Token', $service->requestAccessToken('foo', 'bar', $token));
+ }
+
+ /**
+ * @covers OAuth\OAuth1\Service\Yahoo::request
+ */
+ public function testRequest()
+ {
+ $client = $this->getMock('\\OAuth\\Common\\Http\\Client\\ClientInterface');
+ $client->expects($this->once())->method('retrieveResponse')->will($this->returnValue('response!'));
+
+ $token = $this->getMock('\\OAuth\\OAuth1\\Token\\TokenInterface');
+
+ $storage = $this->getMock('\\OAuth\\Common\\Storage\\TokenStorageInterface');
+ $storage->expects($this->any())->method('retrieveAccessToken')->will($this->returnValue($token));
+
+ $service = new Yahoo(
+ $this->getMock('\\OAuth\\Common\\Consumer\\CredentialsInterface'),
+ $client,
+ $storage,
+ $this->getMock('\\OAuth\\OAuth1\\Signature\\SignatureInterface'),
+ $this->getMock('\\OAuth\\Common\\Http\\Uri\\UriInterface')
+ );
+
+ $this->assertSame('response!', $service->request('/my/awesome/path'));
+ }
+}
diff --git a/vendor/lusitanian/oauth/tests/Unit/OAuth1/Signature/SignatureTest.php b/vendor/lusitanian/oauth/tests/Unit/OAuth1/Signature/SignatureTest.php
new file mode 100644
index 00000000..44c731f5
--- /dev/null
+++ b/vendor/lusitanian/oauth/tests/Unit/OAuth1/Signature/SignatureTest.php
@@ -0,0 +1,325 @@
+getMock('\\OAuth\\Common\\Consumer\\CredentialsInterface'));
+
+ $this->assertInstanceOf('\\OAuth\\OAuth1\\Signature\\SignatureInterface', $signature);
+ }
+
+ /**
+ * @covers OAuth\OAuth1\Signature\Signature::__construct
+ * @covers OAuth\OAuth1\Signature\Signature::setHashingAlgorithm
+ */
+ public function testSetHashingAlgorithm()
+ {
+ $signature = new Signature($this->getMock('\\OAuth\\Common\\Consumer\\CredentialsInterface'));
+
+ $this->assertNull($signature->setHashingAlgorithm('foo'));
+ }
+
+ /**
+ * @covers OAuth\OAuth1\Signature\Signature::__construct
+ * @covers OAuth\OAuth1\Signature\Signature::setTokenSecret
+ */
+ public function testSetTokenSecret()
+ {
+ $signature = new Signature($this->getMock('\\OAuth\\Common\\Consumer\\CredentialsInterface'));
+
+ $this->assertNull($signature->setTokenSecret('foo'));
+ }
+
+ /**
+ * @covers OAuth\OAuth1\Signature\Signature::__construct
+ * @covers OAuth\OAuth1\Signature\Signature::setHashingAlgorithm
+ * @covers OAuth\OAuth1\Signature\Signature::setTokenSecret
+ * @covers OAuth\OAuth1\Signature\Signature::getSignature
+ * @covers OAuth\OAuth1\Signature\Signature::buildSignatureDataString
+ * @covers OAuth\OAuth1\Signature\Signature::hash
+ * @covers OAuth\OAuth1\Signature\Signature::getSigningKey
+ */
+ public function testGetSignatureBareUri()
+ {
+ $credentials = $this->getMock('\\OAuth\\Common\\Consumer\\CredentialsInterface');
+ $credentials->expects($this->any())
+ ->method('getConsumerSecret')
+ ->will($this->returnValue('foo'));
+
+
+ $signature = new Signature($credentials);
+
+ $signature->setHashingAlgorithm('HMAC-SHA1');
+ $signature->setTokenSecret('foo');
+
+ $uri = $this->getMock('\\OAuth\\Common\\Http\\Uri\\UriInterface');
+ $uri->expects($this->any())
+ ->method('getQuery')
+ ->will($this->returnValue(''));
+ $uri->expects($this->any())
+ ->method('getScheme')
+ ->will($this->returnValue('http'));
+ $uri->expects($this->any())
+ ->method('getRawAuthority')
+ ->will($this->returnValue(''));
+ $uri->expects($this->any())
+ ->method('getPath')
+ ->will($this->returnValue('/foo'));
+
+ $this->assertSame('uoCpiII/Lg/cPiF0XrU2pj4eGFQ=', $signature->getSignature($uri, array('pee' => 'haa')));
+ }
+
+ /**
+ * @covers OAuth\OAuth1\Signature\Signature::__construct
+ * @covers OAuth\OAuth1\Signature\Signature::setHashingAlgorithm
+ * @covers OAuth\OAuth1\Signature\Signature::setTokenSecret
+ * @covers OAuth\OAuth1\Signature\Signature::getSignature
+ * @covers OAuth\OAuth1\Signature\Signature::buildSignatureDataString
+ * @covers OAuth\OAuth1\Signature\Signature::hash
+ * @covers OAuth\OAuth1\Signature\Signature::getSigningKey
+ */
+ public function testGetSignatureWithQueryString()
+ {
+ $credentials = $this->getMock('\\OAuth\\Common\\Consumer\\CredentialsInterface');
+ $credentials->expects($this->any())
+ ->method('getConsumerSecret')
+ ->will($this->returnValue('foo'));
+
+
+ $signature = new Signature($credentials);
+
+ $signature->setHashingAlgorithm('HMAC-SHA1');
+ $signature->setTokenSecret('foo');
+
+ $uri = $this->getMock('\\OAuth\\Common\\Http\\Uri\\UriInterface');
+ $uri->expects($this->any())
+ ->method('getQuery')
+ ->will($this->returnValue('param1=value1'));
+ $uri->expects($this->any())
+ ->method('getScheme')
+ ->will($this->returnValue('http'));
+ $uri->expects($this->any())
+ ->method('getRawAuthority')
+ ->will($this->returnValue(''));
+ $uri->expects($this->any())
+ ->method('getPath')
+ ->will($this->returnValue('/foo'));
+
+ $this->assertSame('LxtD+WjJBRppIUvEI79iQ7I0hSo=', $signature->getSignature($uri, array('pee' => 'haa')));
+ }
+
+ /**
+ * @covers OAuth\OAuth1\Signature\Signature::__construct
+ * @covers OAuth\OAuth1\Signature\Signature::setHashingAlgorithm
+ * @covers OAuth\OAuth1\Signature\Signature::setTokenSecret
+ * @covers OAuth\OAuth1\Signature\Signature::getSignature
+ * @covers OAuth\OAuth1\Signature\Signature::buildSignatureDataString
+ * @covers OAuth\OAuth1\Signature\Signature::hash
+ * @covers OAuth\OAuth1\Signature\Signature::getSigningKey
+ */
+ public function testGetSignatureWithAuthority()
+ {
+ $credentials = $this->getMock('\\OAuth\\Common\\Consumer\\CredentialsInterface');
+ $credentials->expects($this->any())
+ ->method('getConsumerSecret')
+ ->will($this->returnValue('foo'));
+
+
+ $signature = new Signature($credentials);
+
+ $signature->setHashingAlgorithm('HMAC-SHA1');
+ $signature->setTokenSecret('foo');
+
+ $uri = $this->getMock('\\OAuth\\Common\\Http\\Uri\\UriInterface');
+ $uri->expects($this->any())
+ ->method('getQuery')
+ ->will($this->returnValue('param1=value1'));
+ $uri->expects($this->any())
+ ->method('getScheme')
+ ->will($this->returnValue('http'));
+ $uri->expects($this->any())
+ ->method('getRawAuthority')
+ ->will($this->returnValue('peehaa:pass'));
+ $uri->expects($this->any())
+ ->method('getPath')
+ ->will($this->returnValue('/foo'));
+
+ $this->assertSame('MHvkRndIntLrxiPkjkiCNsMEqv4=', $signature->getSignature($uri, array('pee' => 'haa')));
+ }
+
+ /**
+ * @covers OAuth\OAuth1\Signature\Signature::__construct
+ * @covers OAuth\OAuth1\Signature\Signature::setHashingAlgorithm
+ * @covers OAuth\OAuth1\Signature\Signature::setTokenSecret
+ * @covers OAuth\OAuth1\Signature\Signature::getSignature
+ * @covers OAuth\OAuth1\Signature\Signature::buildSignatureDataString
+ * @covers OAuth\OAuth1\Signature\Signature::hash
+ * @covers OAuth\OAuth1\Signature\Signature::getSigningKey
+ */
+ public function testGetSignatureWithBarePathNonExplicitTrailingHostSlash()
+ {
+ $credentials = $this->getMock('\\OAuth\\Common\\Consumer\\CredentialsInterface');
+ $credentials->expects($this->any())
+ ->method('getConsumerSecret')
+ ->will($this->returnValue('foo'));
+
+
+ $signature = new Signature($credentials);
+
+ $signature->setHashingAlgorithm('HMAC-SHA1');
+ $signature->setTokenSecret('foo');
+
+ $uri = $this->getMock('\\OAuth\\Common\\Http\\Uri\\UriInterface');
+ $uri->expects($this->any())
+ ->method('getQuery')
+ ->will($this->returnValue('param1=value1'));
+ $uri->expects($this->any())
+ ->method('getScheme')
+ ->will($this->returnValue('http'));
+ $uri->expects($this->any())
+ ->method('getRawAuthority')
+ ->will($this->returnValue('peehaa:pass'));
+ $uri->expects($this->any())
+ ->method('getPath')
+ ->will($this->returnValue('/'));
+ $uri->expects($this->any())
+ ->method('hasExplicitTrailingHostSlash')
+ ->will($this->returnValue(false));
+
+ $this->assertSame('iFELDoiI5Oj9ixB3kHzoPvBpq0w=', $signature->getSignature($uri, array('pee' => 'haa')));
+ }
+
+ /**
+ * @covers OAuth\OAuth1\Signature\Signature::__construct
+ * @covers OAuth\OAuth1\Signature\Signature::setHashingAlgorithm
+ * @covers OAuth\OAuth1\Signature\Signature::setTokenSecret
+ * @covers OAuth\OAuth1\Signature\Signature::getSignature
+ * @covers OAuth\OAuth1\Signature\Signature::buildSignatureDataString
+ * @covers OAuth\OAuth1\Signature\Signature::hash
+ * @covers OAuth\OAuth1\Signature\Signature::getSigningKey
+ */
+ public function testGetSignatureWithBarePathWithExplicitTrailingHostSlash()
+ {
+ $credentials = $this->getMock('\\OAuth\\Common\\Consumer\\CredentialsInterface');
+ $credentials->expects($this->any())
+ ->method('getConsumerSecret')
+ ->will($this->returnValue('foo'));
+
+
+ $signature = new Signature($credentials);
+
+ $signature->setHashingAlgorithm('HMAC-SHA1');
+ $signature->setTokenSecret('foo');
+
+ $uri = $this->getMock('\\OAuth\\Common\\Http\\Uri\\UriInterface');
+ $uri->expects($this->any())
+ ->method('getQuery')
+ ->will($this->returnValue('param1=value1'));
+ $uri->expects($this->any())
+ ->method('getScheme')
+ ->will($this->returnValue('http'));
+ $uri->expects($this->any())
+ ->method('getRawAuthority')
+ ->will($this->returnValue('peehaa:pass'));
+ $uri->expects($this->any())
+ ->method('getPath')
+ ->will($this->returnValue('/'));
+ $uri->expects($this->any())
+ ->method('hasExplicitTrailingHostSlash')
+ ->will($this->returnValue(true));
+
+ $this->assertSame('IEhUsArSTLvbQ3QYr0zzn+Rxpjg=', $signature->getSignature($uri, array('pee' => 'haa')));
+ }
+
+ /**
+ * @covers OAuth\OAuth1\Signature\Signature::__construct
+ * @covers OAuth\OAuth1\Signature\Signature::setHashingAlgorithm
+ * @covers OAuth\OAuth1\Signature\Signature::setTokenSecret
+ * @covers OAuth\OAuth1\Signature\Signature::getSignature
+ * @covers OAuth\OAuth1\Signature\Signature::buildSignatureDataString
+ * @covers OAuth\OAuth1\Signature\Signature::hash
+ * @covers OAuth\OAuth1\Signature\Signature::getSigningKey
+ */
+ public function testGetSignatureNoTokenSecretSet()
+ {
+ $credentials = $this->getMock('\\OAuth\\Common\\Consumer\\CredentialsInterface');
+ $credentials->expects($this->any())
+ ->method('getConsumerSecret')
+ ->will($this->returnValue('foo'));
+
+
+ $signature = new Signature($credentials);
+
+ $signature->setHashingAlgorithm('HMAC-SHA1');
+
+ $uri = $this->getMock('\\OAuth\\Common\\Http\\Uri\\UriInterface');
+ $uri->expects($this->any())
+ ->method('getQuery')
+ ->will($this->returnValue('param1=value1'));
+ $uri->expects($this->any())
+ ->method('getScheme')
+ ->will($this->returnValue('http'));
+ $uri->expects($this->any())
+ ->method('getRawAuthority')
+ ->will($this->returnValue('peehaa:pass'));
+ $uri->expects($this->any())
+ ->method('getPath')
+ ->will($this->returnValue('/'));
+ $uri->expects($this->any())
+ ->method('hasExplicitTrailingHostSlash')
+ ->will($this->returnValue(true));
+
+ $this->assertSame('YMHF7FYmLq7wzGnnHWYtd1VoBBE=', $signature->getSignature($uri, array('pee' => 'haa')));
+ }
+
+ /**
+ * @covers OAuth\OAuth1\Signature\Signature::__construct
+ * @covers OAuth\OAuth1\Signature\Signature::setHashingAlgorithm
+ * @covers OAuth\OAuth1\Signature\Signature::setTokenSecret
+ * @covers OAuth\OAuth1\Signature\Signature::getSignature
+ * @covers OAuth\OAuth1\Signature\Signature::buildSignatureDataString
+ * @covers OAuth\OAuth1\Signature\Signature::hash
+ * @covers OAuth\OAuth1\Signature\Signature::getSigningKey
+ */
+ public function testGetSignatureThrowsExceptionOnUnsupportedAlgo()
+ {
+ $this->setExpectedException('\\OAuth\\OAuth1\\Signature\\Exception\\UnsupportedHashAlgorithmException');
+
+ $credentials = $this->getMock('\\OAuth\\Common\\Consumer\\CredentialsInterface');
+ $credentials->expects($this->any())
+ ->method('getConsumerSecret')
+ ->will($this->returnValue('foo'));
+
+
+ $signature = new Signature($credentials);
+
+ $signature->setHashingAlgorithm('UnsupportedAlgo');
+
+ $uri = $this->getMock('\\OAuth\\Common\\Http\\Uri\\UriInterface');
+ $uri->expects($this->any())
+ ->method('getQuery')
+ ->will($this->returnValue('param1=value1'));
+ $uri->expects($this->any())
+ ->method('getScheme')
+ ->will($this->returnValue('http'));
+ $uri->expects($this->any())
+ ->method('getRawAuthority')
+ ->will($this->returnValue('peehaa:pass'));
+ $uri->expects($this->any())
+ ->method('getPath')
+ ->will($this->returnValue('/'));
+ $uri->expects($this->any())
+ ->method('hasExplicitTrailingHostSlash')
+ ->will($this->returnValue(true));
+
+ $signature->getSignature($uri, array('pee' => 'haa'));
+ }
+}
diff --git a/vendor/lusitanian/oauth/tests/Unit/OAuth1/Token/StdOAuth1TokenTest.php b/vendor/lusitanian/oauth/tests/Unit/OAuth1/Token/StdOAuth1TokenTest.php
new file mode 100644
index 00000000..9b065b1e
--- /dev/null
+++ b/vendor/lusitanian/oauth/tests/Unit/OAuth1/Token/StdOAuth1TokenTest.php
@@ -0,0 +1,85 @@
+assertInstanceOf('\\OAuth\\OAuth1\\Token\\TokenInterface', $token);
+ $this->assertInstanceOf('\\OAuth\\Common\\Token\\AbstractToken', $token);
+ }
+
+ /**
+ * @covers OAuth\OAuth1\Token\StdOAuth1Token::setRequestToken
+ */
+ public function testSetRequestToken()
+ {
+ $token = new StdOAuth1Token();
+
+ $this->assertNull($token->setRequestToken('foo'));
+ }
+
+ /**
+ * @covers OAuth\OAuth1\Token\StdOAuth1Token::setRequestToken
+ * @covers OAuth\OAuth1\Token\StdOAuth1Token::getRequestToken
+ */
+ public function testGetRequestToken()
+ {
+ $token = new StdOAuth1Token();
+
+ $this->assertNull($token->setRequestToken('foo'));
+ $this->assertSame('foo', $token->getRequestToken());
+ }
+
+ /**
+ * @covers OAuth\OAuth1\Token\StdOAuth1Token::setRequestTokenSecret
+ */
+ public function testSetRequestTokenSecret()
+ {
+ $token = new StdOAuth1Token();
+
+ $this->assertNull($token->setRequestTokenSecret('foo'));
+ }
+
+ /**
+ * @covers OAuth\OAuth1\Token\StdOAuth1Token::setRequestTokenSecret
+ * @covers OAuth\OAuth1\Token\StdOAuth1Token::getRequestTokenSecret
+ */
+ public function testGetRequestTokenSecret()
+ {
+ $token = new StdOAuth1Token();
+
+ $this->assertNull($token->setRequestTokenSecret('foo'));
+ $this->assertSame('foo', $token->getRequestTokenSecret());
+ }
+
+ /**
+ * @covers OAuth\OAuth1\Token\StdOAuth1Token::setAccessTokenSecret
+ */
+ public function testSetAccessTokenSecret()
+ {
+ $token = new StdOAuth1Token();
+
+ $this->assertNull($token->setAccessTokenSecret('foo'));
+ }
+
+ /**
+ * @covers OAuth\OAuth1\Token\StdOAuth1Token::setAccessTokenSecret
+ * @covers OAuth\OAuth1\Token\StdOAuth1Token::getAccessTokenSecret
+ */
+ public function testGetAccessTokenSecret()
+ {
+ $token = new StdOAuth1Token();
+
+ $this->assertNull($token->setAccessTokenSecret('foo'));
+ $this->assertSame('foo', $token->getAccessTokenSecret());
+ }
+}
diff --git a/vendor/lusitanian/oauth/tests/Unit/OAuth2/Service/AbstractServiceTest.php b/vendor/lusitanian/oauth/tests/Unit/OAuth2/Service/AbstractServiceTest.php
new file mode 100644
index 00000000..595db2a3
--- /dev/null
+++ b/vendor/lusitanian/oauth/tests/Unit/OAuth2/Service/AbstractServiceTest.php
@@ -0,0 +1,401 @@
+getMockForAbstractClass(
+ '\\OAuth\\OAuth2\\Service\\AbstractService',
+ array(
+ $this->getMock('\\OAuth\\Common\\Consumer\\CredentialsInterface'),
+ $this->getMock('\\OAuth\\Common\\Http\\Client\\ClientInterface'),
+ $this->getMock('\\OAuth\\Common\\Storage\\TokenStorageInterface'),
+ array(),
+ )
+ );
+
+ $this->assertInstanceOf('\\OAuth\\OAuth2\\Service\\ServiceInterface', $service);
+ }
+
+ /**
+ * @covers OAuth\OAuth2\Service\AbstractService::__construct
+ */
+ public function testConstructCorrectParent()
+ {
+ $service = $this->getMockForAbstractClass(
+ '\\OAuth\\OAuth2\\Service\\AbstractService',
+ array(
+ $this->getMock('\\OAuth\\Common\\Consumer\\CredentialsInterface'),
+ $this->getMock('\\OAuth\\Common\\Http\\Client\\ClientInterface'),
+ $this->getMock('\\OAuth\\Common\\Storage\\TokenStorageInterface'),
+ array(),
+ )
+ );
+
+ $this->assertInstanceOf('\\OAuth\\Common\\Service\\AbstractService', $service);
+ }
+
+ /**
+ * @covers OAuth\OAuth2\Service\AbstractService::__construct
+ */
+ public function testConstructCorrectParentCustomUri()
+ {
+ $service = $this->getMockForAbstractClass(
+ '\\OAuth\\OAuth2\\Service\\AbstractService',
+ array(
+ $this->getMock('\\OAuth\\Common\\Consumer\\CredentialsInterface'),
+ $this->getMock('\\OAuth\\Common\\Http\\Client\\ClientInterface'),
+ $this->getMock('\\OAuth\\Common\\Storage\\TokenStorageInterface'),
+ array(),
+ $this->getMock('\\OAuth\\Common\\Http\\Uri\\UriInterface'),
+ )
+ );
+
+ $this->assertInstanceOf('\\OAuth\\Common\\Service\\AbstractService', $service);
+ }
+
+ /**
+ * @covers OAuth\OAuth2\Service\AbstractService::__construct
+ * @covers OAuth\OAuth2\Service\AbstractService::isValidScope
+ */
+ public function testConstructThrowsExceptionOnInvalidScope()
+ {
+ $this->setExpectedException('\\OAuth\\OAuth2\\Service\\Exception\\InvalidScopeException');
+
+ $service = new Mock(
+ $this->getMock('\\OAuth\\Common\\Consumer\\CredentialsInterface'),
+ $this->getMock('\\OAuth\\Common\\Http\\Client\\ClientInterface'),
+ $this->getMock('\\OAuth\\Common\\Storage\\TokenStorageInterface'),
+ array('invalidscope')
+ );
+ }
+
+ /**
+ * @covers OAuth\OAuth2\Service\AbstractService::__construct
+ * @covers OAuth\OAuth2\Service\AbstractService::getAuthorizationUri
+ * @covers OAuth\OAuth2\Service\AbstractService::getAuthorizationEndpoint
+ */
+ public function testGetAuthorizationUriWithoutParametersOrScopes()
+ {
+ $credentials = $this->getMock('\\OAuth\\Common\\Consumer\\CredentialsInterface');
+ $credentials->expects($this->once())->method('getConsumerId')->will($this->returnValue('foo'));
+ $credentials->expects($this->once())->method('getCallbackUrl')->will($this->returnValue('bar'));
+
+ $service = new Mock(
+ $credentials,
+ $this->getMock('\\OAuth\\Common\\Http\\Client\\ClientInterface'),
+ $this->getMock('\\OAuth\\Common\\Storage\\TokenStorageInterface')
+ );
+
+ $this->assertSame(
+ 'http://pieterhordijk.com/auth?type=web_server&client_id=foo&redirect_uri=bar&response_type=code&scope=',
+ $service->getAuthorizationUri()->getAbsoluteUri()
+ );
+ }
+
+ /**
+ * @covers OAuth\OAuth2\Service\AbstractService::__construct
+ * @covers OAuth\OAuth2\Service\AbstractService::getAuthorizationUri
+ * @covers OAuth\OAuth2\Service\AbstractService::getAuthorizationEndpoint
+ */
+ public function testGetAuthorizationUriWithParametersWithoutScopes()
+ {
+ $credentials = $this->getMock('\\OAuth\\Common\\Consumer\\CredentialsInterface');
+ $credentials->expects($this->once())->method('getConsumerId')->will($this->returnValue('foo'));
+ $credentials->expects($this->once())->method('getCallbackUrl')->will($this->returnValue('bar'));
+
+ $service = new Mock(
+ $credentials,
+ $this->getMock('\\OAuth\\Common\\Http\\Client\\ClientInterface'),
+ $this->getMock('\\OAuth\\Common\\Storage\\TokenStorageInterface')
+ );
+
+ $this->assertSame(
+ 'http://pieterhordijk.com/auth?foo=bar&baz=beer&type=web_server&client_id=foo&redirect_uri=bar&response_type=code&scope=',
+ $service->getAuthorizationUri(array('foo' => 'bar', 'baz' => 'beer'))->getAbsoluteUri()
+ );
+ }
+
+ /**
+ * @covers OAuth\OAuth2\Service\AbstractService::__construct
+ * @covers OAuth\OAuth2\Service\AbstractService::isValidScope
+ * @covers OAuth\OAuth2\Service\AbstractService::getAuthorizationUri
+ * @covers OAuth\OAuth2\Service\AbstractService::getAuthorizationEndpoint
+ */
+ public function testGetAuthorizationUriWithParametersAndScopes()
+ {
+ $credentials = $this->getMock('\\OAuth\\Common\\Consumer\\CredentialsInterface');
+ $credentials->expects($this->once())->method('getConsumerId')->will($this->returnValue('foo'));
+ $credentials->expects($this->once())->method('getCallbackUrl')->will($this->returnValue('bar'));
+
+ $service = new Mock(
+ $credentials,
+ $this->getMock('\\OAuth\\Common\\Http\\Client\\ClientInterface'),
+ $this->getMock('\\OAuth\\Common\\Storage\\TokenStorageInterface'),
+ array('mock', 'mock2')
+ );
+
+ $this->assertSame(
+ 'http://pieterhordijk.com/auth?foo=bar&baz=beer&type=web_server&client_id=foo&redirect_uri=bar&response_type=code&scope=mock+mock2',
+ $service->getAuthorizationUri(array('foo' => 'bar', 'baz' => 'beer'))->getAbsoluteUri()
+ );
+ }
+
+ /**
+ * @covers OAuth\OAuth2\Service\AbstractService::__construct
+ * @covers OAuth\OAuth2\Service\AbstractService::requestAccessToken
+ * @covers OAuth\OAuth2\Service\AbstractService::getAccessTokenEndpoint
+ * @covers OAuth\OAuth2\Service\AbstractService::getExtraOAuthHeaders
+ * @covers OAuth\OAuth2\Service\AbstractService::parseAccessTokenResponse
+ * @covers OAuth\OAuth2\Service\AbstractService::service
+ */
+ public function testRequestAccessToken()
+ {
+ $service = new Mock(
+ $this->getMock('\\OAuth\\Common\\Consumer\\CredentialsInterface'),
+ $this->getMock('\\OAuth\\Common\\Http\\Client\\ClientInterface'),
+ $this->getMock('\\OAuth\\Common\\Storage\\TokenStorageInterface')
+ );
+
+ $this->assertInstanceof('\\OAuth\\OAuth2\\Token\\StdOAuth2Token', $service->requestAccessToken('code'));
+ }
+
+ /**
+ * @covers OAuth\OAuth2\Service\AbstractService::__construct
+ * @covers OAuth\OAuth2\Service\AbstractService::request
+ * @covers OAuth\OAuth2\Service\AbstractService::determineRequestUriFromPath
+ */
+ public function testRequestThrowsExceptionWhenTokenIsExpired()
+ {
+ $tokenExpiration = new \DateTime('26-03-1984 00:00:00');
+
+ $token = $this->getMock('\\OAuth\\OAuth2\\Token\\TokenInterface');
+ $token->expects($this->any())->method('getEndOfLife')->will($this->returnValue($tokenExpiration->format('U')));
+
+ $storage = $this->getMock('\\OAuth\\Common\\Storage\\TokenStorageInterface');
+ $storage->expects($this->once())->method('retrieveAccessToken')->will($this->returnValue($token));
+
+ $service = new Mock(
+ $this->getMock('\\OAuth\\Common\\Consumer\\CredentialsInterface'),
+ $this->getMock('\\OAuth\\Common\\Http\\Client\\ClientInterface'),
+ $storage
+ );
+
+ $this->setExpectedException('\\OAuth\\Common\\Token\\Exception\\ExpiredTokenException', 'Token expired on 03/26/1984 at 12:00:00 AM');
+
+ $service->request('https://pieterhordijk.com/my/awesome/path');
+ }
+
+ /**
+ * @covers OAuth\OAuth2\Service\AbstractService::__construct
+ * @covers OAuth\OAuth2\Service\AbstractService::request
+ * @covers OAuth\OAuth2\Service\AbstractService::determineRequestUriFromPath
+ * @covers OAuth\OAuth2\Service\AbstractService::getAuthorizationMethod
+ * @covers OAuth\OAuth2\Service\AbstractService::parseAccessTokenResponse
+ * @covers OAuth\OAuth2\Service\AbstractService::service
+ * @covers OAuth\OAuth2\Service\AbstractService::getExtraApiHeaders
+ */
+ public function testRequestOauthAuthorizationMethod()
+ {
+ $client = $this->getMock('\\OAuth\\Common\\Http\\Client\\ClientInterface');
+ $client->expects($this->once())->method('retrieveResponse')->will($this->returnArgument(2));
+
+ $token = $this->getMock('\\OAuth\\OAuth2\\Token\\TokenInterface');
+ $token->expects($this->once())->method('getEndOfLife')->will($this->returnValue(TokenInterface::EOL_NEVER_EXPIRES));
+ $token->expects($this->once())->method('getAccessToken')->will($this->returnValue('foo'));
+
+ $storage = $this->getMock('\\OAuth\\Common\\Storage\\TokenStorageInterface');
+ $storage->expects($this->once())->method('retrieveAccessToken')->will($this->returnValue($token));
+
+ $service = new Mock(
+ $this->getMock('\\OAuth\\Common\\Consumer\\CredentialsInterface'),
+ $client,
+ $storage
+ );
+
+ $headers = $service->request('https://pieterhordijk.com/my/awesome/path');
+
+ $this->assertTrue(array_key_exists('Authorization', $headers));
+ $this->assertTrue(in_array('OAuth foo', $headers, true));
+ }
+
+ /**
+ * @covers OAuth\OAuth2\Service\AbstractService::__construct
+ * @covers OAuth\OAuth2\Service\AbstractService::request
+ * @covers OAuth\OAuth2\Service\AbstractService::determineRequestUriFromPath
+ * @covers OAuth\OAuth2\Service\AbstractService::getAuthorizationMethod
+ * @covers OAuth\OAuth2\Service\AbstractService::parseAccessTokenResponse
+ * @covers OAuth\OAuth2\Service\AbstractService::service
+ * @covers OAuth\OAuth2\Service\AbstractService::getExtraApiHeaders
+ */
+ public function testRequestQueryStringMethod()
+ {
+ $client = $this->getMock('\\OAuth\\Common\\Http\\Client\\ClientInterface');
+ $client->expects($this->once())->method('retrieveResponse')->will($this->returnArgument(0));
+
+ $token = $this->getMock('\\OAuth\\OAuth2\\Token\\TokenInterface');
+ $token->expects($this->once())->method('getEndOfLife')->will($this->returnValue(TokenInterface::EOL_NEVER_EXPIRES));
+ $token->expects($this->once())->method('getAccessToken')->will($this->returnValue('foo'));
+
+ $storage = $this->getMock('\\OAuth\\Common\\Storage\\TokenStorageInterface');
+ $storage->expects($this->once())->method('retrieveAccessToken')->will($this->returnValue($token));
+
+ $service = new Mock(
+ $this->getMock('\\OAuth\\Common\\Consumer\\CredentialsInterface'),
+ $client,
+ $storage
+ );
+
+ $service->setAuthorizationMethod('querystring');
+
+ $uri = $service->request('https://pieterhordijk.com/my/awesome/path');
+ $absoluteUri = parse_url($uri->getAbsoluteUri());
+
+ $this->assertSame('access_token=foo', $absoluteUri['query']);
+ }
+
+ /**
+ * @covers OAuth\OAuth2\Service\AbstractService::__construct
+ * @covers OAuth\OAuth2\Service\AbstractService::request
+ * @covers OAuth\OAuth2\Service\AbstractService::determineRequestUriFromPath
+ * @covers OAuth\OAuth2\Service\AbstractService::getAuthorizationMethod
+ * @covers OAuth\OAuth2\Service\AbstractService::parseAccessTokenResponse
+ * @covers OAuth\OAuth2\Service\AbstractService::service
+ * @covers OAuth\OAuth2\Service\AbstractService::getExtraApiHeaders
+ */
+ public function testRequestQueryStringTwoMethod()
+ {
+ $client = $this->getMock('\\OAuth\\Common\\Http\\Client\\ClientInterface');
+ $client->expects($this->once())->method('retrieveResponse')->will($this->returnArgument(0));
+
+ $token = $this->getMock('\\OAuth\\OAuth2\\Token\\TokenInterface');
+ $token->expects($this->once())->method('getEndOfLife')->will($this->returnValue(TokenInterface::EOL_NEVER_EXPIRES));
+ $token->expects($this->once())->method('getAccessToken')->will($this->returnValue('foo'));
+
+ $storage = $this->getMock('\\OAuth\\Common\\Storage\\TokenStorageInterface');
+ $storage->expects($this->once())->method('retrieveAccessToken')->will($this->returnValue($token));
+
+ $service = new Mock(
+ $this->getMock('\\OAuth\\Common\\Consumer\\CredentialsInterface'),
+ $client,
+ $storage
+ );
+
+ $service->setAuthorizationMethod('querystring2');
+
+ $uri = $service->request('https://pieterhordijk.com/my/awesome/path');
+ $absoluteUri = parse_url($uri->getAbsoluteUri());
+
+ $this->assertSame('oauth2_access_token=foo', $absoluteUri['query']);
+ }
+
+ /**
+ * @covers OAuth\OAuth2\Service\AbstractService::__construct
+ * @covers OAuth\OAuth2\Service\AbstractService::request
+ * @covers OAuth\OAuth2\Service\AbstractService::determineRequestUriFromPath
+ * @covers OAuth\OAuth2\Service\AbstractService::getAuthorizationMethod
+ * @covers OAuth\OAuth2\Service\AbstractService::parseAccessTokenResponse
+ * @covers OAuth\OAuth2\Service\AbstractService::service
+ * @covers OAuth\OAuth2\Service\AbstractService::getExtraApiHeaders
+ */
+ public function testRequestBearerMethod()
+ {
+ $client = $this->getMock('\\OAuth\\Common\\Http\\Client\\ClientInterface');
+ $client->expects($this->once())->method('retrieveResponse')->will($this->returnArgument(2));
+
+ $token = $this->getMock('\\OAuth\\OAuth2\\Token\\TokenInterface');
+ $token->expects($this->once())->method('getEndOfLife')->will($this->returnValue(TokenInterface::EOL_NEVER_EXPIRES));
+ $token->expects($this->once())->method('getAccessToken')->will($this->returnValue('foo'));
+
+ $storage = $this->getMock('\\OAuth\\Common\\Storage\\TokenStorageInterface');
+ $storage->expects($this->once())->method('retrieveAccessToken')->will($this->returnValue($token));
+
+ $service = new Mock(
+ $this->getMock('\\OAuth\\Common\\Consumer\\CredentialsInterface'),
+ $client,
+ $storage
+ );
+
+ $service->setAuthorizationMethod('bearer');
+
+ $headers = $service->request('https://pieterhordijk.com/my/awesome/path');
+
+ $this->assertTrue(array_key_exists('Authorization', $headers));
+ $this->assertTrue(in_array('Bearer foo', $headers, true));
+ }
+
+ /**
+ * @covers OAuth\OAuth2\Service\AbstractService::__construct
+ * @covers OAuth\OAuth2\Service\AbstractService::getStorage
+ */
+ public function testGetStorage()
+ {
+ $service = new Mock(
+ $this->getMock('\\OAuth\\Common\\Consumer\\CredentialsInterface'),
+ $this->getMock('\\OAuth\\Common\\Http\\Client\\ClientInterface'),
+ $this->getMock('\\OAuth\\Common\\Storage\\TokenStorageInterface')
+ );
+
+ $this->assertInstanceOf('\\OAuth\\Common\\Storage\\TokenStorageInterface', $service->getStorage());
+ }
+
+ /**
+ * @covers OAuth\OAuth2\Service\AbstractService::__construct
+ * @covers OAuth\OAuth2\Service\AbstractService::refreshAccessToken
+ * @covers OAuth\OAuth2\Service\AbstractService::getAccessTokenEndpoint
+ * @covers OAuth\OAuth2\Service\AbstractService::getExtraOAuthHeaders
+ * @covers OAuth\OAuth2\Service\AbstractService::parseAccessTokenResponse
+ */
+ public function testRefreshAccessTokenSuccess()
+ {
+ $service = new Mock(
+ $this->getMock('\\OAuth\\Common\\Consumer\\CredentialsInterface'),
+ $this->getMock('\\OAuth\\Common\\Http\\Client\\ClientInterface'),
+ $this->getMock('\\OAuth\\Common\\Storage\\TokenStorageInterface')
+ );
+
+ $token = $this->getMock('\\OAuth\\OAuth2\\Token\\StdOAuth2Token');
+ $token->expects($this->once())->method('getRefreshToken')->will($this->returnValue('foo'));
+
+ $this->assertInstanceOf('\\OAuth\\OAuth2\\Token\\StdOAuth2Token', $service->refreshAccessToken($token));
+ }
+
+ /**
+ * @covers OAuth\OAuth2\Service\AbstractService::__construct
+ * @covers OAuth\OAuth2\Service\AbstractService::isValidScope
+ */
+ public function testIsValidScopeTrue()
+ {
+ $service = new Mock(
+ $this->getMock('\\OAuth\\Common\\Consumer\\CredentialsInterface'),
+ $this->getMock('\\OAuth\\Common\\Http\\Client\\ClientInterface'),
+ $this->getMock('\\OAuth\\Common\\Storage\\TokenStorageInterface')
+ );
+
+ $this->assertTrue($service->isValidScope('mock'));
+ }
+
+ /**
+ * @covers OAuth\OAuth2\Service\AbstractService::__construct
+ * @covers OAuth\OAuth2\Service\AbstractService::isValidScope
+ */
+ public function testIsValidScopeFalse()
+ {
+ $service = new Mock(
+ $this->getMock('\\OAuth\\Common\\Consumer\\CredentialsInterface'),
+ $this->getMock('\\OAuth\\Common\\Http\\Client\\ClientInterface'),
+ $this->getMock('\\OAuth\\Common\\Storage\\TokenStorageInterface')
+ );
+
+ $this->assertFalse($service->isValidScope('invalid'));
+ }
+}
diff --git a/vendor/lusitanian/oauth/tests/Unit/OAuth2/Service/AmazonTest.php b/vendor/lusitanian/oauth/tests/Unit/OAuth2/Service/AmazonTest.php
new file mode 100644
index 00000000..f70fe401
--- /dev/null
+++ b/vendor/lusitanian/oauth/tests/Unit/OAuth2/Service/AmazonTest.php
@@ -0,0 +1,207 @@
+getMock('\\OAuth\\Common\\Consumer\\CredentialsInterface'),
+ $this->getMock('\\OAuth\\Common\\Http\\Client\\ClientInterface'),
+ $this->getMock('\\OAuth\\Common\\Storage\\TokenStorageInterface')
+ );
+
+ $this->assertInstanceOf('\\OAuth\\OAuth2\\Service\\ServiceInterface', $service);
+ }
+
+ /**
+ * @covers OAuth\OAuth2\Service\Amazon::__construct
+ */
+ public function testConstructCorrectInstanceWithoutCustomUri()
+ {
+ $service = new Amazon(
+ $this->getMock('\\OAuth\\Common\\Consumer\\CredentialsInterface'),
+ $this->getMock('\\OAuth\\Common\\Http\\Client\\ClientInterface'),
+ $this->getMock('\\OAuth\\Common\\Storage\\TokenStorageInterface')
+ );
+
+ $this->assertInstanceOf('\\OAuth\\OAuth2\\Service\\AbstractService', $service);
+ }
+
+ /**
+ * @covers OAuth\OAuth2\Service\Amazon::__construct
+ */
+ public function testConstructCorrectInstanceWithCustomUri()
+ {
+ $service = new Amazon(
+ $this->getMock('\\OAuth\\Common\\Consumer\\CredentialsInterface'),
+ $this->getMock('\\OAuth\\Common\\Http\\Client\\ClientInterface'),
+ $this->getMock('\\OAuth\\Common\\Storage\\TokenStorageInterface'),
+ array(),
+ $this->getMock('\\OAuth\\Common\\Http\\Uri\\UriInterface')
+ );
+
+ $this->assertInstanceOf('\\OAuth\\OAuth2\\Service\\AbstractService', $service);
+ }
+
+ /**
+ * @covers OAuth\OAuth2\Service\Amazon::__construct
+ * @covers OAuth\OAuth2\Service\Amazon::getAuthorizationEndpoint
+ */
+ public function testGetAuthorizationEndpoint()
+ {
+ $service = new Amazon(
+ $this->getMock('\\OAuth\\Common\\Consumer\\CredentialsInterface'),
+ $this->getMock('\\OAuth\\Common\\Http\\Client\\ClientInterface'),
+ $this->getMock('\\OAuth\\Common\\Storage\\TokenStorageInterface')
+ );
+
+ $this->assertSame('https://www.amazon.com/ap/oa', $service->getAuthorizationEndpoint()->getAbsoluteUri());
+ }
+
+ /**
+ * @covers OAuth\OAuth2\Service\Amazon::__construct
+ * @covers OAuth\OAuth2\Service\Amazon::getAccessTokenEndpoint
+ */
+ public function testGetAccessTokenEndpoint()
+ {
+ $service = new Amazon(
+ $this->getMock('\\OAuth\\Common\\Consumer\\CredentialsInterface'),
+ $this->getMock('\\OAuth\\Common\\Http\\Client\\ClientInterface'),
+ $this->getMock('\\OAuth\\Common\\Storage\\TokenStorageInterface')
+ );
+
+ $this->assertSame('https://www.amazon.com/ap/oatoken', $service->getAccessTokenEndpoint()->getAbsoluteUri());
+ }
+
+ /**
+ * @covers OAuth\OAuth2\Service\Amazon::__construct
+ * @covers OAuth\OAuth2\Service\Amazon::getAuthorizationMethod
+ */
+ public function testGetAuthorizationMethod()
+ {
+ $client = $this->getMock('\\OAuth\\Common\\Http\\Client\\ClientInterface');
+ $client->expects($this->once())->method('retrieveResponse')->will($this->returnArgument(2));
+
+ $token = $this->getMock('\\OAuth\\OAuth2\\Token\\TokenInterface');
+ $token->expects($this->once())->method('getEndOfLife')->will($this->returnValue(TokenInterface::EOL_NEVER_EXPIRES));
+ $token->expects($this->once())->method('getAccessToken')->will($this->returnValue('foo'));
+
+ $storage = $this->getMock('\\OAuth\\Common\\Storage\\TokenStorageInterface');
+ $storage->expects($this->once())->method('retrieveAccessToken')->will($this->returnValue($token));
+
+ $service = new Amazon(
+ $this->getMock('\\OAuth\\Common\\Consumer\\CredentialsInterface'),
+ $client,
+ $storage
+ );
+
+ $headers = $service->request('https://pieterhordijk.com/my/awesome/path');
+
+ $this->assertTrue(array_key_exists('Authorization', $headers));
+ $this->assertTrue(in_array('Bearer foo', $headers, true));
+ }
+
+ /**
+ * @covers OAuth\OAuth2\Service\Amazon::__construct
+ * @covers OAuth\OAuth2\Service\Amazon::parseAccessTokenResponse
+ */
+ public function testParseAccessTokenResponseThrowsExceptionOnNulledResponse()
+ {
+ $client = $this->getMock('\\OAuth\\Common\\Http\\Client\\ClientInterface');
+ $client->expects($this->once())->method('retrieveResponse')->will($this->returnValue(null));
+
+ $service = new Amazon(
+ $this->getMock('\\OAuth\\Common\\Consumer\\CredentialsInterface'),
+ $client,
+ $this->getMock('\\OAuth\\Common\\Storage\\TokenStorageInterface')
+ );
+
+ $this->setExpectedException('\\OAuth\\Common\\Http\\Exception\\TokenResponseException');
+
+ $service->requestAccessToken('foo');
+ }
+
+ /**
+ * @covers OAuth\OAuth2\Service\Amazon::__construct
+ * @covers OAuth\OAuth2\Service\Amazon::parseAccessTokenResponse
+ */
+ public function testParseAccessTokenResponseThrowsExceptionOnErrorDescription()
+ {
+ $client = $this->getMock('\\OAuth\\Common\\Http\\Client\\ClientInterface');
+ $client->expects($this->once())->method('retrieveResponse')->will($this->returnValue('error_description=some_error'));
+
+ $service = new Amazon(
+ $this->getMock('\\OAuth\\Common\\Consumer\\CredentialsInterface'),
+ $client,
+ $this->getMock('\\OAuth\\Common\\Storage\\TokenStorageInterface')
+ );
+
+ $this->setExpectedException('\\OAuth\\Common\\Http\\Exception\\TokenResponseException');
+
+ $service->requestAccessToken('foo');
+ }
+
+ /**
+ * @covers OAuth\OAuth2\Service\Amazon::__construct
+ * @covers OAuth\OAuth2\Service\Amazon::parseAccessTokenResponse
+ */
+ public function testParseAccessTokenResponseThrowsExceptionOnError()
+ {
+ $client = $this->getMock('\\OAuth\\Common\\Http\\Client\\ClientInterface');
+ $client->expects($this->once())->method('retrieveResponse')->will($this->returnValue('error=some_error'));
+
+ $service = new Amazon(
+ $this->getMock('\\OAuth\\Common\\Consumer\\CredentialsInterface'),
+ $client,
+ $this->getMock('\\OAuth\\Common\\Storage\\TokenStorageInterface')
+ );
+
+ $this->setExpectedException('\\OAuth\\Common\\Http\\Exception\\TokenResponseException');
+
+ $service->requestAccessToken('foo');
+ }
+
+ /**
+ * @covers OAuth\OAuth2\Service\Amazon::__construct
+ * @covers OAuth\OAuth2\Service\Amazon::parseAccessTokenResponse
+ */
+ public function testParseAccessTokenResponseValidWithoutRefreshToken()
+ {
+ $client = $this->getMock('\\OAuth\\Common\\Http\\Client\\ClientInterface');
+ $client->expects($this->once())->method('retrieveResponse')->will($this->returnValue('{"access_token":"foo","expires_in":"bar"}'));
+
+ $service = new Amazon(
+ $this->getMock('\\OAuth\\Common\\Consumer\\CredentialsInterface'),
+ $client,
+ $this->getMock('\\OAuth\\Common\\Storage\\TokenStorageInterface')
+ );
+
+ $this->assertInstanceOf('\\OAuth\\OAuth2\\Token\\StdOAuth2Token', $service->requestAccessToken('foo'));
+ }
+
+ /**
+ * @covers OAuth\OAuth2\Service\Amazon::__construct
+ * @covers OAuth\OAuth2\Service\Amazon::parseAccessTokenResponse
+ */
+ public function testParseAccessTokenResponseValidWithRefreshToken()
+ {
+ $client = $this->getMock('\\OAuth\\Common\\Http\\Client\\ClientInterface');
+ $client->expects($this->once())->method('retrieveResponse')->will($this->returnValue('{"access_token":"foo","expires_in":"bar","refresh_token":"baz"}'));
+
+ $service = new Amazon(
+ $this->getMock('\\OAuth\\Common\\Consumer\\CredentialsInterface'),
+ $client,
+ $this->getMock('\\OAuth\\Common\\Storage\\TokenStorageInterface')
+ );
+
+ $this->assertInstanceOf('\\OAuth\\OAuth2\\Token\\StdOAuth2Token', $service->requestAccessToken('foo'));
+ }
+}
diff --git a/vendor/lusitanian/oauth/tests/Unit/OAuth2/Service/BitlyTest.php b/vendor/lusitanian/oauth/tests/Unit/OAuth2/Service/BitlyTest.php
new file mode 100644
index 00000000..9944b260
--- /dev/null
+++ b/vendor/lusitanian/oauth/tests/Unit/OAuth2/Service/BitlyTest.php
@@ -0,0 +1,150 @@
+getMock('\\OAuth\\Common\\Consumer\\CredentialsInterface'),
+ $this->getMock('\\OAuth\\Common\\Http\\Client\\ClientInterface'),
+ $this->getMock('\\OAuth\\Common\\Storage\\TokenStorageInterface')
+ );
+
+ $this->assertInstanceOf('\\OAuth\\OAuth2\\Service\\ServiceInterface', $service);
+ }
+
+ /**
+ * @covers OAuth\OAuth2\Service\Bitly::__construct
+ */
+ public function testConstructCorrectInstanceWithoutCustomUri()
+ {
+ $service = new Bitly(
+ $this->getMock('\\OAuth\\Common\\Consumer\\CredentialsInterface'),
+ $this->getMock('\\OAuth\\Common\\Http\\Client\\ClientInterface'),
+ $this->getMock('\\OAuth\\Common\\Storage\\TokenStorageInterface')
+ );
+
+ $this->assertInstanceOf('\\OAuth\\OAuth2\\Service\\AbstractService', $service);
+ }
+
+ /**
+ * @covers OAuth\OAuth2\Service\Bitly::__construct
+ */
+ public function testConstructCorrectInstanceWithCustomUri()
+ {
+ $service = new Bitly(
+ $this->getMock('\\OAuth\\Common\\Consumer\\CredentialsInterface'),
+ $this->getMock('\\OAuth\\Common\\Http\\Client\\ClientInterface'),
+ $this->getMock('\\OAuth\\Common\\Storage\\TokenStorageInterface'),
+ array(),
+ $this->getMock('\\OAuth\\Common\\Http\\Uri\\UriInterface')
+ );
+
+ $this->assertInstanceOf('\\OAuth\\OAuth2\\Service\\AbstractService', $service);
+ }
+
+ /**
+ * @covers OAuth\OAuth2\Service\Bitly::__construct
+ * @covers OAuth\OAuth2\Service\Bitly::getAuthorizationEndpoint
+ */
+ public function testGetAuthorizationEndpoint()
+ {
+ $service = new Bitly(
+ $this->getMock('\\OAuth\\Common\\Consumer\\CredentialsInterface'),
+ $this->getMock('\\OAuth\\Common\\Http\\Client\\ClientInterface'),
+ $this->getMock('\\OAuth\\Common\\Storage\\TokenStorageInterface')
+ );
+
+ $this->assertSame('https://bitly.com/oauth/authorize', $service->getAuthorizationEndpoint()->getAbsoluteUri());
+ }
+
+ /**
+ * @covers OAuth\OAuth2\Service\Bitly::__construct
+ * @covers OAuth\OAuth2\Service\Bitly::getAccessTokenEndpoint
+ */
+ public function testGetAccessTokenEndpoint()
+ {
+ $service = new Bitly(
+ $this->getMock('\\OAuth\\Common\\Consumer\\CredentialsInterface'),
+ $this->getMock('\\OAuth\\Common\\Http\\Client\\ClientInterface'),
+ $this->getMock('\\OAuth\\Common\\Storage\\TokenStorageInterface')
+ );
+
+ $this->assertSame('https://api-ssl.bitly.com/oauth/access_token', $service->getAccessTokenEndpoint()->getAbsoluteUri());
+ }
+
+ /**
+ * @covers OAuth\OAuth2\Service\Bitly::__construct
+ * @covers OAuth\OAuth2\Service\Bitly::getAuthorizationMethod
+ */
+ public function testGetAuthorizationMethod()
+ {
+ $client = $this->getMock('\\OAuth\\Common\\Http\\Client\\ClientInterface');
+ $client->expects($this->once())->method('retrieveResponse')->will($this->returnArgument(0));
+
+ $token = $this->getMock('\\OAuth\\OAuth2\\Token\\TokenInterface');
+ $token->expects($this->once())->method('getEndOfLife')->will($this->returnValue(TokenInterface::EOL_NEVER_EXPIRES));
+ $token->expects($this->once())->method('getAccessToken')->will($this->returnValue('foo'));
+
+ $storage = $this->getMock('\\OAuth\\Common\\Storage\\TokenStorageInterface');
+ $storage->expects($this->once())->method('retrieveAccessToken')->will($this->returnValue($token));
+
+ $service = new Bitly(
+ $this->getMock('\\OAuth\\Common\\Consumer\\CredentialsInterface'),
+ $client,
+ $storage
+ );
+
+ $uri = $service->request('https://pieterhordijk.com/my/awesome/path');
+ $absoluteUri = parse_url($uri->getAbsoluteUri());
+
+ $this->assertSame('access_token=foo', $absoluteUri['query']);
+ }
+
+ /**
+ * @covers OAuth\OAuth2\Service\Bitly::__construct
+ * @covers OAuth\OAuth2\Service\Bitly::parseAccessTokenResponse
+ */
+ public function testParseAccessTokenResponseThrowsExceptionOnError()
+ {
+ $client = $this->getMock('\\OAuth\\Common\\Http\\Client\\ClientInterface');
+ $client->expects($this->once())->method('retrieveResponse')->will($this->returnValue('error=some_error'));
+
+ $service = new Bitly(
+ $this->getMock('\\OAuth\\Common\\Consumer\\CredentialsInterface'),
+ $client,
+ $this->getMock('\\OAuth\\Common\\Storage\\TokenStorageInterface')
+ );
+
+ $this->setExpectedException('\\OAuth\\Common\\Http\\Exception\\TokenResponseException');
+
+ $service->requestAccessToken('foo');
+ }
+
+ /**
+ * @covers OAuth\OAuth2\Service\Bitly::__construct
+ * @covers OAuth\OAuth2\Service\Bitly::parseAccessTokenResponse
+ * @covers OAuth\OAuth2\Service\Bitly::requestAccessToken
+ */
+ public function testParseAccessTokenResponseValid()
+ {
+ $client = $this->getMock('\\OAuth\\Common\\Http\\Client\\ClientInterface');
+ $client->expects($this->once())->method('retrieveResponse')->will($this->returnValue('access_token=foo'));
+
+ $service = new Bitly(
+ $this->getMock('\\OAuth\\Common\\Consumer\\CredentialsInterface'),
+ $client,
+ $this->getMock('\\OAuth\\Common\\Storage\\TokenStorageInterface')
+ );
+
+ $this->assertInstanceOf('\\OAuth\\OAuth2\\Token\\StdOAuth2Token', $service->requestAccessToken('foo'));
+ }
+}
diff --git a/vendor/lusitanian/oauth/tests/Unit/OAuth2/Service/BoxTest.php b/vendor/lusitanian/oauth/tests/Unit/OAuth2/Service/BoxTest.php
new file mode 100644
index 00000000..b5b2a789
--- /dev/null
+++ b/vendor/lusitanian/oauth/tests/Unit/OAuth2/Service/BoxTest.php
@@ -0,0 +1,207 @@
+getMock('\\OAuth\\Common\\Consumer\\CredentialsInterface'),
+ $this->getMock('\\OAuth\\Common\\Http\\Client\\ClientInterface'),
+ $this->getMock('\\OAuth\\Common\\Storage\\TokenStorageInterface')
+ );
+
+ $this->assertInstanceOf('\\OAuth\\OAuth2\\Service\\ServiceInterface', $service);
+ }
+
+ /**
+ * @covers OAuth\OAuth2\Service\Box::__construct
+ */
+ public function testConstructCorrectInstanceWithoutCustomUri()
+ {
+ $service = new Box(
+ $this->getMock('\\OAuth\\Common\\Consumer\\CredentialsInterface'),
+ $this->getMock('\\OAuth\\Common\\Http\\Client\\ClientInterface'),
+ $this->getMock('\\OAuth\\Common\\Storage\\TokenStorageInterface')
+ );
+
+ $this->assertInstanceOf('\\OAuth\\OAuth2\\Service\\AbstractService', $service);
+ }
+
+ /**
+ * @covers OAuth\OAuth2\Service\Box::__construct
+ */
+ public function testConstructCorrectInstanceWithCustomUri()
+ {
+ $service = new Box(
+ $this->getMock('\\OAuth\\Common\\Consumer\\CredentialsInterface'),
+ $this->getMock('\\OAuth\\Common\\Http\\Client\\ClientInterface'),
+ $this->getMock('\\OAuth\\Common\\Storage\\TokenStorageInterface'),
+ array(),
+ $this->getMock('\\OAuth\\Common\\Http\\Uri\\UriInterface')
+ );
+
+ $this->assertInstanceOf('\\OAuth\\OAuth2\\Service\\AbstractService', $service);
+ }
+
+ /**
+ * @covers OAuth\OAuth2\Service\Box::__construct
+ * @covers OAuth\OAuth2\Service\Box::getAuthorizationEndpoint
+ */
+ public function testGetAuthorizationEndpoint()
+ {
+ $service = new Box(
+ $this->getMock('\\OAuth\\Common\\Consumer\\CredentialsInterface'),
+ $this->getMock('\\OAuth\\Common\\Http\\Client\\ClientInterface'),
+ $this->getMock('\\OAuth\\Common\\Storage\\TokenStorageInterface')
+ );
+
+ $this->assertSame('https://www.box.com/api/oauth2/authorize', $service->getAuthorizationEndpoint()->getAbsoluteUri());
+ }
+
+ /**
+ * @covers OAuth\OAuth2\Service\Box::__construct
+ * @covers OAuth\OAuth2\Service\Box::getAccessTokenEndpoint
+ */
+ public function testGetAccessTokenEndpoint()
+ {
+ $service = new Box(
+ $this->getMock('\\OAuth\\Common\\Consumer\\CredentialsInterface'),
+ $this->getMock('\\OAuth\\Common\\Http\\Client\\ClientInterface'),
+ $this->getMock('\\OAuth\\Common\\Storage\\TokenStorageInterface')
+ );
+
+ $this->assertSame('https://www.box.com/api/oauth2/token', $service->getAccessTokenEndpoint()->getAbsoluteUri());
+ }
+
+ /**
+ * @covers OAuth\OAuth2\Service\Box::__construct
+ * @covers OAuth\OAuth2\Service\Box::getAuthorizationMethod
+ */
+ public function testGetAuthorizationMethod()
+ {
+ $client = $this->getMock('\\OAuth\\Common\\Http\\Client\\ClientInterface');
+ $client->expects($this->once())->method('retrieveResponse')->will($this->returnArgument(2));
+
+ $token = $this->getMock('\\OAuth\\OAuth2\\Token\\TokenInterface');
+ $token->expects($this->once())->method('getEndOfLife')->will($this->returnValue(TokenInterface::EOL_NEVER_EXPIRES));
+ $token->expects($this->once())->method('getAccessToken')->will($this->returnValue('foo'));
+
+ $storage = $this->getMock('\\OAuth\\Common\\Storage\\TokenStorageInterface');
+ $storage->expects($this->once())->method('retrieveAccessToken')->will($this->returnValue($token));
+
+ $service = new Box(
+ $this->getMock('\\OAuth\\Common\\Consumer\\CredentialsInterface'),
+ $client,
+ $storage
+ );
+
+ $headers = $service->request('https://pieterhordijk.com/my/awesome/path');
+
+ $this->assertTrue(array_key_exists('Authorization', $headers));
+ $this->assertTrue(in_array('Bearer foo', $headers, true));
+ }
+
+ /**
+ * @covers OAuth\OAuth2\Service\Box::__construct
+ * @covers OAuth\OAuth2\Service\Box::parseAccessTokenResponse
+ */
+ public function testParseAccessTokenResponseThrowsExceptionOnNulledResponse()
+ {
+ $client = $this->getMock('\\OAuth\\Common\\Http\\Client\\ClientInterface');
+ $client->expects($this->once())->method('retrieveResponse')->will($this->returnValue(null));
+
+ $service = new Box(
+ $this->getMock('\\OAuth\\Common\\Consumer\\CredentialsInterface'),
+ $client,
+ $this->getMock('\\OAuth\\Common\\Storage\\TokenStorageInterface')
+ );
+
+ $this->setExpectedException('\\OAuth\\Common\\Http\\Exception\\TokenResponseException');
+
+ $service->requestAccessToken('foo');
+ }
+
+ /**
+ * @covers OAuth\OAuth2\Service\Box::__construct
+ * @covers OAuth\OAuth2\Service\Box::parseAccessTokenResponse
+ */
+ public function testParseAccessTokenResponseThrowsExceptionOnErrorDescription()
+ {
+ $client = $this->getMock('\\OAuth\\Common\\Http\\Client\\ClientInterface');
+ $client->expects($this->once())->method('retrieveResponse')->will($this->returnValue('error_description=some_error'));
+
+ $service = new Box(
+ $this->getMock('\\OAuth\\Common\\Consumer\\CredentialsInterface'),
+ $client,
+ $this->getMock('\\OAuth\\Common\\Storage\\TokenStorageInterface')
+ );
+
+ $this->setExpectedException('\\OAuth\\Common\\Http\\Exception\\TokenResponseException');
+
+ $service->requestAccessToken('foo');
+ }
+
+ /**
+ * @covers OAuth\OAuth2\Service\Box::__construct
+ * @covers OAuth\OAuth2\Service\Box::parseAccessTokenResponse
+ */
+ public function testParseAccessTokenResponseThrowsExceptionOnError()
+ {
+ $client = $this->getMock('\\OAuth\\Common\\Http\\Client\\ClientInterface');
+ $client->expects($this->once())->method('retrieveResponse')->will($this->returnValue('error=some_error'));
+
+ $service = new Box(
+ $this->getMock('\\OAuth\\Common\\Consumer\\CredentialsInterface'),
+ $client,
+ $this->getMock('\\OAuth\\Common\\Storage\\TokenStorageInterface')
+ );
+
+ $this->setExpectedException('\\OAuth\\Common\\Http\\Exception\\TokenResponseException');
+
+ $service->requestAccessToken('foo');
+ }
+
+ /**
+ * @covers OAuth\OAuth2\Service\Box::__construct
+ * @covers OAuth\OAuth2\Service\Box::parseAccessTokenResponse
+ */
+ public function testParseAccessTokenResponseValidWithoutRefreshToken()
+ {
+ $client = $this->getMock('\\OAuth\\Common\\Http\\Client\\ClientInterface');
+ $client->expects($this->once())->method('retrieveResponse')->will($this->returnValue('{"access_token":"foo","expires_in":"bar"}'));
+
+ $service = new Box(
+ $this->getMock('\\OAuth\\Common\\Consumer\\CredentialsInterface'),
+ $client,
+ $this->getMock('\\OAuth\\Common\\Storage\\TokenStorageInterface')
+ );
+
+ $this->assertInstanceOf('\\OAuth\\OAuth2\\Token\\StdOAuth2Token', $service->requestAccessToken('foo'));
+ }
+
+ /**
+ * @covers OAuth\OAuth2\Service\Box::__construct
+ * @covers OAuth\OAuth2\Service\Box::parseAccessTokenResponse
+ */
+ public function testParseAccessTokenResponseValidWithRefreshToken()
+ {
+ $client = $this->getMock('\\OAuth\\Common\\Http\\Client\\ClientInterface');
+ $client->expects($this->once())->method('retrieveResponse')->will($this->returnValue('{"access_token":"foo","expires_in":"bar","refresh_token":"baz"}'));
+
+ $service = new Box(
+ $this->getMock('\\OAuth\\Common\\Consumer\\CredentialsInterface'),
+ $client,
+ $this->getMock('\\OAuth\\Common\\Storage\\TokenStorageInterface')
+ );
+
+ $this->assertInstanceOf('\\OAuth\\OAuth2\\Token\\StdOAuth2Token', $service->requestAccessToken('foo'));
+ }
+}
diff --git a/vendor/lusitanian/oauth/tests/Unit/OAuth2/Service/BufferTest.php b/vendor/lusitanian/oauth/tests/Unit/OAuth2/Service/BufferTest.php
new file mode 100644
index 00000000..29726d0a
--- /dev/null
+++ b/vendor/lusitanian/oauth/tests/Unit/OAuth2/Service/BufferTest.php
@@ -0,0 +1,150 @@
+getMock('\\OAuth\\Common\\Consumer\\CredentialsInterface'),
+ $this->getMock('\\OAuth\\Common\\Http\\Client\\ClientInterface'),
+ $this->getMock('\\OAuth\\Common\\Storage\\TokenStorageInterface')
+ );
+
+ $this->assertInstanceOf('\\OAuth\\OAuth2\\Service\\ServiceInterface', $service);
+ }
+
+ /**
+ * @covers OAuth\OAuth2\Service\Buffer::__construct
+ */
+ public function testConstructCorrectInstanceWithoutCustomUri()
+ {
+ $service = new Buffer(
+ $this->getMock('\\OAuth\\Common\\Consumer\\CredentialsInterface'),
+ $this->getMock('\\OAuth\\Common\\Http\\Client\\ClientInterface'),
+ $this->getMock('\\OAuth\\Common\\Storage\\TokenStorageInterface')
+ );
+
+ $this->assertInstanceOf('\\OAuth\\OAuth2\\Service\\AbstractService', $service);
+ }
+
+ /**
+ * @covers OAuth\OAuth2\Service\Buffer::__construct
+ */
+ public function testConstructCorrectInstanceWithCustomUri()
+ {
+ $service = new Buffer(
+ $this->getMock('\\OAuth\\Common\\Consumer\\CredentialsInterface'),
+ $this->getMock('\\OAuth\\Common\\Http\\Client\\ClientInterface'),
+ $this->getMock('\\OAuth\\Common\\Storage\\TokenStorageInterface'),
+ array(),
+ $this->getMock('\\OAuth\\Common\\Http\\Uri\\UriInterface')
+ );
+
+ $this->assertInstanceOf('\\OAuth\\OAuth2\\Service\\AbstractService', $service);
+ }
+
+ /**
+ * @covers OAuth\OAuth2\Service\Buffer::__construct
+ * @covers OAuth\OAuth2\Service\Buffer::getAuthorizationEndpoint
+ */
+ public function testGetAuthorizationEndpoint()
+ {
+ $service = new Buffer(
+ $this->getMock('\\OAuth\\Common\\Consumer\\CredentialsInterface'),
+ $this->getMock('\\OAuth\\Common\\Http\\Client\\ClientInterface'),
+ $this->getMock('\\OAuth\\Common\\Storage\\TokenStorageInterface')
+ );
+
+ $this->assertSame('https://bufferapp.com/oauth2/authorize', $service->getAuthorizationEndpoint()->getAbsoluteUri());
+ }
+
+ /**
+ * @covers OAuth\OAuth2\Service\Buffer::__construct
+ * @covers OAuth\OAuth2\Service\Buffer::getAccessTokenEndpoint
+ */
+ public function testGetAccessTokenEndpoint()
+ {
+ $service = new Buffer(
+ $this->getMock('\\OAuth\\Common\\Consumer\\CredentialsInterface'),
+ $this->getMock('\\OAuth\\Common\\Http\\Client\\ClientInterface'),
+ $this->getMock('\\OAuth\\Common\\Storage\\TokenStorageInterface')
+ );
+
+ $this->assertSame('https://api.bufferapp.com/1/oauth2/token.json', $service->getAccessTokenEndpoint()->getAbsoluteUri());
+ }
+
+ /**
+ * @covers OAuth\OAuth2\Service\Buffer::__construct
+ * @covers OAuth\OAuth2\Service\Buffer::getAuthorizationMethod
+ */
+ public function testGetAuthorizationMethod()
+ {
+ $client = $this->getMock('\\OAuth\\Common\\Http\\Client\\ClientInterface');
+ $client->expects($this->once())->method('retrieveResponse')->will($this->returnArgument(0));
+
+ $token = $this->getMock('\\OAuth\\OAuth2\\Token\\TokenInterface');
+ $token->expects($this->once())->method('getEndOfLife')->will($this->returnValue(TokenInterface::EOL_NEVER_EXPIRES));
+ $token->expects($this->once())->method('getAccessToken')->will($this->returnValue('foo'));
+
+ $storage = $this->getMock('\\OAuth\\Common\\Storage\\TokenStorageInterface');
+ $storage->expects($this->once())->method('retrieveAccessToken')->will($this->returnValue($token));
+
+ $service = new Buffer(
+ $this->getMock('\\OAuth\\Common\\Consumer\\CredentialsInterface'),
+ $client,
+ $storage
+ );
+
+ $uri = $service->request('https://pieterhordijk.com/my/awesome/path');
+ $absoluteUri = parse_url($uri->getAbsoluteUri());
+
+ $this->assertSame('access_token=foo', $absoluteUri['query']);
+ }
+
+ /**
+ * @covers OAuth\OAuth2\Service\Buffer::__construct
+ * @covers OAuth\OAuth2\Service\Buffer::parseAccessTokenResponse
+ */
+ public function testParseAccessTokenResponseThrowsExceptionOnError()
+ {
+ $client = $this->getMock('\\OAuth\\Common\\Http\\Client\\ClientInterface');
+ $client->expects($this->once())->method('retrieveResponse')->will($this->returnValue('error=some_error'));
+
+ $service = new Buffer(
+ $this->getMock('\\OAuth\\Common\\Consumer\\CredentialsInterface'),
+ $client,
+ $this->getMock('\\OAuth\\Common\\Storage\\TokenStorageInterface')
+ );
+
+ $this->setExpectedException('\\OAuth\\Common\\Http\\Exception\\TokenResponseException');
+
+ $service->requestAccessToken('foo');
+ }
+
+ /**
+ * @covers OAuth\OAuth2\Service\Buffer::__construct
+ * @covers OAuth\OAuth2\Service\Buffer::parseAccessTokenResponse
+ * @covers OAuth\OAuth2\Service\Buffer::requestAccessToken
+ */
+ public function testParseAccessTokenResponseValid()
+ {
+ $client = $this->getMock('\\OAuth\\Common\\Http\\Client\\ClientInterface');
+ $client->expects($this->once())->method('retrieveResponse')->will($this->returnValue('{"access_token":"foo"}'));
+
+ $service = new Buffer(
+ $this->getMock('\\OAuth\\Common\\Consumer\\CredentialsInterface'),
+ $client,
+ $this->getMock('\\OAuth\\Common\\Storage\\TokenStorageInterface')
+ );
+
+ $this->assertInstanceOf('\\OAuth\\OAuth2\\Token\\StdOAuth2Token', $service->requestAccessToken('foo'));
+ }
+}
\ No newline at end of file
diff --git a/vendor/lusitanian/oauth/tests/Unit/OAuth2/Service/DailymotionTest.php b/vendor/lusitanian/oauth/tests/Unit/OAuth2/Service/DailymotionTest.php
new file mode 100644
index 00000000..f3fbaa8e
--- /dev/null
+++ b/vendor/lusitanian/oauth/tests/Unit/OAuth2/Service/DailymotionTest.php
@@ -0,0 +1,230 @@
+getMock('\\OAuth\\Common\\Consumer\\CredentialsInterface'),
+ $this->getMock('\\OAuth\\Common\\Http\\Client\\ClientInterface'),
+ $this->getMock('\\OAuth\\Common\\Storage\\TokenStorageInterface')
+ );
+
+ $this->assertInstanceOf('\\OAuth\\OAuth2\\Service\\ServiceInterface', $service);
+ }
+
+ /**
+ * @covers OAuth\OAuth2\Service\Dailymotion::__construct
+ */
+ public function testConstructCorrectInstanceWithoutCustomUri()
+ {
+ $service = new Dailymotion(
+ $this->getMock('\\OAuth\\Common\\Consumer\\CredentialsInterface'),
+ $this->getMock('\\OAuth\\Common\\Http\\Client\\ClientInterface'),
+ $this->getMock('\\OAuth\\Common\\Storage\\TokenStorageInterface')
+ );
+
+ $this->assertInstanceOf('\\OAuth\\OAuth2\\Service\\AbstractService', $service);
+ }
+
+ /**
+ * @covers OAuth\OAuth2\Service\Dailymotion::__construct
+ */
+ public function testConstructCorrectInstanceWithCustomUri()
+ {
+ $service = new Dailymotion(
+ $this->getMock('\\OAuth\\Common\\Consumer\\CredentialsInterface'),
+ $this->getMock('\\OAuth\\Common\\Http\\Client\\ClientInterface'),
+ $this->getMock('\\OAuth\\Common\\Storage\\TokenStorageInterface'),
+ array(),
+ $this->getMock('\\OAuth\\Common\\Http\\Uri\\UriInterface')
+ );
+
+ $this->assertInstanceOf('\\OAuth\\OAuth2\\Service\\AbstractService', $service);
+ }
+
+ /**
+ * @covers OAuth\OAuth2\Service\Dailymotion::__construct
+ * @covers OAuth\OAuth2\Service\Dailymotion::getAuthorizationEndpoint
+ */
+ public function testGetAuthorizationEndpoint()
+ {
+ $service = new Dailymotion(
+ $this->getMock('\\OAuth\\Common\\Consumer\\CredentialsInterface'),
+ $this->getMock('\\OAuth\\Common\\Http\\Client\\ClientInterface'),
+ $this->getMock('\\OAuth\\Common\\Storage\\TokenStorageInterface')
+ );
+
+ $this->assertSame('https://api.dailymotion.com/oauth/authorize', $service->getAuthorizationEndpoint()->getAbsoluteUri());
+ }
+
+ /**
+ * @covers OAuth\OAuth2\Service\Dailymotion::__construct
+ * @covers OAuth\OAuth2\Service\Dailymotion::getAccessTokenEndpoint
+ */
+ public function testGetAccessTokenEndpoint()
+ {
+ $service = new Dailymotion(
+ $this->getMock('\\OAuth\\Common\\Consumer\\CredentialsInterface'),
+ $this->getMock('\\OAuth\\Common\\Http\\Client\\ClientInterface'),
+ $this->getMock('\\OAuth\\Common\\Storage\\TokenStorageInterface')
+ );
+
+ $this->assertSame('https://api.dailymotion.com/oauth/token', $service->getAccessTokenEndpoint()->getAbsoluteUri());
+ }
+
+ /**
+ * @covers OAuth\OAuth2\Service\Dailymotion::__construct
+ * @covers OAuth\OAuth2\Service\Dailymotion::getAuthorizationMethod
+ */
+ public function testGetAuthorizationMethod()
+ {
+ $client = $this->getMock('\\OAuth\\Common\\Http\\Client\\ClientInterface');
+ $client->expects($this->once())->method('retrieveResponse')->will($this->returnArgument(2));
+
+ $token = $this->getMock('\\OAuth\\OAuth2\\Token\\TokenInterface');
+ $token->expects($this->once())->method('getEndOfLife')->will($this->returnValue(TokenInterface::EOL_NEVER_EXPIRES));
+ $token->expects($this->once())->method('getAccessToken')->will($this->returnValue('foo'));
+
+ $storage = $this->getMock('\\OAuth\\Common\\Storage\\TokenStorageInterface');
+ $storage->expects($this->once())->method('retrieveAccessToken')->will($this->returnValue($token));
+
+ $service = new Dailymotion(
+ $this->getMock('\\OAuth\\Common\\Consumer\\CredentialsInterface'),
+ $client,
+ $storage
+ );
+
+ $headers = $service->request('https://pieterhordijk.com/my/awesome/path');
+
+ $this->assertTrue(array_key_exists('Authorization', $headers));
+ $this->assertTrue(in_array('OAuth foo', $headers, true));
+ }
+
+ /**
+ * @covers OAuth\OAuth2\Service\Dailymotion::__construct
+ * @covers OAuth\OAuth2\Service\Dailymotion::parseAccessTokenResponse
+ */
+ public function testParseAccessTokenResponseThrowsExceptionOnNulledResponse()
+ {
+ $client = $this->getMock('\\OAuth\\Common\\Http\\Client\\ClientInterface');
+ $client->expects($this->once())->method('retrieveResponse')->will($this->returnValue(null));
+
+ $service = new Dailymotion(
+ $this->getMock('\\OAuth\\Common\\Consumer\\CredentialsInterface'),
+ $client,
+ $this->getMock('\\OAuth\\Common\\Storage\\TokenStorageInterface')
+ );
+
+ $this->setExpectedException('\\OAuth\\Common\\Http\\Exception\\TokenResponseException');
+
+ $service->requestAccessToken('foo');
+ }
+
+ /**
+ * @covers OAuth\OAuth2\Service\Dailymotion::__construct
+ * @covers OAuth\OAuth2\Service\Dailymotion::parseAccessTokenResponse
+ */
+ public function testParseAccessTokenResponseThrowsExceptionOnErrorDescription()
+ {
+ $client = $this->getMock('\\OAuth\\Common\\Http\\Client\\ClientInterface');
+ $client->expects($this->once())->method('retrieveResponse')->will($this->returnValue('error_description=some_error'));
+
+ $service = new Dailymotion(
+ $this->getMock('\\OAuth\\Common\\Consumer\\CredentialsInterface'),
+ $client,
+ $this->getMock('\\OAuth\\Common\\Storage\\TokenStorageInterface')
+ );
+
+ $this->setExpectedException('\\OAuth\\Common\\Http\\Exception\\TokenResponseException');
+
+ $service->requestAccessToken('foo');
+ }
+
+ /**
+ * @covers OAuth\OAuth2\Service\Dailymotion::__construct
+ * @covers OAuth\OAuth2\Service\Dailymotion::parseAccessTokenResponse
+ */
+ public function testParseAccessTokenResponseThrowsExceptionOnError()
+ {
+ $client = $this->getMock('\\OAuth\\Common\\Http\\Client\\ClientInterface');
+ $client->expects($this->once())->method('retrieveResponse')->will($this->returnValue('error=some_error'));
+
+ $service = new Dailymotion(
+ $this->getMock('\\OAuth\\Common\\Consumer\\CredentialsInterface'),
+ $client,
+ $this->getMock('\\OAuth\\Common\\Storage\\TokenStorageInterface')
+ );
+
+ $this->setExpectedException('\\OAuth\\Common\\Http\\Exception\\TokenResponseException');
+
+ $service->requestAccessToken('foo');
+ }
+
+ /**
+ * @covers OAuth\OAuth2\Service\Dailymotion::__construct
+ * @covers OAuth\OAuth2\Service\Dailymotion::parseAccessTokenResponse
+ */
+ public function testParseAccessTokenResponseValidWithoutRefreshToken()
+ {
+ $client = $this->getMock('\\OAuth\\Common\\Http\\Client\\ClientInterface');
+ $client->expects($this->once())->method('retrieveResponse')->will($this->returnValue('{"access_token":"foo","expires_in":"bar"}'));
+
+ $service = new Dailymotion(
+ $this->getMock('\\OAuth\\Common\\Consumer\\CredentialsInterface'),
+ $client,
+ $this->getMock('\\OAuth\\Common\\Storage\\TokenStorageInterface')
+ );
+
+ $this->assertInstanceOf('\\OAuth\\OAuth2\\Token\\StdOAuth2Token', $service->requestAccessToken('foo'));
+ }
+
+ /**
+ * @covers OAuth\OAuth2\Service\Dailymotion::__construct
+ * @covers OAuth\OAuth2\Service\Dailymotion::parseAccessTokenResponse
+ */
+ public function testParseAccessTokenResponseValidWithRefreshToken()
+ {
+ $client = $this->getMock('\\OAuth\\Common\\Http\\Client\\ClientInterface');
+ $client->expects($this->once())->method('retrieveResponse')->will($this->returnValue('{"access_token":"foo","expires_in":"bar","refresh_token":"baz"}'));
+
+ $service = new Dailymotion(
+ $this->getMock('\\OAuth\\Common\\Consumer\\CredentialsInterface'),
+ $client,
+ $this->getMock('\\OAuth\\Common\\Storage\\TokenStorageInterface')
+ );
+
+ $this->assertInstanceOf('\\OAuth\\OAuth2\\Token\\StdOAuth2Token', $service->requestAccessToken('foo'));
+ }
+
+ /**
+ * @covers OAuth\OAuth2\Service\Dailymotion::__construct
+ * @covers OAuth\OAuth2\Service\Dailymotion::getExtraOAuthHeaders
+ */
+ public function testGetExtraOAuthHeaders()
+ {
+ $client = $this->getMock('\\OAuth\\Common\\Http\\Client\\ClientInterface');
+ $client->expects($this->once())->method('retrieveResponse')->will($this->returnCallback(function($uri, $params, $extraHeaders) {
+ \PHPUnit_Framework_Assert::assertTrue(array_key_exists('Accept', $extraHeaders));
+ \PHPUnit_Framework_Assert::assertTrue(in_array('application/json', $extraHeaders, true));
+
+ return '{"access_token":"foo","expires_in":"bar"}';
+ }));
+
+ $service = new Dailymotion(
+ $this->getMock('\\OAuth\\Common\\Consumer\\CredentialsInterface'),
+ $client,
+ $this->getMock('\\OAuth\\Common\\Storage\\TokenStorageInterface')
+ );
+
+ $this->assertInstanceOf('\\OAuth\\OAuth2\\Token\\StdOAuth2Token', $service->requestAccessToken('foo'));
+ }
+}
diff --git a/vendor/lusitanian/oauth/tests/Unit/OAuth2/Service/DropboxTest.php b/vendor/lusitanian/oauth/tests/Unit/OAuth2/Service/DropboxTest.php
new file mode 100644
index 00000000..8f052c6b
--- /dev/null
+++ b/vendor/lusitanian/oauth/tests/Unit/OAuth2/Service/DropboxTest.php
@@ -0,0 +1,231 @@
+getMock('\\OAuth\\Common\\Consumer\\CredentialsInterface'),
+ $this->getMock('\\OAuth\\Common\\Http\\Client\\ClientInterface'),
+ $this->getMock('\\OAuth\\Common\\Storage\\TokenStorageInterface')
+ );
+
+ $this->assertInstanceOf('\\OAuth\\OAuth2\\Service\\ServiceInterface', $service);
+ }
+
+ /**
+ * @covers OAuth\OAuth2\Service\Dropbox::__construct
+ */
+ public function testConstructCorrectInstanceWithoutCustomUri()
+ {
+ $service = new Dropbox(
+ $this->getMock('\\OAuth\\Common\\Consumer\\CredentialsInterface'),
+ $this->getMock('\\OAuth\\Common\\Http\\Client\\ClientInterface'),
+ $this->getMock('\\OAuth\\Common\\Storage\\TokenStorageInterface')
+ );
+
+ $this->assertInstanceOf('\\OAuth\\OAuth2\\Service\\AbstractService', $service);
+ }
+
+ /**
+ * @covers OAuth\OAuth2\Service\Dropbox::__construct
+ */
+ public function testConstructCorrectInstanceWithCustomUri()
+ {
+ $service = new Dropbox(
+ $this->getMock('\\OAuth\\Common\\Consumer\\CredentialsInterface'),
+ $this->getMock('\\OAuth\\Common\\Http\\Client\\ClientInterface'),
+ $this->getMock('\\OAuth\\Common\\Storage\\TokenStorageInterface'),
+ array(),
+ $this->getMock('\\OAuth\\Common\\Http\\Uri\\UriInterface')
+ );
+
+ $this->assertInstanceOf('\\OAuth\\OAuth2\\Service\\AbstractService', $service);
+ }
+
+ /**
+ * @covers OAuth\OAuth2\Service\Dropbox::__construct
+ * @covers OAuth\OAuth2\Service\Dropbox::getAuthorizationUri
+ */
+ public function testGetAuthorizationUriWithoutAdditionalParams()
+ {
+ $credentials = $this->getMock('\\OAuth\\Common\\Consumer\\CredentialsInterface');
+ $credentials->expects($this->once())->method('getConsumerId')->will($this->returnValue('foo'));
+ $credentials->expects($this->once())->method('getCallbackUrl')->will($this->returnValue('bar'));
+
+ $service = new Dropbox(
+ $credentials,
+ $this->getMock('\\OAuth\\Common\\Http\\Client\\ClientInterface'),
+ $this->getMock('\\OAuth\\Common\\Storage\\TokenStorageInterface')
+ );
+
+ $this->assertSame(
+ 'https://www.dropbox.com/1/oauth2/authorize?client_id=foo&redirect_uri=bar&response_type=code&scope=',
+ $service->getAuthorizationUri()->getAbsoluteUri()
+ );
+ }
+
+ /**
+ * @covers OAuth\OAuth2\Service\Dropbox::__construct
+ * @covers OAuth\OAuth2\Service\Dropbox::getAuthorizationUri
+ */
+ public function testGetAuthorizationUriWithAdditionalParams()
+ {
+ $credentials = $this->getMock('\\OAuth\\Common\\Consumer\\CredentialsInterface');
+ $credentials->expects($this->once())->method('getConsumerId')->will($this->returnValue('foo'));
+ $credentials->expects($this->once())->method('getCallbackUrl')->will($this->returnValue('bar'));
+
+ $service = new Dropbox(
+ $credentials,
+ $this->getMock('\\OAuth\\Common\\Http\\Client\\ClientInterface'),
+ $this->getMock('\\OAuth\\Common\\Storage\\TokenStorageInterface')
+ );
+
+ $this->assertSame(
+ 'https://www.dropbox.com/1/oauth2/authorize?client_id=foo&redirect_uri=bar&response_type=code&scope=',
+ $service->getAuthorizationUri()->getAbsoluteUri()
+ );
+ }
+
+ /**
+ * @covers OAuth\OAuth2\Service\Dropbox::__construct
+ * @covers OAuth\OAuth2\Service\Dropbox::getAuthorizationEndpoint
+ */
+ public function testGetAuthorizationEndpoint()
+ {
+ $service = new Dropbox(
+ $this->getMock('\\OAuth\\Common\\Consumer\\CredentialsInterface'),
+ $this->getMock('\\OAuth\\Common\\Http\\Client\\ClientInterface'),
+ $this->getMock('\\OAuth\\Common\\Storage\\TokenStorageInterface')
+ );
+
+ $this->assertSame('https://www.dropbox.com/1/oauth2/authorize', $service->getAuthorizationEndpoint()->getAbsoluteUri());
+ }
+
+ /**
+ * @covers OAuth\OAuth2\Service\Dropbox::__construct
+ * @covers OAuth\OAuth2\Service\Dropbox::getAccessTokenEndpoint
+ */
+ public function testGetAccessTokenEndpoint()
+ {
+ $service = new Dropbox(
+ $this->getMock('\\OAuth\\Common\\Consumer\\CredentialsInterface'),
+ $this->getMock('\\OAuth\\Common\\Http\\Client\\ClientInterface'),
+ $this->getMock('\\OAuth\\Common\\Storage\\TokenStorageInterface')
+ );
+
+ $this->assertSame('https://api.dropbox.com/1/oauth2/token', $service->getAccessTokenEndpoint()->getAbsoluteUri());
+ }
+
+ /**
+ * @covers OAuth\OAuth2\Service\Dropbox::__construct
+ * @covers OAuth\OAuth2\Service\Dropbox::getAuthorizationMethod
+ */
+ public function testGetAuthorizationMethod()
+ {
+ $client = $this->getMock('\\OAuth\\Common\\Http\\Client\\ClientInterface');
+ $client->expects($this->once())->method('retrieveResponse')->will($this->returnArgument(0));
+
+ $token = $this->getMock('\\OAuth\\OAuth2\\Token\\TokenInterface');
+ $token->expects($this->once())->method('getEndOfLife')->will($this->returnValue(TokenInterface::EOL_NEVER_EXPIRES));
+ $token->expects($this->once())->method('getAccessToken')->will($this->returnValue('foo'));
+
+ $storage = $this->getMock('\\OAuth\\Common\\Storage\\TokenStorageInterface');
+ $storage->expects($this->once())->method('retrieveAccessToken')->will($this->returnValue($token));
+
+ $service = new Dropbox(
+ $this->getMock('\\OAuth\\Common\\Consumer\\CredentialsInterface'),
+ $client,
+ $storage
+ );
+
+ $uri = $service->request('https://pieterhordijk.com/my/awesome/path');
+ $absoluteUri = parse_url($uri->getAbsoluteUri());
+
+ $this->assertSame('access_token=foo', $absoluteUri['query']);
+ }
+
+ /**
+ * @covers OAuth\OAuth2\Service\Dropbox::__construct
+ * @covers OAuth\OAuth2\Service\Dropbox::parseAccessTokenResponse
+ */
+ public function testParseAccessTokenResponseThrowsExceptionOnNulledResponse()
+ {
+ $client = $this->getMock('\\OAuth\\Common\\Http\\Client\\ClientInterface');
+ $client->expects($this->once())->method('retrieveResponse')->will($this->returnValue(null));
+
+ $service = new Dropbox(
+ $this->getMock('\\OAuth\\Common\\Consumer\\CredentialsInterface'),
+ $client,
+ $this->getMock('\\OAuth\\Common\\Storage\\TokenStorageInterface')
+ );
+
+ $this->setExpectedException('\\OAuth\\Common\\Http\\Exception\\TokenResponseException');
+
+ $service->requestAccessToken('foo');
+ }
+
+ /**
+ * @covers OAuth\OAuth2\Service\Dropbox::__construct
+ * @covers OAuth\OAuth2\Service\Dropbox::parseAccessTokenResponse
+ */
+ public function testParseAccessTokenResponseThrowsExceptionOnError()
+ {
+ $client = $this->getMock('\\OAuth\\Common\\Http\\Client\\ClientInterface');
+ $client->expects($this->once())->method('retrieveResponse')->will($this->returnValue('error=some_error'));
+
+ $service = new Dropbox(
+ $this->getMock('\\OAuth\\Common\\Consumer\\CredentialsInterface'),
+ $client,
+ $this->getMock('\\OAuth\\Common\\Storage\\TokenStorageInterface')
+ );
+
+ $this->setExpectedException('\\OAuth\\Common\\Http\\Exception\\TokenResponseException');
+
+ $service->requestAccessToken('foo');
+ }
+
+ /**
+ * @covers OAuth\OAuth2\Service\Dropbox::__construct
+ * @covers OAuth\OAuth2\Service\Dropbox::parseAccessTokenResponse
+ */
+ public function testParseAccessTokenResponseValidWithoutRefreshToken()
+ {
+ $client = $this->getMock('\\OAuth\\Common\\Http\\Client\\ClientInterface');
+ $client->expects($this->once())->method('retrieveResponse')->will($this->returnValue('{"access_token":"foo","expires_in":"bar"}'));
+
+ $service = new Dropbox(
+ $this->getMock('\\OAuth\\Common\\Consumer\\CredentialsInterface'),
+ $client,
+ $this->getMock('\\OAuth\\Common\\Storage\\TokenStorageInterface')
+ );
+
+ $this->assertInstanceOf('\\OAuth\\OAuth2\\Token\\StdOAuth2Token', $service->requestAccessToken('foo'));
+ }
+
+ /**
+ * @covers OAuth\OAuth2\Service\Dropbox::__construct
+ * @covers OAuth\OAuth2\Service\Dropbox::parseAccessTokenResponse
+ */
+ public function testParseAccessTokenResponseValidWithRefreshToken()
+ {
+ $client = $this->getMock('\\OAuth\\Common\\Http\\Client\\ClientInterface');
+ $client->expects($this->once())->method('retrieveResponse')->will($this->returnValue('{"access_token":"foo","expires_in":"bar","refresh_token":"baz"}'));
+
+ $service = new Dropbox(
+ $this->getMock('\\OAuth\\Common\\Consumer\\CredentialsInterface'),
+ $client,
+ $this->getMock('\\OAuth\\Common\\Storage\\TokenStorageInterface')
+ );
+
+ $this->assertInstanceOf('\\OAuth\\OAuth2\\Token\\StdOAuth2Token', $service->requestAccessToken('foo'));
+ }
+}
diff --git a/vendor/lusitanian/oauth/tests/Unit/OAuth2/Service/FacebookTest.php b/vendor/lusitanian/oauth/tests/Unit/OAuth2/Service/FacebookTest.php
new file mode 100644
index 00000000..f2fed463
--- /dev/null
+++ b/vendor/lusitanian/oauth/tests/Unit/OAuth2/Service/FacebookTest.php
@@ -0,0 +1,242 @@
+getMock('\\OAuth\\Common\\Consumer\\CredentialsInterface'),
+ $this->getMock('\\OAuth\\Common\\Http\\Client\\ClientInterface'),
+ $this->getMock('\\OAuth\\Common\\Storage\\TokenStorageInterface')
+ );
+
+ $this->assertInstanceOf('\\OAuth\\OAuth2\\Service\\ServiceInterface', $service);
+ }
+
+ /**
+ * @covers OAuth\OAuth2\Service\Facebook::__construct
+ */
+ public function testConstructCorrectInstanceWithoutCustomUri()
+ {
+ $service = new Facebook(
+ $this->getMock('\\OAuth\\Common\\Consumer\\CredentialsInterface'),
+ $this->getMock('\\OAuth\\Common\\Http\\Client\\ClientInterface'),
+ $this->getMock('\\OAuth\\Common\\Storage\\TokenStorageInterface')
+ );
+
+ $this->assertInstanceOf('\\OAuth\\OAuth2\\Service\\AbstractService', $service);
+ }
+
+ /**
+ * @covers OAuth\OAuth2\Service\Facebook::__construct
+ */
+ public function testConstructCorrectInstanceWithCustomUri()
+ {
+ $service = new Facebook(
+ $this->getMock('\\OAuth\\Common\\Consumer\\CredentialsInterface'),
+ $this->getMock('\\OAuth\\Common\\Http\\Client\\ClientInterface'),
+ $this->getMock('\\OAuth\\Common\\Storage\\TokenStorageInterface'),
+ array(),
+ $this->getMock('\\OAuth\\Common\\Http\\Uri\\UriInterface')
+ );
+
+ $this->assertInstanceOf('\\OAuth\\OAuth2\\Service\\AbstractService', $service);
+ }
+
+ /**
+ * @covers OAuth\OAuth2\Service\Facebook::__construct
+ * @covers OAuth\OAuth2\Service\Facebook::getAuthorizationEndpoint
+ */
+ public function testGetAuthorizationEndpoint()
+ {
+ $service = new Facebook(
+ $this->getMock('\\OAuth\\Common\\Consumer\\CredentialsInterface'),
+ $this->getMock('\\OAuth\\Common\\Http\\Client\\ClientInterface'),
+ $this->getMock('\\OAuth\\Common\\Storage\\TokenStorageInterface')
+ );
+
+ $this->assertSame('https://www.facebook.com/dialog/oauth', $service->getAuthorizationEndpoint()->getAbsoluteUri());
+ }
+
+ /**
+ * @covers OAuth\OAuth2\Service\Facebook::__construct
+ * @covers OAuth\OAuth2\Service\Facebook::getAccessTokenEndpoint
+ */
+ public function testGetAccessTokenEndpoint()
+ {
+ $service = new Facebook(
+ $this->getMock('\\OAuth\\Common\\Consumer\\CredentialsInterface'),
+ $this->getMock('\\OAuth\\Common\\Http\\Client\\ClientInterface'),
+ $this->getMock('\\OAuth\\Common\\Storage\\TokenStorageInterface')
+ );
+
+ $this->assertSame('https://graph.facebook.com/oauth/access_token', $service->getAccessTokenEndpoint()->getAbsoluteUri());
+ }
+
+ /**
+ * @covers OAuth\OAuth2\Service\Facebook::__construct
+ */
+ public function testGetAuthorizationMethod()
+ {
+ $client = $this->getMock('\\OAuth\\Common\\Http\\Client\\ClientInterface');
+ $client->expects($this->once())->method('retrieveResponse')->will($this->returnArgument(2));
+
+ $token = $this->getMock('\\OAuth\\OAuth2\\Token\\TokenInterface');
+ $token->expects($this->once())->method('getEndOfLife')->will($this->returnValue(TokenInterface::EOL_NEVER_EXPIRES));
+ $token->expects($this->once())->method('getAccessToken')->will($this->returnValue('foo'));
+
+ $storage = $this->getMock('\\OAuth\\Common\\Storage\\TokenStorageInterface');
+ $storage->expects($this->once())->method('retrieveAccessToken')->will($this->returnValue($token));
+
+ $service = new Facebook(
+ $this->getMock('\\OAuth\\Common\\Consumer\\CredentialsInterface'),
+ $client,
+ $storage
+ );
+
+ $headers = $service->request('https://pieterhordijk.com/my/awesome/path');
+
+ $this->assertTrue(array_key_exists('Authorization', $headers));
+ $this->assertTrue(in_array('OAuth foo', $headers, true));
+ }
+
+ /**
+ * @covers OAuth\OAuth2\Service\Facebook::__construct
+ * @covers OAuth\OAuth2\Service\Facebook::parseAccessTokenResponse
+ */
+ public function testParseAccessTokenResponseThrowsExceptionOnError()
+ {
+ $client = $this->getMock('\\OAuth\\Common\\Http\\Client\\ClientInterface');
+ $client->expects($this->once())->method('retrieveResponse')->will($this->returnValue('error=some_error'));
+
+ $service = new Facebook(
+ $this->getMock('\\OAuth\\Common\\Consumer\\CredentialsInterface'),
+ $client,
+ $this->getMock('\\OAuth\\Common\\Storage\\TokenStorageInterface')
+ );
+
+ $this->setExpectedException('\\OAuth\\Common\\Http\\Exception\\TokenResponseException');
+
+ $service->requestAccessToken('foo');
+ }
+
+ /**
+ * @covers OAuth\OAuth2\Service\Facebook::__construct
+ * @covers OAuth\OAuth2\Service\Facebook::parseAccessTokenResponse
+ */
+ public function testParseAccessTokenResponseValidWithoutRefreshToken()
+ {
+ $client = $this->getMock('\\OAuth\\Common\\Http\\Client\\ClientInterface');
+ $client->expects($this->once())->method('retrieveResponse')->will($this->returnValue('access_token=foo&expires=bar'));
+
+ $service = new Facebook(
+ $this->getMock('\\OAuth\\Common\\Consumer\\CredentialsInterface'),
+ $client,
+ $this->getMock('\\OAuth\\Common\\Storage\\TokenStorageInterface')
+ );
+
+ $this->assertInstanceOf('\\OAuth\\OAuth2\\Token\\StdOAuth2Token', $service->requestAccessToken('foo'));
+ }
+
+ /**
+ * @covers OAuth\OAuth2\Service\Facebook::__construct
+ * @covers OAuth\OAuth2\Service\Facebook::parseAccessTokenResponse
+ */
+ public function testParseAccessTokenResponseValidWithRefreshToken()
+ {
+ $client = $this->getMock('\\OAuth\\Common\\Http\\Client\\ClientInterface');
+ $client->expects($this->once())->method('retrieveResponse')->will($this->returnValue('access_token=foo&expires=bar&refresh_token=baz'));
+
+ $service = new Facebook(
+ $this->getMock('\\OAuth\\Common\\Consumer\\CredentialsInterface'),
+ $client,
+ $this->getMock('\\OAuth\\Common\\Storage\\TokenStorageInterface')
+ );
+
+ $this->assertInstanceOf('\\OAuth\\OAuth2\\Token\\StdOAuth2Token', $service->requestAccessToken('foo'));
+ }
+
+ /**
+ * @covers OAuth\OAuth2\Service\Facebook::__construct
+ * @covers OAuth\OAuth2\Service\Facebook::getDialogUri
+ */
+ public function testGetDialogUriRedirectUriMissing()
+ {
+ $client = $this->getMock('\\OAuth\\Common\\Http\\Client\\ClientInterface');
+
+ $service = new Facebook(
+ $this->getMock('\\OAuth\\Common\\Consumer\\CredentialsInterface'),
+ $client,
+ $this->getMock('\\OAuth\\Common\\Storage\\TokenStorageInterface')
+ );
+
+ $this->setExpectedException('\\OAuth\\Common\\Exception\\Exception');
+
+ $service->getDialogUri('feed', array());
+ }
+
+ /**
+ * @covers OAuth\OAuth2\Service\Facebook::__construct
+ * @covers OAuth\OAuth2\Service\Facebook::getDialogUri
+ */
+ public function testGetDialogUriInstanceofUri()
+ {
+ $client = $this->getMock('\\OAuth\\Common\\Http\\Client\\ClientInterface');
+
+ $service = new Facebook(
+ $this->getMock('\\OAuth\\Common\\Consumer\\CredentialsInterface'),
+ $client,
+ $this->getMock('\\OAuth\\Common\\Storage\\TokenStorageInterface')
+ );
+
+ $dialogUri = $service->getDialogUri(
+ 'feed',
+ array(
+ 'redirect_uri' => 'http://www.facebook.com',
+ 'state' => 'Random state'
+ )
+ );
+ $this->assertInstanceOf('\\OAuth\\Common\\Http\\Uri\\Uri',$dialogUri);
+ }
+
+ /**
+ * @covers OAuth\OAuth2\Service\Facebook::__construct
+ * @covers OAuth\OAuth2\Service\Facebook::getDialogUri
+ */
+ public function testGetDialogUriContainsAppIdAndOtherParameters()
+ {
+ $client = $this->getMock('\\OAuth\\Common\\Http\\Client\\ClientInterface');
+ $credentials = $this->getMock('\\OAuth\\Common\\Consumer\\CredentialsInterface');
+ $credentials->expects($this->any())->method('getConsumerId')->will($this->returnValue('application_id'));
+
+
+ $service = new Facebook(
+ $credentials,
+ $client,
+ $this->getMock('\\OAuth\\Common\\Storage\\TokenStorageInterface')
+ );
+
+ $dialogUri = $service->getDialogUri(
+ 'feed',
+ array(
+ 'redirect_uri' => 'http://www.facebook.com',
+ 'state' => 'Random state'
+ )
+ );
+
+ $queryString = $dialogUri->getQuery();
+ parse_str($queryString, $queryArray);
+
+ $this->assertArrayHasKey('app_id', $queryArray);
+ $this->assertArrayHasKey('redirect_uri', $queryArray);
+ $this->assertArrayHasKey('state', $queryArray);
+ }
+}
diff --git a/vendor/lusitanian/oauth/tests/Unit/OAuth2/Service/FoursquareTest.php b/vendor/lusitanian/oauth/tests/Unit/OAuth2/Service/FoursquareTest.php
new file mode 100644
index 00000000..96356ec5
--- /dev/null
+++ b/vendor/lusitanian/oauth/tests/Unit/OAuth2/Service/FoursquareTest.php
@@ -0,0 +1,197 @@
+getMock('\\OAuth\\Common\\Consumer\\CredentialsInterface'),
+ $this->getMock('\\OAuth\\Common\\Http\\Client\\ClientInterface'),
+ $this->getMock('\\OAuth\\Common\\Storage\\TokenStorageInterface')
+ );
+
+ $this->assertInstanceOf('\\OAuth\\OAuth2\\Service\\ServiceInterface', $service);
+ }
+
+ /**
+ * @covers OAuth\OAuth2\Service\Foursquare::__construct
+ */
+ public function testConstructCorrectInstanceWithoutCustomUri()
+ {
+ $service = new Foursquare(
+ $this->getMock('\\OAuth\\Common\\Consumer\\CredentialsInterface'),
+ $this->getMock('\\OAuth\\Common\\Http\\Client\\ClientInterface'),
+ $this->getMock('\\OAuth\\Common\\Storage\\TokenStorageInterface')
+ );
+
+ $this->assertInstanceOf('\\OAuth\\OAuth2\\Service\\AbstractService', $service);
+ }
+
+ /**
+ * @covers OAuth\OAuth2\Service\Foursquare::__construct
+ */
+ public function testConstructCorrectInstanceWithCustomUri()
+ {
+ $service = new Foursquare(
+ $this->getMock('\\OAuth\\Common\\Consumer\\CredentialsInterface'),
+ $this->getMock('\\OAuth\\Common\\Http\\Client\\ClientInterface'),
+ $this->getMock('\\OAuth\\Common\\Storage\\TokenStorageInterface'),
+ array(),
+ $this->getMock('\\OAuth\\Common\\Http\\Uri\\UriInterface')
+ );
+
+ $this->assertInstanceOf('\\OAuth\\OAuth2\\Service\\AbstractService', $service);
+ }
+
+ /**
+ * @covers OAuth\OAuth2\Service\Foursquare::__construct
+ * @covers OAuth\OAuth2\Service\Foursquare::getAuthorizationEndpoint
+ */
+ public function testGetAuthorizationEndpoint()
+ {
+ $service = new Foursquare(
+ $this->getMock('\\OAuth\\Common\\Consumer\\CredentialsInterface'),
+ $this->getMock('\\OAuth\\Common\\Http\\Client\\ClientInterface'),
+ $this->getMock('\\OAuth\\Common\\Storage\\TokenStorageInterface')
+ );
+
+ $this->assertSame('https://foursquare.com/oauth2/authenticate', $service->getAuthorizationEndpoint()->getAbsoluteUri());
+ }
+
+ /**
+ * @covers OAuth\OAuth2\Service\Foursquare::__construct
+ * @covers OAuth\OAuth2\Service\Foursquare::getAccessTokenEndpoint
+ */
+ public function testGetAccessTokenEndpoint()
+ {
+ $service = new Foursquare(
+ $this->getMock('\\OAuth\\Common\\Consumer\\CredentialsInterface'),
+ $this->getMock('\\OAuth\\Common\\Http\\Client\\ClientInterface'),
+ $this->getMock('\\OAuth\\Common\\Storage\\TokenStorageInterface')
+ );
+
+ $this->assertSame('https://foursquare.com/oauth2/access_token', $service->getAccessTokenEndpoint()->getAbsoluteUri());
+ }
+
+ /**
+ * @covers OAuth\OAuth2\Service\Foursquare::__construct
+ * @covers OAuth\OAuth2\Service\Foursquare::getAuthorizationMethod
+ */
+ public function testGetAuthorizationMethod()
+ {
+ $client = $this->getMock('\\OAuth\\Common\\Http\\Client\\ClientInterface');
+ $client->expects($this->once())->method('retrieveResponse')->will($this->returnArgument(2));
+
+ $token = $this->getMock('\\OAuth\\OAuth2\\Token\\TokenInterface');
+ $token->expects($this->once())->method('getEndOfLife')->will($this->returnValue(TokenInterface::EOL_NEVER_EXPIRES));
+ $token->expects($this->once())->method('getAccessToken')->will($this->returnValue('foo'));
+
+ $storage = $this->getMock('\\OAuth\\Common\\Storage\\TokenStorageInterface');
+ $storage->expects($this->once())->method('retrieveAccessToken')->will($this->returnValue($token));
+
+ $service = new Foursquare(
+ $this->getMock('\\OAuth\\Common\\Consumer\\CredentialsInterface'),
+ $client,
+ $storage
+ );
+
+ $headers = $service->request('https://pieterhordijk.com/my/awesome/path');
+
+ $this->assertTrue(array_key_exists('Authorization', $headers));
+ $this->assertTrue(in_array('OAuth foo', $headers, true));
+ }
+
+ /**
+ * @covers OAuth\OAuth2\Service\Foursquare::__construct
+ * @covers OAuth\OAuth2\Service\Foursquare::parseAccessTokenResponse
+ */
+ public function testParseAccessTokenResponseThrowsExceptionOnNulledResponse()
+ {
+ $client = $this->getMock('\\OAuth\\Common\\Http\\Client\\ClientInterface');
+ $client->expects($this->once())->method('retrieveResponse')->will($this->returnValue(null));
+
+ $service = new Foursquare(
+ $this->getMock('\\OAuth\\Common\\Consumer\\CredentialsInterface'),
+ $client,
+ $this->getMock('\\OAuth\\Common\\Storage\\TokenStorageInterface')
+ );
+
+ $this->setExpectedException('\\OAuth\\Common\\Http\\Exception\\TokenResponseException');
+
+ $service->requestAccessToken('foo');
+ }
+
+ /**
+ * @covers OAuth\OAuth2\Service\Foursquare::__construct
+ * @covers OAuth\OAuth2\Service\Foursquare::parseAccessTokenResponse
+ */
+ public function testParseAccessTokenResponseThrowsExceptionOnError()
+ {
+ $client = $this->getMock('\\OAuth\\Common\\Http\\Client\\ClientInterface');
+ $client->expects($this->once())->method('retrieveResponse')->will($this->returnValue('{"error":"some_error"}'));
+
+ $service = new Foursquare(
+ $this->getMock('\\OAuth\\Common\\Consumer\\CredentialsInterface'),
+ $client,
+ $this->getMock('\\OAuth\\Common\\Storage\\TokenStorageInterface')
+ );
+
+ $this->setExpectedException('\\OAuth\\Common\\Http\\Exception\\TokenResponseException');
+
+ $service->requestAccessToken('foo');
+ }
+
+ /**
+ * @covers OAuth\OAuth2\Service\Foursquare::__construct
+ * @covers OAuth\OAuth2\Service\Foursquare::parseAccessTokenResponse
+ */
+ public function testParseAccessTokenResponseValidWithoutRefreshToken()
+ {
+ $client = $this->getMock('\\OAuth\\Common\\Http\\Client\\ClientInterface');
+ $client->expects($this->once())->method('retrieveResponse')->will($this->returnValue('{"access_token":"foo","expires_in":"bar"}'));
+
+ $service = new Foursquare(
+ $this->getMock('\\OAuth\\Common\\Consumer\\CredentialsInterface'),
+ $client,
+ $this->getMock('\\OAuth\\Common\\Storage\\TokenStorageInterface')
+ );
+
+ $this->assertInstanceOf('\\OAuth\\OAuth2\\Token\\StdOAuth2Token', $service->requestAccessToken('foo'));
+ }
+
+ /**
+ * @covers OAuth\OAuth2\Service\Foursquare::__construct
+ * @covers OAuth\OAuth2\Service\Foursquare::request
+ */
+ public function testRequest()
+ {
+ $client = $this->getMock('\\OAuth\\Common\\Http\\Client\\ClientInterface');
+ $client->expects($this->once())->method('retrieveResponse')->will($this->returnArgument(0));
+
+ $token = $this->getMock('\\OAuth\\OAuth2\\Token\\TokenInterface');
+ $token->expects($this->once())->method('getEndOfLife')->will($this->returnValue(TokenInterface::EOL_NEVER_EXPIRES));
+ $token->expects($this->once())->method('getAccessToken')->will($this->returnValue('foo'));
+
+ $storage = $this->getMock('\\OAuth\\Common\\Storage\\TokenStorageInterface');
+ $storage->expects($this->once())->method('retrieveAccessToken')->will($this->returnValue($token));
+
+ $service = new Foursquare(
+ $this->getMock('\\OAuth\\Common\\Consumer\\CredentialsInterface'),
+ $client,
+ $storage
+ );
+
+ $this->assertSame(
+ 'https://api.foursquare.com/v2/https://pieterhordijk.com/my/awesome/path?v=20130829',
+ $service->request('https://pieterhordijk.com/my/awesome/path')->getAbsoluteUri()
+ );
+ }
+}
diff --git a/vendor/lusitanian/oauth/tests/Unit/OAuth2/Service/GitHubTest.php b/vendor/lusitanian/oauth/tests/Unit/OAuth2/Service/GitHubTest.php
new file mode 100644
index 00000000..edb0fee3
--- /dev/null
+++ b/vendor/lusitanian/oauth/tests/Unit/OAuth2/Service/GitHubTest.php
@@ -0,0 +1,220 @@
+getMock('\\OAuth\\Common\\Consumer\\CredentialsInterface'),
+ $this->getMock('\\OAuth\\Common\\Http\\Client\\ClientInterface'),
+ $this->getMock('\\OAuth\\Common\\Storage\\TokenStorageInterface')
+ );
+
+ $this->assertInstanceOf('\\OAuth\\OAuth2\\Service\\ServiceInterface', $service);
+ }
+
+ /**
+ * @covers OAuth\OAuth2\Service\GitHub::__construct
+ */
+ public function testConstructCorrectInstanceWithoutCustomUri()
+ {
+ $service = new GitHub(
+ $this->getMock('\\OAuth\\Common\\Consumer\\CredentialsInterface'),
+ $this->getMock('\\OAuth\\Common\\Http\\Client\\ClientInterface'),
+ $this->getMock('\\OAuth\\Common\\Storage\\TokenStorageInterface')
+ );
+
+ $this->assertInstanceOf('\\OAuth\\OAuth2\\Service\\AbstractService', $service);
+ }
+
+ /**
+ * @covers OAuth\OAuth2\Service\GitHub::__construct
+ */
+ public function testConstructCorrectInstanceWithCustomUri()
+ {
+ $service = new GitHub(
+ $this->getMock('\\OAuth\\Common\\Consumer\\CredentialsInterface'),
+ $this->getMock('\\OAuth\\Common\\Http\\Client\\ClientInterface'),
+ $this->getMock('\\OAuth\\Common\\Storage\\TokenStorageInterface'),
+ array(),
+ $this->getMock('\\OAuth\\Common\\Http\\Uri\\UriInterface')
+ );
+
+ $this->assertInstanceOf('\\OAuth\\OAuth2\\Service\\AbstractService', $service);
+ }
+
+ /**
+ * @covers OAuth\OAuth2\Service\GitHub::__construct
+ * @covers OAuth\OAuth2\Service\GitHub::getAuthorizationEndpoint
+ */
+ public function testGetAuthorizationEndpoint()
+ {
+ $service = new GitHub(
+ $this->getMock('\\OAuth\\Common\\Consumer\\CredentialsInterface'),
+ $this->getMock('\\OAuth\\Common\\Http\\Client\\ClientInterface'),
+ $this->getMock('\\OAuth\\Common\\Storage\\TokenStorageInterface')
+ );
+
+ $this->assertSame('https://github.com/login/oauth/authorize', $service->getAuthorizationEndpoint()->getAbsoluteUri());
+ }
+
+ /**
+ * @covers OAuth\OAuth2\Service\GitHub::__construct
+ * @covers OAuth\OAuth2\Service\GitHub::getAccessTokenEndpoint
+ */
+ public function testGetAccessTokenEndpoint()
+ {
+ $service = new GitHub(
+ $this->getMock('\\OAuth\\Common\\Consumer\\CredentialsInterface'),
+ $this->getMock('\\OAuth\\Common\\Http\\Client\\ClientInterface'),
+ $this->getMock('\\OAuth\\Common\\Storage\\TokenStorageInterface')
+ );
+
+ $this->assertSame('https://github.com/login/oauth/access_token', $service->getAccessTokenEndpoint()->getAbsoluteUri());
+ }
+
+ /**
+ * @covers OAuth\OAuth2\Service\GitHub::__construct
+ * @covers OAuth\OAuth2\Service\GitHub::getAuthorizationMethod
+ */
+ public function testGetAuthorizationMethod()
+ {
+ $client = $this->getMock('\\OAuth\\Common\\Http\\Client\\ClientInterface');
+ $client->expects($this->once())->method('retrieveResponse')->will($this->returnArgument(0));
+
+ $token = $this->getMock('\\OAuth\\OAuth2\\Token\\TokenInterface');
+ $token->expects($this->once())->method('getEndOfLife')->will($this->returnValue(TokenInterface::EOL_NEVER_EXPIRES));
+ $token->expects($this->once())->method('getAccessToken')->will($this->returnValue('foo'));
+
+ $storage = $this->getMock('\\OAuth\\Common\\Storage\\TokenStorageInterface');
+ $storage->expects($this->once())->method('retrieveAccessToken')->will($this->returnValue($token));
+
+ $service = new GitHub(
+ $this->getMock('\\OAuth\\Common\\Consumer\\CredentialsInterface'),
+ $client,
+ $storage
+ );
+
+ $uri = $service->request('https://pieterhordijk.com/my/awesome/path');
+ $absoluteUri = parse_url($uri->getAbsoluteUri());
+
+ $this->assertSame('access_token=foo', $absoluteUri['query']);
+ }
+
+ /**
+ * @covers OAuth\OAuth2\Service\GitHub::__construct
+ * @covers OAuth\OAuth2\Service\GitHub::parseAccessTokenResponse
+ */
+ public function testParseAccessTokenResponseThrowsExceptionOnNulledResponse()
+ {
+ $client = $this->getMock('\\OAuth\\Common\\Http\\Client\\ClientInterface');
+ $client->expects($this->once())->method('retrieveResponse')->will($this->returnValue(null));
+
+ $service = new GitHub(
+ $this->getMock('\\OAuth\\Common\\Consumer\\CredentialsInterface'),
+ $client,
+ $this->getMock('\\OAuth\\Common\\Storage\\TokenStorageInterface')
+ );
+
+ $this->setExpectedException('\\OAuth\\Common\\Http\\Exception\\TokenResponseException');
+
+ $service->requestAccessToken('foo');
+ }
+
+ /**
+ * @covers OAuth\OAuth2\Service\GitHub::__construct
+ * @covers OAuth\OAuth2\Service\GitHub::parseAccessTokenResponse
+ */
+ public function testParseAccessTokenResponseThrowsExceptionOnError()
+ {
+ $client = $this->getMock('\\OAuth\\Common\\Http\\Client\\ClientInterface');
+ $client->expects($this->once())->method('retrieveResponse')->will($this->returnValue('{"error":"some_error"}'));
+
+ $service = new GitHub(
+ $this->getMock('\\OAuth\\Common\\Consumer\\CredentialsInterface'),
+ $client,
+ $this->getMock('\\OAuth\\Common\\Storage\\TokenStorageInterface')
+ );
+
+ $this->setExpectedException('\\OAuth\\Common\\Http\\Exception\\TokenResponseException');
+
+ $service->requestAccessToken('foo');
+ }
+
+ /**
+ * @covers OAuth\OAuth2\Service\GitHub::__construct
+ * @covers OAuth\OAuth2\Service\GitHub::parseAccessTokenResponse
+ */
+ public function testParseAccessTokenResponseValidWithoutRefreshToken()
+ {
+ $client = $this->getMock('\\OAuth\\Common\\Http\\Client\\ClientInterface');
+ $client->expects($this->once())->method('retrieveResponse')->will($this->returnValue('{"access_token":"foo","expires_in":"bar"}'));
+
+ $service = new GitHub(
+ $this->getMock('\\OAuth\\Common\\Consumer\\CredentialsInterface'),
+ $client,
+ $this->getMock('\\OAuth\\Common\\Storage\\TokenStorageInterface')
+ );
+
+ $this->assertInstanceOf('\\OAuth\\OAuth2\\Token\\StdOAuth2Token', $service->requestAccessToken('foo'));
+ }
+
+ /**
+ * @covers OAuth\OAuth2\Service\GitHub::__construct
+ * @covers OAuth\OAuth2\Service\GitHub::getExtraOAuthHeaders
+ */
+ public function testGetExtraOAuthHeaders()
+ {
+ $client = $this->getMock('\\OAuth\\Common\\Http\\Client\\ClientInterface');
+ $client->expects($this->once())->method('retrieveResponse')->will($this->returnCallback(function($uri, $params, $extraHeaders) {
+ \PHPUnit_Framework_Assert::assertTrue(array_key_exists('Accept', $extraHeaders));
+ \PHPUnit_Framework_Assert::assertTrue(in_array('application/json', $extraHeaders, true));
+
+ return '{"access_token":"foo","expires_in":"bar"}';
+ }));
+
+ $service = new GitHub(
+ $this->getMock('\\OAuth\\Common\\Consumer\\CredentialsInterface'),
+ $client,
+ $this->getMock('\\OAuth\\Common\\Storage\\TokenStorageInterface')
+ );
+
+ $this->assertInstanceOf('\\OAuth\\OAuth2\\Token\\StdOAuth2Token', $service->requestAccessToken('foo'));
+ }
+
+ /**
+ * @covers OAuth\OAuth2\Service\GitHub::__construct
+ * @covers OAuth\OAuth2\Service\GitHub::getExtraApiHeaders
+ */
+ public function testGetExtraApiHeaders()
+ {
+ $client = $this->getMock('\\OAuth\\Common\\Http\\Client\\ClientInterface');
+ $client->expects($this->once())->method('retrieveResponse')->will($this->returnArgument(2));
+
+ $token = $this->getMock('\\OAuth\\OAuth2\\Token\\TokenInterface');
+ $token->expects($this->once())->method('getEndOfLife')->will($this->returnValue(TokenInterface::EOL_NEVER_EXPIRES));
+ $token->expects($this->once())->method('getAccessToken')->will($this->returnValue('foo'));
+
+ $storage = $this->getMock('\\OAuth\\Common\\Storage\\TokenStorageInterface');
+ $storage->expects($this->once())->method('retrieveAccessToken')->will($this->returnValue($token));
+
+ $service = new GitHub(
+ $this->getMock('\\OAuth\\Common\\Consumer\\CredentialsInterface'),
+ $client,
+ $storage
+ );
+
+ $headers = $service->request('https://pieterhordijk.com/my/awesome/path');
+
+ $this->assertTrue(array_key_exists('Accept', $headers));
+ $this->assertSame('application/vnd.github.beta+json', $headers['Accept']);
+ }
+}
diff --git a/vendor/lusitanian/oauth/tests/Unit/OAuth2/Service/GoogleTest.php b/vendor/lusitanian/oauth/tests/Unit/OAuth2/Service/GoogleTest.php
new file mode 100644
index 00000000..b55808d2
--- /dev/null
+++ b/vendor/lusitanian/oauth/tests/Unit/OAuth2/Service/GoogleTest.php
@@ -0,0 +1,195 @@
+getMock('\\OAuth\\Common\\Consumer\\CredentialsInterface'),
+ $this->getMock('\\OAuth\\Common\\Http\\Client\\ClientInterface'),
+ $this->getMock('\\OAuth\\Common\\Storage\\TokenStorageInterface')
+ );
+
+ $this->assertInstanceOf('\\OAuth\\OAuth2\\Service\\ServiceInterface', $service);
+ }
+
+ /**
+ * @covers OAuth\OAuth2\Service\Google::__construct
+ */
+ public function testConstructCorrectInstanceWithoutCustomUri()
+ {
+ $service = new Google(
+ $this->getMock('\\OAuth\\Common\\Consumer\\CredentialsInterface'),
+ $this->getMock('\\OAuth\\Common\\Http\\Client\\ClientInterface'),
+ $this->getMock('\\OAuth\\Common\\Storage\\TokenStorageInterface')
+ );
+
+ $this->assertInstanceOf('\\OAuth\\OAuth2\\Service\\AbstractService', $service);
+ }
+
+ /**
+ * @covers OAuth\OAuth2\Service\Google::__construct
+ */
+ public function testConstructCorrectInstanceWithCustomUri()
+ {
+ $service = new Google(
+ $this->getMock('\\OAuth\\Common\\Consumer\\CredentialsInterface'),
+ $this->getMock('\\OAuth\\Common\\Http\\Client\\ClientInterface'),
+ $this->getMock('\\OAuth\\Common\\Storage\\TokenStorageInterface'),
+ array(),
+ $this->getMock('\\OAuth\\Common\\Http\\Uri\\UriInterface')
+ );
+
+ $this->assertInstanceOf('\\OAuth\\OAuth2\\Service\\AbstractService', $service);
+ }
+
+ /**
+ * @covers OAuth\OAuth2\Service\Google::__construct
+ * @covers OAuth\OAuth2\Service\Google::getAuthorizationEndpoint
+ */
+ public function testGetAuthorizationEndpoint()
+ {
+ $service = new Google(
+ $this->getMock('\\OAuth\\Common\\Consumer\\CredentialsInterface'),
+ $this->getMock('\\OAuth\\Common\\Http\\Client\\ClientInterface'),
+ $this->getMock('\\OAuth\\Common\\Storage\\TokenStorageInterface')
+ );
+
+ $this->assertSame(
+ 'https://accounts.google.com/o/oauth2/auth?access_type=online',
+ $service->getAuthorizationEndpoint()->getAbsoluteUri()
+ );
+
+ // Verify that 'offine' works
+ $service->setAccessType('offline');
+ $this->assertSame(
+ 'https://accounts.google.com/o/oauth2/auth?access_type=offline',
+ $service->getAuthorizationEndpoint()->getAbsoluteUri()
+ );
+
+ }
+
+ /**
+ * @covers OAuth\OAuth2\Service\Google::__construct
+ * @covers OAuth\OAuth2\Service\Google::getAuthorizationEndpoint
+ */
+ public function testGetAuthorizationEndpointException()
+ {
+ $service = new Google(
+ $this->getMock('\\OAuth\\Common\\Consumer\\CredentialsInterface'),
+ $this->getMock('\\OAuth\\Common\\Http\\Client\\ClientInterface'),
+ $this->getMock('\\OAuth\\Common\\Storage\\TokenStorageInterface')
+ );
+
+ $this->setExpectedException('OAuth\OAuth2\Service\Exception\InvalidAccessTypeException');
+
+ try {
+ $service->setAccessType('invalid');
+ } catch (InvalidAccessTypeException $e) {
+ return;
+ }
+ $this->fail('Expected InvalidAccessTypeException not thrown');
+ }
+
+ /**
+ * @covers OAuth\OAuth2\Service\Google::__construct
+ * @covers OAuth\OAuth2\Service\Google::getAccessTokenEndpoint
+ */
+ public function testGetAccessTokenEndpoint()
+ {
+ $service = new Google(
+ $this->getMock('\\OAuth\\Common\\Consumer\\CredentialsInterface'),
+ $this->getMock('\\OAuth\\Common\\Http\\Client\\ClientInterface'),
+ $this->getMock('\\OAuth\\Common\\Storage\\TokenStorageInterface')
+ );
+
+ $this->assertSame(
+ 'https://accounts.google.com/o/oauth2/token',
+ $service->getAccessTokenEndpoint()->getAbsoluteUri()
+ );
+ }
+
+ /**
+ * @covers OAuth\OAuth2\Service\Google::__construct
+ * @covers OAuth\OAuth2\Service\Google::parseAccessTokenResponse
+ */
+ public function testParseAccessTokenResponseThrowsExceptionOnNulledResponse()
+ {
+ $client = $this->getMock('\\OAuth\\Common\\Http\\Client\\ClientInterface');
+ $client->expects($this->once())->method('retrieveResponse')->will($this->returnValue(null));
+
+ $service = new Google(
+ $this->getMock('\\OAuth\\Common\\Consumer\\CredentialsInterface'),
+ $client,
+ $this->getMock('\\OAuth\\Common\\Storage\\TokenStorageInterface')
+ );
+
+ $this->setExpectedException('\\OAuth\\Common\\Http\\Exception\\TokenResponseException');
+
+ $service->requestAccessToken('foo');
+ }
+
+ /**
+ * @covers OAuth\OAuth2\Service\Google::__construct
+ * @covers OAuth\OAuth2\Service\Google::parseAccessTokenResponse
+ */
+ public function testParseAccessTokenResponseThrowsExceptionOnError()
+ {
+ $client = $this->getMock('\\OAuth\\Common\\Http\\Client\\ClientInterface');
+ $client->expects($this->once())->method('retrieveResponse')->will($this->returnValue('error=some_error'));
+
+ $service = new Google(
+ $this->getMock('\\OAuth\\Common\\Consumer\\CredentialsInterface'),
+ $client,
+ $this->getMock('\\OAuth\\Common\\Storage\\TokenStorageInterface')
+ );
+
+ $this->setExpectedException('\\OAuth\\Common\\Http\\Exception\\TokenResponseException');
+
+ $service->requestAccessToken('foo');
+ }
+
+ /**
+ * @covers OAuth\OAuth2\Service\Google::__construct
+ * @covers OAuth\OAuth2\Service\Google::parseAccessTokenResponse
+ */
+ public function testParseAccessTokenResponseValidWithoutRefreshToken()
+ {
+ $client = $this->getMock('\\OAuth\\Common\\Http\\Client\\ClientInterface');
+ $client->expects($this->once())->method('retrieveResponse')->will($this->returnValue('{"access_token":"foo","expires_in":"bar"}'));
+
+ $service = new Google(
+ $this->getMock('\\OAuth\\Common\\Consumer\\CredentialsInterface'),
+ $client,
+ $this->getMock('\\OAuth\\Common\\Storage\\TokenStorageInterface')
+ );
+
+ $this->assertInstanceOf('\\OAuth\\OAuth2\\Token\\StdOAuth2Token', $service->requestAccessToken('foo'));
+ }
+
+ /**
+ * @covers OAuth\OAuth2\Service\Google::__construct
+ * @covers OAuth\OAuth2\Service\Google::parseAccessTokenResponse
+ */
+ public function testParseAccessTokenResponseValidWithRefreshToken()
+ {
+ $client = $this->getMock('\\OAuth\\Common\\Http\\Client\\ClientInterface');
+ $client->expects($this->once())->method('retrieveResponse')->will($this->returnValue('{"access_token":"foo","expires_in":"bar","refresh_token":"baz"}'));
+
+ $service = new Google(
+ $this->getMock('\\OAuth\\Common\\Consumer\\CredentialsInterface'),
+ $client,
+ $this->getMock('\\OAuth\\Common\\Storage\\TokenStorageInterface')
+ );
+
+ $this->assertInstanceOf('\\OAuth\\OAuth2\\Token\\StdOAuth2Token', $service->requestAccessToken('foo'));
+ }
+}
diff --git a/vendor/lusitanian/oauth/tests/Unit/OAuth2/Service/HerokuTest.php b/vendor/lusitanian/oauth/tests/Unit/OAuth2/Service/HerokuTest.php
new file mode 100644
index 00000000..cc2c0f69
--- /dev/null
+++ b/vendor/lusitanian/oauth/tests/Unit/OAuth2/Service/HerokuTest.php
@@ -0,0 +1,261 @@
+getMock('\\OAuth\\Common\\Consumer\\CredentialsInterface'),
+ $this->getMock('\\OAuth\\Common\\Http\\Client\\ClientInterface'),
+ $this->getMock('\\OAuth\\Common\\Storage\\TokenStorageInterface')
+ );
+
+ $this->assertInstanceOf('\\OAuth\\OAuth2\\Service\\ServiceInterface', $service);
+ }
+
+ /**
+ * @covers OAuth\OAuth2\Service\Heroku::__construct
+ */
+ public function testConstructCorrectInstanceWithoutCustomUri()
+ {
+ $service = new Heroku(
+ $this->getMock('\\OAuth\\Common\\Consumer\\CredentialsInterface'),
+ $this->getMock('\\OAuth\\Common\\Http\\Client\\ClientInterface'),
+ $this->getMock('\\OAuth\\Common\\Storage\\TokenStorageInterface')
+ );
+
+ $this->assertInstanceOf('\\OAuth\\OAuth2\\Service\\AbstractService', $service);
+ }
+
+ /**
+ * @covers OAuth\OAuth2\Service\Heroku::__construct
+ */
+ public function testConstructCorrectInstanceWithCustomUri()
+ {
+ $service = new Heroku(
+ $this->getMock('\\OAuth\\Common\\Consumer\\CredentialsInterface'),
+ $this->getMock('\\OAuth\\Common\\Http\\Client\\ClientInterface'),
+ $this->getMock('\\OAuth\\Common\\Storage\\TokenStorageInterface'),
+ array(),
+ $this->getMock('\\OAuth\\Common\\Http\\Uri\\UriInterface')
+ );
+
+ $this->assertInstanceOf('\\OAuth\\OAuth2\\Service\\AbstractService', $service);
+ }
+
+ /**
+ * @covers OAuth\OAuth2\Service\Heroku::__construct
+ * @covers OAuth\OAuth2\Service\Heroku::getAuthorizationEndpoint
+ */
+ public function testGetAuthorizationEndpoint()
+ {
+ $service = new Heroku(
+ $this->getMock('\\OAuth\\Common\\Consumer\\CredentialsInterface'),
+ $this->getMock('\\OAuth\\Common\\Http\\Client\\ClientInterface'),
+ $this->getMock('\\OAuth\\Common\\Storage\\TokenStorageInterface')
+ );
+
+ $this->assertSame(
+ 'https://id.heroku.com/oauth/authorize',
+ $service->getAuthorizationEndpoint()->getAbsoluteUri()
+ );
+ }
+
+ /**
+ * @covers OAuth\OAuth2\Service\Heroku::__construct
+ * @covers OAuth\OAuth2\Service\Heroku::getAccessTokenEndpoint
+ */
+ public function testGetAccessTokenEndpoint()
+ {
+ $service = new Heroku(
+ $this->getMock('\\OAuth\\Common\\Consumer\\CredentialsInterface'),
+ $this->getMock('\\OAuth\\Common\\Http\\Client\\ClientInterface'),
+ $this->getMock('\\OAuth\\Common\\Storage\\TokenStorageInterface')
+ );
+
+ $this->assertSame('https://id.heroku.com/oauth/token', $service->getAccessTokenEndpoint()->getAbsoluteUri());
+ }
+
+ /**
+ * @covers OAuth\OAuth2\Service\Heroku::__construct
+ * @covers OAuth\OAuth2\Service\Heroku::getAuthorizationMethod
+ */
+ public function testGetAuthorizationMethod()
+ {
+ $client = $this->getMock('\\OAuth\\Common\\Http\\Client\\ClientInterface');
+ $client->expects($this->once())->method('retrieveResponse')->will($this->returnArgument(2));
+
+ $token = $this->getMock('\\OAuth\\OAuth2\\Token\\TokenInterface');
+ $token->expects($this->once())->method('getEndOfLife')->will($this->returnValue(TokenInterface::EOL_NEVER_EXPIRES));
+ $token->expects($this->once())->method('getAccessToken')->will($this->returnValue('foo'));
+
+ $storage = $this->getMock('\\OAuth\\Common\\Storage\\TokenStorageInterface');
+ $storage->expects($this->once())->method('retrieveAccessToken')->will($this->returnValue($token));
+
+ $service = new Heroku(
+ $this->getMock('\\OAuth\\Common\\Consumer\\CredentialsInterface'),
+ $client,
+ $storage
+ );
+
+ $headers = $service->request('https://pieterhordijk.com/my/awesome/path');
+
+ $this->assertTrue(array_key_exists('Authorization', $headers));
+ $this->assertTrue(in_array('Bearer foo', $headers, true));
+ }
+
+ /**
+ * @covers OAuth\OAuth2\Service\Heroku::__construct
+ * @covers OAuth\OAuth2\Service\Heroku::parseAccessTokenResponse
+ */
+ public function testParseAccessTokenResponseThrowsExceptionOnNulledResponse()
+ {
+ $client = $this->getMock('\\OAuth\\Common\\Http\\Client\\ClientInterface');
+ $client->expects($this->once())->method('retrieveResponse')->will($this->returnValue(null));
+
+ $service = new Heroku(
+ $this->getMock('\\OAuth\\Common\\Consumer\\CredentialsInterface'),
+ $client,
+ $this->getMock('\\OAuth\\Common\\Storage\\TokenStorageInterface')
+ );
+
+ $this->setExpectedException('\\OAuth\\Common\\Http\\Exception\\TokenResponseException');
+
+ $service->requestAccessToken('foo');
+ }
+
+ /**
+ * @covers OAuth\OAuth2\Service\Heroku::__construct
+ * @covers OAuth\OAuth2\Service\Heroku::parseAccessTokenResponse
+ */
+ public function testParseAccessTokenResponseThrowsExceptionOnErrorDescription()
+ {
+ $client = $this->getMock('\\OAuth\\Common\\Http\\Client\\ClientInterface');
+ $client->expects($this->once())->method('retrieveResponse')->will($this->returnValue('error_description=some_error'));
+
+ $service = new Heroku(
+ $this->getMock('\\OAuth\\Common\\Consumer\\CredentialsInterface'),
+ $client,
+ $this->getMock('\\OAuth\\Common\\Storage\\TokenStorageInterface')
+ );
+
+ $this->setExpectedException('\\OAuth\\Common\\Http\\Exception\\TokenResponseException');
+
+ $service->requestAccessToken('foo');
+ }
+
+ /**
+ * @covers OAuth\OAuth2\Service\Heroku::__construct
+ * @covers OAuth\OAuth2\Service\Heroku::parseAccessTokenResponse
+ */
+ public function testParseAccessTokenResponseThrowsExceptionOnError()
+ {
+ $client = $this->getMock('\\OAuth\\Common\\Http\\Client\\ClientInterface');
+ $client->expects($this->once())->method('retrieveResponse')->will($this->returnValue('error=some_error'));
+
+ $service = new Heroku(
+ $this->getMock('\\OAuth\\Common\\Consumer\\CredentialsInterface'),
+ $client,
+ $this->getMock('\\OAuth\\Common\\Storage\\TokenStorageInterface')
+ );
+
+ $this->setExpectedException('\\OAuth\\Common\\Http\\Exception\\TokenResponseException');
+
+ $service->requestAccessToken('foo');
+ }
+
+ /**
+ * @covers OAuth\OAuth2\Service\Heroku::__construct
+ * @covers OAuth\OAuth2\Service\Heroku::parseAccessTokenResponse
+ */
+ public function testParseAccessTokenResponseValidWithoutRefreshToken()
+ {
+ $client = $this->getMock('\\OAuth\\Common\\Http\\Client\\ClientInterface');
+ $client->expects($this->once())->method('retrieveResponse')->will($this->returnValue('{"access_token":"foo","expires_in":"bar"}'));
+
+ $service = new Heroku(
+ $this->getMock('\\OAuth\\Common\\Consumer\\CredentialsInterface'),
+ $client,
+ $this->getMock('\\OAuth\\Common\\Storage\\TokenStorageInterface')
+ );
+
+ $this->assertInstanceOf('\\OAuth\\OAuth2\\Token\\StdOAuth2Token', $service->requestAccessToken('foo'));
+ }
+
+ /**
+ * @covers OAuth\OAuth2\Service\Heroku::__construct
+ * @covers OAuth\OAuth2\Service\Heroku::parseAccessTokenResponse
+ */
+ public function testParseAccessTokenResponseValidWithRefreshToken()
+ {
+ $client = $this->getMock('\\OAuth\\Common\\Http\\Client\\ClientInterface');
+ $client->expects($this->once())->method('retrieveResponse')->will($this->returnValue('{"access_token":"foo","expires_in":"bar","refresh_token":"baz"}'));
+
+ $service = new Heroku(
+ $this->getMock('\\OAuth\\Common\\Consumer\\CredentialsInterface'),
+ $client,
+ $this->getMock('\\OAuth\\Common\\Storage\\TokenStorageInterface')
+ );
+
+ $this->assertInstanceOf('\\OAuth\\OAuth2\\Token\\StdOAuth2Token', $service->requestAccessToken('foo'));
+ }
+
+ /**
+ * @covers OAuth\OAuth2\Service\Heroku::__construct
+ * @covers OAuth\OAuth2\Service\Heroku::getExtraOAuthHeaders
+ */
+ public function testGetExtraOAuthHeaders()
+ {
+ $client = $this->getMock('\\OAuth\\Common\\Http\\Client\\ClientInterface');
+ $client->expects($this->once())->method('retrieveResponse')->will($this->returnCallback(function($uri, $params, $extraHeaders) {
+ \PHPUnit_Framework_Assert::assertTrue(array_key_exists('Accept', $extraHeaders));
+ \PHPUnit_Framework_Assert::assertTrue(in_array('application/vnd.heroku+json; version=3', $extraHeaders, true));
+
+ return '{"access_token":"foo","expires_in":"bar"}';
+ }));
+
+ $service = new Heroku(
+ $this->getMock('\\OAuth\\Common\\Consumer\\CredentialsInterface'),
+ $client,
+ $this->getMock('\\OAuth\\Common\\Storage\\TokenStorageInterface')
+ );
+
+ $this->assertInstanceOf('\\OAuth\\OAuth2\\Token\\StdOAuth2Token', $service->requestAccessToken('foo'));
+ }
+
+ /**
+ * @covers OAuth\OAuth2\Service\Heroku::__construct
+ * @covers OAuth\OAuth2\Service\Heroku::getExtraApiHeaders
+ */
+ public function testGetExtraApiHeaders()
+ {
+ $client = $this->getMock('\\OAuth\\Common\\Http\\Client\\ClientInterface');
+ $client->expects($this->once())->method('retrieveResponse')->will($this->returnArgument(2));
+
+ $token = $this->getMock('\\OAuth\\OAuth2\\Token\\TokenInterface');
+ $token->expects($this->once())->method('getEndOfLife')->will($this->returnValue(TokenInterface::EOL_NEVER_EXPIRES));
+ $token->expects($this->once())->method('getAccessToken')->will($this->returnValue('foo'));
+
+ $storage = $this->getMock('\\OAuth\\Common\\Storage\\TokenStorageInterface');
+ $storage->expects($this->once())->method('retrieveAccessToken')->will($this->returnValue($token));
+
+ $service = new Heroku(
+ $this->getMock('\\OAuth\\Common\\Consumer\\CredentialsInterface'),
+ $client,
+ $storage
+ );
+
+ $headers = $service->request('https://pieterhordijk.com/my/awesome/path');
+
+ $this->assertTrue(array_key_exists('Accept', $headers));
+ $this->assertSame('application/vnd.heroku+json; version=3', $headers['Accept']);
+ }
+}
diff --git a/vendor/lusitanian/oauth/tests/Unit/OAuth2/Service/InstagramTest.php b/vendor/lusitanian/oauth/tests/Unit/OAuth2/Service/InstagramTest.php
new file mode 100644
index 00000000..bf9d764c
--- /dev/null
+++ b/vendor/lusitanian/oauth/tests/Unit/OAuth2/Service/InstagramTest.php
@@ -0,0 +1,193 @@
+getMock('\\OAuth\\Common\\Consumer\\CredentialsInterface'),
+ $this->getMock('\\OAuth\\Common\\Http\\Client\\ClientInterface'),
+ $this->getMock('\\OAuth\\Common\\Storage\\TokenStorageInterface')
+ );
+
+ $this->assertInstanceOf('\\OAuth\\OAuth2\\Service\\ServiceInterface', $service);
+ }
+
+ /**
+ * @covers OAuth\OAuth2\Service\Instagram::__construct
+ */
+ public function testConstructCorrectInstanceWithoutCustomUri()
+ {
+ $service = new Instagram(
+ $this->getMock('\\OAuth\\Common\\Consumer\\CredentialsInterface'),
+ $this->getMock('\\OAuth\\Common\\Http\\Client\\ClientInterface'),
+ $this->getMock('\\OAuth\\Common\\Storage\\TokenStorageInterface')
+ );
+
+ $this->assertInstanceOf('\\OAuth\\OAuth2\\Service\\AbstractService', $service);
+ }
+
+ /**
+ * @covers OAuth\OAuth2\Service\Instagram::__construct
+ */
+ public function testConstructCorrectInstanceWithCustomUri()
+ {
+ $service = new Instagram(
+ $this->getMock('\\OAuth\\Common\\Consumer\\CredentialsInterface'),
+ $this->getMock('\\OAuth\\Common\\Http\\Client\\ClientInterface'),
+ $this->getMock('\\OAuth\\Common\\Storage\\TokenStorageInterface'),
+ array(),
+ $this->getMock('\\OAuth\\Common\\Http\\Uri\\UriInterface')
+ );
+
+ $this->assertInstanceOf('\\OAuth\\OAuth2\\Service\\AbstractService', $service);
+ }
+
+ /**
+ * @covers OAuth\OAuth2\Service\Instagram::__construct
+ * @covers OAuth\OAuth2\Service\Instagram::getAuthorizationEndpoint
+ */
+ public function testGetAuthorizationEndpoint()
+ {
+ $service = new Instagram(
+ $this->getMock('\\OAuth\\Common\\Consumer\\CredentialsInterface'),
+ $this->getMock('\\OAuth\\Common\\Http\\Client\\ClientInterface'),
+ $this->getMock('\\OAuth\\Common\\Storage\\TokenStorageInterface')
+ );
+
+ $this->assertSame(
+ 'https://api.instagram.com/oauth/authorize/',
+ $service->getAuthorizationEndpoint()->getAbsoluteUri()
+ );
+ }
+
+ /**
+ * @covers OAuth\OAuth2\Service\Instagram::__construct
+ * @covers OAuth\OAuth2\Service\Instagram::getAccessTokenEndpoint
+ */
+ public function testGetAccessTokenEndpoint()
+ {
+ $service = new Instagram(
+ $this->getMock('\\OAuth\\Common\\Consumer\\CredentialsInterface'),
+ $this->getMock('\\OAuth\\Common\\Http\\Client\\ClientInterface'),
+ $this->getMock('\\OAuth\\Common\\Storage\\TokenStorageInterface')
+ );
+
+ $this->assertSame(
+ 'https://api.instagram.com/oauth/access_token',
+ $service->getAccessTokenEndpoint()->getAbsoluteUri()
+ );
+ }
+
+ /**
+ * @covers OAuth\OAuth2\Service\Instagram::__construct
+ * @covers OAuth\OAuth2\Service\Instagram::getAuthorizationMethod
+ */
+ public function testGetAuthorizationMethod()
+ {
+ $client = $this->getMock('\\OAuth\\Common\\Http\\Client\\ClientInterface');
+ $client->expects($this->once())->method('retrieveResponse')->will($this->returnArgument(0));
+
+ $token = $this->getMock('\\OAuth\\OAuth2\\Token\\TokenInterface');
+ $token->expects($this->once())->method('getEndOfLife')->will($this->returnValue(TokenInterface::EOL_NEVER_EXPIRES));
+ $token->expects($this->once())->method('getAccessToken')->will($this->returnValue('foo'));
+
+ $storage = $this->getMock('\\OAuth\\Common\\Storage\\TokenStorageInterface');
+ $storage->expects($this->once())->method('retrieveAccessToken')->will($this->returnValue($token));
+
+ $service = new Instagram(
+ $this->getMock('\\OAuth\\Common\\Consumer\\CredentialsInterface'),
+ $client,
+ $storage
+ );
+
+ $uri = $service->request('https://pieterhordijk.com/my/awesome/path');
+ $absoluteUri = parse_url($uri->getAbsoluteUri());
+
+ $this->assertSame('access_token=foo', $absoluteUri['query']);
+ }
+
+ /**
+ * @covers OAuth\OAuth2\Service\Instagram::__construct
+ * @covers OAuth\OAuth2\Service\Instagram::parseAccessTokenResponse
+ */
+ public function testParseAccessTokenResponseThrowsExceptionOnNulledResponse()
+ {
+ $client = $this->getMock('\\OAuth\\Common\\Http\\Client\\ClientInterface');
+ $client->expects($this->once())->method('retrieveResponse')->will($this->returnValue(null));
+
+ $service = new Instagram(
+ $this->getMock('\\OAuth\\Common\\Consumer\\CredentialsInterface'),
+ $client,
+ $this->getMock('\\OAuth\\Common\\Storage\\TokenStorageInterface')
+ );
+
+ $this->setExpectedException('\\OAuth\\Common\\Http\\Exception\\TokenResponseException');
+
+ $service->requestAccessToken('foo');
+ }
+
+ /**
+ * @covers OAuth\OAuth2\Service\Instagram::__construct
+ * @covers OAuth\OAuth2\Service\Instagram::parseAccessTokenResponse
+ */
+ public function testParseAccessTokenResponseThrowsExceptionOnError()
+ {
+ $client = $this->getMock('\\OAuth\\Common\\Http\\Client\\ClientInterface');
+ $client->expects($this->once())->method('retrieveResponse')->will($this->returnValue('error=some_error'));
+
+ $service = new Instagram(
+ $this->getMock('\\OAuth\\Common\\Consumer\\CredentialsInterface'),
+ $client,
+ $this->getMock('\\OAuth\\Common\\Storage\\TokenStorageInterface')
+ );
+
+ $this->setExpectedException('\\OAuth\\Common\\Http\\Exception\\TokenResponseException');
+
+ $service->requestAccessToken('foo');
+ }
+
+ /**
+ * @covers OAuth\OAuth2\Service\Instagram::__construct
+ * @covers OAuth\OAuth2\Service\Instagram::parseAccessTokenResponse
+ */
+ public function testParseAccessTokenResponseValidWithoutRefreshToken()
+ {
+ $client = $this->getMock('\\OAuth\\Common\\Http\\Client\\ClientInterface');
+ $client->expects($this->once())->method('retrieveResponse')->will($this->returnValue('{"access_token":"foo","expires_in":"bar"}'));
+
+ $service = new Instagram(
+ $this->getMock('\\OAuth\\Common\\Consumer\\CredentialsInterface'),
+ $client,
+ $this->getMock('\\OAuth\\Common\\Storage\\TokenStorageInterface')
+ );
+
+ $this->assertInstanceOf('\\OAuth\\OAuth2\\Token\\StdOAuth2Token', $service->requestAccessToken('foo'));
+ }
+
+ /**
+ * @covers OAuth\OAuth2\Service\Instagram::__construct
+ * @covers OAuth\OAuth2\Service\Instagram::parseAccessTokenResponse
+ */
+ public function testParseAccessTokenResponseValidWithRefreshToken()
+ {
+ $client = $this->getMock('\\OAuth\\Common\\Http\\Client\\ClientInterface');
+ $client->expects($this->once())->method('retrieveResponse')->will($this->returnValue('{"access_token":"foo","expires_in":"bar","refresh_token":"baz"}'));
+
+ $service = new Instagram(
+ $this->getMock('\\OAuth\\Common\\Consumer\\CredentialsInterface'),
+ $client,
+ $this->getMock('\\OAuth\\Common\\Storage\\TokenStorageInterface')
+ );
+
+ $this->assertInstanceOf('\\OAuth\\OAuth2\\Token\\StdOAuth2Token', $service->requestAccessToken('foo'));
+ }
+}
diff --git a/vendor/lusitanian/oauth/tests/Unit/OAuth2/Service/LinkedinTest.php b/vendor/lusitanian/oauth/tests/Unit/OAuth2/Service/LinkedinTest.php
new file mode 100644
index 00000000..c7f5c76e
--- /dev/null
+++ b/vendor/lusitanian/oauth/tests/Unit/OAuth2/Service/LinkedinTest.php
@@ -0,0 +1,213 @@
+getMock('\\OAuth\\Common\\Consumer\\CredentialsInterface'),
+ $this->getMock('\\OAuth\\Common\\Http\\Client\\ClientInterface'),
+ $this->getMock('\\OAuth\\Common\\Storage\\TokenStorageInterface')
+ );
+
+ $this->assertInstanceOf('\\OAuth\\OAuth2\\Service\\ServiceInterface', $service);
+ }
+
+ /**
+ * @covers OAuth\OAuth2\Service\Linkedin::__construct
+ */
+ public function testConstructCorrectInstanceWithoutCustomUri()
+ {
+ $service = new Linkedin(
+ $this->getMock('\\OAuth\\Common\\Consumer\\CredentialsInterface'),
+ $this->getMock('\\OAuth\\Common\\Http\\Client\\ClientInterface'),
+ $this->getMock('\\OAuth\\Common\\Storage\\TokenStorageInterface')
+ );
+
+ $this->assertInstanceOf('\\OAuth\\OAuth2\\Service\\AbstractService', $service);
+ }
+
+ /**
+ * @covers OAuth\OAuth2\Service\Linkedin::__construct
+ */
+ public function testConstructCorrectInstanceWithCustomUri()
+ {
+ $service = new Linkedin(
+ $this->getMock('\\OAuth\\Common\\Consumer\\CredentialsInterface'),
+ $this->getMock('\\OAuth\\Common\\Http\\Client\\ClientInterface'),
+ $this->getMock('\\OAuth\\Common\\Storage\\TokenStorageInterface'),
+ array(),
+ $this->getMock('\\OAuth\\Common\\Http\\Uri\\UriInterface')
+ );
+
+ $this->assertInstanceOf('\\OAuth\\OAuth2\\Service\\AbstractService', $service);
+ }
+
+ /**
+ * @covers OAuth\OAuth2\Service\Linkedin::__construct
+ * @covers OAuth\OAuth2\Service\Linkedin::getAuthorizationEndpoint
+ */
+ public function testGetAuthorizationEndpoint()
+ {
+ $service = new Linkedin(
+ $this->getMock('\\OAuth\\Common\\Consumer\\CredentialsInterface'),
+ $this->getMock('\\OAuth\\Common\\Http\\Client\\ClientInterface'),
+ $this->getMock('\\OAuth\\Common\\Storage\\TokenStorageInterface')
+ );
+
+ $this->assertSame(
+ 'https://www.linkedin.com/uas/oauth2/authorization',
+ $service->getAuthorizationEndpoint()->getAbsoluteUri()
+ );
+ }
+
+ /**
+ * @covers OAuth\OAuth2\Service\Linkedin::__construct
+ * @covers OAuth\OAuth2\Service\Linkedin::getAccessTokenEndpoint
+ */
+ public function testGetAccessTokenEndpoint()
+ {
+ $service = new Linkedin(
+ $this->getMock('\\OAuth\\Common\\Consumer\\CredentialsInterface'),
+ $this->getMock('\\OAuth\\Common\\Http\\Client\\ClientInterface'),
+ $this->getMock('\\OAuth\\Common\\Storage\\TokenStorageInterface')
+ );
+
+ $this->assertSame(
+ 'https://www.linkedin.com/uas/oauth2/accessToken',
+ $service->getAccessTokenEndpoint()->getAbsoluteUri()
+ );
+ }
+
+ /**
+ * @covers OAuth\OAuth2\Service\Linkedin::__construct
+ * @covers OAuth\OAuth2\Service\Linkedin::getAuthorizationMethod
+ */
+ public function testGetAuthorizationMethod()
+ {
+ $client = $this->getMock('\\OAuth\\Common\\Http\\Client\\ClientInterface');
+ $client->expects($this->once())->method('retrieveResponse')->will($this->returnArgument(0));
+
+ $token = $this->getMock('\\OAuth\\OAuth2\\Token\\TokenInterface');
+ $token->expects($this->once())->method('getEndOfLife')->will($this->returnValue(TokenInterface::EOL_NEVER_EXPIRES));
+ $token->expects($this->once())->method('getAccessToken')->will($this->returnValue('foo'));
+
+ $storage = $this->getMock('\\OAuth\\Common\\Storage\\TokenStorageInterface');
+ $storage->expects($this->once())->method('retrieveAccessToken')->will($this->returnValue($token));
+
+ $service = new Linkedin(
+ $this->getMock('\\OAuth\\Common\\Consumer\\CredentialsInterface'),
+ $client,
+ $storage
+ );
+
+ $uri = $service->request('https://pieterhordijk.com/my/awesome/path');
+ $absoluteUri = parse_url($uri->getAbsoluteUri());
+
+ $this->assertSame('oauth2_access_token=foo', $absoluteUri['query']);
+ }
+
+ /**
+ * @covers OAuth\OAuth2\Service\Linkedin::__construct
+ * @covers OAuth\OAuth2\Service\Linkedin::parseAccessTokenResponse
+ */
+ public function testParseAccessTokenResponseThrowsExceptionOnNulledResponse()
+ {
+ $client = $this->getMock('\\OAuth\\Common\\Http\\Client\\ClientInterface');
+ $client->expects($this->once())->method('retrieveResponse')->will($this->returnValue(null));
+
+ $service = new Linkedin(
+ $this->getMock('\\OAuth\\Common\\Consumer\\CredentialsInterface'),
+ $client,
+ $this->getMock('\\OAuth\\Common\\Storage\\TokenStorageInterface')
+ );
+
+ $this->setExpectedException('\\OAuth\\Common\\Http\\Exception\\TokenResponseException');
+
+ $service->requestAccessToken('foo');
+ }
+
+ /**
+ * @covers OAuth\OAuth2\Service\Linkedin::__construct
+ * @covers OAuth\OAuth2\Service\Linkedin::parseAccessTokenResponse
+ */
+ public function testParseAccessTokenResponseThrowsExceptionOnErrorDescription()
+ {
+ $client = $this->getMock('\\OAuth\\Common\\Http\\Client\\ClientInterface');
+ $client->expects($this->once())->method('retrieveResponse')->will($this->returnValue('error_description=some_error'));
+
+ $service = new Linkedin(
+ $this->getMock('\\OAuth\\Common\\Consumer\\CredentialsInterface'),
+ $client,
+ $this->getMock('\\OAuth\\Common\\Storage\\TokenStorageInterface')
+ );
+
+ $this->setExpectedException('\\OAuth\\Common\\Http\\Exception\\TokenResponseException');
+
+ $service->requestAccessToken('foo');
+ }
+
+ /**
+ * @covers OAuth\OAuth2\Service\Linkedin::__construct
+ * @covers OAuth\OAuth2\Service\Linkedin::parseAccessTokenResponse
+ */
+ public function testParseAccessTokenResponseThrowsExceptionOnError()
+ {
+ $client = $this->getMock('\\OAuth\\Common\\Http\\Client\\ClientInterface');
+ $client->expects($this->once())->method('retrieveResponse')->will($this->returnValue('error=some_error'));
+
+ $service = new Linkedin(
+ $this->getMock('\\OAuth\\Common\\Consumer\\CredentialsInterface'),
+ $client,
+ $this->getMock('\\OAuth\\Common\\Storage\\TokenStorageInterface')
+ );
+
+ $this->setExpectedException('\\OAuth\\Common\\Http\\Exception\\TokenResponseException');
+
+ $service->requestAccessToken('foo');
+ }
+
+ /**
+ * @covers OAuth\OAuth2\Service\Linkedin::__construct
+ * @covers OAuth\OAuth2\Service\Linkedin::parseAccessTokenResponse
+ */
+ public function testParseAccessTokenResponseValidWithoutRefreshToken()
+ {
+ $client = $this->getMock('\\OAuth\\Common\\Http\\Client\\ClientInterface');
+ $client->expects($this->once())->method('retrieveResponse')->will($this->returnValue('{"access_token":"foo","expires_in":"bar"}'));
+
+ $service = new Linkedin(
+ $this->getMock('\\OAuth\\Common\\Consumer\\CredentialsInterface'),
+ $client,
+ $this->getMock('\\OAuth\\Common\\Storage\\TokenStorageInterface')
+ );
+
+ $this->assertInstanceOf('\\OAuth\\OAuth2\\Token\\StdOAuth2Token', $service->requestAccessToken('foo'));
+ }
+
+ /**
+ * @covers OAuth\OAuth2\Service\Linkedin::__construct
+ * @covers OAuth\OAuth2\Service\Linkedin::parseAccessTokenResponse
+ */
+ public function testParseAccessTokenResponseValidWithRefreshToken()
+ {
+ $client = $this->getMock('\\OAuth\\Common\\Http\\Client\\ClientInterface');
+ $client->expects($this->once())->method('retrieveResponse')->will($this->returnValue('{"access_token":"foo","expires_in":"bar","refresh_token":"baz"}'));
+
+ $service = new Linkedin(
+ $this->getMock('\\OAuth\\Common\\Consumer\\CredentialsInterface'),
+ $client,
+ $this->getMock('\\OAuth\\Common\\Storage\\TokenStorageInterface')
+ );
+
+ $this->assertInstanceOf('\\OAuth\\OAuth2\\Token\\StdOAuth2Token', $service->requestAccessToken('foo'));
+ }
+}
diff --git a/vendor/lusitanian/oauth/tests/Unit/OAuth2/Service/MailchimpTest.php b/vendor/lusitanian/oauth/tests/Unit/OAuth2/Service/MailchimpTest.php
new file mode 100644
index 00000000..e7f955e1
--- /dev/null
+++ b/vendor/lusitanian/oauth/tests/Unit/OAuth2/Service/MailchimpTest.php
@@ -0,0 +1,179 @@
+getMock('\\OAuth\\Common\\Consumer\\CredentialsInterface'),
+ $this->getMock('\\OAuth\\Common\\Http\\Client\\ClientInterface'),
+ $this->getMock('\\OAuth\\Common\\Storage\\TokenStorageInterface')
+ );
+
+ $this->assertInstanceOf('\\OAuth\\OAuth2\\Service\\ServiceInterface', $service);
+ }
+
+ /**
+ * @covers OAuth\OAuth2\Service\Mailchimp::__construct
+ */
+ public function testConstructCorrectInstanceWithoutCustomUri()
+ {
+ $service = new Mailchimp(
+ $this->getMock('\\OAuth\\Common\\Consumer\\CredentialsInterface'),
+ $this->getMock('\\OAuth\\Common\\Http\\Client\\ClientInterface'),
+ $this->getMock('\\OAuth\\Common\\Storage\\TokenStorageInterface')
+ );
+
+ $this->assertInstanceOf('\\OAuth\\OAuth2\\Service\\AbstractService', $service);
+ }
+
+ /**
+ * @covers OAuth\OAuth2\Service\Mailchimp::__construct
+ */
+ public function testConstructCorrectInstanceWithCustomUri()
+ {
+ $service = new Mailchimp(
+ $this->getMock('\\OAuth\\Common\\Consumer\\CredentialsInterface'),
+ $this->getMock('\\OAuth\\Common\\Http\\Client\\ClientInterface'),
+ $this->getMock('\\OAuth\\Common\\Storage\\TokenStorageInterface'),
+ array(),
+ $this->getMock('\\OAuth\\Common\\Http\\Uri\\UriInterface')
+ );
+
+ $this->assertInstanceOf('\\OAuth\\OAuth2\\Service\\AbstractService', $service);
+ }
+
+ /**
+ * @covers OAuth\OAuth2\Service\Mailchimp::__construct
+ * @covers OAuth\OAuth2\Service\Mailchimp::getAuthorizationEndpoint
+ */
+ public function testGetAuthorizationEndpoint()
+ {
+ $service = new Mailchimp(
+ $this->getMock('\\OAuth\\Common\\Consumer\\CredentialsInterface'),
+ $this->getMock('\\OAuth\\Common\\Http\\Client\\ClientInterface'),
+ $this->getMock('\\OAuth\\Common\\Storage\\TokenStorageInterface')
+ );
+
+ $this->assertSame(
+ 'https://login.mailchimp.com/oauth2/authorize',
+ $service->getAuthorizationEndpoint()->getAbsoluteUri()
+ );
+ }
+
+ /**
+ * @covers OAuth\OAuth2\Service\Mailchimp::__construct
+ * @covers OAuth\OAuth2\Service\Mailchimp::getAccessTokenEndpoint
+ */
+ public function testGetAccessTokenEndpoint()
+ {
+ $service = new Mailchimp(
+ $this->getMock('\\OAuth\\Common\\Consumer\\CredentialsInterface'),
+ $this->getMock('\\OAuth\\Common\\Http\\Client\\ClientInterface'),
+ $this->getMock('\\OAuth\\Common\\Storage\\TokenStorageInterface')
+ );
+
+ $this->assertSame(
+ 'https://login.mailchimp.com/oauth2/token',
+ $service->getAccessTokenEndpoint()->getAbsoluteUri()
+ );
+ }
+
+ /**
+ * @covers OAuth\OAuth2\Service\Mailchimp::__construct
+ * @covers OAuth\OAuth2\Service\Mailchimp::getAuthorizationMethod
+ */
+ public function testGetAuthorizationMethod()
+ {
+ $client = $this->getMock('\\OAuth\\Common\\Http\\Client\\ClientInterface');
+ $client->expects($this->once())->method('retrieveResponse')->will($this->returnArgument(0));
+
+ $token = $this->getMock('\\OAuth\\OAuth2\\Token\\StdOAuth2Token');
+ $token->expects($this->once())->method('getEndOfLife')->will($this->returnValue(TokenInterface::EOL_NEVER_EXPIRES));
+ $token->expects($this->once())->method('getAccessToken')->will($this->returnValue('foo'));
+
+ $storage = $this->getMock('\\OAuth\\Common\\Storage\\TokenStorageInterface');
+ $storage->expects($this->once())->method('retrieveAccessToken')->will($this->returnValue($token));
+
+ $service = new Mailchimp(
+ $this->getMock('\\OAuth\\Common\\Consumer\\CredentialsInterface'),
+ $client,
+ $storage,
+ array(),
+ new Uri('https://us1.api.mailchimp.com/2.0/')
+ );
+
+ $uri = $service->request('https://pieterhordijk.com/my/awesome/path');
+ $absoluteUri = parse_url($uri->getAbsoluteUri());
+
+ $this->assertSame('apikey=foo', $absoluteUri['query']);
+ }
+
+ /**
+ * @covers OAuth\OAuth2\Service\Mailchimp::__construct
+ * @covers OAuth\OAuth2\Service\Mailchimp::parseAccessTokenResponse
+ */
+ public function testParseAccessTokenResponseThrowsExceptionOnNulledResponse()
+ {
+ $client = $this->getMock('\\OAuth\\Common\\Http\\Client\\ClientInterface');
+ $client->expects($this->once())->method('retrieveResponse')->will($this->returnValue(null));
+
+ $service = new Mailchimp(
+ $this->getMock('\\OAuth\\Common\\Consumer\\CredentialsInterface'),
+ $client,
+ $this->getMock('\\OAuth\\Common\\Storage\\TokenStorageInterface')
+ );
+
+ $this->setExpectedException('\\OAuth\\Common\\Http\\Exception\\TokenResponseException');
+
+ $service->requestAccessToken('foo');
+ }
+
+ /**
+ * @covers OAuth\OAuth2\Service\Mailchimp::__construct
+ * @covers OAuth\OAuth2\Service\Mailchimp::parseAccessTokenResponse
+ */
+ public function testParseAccessTokenResponseThrowsExceptionOnError()
+ {
+ $client = $this->getMock('\\OAuth\\Common\\Http\\Client\\ClientInterface');
+ $client->expects($this->once())->method('retrieveResponse')->will($this->returnValue('error=some_error'));
+
+ $service = new Mailchimp(
+ $this->getMock('\\OAuth\\Common\\Consumer\\CredentialsInterface'),
+ $client,
+ $this->getMock('\\OAuth\\Common\\Storage\\TokenStorageInterface')
+ );
+
+ $this->setExpectedException('\\OAuth\\Common\\Http\\Exception\\TokenResponseException');
+
+ $service->requestAccessToken('foo');
+ }
+
+ /**
+ * @covers OAuth\OAuth2\Service\Mailchimp::__construct
+ * @covers OAuth\OAuth2\Service\Mailchimp::parseAccessTokenResponse
+ */
+ public function testParseAccessTokenResponseValid()
+ {
+ $client = $this->getMock('\\OAuth\\Common\\Http\\Client\\ClientInterface');
+ $client->expects($this->at(0))->method('retrieveResponse')->will($this->returnValue('{"access_token":"foo","expires_in":"bar"}'));
+ $client->expects($this->at(1))->method('retrieveResponse')->will($this->returnValue('{"dc": "us7"}'));
+
+ $service = new Mailchimp(
+ $this->getMock('\\OAuth\\Common\\Consumer\\CredentialsInterface'),
+ $client,
+ $this->getMock('\\OAuth\\Common\\Storage\\TokenStorageInterface')
+ );
+
+ $this->assertInstanceOf('\\OAuth\\OAuth2\\Token\\StdOAuth2Token', $service->requestAccessToken('foo'));
+ }
+}
diff --git a/vendor/lusitanian/oauth/tests/Unit/OAuth2/Service/MicrosoftTest.php b/vendor/lusitanian/oauth/tests/Unit/OAuth2/Service/MicrosoftTest.php
new file mode 100644
index 00000000..4001e1e4
--- /dev/null
+++ b/vendor/lusitanian/oauth/tests/Unit/OAuth2/Service/MicrosoftTest.php
@@ -0,0 +1,193 @@
+getMock('\\OAuth\\Common\\Consumer\\CredentialsInterface'),
+ $this->getMock('\\OAuth\\Common\\Http\\Client\\ClientInterface'),
+ $this->getMock('\\OAuth\\Common\\Storage\\TokenStorageInterface')
+ );
+
+ $this->assertInstanceOf('\\OAuth\\OAuth2\\Service\\ServiceInterface', $service);
+ }
+
+ /**
+ * @covers OAuth\OAuth2\Service\Microsoft::__construct
+ */
+ public function testConstructCorrectInstanceWithoutCustomUri()
+ {
+ $service = new Microsoft(
+ $this->getMock('\\OAuth\\Common\\Consumer\\CredentialsInterface'),
+ $this->getMock('\\OAuth\\Common\\Http\\Client\\ClientInterface'),
+ $this->getMock('\\OAuth\\Common\\Storage\\TokenStorageInterface')
+ );
+
+ $this->assertInstanceOf('\\OAuth\\OAuth2\\Service\\AbstractService', $service);
+ }
+
+ /**
+ * @covers OAuth\OAuth2\Service\Microsoft::__construct
+ */
+ public function testConstructCorrectInstanceWithCustomUri()
+ {
+ $service = new Microsoft(
+ $this->getMock('\\OAuth\\Common\\Consumer\\CredentialsInterface'),
+ $this->getMock('\\OAuth\\Common\\Http\\Client\\ClientInterface'),
+ $this->getMock('\\OAuth\\Common\\Storage\\TokenStorageInterface'),
+ array(),
+ $this->getMock('\\OAuth\\Common\\Http\\Uri\\UriInterface')
+ );
+
+ $this->assertInstanceOf('\\OAuth\\OAuth2\\Service\\AbstractService', $service);
+ }
+
+ /**
+ * @covers OAuth\OAuth2\Service\Microsoft::__construct
+ * @covers OAuth\OAuth2\Service\Microsoft::getAuthorizationEndpoint
+ */
+ public function testGetAuthorizationEndpoint()
+ {
+ $service = new Microsoft(
+ $this->getMock('\\OAuth\\Common\\Consumer\\CredentialsInterface'),
+ $this->getMock('\\OAuth\\Common\\Http\\Client\\ClientInterface'),
+ $this->getMock('\\OAuth\\Common\\Storage\\TokenStorageInterface')
+ );
+
+ $this->assertSame(
+ 'https://login.live.com/oauth20_authorize.srf',
+ $service->getAuthorizationEndpoint()->getAbsoluteUri()
+ );
+ }
+
+ /**
+ * @covers OAuth\OAuth2\Service\Microsoft::__construct
+ * @covers OAuth\OAuth2\Service\Microsoft::getAccessTokenEndpoint
+ */
+ public function testGetAccessTokenEndpoint()
+ {
+ $service = new Microsoft(
+ $this->getMock('\\OAuth\\Common\\Consumer\\CredentialsInterface'),
+ $this->getMock('\\OAuth\\Common\\Http\\Client\\ClientInterface'),
+ $this->getMock('\\OAuth\\Common\\Storage\\TokenStorageInterface')
+ );
+
+ $this->assertSame(
+ 'https://login.live.com/oauth20_token.srf',
+ $service->getAccessTokenEndpoint()->getAbsoluteUri()
+ );
+ }
+
+ /**
+ * @covers OAuth\OAuth2\Service\Microsoft::__construct
+ * @covers OAuth\OAuth2\Service\Microsoft::getAuthorizationMethod
+ */
+ public function testGetAuthorizationMethod()
+ {
+ $client = $this->getMock('\\OAuth\\Common\\Http\\Client\\ClientInterface');
+ $client->expects($this->once())->method('retrieveResponse')->will($this->returnArgument(0));
+
+ $token = $this->getMock('\\OAuth\\OAuth2\\Token\\TokenInterface');
+ $token->expects($this->once())->method('getEndOfLife')->will($this->returnValue(TokenInterface::EOL_NEVER_EXPIRES));
+ $token->expects($this->once())->method('getAccessToken')->will($this->returnValue('foo'));
+
+ $storage = $this->getMock('\\OAuth\\Common\\Storage\\TokenStorageInterface');
+ $storage->expects($this->once())->method('retrieveAccessToken')->will($this->returnValue($token));
+
+ $service = new Microsoft(
+ $this->getMock('\\OAuth\\Common\\Consumer\\CredentialsInterface'),
+ $client,
+ $storage
+ );
+
+ $uri = $service->request('https://pieterhordijk.com/my/awesome/path');
+ $absoluteUri = parse_url($uri->getAbsoluteUri());
+
+ $this->assertSame('access_token=foo', $absoluteUri['query']);
+ }
+
+ /**
+ * @covers OAuth\OAuth2\Service\Microsoft::__construct
+ * @covers OAuth\OAuth2\Service\Microsoft::parseAccessTokenResponse
+ */
+ public function testParseAccessTokenResponseThrowsExceptionOnNulledResponse()
+ {
+ $client = $this->getMock('\\OAuth\\Common\\Http\\Client\\ClientInterface');
+ $client->expects($this->once())->method('retrieveResponse')->will($this->returnValue(null));
+
+ $service = new Microsoft(
+ $this->getMock('\\OAuth\\Common\\Consumer\\CredentialsInterface'),
+ $client,
+ $this->getMock('\\OAuth\\Common\\Storage\\TokenStorageInterface')
+ );
+
+ $this->setExpectedException('\\OAuth\\Common\\Http\\Exception\\TokenResponseException');
+
+ $service->requestAccessToken('foo');
+ }
+
+ /**
+ * @covers OAuth\OAuth2\Service\Microsoft::__construct
+ * @covers OAuth\OAuth2\Service\Microsoft::parseAccessTokenResponse
+ */
+ public function testParseAccessTokenResponseThrowsExceptionOnError()
+ {
+ $client = $this->getMock('\\OAuth\\Common\\Http\\Client\\ClientInterface');
+ $client->expects($this->once())->method('retrieveResponse')->will($this->returnValue('error=some_error'));
+
+ $service = new Microsoft(
+ $this->getMock('\\OAuth\\Common\\Consumer\\CredentialsInterface'),
+ $client,
+ $this->getMock('\\OAuth\\Common\\Storage\\TokenStorageInterface')
+ );
+
+ $this->setExpectedException('\\OAuth\\Common\\Http\\Exception\\TokenResponseException');
+
+ $service->requestAccessToken('foo');
+ }
+
+ /**
+ * @covers OAuth\OAuth2\Service\Microsoft::__construct
+ * @covers OAuth\OAuth2\Service\Microsoft::parseAccessTokenResponse
+ */
+ public function testParseAccessTokenResponseValidWithoutRefreshToken()
+ {
+ $client = $this->getMock('\\OAuth\\Common\\Http\\Client\\ClientInterface');
+ $client->expects($this->once())->method('retrieveResponse')->will($this->returnValue('{"access_token":"foo","expires_in":"bar"}'));
+
+ $service = new Microsoft(
+ $this->getMock('\\OAuth\\Common\\Consumer\\CredentialsInterface'),
+ $client,
+ $this->getMock('\\OAuth\\Common\\Storage\\TokenStorageInterface')
+ );
+
+ $this->assertInstanceOf('\\OAuth\\OAuth2\\Token\\StdOAuth2Token', $service->requestAccessToken('foo'));
+ }
+
+ /**
+ * @covers OAuth\OAuth2\Service\Microsoft::__construct
+ * @covers OAuth\OAuth2\Service\Microsoft::parseAccessTokenResponse
+ */
+ public function testParseAccessTokenResponseValidWithRefreshToken()
+ {
+ $client = $this->getMock('\\OAuth\\Common\\Http\\Client\\ClientInterface');
+ $client->expects($this->once())->method('retrieveResponse')->will($this->returnValue('{"access_token":"foo","expires_in":"bar","refresh_token":"baz"}'));
+
+ $service = new Microsoft(
+ $this->getMock('\\OAuth\\Common\\Consumer\\CredentialsInterface'),
+ $client,
+ $this->getMock('\\OAuth\\Common\\Storage\\TokenStorageInterface')
+ );
+
+ $this->assertInstanceOf('\\OAuth\\OAuth2\\Token\\StdOAuth2Token', $service->requestAccessToken('foo'));
+ }
+}
diff --git a/vendor/lusitanian/oauth/tests/Unit/OAuth2/Service/PaypalTest.php b/vendor/lusitanian/oauth/tests/Unit/OAuth2/Service/PaypalTest.php
new file mode 100644
index 00000000..5396326f
--- /dev/null
+++ b/vendor/lusitanian/oauth/tests/Unit/OAuth2/Service/PaypalTest.php
@@ -0,0 +1,213 @@
+getMock('\\OAuth\\Common\\Consumer\\CredentialsInterface'),
+ $this->getMock('\\OAuth\\Common\\Http\\Client\\ClientInterface'),
+ $this->getMock('\\OAuth\\Common\\Storage\\TokenStorageInterface')
+ );
+
+ $this->assertInstanceOf('\\OAuth\\OAuth2\\Service\\ServiceInterface', $service);
+ }
+
+ /**
+ * @covers OAuth\OAuth2\Service\Paypal::__construct
+ */
+ public function testConstructCorrectInstanceWithoutCustomUri()
+ {
+ $service = new Paypal(
+ $this->getMock('\\OAuth\\Common\\Consumer\\CredentialsInterface'),
+ $this->getMock('\\OAuth\\Common\\Http\\Client\\ClientInterface'),
+ $this->getMock('\\OAuth\\Common\\Storage\\TokenStorageInterface')
+ );
+
+ $this->assertInstanceOf('\\OAuth\\OAuth2\\Service\\AbstractService', $service);
+ }
+
+ /**
+ * @covers OAuth\OAuth2\Service\Paypal::__construct
+ */
+ public function testConstructCorrectInstanceWithCustomUri()
+ {
+ $service = new Paypal(
+ $this->getMock('\\OAuth\\Common\\Consumer\\CredentialsInterface'),
+ $this->getMock('\\OAuth\\Common\\Http\\Client\\ClientInterface'),
+ $this->getMock('\\OAuth\\Common\\Storage\\TokenStorageInterface'),
+ array(),
+ $this->getMock('\\OAuth\\Common\\Http\\Uri\\UriInterface')
+ );
+
+ $this->assertInstanceOf('\\OAuth\\OAuth2\\Service\\AbstractService', $service);
+ }
+
+ /**
+ * @covers OAuth\OAuth2\Service\Paypal::__construct
+ * @covers OAuth\OAuth2\Service\Paypal::getAuthorizationEndpoint
+ */
+ public function testGetAuthorizationEndpoint()
+ {
+ $service = new Paypal(
+ $this->getMock('\\OAuth\\Common\\Consumer\\CredentialsInterface'),
+ $this->getMock('\\OAuth\\Common\\Http\\Client\\ClientInterface'),
+ $this->getMock('\\OAuth\\Common\\Storage\\TokenStorageInterface')
+ );
+
+ $this->assertSame(
+ 'https://www.paypal.com/webapps/auth/protocol/openidconnect/v1/authorize',
+ $service->getAuthorizationEndpoint()->getAbsoluteUri()
+ );
+ }
+
+ /**
+ * @covers OAuth\OAuth2\Service\Paypal::__construct
+ * @covers OAuth\OAuth2\Service\Paypal::getAccessTokenEndpoint
+ */
+ public function testGetAccessTokenEndpoint()
+ {
+ $service = new Paypal(
+ $this->getMock('\\OAuth\\Common\\Consumer\\CredentialsInterface'),
+ $this->getMock('\\OAuth\\Common\\Http\\Client\\ClientInterface'),
+ $this->getMock('\\OAuth\\Common\\Storage\\TokenStorageInterface')
+ );
+
+ $this->assertSame(
+ 'https://api.paypal.com/v1/identity/openidconnect/tokenservice',
+ $service->getAccessTokenEndpoint()->getAbsoluteUri()
+ );
+ }
+
+ /**
+ * @covers OAuth\OAuth2\Service\Paypal::__construct
+ * @covers OAuth\OAuth2\Service\Paypal::getAuthorizationMethod
+ */
+ public function testGetAuthorizationMethod()
+ {
+ $client = $this->getMock('\\OAuth\\Common\\Http\\Client\\ClientInterface');
+ $client->expects($this->once())->method('retrieveResponse')->will($this->returnArgument(2));
+
+ $token = $this->getMock('\\OAuth\\OAuth2\\Token\\TokenInterface');
+ $token->expects($this->once())->method('getEndOfLife')->will($this->returnValue(TokenInterface::EOL_NEVER_EXPIRES));
+ $token->expects($this->once())->method('getAccessToken')->will($this->returnValue('foo'));
+
+ $storage = $this->getMock('\\OAuth\\Common\\Storage\\TokenStorageInterface');
+ $storage->expects($this->once())->method('retrieveAccessToken')->will($this->returnValue($token));
+
+ $service = new Paypal(
+ $this->getMock('\\OAuth\\Common\\Consumer\\CredentialsInterface'),
+ $client,
+ $storage
+ );
+
+ $headers = $service->request('https://pieterhordijk.com/my/awesome/path');
+
+ $this->assertTrue(array_key_exists('Authorization', $headers));
+ $this->assertTrue(in_array('Bearer foo', $headers, true));
+ }
+
+ /**
+ * @covers OAuth\OAuth2\Service\Paypal::__construct
+ * @covers OAuth\OAuth2\Service\Paypal::parseAccessTokenResponse
+ */
+ public function testParseAccessTokenResponseThrowsExceptionOnNulledResponse()
+ {
+ $client = $this->getMock('\\OAuth\\Common\\Http\\Client\\ClientInterface');
+ $client->expects($this->once())->method('retrieveResponse')->will($this->returnValue(null));
+
+ $service = new Paypal(
+ $this->getMock('\\OAuth\\Common\\Consumer\\CredentialsInterface'),
+ $client,
+ $this->getMock('\\OAuth\\Common\\Storage\\TokenStorageInterface')
+ );
+
+ $this->setExpectedException('\\OAuth\\Common\\Http\\Exception\\TokenResponseException');
+
+ $service->requestAccessToken('foo');
+ }
+
+ /**
+ * @covers OAuth\OAuth2\Service\Paypal::__construct
+ * @covers OAuth\OAuth2\Service\Paypal::parseAccessTokenResponse
+ */
+ public function testParseAccessTokenResponseThrowsExceptionOnMessage()
+ {
+ $client = $this->getMock('\\OAuth\\Common\\Http\\Client\\ClientInterface');
+ $client->expects($this->once())->method('retrieveResponse')->will($this->returnValue('message=some_error'));
+
+ $service = new Paypal(
+ $this->getMock('\\OAuth\\Common\\Consumer\\CredentialsInterface'),
+ $client,
+ $this->getMock('\\OAuth\\Common\\Storage\\TokenStorageInterface')
+ );
+
+ $this->setExpectedException('\\OAuth\\Common\\Http\\Exception\\TokenResponseException');
+
+ $service->requestAccessToken('foo');
+ }
+
+ /**
+ * @covers OAuth\OAuth2\Service\Paypal::__construct
+ * @covers OAuth\OAuth2\Service\Paypal::parseAccessTokenResponse
+ */
+ public function testParseAccessTokenResponseThrowsExceptionOnName()
+ {
+ $client = $this->getMock('\\OAuth\\Common\\Http\\Client\\ClientInterface');
+ $client->expects($this->once())->method('retrieveResponse')->will($this->returnValue('name=some_error'));
+
+ $service = new Paypal(
+ $this->getMock('\\OAuth\\Common\\Consumer\\CredentialsInterface'),
+ $client,
+ $this->getMock('\\OAuth\\Common\\Storage\\TokenStorageInterface')
+ );
+
+ $this->setExpectedException('\\OAuth\\Common\\Http\\Exception\\TokenResponseException');
+
+ $service->requestAccessToken('foo');
+ }
+
+ /**
+ * @covers OAuth\OAuth2\Service\Paypal::__construct
+ * @covers OAuth\OAuth2\Service\Paypal::parseAccessTokenResponse
+ */
+ public function testParseAccessTokenResponseValidWithoutRefreshToken()
+ {
+ $client = $this->getMock('\\OAuth\\Common\\Http\\Client\\ClientInterface');
+ $client->expects($this->once())->method('retrieveResponse')->will($this->returnValue('{"access_token":"foo","expires_in":"bar"}'));
+
+ $service = new Paypal(
+ $this->getMock('\\OAuth\\Common\\Consumer\\CredentialsInterface'),
+ $client,
+ $this->getMock('\\OAuth\\Common\\Storage\\TokenStorageInterface')
+ );
+
+ $this->assertInstanceOf('\\OAuth\\OAuth2\\Token\\StdOAuth2Token', $service->requestAccessToken('foo'));
+ }
+
+ /**
+ * @covers OAuth\OAuth2\Service\Paypal::__construct
+ * @covers OAuth\OAuth2\Service\Paypal::parseAccessTokenResponse
+ */
+ public function testParseAccessTokenResponseValidWithRefreshToken()
+ {
+ $client = $this->getMock('\\OAuth\\Common\\Http\\Client\\ClientInterface');
+ $client->expects($this->once())->method('retrieveResponse')->will($this->returnValue('{"access_token":"foo","expires_in":"bar","refresh_token":"baz"}'));
+
+ $service = new Paypal(
+ $this->getMock('\\OAuth\\Common\\Consumer\\CredentialsInterface'),
+ $client,
+ $this->getMock('\\OAuth\\Common\\Storage\\TokenStorageInterface')
+ );
+
+ $this->assertInstanceOf('\\OAuth\\OAuth2\\Token\\StdOAuth2Token', $service->requestAccessToken('foo'));
+ }
+}
diff --git a/vendor/lusitanian/oauth/tests/Unit/OAuth2/Service/RedditTest.php b/vendor/lusitanian/oauth/tests/Unit/OAuth2/Service/RedditTest.php
new file mode 100644
index 00000000..e8741e6f
--- /dev/null
+++ b/vendor/lusitanian/oauth/tests/Unit/OAuth2/Service/RedditTest.php
@@ -0,0 +1,193 @@
+getMock('\\OAuth\\Common\\Consumer\\CredentialsInterface'),
+ $this->getMock('\\OAuth\\Common\\Http\\Client\\ClientInterface'),
+ $this->getMock('\\OAuth\\Common\\Storage\\TokenStorageInterface')
+ );
+
+ $this->assertInstanceOf('\\OAuth\\OAuth2\\Service\\ServiceInterface', $service);
+ }
+
+ /**
+ * @covers OAuth\OAuth2\Service\Reddit::__construct
+ */
+ public function testConstructCorrectInstanceWithoutCustomUri()
+ {
+ $service = new Reddit(
+ $this->getMock('\\OAuth\\Common\\Consumer\\CredentialsInterface'),
+ $this->getMock('\\OAuth\\Common\\Http\\Client\\ClientInterface'),
+ $this->getMock('\\OAuth\\Common\\Storage\\TokenStorageInterface')
+ );
+
+ $this->assertInstanceOf('\\OAuth\\OAuth2\\Service\\AbstractService', $service);
+ }
+
+ /**
+ * @covers OAuth\OAuth2\Service\Reddit::__construct
+ */
+ public function testConstructCorrectInstanceWithCustomUri()
+ {
+ $service = new Reddit(
+ $this->getMock('\\OAuth\\Common\\Consumer\\CredentialsInterface'),
+ $this->getMock('\\OAuth\\Common\\Http\\Client\\ClientInterface'),
+ $this->getMock('\\OAuth\\Common\\Storage\\TokenStorageInterface'),
+ array(),
+ $this->getMock('\\OAuth\\Common\\Http\\Uri\\UriInterface')
+ );
+
+ $this->assertInstanceOf('\\OAuth\\OAuth2\\Service\\AbstractService', $service);
+ }
+
+ /**
+ * @covers OAuth\OAuth2\Service\Reddit::__construct
+ * @covers OAuth\OAuth2\Service\Reddit::getAuthorizationEndpoint
+ */
+ public function testGetAuthorizationEndpoint()
+ {
+ $service = new Reddit(
+ $this->getMock('\\OAuth\\Common\\Consumer\\CredentialsInterface'),
+ $this->getMock('\\OAuth\\Common\\Http\\Client\\ClientInterface'),
+ $this->getMock('\\OAuth\\Common\\Storage\\TokenStorageInterface')
+ );
+
+ $this->assertSame(
+ 'https://ssl.reddit.com/api/v1/authorize',
+ $service->getAuthorizationEndpoint()->getAbsoluteUri()
+ );
+ }
+
+ /**
+ * @covers OAuth\OAuth2\Service\Reddit::__construct
+ * @covers OAuth\OAuth2\Service\Reddit::getAccessTokenEndpoint
+ */
+ public function testGetAccessTokenEndpoint()
+ {
+ $service = new Reddit(
+ $this->getMock('\\OAuth\\Common\\Consumer\\CredentialsInterface'),
+ $this->getMock('\\OAuth\\Common\\Http\\Client\\ClientInterface'),
+ $this->getMock('\\OAuth\\Common\\Storage\\TokenStorageInterface')
+ );
+
+ $this->assertSame(
+ 'https://ssl.reddit.com/api/v1/access_token',
+ $service->getAccessTokenEndpoint()->getAbsoluteUri()
+ );
+ }
+
+ /**
+ * @covers OAuth\OAuth2\Service\Reddit::__construct
+ * @covers OAuth\OAuth2\Service\Reddit::getAuthorizationMethod
+ */
+ public function testGetAuthorizationMethod()
+ {
+ $client = $this->getMock('\\OAuth\\Common\\Http\\Client\\ClientInterface');
+ $client->expects($this->once())->method('retrieveResponse')->will($this->returnArgument(2));
+
+ $token = $this->getMock('\\OAuth\\OAuth2\\Token\\TokenInterface');
+ $token->expects($this->once())->method('getEndOfLife')->will($this->returnValue(TokenInterface::EOL_NEVER_EXPIRES));
+ $token->expects($this->once())->method('getAccessToken')->will($this->returnValue('foo'));
+
+ $storage = $this->getMock('\\OAuth\\Common\\Storage\\TokenStorageInterface');
+ $storage->expects($this->once())->method('retrieveAccessToken')->will($this->returnValue($token));
+
+ $service = new Reddit(
+ $this->getMock('\\OAuth\\Common\\Consumer\\CredentialsInterface'),
+ $client,
+ $storage
+ );
+
+ $headers = $service->request('https://pieterhordijk.com/my/awesome/path');
+
+ $this->assertTrue(array_key_exists('Authorization', $headers));
+ $this->assertTrue(in_array('Bearer foo', $headers, true));
+ }
+
+ /**
+ * @covers OAuth\OAuth2\Service\Reddit::__construct
+ * @covers OAuth\OAuth2\Service\Reddit::parseAccessTokenResponse
+ */
+ public function testParseAccessTokenResponseThrowsExceptionOnNulledResponse()
+ {
+ $client = $this->getMock('\\OAuth\\Common\\Http\\Client\\ClientInterface');
+ $client->expects($this->once())->method('retrieveResponse')->will($this->returnValue(null));
+
+ $service = new Reddit(
+ $this->getMock('\\OAuth\\Common\\Consumer\\CredentialsInterface'),
+ $client,
+ $this->getMock('\\OAuth\\Common\\Storage\\TokenStorageInterface')
+ );
+
+ $this->setExpectedException('\\OAuth\\Common\\Http\\Exception\\TokenResponseException');
+
+ $service->requestAccessToken('foo');
+ }
+
+ /**
+ * @covers OAuth\OAuth2\Service\Reddit::__construct
+ * @covers OAuth\OAuth2\Service\Reddit::parseAccessTokenResponse
+ */
+ public function testParseAccessTokenResponseThrowsExceptionOnError()
+ {
+ $client = $this->getMock('\\OAuth\\Common\\Http\\Client\\ClientInterface');
+ $client->expects($this->once())->method('retrieveResponse')->will($this->returnValue('error=some_error'));
+
+ $service = new Reddit(
+ $this->getMock('\\OAuth\\Common\\Consumer\\CredentialsInterface'),
+ $client,
+ $this->getMock('\\OAuth\\Common\\Storage\\TokenStorageInterface')
+ );
+
+ $this->setExpectedException('\\OAuth\\Common\\Http\\Exception\\TokenResponseException');
+
+ $service->requestAccessToken('foo');
+ }
+
+ /**
+ * @covers OAuth\OAuth2\Service\Reddit::__construct
+ * @covers OAuth\OAuth2\Service\Reddit::parseAccessTokenResponse
+ */
+ public function testParseAccessTokenResponseValidWithoutRefreshToken()
+ {
+ $client = $this->getMock('\\OAuth\\Common\\Http\\Client\\ClientInterface');
+ $client->expects($this->once())->method('retrieveResponse')->will($this->returnValue('{"access_token":"foo","expires_in":"bar"}'));
+
+ $service = new Reddit(
+ $this->getMock('\\OAuth\\Common\\Consumer\\CredentialsInterface'),
+ $client,
+ $this->getMock('\\OAuth\\Common\\Storage\\TokenStorageInterface')
+ );
+
+ $this->assertInstanceOf('\\OAuth\\OAuth2\\Token\\StdOAuth2Token', $service->requestAccessToken('foo'));
+ }
+
+ /**
+ * @covers OAuth\OAuth2\Service\Reddit::__construct
+ * @covers OAuth\OAuth2\Service\Reddit::parseAccessTokenResponse
+ */
+ public function testParseAccessTokenResponseValidWithRefreshToken()
+ {
+ $client = $this->getMock('\\OAuth\\Common\\Http\\Client\\ClientInterface');
+ $client->expects($this->once())->method('retrieveResponse')->will($this->returnValue('{"access_token":"foo","expires_in":"bar","refresh_token":"baz"}'));
+
+ $service = new Reddit(
+ $this->getMock('\\OAuth\\Common\\Consumer\\CredentialsInterface'),
+ $client,
+ $this->getMock('\\OAuth\\Common\\Storage\\TokenStorageInterface')
+ );
+
+ $this->assertInstanceOf('\\OAuth\\OAuth2\\Token\\StdOAuth2Token', $service->requestAccessToken('foo'));
+ }
+}
diff --git a/vendor/lusitanian/oauth/tests/Unit/OAuth2/Service/RunKeeperTest.php b/vendor/lusitanian/oauth/tests/Unit/OAuth2/Service/RunKeeperTest.php
new file mode 100644
index 00000000..671bd0cf
--- /dev/null
+++ b/vendor/lusitanian/oauth/tests/Unit/OAuth2/Service/RunKeeperTest.php
@@ -0,0 +1,207 @@
+getMock('\\OAuth\\Common\\Consumer\\CredentialsInterface'),
+ $this->getMock('\\OAuth\\Common\\Http\\Client\\ClientInterface'),
+ $this->getMock('\\OAuth\\Common\\Storage\\TokenStorageInterface')
+ );
+
+ $this->assertInstanceOf('\\OAuth\\OAuth2\\Service\\ServiceInterface', $service);
+ }
+
+ /**
+ * @covers OAuth\OAuth2\Service\RunKeeper::__construct
+ */
+ public function testConstructCorrectInstanceWithoutCustomUri()
+ {
+ $service = new RunKeeper(
+ $this->getMock('\\OAuth\\Common\\Consumer\\CredentialsInterface'),
+ $this->getMock('\\OAuth\\Common\\Http\\Client\\ClientInterface'),
+ $this->getMock('\\OAuth\\Common\\Storage\\TokenStorageInterface')
+ );
+
+ $this->assertInstanceOf('\\OAuth\\OAuth2\\Service\\AbstractService', $service);
+ }
+
+ /**
+ * @covers OAuth\OAuth2\Service\RunKeeper::__construct
+ */
+ public function testConstructCorrectInstanceWithCustomUri()
+ {
+ $service = new RunKeeper(
+ $this->getMock('\\OAuth\\Common\\Consumer\\CredentialsInterface'),
+ $this->getMock('\\OAuth\\Common\\Http\\Client\\ClientInterface'),
+ $this->getMock('\\OAuth\\Common\\Storage\\TokenStorageInterface'),
+ array(),
+ $this->getMock('\\OAuth\\Common\\Http\\Uri\\UriInterface')
+ );
+
+ $this->assertInstanceOf('\\OAuth\\OAuth2\\Service\\AbstractService', $service);
+ }
+
+ /**
+ * @covers OAuth\OAuth2\Service\RunKeeper::__construct
+ * @covers OAuth\OAuth2\Service\RunKeeper::getAuthorizationEndpoint
+ */
+ public function testGetAuthorizationEndpoint()
+ {
+ $service = new RunKeeper(
+ $this->getMock('\\OAuth\\Common\\Consumer\\CredentialsInterface'),
+ $this->getMock('\\OAuth\\Common\\Http\\Client\\ClientInterface'),
+ $this->getMock('\\OAuth\\Common\\Storage\\TokenStorageInterface')
+ );
+
+ $this->assertSame('https://runkeeper.com/apps/authorize', $service->getAuthorizationEndpoint()->getAbsoluteUri());
+ }
+
+ /**
+ * @covers OAuth\OAuth2\Service\RunKeeper::__construct
+ * @covers OAuth\OAuth2\Service\RunKeeper::getAccessTokenEndpoint
+ */
+ public function testGetAccessTokenEndpoint()
+ {
+ $service = new RunKeeper(
+ $this->getMock('\\OAuth\\Common\\Consumer\\CredentialsInterface'),
+ $this->getMock('\\OAuth\\Common\\Http\\Client\\ClientInterface'),
+ $this->getMock('\\OAuth\\Common\\Storage\\TokenStorageInterface')
+ );
+
+ $this->assertSame('https://runkeeper.com/apps/token', $service->getAccessTokenEndpoint()->getAbsoluteUri());
+ }
+
+ /**
+ * @covers OAuth\OAuth2\Service\RunKeeper::__construct
+ * @covers OAuth\OAuth2\Service\RunKeeper::getAuthorizationMethod
+ */
+ public function testGetAuthorizationMethod()
+ {
+ $client = $this->getMock('\\OAuth\\Common\\Http\\Client\\ClientInterface');
+ $client->expects($this->once())->method('retrieveResponse')->will($this->returnArgument(2));
+
+ $token = $this->getMock('\\OAuth\\OAuth2\\Token\\TokenInterface');
+ $token->expects($this->once())->method('getEndOfLife')->will($this->returnValue(TokenInterface::EOL_NEVER_EXPIRES));
+ $token->expects($this->once())->method('getAccessToken')->will($this->returnValue('foo'));
+
+ $storage = $this->getMock('\\OAuth\\Common\\Storage\\TokenStorageInterface');
+ $storage->expects($this->once())->method('retrieveAccessToken')->will($this->returnValue($token));
+
+ $service = new RunKeeper(
+ $this->getMock('\\OAuth\\Common\\Consumer\\CredentialsInterface'),
+ $client,
+ $storage
+ );
+
+ $headers = $service->request('/user');
+
+ $this->assertTrue(array_key_exists('Authorization', $headers));
+ $this->assertTrue(in_array('Bearer foo', $headers, true));
+ }
+
+ /**
+ * @covers OAuth\OAuth2\Service\RunKeeper::__construct
+ * @covers OAuth\OAuth2\Service\RunKeeper::parseAccessTokenResponse
+ */
+ public function testParseAccessTokenResponseThrowsExceptionOnNulledResponse()
+ {
+ $client = $this->getMock('\\OAuth\\Common\\Http\\Client\\ClientInterface');
+ $client->expects($this->once())->method('retrieveResponse')->will($this->returnValue(null));
+
+ $service = new RunKeeper(
+ $this->getMock('\\OAuth\\Common\\Consumer\\CredentialsInterface'),
+ $client,
+ $this->getMock('\\OAuth\\Common\\Storage\\TokenStorageInterface')
+ );
+
+ $this->setExpectedException('\\OAuth\\Common\\Http\\Exception\\TokenResponseException');
+
+ $service->requestAccessToken('foo');
+ }
+
+ /**
+ * @covers OAuth\OAuth2\Service\RunKeeper::__construct
+ * @covers OAuth\OAuth2\Service\RunKeeper::parseAccessTokenResponse
+ */
+ public function testParseAccessTokenResponseThrowsExceptionOnErrorDescription()
+ {
+ $client = $this->getMock('\\OAuth\\Common\\Http\\Client\\ClientInterface');
+ $client->expects($this->once())->method('retrieveResponse')->will($this->returnValue('error_description=some_error'));
+
+ $service = new RunKeeper(
+ $this->getMock('\\OAuth\\Common\\Consumer\\CredentialsInterface'),
+ $client,
+ $this->getMock('\\OAuth\\Common\\Storage\\TokenStorageInterface')
+ );
+
+ $this->setExpectedException('\\OAuth\\Common\\Http\\Exception\\TokenResponseException');
+
+ $service->requestAccessToken('foo');
+ }
+
+ /**
+ * @covers OAuth\OAuth2\Service\RunKeeper::__construct
+ * @covers OAuth\OAuth2\Service\RunKeeper::parseAccessTokenResponse
+ */
+ public function testParseAccessTokenResponseThrowsExceptionOnError()
+ {
+ $client = $this->getMock('\\OAuth\\Common\\Http\\Client\\ClientInterface');
+ $client->expects($this->once())->method('retrieveResponse')->will($this->returnValue('error=some_error'));
+
+ $service = new RunKeeper(
+ $this->getMock('\\OAuth\\Common\\Consumer\\CredentialsInterface'),
+ $client,
+ $this->getMock('\\OAuth\\Common\\Storage\\TokenStorageInterface')
+ );
+
+ $this->setExpectedException('\\OAuth\\Common\\Http\\Exception\\TokenResponseException');
+
+ $service->requestAccessToken('foo');
+ }
+
+ /**
+ * @covers OAuth\OAuth2\Service\RunKeeper::__construct
+ * @covers OAuth\OAuth2\Service\RunKeeper::parseAccessTokenResponse
+ */
+ public function testParseAccessTokenResponseValidWithoutRefreshToken()
+ {
+ $client = $this->getMock('\\OAuth\\Common\\Http\\Client\\ClientInterface');
+ $client->expects($this->once())->method('retrieveResponse')->will($this->returnValue('{"access_token":"foo","expires_in":"bar"}'));
+
+ $service = new RunKeeper(
+ $this->getMock('\\OAuth\\Common\\Consumer\\CredentialsInterface'),
+ $client,
+ $this->getMock('\\OAuth\\Common\\Storage\\TokenStorageInterface')
+ );
+
+ $this->assertInstanceOf('\\OAuth\\OAuth2\\Token\\StdOAuth2Token', $service->requestAccessToken('foo'));
+ }
+
+ /**
+ * @covers OAuth\OAuth2\Service\RunKeeper::__construct
+ * @covers OAuth\OAuth2\Service\RunKeeper::parseAccessTokenResponse
+ */
+ public function testParseAccessTokenResponseValidWithRefreshToken()
+ {
+ $client = $this->getMock('\\OAuth\\Common\\Http\\Client\\ClientInterface');
+ $client->expects($this->once())->method('retrieveResponse')->will($this->returnValue('{"access_token":"foo","expires_in":"bar","refresh_token":"baz"}'));
+
+ $service = new RunKeeper(
+ $this->getMock('\\OAuth\\Common\\Consumer\\CredentialsInterface'),
+ $client,
+ $this->getMock('\\OAuth\\Common\\Storage\\TokenStorageInterface')
+ );
+
+ $this->assertInstanceOf('\\OAuth\\OAuth2\\Token\\StdOAuth2Token', $service->requestAccessToken('foo'));
+ }
+}
diff --git a/vendor/lusitanian/oauth/tests/Unit/OAuth2/Service/SoundCloudTest.php b/vendor/lusitanian/oauth/tests/Unit/OAuth2/Service/SoundCloudTest.php
new file mode 100644
index 00000000..ac988ba2
--- /dev/null
+++ b/vendor/lusitanian/oauth/tests/Unit/OAuth2/Service/SoundCloudTest.php
@@ -0,0 +1,159 @@
+getMock('\\OAuth\\Common\\Consumer\\CredentialsInterface'),
+ $this->getMock('\\OAuth\\Common\\Http\\Client\\ClientInterface'),
+ $this->getMock('\\OAuth\\Common\\Storage\\TokenStorageInterface')
+ );
+
+ $this->assertInstanceOf('\\OAuth\\OAuth2\\Service\\ServiceInterface', $service);
+ }
+
+ /**
+ * @covers OAuth\OAuth2\Service\SoundCloud::__construct
+ */
+ public function testConstructCorrectInstanceWithoutCustomUri()
+ {
+ $service = new SoundCloud(
+ $this->getMock('\\OAuth\\Common\\Consumer\\CredentialsInterface'),
+ $this->getMock('\\OAuth\\Common\\Http\\Client\\ClientInterface'),
+ $this->getMock('\\OAuth\\Common\\Storage\\TokenStorageInterface')
+ );
+
+ $this->assertInstanceOf('\\OAuth\\OAuth2\\Service\\AbstractService', $service);
+ }
+
+ /**
+ * @covers OAuth\OAuth2\Service\SoundCloud::__construct
+ */
+ public function testConstructCorrectInstanceWithCustomUri()
+ {
+ $service = new SoundCloud(
+ $this->getMock('\\OAuth\\Common\\Consumer\\CredentialsInterface'),
+ $this->getMock('\\OAuth\\Common\\Http\\Client\\ClientInterface'),
+ $this->getMock('\\OAuth\\Common\\Storage\\TokenStorageInterface'),
+ array(),
+ $this->getMock('\\OAuth\\Common\\Http\\Uri\\UriInterface')
+ );
+
+ $this->assertInstanceOf('\\OAuth\\OAuth2\\Service\\AbstractService', $service);
+ }
+
+ /**
+ * @covers OAuth\OAuth2\Service\SoundCloud::__construct
+ * @covers OAuth\OAuth2\Service\SoundCloud::getAuthorizationEndpoint
+ */
+ public function testGetAuthorizationEndpoint()
+ {
+ $service = new SoundCloud(
+ $this->getMock('\\OAuth\\Common\\Consumer\\CredentialsInterface'),
+ $this->getMock('\\OAuth\\Common\\Http\\Client\\ClientInterface'),
+ $this->getMock('\\OAuth\\Common\\Storage\\TokenStorageInterface')
+ );
+
+ $this->assertSame('https://soundcloud.com/connect', $service->getAuthorizationEndpoint()->getAbsoluteUri());
+ }
+
+ /**
+ * @covers OAuth\OAuth2\Service\SoundCloud::__construct
+ * @covers OAuth\OAuth2\Service\SoundCloud::getAccessTokenEndpoint
+ */
+ public function testGetAccessTokenEndpoint()
+ {
+ $service = new SoundCloud(
+ $this->getMock('\\OAuth\\Common\\Consumer\\CredentialsInterface'),
+ $this->getMock('\\OAuth\\Common\\Http\\Client\\ClientInterface'),
+ $this->getMock('\\OAuth\\Common\\Storage\\TokenStorageInterface')
+ );
+
+ $this->assertSame('https://api.soundcloud.com/oauth2/token', $service->getAccessTokenEndpoint()->getAbsoluteUri());
+ }
+
+ /**
+ * @covers OAuth\OAuth2\Service\SoundCloud::__construct
+ * @covers OAuth\OAuth2\Service\SoundCloud::parseAccessTokenResponse
+ */
+ public function testParseAccessTokenResponseThrowsExceptionOnNulledResponse()
+ {
+ $client = $this->getMock('\\OAuth\\Common\\Http\\Client\\ClientInterface');
+ $client->expects($this->once())->method('retrieveResponse')->will($this->returnValue(null));
+
+ $service = new SoundCloud(
+ $this->getMock('\\OAuth\\Common\\Consumer\\CredentialsInterface'),
+ $client,
+ $this->getMock('\\OAuth\\Common\\Storage\\TokenStorageInterface')
+ );
+
+ $this->setExpectedException('\\OAuth\\Common\\Http\\Exception\\TokenResponseException');
+
+ $service->requestAccessToken('foo');
+ }
+
+ /**
+ * @covers OAuth\OAuth2\Service\SoundCloud::__construct
+ * @covers OAuth\OAuth2\Service\SoundCloud::parseAccessTokenResponse
+ */
+ public function testParseAccessTokenResponseThrowsExceptionOnError()
+ {
+ $client = $this->getMock('\\OAuth\\Common\\Http\\Client\\ClientInterface');
+ $client->expects($this->once())->method('retrieveResponse')->will($this->returnValue('error=some_error'));
+
+ $service = new SoundCloud(
+ $this->getMock('\\OAuth\\Common\\Consumer\\CredentialsInterface'),
+ $client,
+ $this->getMock('\\OAuth\\Common\\Storage\\TokenStorageInterface')
+ );
+
+ $this->setExpectedException('\\OAuth\\Common\\Http\\Exception\\TokenResponseException');
+
+ $service->requestAccessToken('foo');
+ }
+
+ /**
+ * @covers OAuth\OAuth2\Service\SoundCloud::__construct
+ * @covers OAuth\OAuth2\Service\SoundCloud::parseAccessTokenResponse
+ */
+ public function testParseAccessTokenResponseValidWithoutRefreshToken()
+ {
+ $client = $this->getMock('\\OAuth\\Common\\Http\\Client\\ClientInterface');
+ $client->expects($this->once())->method('retrieveResponse')->will($this->returnValue('{"access_token":"foo","expires_in":"bar"}'));
+
+ $service = new SoundCloud(
+ $this->getMock('\\OAuth\\Common\\Consumer\\CredentialsInterface'),
+ $client,
+ $this->getMock('\\OAuth\\Common\\Storage\\TokenStorageInterface')
+ );
+
+ $this->assertInstanceOf('\\OAuth\\OAuth2\\Token\\StdOAuth2Token', $service->requestAccessToken('foo'));
+ }
+
+ /**
+ * @covers OAuth\OAuth2\Service\SoundCloud::__construct
+ * @covers OAuth\OAuth2\Service\SoundCloud::parseAccessTokenResponse
+ */
+ public function testParseAccessTokenResponseValidWithRefreshToken()
+ {
+ $client = $this->getMock('\\OAuth\\Common\\Http\\Client\\ClientInterface');
+ $client->expects($this->once())->method('retrieveResponse')->will($this->returnValue('{"access_token":"foo","expires_in":"bar","refresh_token":"baz"}'));
+
+ $service = new SoundCloud(
+ $this->getMock('\\OAuth\\Common\\Consumer\\CredentialsInterface'),
+ $client,
+ $this->getMock('\\OAuth\\Common\\Storage\\TokenStorageInterface')
+ );
+
+ $this->assertInstanceOf('\\OAuth\\OAuth2\\Token\\StdOAuth2Token', $service->requestAccessToken('foo'));
+ }
+}
diff --git a/vendor/lusitanian/oauth/tests/Unit/OAuth2/Service/UstreamTest.php b/vendor/lusitanian/oauth/tests/Unit/OAuth2/Service/UstreamTest.php
new file mode 100644
index 00000000..48965ae0
--- /dev/null
+++ b/vendor/lusitanian/oauth/tests/Unit/OAuth2/Service/UstreamTest.php
@@ -0,0 +1,193 @@
+getMock('\\OAuth\\Common\\Consumer\\CredentialsInterface'),
+ $this->getMock('\\OAuth\\Common\\Http\\Client\\ClientInterface'),
+ $this->getMock('\\OAuth\\Common\\Storage\\TokenStorageInterface')
+ );
+
+ $this->assertInstanceOf('\\OAuth\\OAuth2\\Service\\ServiceInterface', $service);
+ }
+
+ /**
+ * @covers OAuth\OAuth2\Service\Ustream::__construct
+ */
+ public function testConstructCorrectInstanceWithoutCustomUri()
+ {
+ $service = new Ustream(
+ $this->getMock('\\OAuth\\Common\\Consumer\\CredentialsInterface'),
+ $this->getMock('\\OAuth\\Common\\Http\\Client\\ClientInterface'),
+ $this->getMock('\\OAuth\\Common\\Storage\\TokenStorageInterface')
+ );
+
+ $this->assertInstanceOf('\\OAuth\\OAuth2\\Service\\AbstractService', $service);
+ }
+
+ /**
+ * @covers OAuth\OAuth2\Service\Ustream::__construct
+ */
+ public function testConstructCorrectInstanceWithCustomUri()
+ {
+ $service = new Ustream(
+ $this->getMock('\\OAuth\\Common\\Consumer\\CredentialsInterface'),
+ $this->getMock('\\OAuth\\Common\\Http\\Client\\ClientInterface'),
+ $this->getMock('\\OAuth\\Common\\Storage\\TokenStorageInterface'),
+ array(),
+ $this->getMock('\\OAuth\\Common\\Http\\Uri\\UriInterface')
+ );
+
+ $this->assertInstanceOf('\\OAuth\\OAuth2\\Service\\AbstractService', $service);
+ }
+
+ /**
+ * @covers OAuth\OAuth2\Service\Ustream::__construct
+ * @covers OAuth\OAuth2\Service\Ustream::getAuthorizationEndpoint
+ */
+ public function testGetAuthorizationEndpoint()
+ {
+ $service = new Ustream(
+ $this->getMock('\\OAuth\\Common\\Consumer\\CredentialsInterface'),
+ $this->getMock('\\OAuth\\Common\\Http\\Client\\ClientInterface'),
+ $this->getMock('\\OAuth\\Common\\Storage\\TokenStorageInterface')
+ );
+
+ $this->assertSame(
+ 'https://www.ustream.tv/oauth2/authorize',
+ $service->getAuthorizationEndpoint()->getAbsoluteUri()
+ );
+ }
+
+ /**
+ * @covers OAuth\OAuth2\Service\Ustream::__construct
+ * @covers OAuth\OAuth2\Service\Ustream::getAccessTokenEndpoint
+ */
+ public function testGetAccessTokenEndpoint()
+ {
+ $service = new Ustream(
+ $this->getMock('\\OAuth\\Common\\Consumer\\CredentialsInterface'),
+ $this->getMock('\\OAuth\\Common\\Http\\Client\\ClientInterface'),
+ $this->getMock('\\OAuth\\Common\\Storage\\TokenStorageInterface')
+ );
+
+ $this->assertSame(
+ 'https://www.ustream.tv/oauth2/token',
+ $service->getAccessTokenEndpoint()->getAbsoluteUri()
+ );
+ }
+
+ /**
+ * @covers OAuth\OAuth2\Service\Ustream::__construct
+ * @covers OAuth\OAuth2\Service\Ustream::getAuthorizationMethod
+ */
+ public function testGetAuthorizationMethod()
+ {
+ $client = $this->getMock('\\OAuth\\Common\\Http\\Client\\ClientInterface');
+ $client->expects($this->once())->method('retrieveResponse')->will($this->returnArgument(2));
+
+ $token = $this->getMock('\\OAuth\\OAuth2\\Token\\TokenInterface');
+ $token->expects($this->once())->method('getEndOfLife')->will($this->returnValue(TokenInterface::EOL_NEVER_EXPIRES));
+ $token->expects($this->once())->method('getAccessToken')->will($this->returnValue('foo'));
+
+ $storage = $this->getMock('\\OAuth\\Common\\Storage\\TokenStorageInterface');
+ $storage->expects($this->once())->method('retrieveAccessToken')->will($this->returnValue($token));
+
+ $service = new Ustream(
+ $this->getMock('\\OAuth\\Common\\Consumer\\CredentialsInterface'),
+ $client,
+ $storage
+ );
+
+ $headers = $service->request('https://pieterhordijk.com/my/awesome/path');
+
+ $this->assertTrue(array_key_exists('Authorization', $headers));
+ $this->assertTrue(in_array('Bearer foo', $headers, true));
+ }
+
+ /**
+ * @covers OAuth\OAuth2\Service\Ustream::__construct
+ * @covers OAuth\OAuth2\Service\Ustream::parseAccessTokenResponse
+ */
+ public function testParseAccessTokenResponseThrowsExceptionOnNulledResponse()
+ {
+ $client = $this->getMock('\\OAuth\\Common\\Http\\Client\\ClientInterface');
+ $client->expects($this->once())->method('retrieveResponse')->will($this->returnValue(null));
+
+ $service = new Ustream(
+ $this->getMock('\\OAuth\\Common\\Consumer\\CredentialsInterface'),
+ $client,
+ $this->getMock('\\OAuth\\Common\\Storage\\TokenStorageInterface')
+ );
+
+ $this->setExpectedException('\\OAuth\\Common\\Http\\Exception\\TokenResponseException');
+
+ $service->requestAccessToken('foo');
+ }
+
+ /**
+ * @covers OAuth\OAuth2\Service\Ustream::__construct
+ * @covers OAuth\OAuth2\Service\Ustream::parseAccessTokenResponse
+ */
+ public function testParseAccessTokenResponseThrowsExceptionOnError()
+ {
+ $client = $this->getMock('\\OAuth\\Common\\Http\\Client\\ClientInterface');
+ $client->expects($this->once())->method('retrieveResponse')->will($this->returnValue('error=some_error'));
+
+ $service = new Ustream(
+ $this->getMock('\\OAuth\\Common\\Consumer\\CredentialsInterface'),
+ $client,
+ $this->getMock('\\OAuth\\Common\\Storage\\TokenStorageInterface')
+ );
+
+ $this->setExpectedException('\\OAuth\\Common\\Http\\Exception\\TokenResponseException');
+
+ $service->requestAccessToken('foo');
+ }
+
+ /**
+ * @covers OAuth\OAuth2\Service\Ustream::__construct
+ * @covers OAuth\OAuth2\Service\Ustream::parseAccessTokenResponse
+ */
+ public function testParseAccessTokenResponseValidWithoutRefreshToken()
+ {
+ $client = $this->getMock('\\OAuth\\Common\\Http\\Client\\ClientInterface');
+ $client->expects($this->once())->method('retrieveResponse')->will($this->returnValue('{"access_token":"foo","expires_in":"bar"}'));
+
+ $service = new Ustream(
+ $this->getMock('\\OAuth\\Common\\Consumer\\CredentialsInterface'),
+ $client,
+ $this->getMock('\\OAuth\\Common\\Storage\\TokenStorageInterface')
+ );
+
+ $this->assertInstanceOf('\\OAuth\\OAuth2\\Token\\StdOAuth2Token', $service->requestAccessToken('foo'));
+ }
+
+ /**
+ * @covers OAuth\OAuth2\Service\Ustream::__construct
+ * @covers OAuth\OAuth2\Service\Ustream::parseAccessTokenResponse
+ */
+ public function testParseAccessTokenResponseValidWithRefreshToken()
+ {
+ $client = $this->getMock('\\OAuth\\Common\\Http\\Client\\ClientInterface');
+ $client->expects($this->once())->method('retrieveResponse')->will($this->returnValue('{"access_token":"foo","expires_in":"bar","refresh_token":"baz"}'));
+
+ $service = new Ustream(
+ $this->getMock('\\OAuth\\Common\\Consumer\\CredentialsInterface'),
+ $client,
+ $this->getMock('\\OAuth\\Common\\Storage\\TokenStorageInterface')
+ );
+
+ $this->assertInstanceOf('\\OAuth\\OAuth2\\Token\\StdOAuth2Token', $service->requestAccessToken('foo'));
+ }
+}
diff --git a/vendor/lusitanian/oauth/tests/Unit/OAuth2/Service/VkontakteTest.php b/vendor/lusitanian/oauth/tests/Unit/OAuth2/Service/VkontakteTest.php
new file mode 100644
index 00000000..7a8279b2
--- /dev/null
+++ b/vendor/lusitanian/oauth/tests/Unit/OAuth2/Service/VkontakteTest.php
@@ -0,0 +1,159 @@
+getMock('\\OAuth\\Common\\Consumer\\CredentialsInterface'),
+ $this->getMock('\\OAuth\\Common\\Http\\Client\\ClientInterface'),
+ $this->getMock('\\OAuth\\Common\\Storage\\TokenStorageInterface')
+ );
+
+ $this->assertInstanceOf('\\OAuth\\OAuth2\\Service\\ServiceInterface', $service);
+ }
+
+ /**
+ * @covers OAuth\OAuth2\Service\Vkontakte::__construct
+ */
+ public function testConstructCorrectInstanceWithoutCustomUri()
+ {
+ $service = new Vkontakte(
+ $this->getMock('\\OAuth\\Common\\Consumer\\CredentialsInterface'),
+ $this->getMock('\\OAuth\\Common\\Http\\Client\\ClientInterface'),
+ $this->getMock('\\OAuth\\Common\\Storage\\TokenStorageInterface')
+ );
+
+ $this->assertInstanceOf('\\OAuth\\OAuth2\\Service\\AbstractService', $service);
+ }
+
+ /**
+ * @covers OAuth\OAuth2\Service\Vkontakte::__construct
+ */
+ public function testConstructCorrectInstanceWithCustomUri()
+ {
+ $service = new Vkontakte(
+ $this->getMock('\\OAuth\\Common\\Consumer\\CredentialsInterface'),
+ $this->getMock('\\OAuth\\Common\\Http\\Client\\ClientInterface'),
+ $this->getMock('\\OAuth\\Common\\Storage\\TokenStorageInterface'),
+ array(),
+ $this->getMock('\\OAuth\\Common\\Http\\Uri\\UriInterface')
+ );
+
+ $this->assertInstanceOf('\\OAuth\\OAuth2\\Service\\AbstractService', $service);
+ }
+
+ /**
+ * @covers OAuth\OAuth2\Service\Vkontakte::__construct
+ * @covers OAuth\OAuth2\Service\Vkontakte::getAuthorizationEndpoint
+ */
+ public function testGetAuthorizationEndpoint()
+ {
+ $service = new Vkontakte(
+ $this->getMock('\\OAuth\\Common\\Consumer\\CredentialsInterface'),
+ $this->getMock('\\OAuth\\Common\\Http\\Client\\ClientInterface'),
+ $this->getMock('\\OAuth\\Common\\Storage\\TokenStorageInterface')
+ );
+
+ $this->assertSame('https://oauth.vk.com/authorize', $service->getAuthorizationEndpoint()->getAbsoluteUri());
+ }
+
+ /**
+ * @covers OAuth\OAuth2\Service\Vkontakte::__construct
+ * @covers OAuth\OAuth2\Service\Vkontakte::getAccessTokenEndpoint
+ */
+ public function testGetAccessTokenEndpoint()
+ {
+ $service = new Vkontakte(
+ $this->getMock('\\OAuth\\Common\\Consumer\\CredentialsInterface'),
+ $this->getMock('\\OAuth\\Common\\Http\\Client\\ClientInterface'),
+ $this->getMock('\\OAuth\\Common\\Storage\\TokenStorageInterface')
+ );
+
+ $this->assertSame('https://oauth.vk.com/access_token', $service->getAccessTokenEndpoint()->getAbsoluteUri());
+ }
+
+ /**
+ * @covers OAuth\OAuth2\Service\Vkontakte::__construct
+ * @covers OAuth\OAuth2\Service\Vkontakte::parseAccessTokenResponse
+ */
+ public function testParseAccessTokenResponseThrowsExceptionOnNulledResponse()
+ {
+ $client = $this->getMock('\\OAuth\\Common\\Http\\Client\\ClientInterface');
+ $client->expects($this->once())->method('retrieveResponse')->will($this->returnValue(null));
+
+ $service = new Vkontakte(
+ $this->getMock('\\OAuth\\Common\\Consumer\\CredentialsInterface'),
+ $client,
+ $this->getMock('\\OAuth\\Common\\Storage\\TokenStorageInterface')
+ );
+
+ $this->setExpectedException('\\OAuth\\Common\\Http\\Exception\\TokenResponseException');
+
+ $service->requestAccessToken('foo');
+ }
+
+ /**
+ * @covers OAuth\OAuth2\Service\Vkontakte::__construct
+ * @covers OAuth\OAuth2\Service\Vkontakte::parseAccessTokenResponse
+ */
+ public function testParseAccessTokenResponseThrowsExceptionOnError()
+ {
+ $client = $this->getMock('\\OAuth\\Common\\Http\\Client\\ClientInterface');
+ $client->expects($this->once())->method('retrieveResponse')->will($this->returnValue('error=some_error'));
+
+ $service = new Vkontakte(
+ $this->getMock('\\OAuth\\Common\\Consumer\\CredentialsInterface'),
+ $client,
+ $this->getMock('\\OAuth\\Common\\Storage\\TokenStorageInterface')
+ );
+
+ $this->setExpectedException('\\OAuth\\Common\\Http\\Exception\\TokenResponseException');
+
+ $service->requestAccessToken('foo');
+ }
+
+ /**
+ * @covers OAuth\OAuth2\Service\Vkontakte::__construct
+ * @covers OAuth\OAuth2\Service\Vkontakte::parseAccessTokenResponse
+ */
+ public function testParseAccessTokenResponseValidWithoutRefreshToken()
+ {
+ $client = $this->getMock('\\OAuth\\Common\\Http\\Client\\ClientInterface');
+ $client->expects($this->once())->method('retrieveResponse')->will($this->returnValue('{"access_token":"foo","expires_in":"bar"}'));
+
+ $service = new Vkontakte(
+ $this->getMock('\\OAuth\\Common\\Consumer\\CredentialsInterface'),
+ $client,
+ $this->getMock('\\OAuth\\Common\\Storage\\TokenStorageInterface')
+ );
+
+ $this->assertInstanceOf('\\OAuth\\OAuth2\\Token\\StdOAuth2Token', $service->requestAccessToken('foo'));
+ }
+
+ /**
+ * @covers OAuth\OAuth2\Service\Vkontakte::__construct
+ * @covers OAuth\OAuth2\Service\Vkontakte::parseAccessTokenResponse
+ */
+ public function testParseAccessTokenResponseValidWithRefreshToken()
+ {
+ $client = $this->getMock('\\OAuth\\Common\\Http\\Client\\ClientInterface');
+ $client->expects($this->once())->method('retrieveResponse')->will($this->returnValue('{"access_token":"foo","expires_in":"bar","refresh_token":"baz"}'));
+
+ $service = new Vkontakte(
+ $this->getMock('\\OAuth\\Common\\Consumer\\CredentialsInterface'),
+ $client,
+ $this->getMock('\\OAuth\\Common\\Storage\\TokenStorageInterface')
+ );
+
+ $this->assertInstanceOf('\\OAuth\\OAuth2\\Token\\StdOAuth2Token', $service->requestAccessToken('foo'));
+ }
+}
diff --git a/vendor/lusitanian/oauth/tests/Unit/OAuth2/Service/YammerTest.php b/vendor/lusitanian/oauth/tests/Unit/OAuth2/Service/YammerTest.php
new file mode 100644
index 00000000..86440395
--- /dev/null
+++ b/vendor/lusitanian/oauth/tests/Unit/OAuth2/Service/YammerTest.php
@@ -0,0 +1,187 @@
+getMock('\\OAuth\\Common\\Consumer\\CredentialsInterface'),
+ $this->getMock('\\OAuth\\Common\\Http\\Client\\ClientInterface'),
+ $this->getMock('\\OAuth\\Common\\Storage\\TokenStorageInterface')
+ );
+
+ $this->assertInstanceOf('\\OAuth\\OAuth2\\Service\\ServiceInterface', $service);
+ }
+
+ /**
+ * @covers OAuth\OAuth2\Service\Yammer::__construct
+ */
+ public function testConstructCorrectInstanceWithoutCustomUri()
+ {
+ $service = new Yammer(
+ $this->getMock('\\OAuth\\Common\\Consumer\\CredentialsInterface'),
+ $this->getMock('\\OAuth\\Common\\Http\\Client\\ClientInterface'),
+ $this->getMock('\\OAuth\\Common\\Storage\\TokenStorageInterface')
+ );
+
+ $this->assertInstanceOf('\\OAuth\\OAuth2\\Service\\AbstractService', $service);
+ }
+
+ /**
+ * @covers OAuth\OAuth2\Service\Yammer::__construct
+ */
+ public function testConstructCorrectInstanceWithCustomUri()
+ {
+ $service = new Yammer(
+ $this->getMock('\\OAuth\\Common\\Consumer\\CredentialsInterface'),
+ $this->getMock('\\OAuth\\Common\\Http\\Client\\ClientInterface'),
+ $this->getMock('\\OAuth\\Common\\Storage\\TokenStorageInterface'),
+ array(),
+ $this->getMock('\\OAuth\\Common\\Http\\Uri\\UriInterface')
+ );
+
+ $this->assertInstanceOf('\\OAuth\\OAuth2\\Service\\AbstractService', $service);
+ }
+
+ /**
+ * @covers OAuth\OAuth2\Service\Yammer::__construct
+ * @covers OAuth\OAuth2\Service\Yammer::getAuthorizationEndpoint
+ */
+ public function testGetAuthorizationEndpoint()
+ {
+ $service = new Yammer(
+ $this->getMock('\\OAuth\\Common\\Consumer\\CredentialsInterface'),
+ $this->getMock('\\OAuth\\Common\\Http\\Client\\ClientInterface'),
+ $this->getMock('\\OAuth\\Common\\Storage\\TokenStorageInterface')
+ );
+
+ $this->assertSame('https://www.yammer.com/dialog/oauth', $service->getAuthorizationEndpoint()->getAbsoluteUri());
+ }
+
+ /**
+ * @covers OAuth\OAuth2\Service\Yammer::__construct
+ * @covers OAuth\OAuth2\Service\Yammer::getAccessTokenEndpoint
+ */
+ public function testGetAccessTokenEndpoint()
+ {
+ $service = new Yammer(
+ $this->getMock('\\OAuth\\Common\\Consumer\\CredentialsInterface'),
+ $this->getMock('\\OAuth\\Common\\Http\\Client\\ClientInterface'),
+ $this->getMock('\\OAuth\\Common\\Storage\\TokenStorageInterface')
+ );
+
+ $this->assertSame('https://www.yammer.com/oauth2/access_token.json', $service->getAccessTokenEndpoint()->getAbsoluteUri());
+ }
+
+ /**
+ * @covers OAuth\OAuth2\Service\Yammer::__construct
+ * @covers OAuth\OAuth2\Service\Yammer::getAuthorizationMethod
+ */
+ public function testGetAuthorizationMethod()
+ {
+ $client = $this->getMock('\\OAuth\\Common\\Http\\Client\\ClientInterface');
+ $client->expects($this->once())->method('retrieveResponse')->will($this->returnArgument(2));
+
+ $token = $this->getMock('\\OAuth\\OAuth2\\Token\\TokenInterface');
+ $token->expects($this->once())->method('getEndOfLife')->will($this->returnValue(TokenInterface::EOL_NEVER_EXPIRES));
+ $token->expects($this->once())->method('getAccessToken')->will($this->returnValue('foo'));
+
+ $storage = $this->getMock('\\OAuth\\Common\\Storage\\TokenStorageInterface');
+ $storage->expects($this->once())->method('retrieveAccessToken')->will($this->returnValue($token));
+
+ $service = new Yammer(
+ $this->getMock('\\OAuth\\Common\\Consumer\\CredentialsInterface'),
+ $client,
+ $storage
+ );
+
+ $headers = $service->request('https://pieterhordijk.com/my/awesome/path');
+
+ $this->assertTrue(array_key_exists('Authorization', $headers));
+ $this->assertTrue(in_array('Bearer foo', $headers, true));
+ }
+
+ /**
+ * @covers OAuth\OAuth2\Service\Yammer::__construct
+ * @covers OAuth\OAuth2\Service\Yammer::parseAccessTokenResponse
+ */
+ public function testParseAccessTokenResponseThrowsExceptionOnNulledResponse()
+ {
+ $client = $this->getMock('\\OAuth\\Common\\Http\\Client\\ClientInterface');
+ $client->expects($this->once())->method('retrieveResponse')->will($this->returnValue(null));
+
+ $service = new Yammer(
+ $this->getMock('\\OAuth\\Common\\Consumer\\CredentialsInterface'),
+ $client,
+ $this->getMock('\\OAuth\\Common\\Storage\\TokenStorageInterface')
+ );
+
+ $this->setExpectedException('\\OAuth\\Common\\Http\\Exception\\TokenResponseException');
+
+ $service->requestAccessToken('foo');
+ }
+
+ /**
+ * @covers OAuth\OAuth2\Service\Yammer::__construct
+ * @covers OAuth\OAuth2\Service\Yammer::parseAccessTokenResponse
+ */
+ public function testParseAccessTokenResponseThrowsExceptionOnError()
+ {
+ $client = $this->getMock('\\OAuth\\Common\\Http\\Client\\ClientInterface');
+ $client->expects($this->once())->method('retrieveResponse')->will($this->returnValue('error=some_error'));
+
+ $service = new Yammer(
+ $this->getMock('\\OAuth\\Common\\Consumer\\CredentialsInterface'),
+ $client,
+ $this->getMock('\\OAuth\\Common\\Storage\\TokenStorageInterface')
+ );
+
+ $this->setExpectedException('\\OAuth\\Common\\Http\\Exception\\TokenResponseException');
+
+ $service->requestAccessToken('foo');
+ }
+
+ /**
+ * @covers OAuth\OAuth2\Service\Yammer::__construct
+ * @covers OAuth\OAuth2\Service\Yammer::parseAccessTokenResponse
+ */
+ public function testParseAccessTokenResponseValidWithoutRefreshToken()
+ {
+ $client = $this->getMock('\\OAuth\\Common\\Http\\Client\\ClientInterface');
+ $client->expects($this->once())->method('retrieveResponse')->will($this->returnValue('{"access_token":{"token":"foo", "expires_at":null}}'));
+
+ $service = new Yammer(
+ $this->getMock('\\OAuth\\Common\\Consumer\\CredentialsInterface'),
+ $client,
+ $this->getMock('\\OAuth\\Common\\Storage\\TokenStorageInterface')
+ );
+
+ $this->assertInstanceOf('\\OAuth\\OAuth2\\Token\\StdOAuth2Token', $service->requestAccessToken('foo'));
+ }
+
+ /**
+ * @covers OAuth\OAuth2\Service\Yammer::__construct
+ * @covers OAuth\OAuth2\Service\Yammer::parseAccessTokenResponse
+ */
+ public function testParseAccessTokenResponseValidWithRefreshToken()
+ {
+ $client = $this->getMock('\\OAuth\\Common\\Http\\Client\\ClientInterface');
+ $client->expects($this->once())->method('retrieveResponse')->will($this->returnValue('{"access_token":{"token":"foo", "expires_at":null},"refresh_token":"baz"}'));
+
+ $service = new Yammer(
+ $this->getMock('\\OAuth\\Common\\Consumer\\CredentialsInterface'),
+ $client,
+ $this->getMock('\\OAuth\\Common\\Storage\\TokenStorageInterface')
+ );
+
+ $this->assertInstanceOf('\\OAuth\\OAuth2\\Token\\StdOAuth2Token', $service->requestAccessToken('foo'));
+ }
+}
diff --git a/vendor/lusitanian/oauth/tests/Unit/ServiceFactoryTest.php b/vendor/lusitanian/oauth/tests/Unit/ServiceFactoryTest.php
new file mode 100644
index 00000000..26588dc0
--- /dev/null
+++ b/vendor/lusitanian/oauth/tests/Unit/ServiceFactoryTest.php
@@ -0,0 +1,311 @@
+
+ * @author Chris Heng
+ * @author Pieter Hordijk
+ * @copyright Copyright (c) 2013 The authors
+ * @license http://www.opensource.org/licenses/mit-license.html MIT License
+ */
+namespace OAuth\Unit;
+
+use OAuth\ServiceFactory;
+
+class ServiceFactoryTest extends \PHPUnit_Framework_TestCase
+{
+ /**
+ * @covers OAuth\ServiceFactory::setHttpClient
+ */
+ public function testSetHttpClient()
+ {
+ $factory = new ServiceFactory();
+
+ $this->assertInstanceOf(
+ '\\OAuth\\ServiceFactory',
+ $factory->setHttpClient($this->getMock('\\OAuth\\Common\\Http\\Client\\ClientInterface'))
+ );
+ }
+
+ /**
+ * @covers OAuth\ServiceFactory::registerService
+ */
+ public function testRegisterServiceThrowsExceptionNonExistentClass()
+ {
+ $this->setExpectedException('\\OAuth\Common\Exception\Exception');
+
+ $factory = new ServiceFactory();
+ $factory->registerService('foo', 'bar');
+ }
+
+ /**
+ * @covers OAuth\ServiceFactory::registerService
+ */
+ public function testRegisterServiceThrowsExceptionWithClassIncorrectImplementation()
+ {
+ $this->setExpectedException('\\OAuth\Common\Exception\Exception');
+
+ $factory = new ServiceFactory();
+ $factory->registerService('foo', 'OAuth\\ServiceFactory');
+ }
+
+ /**
+ * @covers OAuth\ServiceFactory::registerService
+ */
+ public function testRegisterServiceSuccessOAuth1()
+ {
+ $factory = new ServiceFactory();
+
+ $this->assertInstanceOf(
+ '\\OAuth\\ServiceFactory',
+ $factory->registerService('foo', '\\OAuthTest\\Mocks\\OAuth1\\Service\\Fake')
+ );
+ }
+
+ /**
+ * @covers OAuth\ServiceFactory::registerService
+ */
+ public function testRegisterServiceSuccessOAuth2()
+ {
+ $factory = new ServiceFactory();
+
+ $this->assertInstanceOf(
+ '\\OAuth\\ServiceFactory',
+ $factory->registerService('foo', '\\OAuthTest\\Mocks\\OAuth2\\Service\\Fake')
+ );
+ }
+
+ /**
+ * @covers OAuth\ServiceFactory::createService
+ * @covers OAuth\ServiceFactory::getFullyQualifiedServiceName
+ * @covers OAuth\ServiceFactory::buildV1Service
+ */
+ public function testCreateServiceOAuth1NonRegistered()
+ {
+ $factory = new ServiceFactory();
+
+ $service = $factory->createService(
+ 'twitter',
+ $this->getMock('\\OAuth\\Common\\Consumer\\CredentialsInterface'),
+ $this->getMock('\\OAuth\\Common\\Storage\\TokenStorageInterface')
+ );
+
+ $this->assertInstanceOf('\\OAuth\\OAuth1\\Service\\Twitter', $service);
+ }
+
+ /**
+ * @covers OAuth\ServiceFactory::registerService
+ * @covers OAuth\ServiceFactory::createService
+ * @covers OAuth\ServiceFactory::getFullyQualifiedServiceName
+ * @covers OAuth\ServiceFactory::buildV1Service
+ */
+ public function testCreateServiceOAuth1Registered()
+ {
+ $factory = new ServiceFactory();
+
+ $factory->registerService('foo', '\\OAuthTest\\Mocks\\OAuth1\\Service\\Fake');
+
+ $service = $factory->createService(
+ 'foo',
+ $this->getMock('\\OAuth\\Common\\Consumer\\CredentialsInterface'),
+ $this->getMock('\\OAuth\\Common\\Storage\\TokenStorageInterface')
+ );
+
+ $this->assertInstanceOf('\\OAuth\OAuth1\Service\\ServiceInterface', $service);
+ $this->assertInstanceOf('\\OAuthTest\\Mocks\\OAuth1\\Service\\Fake', $service);
+ }
+
+ /**
+ * @covers OAuth\ServiceFactory::registerService
+ * @covers OAuth\ServiceFactory::createService
+ * @covers OAuth\ServiceFactory::getFullyQualifiedServiceName
+ * @covers OAuth\ServiceFactory::buildV1Service
+ */
+ public function testCreateServiceOAuth1RegisteredAndNonRegisteredSameName()
+ {
+ $factory = new ServiceFactory();
+
+ $factory->registerService('twitter', '\\OAuthTest\\Mocks\\OAuth1\\Service\\Fake');
+
+ $service = $factory->createService(
+ 'twitter',
+ $this->getMock('\\OAuth\\Common\\Consumer\\CredentialsInterface'),
+ $this->getMock('\\OAuth\\Common\\Storage\\TokenStorageInterface')
+ );
+
+ $this->assertInstanceOf('\\OAuth\OAuth1\Service\\ServiceInterface', $service);
+ $this->assertInstanceOf('\\OAuthTest\\Mocks\\OAuth1\\Service\\Fake', $service);
+ }
+
+ /**
+ * @covers OAuth\ServiceFactory::createService
+ * @covers OAuth\ServiceFactory::getFullyQualifiedServiceName
+ * @covers OAuth\ServiceFactory::buildV2Service
+ * @covers OAuth\ServiceFactory::resolveScopes
+ */
+ public function testCreateServiceOAuth2NonRegistered()
+ {
+ $factory = new ServiceFactory();
+
+ $service = $factory->createService(
+ 'facebook',
+ $this->getMock('\\OAuth\\Common\\Consumer\\CredentialsInterface'),
+ $this->getMock('\\OAuth\\Common\\Storage\\TokenStorageInterface')
+ );
+
+ $this->assertInstanceOf('\\OAuth\\OAuth2\\Service\\Facebook', $service);
+ }
+
+ /**
+ * @covers OAuth\ServiceFactory::createService
+ * @covers OAuth\ServiceFactory::getFullyQualifiedServiceName
+ * @covers OAuth\ServiceFactory::buildV2Service
+ * @covers OAuth\ServiceFactory::resolveScopes
+ */
+ public function testCreateServiceOAuth2Registered()
+ {
+ $factory = new ServiceFactory();
+
+ $factory->registerService('foo', '\\OAuthTest\\Mocks\\OAuth2\\Service\\Fake');
+
+ $service = $factory->createService(
+ 'foo',
+ $this->getMock('\\OAuth\\Common\\Consumer\\CredentialsInterface'),
+ $this->getMock('\\OAuth\\Common\\Storage\\TokenStorageInterface')
+ );
+
+ $this->assertInstanceOf('\\OAuth\OAuth2\Service\\ServiceInterface', $service);
+ $this->assertInstanceOf('\\OAuthTest\\Mocks\\OAuth2\\Service\\Fake', $service);
+ }
+
+ /**
+ * @covers OAuth\ServiceFactory::createService
+ * @covers OAuth\ServiceFactory::getFullyQualifiedServiceName
+ * @covers OAuth\ServiceFactory::buildV2Service
+ * @covers OAuth\ServiceFactory::resolveScopes
+ */
+ public function testCreateServiceOAuth2RegisteredAndNonRegisteredSameName()
+ {
+ $factory = new ServiceFactory();
+
+ $factory->registerService('facebook', '\\OAuthTest\\Mocks\\OAuth2\\Service\\Fake');
+
+ $service = $factory->createService(
+ 'facebook',
+ $this->getMock('\\OAuth\\Common\\Consumer\\CredentialsInterface'),
+ $this->getMock('\\OAuth\\Common\\Storage\\TokenStorageInterface')
+ );
+
+ $this->assertInstanceOf('\\OAuth\OAuth2\Service\\ServiceInterface', $service);
+ $this->assertInstanceOf('\\OAuthTest\\Mocks\\OAuth2\\Service\\Fake', $service);
+ }
+
+ /**
+ * @covers OAuth\ServiceFactory::registerService
+ * @covers OAuth\ServiceFactory::createService
+ * @covers OAuth\ServiceFactory::getFullyQualifiedServiceName
+ * @covers OAuth\ServiceFactory::buildV1Service
+ */
+ public function testCreateServiceThrowsExceptionOnPassingScopesToV1Service()
+ {
+ $this->setExpectedException('\\OAuth\Common\Exception\Exception');
+
+ $factory = new ServiceFactory();
+
+ $factory->registerService('foo', '\\OAuthTest\\Mocks\\OAuth1\\Service\\Fake');
+
+ $service = $factory->createService(
+ 'foo',
+ $this->getMock('\\OAuth\\Common\\Consumer\\CredentialsInterface'),
+ $this->getMock('\\OAuth\\Common\\Storage\\TokenStorageInterface'),
+ array('bar')
+ );
+ }
+
+ /**
+ * @covers OAuth\ServiceFactory::createService
+ * @covers OAuth\ServiceFactory::getFullyQualifiedServiceName
+ */
+ public function testCreateServiceNonExistentService()
+ {
+ $factory = new ServiceFactory();
+
+ $service = $factory->createService(
+ 'foo',
+ $this->getMock('\\OAuth\\Common\\Consumer\\CredentialsInterface'),
+ $this->getMock('\\OAuth\\Common\\Storage\\TokenStorageInterface')
+ );
+
+ $this->assertNull($service);
+ }
+
+ /**
+ * @covers OAuth\ServiceFactory::registerService
+ * @covers OAuth\ServiceFactory::createService
+ * @covers OAuth\ServiceFactory::getFullyQualifiedServiceName
+ * @covers OAuth\ServiceFactory::buildV2Service
+ * @covers OAuth\ServiceFactory::resolveScopes
+ */
+ public function testCreateServicePrefersOauth2()
+ {
+ $factory = new ServiceFactory();
+
+ $factory->registerService('foo', '\\OAuthTest\\Mocks\\OAuth1\\Service\\Fake');
+ $factory->registerService('foo', '\\OAuthTest\\Mocks\\OAuth2\\Service\\Fake');
+
+ $service = $factory->createService(
+ 'foo',
+ $this->getMock('\\OAuth\\Common\\Consumer\\CredentialsInterface'),
+ $this->getMock('\\OAuth\\Common\\Storage\\TokenStorageInterface')
+ );
+
+ $this->assertInstanceOf('\\OAuth\OAuth2\Service\\ServiceInterface', $service);
+ $this->assertInstanceOf('\\OAuthTest\\Mocks\\OAuth2\\Service\\Fake', $service);
+ }
+
+ /**
+ * @covers OAuth\ServiceFactory::createService
+ * @covers OAuth\ServiceFactory::getFullyQualifiedServiceName
+ * @covers OAuth\ServiceFactory::buildV2Service
+ * @covers OAuth\ServiceFactory::resolveScopes
+ */
+ public function testCreateServiceOAuth2RegisteredWithClassConstantsAsScope()
+ {
+ $factory = new ServiceFactory();
+
+ $factory->registerService('foo', '\\OAuthTest\\Mocks\\OAuth2\\Service\\Fake');
+
+ $service = $factory->createService(
+ 'foo',
+ $this->getMock('\\OAuth\\Common\\Consumer\\CredentialsInterface'),
+ $this->getMock('\\OAuth\\Common\\Storage\\TokenStorageInterface'),
+ array('FOO')
+ );
+
+ $this->assertInstanceOf('\\OAuth\OAuth2\Service\\ServiceInterface', $service);
+ $this->assertInstanceOf('\\OAuthTest\\Mocks\\OAuth2\\Service\\Fake', $service);
+ }
+
+ /**
+ * @covers OAuth\ServiceFactory::createService
+ * @covers OAuth\ServiceFactory::getFullyQualifiedServiceName
+ * @covers OAuth\ServiceFactory::buildV2Service
+ * @covers OAuth\ServiceFactory::resolveScopes
+ */
+ public function testCreateServiceOAuth2RegisteredWithCustomScope()
+ {
+ $factory = new ServiceFactory();
+
+ $factory->registerService('foo', '\\OAuthTest\\Mocks\\OAuth2\\Service\\Fake');
+
+ $service = $factory->createService(
+ 'foo',
+ $this->getMock('\\OAuth\\Common\\Consumer\\CredentialsInterface'),
+ $this->getMock('\\OAuth\\Common\\Storage\\TokenStorageInterface'),
+ array('custom')
+ );
+
+ $this->assertInstanceOf('\\OAuth\OAuth2\Service\\ServiceInterface', $service);
+ $this->assertInstanceOf('\\OAuthTest\\Mocks\\OAuth2\\Service\\Fake', $service);
+ }
+}
diff --git a/vendor/lusitanian/oauth/tests/bootstrap.php b/vendor/lusitanian/oauth/tests/bootstrap.php
new file mode 100644
index 00000000..193b857a
--- /dev/null
+++ b/vendor/lusitanian/oauth/tests/bootstrap.php
@@ -0,0 +1,42 @@
+
+ * @author David Desberg
+ * @copyright Copyright (c) 2012 Pieter Hordijk
+ * @license http://www.opensource.org/licenses/mit-license.html MIT License
+ */
+namespace OAuthTest;
+
+/**
+ * Setting up the default timezone. because well... PHP sucks
+ */
+date_default_timezone_set('Europe/Amsterdam');
+
+/**
+ * Simple SPL autoloader for the OAuthTest mocks
+ *
+ * @param string $class The class name to load
+ *
+ * @return void
+ */
+spl_autoload_register(function ($class) {
+ $nslen = strlen(__NAMESPACE__);
+ if (substr($class, 0, $nslen) !== __NAMESPACE__) {
+ return;
+ }
+ $path = substr(str_replace('\\', '/', $class), $nslen);
+ $path = __DIR__ . $path . '.php';
+ if (file_exists($path)) {
+ require $path;
+ }
+});
+
+/**
+ * Fire up the autoloader
+ */
+require_once __DIR__ . '/../vendor/autoload.php';
diff --git a/vendor/swiftmailer/swiftmailer/.gitattributes b/vendor/swiftmailer/swiftmailer/.gitattributes
new file mode 100644
index 00000000..5568ef09
--- /dev/null
+++ b/vendor/swiftmailer/swiftmailer/.gitattributes
@@ -0,0 +1,6 @@
+*.crt -crlf
+*.key -crlf
+*.srl -crlf
+*.pub -crlf
+*.priv -crlf
+*.txt -crlf
diff --git a/vendor/swiftmailer/swiftmailer/.gitignore b/vendor/swiftmailer/swiftmailer/.gitignore
new file mode 100644
index 00000000..9a23ffe6
--- /dev/null
+++ b/vendor/swiftmailer/swiftmailer/.gitignore
@@ -0,0 +1,4 @@
+/tests/acceptance.conf.php
+/tests/smoke.conf.php
+/build/*
+/vendor/
diff --git a/vendor/swiftmailer/swiftmailer/.travis.yml b/vendor/swiftmailer/swiftmailer/.travis.yml
new file mode 100644
index 00000000..cadee014
--- /dev/null
+++ b/vendor/swiftmailer/swiftmailer/.travis.yml
@@ -0,0 +1,25 @@
+language: php
+
+php:
+ - 5.3
+ - 5.4
+ - 5.5
+ - 5.6
+ - hhvm-nightly
+
+before_script:
+ - cp tests/acceptance.conf.php.default tests/acceptance.conf.php
+ - cp tests/smoke.conf.php.default tests/smoke.conf.php
+ - composer self-update
+ - composer update --no-interaction --prefer-source
+ - gem install mailcatcher
+ - mailcatcher --smtp-port 4456
+
+script:
+ - phpunit --verbose
+
+matrix:
+ allow_failures:
+ - php: 5.6
+ - php: hhvm-nightly
+ fast_finish: true
diff --git a/vendor/swiftmailer/swiftmailer/CHANGES b/vendor/swiftmailer/swiftmailer/CHANGES
new file mode 100644
index 00000000..177766fa
--- /dev/null
+++ b/vendor/swiftmailer/swiftmailer/CHANGES
@@ -0,0 +1,186 @@
+Changelog
+=========
+
+5.3.0 (2014-10-04)
+------------------
+
+ * fixed cloning when using signers
+ * reverted removal of Swift_Encoding
+ * drop support for PHP 5.2.x
+
+5.2.2 (2014-09-20)
+------------------
+
+ * fixed Japanese support
+ * fixed the memory spool when the message changes when in the pool
+ * added support for cloning messages
+ * fixed PHP warning in the redirect plugin
+ * changed the way to and cc-ed email are sent to only use one transaction
+
+5.2.1 (2014-06-13)
+------------------
+
+ * SECURITY FIX: fixed CLI escaping when using sendmail as a transport
+
+ Prior to 5.2.1, the sendmail transport (Swift_Transport_SendmailTransport)
+ was vulnerable to an arbitrary shell execution if the "From" header came
+ from a non-trusted source and no "Return-Path" is configured.
+
+ * fixed parameter in DKIMSigner
+ * fixed compatibility with PHP < 5.4
+
+5.2.0 (2014-05-08)
+------------------
+
+ * fixed Swift_ByteStream_FileByteStream::read() to match to the specification
+ * fixed from-charset and to-charset arguments in mbstring_convert_encoding() usages
+ * fixed infinite loop in StreamBuffer
+ * fixed NullTransport to return the number of ignored emails instead of 0
+ * Use phpunit and mockery for unit testing (realityking)
+
+5.1.0 (2014-03-18)
+------------------
+
+ * fixed data writing to stream when sending large messages
+ * added support for libopendkim (https://github.com/xdecock/php-opendkim)
+ * merged SignedMessage and Message
+ * added Gmail XOAuth2 authentication
+ * updated the list of known mime types
+ * added NTLM authentication
+
+5.0.3 (2013-12-03)
+------------------
+
+ * fixed double-dot bug
+ * fixed DKIM signer
+
+5.0.2 (2013-08-30)
+------------------
+
+ * handled correct exception type while reading IoBuffer output
+
+5.0.1 (2013-06-17)
+------------------
+
+ * changed the spool to only start the transport when a mail has to be sent
+ * fixed compatibility with PHP 5.2
+ * fixed LICENSE file
+
+5.0.0 (2013-04-30)
+------------------
+
+ * changed the license from LGPL to MIT
+
+4.3.1 (2013-04-11)
+------------------
+
+ * removed usage of the native QP encoder when the charset is not UTF-8
+ * fixed usage of uniqid to avoid collisions
+ * made a performance improvement when tokenizing large headers
+ * fixed usage of the PHP native QP encoder on PHP 5.4.7+
+
+4.3.0 (2013-01-08)
+------------------
+
+ * made the temporary directory configurable via the TMPDIR env variable
+ * added S/MIME signer and encryption support
+
+4.2.2 (2012-10-25)
+------------------
+
+ * added the possibility to throttle messages per second in ThrottlerPlugin (mostly for Amazon SES)
+ * switched mime.qpcontentencoder to automatically use the PHP native encoder on PHP 5.4.7+
+ * allowed specifying a whitelist with regular expressions in RedirectingPlugin
+
+4.2.1 (2012-07-13)
+------------------
+
+ * changed the coding standards to PSR-1/2
+ * fixed issue with autoloading
+ * added NativeQpContentEncoder to enhance performance (for PHP 5.3+)
+
+4.2.0 (2012-06-29)
+------------------
+
+ * added documentation about how to use the Japanese support introduced in 4.1.8
+ * added a way to override the default configuration in a lazy way
+ * changed the PEAR init script to lazy-load the initialization
+ * fixed a bug when calling Swift_Preferences before anything else (regression introduced in 4.1.8)
+
+4.1.8 (2012-06-17)
+------------------
+
+ * added Japanese iso-2022-jp support
+ * changed the init script to lazy-load the initialization
+ * fixed docblocks (@id) which caused some problems with libraries parsing the dobclocks
+ * fixed Swift_Mime_Headers_IdentificationHeader::setId() when passed an array of ids
+ * fixed encoding of email addresses in headers
+ * added replacements setter to the Decorator plugin
+
+4.1.7 (2012-04-26)
+------------------
+
+ * fixed QpEncoder safeMapShareId property
+
+4.1.6 (2012-03-23)
+------------------
+
+ * reduced the size of serialized Messages
+
+4.1.5 (2012-01-04)
+------------------
+
+ * enforced Swift_Spool::queueMessage() to return a Boolean
+ * made an optimization to the memory spool: start the transport only when required
+ * prevented stream_socket_client() from generating an error and throw a Swift_TransportException instead
+ * fixed a PHP warning when calling to mail() when safe_mode is off
+ * many doc tweaks
+
+4.1.4 (2011-12-16)
+------------------
+
+ * added a memory spool (Swift_MemorySpool)
+ * fixed too many opened files when sending emails with attachments
+
+4.1.3 (2011-10-27)
+------------------
+
+ * added STARTTLS support
+ * added missing @return tags on fluent methods
+ * added a MessageLogger plugin that logs all sent messages
+ * added composer.json
+
+4.1.2 (2011-09-13)
+------------------
+
+ * fixed wrong detection of magic_quotes_runtime
+ * fixed fatal errors when no To or Subject header has been set
+ * fixed charset on parameter header continuations
+ * added documentation about how to install Swiftmailer from the PEAR channel
+ * fixed various typos and markup problem in the documentation
+ * fixed warning when cache directory does not exist
+ * fixed "slashes are escaped" bug
+ * changed require_once() to require() in autoload
+
+4.1.1 (2011-07-04)
+------------------
+
+ * added missing file in PEAR package
+
+4.1.0 (2011-06-30)
+------------------
+
+ * documentation has been converted to ReST
+
+4.1.0 RC1 (2011-06-17)
+----------------------
+
+New features:
+
+ * changed the Decorator Plugin to allow replacements in all headers
+ * added Swift_Mime_Grammar and Swift_Validate to validate an email address
+ * modified the autoloader to lazy-initialize Swiftmailer
+ * removed Swift_Mailer::batchSend()
+ * added NullTransport
+ * added new plugins: RedirectingPlugin and ImpersonatePlugin
+ * added a way to send messages asynchronously (Spool)
diff --git a/vendor/swiftmailer/swiftmailer/LICENSE b/vendor/swiftmailer/swiftmailer/LICENSE
new file mode 100644
index 00000000..674bb2a6
--- /dev/null
+++ b/vendor/swiftmailer/swiftmailer/LICENSE
@@ -0,0 +1,19 @@
+Copyright (c) 2013 Fabien Potencier
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is furnished
+to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
diff --git a/vendor/swiftmailer/swiftmailer/README b/vendor/swiftmailer/swiftmailer/README
new file mode 100644
index 00000000..eb5f8bcf
--- /dev/null
+++ b/vendor/swiftmailer/swiftmailer/README
@@ -0,0 +1,16 @@
+Swift Mailer
+------------
+
+Swift Mailer is a component based mailing solution for PHP 5.
+It is released under the MIT license.
+
+Homepage: http://swiftmailer.org
+Documentation: http://swiftmailer.org/docs
+Mailing List: http://groups.google.com/group/swiftmailer
+Bugs: https://github.com/swiftmailer/swiftmailer/issues
+Repository: https://github.com/swiftmailer/swiftmailer
+
+Swift Mailer is highly object-oriented by design and lends itself
+to use in complex web application with a great deal of flexibility.
+
+For full details on usage, see the documentation.
diff --git a/vendor/swiftmailer/swiftmailer/VERSION b/vendor/swiftmailer/swiftmailer/VERSION
new file mode 100644
index 00000000..97a04ab9
--- /dev/null
+++ b/vendor/swiftmailer/swiftmailer/VERSION
@@ -0,0 +1 @@
+Swift-5.3.0
diff --git a/vendor/swiftmailer/swiftmailer/composer.json b/vendor/swiftmailer/swiftmailer/composer.json
new file mode 100644
index 00000000..ccc66326
--- /dev/null
+++ b/vendor/swiftmailer/swiftmailer/composer.json
@@ -0,0 +1,31 @@
+{
+ "name": "swiftmailer/swiftmailer",
+ "type": "library",
+ "description": "Swiftmailer, free feature-rich PHP mailer",
+ "keywords": ["mail","mailer"],
+ "homepage": "http://swiftmailer.org",
+ "license": "MIT",
+ "authors": [
+ {
+ "name": "Chris Corbyn"
+ },
+ {
+ "name": "Fabien Potencier",
+ "email": "fabien@symfony.com"
+ }
+ ],
+ "require": {
+ "php": ">=5.3.3"
+ },
+ "require-dev": {
+ "mockery/mockery": "~0.9.1"
+ },
+ "autoload": {
+ "files": ["lib/swift_required.php"]
+ },
+ "extra": {
+ "branch-alias": {
+ "dev-master": "5.3-dev"
+ }
+ }
+}
diff --git a/vendor/swiftmailer/swiftmailer/doc/headers.rst b/vendor/swiftmailer/swiftmailer/doc/headers.rst
new file mode 100644
index 00000000..6aec23ff
--- /dev/null
+++ b/vendor/swiftmailer/swiftmailer/doc/headers.rst
@@ -0,0 +1,742 @@
+Message Headers
+===============
+
+Sometimes you'll want to add your own headers to a message or modify/remove
+headers that are already present. You work with the message's HeaderSet to do
+this.
+
+Header Basics
+-------------
+
+All MIME entities in Swift Mailer -- including the message itself --
+store their headers in a single object called a HeaderSet. This HeaderSet is
+retrieved with the ``getHeaders()`` method.
+
+As mentioned in the previous chapter, everything that forms a part of a message
+in Swift Mailer is a MIME entity that is represented by an instance of
+``Swift_Mime_MimeEntity``. This includes -- most notably -- the message object
+itself, attachments, MIME parts and embedded images. Each of these MIME entities
+consists of a body and a set of headers that describe the body.
+
+For all of the "standard" headers in these MIME entities, such as the
+``Content-Type``, there are named methods for working with them, such as
+``setContentType()`` and ``getContentType()``. This is because headers are a
+moderately complex area of the library. Each header has a slightly different
+required structure that it must meet in order to comply with the standards that
+govern email (and that are checked by spam blockers etc).
+
+You fetch the HeaderSet from a MIME entity like so:
+
+.. code-block:: php
+
+ $message = Swift_Message::newInstance();
+
+ // Fetch the HeaderSet from a Message object
+ $headers = $message->getHeaders();
+
+ $attachment = Swift_Attachment::fromPath('document.pdf');
+
+ // Fetch the HeaderSet from an attachment object
+ $headers = $attachment->getHeaders();
+
+The job of the HeaderSet is to contain and manage instances of Header objects.
+Depending upon the MIME entity the HeaderSet came from, the contents of the
+HeaderSet will be different, since an attachment for example has a different
+set of headers to those in a message.
+
+You can find out what the HeaderSet contains with a quick loop, dumping out
+the names of the headers:
+
+.. code-block:: php
+
+ foreach ($headers->getAll() as $header) {
+ printf("%s \n", $header->getFieldName());
+ }
+
+ /*
+ Content-Transfer-Encoding
+ Content-Type
+ MIME-Version
+ Date
+ Message-ID
+ From
+ Subject
+ To
+ */
+
+You can also dump out the rendered HeaderSet by calling its ``toString()``
+method:
+
+.. code-block:: php
+
+ echo $headers->toString();
+
+ /*
+ Message-ID: <1234869991.499a9ee7f1d5e@swift.generated>
+ Date: Tue, 17 Feb 2009 22:26:31 +1100
+ Subject: Awesome subject!
+ From: sender@example.org
+ To: recipient@example.org
+ MIME-Version: 1.0
+ Content-Type: text/plain; charset=utf-8
+ Content-Transfer-Encoding: quoted-printable
+ */
+
+Where the complexity comes in is when you want to modify an existing header.
+This complexity comes from the fact that each header can be of a slightly
+different type (such as a Date header, or a header that contains email
+addresses, or a header that has key-value parameters on it!). Each header in the
+HeaderSet is an instance of ``Swift_Mime_Header``. They all have common
+functionality, but knowing exactly what type of header you're working with will
+allow you a little more control.
+
+You can determine the type of header by comparing the return value of its
+``getFieldType()`` method with the constants ``TYPE_TEXT``,
+``TYPE_PARAMETERIZED``, ``TYPE_DATE``, ``TYPE_MAILBOX``, ``TYPE_ID`` and
+``TYPE_PATH`` which are defined in ``Swift_Mime_Header``.
+
+
+.. code-block:: php
+
+ foreach ($headers->getAll() as $header) {
+ switch ($header->getFieldType()) {
+ case Swift_Mime_Header::TYPE_TEXT: $type = 'text';
+ break;
+ case Swift_Mime_Header::TYPE_PARAMETERIZED: $type = 'parameterized';
+ break;
+ case Swift_Mime_Header::TYPE_MAILBOX: $type = 'mailbox';
+ break;
+ case Swift_Mime_Header::TYPE_DATE: $type = 'date';
+ break;
+ case Swift_Mime_Header::TYPE_ID: $type = 'ID';
+ break;
+ case Swift_Mime_Header::TYPE_PATH: $type = 'path';
+ break;
+ }
+ printf("%s: is a %s header \n", $header->getFieldName(), $type);
+ }
+
+ /*
+ Content-Transfer-Encoding: is a text header
+ Content-Type: is a parameterized header
+ MIME-Version: is a text header
+ Date: is a date header
+ Message-ID: is a ID header
+ From: is a mailbox header
+ Subject: is a text header
+ To: is a mailbox header
+ */
+
+Headers can be removed from the set, modified within the set, or added to the
+set.
+
+The following sections show you how to work with the HeaderSet and explain the
+details of each implementation of ``Swift_Mime_Header`` that may
+exist within the HeaderSet.
+
+Header Types
+------------
+
+Because all headers are modeled on different data (dates, addresses, text!)
+there are different types of Header in Swift Mailer. Swift Mailer attempts to
+categorize all possible MIME headers into more general groups, defined by a
+small number of classes.
+
+Text Headers
+~~~~~~~~~~~~
+
+Text headers are the simplest type of Header. They contain textual information
+with no special information included within it -- for example the Subject
+header in a message.
+
+There's nothing particularly interesting about a text header, though it is
+probably the one you'd opt to use if you need to add a custom header to a
+message. It represents text just like you'd think it does. If the text
+contains characters that are not permitted in a message header (such as new
+lines, or non-ascii characters) then the header takes care of encoding the
+text so that it can be used.
+
+No header -- including text headers -- in Swift Mailer is vulnerable to
+header-injection attacks. Swift Mailer breaks any attempt at header injection by
+encoding the dangerous data into a non-dangerous form.
+
+It's easy to add a new text header to a HeaderSet. You do this by calling the
+HeaderSet's ``addTextHeader()`` method.
+
+.. code-block:: php
+
+ $message = Swift_Message::newInstance();
+
+ $headers = $message->getHeaders();
+
+ $headers->addTextHeader('Your-Header-Name', 'the header value');
+
+Changing the value of an existing text header is done by calling it's
+``setValue()`` method.
+
+.. code-block:: php
+
+ $subject = $message->getHeaders()->get('Subject');
+
+ $subject->setValue('new subject');
+
+When output via ``toString()``, a text header produces something like the
+following:
+
+.. code-block:: php
+
+ $subject = $message->getHeaders()->get('Subject');
+
+ $subject->setValue('amazing subject line');
+
+ echo $subject->toString();
+
+ /*
+
+ Subject: amazing subject line
+
+ */
+
+If the header contains any characters that are outside of the US-ASCII range
+however, they will be encoded. This is nothing to be concerned about since
+mail clients will decode them back.
+
+.. code-block:: php
+
+ $subject = $message->getHeaders()->get('Subject');
+
+ $subject->setValue('contains – dash');
+
+ echo $subject->toString();
+
+ /*
+
+ Subject: contains =?utf-8?Q?=E2=80=93?= dash
+
+ */
+
+Parameterized Headers
+~~~~~~~~~~~~~~~~~~~~~
+
+Parameterized headers are text headers that contain key-value parameters
+following the textual content. The Content-Type header of a message is a
+parameterized header since it contains charset information after the content
+type.
+
+The parameterized header type is a special type of text header. It extends the
+text header by allowing additional information to follow it. All of the methods
+from text headers are available in addition to the methods described here.
+
+Adding a parameterized header to a HeaderSet is done by using the
+``addParameterizedHeader()`` method which takes a text value like
+``addTextHeader()`` but it also accepts an associative array of
+key-value parameters.
+
+.. code-block:: php
+
+ $message = Swift_Message::newInstance();
+
+ $headers = $message->getHeaders();
+
+ $headers->addParameterizedHeader(
+ 'Header-Name', 'header value',
+ array('foo' => 'bar')
+ );
+
+To change the text value of the header, call it's ``setValue()`` method just as
+you do with text headers.
+
+To change the parameters in the header, call the header's ``setParameters()``
+method or the ``setParameter()`` method (note the pluralization).
+
+.. code-block:: php
+
+ $type = $message->getHeaders()->get('Content-Type');
+
+ // setParameters() takes an associative array
+ $type->setParameters(array(
+ 'name' => 'file.txt',
+ 'charset' => 'iso-8859-1'
+ ));
+
+ // setParameter() takes two args for $key and $value
+ $type->setParameter('charset', 'iso-8859-1');
+
+When output via ``toString()``, a parameterized header produces something like
+the following:
+
+.. code-block:: php
+
+ $type = $message->getHeaders()->get('Content-Type');
+
+ $type->setValue('text/html');
+ $type->setParameter('charset', 'utf-8');
+
+ echo $type->toString();
+
+ /*
+
+ Content-Type: text/html; charset=utf-8
+
+ */
+
+If the header contains any characters that are outside of the US-ASCII range
+however, they will be encoded, just like they are for text headers. This is
+nothing to be concerned about since mail clients will decode them back.
+Likewise, if the parameters contain any non-ascii characters they will be
+encoded so that they can be transmitted safely.
+
+.. code-block:: php
+
+ $attachment = Swift_Attachment::newInstance();
+
+ $disp = $attachment->getHeaders()->get('Content-Disposition');
+
+ $disp->setValue('attachment');
+ $disp->setParameter('filename', 'report–may.pdf');
+
+ echo $disp->toString();
+
+ /*
+
+ Content-Disposition: attachment; filename*=utf-8''report%E2%80%93may.pdf
+
+ */
+
+Date Headers
+~~~~~~~~~~~~
+
+Date headers contains an RFC 2822 formatted date (i.e. what PHP's ``date('r')``
+returns). They are used anywhere a date or time is needed to be presented as a
+message header.
+
+The data on which a date header is modeled is simply a UNIX timestamp such as
+that returned by ``time()`` or ``strtotime()``. The timestamp is used to create
+a correctly structured RFC 2822 formatted date such as
+``Tue, 17 Feb 2009 22:26:31 +1100``.
+
+The obvious place this header type is used is in the ``Date:`` header of the
+message itself.
+
+It's easy to add a new date header to a HeaderSet. You do this by calling
+the HeaderSet's ``addDateHeader()`` method.
+
+.. code-block:: php
+
+ $message = Swift_Message::newInstance();
+
+ $headers = $message->getHeaders();
+
+ $headers->addDateHeader('Your-Header-Name', strtotime('3 days ago'));
+
+Changing the value of an existing date header is done by calling it's
+``setTimestamp()`` method.
+
+.. code-block:: php
+
+ $date = $message->getHeaders()->get('Date');
+
+ $date->setTimestamp(time());
+
+When output via ``toString()``, a date header produces something like the
+following:
+
+.. code-block:: php
+
+ $date = $message->getHeaders()->get('Date');
+
+ echo $date->toString();
+
+ /*
+
+ Date: Wed, 18 Feb 2009 13:35:02 +1100
+
+ */
+
+Mailbox (e-mail address) Headers
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+Mailbox headers contain one or more email addresses, possibly with
+personalized names attached to them. The data on which they are modeled is
+represented by an associative array of email addresses and names.
+
+Mailbox headers are probably the most complex header type to understand in
+Swift Mailer because they accept their input as an array which can take various
+forms, as described in the previous chapter.
+
+All of the headers that contain e-mail addresses in a message -- with the
+exception of ``Return-Path:`` which has a stricter syntax -- use this header
+type. That is, ``To:``, ``From:`` etc.
+
+You add a new mailbox header to a HeaderSet by calling the HeaderSet's
+``addMailboxHeader()`` method.
+
+.. code-block:: php
+
+ $message = Swift_Message::newInstance();
+
+ $headers = $message->getHeaders();
+
+ $headers->addMailboxHeader('Your-Header-Name', array(
+ 'person1@example.org' => 'Person Name One',
+ 'person2@example.org',
+ 'person3@example.org',
+ 'person4@example.org' => 'Another named person'
+ ));
+
+Changing the value of an existing mailbox header is done by calling it's
+``setNameAddresses()`` method.
+
+.. code-block:: php
+
+ $to = $message->getHeaders()->get('To');
+
+ $to->setNameAddresses(array(
+ 'joe@example.org' => 'Joe Bloggs',
+ 'john@example.org' => 'John Doe',
+ 'no-name@example.org'
+ ));
+
+If you don't wish to concern yourself with the complicated accepted input
+formats accepted by ``setNameAddresses()`` as described in the previous chapter
+and you only want to set one or more addresses (not names) then you can just
+use the ``setAddresses()`` method instead.
+
+.. code-block:: php
+
+ $to = $message->getHeaders()->get('To');
+
+ $to->setAddresses(array(
+ 'joe@example.org',
+ 'john@example.org',
+ 'no-name@example.org'
+ ));
+
+.. note::
+
+ Both methods will accept the above input format in practice.
+
+If all you want to do is set a single address in the header, you can use a
+string as the input parameter to ``setAddresses()`` and/or
+``setNameAddresses()``.
+
+.. code-block:: php
+
+ $to = $message->getHeaders()->get('To');
+
+ $to->setAddresses('joe-bloggs@example.org');
+
+When output via ``toString()``, a mailbox header produces something like the
+following:
+
+.. code-block:: php
+
+ $to = $message->getHeaders()->get('To');
+
+ $to->setNameAddresses(array(
+ 'person1@example.org' => 'Name of Person',
+ 'person2@example.org',
+ 'person3@example.org' => 'Another Person'
+ ));
+
+ echo $to->toString();
+
+ /*
+
+ To: Name of Person , person2@example.org, Another Person
+
+
+ */
+
+ID Headers
+~~~~~~~~~~
+
+ID headers contain identifiers for the entity (or the message). The most
+notable ID header is the Message-ID header on the message itself.
+
+An ID that exists inside an ID header looks more-or-less less like an email
+address. For example, ``<1234955437.499becad62ec2@example.org>``.
+The part to the left of the @ sign is usually unique, based on the current time
+and some random factor. The part on the right is usually a domain name.
+
+Any ID passed to the header's ``setId()`` method absolutely MUST conform to
+this structure, otherwise you'll get an Exception thrown at you by Swift Mailer
+(a ``Swift_RfcComplianceException``). This is to ensure that the generated
+email complies with relevant RFC documents and therefore is less likely to be
+blocked as spam.
+
+It's easy to add a new ID header to a HeaderSet. You do this by calling
+the HeaderSet's ``addIdHeader()`` method.
+
+.. code-block:: php
+
+ $message = Swift_Message::newInstance();
+
+ $headers = $message->getHeaders();
+
+ $headers->addIdHeader('Your-Header-Name', '123456.unqiue@example.org');
+
+Changing the value of an existing date header is done by calling its
+``setId()`` method.
+
+.. code-block:: php
+
+ $msgId = $message->getHeaders()->get('Message-ID');
+
+ $msgId->setId(time() . '.' . uniqid('thing') . '@example.org');
+
+When output via ``toString()``, an ID header produces something like the
+following:
+
+.. code-block:: php
+
+ $msgId = $message->getHeaders()->get('Message-ID');
+
+ echo $msgId->toString();
+
+ /*
+
+ Message-ID: <1234955437.499becad62ec2@example.org>
+
+ */
+
+Path Headers
+~~~~~~~~~~~~
+
+Path headers are like very-restricted mailbox headers. They contain a single
+email address with no associated name. The Return-Path header of a message is
+a path header.
+
+You add a new path header to a HeaderSet by calling the HeaderSet's
+``addPathHeader()`` method.
+
+.. code-block:: php
+
+ $message = Swift_Message::newInstance();
+
+ $headers = $message->getHeaders();
+
+ $headers->addPathHeader('Your-Header-Name', 'person@example.org');
+
+
+Changing the value of an existing path header is done by calling its
+``setAddress()`` method.
+
+.. code-block:: php
+
+ $return = $message->getHeaders()->get('Return-Path');
+
+ $return->setAddress('my-address@example.org');
+
+When output via ``toString()``, a path header produces something like the
+following:
+
+.. code-block:: php
+
+ $return = $message->getHeaders()->get('Return-Path');
+
+ $return->setAddress('person@example.org');
+
+ echo $return->toString();
+
+ /*
+
+ Return-Path:
+
+ */
+
+Header Operations
+-----------------
+
+Working with the headers in a message involves knowing how to use the methods
+on the HeaderSet and on the individual Headers within the HeaderSet.
+
+Adding new Headers
+~~~~~~~~~~~~~~~~~~
+
+New headers can be added to the HeaderSet by using one of the provided
+``add..Header()`` methods.
+
+To add a header to a MIME entity (such as the message):
+
+Get the HeaderSet from the entity by via its ``getHeaders()`` method.
+
+* Add the header to the HeaderSet by calling one of the ``add..Header()``
+ methods.
+
+The added header will appear in the message when it is sent.
+
+.. code-block:: php
+
+ // Adding a custom header to a message
+ $message = Swift_Message::newInstance();
+ $headers = $message->getHeaders();
+ $headers->addTextHeader('X-Mine', 'something here');
+
+ // Adding a custom header to an attachment
+ $attachment = Swift_Attachment::fromPath('/path/to/doc.pdf');
+ $attachment->getHeaders()->addDateHeader('X-Created-Time', time());
+
+Retrieving Headers
+~~~~~~~~~~~~~~~~~~
+
+Headers are retrieved through the HeaderSet's ``get()`` and ``getAll()``
+methods.
+
+To get a header, or several headers from a MIME entity:
+
+* Get the HeaderSet from the entity by via its ``getHeaders()`` method.
+
+* Get the header(s) from the HeaderSet by calling either ``get()`` or
+ ``getAll()``.
+
+When using ``get()`` a single header is returned that matches the name (case
+insensitive) that is passed to it. When using ``getAll()`` with a header name,
+an array of headers with that name are returned. Calling ``getAll()`` with no
+arguments returns an array of all headers present in the entity.
+
+.. note::
+
+ It's valid for some headers to appear more than once in a message (e.g.
+ the Received header). For this reason ``getAll()`` exists to fetch all
+ headers with a specified name. In addition, ``get()`` accepts an optional
+ numerical index, starting from zero to specify which header you want more
+ specifically.
+
+.. note::
+
+ If you want to modify the contents of the header and you don't know for
+ sure what type of header it is then you may need to check the type by
+ calling its ``getFieldType()`` method.
+
+ .. code-block:: php
+
+ $headers = $message->getHeaders();
+
+ // Get the To: header
+ $toHeader = $headers->get('To');
+
+ // Get all headers named "X-Foo"
+ $fooHeaders = $headers->getAll('X-Foo');
+
+ // Get the second header named "X-Foo"
+ $foo = $headers->get('X-Foo', 1);
+
+ // Get all headers that are present
+ $all = $headers->getAll();
+
+Check if a Header Exists
+~~~~~~~~~~~~~~~~~~~~~~~~
+
+You can check if a named header is present in a HeaderSet by calling its
+``has()`` method.
+
+To check if a header exists:
+
+* Get the HeaderSet from the entity by via its ``getHeaders()`` method.
+
+* Call the HeaderSet's ``has()`` method specifying the header you're looking
+ for.
+
+If the header exists, ``true`` will be returned or ``false`` if not.
+
+.. note::
+
+ It's valid for some headers to appear more than once in a message (e.g.
+ the Received header). For this reason ``has()`` accepts an optional
+ numerical index, starting from zero to specify which header you want to
+ check more specifically.
+
+ .. code-block:: php
+
+ $headers = $message->getHeaders();
+
+ // Check if the To: header exists
+ if ($headers->has('To')) {
+ echo 'To: exists';
+ }
+
+ // Check if an X-Foo header exists twice (i.e. check for the 2nd one)
+ if ($headers->has('X-Foo', 1)) {
+ echo 'Second X-Foo header exists';
+ }
+
+Removing Headers
+~~~~~~~~~~~~~~~~
+
+Removing a Header from the HeaderSet is done by calling the HeaderSet's
+``remove()`` or ``removeAll()`` methods.
+
+To remove an existing header:
+
+* Get the HeaderSet from the entity by via its ``getHeaders()`` method.
+
+* Call the HeaderSet's ``remove()`` or ``removeAll()`` methods specifying the
+ header you want to remove.
+
+When calling ``remove()`` a single header will be removed. When calling
+``removeAll()`` all headers with the given name will be removed. If no headers
+exist with the given name, no errors will occur.
+
+.. note::
+
+ It's valid for some headers to appear more than once in a message (e.g.
+ the Received header). For this reason ``remove()`` accepts an optional
+ numerical index, starting from zero to specify which header you want to
+ check more specifically. For the same reason, ``removeAll()`` exists to
+ remove all headers that have the given name.
+
+ .. code-block:: php
+
+ $headers = $message->getHeaders();
+
+ // Remove the Subject: header
+ $headers->remove('Subject');
+
+ // Remove all X-Foo headers
+ $headers->removeAll('X-Foo');
+
+ // Remove only the second X-Foo header
+ $headers->remove('X-Foo', 1);
+
+Modifying a Header's Content
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+To change a Header's content you should know what type of header it is and then
+call it's appropriate setter method. All headers also have a
+``setFieldBodyModel()`` method that accepts a mixed parameter and delegates to
+the correct setter.
+
+To modify an existing header:
+
+* Get the HeaderSet from the entity by via its ``getHeaders()`` method.
+
+* Get the Header by using the HeaderSet's ``get()``.
+
+* Call the Header's appropriate setter method or call the header's
+ ``setFieldBodyModel()`` method.
+
+The header will be updated inside the HeaderSet and the changes will be seen
+when the message is sent.
+
+.. code-block:: php
+
+ $headers = $message->getHeaders();
+
+ // Change the Subject: header
+ $subj = $headers->get('Subject');
+ $subj->setValue('new subject here');
+
+ // Change the To: header
+ $to = $headers->get('To');
+ $to->setNameAddresses(array(
+ 'person@example.org' => 'Person',
+ 'thing@example.org'
+ ));
+
+ // Using the setFieldBodyModel() just delegates to the correct method
+ // So here to calls setNameAddresses()
+ $to->setFieldBodyModel(array(
+ 'person@example.org' => 'Person',
+ 'thing@example.org'
+ ));
diff --git a/vendor/swiftmailer/swiftmailer/doc/help-resources.rst b/vendor/swiftmailer/swiftmailer/doc/help-resources.rst
new file mode 100644
index 00000000..42089359
--- /dev/null
+++ b/vendor/swiftmailer/swiftmailer/doc/help-resources.rst
@@ -0,0 +1,44 @@
+Getting Help
+============
+
+There are a number of ways you can get help when using Swift Mailer, depending
+upon the nature of your problem. For bug reports and feature requests create a
+new ticket in GitHub. For general advice ask on the Google Group
+(swiftmailer).
+
+Submitting Bugs & Feature Requests
+----------------------------------
+
+Bugs and feature requests should be posted on GitHub.
+
+If you post a bug or request a feature in the forum, or on the Google Group
+you will most likely be asked to create a ticket in `GitHub`_ since it is
+simply not feasible to manage such requests from a number of a different
+sources.
+
+When you go to GitHub you will be asked to create a username and password
+before you can create a ticket. This is free and takes very little time.
+
+When you create your ticket, do not assign it to any milestones. A developer
+will assess your ticket and re-assign it as needed.
+
+If your ticket is reporting a bug present in the current version, which was
+not present in the previous version please include the tag "regression" in
+your ticket.
+
+GitHub will update you when work is performed on your ticket.
+
+Ask on the Google Group
+-----------------------
+
+You can seek advice at Google Groups, within the "swiftmailer" `group`_.
+
+You can post messages to this group if you want help, or there's something you
+wish to discuss with the developers and with other users.
+
+This is probably the fastest way to get help since it is primarily email-based
+for most users, though bug reports should not be posted here since they may
+not be resolved.
+
+.. _`GitHub`: https://github.com/swiftmailer/swiftmailer/issues
+.. _`group`: http://groups.google.com/group/swiftmailer
diff --git a/vendor/swiftmailer/swiftmailer/doc/including-the-files.rst b/vendor/swiftmailer/swiftmailer/doc/including-the-files.rst
new file mode 100644
index 00000000..978dca20
--- /dev/null
+++ b/vendor/swiftmailer/swiftmailer/doc/including-the-files.rst
@@ -0,0 +1,46 @@
+Including Swift Mailer (Autoloading)
+====================================
+
+If you are using Composer, Swift Mailer will be automatically autoloaded.
+
+If not, you can use the built-in autoloader by requiring the
+``swift_required.php`` file::
+
+ require_once '/path/to/swift-mailer/lib/swift_required.php';
+
+ /* rest of code goes here */
+
+If you want to override the default Swift Mailer configuration, call the
+``init()`` method on the ``Swift`` class and pass it a valid PHP callable (a
+PHP function name, a PHP 5.3 anonymous function, ...)::
+
+ require_once '/path/to/swift-mailer/lib/swift_required.php';
+
+ function swiftmailer_configurator() {
+ // configure Swift Mailer
+
+ Swift_DependencyContainer::getInstance()->...
+ Swift_Preferences::getInstance()->...
+ }
+
+ Swift::init('swiftmailer_configurator');
+
+ /* rest of code goes here */
+
+The advantage of using the ``init()`` method is that your code will be
+executed only if you use Swift Mailer in your script.
+
+.. note::
+
+ While Swift Mailer's autoloader is designed to play nicely with other
+ autoloaders, sometimes you may have a need to avoid using Swift Mailer's
+ autoloader and use your own instead. Include the ``swift_init.php``
+ instead of the ``swift_required.php`` if you need to do this. The very
+ minimum include is the ``swift_init.php`` file since Swift Mailer will not
+ work without the dependency injection this file sets up:
+
+ .. code-block:: php
+
+ require_once '/path/to/swift-mailer/lib/swift_init.php';
+
+ /* rest of code goes here */
diff --git a/vendor/swiftmailer/swiftmailer/doc/index.rst b/vendor/swiftmailer/swiftmailer/doc/index.rst
new file mode 100644
index 00000000..a1a0a924
--- /dev/null
+++ b/vendor/swiftmailer/swiftmailer/doc/index.rst
@@ -0,0 +1,16 @@
+Swiftmailer
+===========
+
+.. toctree::
+ :maxdepth: 2
+
+ introduction
+ overview
+ installing
+ help-resources
+ including-the-files
+ messages
+ headers
+ sending
+ plugins
+ japanese
diff --git a/vendor/swiftmailer/swiftmailer/doc/installing.rst b/vendor/swiftmailer/swiftmailer/doc/installing.rst
new file mode 100644
index 00000000..557211d4
--- /dev/null
+++ b/vendor/swiftmailer/swiftmailer/doc/installing.rst
@@ -0,0 +1,89 @@
+Installing the Library
+======================
+
+Installing with Composer
+------------------------
+
+The recommended way to install Swiftmailer is via Composer:
+
+.. code-block:: bash
+
+ $ php composer.phar require swiftmailer/swiftmailer @stable
+
+Installing from Git
+-------------------
+
+It's possible to download and install Swift Mailer directly from github.com if
+you want to keep up-to-date with ease.
+
+Swift Mailer's source code is kept in a git repository at github.com so you
+can get the source directly from the repository.
+
+.. note::
+
+ You do not need to have git installed to use Swift Mailer from GitHub. If
+ you don't have git installed, go to `GitHub`_ and click the "Download"
+ button.
+
+Cloning the Repository
+~~~~~~~~~~~~~~~~~~~~~~
+
+The repository can be cloned from git://github.com/swiftmailer/swiftmailer.git
+using the ``git clone`` command.
+
+You will need to have ``git`` installed before you can use the
+``git clone`` command.
+
+To clone the repository:
+
+* Open your favorite terminal environment (command line).
+
+* Move to the directory you want to clone to.
+
+* Run the command ``git clone git://github.com/swiftmailer/swiftmailer.git
+ swiftmailer``.
+
+The source code will be downloaded into a directory called "swiftmailer".
+
+The example shows the process on a UNIX-like system such as Linux, BSD or Mac
+OS X.
+
+.. code-block:: bash
+
+ $ cd source_code/
+ $ git clone git://github.com/swiftmailer/swiftmailer.git swiftmailer
+ Initialized empty Git repository in /Users/chris/source_code/swiftmailer/.git/
+ remote: Counting objects: 6815, done.
+ remote: Compressing objects: 100% (2761/2761), done.
+ remote: Total 6815 (delta 3641), reused 6326 (delta 3286)
+ Receiving objects: 100% (6815/6815), 4.35 MiB | 162 KiB/s, done.
+ Resolving deltas: 100% (3641/3641), done.
+ Checking out files: 100% (1847/1847), done.
+ $ cd swiftmailer/
+ $ ls
+ CHANGES LICENSE ...
+ $
+
+Troubleshooting
+---------------
+
+Swift Mailer does not work when used with function overloading as implemented
+by ``mbstring`` (``mbstring.func_overload`` set to ``2``). A workaround is to
+temporarily change the internal encoding to ``ASCII`` when sending an email:
+
+.. code-block:: php
+
+ if (function_exists('mb_internal_encoding') && ((int) ini_get('mbstring.func_overload')) & 2)
+ {
+ $mbEncoding = mb_internal_encoding();
+ mb_internal_encoding('ASCII');
+ }
+
+ // Create your message and send it with Swift Mailer
+
+ if (isset($mbEncoding))
+ {
+ mb_internal_encoding($mbEncoding);
+ }
+
+.. _`GitHub`: http://github.com/swiftmailer/swiftmailer
diff --git a/vendor/swiftmailer/swiftmailer/doc/introduction.rst b/vendor/swiftmailer/swiftmailer/doc/introduction.rst
new file mode 100644
index 00000000..a85336b7
--- /dev/null
+++ b/vendor/swiftmailer/swiftmailer/doc/introduction.rst
@@ -0,0 +1,135 @@
+Introduction
+============
+
+Swift Mailer is a component-based library for sending e-mails from PHP
+applications.
+
+Organization of this Book
+-------------------------
+
+This book has been written so that those who need information quickly are able
+to find what they need, and those who wish to learn more advanced topics can
+read deeper into each chapter.
+
+The book begins with an overview of Swift Mailer, discussing what's included
+in the package and preparing you for the remainder of the book.
+
+It is possible to read this user guide just like any other book (from
+beginning to end). Each chapter begins with a discussion of the contents it
+contains, followed by a short code sample designed to give you a head start.
+As you get further into a chapter you will learn more about Swift Mailer's
+capabilities, but often you will be able to head directly to the topic you
+wish to learn about.
+
+Throughout this book you will be presented with code samples, which most
+people should find ample to implement Swift Mailer appropriately in their own
+projects. We will also use diagrams where appropriate, and where we believe
+readers may find it helpful we will discuss some related theory, including
+reference to certain documents you are able to find online.
+
+Code Samples
+------------
+
+Code samples presented in this book will be displayed on a different colored
+background in a monospaced font. Samples are not to be taken as copy & paste
+code snippets.
+
+Code examples are used through the book to clarify what is written in text.
+They will sometimes be usable as-is, but they should always be taken as
+outline/pseudo code only.
+
+A code sample will look like this::
+
+ class AClass
+ {
+ ...
+ }
+
+ // A Comment
+ $obj = new AClass($arg1, $arg2, ... );
+
+ /* A note about another way of doing something
+ $obj = AClass::newInstance($arg1, $arg2, ... );
+
+ */
+
+The presence of 3 dots ``...`` in a code sample indicates that we have left
+out a chunk of the code for brevity, they are not actually part of the code.
+
+We will often place multi-line comments ``/* ... */`` in the code so that we
+can show alternative ways of achieving the same result.
+
+You should read the code examples given and try to understand them. They are
+kept concise so that you are not overwhelmed with information.
+
+History of Swift Mailer
+-----------------------
+
+Swift Mailer began back in 2005 as a one-class project for sending mail over
+SMTP. It has since grown into the flexible component-based library that is in
+development today.
+
+Chris Corbyn first posted Swift Mailer on a web forum asking for comments from
+other developers. It was never intended as a fully supported open source
+project, but members of the forum began to adopt it and make use of it.
+
+Very quickly feature requests were coming for the ability to add attachments
+and use SMTP authentication, along with a number of other "obvious" missing
+features. Considering the only alternative was PHPMailer it seemed like a good
+time to bring some fresh tools to the table. Chris began working towards a
+more component based, PHP5-like approach unlike the existing single-class,
+legacy PHP4 approach taken by PHPMailer.
+
+Members of the forum offered a lot of advice and critique on the code as he
+worked through this project and released versions 2 and 3 of the library in
+2005 and 2006, which by then had been broken down into smaller classes
+offering more flexibility and supporting plugins. To this day the Swift Mailer
+team still receive a lot of feature requests from users both on the forum and
+in by email.
+
+Until 2008 Chris was the sole developer of Swift Mailer, but entering 2009 he
+gained the support of two experienced developers well-known to him: Paul
+Annesley and Christopher Thompson. This has been an extremely welcome change.
+
+As of September 2009, Chris handed over the maintenance of Swift Mailer to
+Fabien Potencier.
+
+Now 2009 and in its fourth major version Swift Mailer is more object-oriented
+and flexible than ever, both from a usability standpoint and from a
+development standpoint.
+
+By no means is Swift Mailer ready to call "finished". There are still many
+features that can be added to the library along with the constant refactoring
+that happens behind the scenes.
+
+It's a Library!
+---------------
+
+Swift Mailer is not an application - it's a library.
+
+To most experienced developers this is probably an obvious point to make, but
+it's certainly worth mentioning. Many people often contact us having gotten
+the completely wrong end of the stick in terms of what Swift Mailer is
+actually for.
+
+It's not an application. It does not have a graphical user interface. It
+cannot be opened in your web browser directly.
+
+It's a library (or a framework if you like). It provides a whole lot of
+classes that do some very complicated things, so that you don't have to. You
+"use" Swift Mailer within an application so that your application can have the
+ability to send emails.
+
+The component-based structure of the library means that you are free to
+implement it in a number of different ways and that you can pick and choose
+what you want to use.
+
+An application on the other hand (such as a blog or a forum) is already "put
+together" in a particular way, (usually) provides a graphical user interface
+and most likely doesn't offer a great deal of integration with your own
+application.
+
+Embrace the structure of the library and use the components it offers to your
+advantage. Learning what the components do, rather than blindly copying and
+pasting existing code will put you in a great position to build a powerful
+application!
diff --git a/vendor/swiftmailer/swiftmailer/doc/japanese.rst b/vendor/swiftmailer/swiftmailer/doc/japanese.rst
new file mode 100644
index 00000000..34afa7b8
--- /dev/null
+++ b/vendor/swiftmailer/swiftmailer/doc/japanese.rst
@@ -0,0 +1,22 @@
+Using Swift Mailer for Japanese Emails
+======================================
+
+To send emails in Japanese, you need to tweak the default configuration.
+
+After requiring the Swift Mailer autoloader (by including the
+``swift_required.php`` file), call the ``Swift::init()`` method with the
+following code::
+
+ require_once '/path/to/swift-mailer/lib/swift_required.php';
+
+ Swift::init(function () {
+ Swift_DependencyContainer::getInstance()
+ ->register('mime.qpheaderencoder')
+ ->asAliasOf('mime.base64headerencoder');
+
+ Swift_Preferences::getInstance()->setCharset('iso-2022-jp');
+ });
+
+ /* rest of code goes here */
+
+That's all!
diff --git a/vendor/swiftmailer/swiftmailer/doc/messages.rst b/vendor/swiftmailer/swiftmailer/doc/messages.rst
new file mode 100644
index 00000000..7a192536
--- /dev/null
+++ b/vendor/swiftmailer/swiftmailer/doc/messages.rst
@@ -0,0 +1,1057 @@
+Creating Messages
+=================
+
+Creating messages in Swift Mailer is done by making use of the various MIME
+entities provided with the library. Complex messages can be quickly created
+with very little effort.
+
+Quick Reference for Creating a Message
+---------------------------------------
+
+You can think of creating a Message as being similar to the steps you perform
+when you click the Compose button in your mail client. You give it a subject,
+specify some recipients, add any attachments and write your message.
+
+To create a Message:
+
+* Call the ``newInstance()`` method of ``Swift_Message``.
+
+* Set your sender address (``From:``) with ``setFrom()`` or ``setSender()``.
+
+* Set a subject line with ``setSubject()``.
+
+* Set recipients with ``setTo()``, ``setCc()`` and/or ``setBcc()``.
+
+* Set a body with ``setBody()``.
+
+* Add attachments with ``attach()``.
+
+.. code-block:: php
+
+ require_once 'lib/swift_required.php';
+
+ // Create the message
+ $message = Swift_Message::newInstance()
+
+ // Give the message a subject
+ ->setSubject('Your subject')
+
+ // Set the From address with an associative array
+ ->setFrom(array('john@doe.com' => 'John Doe'))
+
+ // Set the To addresses with an associative array
+ ->setTo(array('receiver@domain.org', 'other@domain.org' => 'A name'))
+
+ // Give it a body
+ ->setBody('Here is the message itself')
+
+ // And optionally an alternative body
+ ->addPart('Here is the message itself', 'text/html')
+
+ // Optionally add any attachments
+ ->attach(Swift_Attachment::fromPath('my-document.pdf'))
+ ;
+
+Message Basics
+--------------
+
+A message is a container for anything you want to send to somebody else. There
+are several basic aspects of a message that you should know.
+
+An e-mail message is made up of several relatively simple entities that are
+combined in different ways to achieve different results. All of these entities
+have the same fundamental outline but serve a different purpose. The Message
+itself can be defined as a MIME entity, an Attachment is a MIME entity, all
+MIME parts are MIME entities -- and so on!
+
+The basic units of each MIME entity -- be it the Message itself, or an
+Attachment -- are its Headers and its body:
+
+.. code-block:: text
+
+ Header-Name: A header value
+ Other-Header: Another value
+
+ The body content itself
+
+The Headers of a MIME entity, and its body must conform to some strict
+standards defined by various RFC documents. Swift Mailer ensures that these
+specifications are followed by using various types of object, including
+Encoders and different Header types to generate the entity.
+
+The Structure of a Message
+~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+Of all of the MIME entities, a message -- ``Swift_Message``
+is the largest and most complex. It has many properties that can be updated
+and it can contain other MIME entities -- attachments for example --
+nested inside it.
+
+A Message has a lot of different Headers which are there to present
+information about the message to the recipients' mail client. Most of these
+headers will be familiar to the majority of users, but we'll list the basic
+ones. Although it's possible to work directly with the Headers of a Message
+(or other MIME entity), the standard Headers have accessor methods provided to
+abstract away the complex details for you. For example, although the Date on a
+message is written with a strict format, you only need to pass a UNIX
+timestamp to ``setDate()``.
+
++-------------------------------+------------------------------------------------------------------------------------------------------------------------------------+---------------------------------------------+
+| Header | Description | Accessors |
++===============================+====================================================================================================================================+=============================================+
+| ``Message-ID`` | Identifies this message with a unique ID, usually containing the domain name and time generated | ``getId()`` / ``setId()`` |
++-------------------------------+------------------------------------------------------------------------------------------------------------------------------------+---------------------------------------------+
+| ``Return-Path`` | Specifies where bounces should go (Swift Mailer reads this for other uses) | ``getReturnPath()`` / ``setReturnPath()`` |
++-------------------------------+------------------------------------------------------------------------------------------------------------------------------------+---------------------------------------------+
+| ``From`` | Specifies the address of the person who the message is from. This can be multiple addresses if multiple people wrote the message. | ``getFrom()`` / ``setFrom()`` |
++-------------------------------+------------------------------------------------------------------------------------------------------------------------------------+---------------------------------------------+
+| ``Sender`` | Specifies the address of the person who physically sent the message (higher precedence than ``From:``) | ``getSender()`` / ``setSender()`` |
++-------------------------------+------------------------------------------------------------------------------------------------------------------------------------+---------------------------------------------+
+| ``To`` | Specifies the addresses of the intended recipients | ``getTo()`` / ``setTo()`` |
++-------------------------------+------------------------------------------------------------------------------------------------------------------------------------+---------------------------------------------+
+| ``Cc`` | Specifies the addresses of recipients who will be copied in on the message | ``getCc()`` / ``setCc()`` |
++-------------------------------+------------------------------------------------------------------------------------------------------------------------------------+---------------------------------------------+
+| ``Bcc`` | Specifies the addresses of recipients who the message will be blind-copied to. Other recipients will not be aware of these copies. | ``getBcc()`` / ``setBcc()`` |
++-------------------------------+------------------------------------------------------------------------------------------------------------------------------------+---------------------------------------------+
+| ``Reply-To`` | Specifies the address where replies are sent to | ``getReplyTo()`` / ``setReplyTo()`` |
++-------------------------------+------------------------------------------------------------------------------------------------------------------------------------+---------------------------------------------+
+| ``Subject`` | Specifies the subject line that is displayed in the recipients' mail client | ``getSubject()`` / ``setSubject()`` |
++-------------------------------+------------------------------------------------------------------------------------------------------------------------------------+---------------------------------------------+
+| ``Date`` | Specifies the date at which the message was sent | ``getDate()`` / ``setDate()`` |
++-------------------------------+------------------------------------------------------------------------------------------------------------------------------------+---------------------------------------------+
+| ``Content-Type`` | Specifies the format of the message (usually text/plain or text/html) | ``getContentType()`` / ``setContentType()`` |
++-------------------------------+------------------------------------------------------------------------------------------------------------------------------------+---------------------------------------------+
+| ``Content-Transfer-Encoding`` | Specifies the encoding scheme in the message | ``getEncoder()`` / ``setEncoder()`` |
++-------------------------------+------------------------------------------------------------------------------------------------------------------------------------+---------------------------------------------+
+
+Working with a Message Object
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+Although there are a lot of available methods on a message object, you only
+need to make use of a small subset of them. Usually you'll use
+``setSubject()``, ``setTo()`` and
+``setFrom()`` before setting the body of your message with
+``setBody()``.
+
+Calling methods is simple. You just call them like functions, but using the
+object operator "``->``" to do so. If you've created
+a message object and called it ``$message`` then you'd set a
+subject on it like so:
+
+.. code-block:: php
+
+ require_once 'lib/swift_required.php';
+
+ $message = Swift_Message::newInstance();
+ $message->setSubject('My subject');
+
+All MIME entities (including a message) have a ``toString()``
+method that you can call if you want to take a look at what is going to be
+sent. For example, if you ``echo
+$message->toString();`` you would see something like this:
+
+.. code-block:: bash
+
+ Message-ID: <1230173678.4952f5eeb1432@swift.generated>
+ Date: Thu, 25 Dec 2008 13:54:38 +1100
+ Subject: Example subject
+ From: Chris Corbyn
+ To: Receiver Name
+ MIME-Version: 1.0
+ Content-Type: text/plain; charset=utf-8
+ Content-Transfer-Encoding: quoted-printable
+
+ Here is the message
+
+We'll take a closer look at the methods you use to create your message in the
+following sections.
+
+Adding Content to Your Message
+------------------------------
+
+Rich content can be added to messages in Swift Mailer with relative ease by
+calling methods such as ``setSubject()``, ``setBody()``, ``addPart()`` and
+``attach()``.
+
+Setting the Subject Line
+~~~~~~~~~~~~~~~~~~~~~~~~
+
+The subject line, displayed in the recipients' mail client can be set with the
+``setSubject()`` method, or as a parameter to ``Swift_Message::newInstance()``.
+
+To set the subject of your Message:
+
+* Call the ``setSubject()`` method of the Message, or specify it at the time
+ you create the message.
+
+ .. code-block:: php
+
+ // Pass it as a parameter when you create the message
+ $message = Swift_Message::newInstance('My amazing subject');
+
+ // Or set it after like this
+ $message->setSubject('My amazing subject');
+
+Setting the Body Content
+~~~~~~~~~~~~~~~~~~~~~~~~
+
+The body of the message -- seen when the user opens the message --
+is specified by calling the ``setBody()`` method. If an alternative body is to
+be included ``addPart()`` can be used.
+
+The body of a message is the main part that is read by the user. Often people
+want to send a message in HTML format (``text/html``), other
+times people want to send in plain text (``text/plain``), or
+sometimes people want to send both versions and allow the recipient to choose
+how they view the message.
+
+As a rule of thumb, if you're going to send a HTML email, always include a
+plain-text equivalent of the same content so that users who prefer to read
+plain text can do so.
+
+To set the body of your Message:
+
+* Call the ``setBody()`` method of the Message, or specify it at the time you
+ create the message.
+
+* Add any alternative bodies with ``addPart()``.
+
+If the recipient's mail client offers preferences for displaying text vs. HTML
+then the mail client will present that part to the user where available. In
+other cases the mail client will display the "best" part it can - usually HTML
+if you've included HTML.
+
+.. code-block:: php
+
+ // Pass it as a parameter when you create the message
+ $message = Swift_Message::newInstance('Subject here', 'My amazing body');
+
+ // Or set it after like this
+ $message->setBody('My amazing body', 'text/html');
+
+ // Add alternative parts with addPart()
+ $message->addPart('My amazing body in plain text', 'text/plain');
+
+Attaching Files
+---------------
+
+Attachments are downloadable parts of a message and can be added by calling
+the ``attach()`` method on the message. You can add attachments that exist on
+disk, or you can create attachments on-the-fly.
+
+Attachments are actually an interesting area of Swift Mailer and something
+that could put a lot of power at your fingertips if you grasp the concept
+behind the way a message is held together.
+
+Although we refer to files sent over e-mails as "attachments" -- because
+they're attached to the message -- lots of other parts of the message are
+actually "attached" even if we don't refer to these parts as attachments.
+
+File attachments are created by the ``Swift_Attachment`` class
+and then attached to the message via the ``attach()`` method on
+it. For all of the "every day" MIME types such as all image formats, word
+documents, PDFs and spreadsheets you don't need to explicitly set the
+content-type of the attachment, though it would do no harm to do so. For less
+common formats you should set the content-type -- which we'll cover in a
+moment.
+
+Attaching Existing Files
+~~~~~~~~~~~~~~~~~~~~~~~~
+
+Files that already exist, either on disk or at a URL can be attached to a
+message with just one line of code, using ``Swift_Attachment::fromPath()``.
+
+You can attach files that exist locally, or if your PHP installation has
+``allow_url_fopen`` turned on you can attach files from other
+websites.
+
+To attach an existing file:
+
+* Create an attachment with ``Swift_Attachment::fromPath()``.
+
+* Add the attachment to the message with ``attach()``.
+
+The attachment will be presented to the recipient as a downloadable file with
+the same filename as the one you attached.
+
+.. code-block:: php
+
+ // Create the attachment
+ // * Note that you can technically leave the content-type parameter out
+ $attachment = Swift_Attachment::fromPath('/path/to/image.jpg', 'image/jpeg');
+
+ // Attach it to the message
+ $message->attach($attachment);
+
+
+ // The two statements above could be written in one line instead
+ $message->attach(Swift_Attachment::fromPath('/path/to/image.jpg'));
+
+
+ // You can attach files from a URL if allow_url_fopen is on in php.ini
+ $message->attach(Swift_Attachment::fromPath('http://site.tld/logo.png'));
+
+Setting the Filename
+~~~~~~~~~~~~~~~~~~~~
+
+Usually you don't need to explicitly set the filename of an attachment because
+the name of the attached file will be used by default, but if you want to set
+the filename you use the ``setFilename()`` method of the Attachment.
+
+To change the filename of an attachment:
+
+* Call its ``setFilename()`` method.
+
+The attachment will be attached in the normal way, but meta-data sent inside
+the email will rename the file to something else.
+
+.. code-block:: php
+
+ // Create the attachment and call its setFilename() method
+ $attachment = Swift_Attachment::fromPath('/path/to/image.jpg')
+ ->setFilename('cool.jpg');
+
+
+ // Because there's a fluid interface, you can do this in one statement
+ $message->attach(
+ Swift_Attachment::fromPath('/path/to/image.jpg')->setFilename('cool.jpg')
+ );
+
+Attaching Dynamic Content
+~~~~~~~~~~~~~~~~~~~~~~~~~
+
+Files that are generated at runtime, such as PDF documents or images created
+via GD can be attached directly to a message without writing them out to disk.
+Use the standard ``Swift_Attachment::newInstance()`` method.
+
+To attach dynamically created content:
+
+* Create your content as you normally would.
+
+* Create an attachment with ``Swift_Attachment::newInstance()``, specifying
+ the source data of your content along with a name and the content-type.
+
+* Add the attachment to the message with ``attach()``.
+
+The attachment will be presented to the recipient as a downloadable file
+with the filename and content-type you specify.
+
+.. note::
+
+ If you would usually write the file to disk anyway you should just attach
+ it with ``Swift_Attachment::fromPath()`` since this will use less memory:
+
+ .. code-block:: php
+
+ // Create your file contents in the normal way, but don't write them to disk
+ $data = create_my_pdf_data();
+
+ // Create the attachment with your data
+ $attachment = Swift_Attachment::newInstance($data, 'my-file.pdf', 'application/pdf');
+
+ // Attach it to the message
+ $message->attach($attachment);
+
+
+ // You can alternatively use method chaining to build the attachment
+ $attachment = Swift_Attachment::newInstance()
+ ->setFilename('my-file.pdf')
+ ->setContentType('application/pdf')
+ ->setBody($data)
+ ;
+
+Changing the Disposition
+~~~~~~~~~~~~~~~~~~~~~~~~
+
+Attachments just appear as files that can be saved to the Desktop if desired.
+You can make attachment appear inline where possible by using the
+``setDisposition()`` method of an attachment.
+
+To make an attachment appear inline:
+
+* Call its ``setDisposition()`` method.
+
+The attachment will be displayed within the email viewing window if the mail
+client knows how to display it.
+
+.. note::
+
+ If you try to create an inline attachment for a non-displayable file type
+ such as a ZIP file, the mail client should just present the attachment as
+ normal:
+
+ .. code-block:: php
+
+ // Create the attachment and call its setDisposition() method
+ $attachment = Swift_Attachment::fromPath('/path/to/image.jpg')
+ ->setDisposition('inline');
+
+
+ // Because there's a fluid interface, you can do this in one statement
+ $message->attach(
+ Swift_Attachment::fromPath('/path/to/image.jpg')->setDisposition('inline')
+ );
+
+Embedding Inline Media Files
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+Often people want to include an image or other content inline with a HTML
+message. It's easy to do this with HTML linking to remote resources, but this
+approach is usually blocked by mail clients. Swift Mailer allows you to embed
+your media directly into the message.
+
+Mail clients usually block downloads from remote resources because this
+technique was often abused as a mean of tracking who opened an email. If
+you're sending a HTML email and you want to include an image in the message
+another approach you can take is to embed the image directly.
+
+Swift Mailer makes embedding files into messages extremely streamlined. You
+embed a file by calling the ``embed()`` method of the message,
+which returns a value you can use in a ``src`` or
+``href`` attribute in your HTML.
+
+Just like with attachments, it's possible to embed dynamically generated
+content without having an existing file available.
+
+The embedded files are sent in the email as a special type of attachment that
+has a unique ID used to reference them within your HTML attributes. On mail
+clients that do not support embedded files they may appear as attachments.
+
+Although this is commonly done for images, in theory it will work for any
+displayable (or playable) media type. Support for other media types (such as
+video) is dependent on the mail client however.
+
+Embedding Existing Files
+........................
+
+Files that already exist, either on disk or at a URL can be embedded in a
+message with just one line of code, using ``Swift_EmbeddedFile::fromPath()``.
+
+You can embed files that exist locally, or if your PHP installation has
+``allow_url_fopen`` turned on you can embed files from other websites.
+
+To embed an existing file:
+
+* Create a message object with ``Swift_Message::newInstance()``.
+
+* Set the body as HTML, and embed a file at the correct point in the message with ``embed()``.
+
+The file will be displayed with the message inline with the HTML wherever its ID
+is used as a ``src`` attribute.
+
+.. note::
+
+ ``Swift_Image`` and ``Swift_EmbeddedFile`` are just aliases of one
+ another. ``Swift_Image`` exists for semantic purposes.
+
+.. note::
+
+ You can embed files in two stages if you prefer. Just capture the return
+ value of ``embed()`` in a variable and use that as the ``src`` attribute.
+
+ .. code-block:: php
+
+ // Create the message
+ $message = Swift_Message::newInstance('My subject');
+
+ // Set the body
+ $message->setBody(
+ '' .
+ ' ' .
+ ' ' .
+ ' Here is an image ' .
+ ' Rest of message' .
+ ' ' .
+ '',
+ 'text/html' // Mark the content-type as HTML
+ );
+
+ // You can embed files from a URL if allow_url_fopen is on in php.ini
+ $message->setBody(
+ '' .
+ ' ' .
+ ' ' .
+ ' Here is an image ' .
+ ' Rest of message' .
+ ' ' .
+ '',
+ 'text/html'
+ );
+
+
+ // If placing the embed() code inline becomes cumbersome
+ // it's easy to do this in two steps
+ $cid = $message->embed(Swift_Image::fromPath('image.png'));
+
+ $message->setBody(
+ '' .
+ ' ' .
+ ' ' .
+ ' Here is an image ' .
+ ' Rest of message' .
+ ' ' .
+ '',
+ 'text/html' // Mark the content-type as HTML
+ );
+
+Embedding Dynamic Content
+.........................
+
+Images that are generated at runtime, such as images created via GD can be
+embedded directly to a message without writing them out to disk. Use the
+standard ``Swift_Image::newInstance()`` method.
+
+To embed dynamically created content:
+
+* Create a message object with ``Swift_Message::newInstance()``.
+
+* Set the body as HTML, and embed a file at the correct point in the message
+ with ``embed()``. You will need to specify a filename and a content-type.
+
+The file will be displayed with the message inline with the HTML wherever its ID
+is used as a ``src`` attribute.
+
+.. note::
+
+ ``Swift_Image`` and ``Swift_EmbeddedFile`` are just aliases of one
+ another. ``Swift_Image`` exists for semantic purposes.
+
+.. note::
+
+ You can embed files in two stages if you prefer. Just capture the return
+ value of ``embed()`` in a variable and use that as the ``src`` attribute.
+
+ .. code-block:: php
+
+ // Create your file contents in the normal way, but don't write them to disk
+ $img_data = create_my_image_data();
+
+ // Create the message
+ $message = Swift_Message::newInstance('My subject');
+
+ // Set the body
+ $message->setBody(
+ '' .
+ ' ' .
+ ' ' .
+ ' Here is an image ' .
+ ' Rest of message' .
+ ' ' .
+ '',
+ 'text/html' // Mark the content-type as HTML
+ );
+
+
+ // If placing the embed() code inline becomes cumbersome
+ // it's easy to do this in two steps
+ $cid = $message->embed(Swift_Image::newInstance($img_data, 'image.jpg', 'image/jpeg'));
+
+ $message->setBody(
+ '' .
+ ' ' .
+ ' ' .
+ ' Here is an image ' .
+ ' Rest of message' .
+ ' ' .
+ '',
+ 'text/html' // Mark the content-type as HTML
+ );
+
+Adding Recipients to Your Message
+---------------------------------
+
+Recipients are specified within the message itself via ``setTo()``, ``setCc()``
+and ``setBcc()``. Swift Mailer reads these recipients from the message when it
+gets sent so that it knows where to send the message to.
+
+Message recipients are one of three types:
+
+* ``To:`` recipients -- the primary recipients (required)
+
+* ``Cc:`` recipients -- receive a copy of the message (optional)
+
+* ``Bcc:`` recipients -- hidden from other recipients (optional)
+
+Each type can contain one, or several addresses. It's possible to list only
+the addresses of the recipients, or you can personalize the address by
+providing the real name of the recipient.
+
+Make sure to add only valid email addresses as recipients. If you try to add an
+invalid email address with ``setTo()``, ``setCc()`` or ``setBcc()``, Swift
+Mailer will throw a ``Swift_RfcComplianceException``.
+
+If you add recipients automatically based on a data source that may contain
+invalid email addresses, you can prevent possible exceptions by validating the
+addresses using ``Swift_Validate::email($email)`` and only adding addresses
+that validate. Another way would be to wrap your ``setTo()``, ``setCc()`` and
+``setBcc()`` calls in a try-catch block and handle the
+``Swift_RfcComplianceException`` in the catch block.
+
+.. sidebar:: Syntax for Addresses
+
+ If you only wish to refer to a single email address (for example your
+ ``From:`` address) then you can just use a string.
+
+ .. code-block:: php
+
+ $message->setFrom('some@address.tld');
+
+ If you want to include a name then you must use an associative array.
+
+ .. code-block:: php
+
+ $message->setFrom(array('some@address.tld' => 'The Name'));
+
+ If you want to include multiple addresses then you must use an array.
+
+ .. code-block:: php
+
+ $message->setTo(array('some@address.tld', 'other@address.tld'));
+
+ You can mix personalized (addresses with a name) and non-personalized
+ addresses in the same list by mixing the use of associative and
+ non-associative array syntax.
+
+ .. code-block:: php
+
+ $message->setTo(array(
+ 'recipient-with-name@example.org' => 'Recipient Name One',
+ 'no-name@example.org', // Note that this is not a key-value pair
+ 'named-recipient@example.org' => 'Recipient Name Two'
+ ));
+
+Setting ``To:`` Recipients
+~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+``To:`` recipients are required in a message and are set with the
+``setTo()`` or ``addTo()`` methods of the message.
+
+To set ``To:`` recipients, create the message object using either
+``new Swift_Message( ... )`` or ``Swift_Message::newInstance( ... )``,
+then call the ``setTo()`` method with a complete array of addresses, or use the
+``addTo()`` method to iteratively add recipients.
+
+The ``setTo()`` method accepts input in various formats as described earlier in
+this chapter. The ``addTo()`` method takes either one or two parameters. The
+first being the email address and the second optional parameter being the name
+of the recipient.
+
+``To:`` recipients are visible in the message headers and will be
+seen by the other recipients.
+
+.. note::
+
+ Multiple calls to ``setTo()`` will not add new recipients -- each
+ call overrides the previous calls. If you want to iteratively add
+ recipients, use the ``addTo()`` method.
+
+ .. code-block:: php
+
+ // Using setTo() to set all recipients in one go
+ $message->setTo(array(
+ 'person1@example.org',
+ 'person2@otherdomain.org' => 'Person 2 Name',
+ 'person3@example.org',
+ 'person4@example.org',
+ 'person5@example.org' => 'Person 5 Name'
+ ));
+
+ // Using addTo() to add recipients iteratively
+ $message->addTo('person1@example.org');
+ $message->addTo('person2@example.org', 'Person 2 Name');
+
+Setting ``Cc:`` Recipients
+~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+``Cc:`` recipients are set with the ``setCc()`` or ``addCc()`` methods of the
+message.
+
+To set ``Cc:`` recipients, create the message object using either
+``new Swift_Message( ... )`` or ``Swift_Message::newInstance( ... )``, then call
+the ``setCc()`` method with a complete array of addresses, or use the
+``addCc()`` method to iteratively add recipients.
+
+The ``setCc()`` method accepts input in various formats as described earlier in
+this chapter. The ``addCc()`` method takes either one or two parameters. The
+first being the email address and the second optional parameter being the name
+of the recipient.
+
+``Cc:`` recipients are visible in the message headers and will be
+seen by the other recipients.
+
+.. note::
+
+ Multiple calls to ``setCc()`` will not add new recipients -- each
+ call overrides the previous calls. If you want to iteratively add Cc:
+ recipients, use the ``addCc()`` method.
+
+ .. code-block:: php
+
+ // Using setCc() to set all recipients in one go
+ $message->setCc(array(
+ 'person1@example.org',
+ 'person2@otherdomain.org' => 'Person 2 Name',
+ 'person3@example.org',
+ 'person4@example.org',
+ 'person5@example.org' => 'Person 5 Name'
+ ));
+
+ // Using addCc() to add recipients iteratively
+ $message->addCc('person1@example.org');
+ $message->addCc('person2@example.org', 'Person 2 Name');
+
+Setting ``Bcc:`` Recipients
+~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+``Bcc:`` recipients receive a copy of the message without anybody else knowing
+it, and are set with the ``setBcc()`` or ``addBcc()`` methods of the message.
+
+To set ``Bcc:`` recipients, create the message object using either ``new
+Swift_Message( ... )`` or ``Swift_Message::newInstance( ... )``, then call the
+``setBcc()`` method with a complete array of addresses, or use
+the ``addBcc()`` method to iteratively add recipients.
+
+The ``setBcc()`` method accepts input in various formats as described earlier in
+this chapter. The ``addBcc()`` method takes either one or two parameters. The
+first being the email address and the second optional parameter being the name
+of the recipient.
+
+Only the individual ``Bcc:`` recipient will see their address in the message
+headers. Other recipients (including other ``Bcc:`` recipients) will not see the
+address.
+
+.. note::
+
+ Multiple calls to ``setBcc()`` will not add new recipients -- each
+ call overrides the previous calls. If you want to iteratively add Bcc:
+ recipients, use the ``addBcc()`` method.
+
+ .. code-block:: php
+
+ // Using setBcc() to set all recipients in one go
+ $message->setBcc(array(
+ 'person1@example.org',
+ 'person2@otherdomain.org' => 'Person 2 Name',
+ 'person3@example.org',
+ 'person4@example.org',
+ 'person5@example.org' => 'Person 5 Name'
+ ));
+
+ // Using addBcc() to add recipients iteratively
+ $message->addBcc('person1@example.org');
+ $message->addBcc('person2@example.org', 'Person 2 Name');
+
+Specifying Sender Details
+-------------------------
+
+An email must include information about who sent it. Usually this is managed
+by the ``From:`` address, however there are other options.
+
+The sender information is contained in three possible places:
+
+* ``From:`` -- the address(es) of who wrote the message (required)
+
+* ``Sender:`` -- the address of the single person who sent the message
+ (optional)
+
+* ``Return-Path:`` -- the address where bounces should go to (optional)
+
+You must always include a ``From:`` address by using ``setFrom()`` on the
+message. Swift Mailer will use this as the default ``Return-Path:`` unless
+otherwise specified.
+
+The ``Sender:`` address exists because the person who actually sent the email
+may not be the person who wrote the email. It has a higher precedence than the
+``From:`` address and will be used as the ``Return-Path:`` unless otherwise
+specified.
+
+Setting the ``From:`` Address
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+A ``From:`` address is required and is set with the ``setFrom()`` method of the
+message. ``From:`` addresses specify who actually wrote the email, and usually who sent it.
+
+What most people probably don't realise is that you can have more than one
+``From:`` address if more than one person wrote the email -- for example if an
+email was put together by a committee.
+
+To set the ``From:`` address(es):
+
+* Call the ``setFrom()`` method on the Message.
+
+The ``From:`` address(es) are visible in the message headers and
+will be seen by the recipients.
+
+.. note::
+
+ If you set multiple ``From:`` addresses then you absolutely must set a
+ ``Sender:`` address to indicate who physically sent the message.
+
+ .. code-block:: php
+
+ // Set a single From: address
+ $message->setFrom('your@address.tld');
+
+ // Set a From: address including a name
+ $message->setFrom(array('your@address.tld' => 'Your Name'));
+
+ // Set multiple From: addresses if multiple people wrote the email
+ $message->setFrom(array(
+ 'person1@example.org' => 'Sender One',
+ 'person2@example.org' => 'Sender Two'
+ ));
+
+Setting the ``Sender:`` Address
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+A ``Sender:`` address specifies who sent the message and is set with the
+``setSender()`` method of the message.
+
+To set the ``Sender:`` address:
+
+* Call the ``setSender()`` method on the Message.
+
+The ``Sender:`` address is visible in the message headers and will be seen by
+the recipients.
+
+This address will be used as the ``Return-Path:`` unless otherwise specified.
+
+.. note::
+
+ If you set multiple ``From:`` addresses then you absolutely must set a
+ ``Sender:`` address to indicate who physically sent the message.
+
+You must not set more than one sender address on a message because it's not
+possible for more than one person to send a single message.
+
+.. code-block:: php
+
+ $message->setSender('your@address.tld');
+
+Setting the ``Return-Path:`` (Bounce) Address
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+The ``Return-Path:`` address specifies where bounce notifications should
+be sent and is set with the ``setReturnPath()`` method of the message.
+
+You can only have one ``Return-Path:`` and it must not include
+a personal name.
+
+To set the ``Return-Path:`` address:
+
+* Call the ``setReturnPath()`` method on the Message.
+
+Bounce notifications will be sent to this address.
+
+.. code-block:: php
+
+ $message->setReturnPath('bounces@address.tld');
+
+
+Signed/Encrypted Message
+------------------------
+
+To increase the integrity/security of a message it is possible to sign and/or
+encrypt an message using one or multiple signers.
+
+S/MIME
+~~~~~~
+
+S/MIME can sign and/or encrypt a message using the OpenSSL extension.
+
+When signing a message, the signer creates a signature of the entire content of the message (including attachments).
+
+The certificate and private key must be PEM encoded, and can be either created using for example OpenSSL or
+obtained at an official Certificate Authority (CA).
+
+**The recipient must have the CA certificate in the list of trusted issuers in order to verify the signature.**
+
+**Make sure the certificate supports emailProtection.**
+
+When using OpenSSL this can done by the including the *-addtrust emailProtection* parameter when creating the certificate.
+
+.. code-block:: php
+
+ $message = Swift_Message::newInstance();
+
+ $smimeSigner = Swift_Signers_SMimeSigner::newInstance();
+ $smimeSigner->setSignCertificate('/path/to/certificate.pem', '/path/to/private-key.pem');
+ $message->attachSigner($smimeSigner);
+
+When the private key is secured using a passphrase use the following instead.
+
+.. code-block:: php
+
+ $message = Swift_Message::newInstance();
+
+ $smimeSigner = Swift_Signers_SMimeSigner::newInstance();
+ $smimeSigner->setSignCertificate('/path/to/certificate.pem', array('/path/to/private-key.pem', 'passphrase'));
+ $message->attachSigner($smimeSigner);
+
+By default the signature is added as attachment,
+making the message still readable for mailing agents not supporting signed messages.
+
+Storing the message as binary is also possible but not recommended.
+
+.. code-block:: php
+
+ $smimeSigner->setSignCertificate('/path/to/certificate.pem', '/path/to/private-key.pem', PKCS7_BINARY);
+
+When encrypting the message (also known as enveloping), the entire message (including attachments)
+is encrypted using a certificate, and the recipient can then decrypt the message using corresponding private key.
+
+Encrypting ensures nobody can read the contents of the message without the private key.
+
+Normally the recipient provides a certificate for encrypting and keeping the decryption key private.
+
+Using both signing and encrypting is also possible.
+
+.. code-block:: php
+
+ $message = Swift_Message::newInstance();
+
+ $smimeSigner = Swift_Signers_SMimeSigner::newInstance();
+ $smimeSigner->setSignCertificate('/path/to/sign-certificate.pem', '/path/to/private-key.pem');
+ $smimeSigner->setEncryptCertificate('/path/to/encrypt-certificate.pem');
+ $message->attachSigner($smimeSigner);
+
+The used encryption cipher can be set as the second parameter of setEncryptCertificate()
+
+See http://php.net/manual/openssl.ciphers for a list of supported ciphers.
+
+By default the message is first signed and then encrypted, this can be changed by adding.
+
+.. code-block:: php
+
+ $smimeSigner->setSignThenEncrypt(false);
+
+**Changing this is not recommended as most mail agents don't support this none-standard way.**
+
+Only when having trouble with sign then encrypt method, this should be changed.
+
+Requesting a Read Receipt
+-------------------------
+
+It is possible to request a read-receipt to be sent to an address when the
+email is opened. To request a read receipt set the address with
+``setReadReceiptTo()``.
+
+To request a read receipt:
+
+* Set the address you want the receipt to be sent to with the
+ ``setReadReceiptTo()`` method on the Message.
+
+When the email is opened, if the mail client supports it a notification will be sent to this address.
+
+.. note::
+
+ Read receipts won't work for the majority of recipients since many mail
+ clients auto-disable them. Those clients that will send a read receipt
+ will make the user aware that one has been requested.
+
+ .. code-block:: php
+
+ $message->setReadReceiptTo('your@address.tld');
+
+Setting the Character Set
+-------------------------
+
+The character set of the message (and it's MIME parts) is set with the
+``setCharset()`` method. You can also change the global default of UTF-8 by
+working with the ``Swift_Preferences`` class.
+
+Swift Mailer will default to the UTF-8 character set unless otherwise
+overridden. UTF-8 will work in most instances since it includes all of the
+standard US keyboard characters in addition to most international characters.
+
+It is absolutely vital however that you know what character set your message
+(or it's MIME parts) are written in otherwise your message may be received
+completely garbled.
+
+There are two places in Swift Mailer where you can change the character set:
+
+* In the ``Swift_Preferences`` class
+
+* On each individual message and/or MIME part
+
+To set the character set of your Message:
+
+* Change the global UTF-8 setting by calling
+ ``Swift_Preferences::setCharset()``; or
+
+* Call the ``setCharset()`` method on the message or the MIME part.
+
+ .. code-block:: php
+
+ // Approach 1: Change the global setting (suggested)
+ Swift_Preferences::getInstance()->setCharset('iso-8859-2');
+
+ // Approach 2: Call the setCharset() method of the message
+ $message = Swift_Message::newInstance()
+ ->setCharset('iso-8859-2');
+
+ // Approach 3: Specify the charset when setting the body
+ $message->setBody('My body', 'text/html', 'iso-8859-2');
+
+ // Approach 4: Specify the charset for each part added
+ $message->addPart('My part', 'text/plain', 'iso-8859-2');
+
+Setting the Line Length
+-----------------------
+
+The length of lines in a message can be changed by using the ``setMaxLineLength()`` method on the message. It should be kept to less than
+1000 characters.
+
+Swift Mailer defaults to using 78 characters per line in a message. This is
+done for historical reasons and so that the message can be easily viewed in
+plain-text terminals.
+
+To change the maximum length of lines in your Message:
+
+* Call the ``setMaxLineLength()`` method on the Message.
+
+Lines that are longer than the line length specified will be wrapped between
+words.
+
+.. note::
+
+ You should never set a maximum length longer than 1000 characters
+ according to RFC 2822. Doing so could have unspecified side-effects such
+ as truncating parts of your message when it is transported between SMTP
+ servers.
+
+ .. code-block:: php
+
+ $message->setMaxLineLength(1000);
+
+Setting the Message Priority
+----------------------------
+
+You can change the priority of the message with ``setPriority()``. Setting the
+priority will not change the way your email is sent -- it is purely an
+indicative setting for the recipient.
+
+The priority of a message is an indication to the recipient what significance
+it has. Swift Mailer allows you to set the priority by calling the ``setPriority`` method. This method takes an integer value between 1 and 5:
+
+* Highest
+* High
+* Normal
+* Low
+* Lowest
+
+To set the message priority:
+
+* Set the priority as an integer between 1 and 5 with the ``setPriority()``
+ method on the Message.
+
+.. code-block:: php
+
+ // Indicate "High" priority
+ $message->setPriority(2);
diff --git a/vendor/swiftmailer/swiftmailer/doc/overview.rst b/vendor/swiftmailer/swiftmailer/doc/overview.rst
new file mode 100644
index 00000000..c9126173
--- /dev/null
+++ b/vendor/swiftmailer/swiftmailer/doc/overview.rst
@@ -0,0 +1,161 @@
+Library Overview
+================
+
+Most features (and more) of your every day mail client software are provided
+by Swift Mailer, using object-oriented PHP code as the interface.
+
+In this chapter we will take a short tour of the various components, which put
+together form the Swift Mailer library as a whole. You will learn key
+terminology used throughout the rest of this book and you will gain a little
+understanding of the classes you will work with as you integrate Swift Mailer
+into your application.
+
+This chapter is intended to prepare you for the information contained in the
+subsequent chapters of this book. You may choose to skip this chapter if you
+are fairly technically minded, though it is likely to save you some time in
+the long run if you at least read between the lines here.
+
+System Requirements
+-------------------
+
+The basic requirements to operate Swift Mailer are extremely minimal and
+easily achieved. Historically, Swift Mailer has supported both PHP 4 and PHP 5
+by following a parallel development workflow. Now in it's fourth major
+version, and Swift Mailer operates on servers running PHP 5.2 or higher.
+
+The library aims to work with as many PHP 5 projects as possible:
+
+* PHP 5.2 or higher, with the SPL extension (standard)
+
+* Limited network access to connect to remote SMTP servers
+
+* 8 MB or more memory limit (Swift Mailer uses around 2 MB)
+
+Component Breakdown
+-------------------
+
+Swift Mailer is made up of many classes. Each of these classes can be grouped
+into a general "component" group which describes the task it is designed to
+perform.
+
+We'll take a brief look at the components which form Swift Mailer in this
+section of the book.
+
+The Mailer
+~~~~~~~~~~
+
+The mailer class, ``Swift_Mailer`` is the central class in the library where
+all of the other components meet one another. ``Swift_Mailer`` acts as a sort
+of message dispatcher, communicating with the underlying Transport to deliver
+your Message to all intended recipients.
+
+If you were to dig around in the source code for Swift Mailer you'd notice
+that ``Swift_Mailer`` itself is pretty bare. It delegates to other objects for
+most tasks and in theory, if you knew the internals of Swift Mailer well you
+could by-pass this class entirely. We wouldn't advise doing such a thing
+however -- there are reasons this class exists:
+
+* for consistency, regardless of the Transport used
+
+* to provide abstraction from the internals in the event internal API changes
+ are made
+
+* to provide convenience wrappers around aspects of the internal API
+
+An instance of ``Swift_Mailer`` is created by the developer before sending any
+Messages.
+
+Transports
+~~~~~~~~~~
+
+Transports are the classes in Swift Mailer that are responsible for
+communicating with a service in order to deliver a Message. There are several
+types of Transport in Swift Mailer, all of which implement the Swift_Transport
+interface and offer underlying start(), stop() and send() methods.
+
+Typically you will not need to know how a Transport works under-the-surface,
+you will only need to know how to create an instance of one, and which one to
+use for your environment.
+
++---------------------------------+---------------------------------------------------------------------------------------------+-----------------------------------------------------------------------------------------------------------------------------------------------+
+| Class | Features | Pros/cons |
++=================================+=============================================================================================+===============================================================================================================================================+
+| ``Swift_SmtpTransport`` | Sends messages over SMTP; Supports Authentication; Supports Encryption | Very portable; Pleasingly predictable results; Provides good feedback |
++---------------------------------+---------------------------------------------------------------------------------------------+-----------------------------------------------------------------------------------------------------------------------------------------------+
+| ``Swift_SendmailTransport`` | Communicates with a locally installed ``sendmail`` executable (Linux/UNIX) | Quick time-to-run; Provides less-accurate feedback than SMTP; Requires ``sendmail`` installation |
++---------------------------------+---------------------------------------------------------------------------------------------+-----------------------------------------------------------------------------------------------------------------------------------------------+
+| ``Swift_MailTransport`` | Uses PHP's built-in ``mail()`` function | Very portable; Potentially unpredictable results; Provides extremely weak feedback |
++---------------------------------+---------------------------------------------------------------------------------------------+-----------------------------------------------------------------------------------------------------------------------------------------------+
+| ``Swift_LoadBalancedTransport`` | Cycles through a collection of the other Transports to manage load-reduction | Provides graceful fallback if one Transport fails (e.g. an SMTP server is down); Keeps the load on remote services down by spreading the work |
++---------------------------------+---------------------------------------------------------------------------------------------+-----------------------------------------------------------------------------------------------------------------------------------------------+
+| ``Swift_FailoverTransport`` | Works in conjunction with a collection of the other Transports to provide high-availability | Provides graceful fallback if one Transport fails (e.g. an SMTP server is down) |
++---------------------------------+---------------------------------------------------------------------------------------------+-----------------------------------------------------------------------------------------------------------------------------------------------+
+
+MIME Entities
+~~~~~~~~~~~~~
+
+Everything that forms part of a Message is called a MIME Entity. All MIME
+entities in Swift Mailer share a common set of features. There are various
+types of MIME entity that serve different purposes such as Attachments and
+MIME parts.
+
+An e-mail message is made up of several relatively simple entities that are
+combined in different ways to achieve different results. All of these entities
+have the same fundamental outline but serve a different purpose. The Message
+itself can be defined as a MIME entity, an Attachment is a MIME entity, all
+MIME parts are MIME entities -- and so on!
+
+The basic units of each MIME entity -- be it the Message itself, or an
+Attachment -- are its Headers and its body:
+
+.. code-block:: text
+
+ Other-Header: Another value
+
+ The body content itself
+
+The Headers of a MIME entity, and its body must conform to some strict
+standards defined by various RFC documents. Swift Mailer ensures that these
+specifications are followed by using various types of object, including
+Encoders and different Header types to generate the entity.
+
+Each MIME component implements the base ``Swift_Mime_MimeEntity`` interface,
+which offers methods for retrieving Headers, adding new Headers, changing the
+Encoder, updating the body and so on!
+
+All MIME entities have one Header in common -- the Content-Type Header,
+updated with the entity's ``setContentType()`` method.
+
+Encoders
+~~~~~~~~
+
+Encoders are used to transform the content of Messages generated in Swift
+Mailer into a format that is safe to send across the internet and that
+conforms to RFC specifications.
+
+Generally speaking you will not need to interact with the Encoders in Swift
+Mailer -- the correct settings will be handled by the library itself.
+However they are probably worth a brief mention in the event that you do want
+to play with them.
+
+Both the Headers and the body of all MIME entities (including the Message
+itself) use Encoders to ensure the data they contain can be sent over the
+internet without becoming corrupted or misinterpreted.
+
+There are two types of Encoder: Base64 and Quoted-Printable.
+
+Plugins
+~~~~~~~
+
+Plugins exist to extend, or modify the behaviour of Swift Mailer. They respond
+to Events that are fired within the Transports during sending.
+
+There are a number of Plugins provided as part of the base Swift Mailer
+package and they all follow a common interface to respond to Events fired
+within the library. Interfaces are provided to "listen" to each type of Event
+fired and to act as desired when a listened-to Event occurs.
+
+Although several plugins are provided with Swift Mailer out-of-the-box, the
+Events system has been specifically designed to make it easy for experienced
+object-oriented developers to write their own plugins in order to achieve
+goals that may not be possible with the base library.
diff --git a/vendor/swiftmailer/swiftmailer/doc/plugins.rst b/vendor/swiftmailer/swiftmailer/doc/plugins.rst
new file mode 100644
index 00000000..16ae3356
--- /dev/null
+++ b/vendor/swiftmailer/swiftmailer/doc/plugins.rst
@@ -0,0 +1,385 @@
+Plugins
+=======
+
+Plugins are provided with Swift Mailer and can be used to extend the behavior
+of the library in situations where using simple class inheritance would be more complex.
+
+AntiFlood Plugin
+----------------
+
+Many SMTP servers have limits on the number of messages that may be sent
+during any single SMTP connection. The AntiFlood plugin provides a way to stay
+within this limit while still managing a large number of emails.
+
+A typical limit for a single connection is 100 emails. If the server you
+connect to imposes such a limit, it expects you to disconnect after that
+number of emails has been sent. You could manage this manually within a loop,
+but the AntiFlood plugin provides the necessary wrapper code so that you don't
+need to worry about this logic.
+
+Regardless of limits imposed by the server, it's usually a good idea to be
+conservative with the resources of the SMTP server. Sending will become
+sluggish if the server is being over-used so using the AntiFlood plugin will
+not be a bad idea even if no limits exist.
+
+The AntiFlood plugin's logic is basically to disconnect and the immediately
+re-connect with the SMTP server every X number of emails sent, where X is a
+number you specify to the plugin.
+
+You can also specify a time period in seconds that Swift Mailer should pause
+for between the disconnect/re-connect process. It's a good idea to pause for a
+short time (say 30 seconds every 100 emails) simply to give the SMTP server a
+chance to process its queue and recover some resources.
+
+Using the AntiFlood Plugin
+~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+The AntiFlood Plugin -- like all plugins -- is added with the Mailer class's
+``registerPlugin()`` method. It takes two constructor parameters: the number of
+emails to pause after, and optionally the number of seconds to pause for.
+
+To use the AntiFlood plugin:
+
+* Create an instance of the Mailer using any Transport you choose.
+
+* Create an instance of the ``Swift_Plugins_AntiFloodPlugin`` class, passing
+ in one or two constructor parameters.
+
+* Register the plugin using the Mailer's ``registerPlugin()`` method.
+
+* Continue using Swift Mailer to send messages as normal.
+
+When Swift Mailer sends messages it will count the number of messages that
+have been sent since the last re-connect. Once the number hits your specified
+threshold it will disconnect and re-connect, optionally pausing for a
+specified amount of time.
+
+.. code-block:: php
+
+ require_once 'lib/swift_required.php';
+
+ // Create the Mailer using any Transport
+ $mailer = Swift_Mailer::newInstance(
+ Swift_SmtpTransport::newInstance('smtp.example.org', 25)
+ );
+
+ // Use AntiFlood to re-connect after 100 emails
+ $mailer->registerPlugin(new Swift_Plugins_AntiFloodPlugin(100));
+
+ // And specify a time in seconds to pause for (30 secs)
+ $mailer->registerPlugin(new Swift_Plugins_AntiFloodPlugin(100, 30));
+
+ // Continue sending as normal
+ for ($lotsOfRecipients as $recipient) {
+ ...
+
+ $mailer->send( ... );
+ }
+
+Throttler Plugin
+----------------
+
+If your SMTP server has restrictions in place to limit the rate at which you
+send emails, then your code will need to be aware of this rate-limiting. The
+Throttler plugin makes Swift Mailer run at a rate-limited speed.
+
+Many shared hosts don't open their SMTP servers as a free-for-all. Usually
+they have policies in place (probably to discourage spammers) that only allow
+you to send a fixed number of emails per-hour/day.
+
+The Throttler plugin supports two modes of rate-limiting and with each, you
+will need to do that math to figure out the values you want. The plugin can
+limit based on the number of emails per minute, or the number of
+bytes-transferred per-minute.
+
+Using the Throttler Plugin
+~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+The Throttler Plugin -- like all plugins -- is added with the Mailer class'
+``registerPlugin()`` method. It has two required constructor parameters that
+tell it how to do its rate-limiting.
+
+To use the Throttler plugin:
+
+* Create an instance of the Mailer using any Transport you choose.
+
+* Create an instance of the ``Swift_Plugins_ThrottlerPlugin`` class, passing
+ the number of emails, or bytes you wish to limit by, along with the mode
+ you're using.
+
+* Register the plugin using the Mailer's ``registerPlugin()`` method.
+
+* Continue using Swift Mailer to send messages as normal.
+
+When Swift Mailer sends messages it will keep track of the rate at which sending
+messages is occurring. If it realises that sending is happening too fast, it
+will cause your program to ``sleep()`` for enough time to average out the rate.
+
+.. code-block:: php
+
+ require_once 'lib/swift_required.php';
+
+ // Create the Mailer using any Transport
+ $mailer = Swift_Mailer::newInstance(
+ Swift_SmtpTransport::newInstance('smtp.example.org', 25)
+ );
+
+ // Rate limit to 100 emails per-minute
+ $mailer->registerPlugin(new Swift_Plugins_ThrottlerPlugin(
+ 100, Swift_Plugins_ThrottlerPlugin::MESSAGES_PER_MINUTE
+ ));
+
+ // Rate limit to 10MB per-minute
+ $mailer->registerPlugin(new Swift_Plugins_ThrottlerPlugin(
+ 1024 * 1024 * 10, Swift_Plugins_ThrottlerPlugin::BYTES_PER_MINUTE
+ ));
+
+ // Continue sending as normal
+ for ($lotsOfRecipients as $recipient) {
+ ...
+
+ $mailer->send( ... );
+ }
+
+Logger Plugin
+-------------
+
+The Logger plugins helps with debugging during the process of sending. It can
+help to identify why an SMTP server is rejecting addresses, or any other
+hard-to-find problems that may arise.
+
+The Logger plugin comes in two parts. There's the plugin itself, along with
+one of a number of possible Loggers that you may choose to use. For example,
+the logger may output messages directly in realtime, or it may capture
+messages in an array.
+
+One other notable feature is the way in which the Logger plugin changes
+Exception messages. If Exceptions are being thrown but the error message does
+not provide conclusive information as to the source of the problem (such as an
+ambiguous SMTP error) the Logger plugin includes the entire SMTP transcript in
+the error message so that debugging becomes a simpler task.
+
+There are a few available Loggers included with Swift Mailer, but writing your
+own implementation is incredibly simple and is achieved by creating a short
+class that implements the ``Swift_Plugins_Logger`` interface.
+
+* ``Swift_Plugins_Loggers_ArrayLogger``: Keeps a collection of log messages
+ inside an array. The array content can be cleared or dumped out to the
+ screen.
+
+* ``Swift_Plugins_Loggers_EchoLogger``: Prints output to the screen in
+ realtime. Handy for very rudimentary debug output.
+
+Using the Logger Plugin
+~~~~~~~~~~~~~~~~~~~~~~~
+
+The Logger Plugin -- like all plugins -- is added with the Mailer class'
+``registerPlugin()`` method. It accepts an instance of ``Swift_Plugins_Logger``
+in its constructor.
+
+To use the Logger plugin:
+
+* Create an instance of the Mailer using any Transport you choose.
+
+* Create an instance of the a Logger implementation of
+ ``Swift_Plugins_Logger``.
+
+* Create an instance of the ``Swift_Plugins_LoggerPlugin`` class, passing the
+ created Logger instance to its constructor.
+
+* Register the plugin using the Mailer's ``registerPlugin()`` method.
+
+* Continue using Swift Mailer to send messages as normal.
+
+* Dump the contents of the log with the logger's ``dump()`` method.
+
+When Swift Mailer sends messages it will keep a log of all the interactions
+with the underlying Transport being used. Depending upon the Logger that has
+been used the behaviour will differ, but all implementations offer a way to
+get the contents of the log.
+
+.. code-block:: php
+
+ require_once 'lib/swift_required.php';
+
+ // Create the Mailer using any Transport
+ $mailer = Swift_Mailer::newInstance(
+ Swift_SmtpTransport::newInstance('smtp.example.org', 25)
+ );
+
+ // To use the ArrayLogger
+ $logger = new Swift_Plugins_Loggers_ArrayLogger();
+ $mailer->registerPlugin(new Swift_Plugins_LoggerPlugin($logger));
+
+ // Or to use the Echo Logger
+ $logger = new Swift_Plugins_Loggers_EchoLogger();
+ $mailer->registerPlugin(new Swift_Plugins_LoggerPlugin($logger));
+
+ // Continue sending as normal
+ for ($lotsOfRecipients as $recipient) {
+ ...
+
+ $mailer->send( ... );
+ }
+
+ // Dump the log contents
+ // NOTE: The EchoLogger dumps in realtime so dump() does nothing for it
+ echo $logger->dump();
+
+Decorator Plugin
+----------------
+
+Often there's a need to send the same message to multiple recipients, but with
+tiny variations such as the recipient's name being used inside the message
+body. The Decorator plugin aims to provide a solution for allowing these small
+differences.
+
+The decorator plugin works by intercepting the sending process of Swift
+Mailer, reading the email address in the To: field and then looking up a set
+of replacements for a template.
+
+While the use of this plugin is simple, it is probably the most commonly
+misunderstood plugin due to the way in which it works. The typical mistake
+users make is to try registering the plugin multiple times (once for each
+recipient) -- inside a loop for example. This is incorrect.
+
+The Decorator plugin should be registered just once, but containing the list
+of all recipients prior to sending. It will use this list of recipients to
+find the required replacements during sending.
+
+Using the Decorator Plugin
+~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+To use the Decorator plugin, simply create an associative array of replacements
+based on email addresses and then use the mailer's ``registerPlugin()`` method
+to add the plugin.
+
+First create an associative array of replacements based on the email addresses
+you'll be sending the message to.
+
+.. note::
+
+ The replacements array becomes a 2-dimensional array whose keys are the
+ email addresses and whose values are an associative array of replacements
+ for that email address. The curly braces used in this example can be any
+ type of syntax you choose, provided they match the placeholders in your
+ email template.
+
+ .. code-block:: php
+
+ $replacements = array();
+ foreach ($users as $user) {
+ $replacements[$user['email']] = array(
+ '{username}'=>$user['username'],
+ '{password}'=>$user['password']
+ );
+ }
+
+Now create an instance of the Decorator plugin using this array of replacements
+and then register it with the Mailer. Do this only once!
+
+.. code-block:: php
+
+ $decorator = new Swift_Plugins_DecoratorPlugin($replacements);
+
+ $mailer->registerPlugin($decorator);
+
+When you create your message, replace elements in the body (and/or the subject
+line) with your placeholders.
+
+.. code-block:: php
+
+ $message = Swift_Message::newInstance()
+ ->setSubject('Important notice for {username}')
+ ->setBody(
+ "Hello {username}, we have reset your password to {password}\n" .
+ "Please log in and change it at your earliest convenience."
+ )
+ ;
+
+ foreach ($users as $user) {
+ $message->addTo($user['email']);
+ }
+
+When you send this message to each of your recipients listed in your
+``$replacements`` array they will receive a message customized for just
+themselves. For example, the message used above when received may appear like
+this to one user:
+
+.. code-block:: text
+
+ Subject: Important notice for smilingsunshine2009
+
+ Hello smilingsunshine2009, we have reset your password to rainyDays
+ Please log in and change it at your earliest convenience.
+
+While another use may receive the message as:
+
+.. code-block:: text
+
+ Subject: Important notice for billy-bo-bob
+
+ Hello billy-bo-bob, we have reset your password to dancingOctopus
+ Please log in and change it at your earliest convenience.
+
+While the decorator plugin provides a means to solve this problem, there are
+various ways you could tackle this problem without the need for a plugin.
+We're trying to come up with a better way ourselves and while we have several
+(obvious) ideas we don't quite have the perfect solution to go ahead and
+implement it. Watch this space.
+
+Providing Your Own Replacements Lookup for the Decorator
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+Filling an array with replacements may not be the best solution for providing
+replacement information to the decorator. If you have a more elegant algorithm
+that performs replacement lookups on-the-fly you may provide your own
+implementation.
+
+Providing your own replacements lookup implementation for the Decorator is
+simply a matter of passing an instance of ``Swift_Plugins_Decorator_Replacements`` to the decorator plugin's constructor,
+rather than passing in an array.
+
+The Replacements interface is very simple to implement since it has just one
+method: ``getReplacementsFor($address)``.
+
+Imagine you want to look up replacements from a database on-the-fly, you might
+provide an implementation that does this. You need to create a small class.
+
+.. code-block:: php
+
+ class DbReplacements implements Swift_Plugins_Decorator_Replacements {
+ public function getReplacementsFor($address) {
+ $sql = sprintf(
+ "SELECT * FROM user WHERE email = '%s'",
+ mysql_real_escape_string($address)
+ );
+
+ $result = mysql_query($sql);
+
+ if ($row = mysql_fetch_assoc($result)) {
+ return array(
+ '{username}'=>$row['username'],
+ '{password}'=>$row['password']
+ );
+ }
+ }
+ }
+
+Now all you need to do is pass an instance of your class into the Decorator
+plugin's constructor instead of passing an array.
+
+.. code-block:: php
+
+ $decorator = new Swift_Plugins_DecoratorPlugin(new DbReplacements());
+
+ $mailer->registerPlugin($decorator);
+
+For each message sent, the plugin will call your class' ``getReplacementsFor()``
+method to find the array of replacements it needs.
+
+.. note::
+
+ If your lookup algorithm is case sensitive, you should transform the
+ ``$address`` argument as appropriate -- for example by passing it
+ through ``strtolower()``.
diff --git a/vendor/swiftmailer/swiftmailer/doc/sending.rst b/vendor/swiftmailer/swiftmailer/doc/sending.rst
new file mode 100644
index 00000000..3e9c3a8d
--- /dev/null
+++ b/vendor/swiftmailer/swiftmailer/doc/sending.rst
@@ -0,0 +1,607 @@
+Sending Messages
+================
+
+Quick Reference for Sending a Message
+-------------------------------------
+
+Sending a message is very straightforward. You create a Transport, use it to
+create the Mailer, then you use the Mailer to send the message.
+
+To send a Message:
+
+* Create a Transport from one of the provided Transports --
+ ``Swift_SmtpTransport``, ``Swift_SendmailTransport``, ``Swift_MailTransport``
+ or one of the aggregate Transports.
+
+* Create an instance of the ``Swift_Mailer`` class, using the Transport as
+ it's constructor parameter.
+
+* Create a Message.
+
+* Send the message via the ``send()`` method on the Mailer object.
+
+.. caution::
+
+ The ``Swift_SmtpTransport`` and ``Swift_SendmailTransport`` transports use
+ ``proc_*`` PHP functions, which might not be available on your PHP
+ installation. You can easily check if that's the case by running the
+ following PHP script: ``setUsername('your username')
+ ->setPassword('your password')
+ ;
+
+ /*
+ You could alternatively use a different transport such as Sendmail or Mail:
+
+ // Sendmail
+ $transport = Swift_SendmailTransport::newInstance('/usr/sbin/sendmail -bs');
+
+ // Mail
+ $transport = Swift_MailTransport::newInstance();
+ */
+
+ // Create the Mailer using your created Transport
+ $mailer = Swift_Mailer::newInstance($transport);
+
+ // Create a message
+ $message = Swift_Message::newInstance('Wonderful Subject')
+ ->setFrom(array('john@doe.com' => 'John Doe'))
+ ->setTo(array('receiver@domain.org', 'other@domain.org' => 'A name'))
+ ->setBody('Here is the message itself')
+ ;
+
+ // Send the message
+ $result = $mailer->send($message);
+
+Transport Types
+~~~~~~~~~~~~~~~
+
+A Transport is the component which actually does the sending. You need to
+provide a Transport object to the Mailer class and there are several possible
+options.
+
+Typically you will not need to know how a Transport works under-the-surface,
+you will only need to know how to create an instance of one, and which one to
+use for your environment.
+
+The SMTP Transport
+..................
+
+The SMTP Transport sends messages over the (standardized) Simple Message
+Transfer Protocol. It can deal with encryption and authentication.
+
+The SMTP Transport, ``Swift_SmtpTransport`` is without doubt the most commonly
+used Transport because it will work on 99% of web servers (I just made that
+number up, but you get the idea). All the server needs is the ability to
+connect to a remote (or even local) SMTP server on the correct port number
+(usually 25).
+
+SMTP servers often require users to authenticate with a username and password
+before any mail can be sent to other domains. This is easily achieved using
+Swift Mailer with the SMTP Transport.
+
+SMTP is a protocol -- in other words it's a "way" of communicating a job
+to be done (i.e. sending a message). The SMTP protocol is the fundamental
+basis on which messages are delivered all over the internet 7 days a week, 365
+days a year. For this reason it's the most "direct" method of sending messages
+you can use and it's the one that will give you the most power and feedback
+(such as delivery failures) when using Swift Mailer.
+
+Because SMTP is generally run as a remote service (i.e. you connect to it over
+the network/internet) it's extremely portable from server-to-server. You can
+easily store the SMTP server address and port number in a configuration file
+within your application and adjust the settings accordingly if the code is
+moved or if the SMTP server is changed.
+
+Some SMTP servers -- Google for example -- use encryption for security reasons.
+Swift Mailer supports using both SSL and TLS encryption settings.
+
+Using the SMTP Transport
+^^^^^^^^^^^^^^^^^^^^^^^^
+
+The SMTP Transport is easy to use. Most configuration options can be set with
+the constructor.
+
+To use the SMTP Transport you need to know which SMTP server your code needs
+to connect to. Ask your web host if you're not sure. Lots of people ask me who
+to connect to -- I really can't answer that since it's a setting that's
+extremely specific to your hosting environment.
+
+To use the SMTP Transport:
+
+* Call ``Swift_SmtpTransport::newInstance()`` with the SMTP server name and
+ optionally with a port number (defaults to 25).
+
+* Use the returned object to create the Mailer.
+
+A connection to the SMTP server will be established upon the first call to
+``send()``.
+
+.. code-block:: php
+
+ require_once 'lib/swift_required.php';
+
+ // Create the Transport
+ $transport = Swift_SmtpTransport::newInstance('smtp.example.org', 25);
+
+ // Create the Mailer using your created Transport
+ $mailer = Swift_Mailer::newInstance($transport);
+
+ /*
+ It's also possible to use multiple method calls
+
+ $transport = Swift_SmtpTransport::newInstance()
+ ->setHost('smtp.example.org')
+ ->setPort(25)
+ ;
+ */
+
+Encrypted SMTP
+^^^^^^^^^^^^^^
+
+You can use SSL or TLS encryption with the SMTP Transport by specifying it as
+a parameter or with a method call.
+
+To use encryption with the SMTP Transport:
+
+* Pass the encryption setting as a third parameter to
+ ``Swift_SmtpTransport::newInstance()``; or
+
+* Call the ``setEncryption()`` method on the Transport.
+
+A connection to the SMTP server will be established upon the first call to
+``send()``. The connection will be initiated with the correct encryption
+settings.
+
+.. note::
+
+ For SSL or TLS encryption to work your PHP installation must have
+ appropriate OpenSSL transports wrappers. You can check if "tls" and/or
+ "ssl" are present in your PHP installation by using the PHP function
+ ``stream_get_transports()``
+
+ .. code-block:: php
+
+ require_once 'lib/swift_required.php';
+
+ // Create the Transport
+ $transport = Swift_SmtpTransport::newInstance('smtp.example.org', 587, 'ssl');
+
+ // Create the Mailer using your created Transport
+ $mailer = Swift_Mailer::newInstance($transport);
+
+ /*
+ It's also possible to use multiple method calls
+
+ $transport = Swift_SmtpTransport::newInstance()
+ ->setHost('smtp.example.org')
+ ->setPort(587)
+ ->setEncryption('ssl')
+ ;
+ */
+
+SMTP with a Username and Password
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+Some servers require authentication. You can provide a username and password
+with ``setUsername()`` and ``setPassword()`` methods.
+
+To use a username and password with the SMTP Transport:
+
+* Create the Transport with ``Swift_SmtpTransport::newInstance()``.
+
+* Call the ``setUsername()`` and ``setPassword()`` methods on the Transport.
+
+Your username and password will be used to authenticate upon first connect
+when ``send()`` are first used on the Mailer.
+
+If authentication fails, an Exception of type ``Swift_TransportException`` will
+be thrown.
+
+.. note::
+
+ If you need to know early whether or not authentication has failed and an
+ Exception is going to be thrown, call the ``start()`` method on the
+ created Transport.
+
+ .. code-block:: php
+
+ require_once 'lib/swift_required.php';
+
+ // Create the Transport the call setUsername() and setPassword()
+ $transport = Swift_SmtpTransport::newInstance('smtp.example.org', 25)
+ ->setUsername('username')
+ ->setPassword('password')
+ ;
+
+ // Create the Mailer using your created Transport
+ $mailer = Swift_Mailer::newInstance($transport);
+
+The Sendmail Transport
+......................
+
+The Sendmail Transport sends messages by communicating with a locally
+installed MTA -- such as ``sendmail``.
+
+The Sendmail Transport, ``Swift_SendmailTransport`` does not directly connect to
+any remote services. It is designed for Linux servers that have ``sendmail``
+installed. The Transport starts a local ``sendmail`` process and sends messages
+to it. Usually the ``sendmail`` process will respond quickly as it spools your
+messages to disk before sending them.
+
+The Transport is named the Sendmail Transport for historical reasons
+(``sendmail`` was the "standard" UNIX tool for sending e-mail for years). It
+will send messages using other transfer agents such as Exim or Postfix despite
+its name, provided they have the relevant sendmail wrappers so that they can be
+started with the correct command-line flags.
+
+It's a common misconception that because the Sendmail Transport returns a
+result very quickly it must therefore deliver messages to recipients quickly
+-- this is not true. It's not slow by any means, but it's certainly not
+faster than SMTP when it comes to getting messages to the intended recipients.
+This is because sendmail itself sends the messages over SMTP once they have
+been quickly spooled to disk.
+
+The Sendmail Transport has the potential to be just as smart of the SMTP
+Transport when it comes to notifying Swift Mailer about which recipients were
+rejected, but in reality the majority of locally installed ``sendmail``
+instances are not configured well enough to provide any useful feedback. As such
+Swift Mailer may report successful deliveries where they did in fact fail before
+they even left your server.
+
+You can run the Sendmail Transport in two different modes specified by command
+line flags:
+
+* "``-bs``" runs in SMTP mode so theoretically it will act like the SMTP
+ Transport
+
+* "``-t``" runs in piped mode with no feedback, but theoretically faster,
+ though not advised
+
+You can think of the Sendmail Transport as a sort of asynchronous SMTP Transport
+-- though if you have problems with delivery failures you should try using the
+SMTP Transport instead. Swift Mailer isn't doing the work here, it's simply
+passing the work to somebody else (i.e. ``sendmail``).
+
+Using the Sendmail Transport
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+To use the Sendmail Transport you simply need to call
+``Swift_SendmailTransport::newInstance()`` with the command as a parameter.
+
+To use the Sendmail Transport you need to know where ``sendmail`` or another MTA
+exists on the server. Swift Mailer uses a default value of
+``/usr/sbin/sendmail``, which should work on most systems.
+
+You specify the entire command as a parameter (i.e. including the command line
+flags). Swift Mailer supports operational modes of "``-bs``" (default) and
+"``-t``".
+
+.. note::
+
+ If you run sendmail in "``-t``" mode you will get no feedback as to whether
+ or not sending has succeeded. Use "``-bs``" unless you have a reason not to.
+
+To use the Sendmail Transport:
+
+* Call ``Swift_SendmailTransport::newInstance()`` with the command, including
+ the correct command line flags. The default is to use ``/usr/sbin/sendmail
+ -bs`` if this is not specified.
+
+* Use the returned object to create the Mailer.
+
+A sendmail process will be started upon the first call to ``send()``. If the
+process cannot be started successfully an Exception of type
+``Swift_TransportException`` will be thrown.
+
+.. code-block:: php
+
+ require_once 'lib/swift_required.php';
+
+ // Create the Transport
+ $transport = Swift_SendmailTransport::newInstance('/usr/sbin/exim -bs');
+
+ // Create the Mailer using your created Transport
+ $mailer = Swift_Mailer::newInstance($transport);
+
+The Mail Transport
+..................
+
+The Mail Transport sends messages by delegating to PHP's internal
+``mail()`` function.
+
+In my experience -- and others' -- the ``mail()`` function is not particularly
+predictable, or helpful.
+
+Quite notably, the ``mail()`` function behaves entirely differently between
+Linux and Windows servers. On linux it uses ``sendmail``, but on Windows it uses
+SMTP.
+
+In order for the ``mail()`` function to even work at all ``php.ini`` needs to be
+configured correctly, specifying the location of sendmail or of an SMTP server.
+
+The problem with ``mail()`` is that it "tries" to simplify things to the point
+that it actually makes things more complex due to poor interface design. The
+developers of Swift Mailer have gone to a lot of effort to make the Mail
+Transport work with a reasonable degree of consistency.
+
+Serious drawbacks when using this Transport are:
+
+* Unpredictable message headers
+
+* Lack of feedback regarding delivery failures
+
+* Lack of support for several plugins that require real-time delivery feedback
+
+It's a last resort, and we say that with a passion!
+
+Using the Mail Transport
+^^^^^^^^^^^^^^^^^^^^^^^^
+
+To use the Mail Transport you simply need to call
+``Swift_MailTransport::newInstance()``. It's unlikely you'll need to configure
+the Transport.
+
+To use the Mail Transport:
+
+* Call ``Swift_MailTransport::newInstance()``.
+
+* Use the returned object to create the Mailer.
+
+Messages will be sent using the ``mail()`` function.
+
+.. note::
+
+ The ``mail()`` function can take a ``$additional_parameters`` parameter.
+ Swift Mailer sets this to "``-f%s``" by default, where the "%s" is
+ substituted with the address of the sender (via a ``sprintf()``) at send
+ time. You may override this default by passing an argument to
+ ``newInstance()``.
+
+ .. code-block:: php
+
+ require_once 'lib/swift_required.php';
+
+ // Create the Transport
+ $transport = Swift_MailTransport::newInstance();
+
+ // Create the Mailer using your created Transport
+ $mailer = Swift_Mailer::newInstance($transport);
+
+Available Methods for Sending Messages
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+The Mailer class offers two methods for sending Messages -- ``send()``.
+Each behaves in a slightly different way.
+
+When a message is sent in Swift Mailer, the Mailer class communicates with
+whichever Transport class you have chosen to use.
+
+Each recipient in the message should either be accepted or rejected by the
+Transport. For example, if the domain name on the email address is not
+reachable the SMTP Transport may reject the address because it cannot process
+it. Whichever method you use -- ``send()`` -- Swift Mailer will return
+an integer indicating the number of accepted recipients.
+
+.. note::
+
+ It's possible to find out which recipients were rejected -- we'll cover that
+ later in this chapter.
+
+Using the ``send()`` Method
+...........................
+
+The ``send()`` method of the ``Swift_Mailer`` class sends a message using
+exactly the same logic as your Desktop mail client would use. Just pass it a
+Message and get a result.
+
+To send a Message with ``send()``:
+
+* Create a Transport from one of the provided Transports --
+ ``Swift_SmtpTransport``, ``Swift_SendmailTransport``,
+ ``Swift_MailTransport`` or one of the aggregate Transports.
+
+* Create an instance of the ``Swift_Mailer`` class, using the Transport as
+ it's constructor parameter.
+
+* Create a Message.
+
+* Send the message via the ``send()`` method on the Mailer object.
+
+The message will be sent just like it would be sent if you used your mail
+client. An integer is returned which includes the number of successful
+recipients. If none of the recipients could be sent to then zero will be
+returned, which equates to a boolean ``false``. If you set two
+``To:`` recipients and three ``Bcc:`` recipients in the message and all of the
+recipients are delivered to successfully then the value 5 will be returned.
+
+.. code-block:: php
+
+ require_once 'lib/swift_required.php';
+
+ // Create the Transport
+ $transport = Swift_SmtpTransport::newInstance('localhost', 25);
+
+ // Create the Mailer using your created Transport
+ $mailer = Swift_Mailer::newInstance($transport);
+
+ // Create a message
+ $message = Swift_Message::newInstance('Wonderful Subject')
+ ->setFrom(array('john@doe.com' => 'John Doe'))
+ ->setTo(array('receiver@domain.org', 'other@domain.org' => 'A name'))
+ ->setBody('Here is the message itself')
+ ;
+
+ // Send the message
+ $numSent = $mailer->send($message);
+
+ printf("Sent %d messages\n", $numSent);
+
+ /* Note that often that only the boolean equivalent of the
+ return value is of concern (zero indicates FALSE)
+
+ if ($mailer->send($message))
+ {
+ echo "Sent\n";
+ }
+ else
+ {
+ echo "Failed\n";
+ }
+
+ */
+
+Sending Emails in Batch
+.......................
+
+If you want to send a separate message to each recipient so that only their
+own address shows up in the ``To:`` field, follow the following recipe:
+
+* Create a Transport from one of the provided Transports --
+ ``Swift_SmtpTransport``, ``Swift_SendmailTransport``,
+ ``Swift_MailTransport`` or one of the aggregate Transports.
+
+* Create an instance of the ``Swift_Mailer`` class, using the Transport as
+ it's constructor parameter.
+
+* Create a Message.
+
+* Iterate over the recipients and send message via the ``send()`` method on
+ the Mailer object.
+
+Each recipient of the messages receives a different copy with only their own
+email address on the ``To:`` field.
+
+Make sure to add only valid email addresses as recipients. If you try to add an
+invalid email address with ``setTo()``, ``setCc()`` or ``setBcc()``, Swift
+Mailer will throw a ``Swift_RfcComplianceException``.
+
+If you add recipients automatically based on a data source that may contain
+invalid email addresses, you can prevent possible exceptions by validating the
+addresses using ``Swift_Validate::email($email)`` and only adding addresses
+that validate. Another way would be to wrap your ``setTo()``, ``setCc()`` and
+``setBcc()`` calls in a try-catch block and handle the
+``Swift_RfcComplianceException`` in the catch block.
+
+Handling invalid addresses properly is especially important when sending emails
+in large batches since a single invalid address might cause an unhandled
+exception and stop the execution or your script early.
+
+.. note::
+
+ In the following example, two emails are sent. One to each of
+ ``receiver@domain.org`` and ``other@domain.org``. These recipients will
+ not be aware of each other.
+
+ .. code-block:: php
+
+ require_once 'lib/swift_required.php';
+
+ // Create the Transport
+ $transport = Swift_SmtpTransport::newInstance('localhost', 25);
+
+ // Create the Mailer using your created Transport
+ $mailer = Swift_Mailer::newInstance($transport);
+
+ // Create a message
+ $message = Swift_Message::newInstance('Wonderful Subject')
+ ->setFrom(array('john@doe.com' => 'John Doe'))
+ ->setBody('Here is the message itself')
+ ;
+
+ // Send the message
+ $failedRecipients = array();
+ $numSent = 0;
+ $to = array('receiver@domain.org', 'other@domain.org' => 'A name');
+
+ foreach ($to as $address => $name)
+ {
+ if (is_int($address)) {
+ $message->setTo($name);
+ } else {
+ $message->setTo(array($address => $name));
+ }
+
+ $numSent += $mailer->send($message, $failedRecipients);
+ }
+
+ printf("Sent %d messages\n", $numSent);
+
+Finding out Rejected Addresses
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+It's possible to get a list of addresses that were rejected by the Transport
+by using a by-reference parameter to ``send()``.
+
+As Swift Mailer attempts to send the message to each address given to it, if a
+recipient is rejected it will be added to the array. You can pass an existing
+array, otherwise one will be created by-reference.
+
+Collecting the list of recipients that were rejected can be useful in
+circumstances where you need to "prune" a mailing list for example when some
+addresses cannot be delivered to.
+
+Getting Failures By-reference
+.............................
+
+Collecting delivery failures by-reference with the ``send()`` method is as
+simple as passing a variable name to the method call.
+
+To get failed recipients by-reference:
+
+* Pass a by-reference variable name to the ``send()`` method of the Mailer
+ class.
+
+If the Transport rejects any of the recipients, the culprit addresses will be
+added to the array provided by-reference.
+
+.. note::
+
+ If the variable name does not yet exist, it will be initialized as an
+ empty array and then failures will be added to that array. If the variable
+ already exists it will be type-cast to an array and failures will be added
+ to it.
+
+ .. code-block:: php
+
+ $mailer = Swift_Mailer::newInstance( ... );
+
+ $message = Swift_Message::newInstance( ... )
+ ->setFrom( ... )
+ ->setTo(array(
+ 'receiver@bad-domain.org' => 'Receiver Name',
+ 'other@domain.org' => 'A name',
+ 'other-receiver@bad-domain.org' => 'Other Name'
+ ))
+ ->setBody( ... )
+ ;
+
+ // Pass a variable name to the send() method
+ if (!$mailer->send($message, $failures))
+ {
+ echo "Failures:";
+ print_r($failures);
+ }
+
+ /*
+ Failures:
+ Array (
+ 0 => receiver@bad-domain.org,
+ 1 => other-receiver@bad-domain.org
+ )
+ */
diff --git a/vendor/swiftmailer/swiftmailer/doc/uml/Encoders.graffle b/vendor/swiftmailer/swiftmailer/doc/uml/Encoders.graffle
new file mode 100644
index 00000000..f895752b
Binary files /dev/null and b/vendor/swiftmailer/swiftmailer/doc/uml/Encoders.graffle differ
diff --git a/vendor/swiftmailer/swiftmailer/doc/uml/Mime.graffle b/vendor/swiftmailer/swiftmailer/doc/uml/Mime.graffle
new file mode 100644
index 00000000..e1e33cbf
Binary files /dev/null and b/vendor/swiftmailer/swiftmailer/doc/uml/Mime.graffle differ
diff --git a/vendor/swiftmailer/swiftmailer/doc/uml/Transports.graffle b/vendor/swiftmailer/swiftmailer/doc/uml/Transports.graffle
new file mode 100644
index 00000000..5670e2b6
Binary files /dev/null and b/vendor/swiftmailer/swiftmailer/doc/uml/Transports.graffle differ
diff --git a/vendor/swiftmailer/swiftmailer/lib/classes/Swift.php b/vendor/swiftmailer/swiftmailer/lib/classes/Swift.php
new file mode 100644
index 00000000..729b9bb2
--- /dev/null
+++ b/vendor/swiftmailer/swiftmailer/lib/classes/Swift.php
@@ -0,0 +1,80 @@
+createDependenciesFor('mime.attachment')
+ );
+
+ $this->setBody($data);
+ $this->setFilename($filename);
+ if ($contentType) {
+ $this->setContentType($contentType);
+ }
+ }
+
+ /**
+ * Create a new Attachment.
+ *
+ * @param string|Swift_OutputByteStream $data
+ * @param string $filename
+ * @param string $contentType
+ *
+ * @return Swift_Mime_Attachment
+ */
+ public static function newInstance($data = null, $filename = null, $contentType = null)
+ {
+ return new self($data, $filename, $contentType);
+ }
+
+ /**
+ * Create a new Attachment from a filesystem path.
+ *
+ * @param string $path
+ * @param string $contentType optional
+ *
+ * @return Swift_Mime_Attachment
+ */
+ public static function fromPath($path, $contentType = null)
+ {
+ return self::newInstance()->setFile(
+ new Swift_ByteStream_FileByteStream($path),
+ $contentType
+ );
+ }
+}
diff --git a/vendor/swiftmailer/swiftmailer/lib/classes/Swift/ByteStream/AbstractFilterableInputStream.php b/vendor/swiftmailer/swiftmailer/lib/classes/Swift/ByteStream/AbstractFilterableInputStream.php
new file mode 100644
index 00000000..3e597d17
--- /dev/null
+++ b/vendor/swiftmailer/swiftmailer/lib/classes/Swift/ByteStream/AbstractFilterableInputStream.php
@@ -0,0 +1,179 @@
+_filters[$key] = $filter;
+ }
+
+ /**
+ * Remove an already present StreamFilter based on its $key.
+ *
+ * @param string $key
+ */
+ public function removeFilter($key)
+ {
+ unset($this->_filters[$key]);
+ }
+
+ /**
+ * Writes $bytes to the end of the stream.
+ *
+ * @param string $bytes
+ *
+ * @return int
+ *
+ * @throws Swift_IoException
+ */
+ public function write($bytes)
+ {
+ $this->_writeBuffer .= $bytes;
+ foreach ($this->_filters as $filter) {
+ if ($filter->shouldBuffer($this->_writeBuffer)) {
+ return;
+ }
+ }
+ $this->_doWrite($this->_writeBuffer);
+
+ return ++$this->_sequence;
+ }
+
+ /**
+ * For any bytes that are currently buffered inside the stream, force them
+ * off the buffer.
+ *
+ * @throws Swift_IoException
+ */
+ public function commit()
+ {
+ $this->_doWrite($this->_writeBuffer);
+ }
+
+ /**
+ * Attach $is to this stream.
+ *
+ * The stream acts as an observer, receiving all data that is written.
+ * All {@link write()} and {@link flushBuffers()} operations will be mirrored.
+ *
+ * @param Swift_InputByteStream $is
+ */
+ public function bind(Swift_InputByteStream $is)
+ {
+ $this->_mirrors[] = $is;
+ }
+
+ /**
+ * Remove an already bound stream.
+ *
+ * If $is is not bound, no errors will be raised.
+ * If the stream currently has any buffered data it will be written to $is
+ * before unbinding occurs.
+ *
+ * @param Swift_InputByteStream $is
+ */
+ public function unbind(Swift_InputByteStream $is)
+ {
+ foreach ($this->_mirrors as $k => $stream) {
+ if ($is === $stream) {
+ if ($this->_writeBuffer !== '') {
+ $stream->write($this->_writeBuffer);
+ }
+ unset($this->_mirrors[$k]);
+ }
+ }
+ }
+
+ /**
+ * Flush the contents of the stream (empty it) and set the internal pointer
+ * to the beginning.
+ *
+ * @throws Swift_IoException
+ */
+ public function flushBuffers()
+ {
+ if ($this->_writeBuffer !== '') {
+ $this->_doWrite($this->_writeBuffer);
+ }
+ $this->_flush();
+
+ foreach ($this->_mirrors as $stream) {
+ $stream->flushBuffers();
+ }
+ }
+
+ /** Run $bytes through all filters */
+ private function _filter($bytes)
+ {
+ foreach ($this->_filters as $filter) {
+ $bytes = $filter->filter($bytes);
+ }
+
+ return $bytes;
+ }
+
+ /** Just write the bytes to the stream */
+ private function _doWrite($bytes)
+ {
+ $this->_commit($this->_filter($bytes));
+
+ foreach ($this->_mirrors as $stream) {
+ $stream->write($bytes);
+ }
+
+ $this->_writeBuffer = '';
+ }
+}
diff --git a/vendor/swiftmailer/swiftmailer/lib/classes/Swift/ByteStream/ArrayByteStream.php b/vendor/swiftmailer/swiftmailer/lib/classes/Swift/ByteStream/ArrayByteStream.php
new file mode 100644
index 00000000..186a7c28
--- /dev/null
+++ b/vendor/swiftmailer/swiftmailer/lib/classes/Swift/ByteStream/ArrayByteStream.php
@@ -0,0 +1,184 @@
+_array = $stack;
+ $this->_arraySize = count($stack);
+ } elseif (is_string($stack)) {
+ $this->write($stack);
+ } else {
+ $this->_array = array();
+ }
+ }
+
+ /**
+ * Reads $length bytes from the stream into a string and moves the pointer
+ * through the stream by $length.
+ *
+ * If less bytes exist than are requested the
+ * remaining bytes are given instead. If no bytes are remaining at all, boolean
+ * false is returned.
+ *
+ * @param int $length
+ *
+ * @return string
+ */
+ public function read($length)
+ {
+ if ($this->_offset == $this->_arraySize) {
+ return false;
+ }
+
+ // Don't use array slice
+ $end = $length + $this->_offset;
+ $end = $this->_arraySize<$end
+ ? $this->_arraySize
+ : $end;
+ $ret = '';
+ for (; $this->_offset < $end; ++$this->_offset) {
+ $ret .= $this->_array[$this->_offset];
+ }
+
+ return $ret;
+ }
+
+ /**
+ * Writes $bytes to the end of the stream.
+ *
+ * @param string $bytes
+ */
+ public function write($bytes)
+ {
+ $to_add = str_split($bytes);
+ foreach ($to_add as $value) {
+ $this->_array[] = $value;
+ }
+ $this->_arraySize = count($this->_array);
+
+ foreach ($this->_mirrors as $stream) {
+ $stream->write($bytes);
+ }
+ }
+
+ /**
+ * Not used.
+ */
+ public function commit()
+ {
+ }
+
+ /**
+ * Attach $is to this stream.
+ *
+ * The stream acts as an observer, receiving all data that is written.
+ * All {@link write()} and {@link flushBuffers()} operations will be mirrored.
+ *
+ * @param Swift_InputByteStream $is
+ */
+ public function bind(Swift_InputByteStream $is)
+ {
+ $this->_mirrors[] = $is;
+ }
+
+ /**
+ * Remove an already bound stream.
+ *
+ * If $is is not bound, no errors will be raised.
+ * If the stream currently has any buffered data it will be written to $is
+ * before unbinding occurs.
+ *
+ * @param Swift_InputByteStream $is
+ */
+ public function unbind(Swift_InputByteStream $is)
+ {
+ foreach ($this->_mirrors as $k => $stream) {
+ if ($is === $stream) {
+ unset($this->_mirrors[$k]);
+ }
+ }
+ }
+
+ /**
+ * Move the internal read pointer to $byteOffset in the stream.
+ *
+ * @param int $byteOffset
+ *
+ * @return bool
+ */
+ public function setReadPointer($byteOffset)
+ {
+ if ($byteOffset > $this->_arraySize) {
+ $byteOffset = $this->_arraySize;
+ } elseif ($byteOffset < 0) {
+ $byteOffset = 0;
+ }
+
+ $this->_offset = $byteOffset;
+ }
+
+ /**
+ * Flush the contents of the stream (empty it) and set the internal pointer
+ * to the beginning.
+ */
+ public function flushBuffers()
+ {
+ $this->_offset = 0;
+ $this->_array = array();
+ $this->_arraySize = 0;
+
+ foreach ($this->_mirrors as $stream) {
+ $stream->flushBuffers();
+ }
+ }
+}
diff --git a/vendor/swiftmailer/swiftmailer/lib/classes/Swift/ByteStream/FileByteStream.php b/vendor/swiftmailer/swiftmailer/lib/classes/Swift/ByteStream/FileByteStream.php
new file mode 100644
index 00000000..6c144623
--- /dev/null
+++ b/vendor/swiftmailer/swiftmailer/lib/classes/Swift/ByteStream/FileByteStream.php
@@ -0,0 +1,229 @@
+_path = $path;
+ $this->_mode = $writable ? 'w+b' : 'rb';
+
+ if (function_exists('get_magic_quotes_runtime') && @get_magic_quotes_runtime() == 1) {
+ $this->_quotes = true;
+ }
+ }
+
+ /**
+ * Get the complete path to the file.
+ *
+ * @return string
+ */
+ public function getPath()
+ {
+ return $this->_path;
+ }
+
+ /**
+ * Reads $length bytes from the stream into a string and moves the pointer
+ * through the stream by $length.
+ *
+ * If less bytes exist than are requested the
+ * remaining bytes are given instead. If no bytes are remaining at all, boolean
+ * false is returned.
+ *
+ * @param int $length
+ *
+ * @return string|bool
+ *
+ * @throws Swift_IoException
+ */
+ public function read($length)
+ {
+ $fp = $this->_getReadHandle();
+ if (!feof($fp)) {
+ if ($this->_quotes) {
+ ini_set('magic_quotes_runtime', 0);
+ }
+ $bytes = fread($fp, $length);
+ if ($this->_quotes) {
+ ini_set('magic_quotes_runtime', 1);
+ }
+ $this->_offset = ftell($fp);
+
+ // If we read one byte after reaching the end of the file
+ // feof() will return false and an empty string is returned
+ if ($bytes === '' && feof($fp)) {
+ $this->_resetReadHandle();
+
+ return false;
+ }
+
+ return $bytes;
+ }
+
+ $this->_resetReadHandle();
+
+ return false;
+ }
+
+ /**
+ * Move the internal read pointer to $byteOffset in the stream.
+ *
+ * @param int $byteOffset
+ *
+ * @return bool
+ */
+ public function setReadPointer($byteOffset)
+ {
+ if (isset($this->_reader)) {
+ $this->_seekReadStreamToPosition($byteOffset);
+ }
+ $this->_offset = $byteOffset;
+ }
+
+ /** Just write the bytes to the file */
+ protected function _commit($bytes)
+ {
+ fwrite($this->_getWriteHandle(), $bytes);
+ $this->_resetReadHandle();
+ }
+
+ /** Not used */
+ protected function _flush()
+ {
+ }
+
+ /** Get the resource for reading */
+ private function _getReadHandle()
+ {
+ if (!isset($this->_reader)) {
+ if (!$this->_reader = fopen($this->_path, 'rb')) {
+ throw new Swift_IoException(
+ 'Unable to open file for reading ['.$this->_path.']'
+ );
+ }
+ if ($this->_offset != 0) {
+ $this->_getReadStreamSeekableStatus();
+ $this->_seekReadStreamToPosition($this->_offset);
+ }
+ }
+
+ return $this->_reader;
+ }
+
+ /** Get the resource for writing */
+ private function _getWriteHandle()
+ {
+ if (!isset($this->_writer)) {
+ if (!$this->_writer = fopen($this->_path, $this->_mode)) {
+ throw new Swift_IoException(
+ 'Unable to open file for writing ['.$this->_path.']'
+ );
+ }
+ }
+
+ return $this->_writer;
+ }
+
+ /** Force a reload of the resource for reading */
+ private function _resetReadHandle()
+ {
+ if (isset($this->_reader)) {
+ fclose($this->_reader);
+ $this->_reader = null;
+ }
+ }
+
+ /** Check if ReadOnly Stream is seekable */
+ private function _getReadStreamSeekableStatus()
+ {
+ $metas = stream_get_meta_data($this->_reader);
+ $this->_seekable = $metas['seekable'];
+ }
+
+ /** Streams in a readOnly stream ensuring copy if needed */
+ private function _seekReadStreamToPosition($offset)
+ {
+ if ($this->_seekable === null) {
+ $this->_getReadStreamSeekableStatus();
+ }
+ if ($this->_seekable === false) {
+ $currentPos = ftell($this->_reader);
+ if ($currentPos<$offset) {
+ $toDiscard = $offset-$currentPos;
+ fread($this->_reader, $toDiscard);
+
+ return;
+ }
+ $this->_copyReadStream();
+ }
+ fseek($this->_reader, $offset, SEEK_SET);
+ }
+
+ /** Copy a readOnly Stream to ensure seekability */
+ private function _copyReadStream()
+ {
+ if ($tmpFile = fopen('php://temp/maxmemory:4096', 'w+b')) {
+ /* We have opened a php:// Stream Should work without problem */
+ } elseif (function_exists('sys_get_temp_dir') && is_writable(sys_get_temp_dir()) && ($tmpFile = tmpfile())) {
+ /* We have opened a tmpfile */
+ } else {
+ throw new Swift_IoException('Unable to copy the file to make it seekable, sys_temp_dir is not writable, php://memory not available');
+ }
+ $currentPos = ftell($this->_reader);
+ fclose($this->_reader);
+ $source = fopen($this->_path, 'rb');
+ if (!$source) {
+ throw new Swift_IoException('Unable to open file for copying ['.$this->_path.']');
+ }
+ fseek($tmpFile, 0, SEEK_SET);
+ while (!feof($source)) {
+ fwrite($tmpFile, fread($source, 4096));
+ }
+ fseek($tmpFile, $currentPos, SEEK_SET);
+ fclose($source);
+ $this->_reader = $tmpFile;
+ }
+}
diff --git a/vendor/swiftmailer/swiftmailer/lib/classes/Swift/ByteStream/TemporaryFileByteStream.php b/vendor/swiftmailer/swiftmailer/lib/classes/Swift/ByteStream/TemporaryFileByteStream.php
new file mode 100644
index 00000000..eb33151b
--- /dev/null
+++ b/vendor/swiftmailer/swiftmailer/lib/classes/Swift/ByteStream/TemporaryFileByteStream.php
@@ -0,0 +1,42 @@
+getPath())) === false) {
+ throw new Swift_IoException('Failed to get temporary file content.');
+ }
+
+ return $content;
+ }
+
+ public function __destruct()
+ {
+ if (file_exists($this->getPath())) {
+ @unlink($this->getPath());
+ }
+ }
+}
diff --git a/vendor/swiftmailer/swiftmailer/lib/classes/Swift/CharacterReader.php b/vendor/swiftmailer/swiftmailer/lib/classes/Swift/CharacterReader.php
new file mode 100644
index 00000000..febd77eb
--- /dev/null
+++ b/vendor/swiftmailer/swiftmailer/lib/classes/Swift/CharacterReader.php
@@ -0,0 +1,67 @@
+
+ */
+interface Swift_CharacterReader
+{
+ const MAP_TYPE_INVALID = 0x01;
+ const MAP_TYPE_FIXED_LEN = 0x02;
+ const MAP_TYPE_POSITIONS = 0x03;
+
+ /**
+ * Returns the complete character map
+ *
+ * @param string $string
+ * @param int $startOffset
+ * @param array $currentMap
+ * @param mixed $ignoredChars
+ *
+ * @return int
+ */
+ public function getCharPositions($string, $startOffset, &$currentMap, &$ignoredChars);
+
+ /**
+ * Returns the mapType, see constants.
+ *
+ * @return int
+ */
+ public function getMapType();
+
+ /**
+ * Returns an integer which specifies how many more bytes to read.
+ *
+ * A positive integer indicates the number of more bytes to fetch before invoking
+ * this method again.
+ *
+ * A value of zero means this is already a valid character.
+ * A value of -1 means this cannot possibly be a valid character.
+ *
+ * @param integer[] $bytes
+ * @param int $size
+ *
+ * @return int
+ */
+ public function validateByteSequence($bytes, $size);
+
+ /**
+ * Returns the number of bytes which should be read to start each character.
+ *
+ * For fixed width character sets this should be the number of octets-per-character.
+ * For multibyte character sets this will probably be 1.
+ *
+ * @return int
+ */
+ public function getInitialByteSize();
+}
diff --git a/vendor/swiftmailer/swiftmailer/lib/classes/Swift/CharacterReader/GenericFixedWidthReader.php b/vendor/swiftmailer/swiftmailer/lib/classes/Swift/CharacterReader/GenericFixedWidthReader.php
new file mode 100644
index 00000000..d0c8698d
--- /dev/null
+++ b/vendor/swiftmailer/swiftmailer/lib/classes/Swift/CharacterReader/GenericFixedWidthReader.php
@@ -0,0 +1,97 @@
+
+ */
+class Swift_CharacterReader_GenericFixedWidthReader implements Swift_CharacterReader
+{
+ /**
+ * The number of bytes in a single character.
+ *
+ * @var int
+ */
+ private $_width;
+
+ /**
+ * Creates a new GenericFixedWidthReader using $width bytes per character.
+ *
+ * @param int $width
+ */
+ public function __construct($width)
+ {
+ $this->_width = $width;
+ }
+
+ /**
+ * Returns the complete character map.
+ *
+ * @param string $string
+ * @param int $startOffset
+ * @param array $currentMap
+ * @param mixed $ignoredChars
+ *
+ * @return int
+ */
+ public function getCharPositions($string, $startOffset, &$currentMap, &$ignoredChars)
+ {
+ $strlen = strlen($string);
+ // % and / are CPU intensive, so, maybe find a better way
+ $ignored = $strlen % $this->_width;
+ $ignoredChars = substr($string, - $ignored);
+ $currentMap = $this->_width;
+
+ return ($strlen - $ignored) / $this->_width;
+ }
+
+ /**
+ * Returns the mapType.
+ *
+ * @return int
+ */
+ public function getMapType()
+ {
+ return self::MAP_TYPE_FIXED_LEN;
+ }
+
+ /**
+ * Returns an integer which specifies how many more bytes to read.
+ *
+ * A positive integer indicates the number of more bytes to fetch before invoking
+ * this method again.
+ *
+ * A value of zero means this is already a valid character.
+ * A value of -1 means this cannot possibly be a valid character.
+ *
+ * @param string $bytes
+ * @param int $size
+ *
+ * @return int
+ */
+ public function validateByteSequence($bytes, $size)
+ {
+ $needed = $this->_width - $size;
+
+ return ($needed > -1) ? $needed : -1;
+ }
+
+ /**
+ * Returns the number of bytes which should be read to start each character.
+ *
+ * @return int
+ */
+ public function getInitialByteSize()
+ {
+ return $this->_width;
+ }
+}
diff --git a/vendor/swiftmailer/swiftmailer/lib/classes/Swift/CharacterReader/UsAsciiReader.php b/vendor/swiftmailer/swiftmailer/lib/classes/Swift/CharacterReader/UsAsciiReader.php
new file mode 100644
index 00000000..229c567f
--- /dev/null
+++ b/vendor/swiftmailer/swiftmailer/lib/classes/Swift/CharacterReader/UsAsciiReader.php
@@ -0,0 +1,84 @@
+"\x07F") {
+ // Invalid char
+ $currentMap[$i+$startOffset] = $string[$i];
+ }
+ }
+
+ return $strlen;
+ }
+
+ /**
+ * Returns mapType
+ *
+ * @return int mapType
+ */
+ public function getMapType()
+ {
+ return self::MAP_TYPE_INVALID;
+ }
+
+ /**
+ * Returns an integer which specifies how many more bytes to read.
+ *
+ * A positive integer indicates the number of more bytes to fetch before invoking
+ * this method again.
+ * A value of zero means this is already a valid character.
+ * A value of -1 means this cannot possibly be a valid character.
+ *
+ * @param string $bytes
+ * @param int $size
+ *
+ * @return int
+ */
+ public function validateByteSequence($bytes, $size)
+ {
+ $byte = reset($bytes);
+ if (1 == count($bytes) && $byte >= 0x00 && $byte <= 0x7F) {
+ return 0;
+ } else {
+ return -1;
+ }
+ }
+
+ /**
+ * Returns the number of bytes which should be read to start each character.
+ *
+ * @return int
+ */
+ public function getInitialByteSize()
+ {
+ return 1;
+ }
+}
diff --git a/vendor/swiftmailer/swiftmailer/lib/classes/Swift/CharacterReader/Utf8Reader.php b/vendor/swiftmailer/swiftmailer/lib/classes/Swift/CharacterReader/Utf8Reader.php
new file mode 100644
index 00000000..aebbecf6
--- /dev/null
+++ b/vendor/swiftmailer/swiftmailer/lib/classes/Swift/CharacterReader/Utf8Reader.php
@@ -0,0 +1,179 @@
+
+ */
+class Swift_CharacterReader_Utf8Reader implements Swift_CharacterReader
+{
+ /** Pre-computed for optimization */
+ private static $length_map = array(
+ // N=0,1,2,3,4,5,6,7,8,9,A,B,C,D,E,F,
+ 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, // 0x0N
+ 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, // 0x1N
+ 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, // 0x2N
+ 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, // 0x3N
+ 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, // 0x4N
+ 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, // 0x5N
+ 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, // 0x6N
+ 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, // 0x7N
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, // 0x8N
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, // 0x9N
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, // 0xAN
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, // 0xBN
+ 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, // 0xCN
+ 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, // 0xDN
+ 3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3, // 0xEN
+ 4,4,4,4,4,4,4,4,5,5,5,5,6,6,0,0, // 0xFN
+ );
+
+ private static $s_length_map = array(
+ "\x00" => 1, "\x01" => 1, "\x02" => 1, "\x03" => 1, "\x04" => 1, "\x05" => 1, "\x06" => 1, "\x07" => 1,
+ "\x08" => 1, "\x09" => 1, "\x0a" => 1, "\x0b" => 1, "\x0c" => 1, "\x0d" => 1, "\x0e" => 1, "\x0f" => 1,
+ "\x10" => 1, "\x11" => 1, "\x12" => 1, "\x13" => 1, "\x14" => 1, "\x15" => 1, "\x16" => 1, "\x17" => 1,
+ "\x18" => 1, "\x19" => 1, "\x1a" => 1, "\x1b" => 1, "\x1c" => 1, "\x1d" => 1, "\x1e" => 1, "\x1f" => 1,
+ "\x20" => 1, "\x21" => 1, "\x22" => 1, "\x23" => 1, "\x24" => 1, "\x25" => 1, "\x26" => 1, "\x27" => 1,
+ "\x28" => 1, "\x29" => 1, "\x2a" => 1, "\x2b" => 1, "\x2c" => 1, "\x2d" => 1, "\x2e" => 1, "\x2f" => 1,
+ "\x30" => 1, "\x31" => 1, "\x32" => 1, "\x33" => 1, "\x34" => 1, "\x35" => 1, "\x36" => 1, "\x37" => 1,
+ "\x38" => 1, "\x39" => 1, "\x3a" => 1, "\x3b" => 1, "\x3c" => 1, "\x3d" => 1, "\x3e" => 1, "\x3f" => 1,
+ "\x40" => 1, "\x41" => 1, "\x42" => 1, "\x43" => 1, "\x44" => 1, "\x45" => 1, "\x46" => 1, "\x47" => 1,
+ "\x48" => 1, "\x49" => 1, "\x4a" => 1, "\x4b" => 1, "\x4c" => 1, "\x4d" => 1, "\x4e" => 1, "\x4f" => 1,
+ "\x50" => 1, "\x51" => 1, "\x52" => 1, "\x53" => 1, "\x54" => 1, "\x55" => 1, "\x56" => 1, "\x57" => 1,
+ "\x58" => 1, "\x59" => 1, "\x5a" => 1, "\x5b" => 1, "\x5c" => 1, "\x5d" => 1, "\x5e" => 1, "\x5f" => 1,
+ "\x60" => 1, "\x61" => 1, "\x62" => 1, "\x63" => 1, "\x64" => 1, "\x65" => 1, "\x66" => 1, "\x67" => 1,
+ "\x68" => 1, "\x69" => 1, "\x6a" => 1, "\x6b" => 1, "\x6c" => 1, "\x6d" => 1, "\x6e" => 1, "\x6f" => 1,
+ "\x70" => 1, "\x71" => 1, "\x72" => 1, "\x73" => 1, "\x74" => 1, "\x75" => 1, "\x76" => 1, "\x77" => 1,
+ "\x78" => 1, "\x79" => 1, "\x7a" => 1, "\x7b" => 1, "\x7c" => 1, "\x7d" => 1, "\x7e" => 1, "\x7f" => 1,
+ "\x80" => 0, "\x81" => 0, "\x82" => 0, "\x83" => 0, "\x84" => 0, "\x85" => 0, "\x86" => 0, "\x87" => 0,
+ "\x88" => 0, "\x89" => 0, "\x8a" => 0, "\x8b" => 0, "\x8c" => 0, "\x8d" => 0, "\x8e" => 0, "\x8f" => 0,
+ "\x90" => 0, "\x91" => 0, "\x92" => 0, "\x93" => 0, "\x94" => 0, "\x95" => 0, "\x96" => 0, "\x97" => 0,
+ "\x98" => 0, "\x99" => 0, "\x9a" => 0, "\x9b" => 0, "\x9c" => 0, "\x9d" => 0, "\x9e" => 0, "\x9f" => 0,
+ "\xa0" => 0, "\xa1" => 0, "\xa2" => 0, "\xa3" => 0, "\xa4" => 0, "\xa5" => 0, "\xa6" => 0, "\xa7" => 0,
+ "\xa8" => 0, "\xa9" => 0, "\xaa" => 0, "\xab" => 0, "\xac" => 0, "\xad" => 0, "\xae" => 0, "\xaf" => 0,
+ "\xb0" => 0, "\xb1" => 0, "\xb2" => 0, "\xb3" => 0, "\xb4" => 0, "\xb5" => 0, "\xb6" => 0, "\xb7" => 0,
+ "\xb8" => 0, "\xb9" => 0, "\xba" => 0, "\xbb" => 0, "\xbc" => 0, "\xbd" => 0, "\xbe" => 0, "\xbf" => 0,
+ "\xc0" => 2, "\xc1" => 2, "\xc2" => 2, "\xc3" => 2, "\xc4" => 2, "\xc5" => 2, "\xc6" => 2, "\xc7" => 2,
+ "\xc8" => 2, "\xc9" => 2, "\xca" => 2, "\xcb" => 2, "\xcc" => 2, "\xcd" => 2, "\xce" => 2, "\xcf" => 2,
+ "\xd0" => 2, "\xd1" => 2, "\xd2" => 2, "\xd3" => 2, "\xd4" => 2, "\xd5" => 2, "\xd6" => 2, "\xd7" => 2,
+ "\xd8" => 2, "\xd9" => 2, "\xda" => 2, "\xdb" => 2, "\xdc" => 2, "\xdd" => 2, "\xde" => 2, "\xdf" => 2,
+ "\xe0" => 3, "\xe1" => 3, "\xe2" => 3, "\xe3" => 3, "\xe4" => 3, "\xe5" => 3, "\xe6" => 3, "\xe7" => 3,
+ "\xe8" => 3, "\xe9" => 3, "\xea" => 3, "\xeb" => 3, "\xec" => 3, "\xed" => 3, "\xee" => 3, "\xef" => 3,
+ "\xf0" => 4, "\xf1" => 4, "\xf2" => 4, "\xf3" => 4, "\xf4" => 4, "\xf5" => 4, "\xf6" => 4, "\xf7" => 4,
+ "\xf8" => 5, "\xf9" => 5, "\xfa" => 5, "\xfb" => 5, "\xfc" => 6, "\xfd" => 6, "\xfe" => 0, "\xff" => 0,
+ );
+
+ /**
+ * Returns the complete character map.
+ *
+ * @param string $string
+ * @param int $startOffset
+ * @param array $currentMap
+ * @param mixed $ignoredChars
+ *
+ * @return int
+ */
+ public function getCharPositions($string, $startOffset, &$currentMap, &$ignoredChars)
+ {
+ if (!isset($currentMap['i']) || ! isset($currentMap['p'])) {
+ $currentMap['p'] = $currentMap['i'] = array();
+ }
+
+ $strlen = strlen($string);
+ $charPos = count($currentMap['p']);
+ $foundChars = 0;
+ $invalid = false;
+ for ($i = 0; $i < $strlen; ++$i) {
+ $char = $string[$i];
+ $size = self::$s_length_map[$char];
+ if ($size == 0) {
+ /* char is invalid, we must wait for a resync */
+ $invalid = true;
+ continue;
+ } else {
+ if ($invalid == true) {
+ /* We mark the chars as invalid and start a new char */
+ $currentMap['p'][$charPos + $foundChars] = $startOffset + $i;
+ $currentMap['i'][$charPos + $foundChars] = true;
+ ++$foundChars;
+ $invalid = false;
+ }
+ if (($i + $size) > $strlen) {
+ $ignoredChars = substr($string, $i);
+ break;
+ }
+ for ($j = 1; $j < $size; ++$j) {
+ $char = $string[$i + $j];
+ if ($char > "\x7F" && $char < "\xC0") {
+ // Valid - continue parsing
+ } else {
+ /* char is invalid, we must wait for a resync */
+ $invalid = true;
+ continue 2;
+ }
+ }
+ /* Ok we got a complete char here */
+ $currentMap['p'][$charPos + $foundChars] = $startOffset + $i + $size;
+ $i += $j - 1;
+ ++$foundChars;
+ }
+ }
+
+ return $foundChars;
+ }
+
+ /**
+ * Returns mapType.
+ *
+ * @return int mapType
+ */
+ public function getMapType()
+ {
+ return self::MAP_TYPE_POSITIONS;
+ }
+
+ /**
+ * Returns an integer which specifies how many more bytes to read.
+ *
+ * A positive integer indicates the number of more bytes to fetch before invoking
+ * this method again.
+ * A value of zero means this is already a valid character.
+ * A value of -1 means this cannot possibly be a valid character.
+ *
+ * @param string $bytes
+ * @param int $size
+ *
+ * @return int
+ */
+ public function validateByteSequence($bytes, $size)
+ {
+ if ($size<1) {
+ return -1;
+ }
+ $needed = self::$length_map[$bytes[0]] - $size;
+
+ return ($needed > -1)
+ ? $needed
+ : -1
+ ;
+ }
+
+ /**
+ * Returns the number of bytes which should be read to start each character.
+ *
+ * @return int
+ */
+ public function getInitialByteSize()
+ {
+ return 1;
+ }
+}
diff --git a/vendor/swiftmailer/swiftmailer/lib/classes/Swift/CharacterReaderFactory.php b/vendor/swiftmailer/swiftmailer/lib/classes/Swift/CharacterReaderFactory.php
new file mode 100644
index 00000000..5bf38b8b
--- /dev/null
+++ b/vendor/swiftmailer/swiftmailer/lib/classes/Swift/CharacterReaderFactory.php
@@ -0,0 +1,26 @@
+init();
+ }
+
+ public function __wakeup()
+ {
+ $this->init();
+ }
+
+ public function init()
+ {
+ if (count(self::$_map) > 0) {
+ return;
+ }
+
+ $prefix = 'Swift_CharacterReader_';
+
+ $singleByte = array(
+ 'class' => $prefix.'GenericFixedWidthReader',
+ 'constructor' => array(1),
+ );
+
+ $doubleByte = array(
+ 'class' => $prefix.'GenericFixedWidthReader',
+ 'constructor' => array(2),
+ );
+
+ $fourBytes = array(
+ 'class' => $prefix.'GenericFixedWidthReader',
+ 'constructor' => array(4),
+ );
+
+ // Utf-8
+ self::$_map['utf-?8'] = array(
+ 'class' => $prefix.'Utf8Reader',
+ 'constructor' => array(),
+ );
+
+ //7-8 bit charsets
+ self::$_map['(us-)?ascii'] = $singleByte;
+ self::$_map['(iso|iec)-?8859-?[0-9]+'] = $singleByte;
+ self::$_map['windows-?125[0-9]'] = $singleByte;
+ self::$_map['cp-?[0-9]+'] = $singleByte;
+ self::$_map['ansi'] = $singleByte;
+ self::$_map['macintosh'] = $singleByte;
+ self::$_map['koi-?7'] = $singleByte;
+ self::$_map['koi-?8-?.+'] = $singleByte;
+ self::$_map['mik'] = $singleByte;
+ self::$_map['(cork|t1)'] = $singleByte;
+ self::$_map['v?iscii'] = $singleByte;
+
+ //16 bits
+ self::$_map['(ucs-?2|utf-?16)'] = $doubleByte;
+
+ //32 bits
+ self::$_map['(ucs-?4|utf-?32)'] = $fourBytes;
+
+ // Fallback
+ self::$_map['.*'] = $singleByte;
+ }
+
+ /**
+ * Returns a CharacterReader suitable for the charset applied.
+ *
+ * @param string $charset
+ *
+ * @return Swift_CharacterReader
+ */
+ public function getReaderFor($charset)
+ {
+ $charset = trim(strtolower($charset));
+ foreach (self::$_map as $pattern => $spec) {
+ $re = '/^'.$pattern.'$/D';
+ if (preg_match($re, $charset)) {
+ if (!array_key_exists($pattern, self::$_loaded)) {
+ $reflector = new ReflectionClass($spec['class']);
+ if ($reflector->getConstructor()) {
+ $reader = $reflector->newInstanceArgs($spec['constructor']);
+ } else {
+ $reader = $reflector->newInstance();
+ }
+ self::$_loaded[$pattern] = $reader;
+ }
+
+ return self::$_loaded[$pattern];
+ }
+ }
+ }
+}
diff --git a/vendor/swiftmailer/swiftmailer/lib/classes/Swift/CharacterStream.php b/vendor/swiftmailer/swiftmailer/lib/classes/Swift/CharacterStream.php
new file mode 100644
index 00000000..aa46779e
--- /dev/null
+++ b/vendor/swiftmailer/swiftmailer/lib/classes/Swift/CharacterStream.php
@@ -0,0 +1,89 @@
+setCharacterReaderFactory($factory);
+ $this->setCharacterSet($charset);
+ }
+
+ /**
+ * Set the character set used in this CharacterStream.
+ *
+ * @param string $charset
+ */
+ public function setCharacterSet($charset)
+ {
+ $this->_charset = $charset;
+ $this->_charReader = null;
+ }
+
+ /**
+ * Set the CharacterReaderFactory for multi charset support.
+ *
+ * @param Swift_CharacterReaderFactory $factory
+ */
+ public function setCharacterReaderFactory(Swift_CharacterReaderFactory $factory)
+ {
+ $this->_charReaderFactory = $factory;
+ }
+
+ /**
+ * Overwrite this character stream using the byte sequence in the byte stream.
+ *
+ * @param Swift_OutputByteStream $os output stream to read from
+ */
+ public function importByteStream(Swift_OutputByteStream $os)
+ {
+ if (!isset($this->_charReader)) {
+ $this->_charReader = $this->_charReaderFactory
+ ->getReaderFor($this->_charset);
+ }
+
+ $startLength = $this->_charReader->getInitialByteSize();
+ while (false !== $bytes = $os->read($startLength)) {
+ $c = array();
+ for ($i = 0, $len = strlen($bytes); $i < $len; ++$i) {
+ $c[] = self::$_byteMap[$bytes[$i]];
+ }
+ $size = count($c);
+ $need = $this->_charReader
+ ->validateByteSequence($c, $size);
+ if ($need > 0 &&
+ false !== $bytes = $os->read($need)) {
+ for ($i = 0, $len = strlen($bytes); $i < $len; ++$i) {
+ $c[] = self::$_byteMap[$bytes[$i]];
+ }
+ }
+ $this->_array[] = $c;
+ ++$this->_array_size;
+ }
+ }
+
+ /**
+ * Import a string a bytes into this CharacterStream, overwriting any existing
+ * data in the stream.
+ *
+ * @param string $string
+ */
+ public function importString($string)
+ {
+ $this->flushContents();
+ $this->write($string);
+ }
+
+ /**
+ * Read $length characters from the stream and move the internal pointer
+ * $length further into the stream.
+ *
+ * @param int $length
+ *
+ * @return string
+ */
+ public function read($length)
+ {
+ if ($this->_offset == $this->_array_size) {
+ return false;
+ }
+
+ // Don't use array slice
+ $arrays = array();
+ $end = $length + $this->_offset;
+ for ($i = $this->_offset; $i < $end; ++$i) {
+ if (!isset($this->_array[$i])) {
+ break;
+ }
+ $arrays[] = $this->_array[$i];
+ }
+ $this->_offset += $i - $this->_offset; // Limit function calls
+ $chars = false;
+ foreach ($arrays as $array) {
+ $chars .= implode('', array_map('chr', $array));
+ }
+
+ return $chars;
+ }
+
+ /**
+ * Read $length characters from the stream and return a 1-dimensional array
+ * containing there octet values.
+ *
+ * @param int $length
+ *
+ * @return integer[]
+ */
+ public function readBytes($length)
+ {
+ if ($this->_offset == $this->_array_size) {
+ return false;
+ }
+ $arrays = array();
+ $end = $length + $this->_offset;
+ for ($i = $this->_offset; $i < $end; ++$i) {
+ if (!isset($this->_array[$i])) {
+ break;
+ }
+ $arrays[] = $this->_array[$i];
+ }
+ $this->_offset += ($i - $this->_offset); // Limit function calls
+
+ return call_user_func_array('array_merge', $arrays);
+ }
+
+ /**
+ * Write $chars to the end of the stream.
+ *
+ * @param string $chars
+ */
+ public function write($chars)
+ {
+ if (!isset($this->_charReader)) {
+ $this->_charReader = $this->_charReaderFactory->getReaderFor(
+ $this->_charset);
+ }
+
+ $startLength = $this->_charReader->getInitialByteSize();
+
+ $fp = fopen('php://memory', 'w+b');
+ fwrite($fp, $chars);
+ unset($chars);
+ fseek($fp, 0, SEEK_SET);
+
+ $buffer = array(0);
+ $buf_pos = 1;
+ $buf_len = 1;
+ $has_datas = true;
+ do {
+ $bytes = array();
+ // Buffer Filing
+ if ($buf_len - $buf_pos < $startLength) {
+ $buf = array_splice($buffer, $buf_pos);
+ $new = $this->_reloadBuffer($fp, 100);
+ if ($new) {
+ $buffer = array_merge($buf, $new);
+ $buf_len = count($buffer);
+ $buf_pos = 0;
+ } else {
+ $has_datas = false;
+ }
+ }
+ if ($buf_len - $buf_pos > 0) {
+ $size = 0;
+ for ($i = 0; $i < $startLength && isset($buffer[$buf_pos]); ++$i) {
+ ++$size;
+ $bytes[] = $buffer[$buf_pos++];
+ }
+ $need = $this->_charReader->validateByteSequence(
+ $bytes, $size);
+ if ($need > 0) {
+ if ($buf_len - $buf_pos < $need) {
+ $new = $this->_reloadBuffer($fp, $need);
+
+ if ($new) {
+ $buffer = array_merge($buffer, $new);
+ $buf_len = count($buffer);
+ }
+ }
+ for ($i = 0; $i < $need && isset($buffer[$buf_pos]); ++$i) {
+ $bytes[] = $buffer[$buf_pos++];
+ }
+ }
+ $this->_array[] = $bytes;
+ ++$this->_array_size;
+ }
+ } while ($has_datas);
+
+ fclose($fp);
+ }
+
+ /**
+ * Move the internal pointer to $charOffset in the stream.
+ *
+ * @param int $charOffset
+ */
+ public function setPointer($charOffset)
+ {
+ if ($charOffset > $this->_array_size) {
+ $charOffset = $this->_array_size;
+ } elseif ($charOffset < 0) {
+ $charOffset = 0;
+ }
+ $this->_offset = $charOffset;
+ }
+
+ /**
+ * Empty the stream and reset the internal pointer.
+ */
+ public function flushContents()
+ {
+ $this->_offset = 0;
+ $this->_array = array();
+ $this->_array_size = 0;
+ }
+
+ private function _reloadBuffer($fp, $len)
+ {
+ if (!feof($fp) && ($bytes = fread($fp, $len)) !== false) {
+ $buf = array();
+ for ($i = 0, $len = strlen($bytes); $i < $len; ++$i) {
+ $buf[] = self::$_byteMap[$bytes[$i]];
+ }
+
+ return $buf;
+ }
+
+ return false;
+ }
+
+ private static function _initializeMaps()
+ {
+ if (!isset(self::$_charMap)) {
+ self::$_charMap = array();
+ for ($byte = 0; $byte < 256; ++$byte) {
+ self::$_charMap[$byte] = chr($byte);
+ }
+ self::$_byteMap = array_flip(self::$_charMap);
+ }
+ }
+}
diff --git a/vendor/swiftmailer/swiftmailer/lib/classes/Swift/CharacterStream/NgCharacterStream.php b/vendor/swiftmailer/swiftmailer/lib/classes/Swift/CharacterStream/NgCharacterStream.php
new file mode 100644
index 00000000..b962e403
--- /dev/null
+++ b/vendor/swiftmailer/swiftmailer/lib/classes/Swift/CharacterStream/NgCharacterStream.php
@@ -0,0 +1,276 @@
+
+ */
+
+class Swift_CharacterStream_NgCharacterStream implements Swift_CharacterStream
+{
+ /**
+ * The char reader (lazy-loaded) for the current charset.
+ *
+ * @var Swift_CharacterReader
+ */
+ private $_charReader;
+
+ /**
+ * A factory for creating CharacterReader instances.
+ *
+ * @var Swift_CharacterReaderFactory
+ */
+ private $_charReaderFactory;
+
+ /**
+ * The character set this stream is using.
+ *
+ * @var string
+ */
+ private $_charset;
+
+ /**
+ * The data's stored as-is.
+ *
+ * @var string
+ */
+ private $_datas = '';
+
+ /**
+ * Number of bytes in the stream
+ *
+ * @var int
+ */
+ private $_datasSize = 0;
+
+ /**
+ * Map.
+ *
+ * @var mixed
+ */
+ private $_map;
+
+ /**
+ * Map Type.
+ *
+ * @var int
+ */
+ private $_mapType = 0;
+
+ /**
+ * Number of characters in the stream.
+ *
+ * @var int
+ */
+ private $_charCount = 0;
+
+ /**
+ * Position in the stream.
+ *
+ * @var int
+ */
+ private $_currentPos = 0;
+
+ /**
+ * Constructor.
+ *
+ * @param Swift_CharacterReaderFactory $factory
+ * @param string $charset
+ */
+ public function __construct(Swift_CharacterReaderFactory $factory, $charset)
+ {
+ $this->setCharacterReaderFactory($factory);
+ $this->setCharacterSet($charset);
+ }
+
+ /* -- Changing parameters of the stream -- */
+
+ /**
+ * Set the character set used in this CharacterStream.
+ *
+ * @param string $charset
+ */
+ public function setCharacterSet($charset)
+ {
+ $this->_charset = $charset;
+ $this->_charReader = null;
+ $this->_mapType = 0;
+ }
+
+ /**
+ * Set the CharacterReaderFactory for multi charset support.
+ *
+ * @param Swift_CharacterReaderFactory $factory
+ */
+ public function setCharacterReaderFactory(Swift_CharacterReaderFactory $factory)
+ {
+ $this->_charReaderFactory = $factory;
+ }
+
+ /**
+ * @see Swift_CharacterStream::flushContents()
+ */
+ public function flushContents()
+ {
+ $this->_datas = null;
+ $this->_map = null;
+ $this->_charCount = 0;
+ $this->_currentPos = 0;
+ $this->_datasSize = 0;
+ }
+
+ /**
+ * @see Swift_CharacterStream::importByteStream()
+ *
+ * @param Swift_OutputByteStream $os
+ */
+ public function importByteStream(Swift_OutputByteStream $os)
+ {
+ $this->flushContents();
+ $blocks = 512;
+ $os->setReadPointer(0);
+ while (false !== ($read = $os->read($blocks))) {
+ $this->write($read);
+ }
+ }
+
+ /**
+ * @see Swift_CharacterStream::importString()
+ *
+ * @param string $string
+ */
+ public function importString($string)
+ {
+ $this->flushContents();
+ $this->write($string);
+ }
+
+ /**
+ * @see Swift_CharacterStream::read()
+ *
+ * @param int $length
+ *
+ * @return string
+ */
+ public function read($length)
+ {
+ if ($this->_currentPos >= $this->_charCount) {
+ return false;
+ }
+ $ret = false;
+ $length = ($this->_currentPos+$length > $this->_charCount)
+ ? $this->_charCount - $this->_currentPos
+ : $length;
+ switch ($this->_mapType) {
+ case Swift_CharacterReader::MAP_TYPE_FIXED_LEN:
+ $len = $length*$this->_map;
+ $ret = substr($this->_datas,
+ $this->_currentPos * $this->_map,
+ $len);
+ $this->_currentPos += $length;
+ break;
+
+ case Swift_CharacterReader::MAP_TYPE_INVALID:
+ $end = $this->_currentPos + $length;
+ $end = $end > $this->_charCount
+ ? $this->_charCount
+ : $end;
+ $ret = '';
+ for (; $this->_currentPos < $length; ++$this->_currentPos) {
+ if (isset ($this->_map[$this->_currentPos])) {
+ $ret .= '?';
+ } else {
+ $ret .= $this->_datas[$this->_currentPos];
+ }
+ }
+ break;
+
+ case Swift_CharacterReader::MAP_TYPE_POSITIONS:
+ $end = $this->_currentPos + $length;
+ $end = $end > $this->_charCount
+ ? $this->_charCount
+ : $end;
+ $ret = '';
+ $start = 0;
+ if ($this->_currentPos>0) {
+ $start = $this->_map['p'][$this->_currentPos-1];
+ }
+ $to = $start;
+ for (; $this->_currentPos < $end; ++$this->_currentPos) {
+ if (isset($this->_map['i'][$this->_currentPos])) {
+ $ret .= substr($this->_datas, $start, $to - $start).'?';
+ $start = $this->_map['p'][$this->_currentPos];
+ } else {
+ $to = $this->_map['p'][$this->_currentPos];
+ }
+ }
+ $ret .= substr($this->_datas, $start, $to - $start);
+ break;
+ }
+
+ return $ret;
+ }
+
+ /**
+ * @see Swift_CharacterStream::readBytes()
+ *
+ * @param int $length
+ *
+ * @return integer[]
+ */
+ public function readBytes($length)
+ {
+ $read = $this->read($length);
+ if ($read !== false) {
+ $ret = array_map('ord', str_split($read, 1));
+
+ return $ret;
+ }
+
+ return false;
+ }
+
+ /**
+ * @see Swift_CharacterStream::setPointer()
+ *
+ * @param int $charOffset
+ */
+ public function setPointer($charOffset)
+ {
+ if ($this->_charCount<$charOffset) {
+ $charOffset = $this->_charCount;
+ }
+ $this->_currentPos = $charOffset;
+ }
+
+ /**
+ * @see Swift_CharacterStream::write()
+ *
+ * @param string $chars
+ */
+ public function write($chars)
+ {
+ if (!isset($this->_charReader)) {
+ $this->_charReader = $this->_charReaderFactory->getReaderFor(
+ $this->_charset);
+ $this->_map = array();
+ $this->_mapType = $this->_charReader->getMapType();
+ }
+ $ignored = '';
+ $this->_datas .= $chars;
+ $this->_charCount += $this->_charReader->getCharPositions(substr($this->_datas, $this->_datasSize), $this->_datasSize, $this->_map, $ignored);
+ if ($ignored !== false) {
+ $this->_datasSize = strlen($this->_datas)-strlen($ignored);
+ } else {
+ $this->_datasSize = strlen($this->_datas);
+ }
+ }
+}
diff --git a/vendor/swiftmailer/swiftmailer/lib/classes/Swift/ConfigurableSpool.php b/vendor/swiftmailer/swiftmailer/lib/classes/Swift/ConfigurableSpool.php
new file mode 100644
index 00000000..df87527f
--- /dev/null
+++ b/vendor/swiftmailer/swiftmailer/lib/classes/Swift/ConfigurableSpool.php
@@ -0,0 +1,63 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+/**
+ * Base class for Spools (implements time and message limits).
+ *
+ * @author Fabien Potencier
+ */
+abstract class Swift_ConfigurableSpool implements Swift_Spool
+{
+ /** The maximum number of messages to send per flush */
+ private $_message_limit;
+
+ /** The time limit per flush */
+ private $_time_limit;
+
+ /**
+ * Sets the maximum number of messages to send per flush.
+ *
+ * @param int $limit
+ */
+ public function setMessageLimit($limit)
+ {
+ $this->_message_limit = (int) $limit;
+ }
+
+ /**
+ * Gets the maximum number of messages to send per flush.
+ *
+ * @return int The limit
+ */
+ public function getMessageLimit()
+ {
+ return $this->_message_limit;
+ }
+
+ /**
+ * Sets the time limit (in seconds) per flush.
+ *
+ * @param int $limit The limit
+ */
+ public function setTimeLimit($limit)
+ {
+ $this->_time_limit = (int) $limit;
+ }
+
+ /**
+ * Gets the time limit (in seconds) per flush.
+ *
+ * @return int The limit
+ */
+ public function getTimeLimit()
+ {
+ return $this->_time_limit;
+ }
+}
diff --git a/vendor/swiftmailer/swiftmailer/lib/classes/Swift/DependencyContainer.php b/vendor/swiftmailer/swiftmailer/lib/classes/Swift/DependencyContainer.php
new file mode 100644
index 00000000..1d8cb3a3
--- /dev/null
+++ b/vendor/swiftmailer/swiftmailer/lib/classes/Swift/DependencyContainer.php
@@ -0,0 +1,372 @@
+_store);
+ }
+
+ /**
+ * Test if an item is registered in this container with the given name.
+ *
+ * @see register()
+ *
+ * @param string $itemName
+ *
+ * @return bool
+ */
+ public function has($itemName)
+ {
+ return array_key_exists($itemName, $this->_store)
+ && isset($this->_store[$itemName]['lookupType']);
+ }
+
+ /**
+ * Lookup the item with the given $itemName.
+ *
+ * @see register()
+ *
+ * @param string $itemName
+ *
+ * @return mixed
+ *
+ * @throws Swift_DependencyException If the dependency is not found
+ */
+ public function lookup($itemName)
+ {
+ if (!$this->has($itemName)) {
+ throw new Swift_DependencyException(
+ 'Cannot lookup dependency "'.$itemName.'" since it is not registered.'
+ );
+ }
+
+ switch ($this->_store[$itemName]['lookupType']) {
+ case self::TYPE_ALIAS:
+ return $this->_createAlias($itemName);
+ case self::TYPE_VALUE:
+ return $this->_getValue($itemName);
+ case self::TYPE_INSTANCE:
+ return $this->_createNewInstance($itemName);
+ case self::TYPE_SHARED:
+ return $this->_createSharedInstance($itemName);
+ }
+ }
+
+ /**
+ * Create an array of arguments passed to the constructor of $itemName.
+ *
+ * @param string $itemName
+ *
+ * @return array
+ */
+ public function createDependenciesFor($itemName)
+ {
+ $args = array();
+ if (isset($this->_store[$itemName]['args'])) {
+ $args = $this->_resolveArgs($this->_store[$itemName]['args']);
+ }
+
+ return $args;
+ }
+
+ /**
+ * Register a new dependency with $itemName.
+ *
+ * This method returns the current DependencyContainer instance because it
+ * requires the use of the fluid interface to set the specific details for the
+ * dependency.
+ * @see asNewInstanceOf(), asSharedInstanceOf(), asValue()
+ *
+ * @param string $itemName
+ *
+ * @return Swift_DependencyContainer
+ */
+ public function register($itemName)
+ {
+ $this->_store[$itemName] = array();
+ $this->_endPoint = & $this->_store[$itemName];
+
+ return $this;
+ }
+
+ /**
+ * Specify the previously registered item as a literal value.
+ *
+ * {@link register()} must be called before this will work.
+ *
+ * @param mixed $value
+ *
+ * @return Swift_DependencyContainer
+ */
+ public function asValue($value)
+ {
+ $endPoint = & $this->_getEndPoint();
+ $endPoint['lookupType'] = self::TYPE_VALUE;
+ $endPoint['value'] = $value;
+
+ return $this;
+ }
+
+ /**
+ * Specify the previously registered item as an alias of another item.
+ *
+ * @param string $lookup
+ *
+ * @return Swift_DependencyContainer
+ */
+ public function asAliasOf($lookup)
+ {
+ $endPoint = & $this->_getEndPoint();
+ $endPoint['lookupType'] = self::TYPE_ALIAS;
+ $endPoint['ref'] = $lookup;
+
+ return $this;
+ }
+
+ /**
+ * Specify the previously registered item as a new instance of $className.
+ *
+ * {@link register()} must be called before this will work.
+ * Any arguments can be set with {@link withDependencies()},
+ * {@link addConstructorValue()} or {@link addConstructorLookup()}.
+ *
+ * @see withDependencies(), addConstructorValue(), addConstructorLookup()
+ *
+ * @param string $className
+ *
+ * @return Swift_DependencyContainer
+ */
+ public function asNewInstanceOf($className)
+ {
+ $endPoint = & $this->_getEndPoint();
+ $endPoint['lookupType'] = self::TYPE_INSTANCE;
+ $endPoint['className'] = $className;
+
+ return $this;
+ }
+
+ /**
+ * Specify the previously registered item as a shared instance of $className.
+ *
+ * {@link register()} must be called before this will work.
+ *
+ * @param string $className
+ *
+ * @return Swift_DependencyContainer
+ */
+ public function asSharedInstanceOf($className)
+ {
+ $endPoint = & $this->_getEndPoint();
+ $endPoint['lookupType'] = self::TYPE_SHARED;
+ $endPoint['className'] = $className;
+
+ return $this;
+ }
+
+ /**
+ * Specify a list of injected dependencies for the previously registered item.
+ *
+ * This method takes an array of lookup names.
+ *
+ * @see addConstructorValue(), addConstructorLookup()
+ *
+ * @param array $lookups
+ *
+ * @return Swift_DependencyContainer
+ */
+ public function withDependencies(array $lookups)
+ {
+ $endPoint = & $this->_getEndPoint();
+ $endPoint['args'] = array();
+ foreach ($lookups as $lookup) {
+ $this->addConstructorLookup($lookup);
+ }
+
+ return $this;
+ }
+
+ /**
+ * Specify a literal (non looked up) value for the constructor of the
+ * previously registered item.
+ *
+ * @see withDependencies(), addConstructorLookup()
+ *
+ * @param mixed $value
+ *
+ * @return Swift_DependencyContainer
+ */
+ public function addConstructorValue($value)
+ {
+ $endPoint = & $this->_getEndPoint();
+ if (!isset($endPoint['args'])) {
+ $endPoint['args'] = array();
+ }
+ $endPoint['args'][] = array('type' => 'value', 'item' => $value);
+
+ return $this;
+ }
+
+ /**
+ * Specify a dependency lookup for the constructor of the previously
+ * registered item.
+ *
+ * @see withDependencies(), addConstructorValue()
+ *
+ * @param string $lookup
+ *
+ * @return Swift_DependencyContainer
+ */
+ public function addConstructorLookup($lookup)
+ {
+ $endPoint = & $this->_getEndPoint();
+ if (!isset($this->_endPoint['args'])) {
+ $endPoint['args'] = array();
+ }
+ $endPoint['args'][] = array('type' => 'lookup', 'item' => $lookup);
+
+ return $this;
+ }
+
+ /** Get the literal value with $itemName */
+ private function _getValue($itemName)
+ {
+ return $this->_store[$itemName]['value'];
+ }
+
+ /** Resolve an alias to another item */
+ private function _createAlias($itemName)
+ {
+ return $this->lookup($this->_store[$itemName]['ref']);
+ }
+
+ /** Create a fresh instance of $itemName */
+ private function _createNewInstance($itemName)
+ {
+ $reflector = new ReflectionClass($this->_store[$itemName]['className']);
+ if ($reflector->getConstructor()) {
+ return $reflector->newInstanceArgs(
+ $this->createDependenciesFor($itemName)
+ );
+ } else {
+ return $reflector->newInstance();
+ }
+ }
+
+ /** Create and register a shared instance of $itemName */
+ private function _createSharedInstance($itemName)
+ {
+ if (!isset($this->_store[$itemName]['instance'])) {
+ $this->_store[$itemName]['instance'] = $this->_createNewInstance($itemName);
+ }
+
+ return $this->_store[$itemName]['instance'];
+ }
+
+ /** Get the current endpoint in the store */
+ private function &_getEndPoint()
+ {
+ if (!isset($this->_endPoint)) {
+ throw new BadMethodCallException(
+ 'Component must first be registered by calling register()'
+ );
+ }
+
+ return $this->_endPoint;
+ }
+
+ /** Get an argument list with dependencies resolved */
+ private function _resolveArgs(array $args)
+ {
+ $resolved = array();
+ foreach ($args as $argDefinition) {
+ switch ($argDefinition['type']) {
+ case 'lookup':
+ $resolved[] = $this->_lookupRecursive($argDefinition['item']);
+ break;
+ case 'value':
+ $resolved[] = $argDefinition['item'];
+ break;
+ }
+ }
+
+ return $resolved;
+ }
+
+ /** Resolve a single dependency with an collections */
+ private function _lookupRecursive($item)
+ {
+ if (is_array($item)) {
+ $collection = array();
+ foreach ($item as $k => $v) {
+ $collection[$k] = $this->_lookupRecursive($v);
+ }
+
+ return $collection;
+ } else {
+ return $this->lookup($item);
+ }
+ }
+}
diff --git a/vendor/swiftmailer/swiftmailer/lib/classes/Swift/DependencyException.php b/vendor/swiftmailer/swiftmailer/lib/classes/Swift/DependencyException.php
new file mode 100644
index 00000000..0a96232e
--- /dev/null
+++ b/vendor/swiftmailer/swiftmailer/lib/classes/Swift/DependencyException.php
@@ -0,0 +1,27 @@
+createDependenciesFor('mime.embeddedfile')
+ );
+
+ $this->setBody($data);
+ $this->setFilename($filename);
+ if ($contentType) {
+ $this->setContentType($contentType);
+ }
+ }
+
+ /**
+ * Create a new EmbeddedFile.
+ *
+ * @param string|Swift_OutputByteStream $data
+ * @param string $filename
+ * @param string $contentType
+ *
+ * @return Swift_Mime_EmbeddedFile
+ */
+ public static function newInstance($data = null, $filename = null, $contentType = null)
+ {
+ return new self($data, $filename, $contentType);
+ }
+
+ /**
+ * Create a new EmbeddedFile from a filesystem path.
+ *
+ * @param string $path
+ *
+ * @return Swift_Mime_EmbeddedFile
+ */
+ public static function fromPath($path)
+ {
+ return self::newInstance()->setFile(
+ new Swift_ByteStream_FileByteStream($path)
+ );
+ }
+}
diff --git a/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Encoder.php b/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Encoder.php
new file mode 100644
index 00000000..7c656424
--- /dev/null
+++ b/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Encoder.php
@@ -0,0 +1,27 @@
+= $maxLineLength || 76 < $maxLineLength) {
+ $maxLineLength = 76;
+ }
+
+ $encodedString = base64_encode($string);
+ $firstLine = '';
+
+ if (0 != $firstLineOffset) {
+ $firstLine = substr(
+ $encodedString, 0, $maxLineLength - $firstLineOffset
+ )."\r\n";
+ $encodedString = substr(
+ $encodedString, $maxLineLength - $firstLineOffset
+ );
+ }
+
+ return $firstLine.trim(chunk_split($encodedString, $maxLineLength, "\r\n"));
+ }
+
+ /**
+ * Does nothing.
+ */
+ public function charsetChanged($charset)
+ {
+ }
+}
diff --git a/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Encoder/QpEncoder.php b/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Encoder/QpEncoder.php
new file mode 100644
index 00000000..81836f77
--- /dev/null
+++ b/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Encoder/QpEncoder.php
@@ -0,0 +1,289 @@
+ '=00', 1 => '=01', 2 => '=02', 3 => '=03', 4 => '=04',
+ 5 => '=05', 6 => '=06', 7 => '=07', 8 => '=08', 9 => '=09',
+ 10 => '=0A', 11 => '=0B', 12 => '=0C', 13 => '=0D', 14 => '=0E',
+ 15 => '=0F', 16 => '=10', 17 => '=11', 18 => '=12', 19 => '=13',
+ 20 => '=14', 21 => '=15', 22 => '=16', 23 => '=17', 24 => '=18',
+ 25 => '=19', 26 => '=1A', 27 => '=1B', 28 => '=1C', 29 => '=1D',
+ 30 => '=1E', 31 => '=1F', 32 => '=20', 33 => '=21', 34 => '=22',
+ 35 => '=23', 36 => '=24', 37 => '=25', 38 => '=26', 39 => '=27',
+ 40 => '=28', 41 => '=29', 42 => '=2A', 43 => '=2B', 44 => '=2C',
+ 45 => '=2D', 46 => '=2E', 47 => '=2F', 48 => '=30', 49 => '=31',
+ 50 => '=32', 51 => '=33', 52 => '=34', 53 => '=35', 54 => '=36',
+ 55 => '=37', 56 => '=38', 57 => '=39', 58 => '=3A', 59 => '=3B',
+ 60 => '=3C', 61 => '=3D', 62 => '=3E', 63 => '=3F', 64 => '=40',
+ 65 => '=41', 66 => '=42', 67 => '=43', 68 => '=44', 69 => '=45',
+ 70 => '=46', 71 => '=47', 72 => '=48', 73 => '=49', 74 => '=4A',
+ 75 => '=4B', 76 => '=4C', 77 => '=4D', 78 => '=4E', 79 => '=4F',
+ 80 => '=50', 81 => '=51', 82 => '=52', 83 => '=53', 84 => '=54',
+ 85 => '=55', 86 => '=56', 87 => '=57', 88 => '=58', 89 => '=59',
+ 90 => '=5A', 91 => '=5B', 92 => '=5C', 93 => '=5D', 94 => '=5E',
+ 95 => '=5F', 96 => '=60', 97 => '=61', 98 => '=62', 99 => '=63',
+ 100 => '=64', 101 => '=65', 102 => '=66', 103 => '=67', 104 => '=68',
+ 105 => '=69', 106 => '=6A', 107 => '=6B', 108 => '=6C', 109 => '=6D',
+ 110 => '=6E', 111 => '=6F', 112 => '=70', 113 => '=71', 114 => '=72',
+ 115 => '=73', 116 => '=74', 117 => '=75', 118 => '=76', 119 => '=77',
+ 120 => '=78', 121 => '=79', 122 => '=7A', 123 => '=7B', 124 => '=7C',
+ 125 => '=7D', 126 => '=7E', 127 => '=7F', 128 => '=80', 129 => '=81',
+ 130 => '=82', 131 => '=83', 132 => '=84', 133 => '=85', 134 => '=86',
+ 135 => '=87', 136 => '=88', 137 => '=89', 138 => '=8A', 139 => '=8B',
+ 140 => '=8C', 141 => '=8D', 142 => '=8E', 143 => '=8F', 144 => '=90',
+ 145 => '=91', 146 => '=92', 147 => '=93', 148 => '=94', 149 => '=95',
+ 150 => '=96', 151 => '=97', 152 => '=98', 153 => '=99', 154 => '=9A',
+ 155 => '=9B', 156 => '=9C', 157 => '=9D', 158 => '=9E', 159 => '=9F',
+ 160 => '=A0', 161 => '=A1', 162 => '=A2', 163 => '=A3', 164 => '=A4',
+ 165 => '=A5', 166 => '=A6', 167 => '=A7', 168 => '=A8', 169 => '=A9',
+ 170 => '=AA', 171 => '=AB', 172 => '=AC', 173 => '=AD', 174 => '=AE',
+ 175 => '=AF', 176 => '=B0', 177 => '=B1', 178 => '=B2', 179 => '=B3',
+ 180 => '=B4', 181 => '=B5', 182 => '=B6', 183 => '=B7', 184 => '=B8',
+ 185 => '=B9', 186 => '=BA', 187 => '=BB', 188 => '=BC', 189 => '=BD',
+ 190 => '=BE', 191 => '=BF', 192 => '=C0', 193 => '=C1', 194 => '=C2',
+ 195 => '=C3', 196 => '=C4', 197 => '=C5', 198 => '=C6', 199 => '=C7',
+ 200 => '=C8', 201 => '=C9', 202 => '=CA', 203 => '=CB', 204 => '=CC',
+ 205 => '=CD', 206 => '=CE', 207 => '=CF', 208 => '=D0', 209 => '=D1',
+ 210 => '=D2', 211 => '=D3', 212 => '=D4', 213 => '=D5', 214 => '=D6',
+ 215 => '=D7', 216 => '=D8', 217 => '=D9', 218 => '=DA', 219 => '=DB',
+ 220 => '=DC', 221 => '=DD', 222 => '=DE', 223 => '=DF', 224 => '=E0',
+ 225 => '=E1', 226 => '=E2', 227 => '=E3', 228 => '=E4', 229 => '=E5',
+ 230 => '=E6', 231 => '=E7', 232 => '=E8', 233 => '=E9', 234 => '=EA',
+ 235 => '=EB', 236 => '=EC', 237 => '=ED', 238 => '=EE', 239 => '=EF',
+ 240 => '=F0', 241 => '=F1', 242 => '=F2', 243 => '=F3', 244 => '=F4',
+ 245 => '=F5', 246 => '=F6', 247 => '=F7', 248 => '=F8', 249 => '=F9',
+ 250 => '=FA', 251 => '=FB', 252 => '=FC', 253 => '=FD', 254 => '=FE',
+ 255 => '=FF',
+ );
+
+ protected static $_safeMapShare = array();
+
+ /**
+ * A map of non-encoded ascii characters.
+ *
+ * @var string[]
+ */
+ protected $_safeMap = array();
+
+ /**
+ * Creates a new QpEncoder for the given CharacterStream.
+ *
+ * @param Swift_CharacterStream $charStream to use for reading characters
+ * @param Swift_StreamFilter $filter if input should be canonicalized
+ */
+ public function __construct(Swift_CharacterStream $charStream, Swift_StreamFilter $filter = null)
+ {
+ $this->_charStream = $charStream;
+ if (!isset(self::$_safeMapShare[$this->getSafeMapShareId()])) {
+ $this->initSafeMap();
+ self::$_safeMapShare[$this->getSafeMapShareId()] = $this->_safeMap;
+ } else {
+ $this->_safeMap = self::$_safeMapShare[$this->getSafeMapShareId()];
+ }
+ $this->_filter = $filter;
+ }
+
+ public function __sleep()
+ {
+ return array('_charStream', '_filter');
+ }
+
+ public function __wakeup()
+ {
+ if (!isset(self::$_safeMapShare[$this->getSafeMapShareId()])) {
+ $this->initSafeMap();
+ self::$_safeMapShare[$this->getSafeMapShareId()] = $this->_safeMap;
+ } else {
+ $this->_safeMap = self::$_safeMapShare[$this->getSafeMapShareId()];
+ }
+ }
+
+ protected function getSafeMapShareId()
+ {
+ return get_class($this);
+ }
+
+ protected function initSafeMap()
+ {
+ foreach (array_merge(
+ array(0x09, 0x20), range(0x21, 0x3C), range(0x3E, 0x7E)) as $byte) {
+ $this->_safeMap[$byte] = chr($byte);
+ }
+ }
+
+ /**
+ * Takes an unencoded string and produces a QP encoded string from it.
+ *
+ * QP encoded strings have a maximum line length of 76 characters.
+ * If the first line needs to be shorter, indicate the difference with
+ * $firstLineOffset.
+ *
+ * @param string $string to encode
+ * @param int $firstLineOffset, optional
+ * @param int $maxLineLength, optional 0 indicates the default of 76 chars
+ *
+ * @return string
+ */
+ public function encodeString($string, $firstLineOffset = 0, $maxLineLength = 0)
+ {
+ if ($maxLineLength > 76 || $maxLineLength <= 0) {
+ $maxLineLength = 76;
+ }
+
+ $thisLineLength = $maxLineLength - $firstLineOffset;
+
+ $lines = array();
+ $lNo = 0;
+ $lines[$lNo] = '';
+ $currentLine = & $lines[$lNo++];
+ $size = $lineLen = 0;
+
+ $this->_charStream->flushContents();
+ $this->_charStream->importString($string);
+
+ // Fetching more than 4 chars at one is slower, as is fetching fewer bytes
+ // Conveniently 4 chars is the UTF-8 safe number since UTF-8 has up to 6
+ // bytes per char and (6 * 4 * 3 = 72 chars per line) * =NN is 3 bytes
+ while (false !== $bytes = $this->_nextSequence()) {
+ // If we're filtering the input
+ if (isset($this->_filter)) {
+ // If we can't filter because we need more bytes
+ while ($this->_filter->shouldBuffer($bytes)) {
+ // Then collect bytes into the buffer
+ if (false === $moreBytes = $this->_nextSequence(1)) {
+ break;
+ }
+
+ foreach ($moreBytes as $b) {
+ $bytes[] = $b;
+ }
+ }
+ // And filter them
+ $bytes = $this->_filter->filter($bytes);
+ }
+
+ $enc = $this->_encodeByteSequence($bytes, $size);
+ if ($currentLine && $lineLen+$size >= $thisLineLength) {
+ $lines[$lNo] = '';
+ $currentLine = & $lines[$lNo++];
+ $thisLineLength = $maxLineLength;
+ $lineLen = 0;
+ }
+ $lineLen += $size;
+ $currentLine .= $enc;
+ }
+
+ return $this->_standardize(implode("=\r\n", $lines));
+ }
+
+ /**
+ * Updates the charset used.
+ *
+ * @param string $charset
+ */
+ public function charsetChanged($charset)
+ {
+ $this->_charStream->setCharacterSet($charset);
+ }
+
+ /**
+ * Encode the given byte array into a verbatim QP form.
+ *
+ * @param integer[] $bytes
+ * @param int $size
+ *
+ * @return string
+ */
+ protected function _encodeByteSequence(array $bytes, &$size)
+ {
+ $ret = '';
+ $size = 0;
+ foreach ($bytes as $b) {
+ if (isset($this->_safeMap[$b])) {
+ $ret .= $this->_safeMap[$b];
+ ++$size;
+ } else {
+ $ret .= self::$_qpMap[$b];
+ $size += 3;
+ }
+ }
+
+ return $ret;
+ }
+
+ /**
+ * Get the next sequence of bytes to read from the char stream.
+ *
+ * @param int $size number of bytes to read
+ *
+ * @return integer[]
+ */
+ protected function _nextSequence($size = 4)
+ {
+ return $this->_charStream->readBytes($size);
+ }
+
+ /**
+ * Make sure CRLF is correct and HT/SPACE are in valid places.
+ *
+ * @param string $string
+ *
+ * @return string
+ */
+ protected function _standardize($string)
+ {
+ $string = str_replace(array("\t=0D=0A", " =0D=0A", "=0D=0A"),
+ array("=09\r\n", "=20\r\n", "\r\n"), $string
+ );
+ switch ($end = ord(substr($string, -1))) {
+ case 0x09:
+ case 0x20:
+ $string = substr_replace($string, self::$_qpMap[$end], -1);
+ }
+
+ return $string;
+ }
+
+ /**
+ * Make a deep copy of object
+ */
+ public function __clone()
+ {
+ $this->_charStream = clone $this->_charStream;
+ }
+}
diff --git a/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Encoder/Rfc2231Encoder.php b/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Encoder/Rfc2231Encoder.php
new file mode 100644
index 00000000..1a7e21eb
--- /dev/null
+++ b/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Encoder/Rfc2231Encoder.php
@@ -0,0 +1,92 @@
+_charStream = $charStream;
+ }
+
+ /**
+ * Takes an unencoded string and produces a string encoded according to
+ * RFC 2231 from it.
+ *
+ * @param string $string
+ * @param int $firstLineOffset
+ * @param int $maxLineLength optional, 0 indicates the default of 75 bytes
+ *
+ * @return string
+ */
+ public function encodeString($string, $firstLineOffset = 0, $maxLineLength = 0)
+ {
+ $lines = array();
+ $lineCount = 0;
+ $lines[] = '';
+ $currentLine = & $lines[$lineCount++];
+
+ if (0 >= $maxLineLength) {
+ $maxLineLength = 75;
+ }
+
+ $this->_charStream->flushContents();
+ $this->_charStream->importString($string);
+
+ $thisLineLength = $maxLineLength - $firstLineOffset;
+
+ while (false !== $char = $this->_charStream->read(4)) {
+ $encodedChar = rawurlencode($char);
+ if (0 != strlen($currentLine)
+ && strlen($currentLine.$encodedChar) > $thisLineLength) {
+ $lines[] = '';
+ $currentLine = & $lines[$lineCount++];
+ $thisLineLength = $maxLineLength;
+ }
+ $currentLine .= $encodedChar;
+ }
+
+ return implode("\r\n", $lines);
+ }
+
+ /**
+ * Updates the charset used.
+ *
+ * @param string $charset
+ */
+ public function charsetChanged($charset)
+ {
+ $this->_charStream->setCharacterSet($charset);
+ }
+
+ /**
+ * Make a deep copy of object
+ */
+ public function __clone()
+ {
+ $this->_charStream = clone $this->_charStream;
+ }
+}
diff --git a/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Encoding.php b/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Encoding.php
new file mode 100644
index 00000000..5cbb20fc
--- /dev/null
+++ b/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Encoding.php
@@ -0,0 +1,64 @@
+lookup($key);
+ }
+}
diff --git a/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Events/CommandEvent.php b/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Events/CommandEvent.php
new file mode 100644
index 00000000..670f4d3d
--- /dev/null
+++ b/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Events/CommandEvent.php
@@ -0,0 +1,65 @@
+_command = $command;
+ $this->_successCodes = $successCodes;
+ }
+
+ /**
+ * Get the command which was sent to the server.
+ *
+ * @return string
+ */
+ public function getCommand()
+ {
+ return $this->_command;
+ }
+
+ /**
+ * Get the numeric response codes which indicate success for this command.
+ *
+ * @return integer[]
+ */
+ public function getSuccessCodes()
+ {
+ return $this->_successCodes;
+ }
+}
diff --git a/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Events/CommandListener.php b/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Events/CommandListener.php
new file mode 100644
index 00000000..3465c8d6
--- /dev/null
+++ b/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Events/CommandListener.php
@@ -0,0 +1,24 @@
+_source = $source;
+ }
+
+ /**
+ * Get the source object of this event.
+ *
+ * @return object
+ */
+ public function getSource()
+ {
+ return $this->_source;
+ }
+
+ /**
+ * Prevent this Event from bubbling any further up the stack.
+ *
+ * @param bool $cancel, optional
+ */
+ public function cancelBubble($cancel = true)
+ {
+ $this->_bubbleCancelled = $cancel;
+ }
+
+ /**
+ * Returns true if this Event will not bubble any further up the stack.
+ *
+ * @return bool
+ */
+ public function bubbleCancelled()
+ {
+ return $this->_bubbleCancelled;
+ }
+}
diff --git a/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Events/ResponseEvent.php b/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Events/ResponseEvent.php
new file mode 100644
index 00000000..b0ac1a8f
--- /dev/null
+++ b/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Events/ResponseEvent.php
@@ -0,0 +1,65 @@
+_response = $response;
+ $this->_valid = $valid;
+ }
+
+ /**
+ * Get the response which was received from the server.
+ *
+ * @return string
+ */
+ public function getResponse()
+ {
+ return $this->_response;
+ }
+
+ /**
+ * Get the success status of this Event.
+ *
+ * @return bool
+ */
+ public function isValid()
+ {
+ return $this->_valid;
+ }
+}
diff --git a/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Events/ResponseListener.php b/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Events/ResponseListener.php
new file mode 100644
index 00000000..9629f1e5
--- /dev/null
+++ b/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Events/ResponseListener.php
@@ -0,0 +1,24 @@
+_message = $message;
+ $this->_result = self::RESULT_PENDING;
+ }
+
+ /**
+ * Get the Transport used to send the Message.
+ *
+ * @return Swift_Transport
+ */
+ public function getTransport()
+ {
+ return $this->getSource();
+ }
+
+ /**
+ * Get the Message being sent.
+ *
+ * @return Swift_Mime_Message
+ */
+ public function getMessage()
+ {
+ return $this->_message;
+ }
+
+ /**
+ * Set the array of addresses that failed in sending.
+ *
+ * @param array $recipients
+ */
+ public function setFailedRecipients($recipients)
+ {
+ $this->_failedRecipients = $recipients;
+ }
+
+ /**
+ * Get an recipient addresses which were not accepted for delivery.
+ *
+ * @return string[]
+ */
+ public function getFailedRecipients()
+ {
+ return $this->_failedRecipients;
+ }
+
+ /**
+ * Set the result of sending.
+ *
+ * @param int $result
+ */
+ public function setResult($result)
+ {
+ $this->_result = $result;
+ }
+
+ /**
+ * Get the result of this Event.
+ *
+ * The return value is a bitmask from
+ * {@see RESULT_PENDING, RESULT_SUCCESS, RESULT_TENTATIVE, RESULT_FAILED}
+ *
+ * @return int
+ */
+ public function getResult()
+ {
+ return $this->_result;
+ }
+}
diff --git a/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Events/SendListener.php b/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Events/SendListener.php
new file mode 100644
index 00000000..7d35f18e
--- /dev/null
+++ b/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Events/SendListener.php
@@ -0,0 +1,31 @@
+_eventMap = array(
+ 'Swift_Events_CommandEvent' => 'Swift_Events_CommandListener',
+ 'Swift_Events_ResponseEvent' => 'Swift_Events_ResponseListener',
+ 'Swift_Events_SendEvent' => 'Swift_Events_SendListener',
+ 'Swift_Events_TransportChangeEvent' => 'Swift_Events_TransportChangeListener',
+ 'Swift_Events_TransportExceptionEvent' => 'Swift_Events_TransportExceptionListener',
+ );
+ }
+
+ /**
+ * Create a new SendEvent for $source and $message.
+ *
+ * @param Swift_Transport $source
+ * @param Swift_Mime_Message
+ *
+ * @return Swift_Events_SendEvent
+ */
+ public function createSendEvent(Swift_Transport $source, Swift_Mime_Message $message)
+ {
+ return new Swift_Events_SendEvent($source, $message);
+ }
+
+ /**
+ * Create a new CommandEvent for $source and $command.
+ *
+ * @param Swift_Transport $source
+ * @param string $command That will be executed
+ * @param array $successCodes That are needed
+ *
+ * @return Swift_Events_CommandEvent
+ */
+ public function createCommandEvent(Swift_Transport $source, $command, $successCodes = array())
+ {
+ return new Swift_Events_CommandEvent($source, $command, $successCodes);
+ }
+
+ /**
+ * Create a new ResponseEvent for $source and $response.
+ *
+ * @param Swift_Transport $source
+ * @param string $response
+ * @param bool $valid If the response is valid
+ *
+ * @return Swift_Events_ResponseEvent
+ */
+ public function createResponseEvent(Swift_Transport $source, $response, $valid)
+ {
+ return new Swift_Events_ResponseEvent($source, $response, $valid);
+ }
+
+ /**
+ * Create a new TransportChangeEvent for $source.
+ *
+ * @param Swift_Transport $source
+ *
+ * @return Swift_Events_TransportChangeEvent
+ */
+ public function createTransportChangeEvent(Swift_Transport $source)
+ {
+ return new Swift_Events_TransportChangeEvent($source);
+ }
+
+ /**
+ * Create a new TransportExceptionEvent for $source.
+ *
+ * @param Swift_Transport $source
+ * @param Swift_TransportException $ex
+ *
+ * @return Swift_Events_TransportExceptionEvent
+ */
+ public function createTransportExceptionEvent(Swift_Transport $source, Swift_TransportException $ex)
+ {
+ return new Swift_Events_TransportExceptionEvent($source, $ex);
+ }
+
+ /**
+ * Bind an event listener to this dispatcher.
+ *
+ * @param Swift_Events_EventListener $listener
+ */
+ public function bindEventListener(Swift_Events_EventListener $listener)
+ {
+ foreach ($this->_listeners as $l) {
+ // Already loaded
+ if ($l === $listener) {
+ return;
+ }
+ }
+ $this->_listeners[] = $listener;
+ }
+
+ /**
+ * Dispatch the given Event to all suitable listeners.
+ *
+ * @param Swift_Events_EventObject $evt
+ * @param string $target method
+ */
+ public function dispatchEvent(Swift_Events_EventObject $evt, $target)
+ {
+ $this->_prepareBubbleQueue($evt);
+ $this->_bubble($evt, $target);
+ }
+
+ /** Queue listeners on a stack ready for $evt to be bubbled up it */
+ private function _prepareBubbleQueue(Swift_Events_EventObject $evt)
+ {
+ $this->_bubbleQueue = array();
+ $evtClass = get_class($evt);
+ foreach ($this->_listeners as $listener) {
+ if (array_key_exists($evtClass, $this->_eventMap)
+ && ($listener instanceof $this->_eventMap[$evtClass])) {
+ $this->_bubbleQueue[] = $listener;
+ }
+ }
+ }
+
+ /** Bubble $evt up the stack calling $target() on each listener */
+ private function _bubble(Swift_Events_EventObject $evt, $target)
+ {
+ if (!$evt->bubbleCancelled() && $listener = array_shift($this->_bubbleQueue)) {
+ $listener->$target($evt);
+ $this->_bubble($evt, $target);
+ }
+ }
+}
diff --git a/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Events/TransportChangeEvent.php b/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Events/TransportChangeEvent.php
new file mode 100644
index 00000000..23c82970
--- /dev/null
+++ b/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Events/TransportChangeEvent.php
@@ -0,0 +1,27 @@
+getSource();
+ }
+}
diff --git a/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Events/TransportChangeListener.php b/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Events/TransportChangeListener.php
new file mode 100644
index 00000000..0edfe377
--- /dev/null
+++ b/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Events/TransportChangeListener.php
@@ -0,0 +1,45 @@
+_exception = $ex;
+ }
+
+ /**
+ * Get the TransportException thrown.
+ *
+ * @return Swift_TransportException
+ */
+ public function getException()
+ {
+ return $this->_exception;
+ }
+}
diff --git a/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Events/TransportExceptionListener.php b/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Events/TransportExceptionListener.php
new file mode 100644
index 00000000..f153742c
--- /dev/null
+++ b/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Events/TransportExceptionListener.php
@@ -0,0 +1,24 @@
+createDependenciesFor('transport.failover')
+ );
+
+ $this->setTransports($transports);
+ }
+
+ /**
+ * Create a new FailoverTransport instance.
+ *
+ * @param Swift_Transport[] $transports
+ *
+ * @return Swift_FailoverTransport
+ */
+ public static function newInstance($transports = array())
+ {
+ return new self($transports);
+ }
+}
diff --git a/vendor/swiftmailer/swiftmailer/lib/classes/Swift/FileSpool.php b/vendor/swiftmailer/swiftmailer/lib/classes/Swift/FileSpool.php
new file mode 100644
index 00000000..b30f9f85
--- /dev/null
+++ b/vendor/swiftmailer/swiftmailer/lib/classes/Swift/FileSpool.php
@@ -0,0 +1,208 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+/**
+ * Stores Messages on the filesystem.
+ *
+ * @author Fabien Potencier
+ * @author Xavier De Cock
+ */
+class Swift_FileSpool extends Swift_ConfigurableSpool
+{
+ /** The spool directory */
+ private $_path;
+
+ /**
+ * File WriteRetry Limit
+ *
+ * @var int
+ */
+ private $_retryLimit = 10;
+
+ /**
+ * Create a new FileSpool.
+ *
+ * @param string $path
+ *
+ * @throws Swift_IoException
+ */
+ public function __construct($path)
+ {
+ $this->_path = $path;
+
+ if (!file_exists($this->_path)) {
+ if (!mkdir($this->_path, 0777, true)) {
+ throw new Swift_IoException('Unable to create Path ['.$this->_path.']');
+ }
+ }
+ }
+
+ /**
+ * Tests if this Spool mechanism has started.
+ *
+ * @return bool
+ */
+ public function isStarted()
+ {
+ return true;
+ }
+
+ /**
+ * Starts this Spool mechanism.
+ */
+ public function start()
+ {
+ }
+
+ /**
+ * Stops this Spool mechanism.
+ */
+ public function stop()
+ {
+ }
+
+ /**
+ * Allow to manage the enqueuing retry limit.
+ *
+ * Default, is ten and allows over 64^20 different fileNames
+ *
+ * @param int $limit
+ */
+ public function setRetryLimit($limit)
+ {
+ $this->_retryLimit = $limit;
+ }
+
+ /**
+ * Queues a message.
+ *
+ * @param Swift_Mime_Message $message The message to store
+ *
+ * @return bool
+ *
+ * @throws Swift_IoException
+ */
+ public function queueMessage(Swift_Mime_Message $message)
+ {
+ $ser = serialize($message);
+ $fileName = $this->_path.'/'.$this->getRandomString(10);
+ for ($i = 0; $i < $this->_retryLimit; ++$i) {
+ /* We try an exclusive creation of the file. This is an atomic operation, it avoid locking mechanism */
+ $fp = @fopen($fileName.'.message', 'x');
+ if (false !== $fp) {
+ if (false === fwrite($fp, $ser)) {
+ return false;
+ }
+
+ return fclose($fp);
+ } else {
+ /* The file already exists, we try a longer fileName */
+ $fileName .= $this->getRandomString(1);
+ }
+ }
+
+ throw new Swift_IoException('Unable to create a file for enqueuing Message');
+ }
+
+ /**
+ * Execute a recovery if for any reason a process is sending for too long.
+ *
+ * @param int $timeout in second Defaults is for very slow smtp responses
+ */
+ public function recover($timeout = 900)
+ {
+ foreach (new DirectoryIterator($this->_path) as $file) {
+ $file = $file->getRealPath();
+
+ if (substr($file, - 16) == '.message.sending') {
+ $lockedtime = filectime($file);
+ if ((time() - $lockedtime) > $timeout) {
+ rename($file, substr($file, 0, - 8));
+ }
+ }
+ }
+ }
+
+ /**
+ * Sends messages using the given transport instance.
+ *
+ * @param Swift_Transport $transport A transport instance
+ * @param string[] $failedRecipients An array of failures by-reference
+ *
+ * @return int The number of sent e-mail's
+ */
+ public function flushQueue(Swift_Transport $transport, &$failedRecipients = null)
+ {
+ $directoryIterator = new DirectoryIterator($this->_path);
+
+ /* Start the transport only if there are queued files to send */
+ if (!$transport->isStarted()) {
+ foreach ($directoryIterator as $file) {
+ if (substr($file->getRealPath(), -8) == '.message') {
+ $transport->start();
+ break;
+ }
+ }
+ }
+
+ $failedRecipients = (array) $failedRecipients;
+ $count = 0;
+ $time = time();
+ foreach ($directoryIterator as $file) {
+ $file = $file->getRealPath();
+
+ if (substr($file, -8) != '.message') {
+ continue;
+ }
+
+ /* We try a rename, it's an atomic operation, and avoid locking the file */
+ if (rename($file, $file.'.sending')) {
+ $message = unserialize(file_get_contents($file.'.sending'));
+
+ $count += $transport->send($message, $failedRecipients);
+
+ unlink($file.'.sending');
+ } else {
+ /* This message has just been catched by another process */
+ continue;
+ }
+
+ if ($this->getMessageLimit() && $count >= $this->getMessageLimit()) {
+ break;
+ }
+
+ if ($this->getTimeLimit() && (time() - $time) >= $this->getTimeLimit()) {
+ break;
+ }
+ }
+
+ return $count;
+ }
+
+ /**
+ * Returns a random string needed to generate a fileName for the queue.
+ *
+ * @param int $count
+ *
+ * @return string
+ */
+ protected function getRandomString($count)
+ {
+ // This string MUST stay FS safe, avoid special chars
+ $base = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_-.";
+ $ret = '';
+ $strlen = strlen($base);
+ for ($i = 0; $i < $count; ++$i) {
+ $ret .= $base[((int) rand(0, $strlen - 1))];
+ }
+
+ return $ret;
+ }
+}
diff --git a/vendor/swiftmailer/swiftmailer/lib/classes/Swift/FileStream.php b/vendor/swiftmailer/swiftmailer/lib/classes/Swift/FileStream.php
new file mode 100644
index 00000000..802cb430
--- /dev/null
+++ b/vendor/swiftmailer/swiftmailer/lib/classes/Swift/FileStream.php
@@ -0,0 +1,24 @@
+setFile(
+ new Swift_ByteStream_FileByteStream($path)
+ );
+
+ return $image;
+ }
+}
diff --git a/vendor/swiftmailer/swiftmailer/lib/classes/Swift/InputByteStream.php b/vendor/swiftmailer/swiftmailer/lib/classes/Swift/InputByteStream.php
new file mode 100644
index 00000000..fd45ab93
--- /dev/null
+++ b/vendor/swiftmailer/swiftmailer/lib/classes/Swift/InputByteStream.php
@@ -0,0 +1,75 @@
+_stream = $stream;
+ }
+
+ /**
+ * Set a string into the cache under $itemKey for the namespace $nsKey.
+ *
+ * @see MODE_WRITE, MODE_APPEND
+ *
+ * @param string $nsKey
+ * @param string $itemKey
+ * @param string $string
+ * @param int $mode
+ */
+ public function setString($nsKey, $itemKey, $string, $mode)
+ {
+ $this->_prepareCache($nsKey);
+ switch ($mode) {
+ case self::MODE_WRITE:
+ $this->_contents[$nsKey][$itemKey] = $string;
+ break;
+ case self::MODE_APPEND:
+ if (!$this->hasKey($nsKey, $itemKey)) {
+ $this->_contents[$nsKey][$itemKey] = '';
+ }
+ $this->_contents[$nsKey][$itemKey] .= $string;
+ break;
+ default:
+ throw new Swift_SwiftException(
+ 'Invalid mode ['.$mode.'] used to set nsKey='.
+ $nsKey.', itemKey='.$itemKey
+ );
+ }
+ }
+
+ /**
+ * Set a ByteStream into the cache under $itemKey for the namespace $nsKey.
+ *
+ * @see MODE_WRITE, MODE_APPEND
+ *
+ * @param string $nsKey
+ * @param string $itemKey
+ * @param Swift_OutputByteStream $os
+ * @param int $mode
+ */
+ public function importFromByteStream($nsKey, $itemKey, Swift_OutputByteStream $os, $mode)
+ {
+ $this->_prepareCache($nsKey);
+ switch ($mode) {
+ case self::MODE_WRITE:
+ $this->clearKey($nsKey, $itemKey);
+ case self::MODE_APPEND:
+ if (!$this->hasKey($nsKey, $itemKey)) {
+ $this->_contents[$nsKey][$itemKey] = '';
+ }
+ while (false !== $bytes = $os->read(8192)) {
+ $this->_contents[$nsKey][$itemKey] .= $bytes;
+ }
+ break;
+ default:
+ throw new Swift_SwiftException(
+ 'Invalid mode ['.$mode.'] used to set nsKey='.
+ $nsKey.', itemKey='.$itemKey
+ );
+ }
+ }
+
+ /**
+ * Provides a ByteStream which when written to, writes data to $itemKey.
+ *
+ * NOTE: The stream will always write in append mode.
+ *
+ * @param string $nsKey
+ * @param string $itemKey
+ * @param Swift_InputByteStream $writeThrough
+ *
+ * @return Swift_InputByteStream
+ */
+ public function getInputByteStream($nsKey, $itemKey, Swift_InputByteStream $writeThrough = null)
+ {
+ $is = clone $this->_stream;
+ $is->setKeyCache($this);
+ $is->setNsKey($nsKey);
+ $is->setItemKey($itemKey);
+ if (isset($writeThrough)) {
+ $is->setWriteThroughStream($writeThrough);
+ }
+
+ return $is;
+ }
+
+ /**
+ * Get data back out of the cache as a string.
+ *
+ * @param string $nsKey
+ * @param string $itemKey
+ *
+ * @return string
+ */
+ public function getString($nsKey, $itemKey)
+ {
+ $this->_prepareCache($nsKey);
+ if ($this->hasKey($nsKey, $itemKey)) {
+ return $this->_contents[$nsKey][$itemKey];
+ }
+ }
+
+ /**
+ * Get data back out of the cache as a ByteStream.
+ *
+ * @param string $nsKey
+ * @param string $itemKey
+ * @param Swift_InputByteStream $is to write the data to
+ */
+ public function exportToByteStream($nsKey, $itemKey, Swift_InputByteStream $is)
+ {
+ $this->_prepareCache($nsKey);
+ $is->write($this->getString($nsKey, $itemKey));
+ }
+
+ /**
+ * Check if the given $itemKey exists in the namespace $nsKey.
+ *
+ * @param string $nsKey
+ * @param string $itemKey
+ *
+ * @return bool
+ */
+ public function hasKey($nsKey, $itemKey)
+ {
+ $this->_prepareCache($nsKey);
+
+ return array_key_exists($itemKey, $this->_contents[$nsKey]);
+ }
+
+ /**
+ * Clear data for $itemKey in the namespace $nsKey if it exists.
+ *
+ * @param string $nsKey
+ * @param string $itemKey
+ */
+ public function clearKey($nsKey, $itemKey)
+ {
+ unset($this->_contents[$nsKey][$itemKey]);
+ }
+
+ /**
+ * Clear all data in the namespace $nsKey if it exists.
+ *
+ * @param string $nsKey
+ */
+ public function clearAll($nsKey)
+ {
+ unset($this->_contents[$nsKey]);
+ }
+
+ /**
+ * Initialize the namespace of $nsKey if needed.
+ *
+ * @param string $nsKey
+ */
+ private function _prepareCache($nsKey)
+ {
+ if (!array_key_exists($nsKey, $this->_contents)) {
+ $this->_contents[$nsKey] = array();
+ }
+ }
+}
diff --git a/vendor/swiftmailer/swiftmailer/lib/classes/Swift/KeyCache/DiskKeyCache.php b/vendor/swiftmailer/swiftmailer/lib/classes/Swift/KeyCache/DiskKeyCache.php
new file mode 100644
index 00000000..5a709625
--- /dev/null
+++ b/vendor/swiftmailer/swiftmailer/lib/classes/Swift/KeyCache/DiskKeyCache.php
@@ -0,0 +1,324 @@
+_stream = $stream;
+ $this->_path = $path;
+
+ if (function_exists('get_magic_quotes_runtime') && @get_magic_quotes_runtime() == 1) {
+ $this->_quotes = true;
+ }
+ }
+
+ /**
+ * Set a string into the cache under $itemKey for the namespace $nsKey.
+ *
+ * @see MODE_WRITE, MODE_APPEND
+ *
+ * @param string $nsKey
+ * @param string $itemKey
+ * @param string $string
+ * @param int $mode
+ *
+ * @throws Swift_IoException
+ */
+ public function setString($nsKey, $itemKey, $string, $mode)
+ {
+ $this->_prepareCache($nsKey);
+ switch ($mode) {
+ case self::MODE_WRITE:
+ $fp = $this->_getHandle($nsKey, $itemKey, self::POSITION_START);
+ break;
+ case self::MODE_APPEND:
+ $fp = $this->_getHandle($nsKey, $itemKey, self::POSITION_END);
+ break;
+ default:
+ throw new Swift_SwiftException(
+ 'Invalid mode ['.$mode.'] used to set nsKey='.
+ $nsKey.', itemKey='.$itemKey
+ );
+ break;
+ }
+ fwrite($fp, $string);
+ $this->_freeHandle($nsKey, $itemKey);
+ }
+
+ /**
+ * Set a ByteStream into the cache under $itemKey for the namespace $nsKey.
+ *
+ * @see MODE_WRITE, MODE_APPEND
+ *
+ * @param string $nsKey
+ * @param string $itemKey
+ * @param Swift_OutputByteStream $os
+ * @param int $mode
+ *
+ * @throws Swift_IoException
+ */
+ public function importFromByteStream($nsKey, $itemKey, Swift_OutputByteStream $os, $mode)
+ {
+ $this->_prepareCache($nsKey);
+ switch ($mode) {
+ case self::MODE_WRITE:
+ $fp = $this->_getHandle($nsKey, $itemKey, self::POSITION_START);
+ break;
+ case self::MODE_APPEND:
+ $fp = $this->_getHandle($nsKey, $itemKey, self::POSITION_END);
+ break;
+ default:
+ throw new Swift_SwiftException(
+ 'Invalid mode ['.$mode.'] used to set nsKey='.
+ $nsKey.', itemKey='.$itemKey
+ );
+ break;
+ }
+ while (false !== $bytes = $os->read(8192)) {
+ fwrite($fp, $bytes);
+ }
+ $this->_freeHandle($nsKey, $itemKey);
+ }
+
+ /**
+ * Provides a ByteStream which when written to, writes data to $itemKey.
+ *
+ * NOTE: The stream will always write in append mode.
+ *
+ * @param string $nsKey
+ * @param string $itemKey
+ * @param Swift_InputByteStream $writeThrough
+ *
+ * @return Swift_InputByteStream
+ */
+ public function getInputByteStream($nsKey, $itemKey, Swift_InputByteStream $writeThrough = null)
+ {
+ $is = clone $this->_stream;
+ $is->setKeyCache($this);
+ $is->setNsKey($nsKey);
+ $is->setItemKey($itemKey);
+ if (isset($writeThrough)) {
+ $is->setWriteThroughStream($writeThrough);
+ }
+
+ return $is;
+ }
+
+ /**
+ * Get data back out of the cache as a string.
+ *
+ * @param string $nsKey
+ * @param string $itemKey
+ *
+ * @return string
+ *
+ * @throws Swift_IoException
+ */
+ public function getString($nsKey, $itemKey)
+ {
+ $this->_prepareCache($nsKey);
+ if ($this->hasKey($nsKey, $itemKey)) {
+ $fp = $this->_getHandle($nsKey, $itemKey, self::POSITION_START);
+ if ($this->_quotes) {
+ ini_set('magic_quotes_runtime', 0);
+ }
+ $str = '';
+ while (!feof($fp) && false !== $bytes = fread($fp, 8192)) {
+ $str .= $bytes;
+ }
+ if ($this->_quotes) {
+ ini_set('magic_quotes_runtime', 1);
+ }
+ $this->_freeHandle($nsKey, $itemKey);
+
+ return $str;
+ }
+ }
+
+ /**
+ * Get data back out of the cache as a ByteStream.
+ *
+ * @param string $nsKey
+ * @param string $itemKey
+ * @param Swift_InputByteStream $is to write the data to
+ */
+ public function exportToByteStream($nsKey, $itemKey, Swift_InputByteStream $is)
+ {
+ if ($this->hasKey($nsKey, $itemKey)) {
+ $fp = $this->_getHandle($nsKey, $itemKey, self::POSITION_START);
+ if ($this->_quotes) {
+ ini_set('magic_quotes_runtime', 0);
+ }
+ while (!feof($fp) && false !== $bytes = fread($fp, 8192)) {
+ $is->write($bytes);
+ }
+ if ($this->_quotes) {
+ ini_set('magic_quotes_runtime', 1);
+ }
+ $this->_freeHandle($nsKey, $itemKey);
+ }
+ }
+
+ /**
+ * Check if the given $itemKey exists in the namespace $nsKey.
+ *
+ * @param string $nsKey
+ * @param string $itemKey
+ *
+ * @return bool
+ */
+ public function hasKey($nsKey, $itemKey)
+ {
+ return is_file($this->_path.'/'.$nsKey.'/'.$itemKey);
+ }
+
+ /**
+ * Clear data for $itemKey in the namespace $nsKey if it exists.
+ *
+ * @param string $nsKey
+ * @param string $itemKey
+ */
+ public function clearKey($nsKey, $itemKey)
+ {
+ if ($this->hasKey($nsKey, $itemKey)) {
+ $this->_freeHandle($nsKey, $itemKey);
+ unlink($this->_path.'/'.$nsKey.'/'.$itemKey);
+ }
+ }
+
+ /**
+ * Clear all data in the namespace $nsKey if it exists.
+ *
+ * @param string $nsKey
+ */
+ public function clearAll($nsKey)
+ {
+ if (array_key_exists($nsKey, $this->_keys)) {
+ foreach ($this->_keys[$nsKey] as $itemKey => $null) {
+ $this->clearKey($nsKey, $itemKey);
+ }
+ if (is_dir($this->_path.'/'.$nsKey)) {
+ rmdir($this->_path.'/'.$nsKey);
+ }
+ unset($this->_keys[$nsKey]);
+ }
+ }
+
+ /**
+ * Initialize the namespace of $nsKey if needed.
+ *
+ * @param string $nsKey
+ */
+ private function _prepareCache($nsKey)
+ {
+ $cacheDir = $this->_path.'/'.$nsKey;
+ if (!is_dir($cacheDir)) {
+ if (!mkdir($cacheDir)) {
+ throw new Swift_IoException('Failed to create cache directory '.$cacheDir);
+ }
+ $this->_keys[$nsKey] = array();
+ }
+ }
+
+ /**
+ * Get a file handle on the cache item.
+ *
+ * @param string $nsKey
+ * @param string $itemKey
+ * @param int $position
+ *
+ * @return resource
+ */
+ private function _getHandle($nsKey, $itemKey, $position)
+ {
+ if (!isset($this->_keys[$nsKey][$itemKey])) {
+ $openMode = $this->hasKey($nsKey, $itemKey)
+ ? 'r+b'
+ : 'w+b'
+ ;
+ $fp = fopen($this->_path.'/'.$nsKey.'/'.$itemKey, $openMode);
+ $this->_keys[$nsKey][$itemKey] = $fp;
+ }
+ if (self::POSITION_START == $position) {
+ fseek($this->_keys[$nsKey][$itemKey], 0, SEEK_SET);
+ } elseif (self::POSITION_END == $position) {
+ fseek($this->_keys[$nsKey][$itemKey], 0, SEEK_END);
+ }
+
+ return $this->_keys[$nsKey][$itemKey];
+ }
+
+ private function _freeHandle($nsKey, $itemKey)
+ {
+ $fp = $this->_getHandle($nsKey, $itemKey, self::POSITION_CURRENT);
+ fclose($fp);
+ $this->_keys[$nsKey][$itemKey] = null;
+ }
+
+ /**
+ * Destructor.
+ */
+ public function __destruct()
+ {
+ foreach ($this->_keys as $nsKey => $null) {
+ $this->clearAll($nsKey);
+ }
+ }
+}
diff --git a/vendor/swiftmailer/swiftmailer/lib/classes/Swift/KeyCache/KeyCacheInputStream.php b/vendor/swiftmailer/swiftmailer/lib/classes/Swift/KeyCache/KeyCacheInputStream.php
new file mode 100644
index 00000000..76039d8a
--- /dev/null
+++ b/vendor/swiftmailer/swiftmailer/lib/classes/Swift/KeyCache/KeyCacheInputStream.php
@@ -0,0 +1,51 @@
+_keyCache = $keyCache;
+ }
+
+ /**
+ * Specify a stream to write through for each write().
+ *
+ * @param Swift_InputByteStream $is
+ */
+ public function setWriteThroughStream(Swift_InputByteStream $is)
+ {
+ $this->_writeThrough = $is;
+ }
+
+ /**
+ * Writes $bytes to the end of the stream.
+ *
+ * @param string $bytes
+ * @param Swift_InputByteStream $is optional
+ */
+ public function write($bytes, Swift_InputByteStream $is = null)
+ {
+ $this->_keyCache->setString(
+ $this->_nsKey, $this->_itemKey, $bytes, Swift_KeyCache::MODE_APPEND
+ );
+ if (isset($is)) {
+ $is->write($bytes);
+ }
+ if (isset($this->_writeThrough)) {
+ $this->_writeThrough->write($bytes);
+ }
+ }
+
+ /**
+ * Not used.
+ */
+ public function commit()
+ {
+ }
+
+ /**
+ * Not used.
+ */
+ public function bind(Swift_InputByteStream $is)
+ {
+ }
+
+ /**
+ * Not used.
+ */
+ public function unbind(Swift_InputByteStream $is)
+ {
+ }
+
+ /**
+ * Flush the contents of the stream (empty it) and set the internal pointer
+ * to the beginning.
+ */
+ public function flushBuffers()
+ {
+ $this->_keyCache->clearKey($this->_nsKey, $this->_itemKey);
+ }
+
+ /**
+ * Set the nsKey which will be written to.
+ *
+ * @param string $nsKey
+ */
+ public function setNsKey($nsKey)
+ {
+ $this->_nsKey = $nsKey;
+ }
+
+ /**
+ * Set the itemKey which will be written to.
+ *
+ * @param string $itemKey
+ */
+ public function setItemKey($itemKey)
+ {
+ $this->_itemKey = $itemKey;
+ }
+
+ /**
+ * Any implementation should be cloneable, allowing the clone to access a
+ * separate $nsKey and $itemKey.
+ */
+ public function __clone()
+ {
+ $this->_writeThrough = null;
+ }
+}
diff --git a/vendor/swiftmailer/swiftmailer/lib/classes/Swift/LoadBalancedTransport.php b/vendor/swiftmailer/swiftmailer/lib/classes/Swift/LoadBalancedTransport.php
new file mode 100644
index 00000000..6e1080b9
--- /dev/null
+++ b/vendor/swiftmailer/swiftmailer/lib/classes/Swift/LoadBalancedTransport.php
@@ -0,0 +1,45 @@
+createDependenciesFor('transport.loadbalanced')
+ );
+
+ $this->setTransports($transports);
+ }
+
+ /**
+ * Create a new LoadBalancedTransport instance.
+ *
+ * @param array $transports
+ *
+ * @return Swift_LoadBalancedTransport
+ */
+ public static function newInstance($transports = array())
+ {
+ return new self($transports);
+ }
+}
diff --git a/vendor/swiftmailer/swiftmailer/lib/classes/Swift/MailTransport.php b/vendor/swiftmailer/swiftmailer/lib/classes/Swift/MailTransport.php
new file mode 100644
index 00000000..a6d3340d
--- /dev/null
+++ b/vendor/swiftmailer/swiftmailer/lib/classes/Swift/MailTransport.php
@@ -0,0 +1,45 @@
+createDependenciesFor('transport.mail')
+ );
+
+ $this->setExtraParams($extraParams);
+ }
+
+ /**
+ * Create a new MailTransport instance.
+ *
+ * @param string $extraParams To be passed to mail()
+ *
+ * @return Swift_MailTransport
+ */
+ public static function newInstance($extraParams = '-f%s')
+ {
+ return new self($extraParams);
+ }
+}
diff --git a/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Mailer.php b/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Mailer.php
new file mode 100644
index 00000000..5677fcb4
--- /dev/null
+++ b/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Mailer.php
@@ -0,0 +1,114 @@
+_transport = $transport;
+ }
+
+ /**
+ * Create a new Mailer instance.
+ *
+ * @param Swift_Transport $transport
+ *
+ * @return Swift_Mailer
+ */
+ public static function newInstance(Swift_Transport $transport)
+ {
+ return new self($transport);
+ }
+
+ /**
+ * Create a new class instance of one of the message services.
+ *
+ * For example 'mimepart' would create a 'message.mimepart' instance
+ *
+ * @param string $service
+ *
+ * @return object
+ */
+ public function createMessage($service = 'message')
+ {
+ return Swift_DependencyContainer::getInstance()
+ ->lookup('message.'.$service);
+ }
+
+ /**
+ * Send the given Message like it would be sent in a mail client.
+ *
+ * All recipients (with the exception of Bcc) will be able to see the other
+ * recipients this message was sent to.
+ *
+ * Recipient/sender data will be retrieved from the Message object.
+ *
+ * The return value is the number of recipients who were accepted for
+ * delivery.
+ *
+ * @param Swift_Mime_Message $message
+ * @param array $failedRecipients An array of failures by-reference
+ *
+ * @return int
+ */
+ public function send(Swift_Mime_Message $message, &$failedRecipients = null)
+ {
+ $failedRecipients = (array) $failedRecipients;
+
+ if (!$this->_transport->isStarted()) {
+ $this->_transport->start();
+ }
+
+ $sent = 0;
+
+ try {
+ $sent = $this->_transport->send($message, $failedRecipients);
+ } catch (Swift_RfcComplianceException $e) {
+ foreach ($message->getTo() as $address => $name) {
+ $failedRecipients[] = $address;
+ }
+ }
+
+ return $sent;
+ }
+
+ /**
+ * Register a plugin using a known unique key (e.g. myPlugin).
+ *
+ * @param Swift_Events_EventListener $plugin
+ */
+ public function registerPlugin(Swift_Events_EventListener $plugin)
+ {
+ $this->_transport->registerPlugin($plugin);
+ }
+
+ /**
+ * The Transport used to send messages.
+ *
+ * @return Swift_Transport
+ */
+ public function getTransport()
+ {
+ return $this->_transport;
+ }
+}
diff --git a/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Mailer/ArrayRecipientIterator.php b/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Mailer/ArrayRecipientIterator.php
new file mode 100644
index 00000000..d02e1846
--- /dev/null
+++ b/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Mailer/ArrayRecipientIterator.php
@@ -0,0 +1,55 @@
+_recipients = $recipients;
+ }
+
+ /**
+ * Returns true only if there are more recipients to send to.
+ *
+ * @return bool
+ */
+ public function hasNext()
+ {
+ return !empty($this->_recipients);
+ }
+
+ /**
+ * Returns an array where the keys are the addresses of recipients and the
+ * values are the names. e.g. ('foo@bar' => 'Foo') or ('foo@bar' => NULL)
+ *
+ * @return array
+ */
+ public function nextRecipient()
+ {
+ return array_splice($this->_recipients, 0, 1);
+ }
+}
diff --git a/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Mailer/RecipientIterator.php b/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Mailer/RecipientIterator.php
new file mode 100644
index 00000000..a935c563
--- /dev/null
+++ b/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Mailer/RecipientIterator.php
@@ -0,0 +1,32 @@
+ 'Foo') or ('foo@bar' => NULL)
+ *
+ * @return array
+ */
+ public function nextRecipient();
+}
diff --git a/vendor/swiftmailer/swiftmailer/lib/classes/Swift/MemorySpool.php b/vendor/swiftmailer/swiftmailer/lib/classes/Swift/MemorySpool.php
new file mode 100644
index 00000000..590fc488
--- /dev/null
+++ b/vendor/swiftmailer/swiftmailer/lib/classes/Swift/MemorySpool.php
@@ -0,0 +1,84 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+/**
+ * Stores Messages in memory.
+ *
+ * @author Fabien Potencier
+ */
+class Swift_MemorySpool implements Swift_Spool
+{
+ protected $messages = array();
+
+ /**
+ * Tests if this Transport mechanism has started.
+ *
+ * @return bool
+ */
+ public function isStarted()
+ {
+ return true;
+ }
+
+ /**
+ * Starts this Transport mechanism.
+ */
+ public function start()
+ {
+ }
+
+ /**
+ * Stops this Transport mechanism.
+ */
+ public function stop()
+ {
+ }
+
+ /**
+ * Stores a message in the queue.
+ *
+ * @param Swift_Mime_Message $message The message to store
+ *
+ * @return bool Whether the operation has succeeded
+ */
+ public function queueMessage(Swift_Mime_Message $message)
+ {
+ //clone the message to make sure it is not changed while in the queue
+ $this->messages[] = clone $message;
+
+ return true;
+ }
+
+ /**
+ * Sends messages using the given transport instance.
+ *
+ * @param Swift_Transport $transport A transport instance
+ * @param string[] $failedRecipients An array of failures by-reference
+ *
+ * @return int The number of sent emails
+ */
+ public function flushQueue(Swift_Transport $transport, &$failedRecipients = null)
+ {
+ if (!$this->messages) {
+ return 0;
+ }
+
+ if (!$transport->isStarted()) {
+ $transport->start();
+ }
+
+ $count = 0;
+ while ($message = array_pop($this->messages)) {
+ $count += $transport->send($message, $failedRecipients);
+ }
+
+ return $count;
+ }
+}
diff --git a/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Message.php b/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Message.php
new file mode 100644
index 00000000..6887a075
--- /dev/null
+++ b/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Message.php
@@ -0,0 +1,287 @@
+createDependenciesFor('mime.message')
+ );
+
+ if (!isset($charset)) {
+ $charset = Swift_DependencyContainer::getInstance()
+ ->lookup('properties.charset');
+ }
+ $this->setSubject($subject);
+ $this->setBody($body);
+ $this->setCharset($charset);
+ if ($contentType) {
+ $this->setContentType($contentType);
+ }
+ }
+
+ /**
+ * Create a new Message.
+ *
+ * @param string $subject
+ * @param string $body
+ * @param string $contentType
+ * @param string $charset
+ *
+ * @return Swift_Message
+ */
+ public static function newInstance($subject = null, $body = null, $contentType = null, $charset = null)
+ {
+ return new self($subject, $body, $contentType, $charset);
+ }
+
+ /**
+ * Add a MimePart to this Message.
+ *
+ * @param string|Swift_OutputByteStream $body
+ * @param string $contentType
+ * @param string $charset
+ *
+ * @return Swift_Mime_SimpleMessage
+ */
+ public function addPart($body, $contentType = null, $charset = null)
+ {
+ return $this->attach(Swift_MimePart::newInstance(
+ $body, $contentType, $charset
+ ));
+ }
+
+ /**
+ * Attach a new signature handler to the message.
+ *
+ * @param Swift_Signer $signer
+ * @return Swift_Message
+ */
+ public function attachSigner(Swift_Signer $signer)
+ {
+ if ($signer instanceof Swift_Signers_HeaderSigner) {
+ $this->headerSigners[] = $signer;
+ } elseif ($signer instanceof Swift_Signers_BodySigner) {
+ $this->bodySigners[] = $signer;
+ }
+
+ return $this;
+ }
+
+ /**
+ * Attach a new signature handler to the message.
+ *
+ * @param Swift_Signer $signer
+ * @return Swift_Message
+ */
+ public function detachSigner(Swift_Signer $signer)
+ {
+ if ($signer instanceof Swift_Signers_HeaderSigner) {
+ foreach ($this->headerSigners as $k => $headerSigner) {
+ if ($headerSigner === $signer) {
+ unset($this->headerSigners[$k]);
+
+ return $this;
+ }
+ }
+ } elseif ($signer instanceof Swift_Signers_BodySigner) {
+ foreach ($this->bodySigners as $k => $bodySigner) {
+ if ($bodySigner === $signer) {
+ unset($this->bodySigners[$k]);
+
+ return $this;
+ }
+ }
+ }
+
+ return $this;
+ }
+
+ /**
+ * Get this message as a complete string.
+ *
+ * @return string
+ */
+ public function toString()
+ {
+ if (empty($this->headerSigners) && empty($this->bodySigners)) {
+ return parent::toString();
+ }
+
+ $this->saveMessage();
+
+ $this->doSign();
+
+ $string = parent::toString();
+
+ $this->restoreMessage();
+
+ return $string;
+ }
+
+ /**
+ * Write this message to a {@link Swift_InputByteStream}.
+ *
+ * @param Swift_InputByteStream $is
+ */
+ public function toByteStream(Swift_InputByteStream $is)
+ {
+ if (empty($this->headerSigners) && empty($this->bodySigners)) {
+ parent::toByteStream($is);
+
+ return;
+ }
+
+ $this->saveMessage();
+
+ $this->doSign();
+
+ parent::toByteStream($is);
+
+ $this->restoreMessage();
+ }
+
+ public function __wakeup()
+ {
+ Swift_DependencyContainer::getInstance()->createDependenciesFor('mime.message');
+ }
+
+ /**
+ * loops through signers and apply the signatures
+ */
+ protected function doSign()
+ {
+ foreach ($this->bodySigners as $signer) {
+ $altered = $signer->getAlteredHeaders();
+ $this->saveHeaders($altered);
+ $signer->signMessage($this);
+ }
+
+ foreach ($this->headerSigners as $signer) {
+ $altered = $signer->getAlteredHeaders();
+ $this->saveHeaders($altered);
+ $signer->reset();
+
+ $signer->setHeaders($this->getHeaders());
+
+ $signer->startBody();
+ $this->_bodyToByteStream($signer);
+ $signer->endBody();
+
+ $signer->addSignature($this->getHeaders());
+ }
+ }
+
+ /**
+ * save the message before any signature is applied
+ */
+ protected function saveMessage()
+ {
+ $this->savedMessage = array('headers' => array());
+ $this->savedMessage['body'] = $this->getBody();
+ $this->savedMessage['children'] = $this->getChildren();
+ if (count($this->savedMessage['children']) > 0 && $this->getBody() != '') {
+ $this->setChildren(array_merge(array($this->_becomeMimePart()), $this->savedMessage['children']));
+ $this->setBody('');
+ }
+ }
+
+ /**
+ * save the original headers
+ * @param array $altered
+ */
+ protected function saveHeaders(array $altered)
+ {
+ foreach ($altered as $head) {
+ $lc = strtolower($head);
+
+ if (!isset($this->savedMessage['headers'][$lc])) {
+ $this->savedMessage['headers'][$lc] = $this->getHeaders()->getAll($head);
+ }
+ }
+ }
+
+ /**
+ * Remove or restore altered headers
+ */
+ protected function restoreHeaders()
+ {
+ foreach ($this->savedMessage['headers'] as $name => $savedValue) {
+ $headers = $this->getHeaders()->getAll($name);
+
+ foreach ($headers as $key => $value) {
+ if (!isset($savedValue[$key])) {
+ $this->getHeaders()->remove($name, $key);
+ }
+ }
+ }
+ }
+
+ /**
+ * Restore message body
+ */
+ protected function restoreMessage()
+ {
+ $this->setBody($this->savedMessage['body']);
+ $this->setChildren($this->savedMessage['children']);
+
+ $this->restoreHeaders();
+ $this->savedMessage = array();
+ }
+
+ /**
+ * Clone Message Signers
+ * @see Swift_Mime_SimpleMimeEntity::__clone()
+ */
+ public function __clone()
+ {
+ parent::__clone();
+ foreach ($this->bodySigners as $key => $bodySigner) {
+ $this->bodySigners[$key] = clone($bodySigner);
+ }
+
+ foreach ($this->headerSigners as $key => $headerSigner) {
+ $this->headerSigners[$key] = clone($headerSigner);
+ }
+ }
+}
diff --git a/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Mime/Attachment.php b/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Mime/Attachment.php
new file mode 100644
index 00000000..d9d96529
--- /dev/null
+++ b/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Mime/Attachment.php
@@ -0,0 +1,153 @@
+setDisposition('attachment');
+ $this->setContentType('application/octet-stream');
+ $this->_mimeTypes = $mimeTypes;
+ }
+
+ /**
+ * Get the nesting level used for this attachment.
+ *
+ * Always returns {@link LEVEL_MIXED}.
+ *
+ * @return int
+ */
+ public function getNestingLevel()
+ {
+ return self::LEVEL_MIXED;
+ }
+
+ /**
+ * Get the Content-Disposition of this attachment.
+ *
+ * By default attachments have a disposition of "attachment".
+ *
+ * @return string
+ */
+ public function getDisposition()
+ {
+ return $this->_getHeaderFieldModel('Content-Disposition');
+ }
+
+ /**
+ * Set the Content-Disposition of this attachment.
+ *
+ * @param string $disposition
+ *
+ * @return Swift_Mime_Attachment
+ */
+ public function setDisposition($disposition)
+ {
+ if (!$this->_setHeaderFieldModel('Content-Disposition', $disposition)) {
+ $this->getHeaders()->addParameterizedHeader(
+ 'Content-Disposition', $disposition
+ );
+ }
+
+ return $this;
+ }
+
+ /**
+ * Get the filename of this attachment when downloaded.
+ *
+ * @return string
+ */
+ public function getFilename()
+ {
+ return $this->_getHeaderParameter('Content-Disposition', 'filename');
+ }
+
+ /**
+ * Set the filename of this attachment.
+ *
+ * @param string $filename
+ *
+ * @return Swift_Mime_Attachment
+ */
+ public function setFilename($filename)
+ {
+ $this->_setHeaderParameter('Content-Disposition', 'filename', $filename);
+ $this->_setHeaderParameter('Content-Type', 'name', $filename);
+
+ return $this;
+ }
+
+ /**
+ * Get the file size of this attachment.
+ *
+ * @return int
+ */
+ public function getSize()
+ {
+ return $this->_getHeaderParameter('Content-Disposition', 'size');
+ }
+
+ /**
+ * Set the file size of this attachment.
+ *
+ * @param int $size
+ *
+ * @return Swift_Mime_Attachment
+ */
+ public function setSize($size)
+ {
+ $this->_setHeaderParameter('Content-Disposition', 'size', $size);
+
+ return $this;
+ }
+
+ /**
+ * Set the file that this attachment is for.
+ *
+ * @param Swift_FileStream $file
+ * @param string $contentType optional
+ *
+ * @return Swift_Mime_Attachment
+ */
+ public function setFile(Swift_FileStream $file, $contentType = null)
+ {
+ $this->setFilename(basename($file->getPath()));
+ $this->setBody($file, $contentType);
+ if (!isset($contentType)) {
+ $extension = strtolower(substr(
+ $file->getPath(), strrpos($file->getPath(), '.') + 1
+ ));
+
+ if (array_key_exists($extension, $this->_mimeTypes)) {
+ $this->setContentType($this->_mimeTypes[$extension]);
+ }
+ }
+
+ return $this;
+ }
+}
diff --git a/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Mime/CharsetObserver.php b/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Mime/CharsetObserver.php
new file mode 100644
index 00000000..57d8bc46
--- /dev/null
+++ b/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Mime/CharsetObserver.php
@@ -0,0 +1,24 @@
+= $maxLineLength || 76 < $maxLineLength) {
+ $maxLineLength = 76;
+ }
+
+ $remainder = 0;
+
+ while (false !== $bytes = $os->read(8190)) {
+ $encoded = base64_encode($bytes);
+ $encodedTransformed = '';
+ $thisMaxLineLength = $maxLineLength - $remainder - $firstLineOffset;
+
+ while ($thisMaxLineLength < strlen($encoded)) {
+ $encodedTransformed .= substr($encoded, 0, $thisMaxLineLength)."\r\n";
+ $firstLineOffset = 0;
+ $encoded = substr($encoded, $thisMaxLineLength);
+ $thisMaxLineLength = $maxLineLength;
+ $remainder = 0;
+ }
+
+ if (0 < $remainingLength = strlen($encoded)) {
+ $remainder += $remainingLength;
+ $encodedTransformed .= $encoded;
+ $encoded = null;
+ }
+
+ $is->write($encodedTransformed);
+ }
+ }
+
+ /**
+ * Get the name of this encoding scheme.
+ * Returns the string 'base64'.
+ *
+ * @return string
+ */
+ public function getName()
+ {
+ return 'base64';
+ }
+}
diff --git a/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Mime/ContentEncoder/NativeQpContentEncoder.php b/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Mime/ContentEncoder/NativeQpContentEncoder.php
new file mode 100644
index 00000000..e97195a5
--- /dev/null
+++ b/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Mime/ContentEncoder/NativeQpContentEncoder.php
@@ -0,0 +1,123 @@
+charset = $charset ? $charset : 'utf-8';
+ }
+
+ /**
+ * Notify this observer that the entity's charset has changed.
+ *
+ * @param string $charset
+ */
+ public function charsetChanged($charset)
+ {
+ $this->charset = $charset;
+ }
+
+ /**
+ * Encode $in to $out.
+ *
+ * @param Swift_OutputByteStream $os to read from
+ * @param Swift_InputByteStream $is to write to
+ * @param int $firstLineOffset
+ * @param int $maxLineLength 0 indicates the default length for this encoding
+ *
+ * @throws RuntimeException
+ */
+ public function encodeByteStream(Swift_OutputByteStream $os, Swift_InputByteStream $is, $firstLineOffset = 0, $maxLineLength = 0)
+ {
+ if ($this->charset !== 'utf-8') {
+ throw new RuntimeException(
+ sprintf('Charset "%s" not supported. NativeQpContentEncoder only supports "utf-8"', $this->charset));
+ }
+
+ $string = '';
+
+ while (false !== $bytes = $os->read(8192)) {
+ $string .= $bytes;
+ }
+
+ $is->write($this->encodeString($string));
+ }
+
+ /**
+ * Get the MIME name of this content encoding scheme.
+ *
+ * @return string
+ */
+ public function getName()
+ {
+ return 'quoted-printable';
+ }
+
+ /**
+ * Encode a given string to produce an encoded string.
+ *
+ * @param string $string
+ * @param int $firstLineOffset if first line needs to be shorter
+ * @param int $maxLineLength 0 indicates the default length for this encoding
+ *
+ * @return string
+ *
+ * @throws RuntimeException
+ */
+ public function encodeString($string, $firstLineOffset = 0, $maxLineLength = 0)
+ {
+ if ($this->charset !== 'utf-8') {
+ throw new RuntimeException(
+ sprintf('Charset "%s" not supported. NativeQpContentEncoder only supports "utf-8"', $this->charset));
+ }
+
+ return $this->_standardize(quoted_printable_encode($string));
+ }
+
+ /**
+ * Make sure CRLF is correct and HT/SPACE are in valid places.
+ *
+ * @param string $string
+ *
+ * @return string
+ */
+ protected function _standardize($string)
+ {
+ // transform CR or LF to CRLF
+ $string = preg_replace('~=0D(?!=0A)|(?_name = $name;
+ $this->_canonical = $canonical;
+ }
+
+ /**
+ * Encode a given string to produce an encoded string.
+ *
+ * @param string $string
+ * @param int $firstLineOffset ignored
+ * @param int $maxLineLength - 0 means no wrapping will occur
+ *
+ * @return string
+ */
+ public function encodeString($string, $firstLineOffset = 0, $maxLineLength = 0)
+ {
+ if ($this->_canonical) {
+ $string = $this->_canonicalize($string);
+ }
+
+ return $this->_safeWordWrap($string, $maxLineLength, "\r\n");
+ }
+
+ /**
+ * Encode stream $in to stream $out.
+ *
+ * @param Swift_OutputByteStream $os
+ * @param Swift_InputByteStream $is
+ * @param int $firstLineOffset ignored
+ * @param int $maxLineLength optional, 0 means no wrapping will occur
+ */
+ public function encodeByteStream(Swift_OutputByteStream $os, Swift_InputByteStream $is, $firstLineOffset = 0, $maxLineLength = 0)
+ {
+ $leftOver = '';
+ while (false !== $bytes = $os->read(8192)) {
+ $toencode = $leftOver.$bytes;
+ if ($this->_canonical) {
+ $toencode = $this->_canonicalize($toencode);
+ }
+ $wrapped = $this->_safeWordWrap($toencode, $maxLineLength, "\r\n");
+ $lastLinePos = strrpos($wrapped, "\r\n");
+ $leftOver = substr($wrapped, $lastLinePos);
+ $wrapped = substr($wrapped, 0, $lastLinePos);
+
+ $is->write($wrapped);
+ }
+ if (strlen($leftOver)) {
+ $is->write($leftOver);
+ }
+ }
+
+ /**
+ * Get the name of this encoding scheme.
+ *
+ * @return string
+ */
+ public function getName()
+ {
+ return $this->_name;
+ }
+
+ /**
+ * Not used.
+ */
+ public function charsetChanged($charset)
+ {
+ }
+
+ /**
+ * A safer (but weaker) wordwrap for unicode.
+ *
+ * @param string $string
+ * @param int $length
+ * @param string $le
+ *
+ * @return string
+ */
+ private function _safeWordwrap($string, $length = 75, $le = "\r\n")
+ {
+ if (0 >= $length) {
+ return $string;
+ }
+
+ $originalLines = explode($le, $string);
+
+ $lines = array();
+ $lineCount = 0;
+
+ foreach ($originalLines as $originalLine) {
+ $lines[] = '';
+ $currentLine = & $lines[$lineCount++];
+
+ //$chunks = preg_split('/(?<=[\ \t,\.!\?\-&\+\/])/', $originalLine);
+ $chunks = preg_split('/(?<=\s)/', $originalLine);
+
+ foreach ($chunks as $chunk) {
+ if (0 != strlen($currentLine)
+ && strlen($currentLine.$chunk) > $length) {
+ $lines[] = '';
+ $currentLine = & $lines[$lineCount++];
+ }
+ $currentLine .= $chunk;
+ }
+ }
+
+ return implode("\r\n", $lines);
+ }
+
+ /**
+ * Canonicalize string input (fix CRLF).
+ *
+ * @param string $string
+ *
+ * @return string
+ */
+ private function _canonicalize($string)
+ {
+ return str_replace(
+ array("\r\n", "\r", "\n"),
+ array("\n", "\n", "\r\n"),
+ $string
+ );
+ }
+}
diff --git a/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Mime/ContentEncoder/QpContentEncoder.php b/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Mime/ContentEncoder/QpContentEncoder.php
new file mode 100644
index 00000000..58f05a10
--- /dev/null
+++ b/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Mime/ContentEncoder/QpContentEncoder.php
@@ -0,0 +1,123 @@
+_dotEscape = $dotEscape;
+ parent::__construct($charStream, $filter);
+ }
+
+ public function __sleep()
+ {
+ return array('_charStream', '_filter', '_dotEscape');
+ }
+
+ protected function getSafeMapShareId()
+ {
+ return get_class($this).($this->_dotEscape ? '.dotEscape' : '');
+ }
+
+ protected function initSafeMap()
+ {
+ parent::initSafeMap();
+ if ($this->_dotEscape) {
+ /* Encode . as =2e for buggy remote servers */
+ unset($this->_safeMap[0x2e]);
+ }
+ }
+
+ /**
+ * Encode stream $in to stream $out.
+ *
+ * QP encoded strings have a maximum line length of 76 characters.
+ * If the first line needs to be shorter, indicate the difference with
+ * $firstLineOffset.
+ *
+ * @param Swift_OutputByteStream $os output stream
+ * @param Swift_InputByteStream $is input stream
+ * @param int $firstLineOffset
+ * @param int $maxLineLength
+ */
+ public function encodeByteStream(Swift_OutputByteStream $os, Swift_InputByteStream $is, $firstLineOffset = 0, $maxLineLength = 0)
+ {
+ if ($maxLineLength > 76 || $maxLineLength <= 0) {
+ $maxLineLength = 76;
+ }
+
+ $thisLineLength = $maxLineLength - $firstLineOffset;
+
+ $this->_charStream->flushContents();
+ $this->_charStream->importByteStream($os);
+
+ $currentLine = '';
+ $prepend = '';
+ $size = $lineLen = 0;
+
+ while (false !== $bytes = $this->_nextSequence()) {
+ // If we're filtering the input
+ if (isset($this->_filter)) {
+ // If we can't filter because we need more bytes
+ while ($this->_filter->shouldBuffer($bytes)) {
+ // Then collect bytes into the buffer
+ if (false === $moreBytes = $this->_nextSequence(1)) {
+ break;
+ }
+
+ foreach ($moreBytes as $b) {
+ $bytes[] = $b;
+ }
+ }
+ // And filter them
+ $bytes = $this->_filter->filter($bytes);
+ }
+
+ $enc = $this->_encodeByteSequence($bytes, $size);
+ if ($currentLine && $lineLen+$size >= $thisLineLength) {
+ $is->write($prepend.$this->_standardize($currentLine));
+ $currentLine = '';
+ $prepend = "=\r\n";
+ $thisLineLength = $maxLineLength;
+ $lineLen = 0;
+ }
+ $lineLen += $size;
+ $currentLine .= $enc;
+ }
+ if (strlen($currentLine)) {
+ $is->write($prepend.$this->_standardize($currentLine));
+ }
+ }
+
+ /**
+ * Get the name of this encoding scheme.
+ * Returns the string 'quoted-printable'.
+ *
+ * @return string
+ */
+ public function getName()
+ {
+ return 'quoted-printable';
+ }
+}
diff --git a/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Mime/ContentEncoder/QpContentEncoderProxy.php b/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Mime/ContentEncoder/QpContentEncoderProxy.php
new file mode 100644
index 00000000..d6e8d7c3
--- /dev/null
+++ b/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Mime/ContentEncoder/QpContentEncoderProxy.php
@@ -0,0 +1,97 @@
+
+ */
+class Swift_Mime_ContentEncoder_QpContentEncoderProxy implements Swift_Mime_ContentEncoder
+{
+ /**
+ * @var Swift_Mime_ContentEncoder_QpContentEncoder
+ */
+ private $safeEncoder;
+
+ /**
+ * @var Swift_Mime_ContentEncoder_NativeQpContentEncoder
+ */
+ private $nativeEncoder;
+
+ /**
+ * @var null|string
+ */
+ private $charset;
+
+ /**
+ * Constructor.
+ *
+ * @param Swift_Mime_ContentEncoder_QpContentEncoder $safeEncoder
+ * @param Swift_Mime_ContentEncoder_NativeQpContentEncoder $nativeEncoder
+ * @param string|null $charset
+ */
+ public function __construct(Swift_Mime_ContentEncoder_QpContentEncoder $safeEncoder, Swift_Mime_ContentEncoder_NativeQpContentEncoder $nativeEncoder, $charset)
+ {
+ $this->safeEncoder = $safeEncoder;
+ $this->nativeEncoder = $nativeEncoder;
+ $this->charset = $charset;
+ }
+
+ /**
+ * Make a deep copy of object
+ */
+ public function __clone()
+ {
+ $this->safeEncoder = clone $this->safeEncoder;
+ $this->nativeEncoder = clone $this->nativeEncoder;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function charsetChanged($charset)
+ {
+ $this->charset = $charset;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function encodeByteStream(Swift_OutputByteStream $os, Swift_InputByteStream $is, $firstLineOffset = 0, $maxLineLength = 0)
+ {
+ $this->getEncoder()->encodeByteStream($os, $is, $firstLineOffset, $maxLineLength);
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function getName()
+ {
+ return 'quoted-printable';
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function encodeString($string, $firstLineOffset = 0, $maxLineLength = 0)
+ {
+ return $this->getEncoder()->encodeString($string, $firstLineOffset, $maxLineLength);
+ }
+
+ /**
+ * @return Swift_Mime_ContentEncoder
+ */
+ private function getEncoder()
+ {
+ return 'utf-8' === $this->charset ? $this->nativeEncoder : $this->safeEncoder;
+ }
+}
diff --git a/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Mime/ContentEncoder/RawContentEncoder.php b/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Mime/ContentEncoder/RawContentEncoder.php
new file mode 100644
index 00000000..f717dc78
--- /dev/null
+++ b/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Mime/ContentEncoder/RawContentEncoder.php
@@ -0,0 +1,63 @@
+
+ */
+class Swift_Mime_ContentEncoder_RawContentEncoder implements Swift_Mime_ContentEncoder
+{
+ /**
+ * Encode a given string to produce an encoded string.
+ *
+ * @param string $string
+ * @param int $firstLineOffset ignored
+ * @param int $maxLineLength ignored
+ * @return string
+ */
+ public function encodeString($string, $firstLineOffset = 0, $maxLineLength = 0)
+ {
+ return $string;
+ }
+
+ /**
+ * Encode stream $in to stream $out.
+ *
+ * @param Swift_OutputByteStream $in
+ * @param Swift_InputByteStream $out
+ * @param int $firstLineOffset ignored
+ * @param int $maxLineLength ignored
+ */
+ public function encodeByteStream(Swift_OutputByteStream $os, Swift_InputByteStream $is, $firstLineOffset = 0, $maxLineLength = 0)
+ {
+ while (false !== ($bytes = $os->read(8192))) {
+ $is->write($bytes);
+ }
+ }
+
+ /**
+ * Get the name of this encoding scheme.
+ *
+ * @return string
+ */
+ public function getName()
+ {
+ return 'raw';
+ }
+
+ /**
+ * Not used.
+ */
+ public function charsetChanged($charset)
+ {
+ }
+}
diff --git a/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Mime/EmbeddedFile.php b/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Mime/EmbeddedFile.php
new file mode 100644
index 00000000..ec1ef535
--- /dev/null
+++ b/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Mime/EmbeddedFile.php
@@ -0,0 +1,45 @@
+setDisposition('inline');
+ $this->setId($this->getId());
+ }
+
+ /**
+ * Get the nesting level of this EmbeddedFile.
+ *
+ * Returns {@see LEVEL_RELATED}.
+ *
+ * @return int
+ */
+ public function getNestingLevel()
+ {
+ return self::LEVEL_RELATED;
+ }
+}
diff --git a/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Mime/EncodingObserver.php b/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Mime/EncodingObserver.php
new file mode 100644
index 00000000..e262974b
--- /dev/null
+++ b/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Mime/EncodingObserver.php
@@ -0,0 +1,24 @@
+init();
+ }
+
+ public function __wakeup()
+ {
+ $this->init();
+ }
+
+ protected function init()
+ {
+ if (count(self::$_specials) > 0) {
+ return;
+ }
+
+ self::$_specials = array(
+ '(', ')', '<', '>', '[', ']',
+ ':', ';', '@', ',', '.', '"',
+ );
+
+ /*** Refer to RFC 2822 for ABNF grammar ***/
+
+ // All basic building blocks
+ self::$_grammar['NO-WS-CTL'] = '[\x01-\x08\x0B\x0C\x0E-\x19\x7F]';
+ self::$_grammar['WSP'] = '[ \t]';
+ self::$_grammar['CRLF'] = '(?:\r\n)';
+ self::$_grammar['FWS'] = '(?:(?:'.self::$_grammar['WSP'].'*'.
+ self::$_grammar['CRLF'].')?'.self::$_grammar['WSP'].')';
+ self::$_grammar['text'] = '[\x00-\x08\x0B\x0C\x0E-\x7F]';
+ self::$_grammar['quoted-pair'] = '(?:\\\\'.self::$_grammar['text'].')';
+ self::$_grammar['ctext'] = '(?:'.self::$_grammar['NO-WS-CTL'].
+ '|[\x21-\x27\x2A-\x5B\x5D-\x7E])';
+ // Uses recursive PCRE (?1) -- could be a weak point??
+ self::$_grammar['ccontent'] = '(?:'.self::$_grammar['ctext'].'|'.
+ self::$_grammar['quoted-pair'].'|(?1))';
+ self::$_grammar['comment'] = '(\((?:'.self::$_grammar['FWS'].'|'.
+ self::$_grammar['ccontent'].')*'.self::$_grammar['FWS'].'?\))';
+ self::$_grammar['CFWS'] = '(?:(?:'.self::$_grammar['FWS'].'?'.
+ self::$_grammar['comment'].')*(?:(?:'.self::$_grammar['FWS'].'?'.
+ self::$_grammar['comment'].')|'.self::$_grammar['FWS'].'))';
+ self::$_grammar['qtext'] = '(?:'.self::$_grammar['NO-WS-CTL'].
+ '|[\x21\x23-\x5B\x5D-\x7E])';
+ self::$_grammar['qcontent'] = '(?:'.self::$_grammar['qtext'].'|'.
+ self::$_grammar['quoted-pair'].')';
+ self::$_grammar['quoted-string'] = '(?:'.self::$_grammar['CFWS'].'?"'.
+ '('.self::$_grammar['FWS'].'?'.self::$_grammar['qcontent'].')*'.
+ self::$_grammar['FWS'].'?"'.self::$_grammar['CFWS'].'?)';
+ self::$_grammar['atext'] = '[a-zA-Z0-9!#\$%&\'\*\+\-\/=\?\^_`\{\}\|~]';
+ self::$_grammar['atom'] = '(?:'.self::$_grammar['CFWS'].'?'.
+ self::$_grammar['atext'].'+'.self::$_grammar['CFWS'].'?)';
+ self::$_grammar['dot-atom-text'] = '(?:'.self::$_grammar['atext'].'+'.
+ '(\.'.self::$_grammar['atext'].'+)*)';
+ self::$_grammar['dot-atom'] = '(?:'.self::$_grammar['CFWS'].'?'.
+ self::$_grammar['dot-atom-text'].'+'.self::$_grammar['CFWS'].'?)';
+ self::$_grammar['word'] = '(?:'.self::$_grammar['atom'].'|'.
+ self::$_grammar['quoted-string'].')';
+ self::$_grammar['phrase'] = '(?:'.self::$_grammar['word'].'+?)';
+ self::$_grammar['no-fold-quote'] = '(?:"(?:'.self::$_grammar['qtext'].
+ '|'.self::$_grammar['quoted-pair'].')*")';
+ self::$_grammar['dtext'] = '(?:'.self::$_grammar['NO-WS-CTL'].
+ '|[\x21-\x5A\x5E-\x7E])';
+ self::$_grammar['no-fold-literal'] = '(?:\[(?:'.self::$_grammar['dtext'].
+ '|'.self::$_grammar['quoted-pair'].')*\])';
+
+ // Message IDs
+ self::$_grammar['id-left'] = '(?:'.self::$_grammar['dot-atom-text'].'|'.
+ self::$_grammar['no-fold-quote'].')';
+ self::$_grammar['id-right'] = '(?:'.self::$_grammar['dot-atom-text'].'|'.
+ self::$_grammar['no-fold-literal'].')';
+
+ // Addresses, mailboxes and paths
+ self::$_grammar['local-part'] = '(?:'.self::$_grammar['dot-atom'].'|'.
+ self::$_grammar['quoted-string'].')';
+ self::$_grammar['dcontent'] = '(?:'.self::$_grammar['dtext'].'|'.
+ self::$_grammar['quoted-pair'].')';
+ self::$_grammar['domain-literal'] = '(?:'.self::$_grammar['CFWS'].'?\[('.
+ self::$_grammar['FWS'].'?'.self::$_grammar['dcontent'].')*?'.
+ self::$_grammar['FWS'].'?\]'.self::$_grammar['CFWS'].'?)';
+ self::$_grammar['domain'] = '(?:'.self::$_grammar['dot-atom'].'|'.
+ self::$_grammar['domain-literal'].')';
+ self::$_grammar['addr-spec'] = '(?:'.self::$_grammar['local-part'].'@'.
+ self::$_grammar['domain'].')';
+ }
+
+ /**
+ * Get the grammar defined for $name token.
+ *
+ * @param string $name exactly as written in the RFC
+ *
+ * @return string
+ */
+ public function getDefinition($name)
+ {
+ if (array_key_exists($name, self::$_grammar)) {
+ return self::$_grammar[$name];
+ } else {
+ throw new Swift_RfcComplianceException(
+ "No such grammar '".$name."' defined."
+ );
+ }
+ }
+
+ /**
+ * Returns the tokens defined in RFC 2822 (and some related RFCs).
+ *
+ * @return array
+ */
+ public function getGrammarDefinitions()
+ {
+ return self::$_grammar;
+ }
+
+ /**
+ * Returns the current special characters used in the syntax which need to be escaped.
+ *
+ * @return array
+ */
+ public function getSpecials()
+ {
+ return self::$_specials;
+ }
+
+ /**
+ * Escape special characters in a string (convert to quoted-pairs).
+ *
+ * @param string $token
+ * @param string[] $include additional chars to escape
+ * @param string[] $exclude chars from escaping
+ *
+ * @return string
+ */
+ public function escapeSpecials($token, $include = array(), $exclude = array())
+ {
+ foreach (array_merge(array('\\'), array_diff(self::$_specials, $exclude), $include) as $char) {
+ $token = str_replace($char, '\\'.$char, $token);
+ }
+
+ return $token;
+ }
+}
diff --git a/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Mime/Header.php b/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Mime/Header.php
new file mode 100644
index 00000000..7074c4f6
--- /dev/null
+++ b/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Mime/Header.php
@@ -0,0 +1,93 @@
+getName(), "\r\n");
+ mb_internal_encoding($old);
+
+ return $newstring;
+ }
+
+ return parent::encodeString($string, $firstLineOffset, $maxLineLength);
+ }
+}
diff --git a/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Mime/HeaderEncoder/QpHeaderEncoder.php b/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Mime/HeaderEncoder/QpHeaderEncoder.php
new file mode 100644
index 00000000..dd8ff382
--- /dev/null
+++ b/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Mime/HeaderEncoder/QpHeaderEncoder.php
@@ -0,0 +1,65 @@
+_safeMap[$byte] = chr($byte);
+ }
+ }
+
+ /**
+ * Get the name of this encoding scheme.
+ *
+ * Returns the string 'Q'.
+ *
+ * @return string
+ */
+ public function getName()
+ {
+ return 'Q';
+ }
+
+ /**
+ * Takes an unencoded string and produces a QP encoded string from it.
+ *
+ * @param string $string string to encode
+ * @param int $firstLineOffset optional
+ * @param int $maxLineLength optional, 0 indicates the default of 76 chars
+ *
+ * @return string
+ */
+ public function encodeString($string, $firstLineOffset = 0, $maxLineLength = 0)
+ {
+ return str_replace(array(' ', '=20', "=\r\n"), array('_', '_', "\r\n"),
+ parent::encodeString($string, $firstLineOffset, $maxLineLength)
+ );
+ }
+}
diff --git a/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Mime/HeaderFactory.php b/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Mime/HeaderFactory.php
new file mode 100644
index 00000000..423cebcf
--- /dev/null
+++ b/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Mime/HeaderFactory.php
@@ -0,0 +1,78 @@
+setGrammar($grammar);
+ }
+
+ /**
+ * Set the character set used in this Header.
+ *
+ * @param string $charset
+ */
+ public function setCharset($charset)
+ {
+ $this->clearCachedValueIf($charset != $this->_charset);
+ $this->_charset = $charset;
+ if (isset($this->_encoder)) {
+ $this->_encoder->charsetChanged($charset);
+ }
+ }
+
+ /**
+ * Get the character set used in this Header.
+ *
+ * @return string
+ */
+ public function getCharset()
+ {
+ return $this->_charset;
+ }
+
+ /**
+ * Set the language used in this Header.
+ *
+ * For example, for US English, 'en-us'.
+ * This can be unspecified.
+ *
+ * @param string $lang
+ */
+ public function setLanguage($lang)
+ {
+ $this->clearCachedValueIf($this->_lang != $lang);
+ $this->_lang = $lang;
+ }
+
+ /**
+ * Get the language used in this Header.
+ *
+ * @return string
+ */
+ public function getLanguage()
+ {
+ return $this->_lang;
+ }
+
+ /**
+ * Set the encoder used for encoding the header.
+ *
+ * @param Swift_Mime_HeaderEncoder $encoder
+ */
+ public function setEncoder(Swift_Mime_HeaderEncoder $encoder)
+ {
+ $this->_encoder = $encoder;
+ $this->setCachedValue(null);
+ }
+
+ /**
+ * Get the encoder used for encoding this Header.
+ *
+ * @return Swift_Mime_HeaderEncoder
+ */
+ public function getEncoder()
+ {
+ return $this->_encoder;
+ }
+
+ /**
+ * Set the grammar used for the header.
+ *
+ * @param Swift_Mime_Grammar $grammar
+ */
+ public function setGrammar(Swift_Mime_Grammar $grammar)
+ {
+ $this->_grammar = $grammar;
+ $this->setCachedValue(null);
+ }
+
+ /**
+ * Get the grammar used for this Header.
+ *
+ * @return Swift_Mime_Grammar
+ */
+ public function getGrammar()
+ {
+ return $this->_grammar;
+ }
+
+ /**
+ * Get the name of this header (e.g. charset).
+ *
+ * @return string
+ */
+ public function getFieldName()
+ {
+ return $this->_name;
+ }
+
+ /**
+ * Set the maximum length of lines in the header (excluding EOL).
+ *
+ * @param int $lineLength
+ */
+ public function setMaxLineLength($lineLength)
+ {
+ $this->clearCachedValueIf($this->_lineLength != $lineLength);
+ $this->_lineLength = $lineLength;
+ }
+
+ /**
+ * Get the maximum permitted length of lines in this Header.
+ *
+ * @return int
+ */
+ public function getMaxLineLength()
+ {
+ return $this->_lineLength;
+ }
+
+ /**
+ * Get this Header rendered as a RFC 2822 compliant string.
+ *
+ * @return string
+ *
+ * @throws Swift_RfcComplianceException
+ */
+ public function toString()
+ {
+ return $this->_tokensToString($this->toTokens());
+ }
+
+ /**
+ * Returns a string representation of this object.
+ *
+ * @return string
+ *
+ * @see toString()
+ */
+ public function __toString()
+ {
+ return $this->toString();
+ }
+
+ // -- Points of extension
+
+ /**
+ * Set the name of this Header field.
+ *
+ * @param string $name
+ */
+ protected function setFieldName($name)
+ {
+ $this->_name = $name;
+ }
+
+ /**
+ * Produces a compliant, formatted RFC 2822 'phrase' based on the string given.
+ *
+ * @param Swift_Mime_Header $header
+ * @param string $string as displayed
+ * @param string $charset of the text
+ * @param Swift_Mime_HeaderEncoder $encoder
+ * @param bool $shorten the first line to make remove for header name
+ *
+ * @return string
+ */
+ protected function createPhrase(Swift_Mime_Header $header, $string, $charset, Swift_Mime_HeaderEncoder $encoder = null, $shorten = false)
+ {
+ // Treat token as exactly what was given
+ $phraseStr = $string;
+ // If it's not valid
+ if (!preg_match('/^'.$this->getGrammar()->getDefinition('phrase').'$/D', $phraseStr)) {
+ // .. but it is just ascii text, try escaping some characters
+ // and make it a quoted-string
+ if (preg_match('/^'.$this->getGrammar()->getDefinition('text').'*$/D', $phraseStr)) {
+ $phraseStr = $this->getGrammar()->escapeSpecials(
+ $phraseStr, array('"'), $this->getGrammar()->getSpecials()
+ );
+ $phraseStr = '"'.$phraseStr.'"';
+ } else {
+ // ... otherwise it needs encoding
+ // Determine space remaining on line if first line
+ if ($shorten) {
+ $usedLength = strlen($header->getFieldName().': ');
+ } else {
+ $usedLength = 0;
+ }
+ $phraseStr = $this->encodeWords($header, $string, $usedLength);
+ }
+ }
+
+ return $phraseStr;
+ }
+
+ /**
+ * Encode needed word tokens within a string of input.
+ *
+ * @param Swift_Mime_Header $header
+ * @param string $input
+ * @param string $usedLength optional
+ *
+ * @return string
+ */
+ protected function encodeWords(Swift_Mime_Header $header, $input, $usedLength = -1)
+ {
+ $value = '';
+
+ $tokens = $this->getEncodableWordTokens($input);
+
+ foreach ($tokens as $token) {
+ // See RFC 2822, Sect 2.2 (really 2.2 ??)
+ if ($this->tokenNeedsEncoding($token)) {
+ // Don't encode starting WSP
+ $firstChar = substr($token, 0, 1);
+ switch ($firstChar) {
+ case ' ':
+ case "\t":
+ $value .= $firstChar;
+ $token = substr($token, 1);
+ }
+
+ if (-1 == $usedLength) {
+ $usedLength = strlen($header->getFieldName().': ') + strlen($value);
+ }
+ $value .= $this->getTokenAsEncodedWord($token, $usedLength);
+
+ $header->setMaxLineLength(76); // Forcefully override
+ } else {
+ $value .= $token;
+ }
+ }
+
+ return $value;
+ }
+
+ /**
+ * Test if a token needs to be encoded or not.
+ *
+ * @param string $token
+ *
+ * @return bool
+ */
+ protected function tokenNeedsEncoding($token)
+ {
+ return preg_match('~[\x00-\x08\x10-\x19\x7F-\xFF\r\n]~', $token);
+ }
+
+ /**
+ * Splits a string into tokens in blocks of words which can be encoded quickly.
+ *
+ * @param string $string
+ *
+ * @return string[]
+ */
+ protected function getEncodableWordTokens($string)
+ {
+ $tokens = array();
+
+ $encodedToken = '';
+ // Split at all whitespace boundaries
+ foreach (preg_split('~(?=[\t ])~', $string) as $token) {
+ if ($this->tokenNeedsEncoding($token)) {
+ $encodedToken .= $token;
+ } else {
+ if (strlen($encodedToken) > 0) {
+ $tokens[] = $encodedToken;
+ $encodedToken = '';
+ }
+ $tokens[] = $token;
+ }
+ }
+ if (strlen($encodedToken)) {
+ $tokens[] = $encodedToken;
+ }
+
+ return $tokens;
+ }
+
+ /**
+ * Get a token as an encoded word for safe insertion into headers.
+ *
+ * @param string $token token to encode
+ * @param int $firstLineOffset optional
+ *
+ * @return string
+ */
+ protected function getTokenAsEncodedWord($token, $firstLineOffset = 0)
+ {
+ // Adjust $firstLineOffset to account for space needed for syntax
+ $charsetDecl = $this->_charset;
+ if (isset($this->_lang)) {
+ $charsetDecl .= '*'.$this->_lang;
+ }
+ $encodingWrapperLength = strlen(
+ '=?'.$charsetDecl.'?'.$this->_encoder->getName().'??='
+ );
+
+ if ($firstLineOffset >= 75) {
+ //Does this logic need to be here?
+ $firstLineOffset = 0;
+ }
+
+ $encodedTextLines = explode("\r\n",
+ $this->_encoder->encodeString(
+ $token, $firstLineOffset, 75 - $encodingWrapperLength, $this->_charset
+ )
+ );
+
+ if (strtolower($this->_charset) !== 'iso-2022-jp') {
+ // special encoding for iso-2022-jp using mb_encode_mimeheader
+ foreach ($encodedTextLines as $lineNum => $line) {
+ $encodedTextLines[$lineNum] = '=?'.$charsetDecl.
+ '?'.$this->_encoder->getName().
+ '?'.$line.'?=';
+ }
+ }
+
+ return implode("\r\n ", $encodedTextLines);
+ }
+
+ /**
+ * Generates tokens from the given string which include CRLF as individual tokens.
+ *
+ * @param string $token
+ *
+ * @return string[]
+ */
+ protected function generateTokenLines($token)
+ {
+ return preg_split('~(\r\n)~', $token, -1, PREG_SPLIT_DELIM_CAPTURE);
+ }
+
+ /**
+ * Set a value into the cache.
+ *
+ * @param string $value
+ */
+ protected function setCachedValue($value)
+ {
+ $this->_cachedValue = $value;
+ }
+
+ /**
+ * Get the value in the cache.
+ *
+ * @return string
+ */
+ protected function getCachedValue()
+ {
+ return $this->_cachedValue;
+ }
+
+ /**
+ * Clear the cached value if $condition is met.
+ *
+ * @param bool $condition
+ */
+ protected function clearCachedValueIf($condition)
+ {
+ if ($condition) {
+ $this->setCachedValue(null);
+ }
+ }
+
+ /**
+ * Generate a list of all tokens in the final header.
+ *
+ * @param string $string The string to tokenize
+ *
+ * @return array An array of tokens as strings
+ */
+ protected function toTokens($string = null)
+ {
+ if (is_null($string)) {
+ $string = $this->getFieldBody();
+ }
+
+ $tokens = array();
+
+ // Generate atoms; split at all invisible boundaries followed by WSP
+ foreach (preg_split('~(?=[ \t])~', $string) as $token) {
+ $newTokens = $this->generateTokenLines($token);
+ foreach ($newTokens as $newToken) {
+ $tokens[] = $newToken;
+ }
+ }
+
+ return $tokens;
+ }
+
+ /**
+ * Takes an array of tokens which appear in the header and turns them into
+ * an RFC 2822 compliant string, adding FWSP where needed.
+ *
+ * @param string[] $tokens
+ *
+ * @return string
+ */
+ private function _tokensToString(array $tokens)
+ {
+ $lineCount = 0;
+ $headerLines = array();
+ $headerLines[] = $this->_name.': ';
+ $currentLine = & $headerLines[$lineCount++];
+
+ // Build all tokens back into compliant header
+ foreach ($tokens as $i => $token) {
+ // Line longer than specified maximum or token was just a new line
+ if (("\r\n" == $token) ||
+ ($i > 0 && strlen($currentLine.$token) > $this->_lineLength)
+ && 0 < strlen($currentLine)) {
+ $headerLines[] = '';
+ $currentLine = & $headerLines[$lineCount++];
+ }
+
+ // Append token to the line
+ if ("\r\n" != $token) {
+ $currentLine .= $token;
+ }
+ }
+
+ // Implode with FWS (RFC 2822, 2.2.3)
+ return implode("\r\n", $headerLines)."\r\n";
+ }
+}
diff --git a/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Mime/Headers/DateHeader.php b/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Mime/Headers/DateHeader.php
new file mode 100644
index 00000000..a1093fb0
--- /dev/null
+++ b/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Mime/Headers/DateHeader.php
@@ -0,0 +1,125 @@
+
+ *
+ *
+ *
+ * @param string $name of Header
+ * @param Swift_Mime_Grammar $grammar
+ */
+ public function __construct($name, Swift_Mime_Grammar $grammar)
+ {
+ $this->setFieldName($name);
+ parent::__construct($grammar);
+ }
+
+ /**
+ * Get the type of Header that this instance represents.
+ *
+ * @see TYPE_TEXT, TYPE_PARAMETERIZED, TYPE_MAILBOX
+ * @see TYPE_DATE, TYPE_ID, TYPE_PATH
+ *
+ * @return int
+ */
+ public function getFieldType()
+ {
+ return self::TYPE_DATE;
+ }
+
+ /**
+ * Set the model for the field body.
+ *
+ * This method takes a UNIX timestamp.
+ *
+ * @param int $model
+ */
+ public function setFieldBodyModel($model)
+ {
+ $this->setTimestamp($model);
+ }
+
+ /**
+ * Get the model for the field body.
+ *
+ * This method returns a UNIX timestamp.
+ *
+ * @return mixed
+ */
+ public function getFieldBodyModel()
+ {
+ return $this->getTimestamp();
+ }
+
+ /**
+ * Get the UNIX timestamp of the Date in this Header.
+ *
+ * @return int
+ */
+ public function getTimestamp()
+ {
+ return $this->_timestamp;
+ }
+
+ /**
+ * Set the UNIX timestamp of the Date in this Header.
+ *
+ * @param int $timestamp
+ */
+ public function setTimestamp($timestamp)
+ {
+ if (!is_null($timestamp)) {
+ $timestamp = (int) $timestamp;
+ }
+ $this->clearCachedValueIf($this->_timestamp != $timestamp);
+ $this->_timestamp = $timestamp;
+ }
+
+ /**
+ * Get the string value of the body in this Header.
+ *
+ * This is not necessarily RFC 2822 compliant since folding white space will
+ * not be added at this stage (see {@link toString()} for that).
+ *
+ * @see toString()
+ *
+ * @return string
+ */
+ public function getFieldBody()
+ {
+ if (!$this->getCachedValue()) {
+ if (isset($this->_timestamp)) {
+ $this->setCachedValue(date('r', $this->_timestamp));
+ }
+ }
+
+ return $this->getCachedValue();
+ }
+}
diff --git a/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Mime/Headers/IdentificationHeader.php b/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Mime/Headers/IdentificationHeader.php
new file mode 100644
index 00000000..1a5a3dd9
--- /dev/null
+++ b/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Mime/Headers/IdentificationHeader.php
@@ -0,0 +1,180 @@
+setFieldName($name);
+ parent::__construct($grammar);
+ }
+
+ /**
+ * Get the type of Header that this instance represents.
+ *
+ * @see TYPE_TEXT, TYPE_PARAMETERIZED, TYPE_MAILBOX
+ * @see TYPE_DATE, TYPE_ID, TYPE_PATH
+ *
+ * @return int
+ */
+ public function getFieldType()
+ {
+ return self::TYPE_ID;
+ }
+
+ /**
+ * Set the model for the field body.
+ *
+ * This method takes a string ID, or an array of IDs.
+ *
+ * @param mixed $model
+ *
+ * @throws Swift_RfcComplianceException
+ */
+ public function setFieldBodyModel($model)
+ {
+ $this->setId($model);
+ }
+
+ /**
+ * Get the model for the field body.
+ *
+ * This method returns an array of IDs
+ *
+ * @return array
+ */
+ public function getFieldBodyModel()
+ {
+ return $this->getIds();
+ }
+
+ /**
+ * Set the ID used in the value of this header.
+ *
+ * @param string|array $id
+ *
+ * @throws Swift_RfcComplianceException
+ */
+ public function setId($id)
+ {
+ $this->setIds(is_array($id) ? $id : array($id));
+ }
+
+ /**
+ * Get the ID used in the value of this Header.
+ *
+ * If multiple IDs are set only the first is returned.
+ *
+ * @return string
+ */
+ public function getId()
+ {
+ if (count($this->_ids) > 0) {
+ return $this->_ids[0];
+ }
+ }
+
+ /**
+ * Set a collection of IDs to use in the value of this Header.
+ *
+ * @param string[] $ids
+ *
+ * @throws Swift_RfcComplianceException
+ */
+ public function setIds(array $ids)
+ {
+ $actualIds = array();
+
+ foreach ($ids as $id) {
+ $this->_assertValidId($id);
+ $actualIds[] = $id;
+ }
+
+ $this->clearCachedValueIf($this->_ids != $actualIds);
+ $this->_ids = $actualIds;
+ }
+
+ /**
+ * Get the list of IDs used in this Header.
+ *
+ * @return string[]
+ */
+ public function getIds()
+ {
+ return $this->_ids;
+ }
+
+ /**
+ * Get the string value of the body in this Header.
+ *
+ * This is not necessarily RFC 2822 compliant since folding white space will
+ * not be added at this stage (see {@see toString()} for that).
+ *
+ * @see toString()
+ *
+ * @return string
+ *
+ * @throws Swift_RfcComplianceException
+ */
+ public function getFieldBody()
+ {
+ if (!$this->getCachedValue()) {
+ $angleAddrs = array();
+
+ foreach ($this->_ids as $id) {
+ $angleAddrs[] = '<'.$id.'>';
+ }
+
+ $this->setCachedValue(implode(' ', $angleAddrs));
+ }
+
+ return $this->getCachedValue();
+ }
+
+ /**
+ * Throws an Exception if the id passed does not comply with RFC 2822.
+ *
+ * @param string $id
+ *
+ * @throws Swift_RfcComplianceException
+ */
+ private function _assertValidId($id)
+ {
+ if (!preg_match(
+ '/^'.$this->getGrammar()->getDefinition('id-left').'@'.
+ $this->getGrammar()->getDefinition('id-right').'$/D',
+ $id
+ )) {
+ throw new Swift_RfcComplianceException(
+ 'Invalid ID given <'.$id.'>'
+ );
+ }
+ }
+}
diff --git a/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Mime/Headers/MailboxHeader.php b/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Mime/Headers/MailboxHeader.php
new file mode 100644
index 00000000..165b8619
--- /dev/null
+++ b/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Mime/Headers/MailboxHeader.php
@@ -0,0 +1,354 @@
+setFieldName($name);
+ $this->setEncoder($encoder);
+ parent::__construct($grammar);
+ }
+
+ /**
+ * Get the type of Header that this instance represents.
+ *
+ * @see TYPE_TEXT, TYPE_PARAMETERIZED, TYPE_MAILBOX
+ * @see TYPE_DATE, TYPE_ID, TYPE_PATH
+ *
+ * @return int
+ */
+ public function getFieldType()
+ {
+ return self::TYPE_MAILBOX;
+ }
+
+ /**
+ * Set the model for the field body.
+ *
+ * This method takes a string, or an array of addresses.
+ *
+ * @param mixed $model
+ *
+ * @throws Swift_RfcComplianceException
+ */
+ public function setFieldBodyModel($model)
+ {
+ $this->setNameAddresses($model);
+ }
+
+ /**
+ * Get the model for the field body.
+ *
+ * This method returns an associative array like {@link getNameAddresses()}
+ *
+ * @return array
+ *
+ * @throws Swift_RfcComplianceException
+ */
+ public function getFieldBodyModel()
+ {
+ return $this->getNameAddresses();
+ }
+
+ /**
+ * Set a list of mailboxes to be shown in this Header.
+ *
+ * The mailboxes can be a simple array of addresses, or an array of
+ * key=>value pairs where (email => personalName).
+ * Example:
+ *
+ * setNameAddresses(array(
+ * 'chris@swiftmailer.org' => 'Chris Corbyn',
+ * 'mark@swiftmailer.org' //No associated personal name
+ * ));
+ * ?>
+ *
+ *
+ * @see __construct()
+ * @see setAddresses()
+ * @see setValue()
+ *
+ * @param string|string[] $mailboxes
+ *
+ * @throws Swift_RfcComplianceException
+ */
+ public function setNameAddresses($mailboxes)
+ {
+ $this->_mailboxes = $this->normalizeMailboxes((array) $mailboxes);
+ $this->setCachedValue(null); //Clear any cached value
+ }
+
+ /**
+ * Get the full mailbox list of this Header as an array of valid RFC 2822 strings.
+ *
+ * Example:
+ *
+ * 'Chris Corbyn',
+ * 'mark@swiftmailer.org' => 'Mark Corbyn')
+ * );
+ * print_r($header->getNameAddressStrings());
+ * // array (
+ * // 0 => Chris Corbyn ,
+ * // 1 => Mark Corbyn
+ * // )
+ * ?>
+ *
+ *
+ * @see getNameAddresses()
+ * @see toString()
+ *
+ * @return string[]
+ *
+ * @throws Swift_RfcComplianceException
+ */
+ public function getNameAddressStrings()
+ {
+ return $this->_createNameAddressStrings($this->getNameAddresses());
+ }
+
+ /**
+ * Get all mailboxes in this Header as key=>value pairs.
+ *
+ * The key is the address and the value is the name (or null if none set).
+ * Example:
+ *
+ * 'Chris Corbyn',
+ * 'mark@swiftmailer.org' => 'Mark Corbyn')
+ * );
+ * print_r($header->getNameAddresses());
+ * // array (
+ * // chris@swiftmailer.org => Chris Corbyn,
+ * // mark@swiftmailer.org => Mark Corbyn
+ * // )
+ * ?>
+ *
+ *
+ * @see getAddresses()
+ * @see getNameAddressStrings()
+ *
+ * @return string[]
+ */
+ public function getNameAddresses()
+ {
+ return $this->_mailboxes;
+ }
+
+ /**
+ * Makes this Header represent a list of plain email addresses with no names.
+ *
+ * Example:
+ *
+ * setAddresses(
+ * array('one@domain.tld', 'two@domain.tld', 'three@domain.tld')
+ * );
+ * ?>
+ *
+ *
+ * @see setNameAddresses()
+ * @see setValue()
+ *
+ * @param string[] $addresses
+ *
+ * @throws Swift_RfcComplianceException
+ */
+ public function setAddresses($addresses)
+ {
+ $this->setNameAddresses(array_values((array) $addresses));
+ }
+
+ /**
+ * Get all email addresses in this Header.
+ *
+ * @see getNameAddresses()
+ *
+ * @return string[]
+ */
+ public function getAddresses()
+ {
+ return array_keys($this->_mailboxes);
+ }
+
+ /**
+ * Remove one or more addresses from this Header.
+ *
+ * @param string|string[] $addresses
+ */
+ public function removeAddresses($addresses)
+ {
+ $this->setCachedValue(null);
+ foreach ((array) $addresses as $address) {
+ unset($this->_mailboxes[$address]);
+ }
+ }
+
+ /**
+ * Get the string value of the body in this Header.
+ *
+ * This is not necessarily RFC 2822 compliant since folding white space will
+ * not be added at this stage (see {@link toString()} for that).
+ *
+ * @see toString()
+ *
+ * @return string
+ *
+ * @throws Swift_RfcComplianceException
+ */
+ public function getFieldBody()
+ {
+ // Compute the string value of the header only if needed
+ if (is_null($this->getCachedValue())) {
+ $this->setCachedValue($this->createMailboxListString($this->_mailboxes));
+ }
+
+ return $this->getCachedValue();
+ }
+
+ // -- Points of extension
+
+ /**
+ * Normalizes a user-input list of mailboxes into consistent key=>value pairs.
+ *
+ * @param string[] $mailboxes
+ *
+ * @return string[]
+ */
+ protected function normalizeMailboxes(array $mailboxes)
+ {
+ $actualMailboxes = array();
+
+ foreach ($mailboxes as $key => $value) {
+ if (is_string($key)) {
+ //key is email addr
+ $address = $key;
+ $name = $value;
+ } else {
+ $address = $value;
+ $name = null;
+ }
+ $this->_assertValidAddress($address);
+ $actualMailboxes[$address] = $name;
+ }
+
+ return $actualMailboxes;
+ }
+
+ /**
+ * Produces a compliant, formatted display-name based on the string given.
+ *
+ * @param string $displayName as displayed
+ * @param bool $shorten the first line to make remove for header name
+ *
+ * @return string
+ */
+ protected function createDisplayNameString($displayName, $shorten = false)
+ {
+ return $this->createPhrase($this, $displayName,
+ $this->getCharset(), $this->getEncoder(), $shorten
+ );
+ }
+
+ /**
+ * Creates a string form of all the mailboxes in the passed array.
+ *
+ * @param string[] $mailboxes
+ *
+ * @return string
+ *
+ * @throws Swift_RfcComplianceException
+ */
+ protected function createMailboxListString(array $mailboxes)
+ {
+ return implode(', ', $this->_createNameAddressStrings($mailboxes));
+ }
+
+ /**
+ * Redefine the encoding requirements for mailboxes.
+ *
+ * Commas and semicolons are used to separate
+ * multiple addresses, and should therefore be encoded
+ *
+ * @param string $token
+ *
+ * @return bool
+ */
+ protected function tokenNeedsEncoding($token)
+ {
+ return preg_match('/[,;]/', $token) || parent::tokenNeedsEncoding($token);
+ }
+
+ /**
+ * Return an array of strings conforming the the name-addr spec of RFC 2822.
+ *
+ * @param string[] $mailboxes
+ *
+ * @return string[]
+ */
+ private function _createNameAddressStrings(array $mailboxes)
+ {
+ $strings = array();
+
+ foreach ($mailboxes as $email => $name) {
+ $mailboxStr = $email;
+ if (!is_null($name)) {
+ $nameStr = $this->createDisplayNameString($name, empty($strings));
+ $mailboxStr = $nameStr.' <'.$mailboxStr.'>';
+ }
+ $strings[] = $mailboxStr;
+ }
+
+ return $strings;
+ }
+
+ /**
+ * Throws an Exception if the address passed does not comply with RFC 2822.
+ *
+ * @param string $address
+ *
+ * @throws Swift_RfcComplianceException If invalid.
+ */
+ private function _assertValidAddress($address)
+ {
+ if (!preg_match('/^'.$this->getGrammar()->getDefinition('addr-spec').'$/D',
+ $address)) {
+ throw new Swift_RfcComplianceException(
+ 'Address in mailbox given ['.$address.
+ '] does not comply with RFC 2822, 3.6.2.'
+ );
+ }
+ }
+}
diff --git a/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Mime/Headers/OpenDKIMHeader.php b/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Mime/Headers/OpenDKIMHeader.php
new file mode 100644
index 00000000..b55d4609
--- /dev/null
+++ b/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Mime/Headers/OpenDKIMHeader.php
@@ -0,0 +1,135 @@
+
+ */
+class Swift_Mime_Headers_OpenDKIMHeader implements Swift_Mime_Header
+{
+ /**
+ * The value of this Header.
+ *
+ * @var string
+ */
+ private $_value;
+
+ /**
+ * The name of this Header
+ * @var string
+ */
+ private $_fieldName;
+
+ /**
+ * Creates a new SimpleHeader with $name.
+ *
+ * @param string $name
+ * @param Swift_Mime_HeaderEncoder $encoder
+ * @param Swift_Mime_Grammar $grammar
+ */
+ public function __construct($name)
+ {
+ $this->_fieldName = $name;
+ }
+
+ /**
+ * Get the type of Header that this instance represents.
+ *
+ * @see TYPE_TEXT, TYPE_PARAMETERIZED, TYPE_MAILBOX
+ * @see TYPE_DATE, TYPE_ID, TYPE_PATH
+ *
+ * @return int
+ */
+ public function getFieldType()
+ {
+ return self::TYPE_TEXT;
+ }
+
+ /**
+ * Set the model for the field body.
+ *
+ * This method takes a string for the field value.
+ *
+ * @param string $model
+ */
+ public function setFieldBodyModel($model)
+ {
+ $this->setValue($model);
+ }
+
+ /**
+ * Get the model for the field body.
+ *
+ * This method returns a string.
+ *
+ * @return string
+ */
+ public function getFieldBodyModel()
+ {
+ return $this->getValue();
+ }
+
+ /**
+ * Get the (unencoded) value of this header.
+ *
+ * @return string
+ */
+ public function getValue()
+ {
+ return $this->_value;
+ }
+
+ /**
+ * Set the (unencoded) value of this header.
+ *
+ * @param string $value
+ */
+ public function setValue($value)
+ {
+ $this->_value = $value;
+ }
+
+ /**
+ * Get the value of this header prepared for rendering.
+ *
+ * @return string
+ */
+ public function getFieldBody()
+ {
+ return $this->_value;
+ }
+
+ /**
+ * Get this Header rendered as a RFC 2822 compliant string.
+ *
+ * @return string
+ */
+ public function toString()
+ {
+ return $this->_fieldName.': '.$this->_value;
+ }
+
+ /**
+ * Set the Header FieldName
+ * @see Swift_Mime_Header::getFieldName()
+ */
+ public function getFieldName()
+ {
+ return $this->_fieldName;
+ }
+
+ /**
+ * Ignored
+ */
+ public function setCharset($charset)
+ {
+ }
+}
diff --git a/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Mime/Headers/ParameterizedHeader.php b/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Mime/Headers/ParameterizedHeader.php
new file mode 100644
index 00000000..994fc940
--- /dev/null
+++ b/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Mime/Headers/ParameterizedHeader.php
@@ -0,0 +1,260 @@
+_paramEncoder = $paramEncoder;
+ }
+
+ /**
+ * Get the type of Header that this instance represents.
+ *
+ * @see TYPE_TEXT, TYPE_PARAMETERIZED, TYPE_MAILBOX
+ * @see TYPE_DATE, TYPE_ID, TYPE_PATH
+ *
+ * @return int
+ */
+ public function getFieldType()
+ {
+ return self::TYPE_PARAMETERIZED;
+ }
+
+ /**
+ * Set the character set used in this Header.
+ *
+ * @param string $charset
+ */
+ public function setCharset($charset)
+ {
+ parent::setCharset($charset);
+ if (isset($this->_paramEncoder)) {
+ $this->_paramEncoder->charsetChanged($charset);
+ }
+ }
+
+ /**
+ * Set the value of $parameter.
+ *
+ * @param string $parameter
+ * @param string $value
+ */
+ public function setParameter($parameter, $value)
+ {
+ $this->setParameters(array_merge($this->getParameters(), array($parameter => $value)));
+ }
+
+ /**
+ * Get the value of $parameter.
+ *
+ * @param string $parameter
+ *
+ * @return string
+ */
+ public function getParameter($parameter)
+ {
+ $params = $this->getParameters();
+
+ return array_key_exists($parameter, $params)
+ ? $params[$parameter]
+ : null;
+ }
+
+ /**
+ * Set an associative array of parameter names mapped to values.
+ *
+ * @param string[] $parameters
+ */
+ public function setParameters(array $parameters)
+ {
+ $this->clearCachedValueIf($this->_params != $parameters);
+ $this->_params = $parameters;
+ }
+
+ /**
+ * Returns an associative array of parameter names mapped to values.
+ *
+ * @return string[]
+ */
+ public function getParameters()
+ {
+ return $this->_params;
+ }
+
+ /**
+ * Get the value of this header prepared for rendering.
+ *
+ * @return string
+ */
+ public function getFieldBody() //TODO: Check caching here
+ {
+ $body = parent::getFieldBody();
+ foreach ($this->_params as $name => $value) {
+ if (!is_null($value)) {
+ // Add the parameter
+ $body .= '; '.$this->_createParameter($name, $value);
+ }
+ }
+
+ return $body;
+ }
+
+ /**
+ * Generate a list of all tokens in the final header.
+ *
+ * This doesn't need to be overridden in theory, but it is for implementation
+ * reasons to prevent potential breakage of attributes.
+ *
+ * @param string $string The string to tokenize
+ *
+ * @return array An array of tokens as strings
+ */
+ protected function toTokens($string = null)
+ {
+ $tokens = parent::toTokens(parent::getFieldBody());
+
+ // Try creating any parameters
+ foreach ($this->_params as $name => $value) {
+ if (!is_null($value)) {
+ // Add the semi-colon separator
+ $tokens[count($tokens)-1] .= ';';
+ $tokens = array_merge($tokens, $this->generateTokenLines(
+ ' '.$this->_createParameter($name, $value)
+ ));
+ }
+ }
+
+ return $tokens;
+ }
+
+ /**
+ * Render a RFC 2047 compliant header parameter from the $name and $value.
+ *
+ * @param string $name
+ * @param string $value
+ *
+ * @return string
+ */
+ private function _createParameter($name, $value)
+ {
+ $origValue = $value;
+
+ $encoded = false;
+ // Allow room for parameter name, indices, "=" and DQUOTEs
+ $maxValueLength = $this->getMaxLineLength() - strlen($name.'=*N"";') - 1;
+ $firstLineOffset = 0;
+
+ // If it's not already a valid parameter value...
+ if (!preg_match('/^'.self::TOKEN_REGEX.'$/D', $value)) {
+ // TODO: text, or something else??
+ // ... and it's not ascii
+ if (!preg_match('/^'.$this->getGrammar()->getDefinition('text').'*$/D', $value)) {
+ $encoded = true;
+ // Allow space for the indices, charset and language
+ $maxValueLength = $this->getMaxLineLength() - strlen($name.'*N*="";') - 1;
+ $firstLineOffset = strlen(
+ $this->getCharset()."'".$this->getLanguage()."'"
+ );
+ }
+ }
+
+ // Encode if we need to
+ if ($encoded || strlen($value) > $maxValueLength) {
+ if (isset($this->_paramEncoder)) {
+ $value = $this->_paramEncoder->encodeString(
+ $origValue, $firstLineOffset, $maxValueLength, $this->getCharset()
+ );
+ } else {
+ // We have to go against RFC 2183/2231 in some areas for interoperability
+ $value = $this->getTokenAsEncodedWord($origValue);
+ $encoded = false;
+ }
+ }
+
+ $valueLines = isset($this->_paramEncoder) ? explode("\r\n", $value) : array($value);
+
+ // Need to add indices
+ if (count($valueLines) > 1) {
+ $paramLines = array();
+ foreach ($valueLines as $i => $line) {
+ $paramLines[] = $name.'*'.$i.
+ $this->_getEndOfParameterValue($line, true, $i == 0);
+ }
+
+ return implode(";\r\n ", $paramLines);
+ } else {
+ return $name.$this->_getEndOfParameterValue(
+ $valueLines[0], $encoded, true
+ );
+ }
+ }
+
+ /**
+ * Returns the parameter value from the "=" and beyond.
+ *
+ * @param string $value to append
+ * @param bool $encoded
+ * @param bool $firstLine
+ *
+ * @return string
+ */
+ private function _getEndOfParameterValue($value, $encoded = false, $firstLine = false)
+ {
+ if (!preg_match('/^'.self::TOKEN_REGEX.'$/D', $value)) {
+ $value = '"'.$value.'"';
+ }
+ $prepend = '=';
+ if ($encoded) {
+ $prepend = '*=';
+ if ($firstLine) {
+ $prepend = '*='.$this->getCharset()."'".$this->getLanguage().
+ "'";
+ }
+ }
+
+ return $prepend.$value;
+ }
+}
diff --git a/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Mime/Headers/PathHeader.php b/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Mime/Headers/PathHeader.php
new file mode 100644
index 00000000..eea9a9ee
--- /dev/null
+++ b/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Mime/Headers/PathHeader.php
@@ -0,0 +1,143 @@
+setFieldName($name);
+ parent::__construct($grammar);
+ }
+
+ /**
+ * Get the type of Header that this instance represents.
+ *
+ * @see TYPE_TEXT, TYPE_PARAMETERIZED, TYPE_MAILBOX
+ * @see TYPE_DATE, TYPE_ID, TYPE_PATH
+ *
+ * @return int
+ */
+ public function getFieldType()
+ {
+ return self::TYPE_PATH;
+ }
+
+ /**
+ * Set the model for the field body.
+ * This method takes a string for an address.
+ *
+ * @param string $model
+ *
+ * @throws Swift_RfcComplianceException
+ */
+ public function setFieldBodyModel($model)
+ {
+ $this->setAddress($model);
+ }
+
+ /**
+ * Get the model for the field body.
+ * This method returns a string email address.
+ *
+ * @return mixed
+ */
+ public function getFieldBodyModel()
+ {
+ return $this->getAddress();
+ }
+
+ /**
+ * Set the Address which should appear in this Header.
+ *
+ * @param string $address
+ *
+ * @throws Swift_RfcComplianceException
+ */
+ public function setAddress($address)
+ {
+ if (is_null($address)) {
+ $this->_address = null;
+ } elseif ('' == $address) {
+ $this->_address = '';
+ } else {
+ $this->_assertValidAddress($address);
+ $this->_address = $address;
+ }
+ $this->setCachedValue(null);
+ }
+
+ /**
+ * Get the address which is used in this Header (if any).
+ *
+ * Null is returned if no address is set.
+ *
+ * @return string
+ */
+ public function getAddress()
+ {
+ return $this->_address;
+ }
+
+ /**
+ * Get the string value of the body in this Header.
+ *
+ * This is not necessarily RFC 2822 compliant since folding white space will
+ * not be added at this stage (see {@link toString()} for that).
+ *
+ * @see toString()
+ *
+ * @return string
+ */
+ public function getFieldBody()
+ {
+ if (!$this->getCachedValue()) {
+ if (isset($this->_address)) {
+ $this->setCachedValue('<'.$this->_address.'>');
+ }
+ }
+
+ return $this->getCachedValue();
+ }
+
+ /**
+ * Throws an Exception if the address passed does not comply with RFC 2822.
+ *
+ * @param string $address
+ *
+ * @throws Swift_RfcComplianceException If address is invalid
+ */
+ private function _assertValidAddress($address)
+ {
+ if (!preg_match('/^'.$this->getGrammar()->getDefinition('addr-spec').'$/D',
+ $address)) {
+ throw new Swift_RfcComplianceException(
+ 'Address set in PathHeader does not comply with addr-spec of RFC 2822.'
+ );
+ }
+ }
+}
diff --git a/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Mime/Headers/UnstructuredHeader.php b/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Mime/Headers/UnstructuredHeader.php
new file mode 100644
index 00000000..41d4e63d
--- /dev/null
+++ b/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Mime/Headers/UnstructuredHeader.php
@@ -0,0 +1,112 @@
+setFieldName($name);
+ $this->setEncoder($encoder);
+ parent::__construct($grammar);
+ }
+
+ /**
+ * Get the type of Header that this instance represents.
+ *
+ * @see TYPE_TEXT, TYPE_PARAMETERIZED, TYPE_MAILBOX
+ * @see TYPE_DATE, TYPE_ID, TYPE_PATH
+ *
+ * @return int
+ */
+ public function getFieldType()
+ {
+ return self::TYPE_TEXT;
+ }
+
+ /**
+ * Set the model for the field body.
+ *
+ * This method takes a string for the field value.
+ *
+ * @param string $model
+ */
+ public function setFieldBodyModel($model)
+ {
+ $this->setValue($model);
+ }
+
+ /**
+ * Get the model for the field body.
+ *
+ * This method returns a string.
+ *
+ * @return string
+ */
+ public function getFieldBodyModel()
+ {
+ return $this->getValue();
+ }
+
+ /**
+ * Get the (unencoded) value of this header.
+ *
+ * @return string
+ */
+ public function getValue()
+ {
+ return $this->_value;
+ }
+
+ /**
+ * Set the (unencoded) value of this header.
+ *
+ * @param string $value
+ */
+ public function setValue($value)
+ {
+ $this->clearCachedValueIf($this->_value != $value);
+ $this->_value = $value;
+ }
+
+ /**
+ * Get the value of this header prepared for rendering.
+ *
+ * @return string
+ */
+ public function getFieldBody()
+ {
+ if (!$this->getCachedValue()) {
+ $this->setCachedValue(
+ $this->encodeWords($this, $this->_value)
+ );
+ }
+
+ return $this->getCachedValue();
+ }
+}
diff --git a/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Mime/Message.php b/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Mime/Message.php
new file mode 100644
index 00000000..29bc4b33
--- /dev/null
+++ b/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Mime/Message.php
@@ -0,0 +1,223 @@
+ 'Real Name').
+ *
+ * If the second parameter is provided and the first is a string, then $name
+ * is associated with the address.
+ *
+ * @param mixed $address
+ * @param string $name optional
+ */
+ public function setSender($address, $name = null);
+
+ /**
+ * Get the sender address for this message.
+ *
+ * This has a higher significance than the From address.
+ *
+ * @return string
+ */
+ public function getSender();
+
+ /**
+ * Set the From address of this message.
+ *
+ * It is permissible for multiple From addresses to be set using an array.
+ *
+ * If multiple From addresses are used, you SHOULD set the Sender address and
+ * according to RFC 2822, MUST set the sender address.
+ *
+ * An array can be used if display names are to be provided: i.e.
+ * array('email@address.com' => 'Real Name').
+ *
+ * If the second parameter is provided and the first is a string, then $name
+ * is associated with the address.
+ *
+ * @param mixed $addresses
+ * @param string $name optional
+ */
+ public function setFrom($addresses, $name = null);
+
+ /**
+ * Get the From address(es) of this message.
+ *
+ * This method always returns an associative array where the keys are the
+ * addresses.
+ *
+ * @return string[]
+ */
+ public function getFrom();
+
+ /**
+ * Set the Reply-To address(es).
+ *
+ * Any replies from the receiver will be sent to this address.
+ *
+ * It is permissible for multiple reply-to addresses to be set using an array.
+ *
+ * This method has the same synopsis as {@link setFrom()} and {@link setTo()}.
+ *
+ * If the second parameter is provided and the first is a string, then $name
+ * is associated with the address.
+ *
+ * @param mixed $addresses
+ * @param string $name optional
+ */
+ public function setReplyTo($addresses, $name = null);
+
+ /**
+ * Get the Reply-To addresses for this message.
+ *
+ * This method always returns an associative array where the keys provide the
+ * email addresses.
+ *
+ * @return string[]
+ */
+ public function getReplyTo();
+
+ /**
+ * Set the To address(es).
+ *
+ * Recipients set in this field will receive a copy of this message.
+ *
+ * This method has the same synopsis as {@link setFrom()} and {@link setCc()}.
+ *
+ * If the second parameter is provided and the first is a string, then $name
+ * is associated with the address.
+ *
+ * @param mixed $addresses
+ * @param string $name optional
+ */
+ public function setTo($addresses, $name = null);
+
+ /**
+ * Get the To addresses for this message.
+ *
+ * This method always returns an associative array, whereby the keys provide
+ * the actual email addresses.
+ *
+ * @return string[]
+ */
+ public function getTo();
+
+ /**
+ * Set the Cc address(es).
+ *
+ * Recipients set in this field will receive a 'carbon-copy' of this message.
+ *
+ * This method has the same synopsis as {@link setFrom()} and {@link setTo()}.
+ *
+ * @param mixed $addresses
+ * @param string $name optional
+ */
+ public function setCc($addresses, $name = null);
+
+ /**
+ * Get the Cc addresses for this message.
+ *
+ * This method always returns an associative array, whereby the keys provide
+ * the actual email addresses.
+ *
+ * @return string[]
+ */
+ public function getCc();
+
+ /**
+ * Set the Bcc address(es).
+ *
+ * Recipients set in this field will receive a 'blind-carbon-copy' of this
+ * message.
+ *
+ * In other words, they will get the message, but any other recipients of the
+ * message will have no such knowledge of their receipt of it.
+ *
+ * This method has the same synopsis as {@link setFrom()} and {@link setTo()}.
+ *
+ * @param mixed $addresses
+ * @param string $name optional
+ */
+ public function setBcc($addresses, $name = null);
+
+ /**
+ * Get the Bcc addresses for this message.
+ *
+ * This method always returns an associative array, whereby the keys provide
+ * the actual email addresses.
+ *
+ * @return string[]
+ */
+ public function getBcc();
+}
diff --git a/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Mime/MimeEntity.php b/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Mime/MimeEntity.php
new file mode 100644
index 00000000..cd8b8a2b
--- /dev/null
+++ b/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Mime/MimeEntity.php
@@ -0,0 +1,115 @@
+setContentType('text/plain');
+ if (!is_null($charset)) {
+ $this->setCharset($charset);
+ }
+ }
+
+ /**
+ * Set the body of this entity, either as a string, or as an instance of
+ * {@link Swift_OutputByteStream}.
+ *
+ * @param mixed $body
+ * @param string $contentType optional
+ * @param string $charset optional
+ *
+ * @return Swift_Mime_MimePart
+ */
+ public function setBody($body, $contentType = null, $charset = null)
+ {
+ if (isset($charset)) {
+ $this->setCharset($charset);
+ }
+ $body = $this->_convertString($body);
+
+ parent::setBody($body, $contentType);
+
+ return $this;
+ }
+
+ /**
+ * Get the character set of this entity.
+ *
+ * @return string
+ */
+ public function getCharset()
+ {
+ return $this->_getHeaderParameter('Content-Type', 'charset');
+ }
+
+ /**
+ * Set the character set of this entity.
+ *
+ * @param string $charset
+ *
+ * @return Swift_Mime_MimePart
+ */
+ public function setCharset($charset)
+ {
+ $this->_setHeaderParameter('Content-Type', 'charset', $charset);
+ if ($charset !== $this->_userCharset) {
+ $this->_clearCache();
+ }
+ $this->_userCharset = $charset;
+ parent::charsetChanged($charset);
+
+ return $this;
+ }
+
+ /**
+ * Get the format of this entity (i.e. flowed or fixed).
+ *
+ * @return string
+ */
+ public function getFormat()
+ {
+ return $this->_getHeaderParameter('Content-Type', 'format');
+ }
+
+ /**
+ * Set the format of this entity (flowed or fixed).
+ *
+ * @param string $format
+ *
+ * @return Swift_Mime_MimePart
+ */
+ public function setFormat($format)
+ {
+ $this->_setHeaderParameter('Content-Type', 'format', $format);
+ $this->_userFormat = $format;
+
+ return $this;
+ }
+
+ /**
+ * Test if delsp is being used for this entity.
+ *
+ * @return bool
+ */
+ public function getDelSp()
+ {
+ return ($this->_getHeaderParameter('Content-Type', 'delsp') == 'yes')
+ ? true
+ : false;
+ }
+
+ /**
+ * Turn delsp on or off for this entity.
+ *
+ * @param bool $delsp
+ *
+ * @return Swift_Mime_MimePart
+ */
+ public function setDelSp($delsp = true)
+ {
+ $this->_setHeaderParameter('Content-Type', 'delsp', $delsp ? 'yes' : null);
+ $this->_userDelSp = $delsp;
+
+ return $this;
+ }
+
+ /**
+ * Get the nesting level of this entity.
+ *
+ * @see LEVEL_TOP, LEVEL_ALTERNATIVE, LEVEL_MIXED, LEVEL_RELATED
+ *
+ * @return int
+ */
+ public function getNestingLevel()
+ {
+ return $this->_nestingLevel;
+ }
+
+ /**
+ * Receive notification that the charset has changed on this document, or a
+ * parent document.
+ *
+ * @param string $charset
+ */
+ public function charsetChanged($charset)
+ {
+ $this->setCharset($charset);
+ }
+
+ /** Fix the content-type and encoding of this entity */
+ protected function _fixHeaders()
+ {
+ parent::_fixHeaders();
+ if (count($this->getChildren())) {
+ $this->_setHeaderParameter('Content-Type', 'charset', null);
+ $this->_setHeaderParameter('Content-Type', 'format', null);
+ $this->_setHeaderParameter('Content-Type', 'delsp', null);
+ } else {
+ $this->setCharset($this->_userCharset);
+ $this->setFormat($this->_userFormat);
+ $this->setDelSp($this->_userDelSp);
+ }
+ }
+
+ /** Set the nesting level of this entity */
+ protected function _setNestingLevel($level)
+ {
+ $this->_nestingLevel = $level;
+ }
+
+ /** Encode charset when charset is not utf-8 */
+ protected function _convertString($string)
+ {
+ $charset = strtolower($this->getCharset());
+ if (!in_array($charset, array('utf-8', 'iso-8859-1', ''))) {
+ // mb_convert_encoding must be the first one to check, since iconv cannot convert some words.
+ if (function_exists('mb_convert_encoding')) {
+ $string = mb_convert_encoding($string, $charset, 'utf-8');
+ } elseif (function_exists('iconv')) {
+ $string = iconv('utf-8//TRANSLIT//IGNORE', $charset, $string);
+ } else {
+ throw new Swift_SwiftException('No suitable convert encoding function (use UTF-8 as your charset or install the mbstring or iconv extension).');
+ }
+
+ return $string;
+ }
+
+ return $string;
+ }
+}
diff --git a/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Mime/ParameterizedHeader.php b/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Mime/ParameterizedHeader.php
new file mode 100644
index 00000000..ea793201
--- /dev/null
+++ b/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Mime/ParameterizedHeader.php
@@ -0,0 +1,34 @@
+_encoder = $encoder;
+ $this->_paramEncoder = $paramEncoder;
+ $this->_grammar = $grammar;
+ $this->_charset = $charset;
+ }
+
+ /**
+ * Create a new Mailbox Header with a list of $addresses.
+ *
+ * @param string $name
+ * @param array|string|null $addresses
+ *
+ * @return Swift_Mime_Header
+ */
+ public function createMailboxHeader($name, $addresses = null)
+ {
+ $header = new Swift_Mime_Headers_MailboxHeader($name, $this->_encoder, $this->_grammar);
+ if (isset($addresses)) {
+ $header->setFieldBodyModel($addresses);
+ }
+ $this->_setHeaderCharset($header);
+
+ return $header;
+ }
+
+ /**
+ * Create a new Date header using $timestamp (UNIX time).
+ * @param string $name
+ * @param int|null $timestamp
+ *
+ * @return Swift_Mime_Header
+ */
+ public function createDateHeader($name, $timestamp = null)
+ {
+ $header = new Swift_Mime_Headers_DateHeader($name, $this->_grammar);
+ if (isset($timestamp)) {
+ $header->setFieldBodyModel($timestamp);
+ }
+ $this->_setHeaderCharset($header);
+
+ return $header;
+ }
+
+ /**
+ * Create a new basic text header with $name and $value.
+ *
+ * @param string $name
+ * @param string $value
+ *
+ * @return Swift_Mime_Header
+ */
+ public function createTextHeader($name, $value = null)
+ {
+ $header = new Swift_Mime_Headers_UnstructuredHeader($name, $this->_encoder, $this->_grammar);
+ if (isset($value)) {
+ $header->setFieldBodyModel($value);
+ }
+ $this->_setHeaderCharset($header);
+
+ return $header;
+ }
+
+ /**
+ * Create a new ParameterizedHeader with $name, $value and $params.
+ *
+ * @param string $name
+ * @param string $value
+ * @param array $params
+ *
+ * @return Swift_Mime_ParameterizedHeader
+ */
+ public function createParameterizedHeader($name, $value = null,
+ $params = array())
+ {
+ $header = new Swift_Mime_Headers_ParameterizedHeader($name,
+ $this->_encoder, (strtolower($name) == 'content-disposition')
+ ? $this->_paramEncoder
+ : null,
+ $this->_grammar
+ );
+ if (isset($value)) {
+ $header->setFieldBodyModel($value);
+ }
+ foreach ($params as $k => $v) {
+ $header->setParameter($k, $v);
+ }
+ $this->_setHeaderCharset($header);
+
+ return $header;
+ }
+
+ /**
+ * Create a new ID header for Message-ID or Content-ID.
+ *
+ * @param string $name
+ * @param string|array $ids
+ *
+ * @return Swift_Mime_Header
+ */
+ public function createIdHeader($name, $ids = null)
+ {
+ $header = new Swift_Mime_Headers_IdentificationHeader($name, $this->_grammar);
+ if (isset($ids)) {
+ $header->setFieldBodyModel($ids);
+ }
+ $this->_setHeaderCharset($header);
+
+ return $header;
+ }
+
+ /**
+ * Create a new Path header with an address (path) in it.
+ *
+ * @param string $name
+ * @param string $path
+ *
+ * @return Swift_Mime_Header
+ */
+ public function createPathHeader($name, $path = null)
+ {
+ $header = new Swift_Mime_Headers_PathHeader($name, $this->_grammar);
+ if (isset($path)) {
+ $header->setFieldBodyModel($path);
+ }
+ $this->_setHeaderCharset($header);
+
+ return $header;
+ }
+
+ /**
+ * Notify this observer that the entity's charset has changed.
+ *
+ * @param string $charset
+ */
+ public function charsetChanged($charset)
+ {
+ $this->_charset = $charset;
+ $this->_encoder->charsetChanged($charset);
+ $this->_paramEncoder->charsetChanged($charset);
+ }
+
+ /**
+ * Make a deep copy of object
+ */
+ public function __clone()
+ {
+ $this->_encoder = clone $this->_encoder;
+ $this->_paramEncoder = clone $this->_paramEncoder;
+ }
+
+ /** Apply the charset to the Header */
+ private function _setHeaderCharset(Swift_Mime_Header $header)
+ {
+ if (isset($this->_charset)) {
+ $header->setCharset($this->_charset);
+ }
+ }
+}
diff --git a/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Mime/SimpleHeaderSet.php b/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Mime/SimpleHeaderSet.php
new file mode 100644
index 00000000..b44a02ca
--- /dev/null
+++ b/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Mime/SimpleHeaderSet.php
@@ -0,0 +1,396 @@
+_factory = $factory;
+ if (isset($charset)) {
+ $this->setCharset($charset);
+ }
+ }
+
+ /**
+ * Set the charset used by these headers.
+ *
+ * @param string $charset
+ */
+ public function setCharset($charset)
+ {
+ $this->_charset = $charset;
+ $this->_factory->charsetChanged($charset);
+ $this->_notifyHeadersOfCharset($charset);
+ }
+
+ /**
+ * Add a new Mailbox Header with a list of $addresses.
+ *
+ * @param string $name
+ * @param array|string $addresses
+ */
+ public function addMailboxHeader($name, $addresses = null)
+ {
+ $this->_storeHeader($name,
+ $this->_factory->createMailboxHeader($name, $addresses));
+ }
+
+ /**
+ * Add a new Date header using $timestamp (UNIX time).
+ *
+ * @param string $name
+ * @param int $timestamp
+ */
+ public function addDateHeader($name, $timestamp = null)
+ {
+ $this->_storeHeader($name,
+ $this->_factory->createDateHeader($name, $timestamp));
+ }
+
+ /**
+ * Add a new basic text header with $name and $value.
+ *
+ * @param string $name
+ * @param string $value
+ */
+ public function addTextHeader($name, $value = null)
+ {
+ $this->_storeHeader($name,
+ $this->_factory->createTextHeader($name, $value));
+ }
+
+ /**
+ * Add a new ParameterizedHeader with $name, $value and $params.
+ *
+ * @param string $name
+ * @param string $value
+ * @param array $params
+ */
+ public function addParameterizedHeader($name, $value = null, $params = array())
+ {
+ $this->_storeHeader($name, $this->_factory->createParameterizedHeader($name, $value, $params));
+ }
+
+ /**
+ * Add a new ID header for Message-ID or Content-ID.
+ *
+ * @param string $name
+ * @param string|array $ids
+ */
+ public function addIdHeader($name, $ids = null)
+ {
+ $this->_storeHeader($name, $this->_factory->createIdHeader($name, $ids));
+ }
+
+ /**
+ * Add a new Path header with an address (path) in it.
+ *
+ * @param string $name
+ * @param string $path
+ */
+ public function addPathHeader($name, $path = null)
+ {
+ $this->_storeHeader($name, $this->_factory->createPathHeader($name, $path));
+ }
+
+ /**
+ * Returns true if at least one header with the given $name exists.
+ *
+ * If multiple headers match, the actual one may be specified by $index.
+ *
+ * @param string $name
+ * @param int $index
+ *
+ * @return bool
+ */
+ public function has($name, $index = 0)
+ {
+ $lowerName = strtolower($name);
+
+ return array_key_exists($lowerName, $this->_headers) && array_key_exists($index, $this->_headers[$lowerName]);
+ }
+
+ /**
+ * Set a header in the HeaderSet.
+ *
+ * The header may be a previously fetched header via {@link get()} or it may
+ * be one that has been created separately.
+ *
+ * If $index is specified, the header will be inserted into the set at this
+ * offset.
+ *
+ * @param Swift_Mime_Header $header
+ * @param int $index
+ */
+ public function set(Swift_Mime_Header $header, $index = 0)
+ {
+ $this->_storeHeader($header->getFieldName(), $header, $index);
+ }
+
+ /**
+ * Get the header with the given $name.
+ *
+ * If multiple headers match, the actual one may be specified by $index.
+ * Returns NULL if none present.
+ *
+ * @param string $name
+ * @param int $index
+ *
+ * @return Swift_Mime_Header
+ */
+ public function get($name, $index = 0)
+ {
+ if ($this->has($name, $index)) {
+ $lowerName = strtolower($name);
+
+ return $this->_headers[$lowerName][$index];
+ }
+ }
+
+ /**
+ * Get all headers with the given $name.
+ *
+ * @param string $name
+ *
+ * @return array
+ */
+ public function getAll($name = null)
+ {
+ if (!isset($name)) {
+ $headers = array();
+ foreach ($this->_headers as $collection) {
+ $headers = array_merge($headers, $collection);
+ }
+
+ return $headers;
+ }
+
+ $lowerName = strtolower($name);
+ if (!array_key_exists($lowerName, $this->_headers)) {
+ return array();
+ }
+
+ return $this->_headers[$lowerName];
+ }
+
+ /**
+ * Return the name of all Headers
+ *
+ * @return array
+ */
+ public function listAll()
+ {
+ $headers = $this->_headers;
+ if ($this->_canSort()) {
+ uksort($headers, array($this, '_sortHeaders'));
+ }
+
+ return array_keys($headers);
+ }
+
+ /**
+ * Remove the header with the given $name if it's set.
+ *
+ * If multiple headers match, the actual one may be specified by $index.
+ *
+ * @param string $name
+ * @param int $index
+ */
+ public function remove($name, $index = 0)
+ {
+ $lowerName = strtolower($name);
+ unset($this->_headers[$lowerName][$index]);
+ }
+
+ /**
+ * Remove all headers with the given $name.
+ *
+ * @param string $name
+ */
+ public function removeAll($name)
+ {
+ $lowerName = strtolower($name);
+ unset($this->_headers[$lowerName]);
+ }
+
+ /**
+ * Create a new instance of this HeaderSet.
+ *
+ * @return Swift_Mime_HeaderSet
+ */
+ public function newInstance()
+ {
+ return new self($this->_factory);
+ }
+
+ /**
+ * Define a list of Header names as an array in the correct order.
+ *
+ * These Headers will be output in the given order where present.
+ *
+ * @param array $sequence
+ */
+ public function defineOrdering(array $sequence)
+ {
+ $this->_order = array_flip(array_map('strtolower', $sequence));
+ }
+
+ /**
+ * Set a list of header names which must always be displayed when set.
+ *
+ * Usually headers without a field value won't be output unless set here.
+ *
+ * @param array $names
+ */
+ public function setAlwaysDisplayed(array $names)
+ {
+ $this->_required = array_flip(array_map('strtolower', $names));
+ }
+
+ /**
+ * Notify this observer that the entity's charset has changed.
+ *
+ * @param string $charset
+ */
+ public function charsetChanged($charset)
+ {
+ $this->setCharset($charset);
+ }
+
+ /**
+ * Returns a string with a representation of all headers.
+ *
+ * @return string
+ */
+ public function toString()
+ {
+ $string = '';
+ $headers = $this->_headers;
+ if ($this->_canSort()) {
+ uksort($headers, array($this, '_sortHeaders'));
+ }
+ foreach ($headers as $collection) {
+ foreach ($collection as $header) {
+ if ($this->_isDisplayed($header) || $header->getFieldBody() != '') {
+ $string .= $header->toString();
+ }
+ }
+ }
+
+ return $string;
+ }
+
+ /**
+ * Returns a string representation of this object.
+ *
+ * @return string
+ *
+ * @see toString()
+ */
+ public function __toString()
+ {
+ return $this->toString();
+ }
+
+ /** Save a Header to the internal collection */
+ private function _storeHeader($name, Swift_Mime_Header $header, $offset = null)
+ {
+ if (!isset($this->_headers[strtolower($name)])) {
+ $this->_headers[strtolower($name)] = array();
+ }
+ if (!isset($offset)) {
+ $this->_headers[strtolower($name)][] = $header;
+ } else {
+ $this->_headers[strtolower($name)][$offset] = $header;
+ }
+ }
+
+ /** Test if the headers can be sorted */
+ private function _canSort()
+ {
+ return count($this->_order) > 0;
+ }
+
+ /** uksort() algorithm for Header ordering */
+ private function _sortHeaders($a, $b)
+ {
+ $lowerA = strtolower($a);
+ $lowerB = strtolower($b);
+ $aPos = array_key_exists($lowerA, $this->_order)
+ ? $this->_order[$lowerA]
+ : -1;
+ $bPos = array_key_exists($lowerB, $this->_order)
+ ? $this->_order[$lowerB]
+ : -1;
+
+ if ($aPos == -1) {
+ return 1;
+ } elseif ($bPos == -1) {
+ return -1;
+ }
+
+ return ($aPos < $bPos) ? -1 : 1;
+ }
+
+ /** Test if the given Header is always displayed */
+ private function _isDisplayed(Swift_Mime_Header $header)
+ {
+ return array_key_exists(strtolower($header->getFieldName()), $this->_required);
+ }
+
+ /** Notify all Headers of the new charset */
+ private function _notifyHeadersOfCharset($charset)
+ {
+ foreach ($this->_headers as $headerGroup) {
+ foreach ($headerGroup as $header) {
+ $header->setCharset($charset);
+ }
+ }
+ }
+
+ /**
+ * Make a deep copy of object
+ */
+ public function __clone()
+ {
+ $this->_factory = clone $this->_factory;
+ foreach ($this->_headers as $groupKey => $headerGroup) {
+ foreach ($headerGroup as $key => $header) {
+ $this->_headers[$groupKey][$key] = clone $header;
+ }
+ }
+ }
+}
diff --git a/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Mime/SimpleMessage.php b/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Mime/SimpleMessage.php
new file mode 100644
index 00000000..16d8d091
--- /dev/null
+++ b/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Mime/SimpleMessage.php
@@ -0,0 +1,649 @@
+getHeaders()->defineOrdering(array(
+ 'Return-Path',
+ 'Received',
+ 'DKIM-Signature',
+ 'DomainKey-Signature',
+ 'Sender',
+ 'Message-ID',
+ 'Date',
+ 'Subject',
+ 'From',
+ 'Reply-To',
+ 'To',
+ 'Cc',
+ 'Bcc',
+ 'MIME-Version',
+ 'Content-Type',
+ 'Content-Transfer-Encoding',
+ ));
+ $this->getHeaders()->setAlwaysDisplayed(array('Date', 'Message-ID', 'From'));
+ $this->getHeaders()->addTextHeader('MIME-Version', '1.0');
+ $this->setDate(time());
+ $this->setId($this->getId());
+ $this->getHeaders()->addMailboxHeader('From');
+ }
+
+ /**
+ * Always returns {@link LEVEL_TOP} for a message instance.
+ *
+ * @return int
+ */
+ public function getNestingLevel()
+ {
+ return self::LEVEL_TOP;
+ }
+
+ /**
+ * Set the subject of this message.
+ *
+ * @param string $subject
+ *
+ * @return Swift_Mime_SimpleMessage
+ */
+ public function setSubject($subject)
+ {
+ if (!$this->_setHeaderFieldModel('Subject', $subject)) {
+ $this->getHeaders()->addTextHeader('Subject', $subject);
+ }
+
+ return $this;
+ }
+
+ /**
+ * Get the subject of this message.
+ *
+ * @return string
+ */
+ public function getSubject()
+ {
+ return $this->_getHeaderFieldModel('Subject');
+ }
+
+ /**
+ * Set the date at which this message was created.
+ *
+ * @param int $date
+ *
+ * @return Swift_Mime_SimpleMessage
+ */
+ public function setDate($date)
+ {
+ if (!$this->_setHeaderFieldModel('Date', $date)) {
+ $this->getHeaders()->addDateHeader('Date', $date);
+ }
+
+ return $this;
+ }
+
+ /**
+ * Get the date at which this message was created.
+ *
+ * @return int
+ */
+ public function getDate()
+ {
+ return $this->_getHeaderFieldModel('Date');
+ }
+
+ /**
+ * Set the return-path (the bounce address) of this message.
+ *
+ * @param string $address
+ *
+ * @return Swift_Mime_SimpleMessage
+ */
+ public function setReturnPath($address)
+ {
+ if (!$this->_setHeaderFieldModel('Return-Path', $address)) {
+ $this->getHeaders()->addPathHeader('Return-Path', $address);
+ }
+
+ return $this;
+ }
+
+ /**
+ * Get the return-path (bounce address) of this message.
+ *
+ * @return string
+ */
+ public function getReturnPath()
+ {
+ return $this->_getHeaderFieldModel('Return-Path');
+ }
+
+ /**
+ * Set the sender of this message.
+ *
+ * This does not override the From field, but it has a higher significance.
+ *
+ * @param string $address
+ * @param string $name optional
+ *
+ * @return Swift_Mime_SimpleMessage
+ */
+ public function setSender($address, $name = null)
+ {
+ if (!is_array($address) && isset($name)) {
+ $address = array($address => $name);
+ }
+
+ if (!$this->_setHeaderFieldModel('Sender', (array) $address)) {
+ $this->getHeaders()->addMailboxHeader('Sender', (array) $address);
+ }
+
+ return $this;
+ }
+
+ /**
+ * Get the sender of this message.
+ *
+ * @return string
+ */
+ public function getSender()
+ {
+ return $this->_getHeaderFieldModel('Sender');
+ }
+
+ /**
+ * Add a From: address to this message.
+ *
+ * If $name is passed this name will be associated with the address.
+ *
+ * @param string $address
+ * @param string $name optional
+ *
+ * @return Swift_Mime_SimpleMessage
+ */
+ public function addFrom($address, $name = null)
+ {
+ $current = $this->getFrom();
+ $current[$address] = $name;
+
+ return $this->setFrom($current);
+ }
+
+ /**
+ * Set the from address of this message.
+ *
+ * You may pass an array of addresses if this message is from multiple people.
+ *
+ * If $name is passed and the first parameter is a string, this name will be
+ * associated with the address.
+ *
+ * @param string $addresses
+ * @param string $name optional
+ *
+ * @return Swift_Mime_SimpleMessage
+ */
+ public function setFrom($addresses, $name = null)
+ {
+ if (!is_array($addresses) && isset($name)) {
+ $addresses = array($addresses => $name);
+ }
+
+ if (!$this->_setHeaderFieldModel('From', (array) $addresses)) {
+ $this->getHeaders()->addMailboxHeader('From', (array) $addresses);
+ }
+
+ return $this;
+ }
+
+ /**
+ * Get the from address of this message.
+ *
+ * @return mixed
+ */
+ public function getFrom()
+ {
+ return $this->_getHeaderFieldModel('From');
+ }
+
+ /**
+ * Add a Reply-To: address to this message.
+ *
+ * If $name is passed this name will be associated with the address.
+ *
+ * @param string $address
+ * @param string $name optional
+ *
+ * @return Swift_Mime_SimpleMessage
+ */
+ public function addReplyTo($address, $name = null)
+ {
+ $current = $this->getReplyTo();
+ $current[$address] = $name;
+
+ return $this->setReplyTo($current);
+ }
+
+ /**
+ * Set the reply-to address of this message.
+ *
+ * You may pass an array of addresses if replies will go to multiple people.
+ *
+ * If $name is passed and the first parameter is a string, this name will be
+ * associated with the address.
+ *
+ * @param string $addresses
+ * @param string $name optional
+ *
+ * @return Swift_Mime_SimpleMessage
+ */
+ public function setReplyTo($addresses, $name = null)
+ {
+ if (!is_array($addresses) && isset($name)) {
+ $addresses = array($addresses => $name);
+ }
+
+ if (!$this->_setHeaderFieldModel('Reply-To', (array) $addresses)) {
+ $this->getHeaders()->addMailboxHeader('Reply-To', (array) $addresses);
+ }
+
+ return $this;
+ }
+
+ /**
+ * Get the reply-to address of this message.
+ *
+ * @return string
+ */
+ public function getReplyTo()
+ {
+ return $this->_getHeaderFieldModel('Reply-To');
+ }
+
+ /**
+ * Add a To: address to this message.
+ *
+ * If $name is passed this name will be associated with the address.
+ *
+ * @param string $address
+ * @param string $name optional
+ *
+ * @return Swift_Mime_SimpleMessage
+ */
+ public function addTo($address, $name = null)
+ {
+ $current = $this->getTo();
+ $current[$address] = $name;
+
+ return $this->setTo($current);
+ }
+
+ /**
+ * Set the to addresses of this message.
+ *
+ * If multiple recipients will receive the message an array should be used.
+ * Example: array('receiver@domain.org', 'other@domain.org' => 'A name')
+ *
+ * If $name is passed and the first parameter is a string, this name will be
+ * associated with the address.
+ *
+ * @param mixed $addresses
+ * @param string $name optional
+ *
+ * @return Swift_Mime_SimpleMessage
+ */
+ public function setTo($addresses, $name = null)
+ {
+ if (!is_array($addresses) && isset($name)) {
+ $addresses = array($addresses => $name);
+ }
+
+ if (!$this->_setHeaderFieldModel('To', (array) $addresses)) {
+ $this->getHeaders()->addMailboxHeader('To', (array) $addresses);
+ }
+
+ return $this;
+ }
+
+ /**
+ * Get the To addresses of this message.
+ *
+ * @return array
+ */
+ public function getTo()
+ {
+ return $this->_getHeaderFieldModel('To');
+ }
+
+ /**
+ * Add a Cc: address to this message.
+ *
+ * If $name is passed this name will be associated with the address.
+ *
+ * @param string $address
+ * @param string $name optional
+ *
+ * @return Swift_Mime_SimpleMessage
+ */
+ public function addCc($address, $name = null)
+ {
+ $current = $this->getCc();
+ $current[$address] = $name;
+
+ return $this->setCc($current);
+ }
+
+ /**
+ * Set the Cc addresses of this message.
+ *
+ * If $name is passed and the first parameter is a string, this name will be
+ * associated with the address.
+ *
+ * @param mixed $addresses
+ * @param string $name optional
+ *
+ * @return Swift_Mime_SimpleMessage
+ */
+ public function setCc($addresses, $name = null)
+ {
+ if (!is_array($addresses) && isset($name)) {
+ $addresses = array($addresses => $name);
+ }
+
+ if (!$this->_setHeaderFieldModel('Cc', (array) $addresses)) {
+ $this->getHeaders()->addMailboxHeader('Cc', (array) $addresses);
+ }
+
+ return $this;
+ }
+
+ /**
+ * Get the Cc address of this message.
+ *
+ * @return array
+ */
+ public function getCc()
+ {
+ return $this->_getHeaderFieldModel('Cc');
+ }
+
+ /**
+ * Add a Bcc: address to this message.
+ *
+ * If $name is passed this name will be associated with the address.
+ *
+ * @param string $address
+ * @param string $name optional
+ *
+ * @return Swift_Mime_SimpleMessage
+ */
+ public function addBcc($address, $name = null)
+ {
+ $current = $this->getBcc();
+ $current[$address] = $name;
+
+ return $this->setBcc($current);
+ }
+
+ /**
+ * Set the Bcc addresses of this message.
+ *
+ * If $name is passed and the first parameter is a string, this name will be
+ * associated with the address.
+ *
+ * @param mixed $addresses
+ * @param string $name optional
+ *
+ * @return Swift_Mime_SimpleMessage
+ */
+ public function setBcc($addresses, $name = null)
+ {
+ if (!is_array($addresses) && isset($name)) {
+ $addresses = array($addresses => $name);
+ }
+
+ if (!$this->_setHeaderFieldModel('Bcc', (array) $addresses)) {
+ $this->getHeaders()->addMailboxHeader('Bcc', (array) $addresses);
+ }
+
+ return $this;
+ }
+
+ /**
+ * Get the Bcc addresses of this message.
+ *
+ * @return array
+ */
+ public function getBcc()
+ {
+ return $this->_getHeaderFieldModel('Bcc');
+ }
+
+ /**
+ * Set the priority of this message.
+ *
+ * The value is an integer where 1 is the highest priority and 5 is the lowest.
+ *
+ * @param int $priority
+ *
+ * @return Swift_Mime_SimpleMessage
+ */
+ public function setPriority($priority)
+ {
+ $priorityMap = array(
+ 1 => 'Highest',
+ 2 => 'High',
+ 3 => 'Normal',
+ 4 => 'Low',
+ 5 => 'Lowest',
+ );
+ $pMapKeys = array_keys($priorityMap);
+ if ($priority > max($pMapKeys)) {
+ $priority = max($pMapKeys);
+ } elseif ($priority < min($pMapKeys)) {
+ $priority = min($pMapKeys);
+ }
+ if (!$this->_setHeaderFieldModel('X-Priority',
+ sprintf('%d (%s)', $priority, $priorityMap[$priority]))) {
+ $this->getHeaders()->addTextHeader('X-Priority',
+ sprintf('%d (%s)', $priority, $priorityMap[$priority]));
+ }
+
+ return $this;
+ }
+
+ /**
+ * Get the priority of this message.
+ *
+ * The returned value is an integer where 1 is the highest priority and 5
+ * is the lowest.
+ *
+ * @return int
+ */
+ public function getPriority()
+ {
+ list($priority) = sscanf($this->_getHeaderFieldModel('X-Priority'),
+ '%[1-5]'
+ );
+
+ return isset($priority) ? $priority : 3;
+ }
+
+ /**
+ * Ask for a delivery receipt from the recipient to be sent to $addresses
+ *
+ * @param array $addresses
+ *
+ * @return Swift_Mime_SimpleMessage
+ */
+ public function setReadReceiptTo($addresses)
+ {
+ if (!$this->_setHeaderFieldModel('Disposition-Notification-To', $addresses)) {
+ $this->getHeaders()
+ ->addMailboxHeader('Disposition-Notification-To', $addresses);
+ }
+
+ return $this;
+ }
+
+ /**
+ * Get the addresses to which a read-receipt will be sent.
+ *
+ * @return string
+ */
+ public function getReadReceiptTo()
+ {
+ return $this->_getHeaderFieldModel('Disposition-Notification-To');
+ }
+
+ /**
+ * Attach a {@link Swift_Mime_MimeEntity} such as an Attachment or MimePart.
+ *
+ * @param Swift_Mime_MimeEntity $entity
+ *
+ * @return Swift_Mime_SimpleMessage
+ */
+ public function attach(Swift_Mime_MimeEntity $entity)
+ {
+ $this->setChildren(array_merge($this->getChildren(), array($entity)));
+
+ return $this;
+ }
+
+ /**
+ * Remove an already attached entity.
+ *
+ * @param Swift_Mime_MimeEntity $entity
+ *
+ * @return Swift_Mime_SimpleMessage
+ */
+ public function detach(Swift_Mime_MimeEntity $entity)
+ {
+ $newChildren = array();
+ foreach ($this->getChildren() as $child) {
+ if ($entity !== $child) {
+ $newChildren[] = $child;
+ }
+ }
+ $this->setChildren($newChildren);
+
+ return $this;
+ }
+
+ /**
+ * Attach a {@link Swift_Mime_MimeEntity} and return it's CID source.
+ * This method should be used when embedding images or other data in a message.
+ *
+ * @param Swift_Mime_MimeEntity $entity
+ *
+ * @return string
+ */
+ public function embed(Swift_Mime_MimeEntity $entity)
+ {
+ $this->attach($entity);
+
+ return 'cid:'.$entity->getId();
+ }
+
+ /**
+ * Get this message as a complete string.
+ *
+ * @return string
+ */
+ public function toString()
+ {
+ if (count($children = $this->getChildren()) > 0 && $this->getBody() != '') {
+ $this->setChildren(array_merge(array($this->_becomeMimePart()), $children));
+ $string = parent::toString();
+ $this->setChildren($children);
+ } else {
+ $string = parent::toString();
+ }
+
+ return $string;
+ }
+
+ /**
+ * Returns a string representation of this object.
+ *
+ * @see toString()
+ *
+ * @return string
+ */
+ public function __toString()
+ {
+ return $this->toString();
+ }
+
+ /**
+ * Write this message to a {@link Swift_InputByteStream}.
+ *
+ * @param Swift_InputByteStream $is
+ */
+ public function toByteStream(Swift_InputByteStream $is)
+ {
+ if (count($children = $this->getChildren()) > 0 && $this->getBody() != '') {
+ $this->setChildren(array_merge(array($this->_becomeMimePart()), $children));
+ parent::toByteStream($is);
+ $this->setChildren($children);
+ } else {
+ parent::toByteStream($is);
+ }
+ }
+
+ /** @see Swift_Mime_SimpleMimeEntity::_getIdField() */
+ protected function _getIdField()
+ {
+ return 'Message-ID';
+ }
+
+ /** Turn the body of this message into a child of itself if needed */
+ protected function _becomeMimePart()
+ {
+ $part = new parent($this->getHeaders()->newInstance(), $this->getEncoder(),
+ $this->_getCache(), $this->_getGrammar(), $this->_userCharset
+ );
+ $part->setContentType($this->_userContentType);
+ $part->setBody($this->getBody());
+ $part->setFormat($this->_userFormat);
+ $part->setDelSp($this->_userDelSp);
+ $part->_setNestingLevel($this->_getTopNestingLevel());
+
+ return $part;
+ }
+
+ /** Get the highest nesting level nested inside this message */
+ private function _getTopNestingLevel()
+ {
+ $highestLevel = $this->getNestingLevel();
+ foreach ($this->getChildren() as $child) {
+ $childLevel = $child->getNestingLevel();
+ if ($highestLevel < $childLevel) {
+ $highestLevel = $childLevel;
+ }
+ }
+
+ return $highestLevel;
+ }
+}
diff --git a/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Mime/SimpleMimeEntity.php b/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Mime/SimpleMimeEntity.php
new file mode 100644
index 00000000..60492920
--- /dev/null
+++ b/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Mime/SimpleMimeEntity.php
@@ -0,0 +1,866 @@
+ array(self::LEVEL_TOP, self::LEVEL_MIXED),
+ 'multipart/alternative' => array(self::LEVEL_MIXED, self::LEVEL_ALTERNATIVE),
+ 'multipart/related' => array(self::LEVEL_ALTERNATIVE, self::LEVEL_RELATED),
+ );
+
+ /** A set of filter rules to define what level an entity should be nested at */
+ private $_compoundLevelFilters = array();
+
+ /** The nesting level of this entity */
+ private $_nestingLevel = self::LEVEL_ALTERNATIVE;
+
+ /** A KeyCache instance used during encoding and streaming */
+ private $_cache;
+
+ /** Direct descendants of this entity */
+ private $_immediateChildren = array();
+
+ /** All descendants of this entity */
+ private $_children = array();
+
+ /** The maximum line length of the body of this entity */
+ private $_maxLineLength = 78;
+
+ /** The order in which alternative mime types should appear */
+ private $_alternativePartOrder = array(
+ 'text/plain' => 1,
+ 'text/html' => 2,
+ 'multipart/related' => 3,
+ );
+
+ /** The CID of this entity */
+ private $_id;
+
+ /** The key used for accessing the cache */
+ private $_cacheKey;
+
+ protected $_userContentType;
+
+ /**
+ * Create a new SimpleMimeEntity with $headers, $encoder and $cache.
+ *
+ * @param Swift_Mime_HeaderSet $headers
+ * @param Swift_Mime_ContentEncoder $encoder
+ * @param Swift_KeyCache $cache
+ * @param Swift_Mime_Grammar $grammar
+ */
+ public function __construct(Swift_Mime_HeaderSet $headers, Swift_Mime_ContentEncoder $encoder, Swift_KeyCache $cache, Swift_Mime_Grammar $grammar)
+ {
+ $this->_cacheKey = md5(uniqid(getmypid().mt_rand(), true));
+ $this->_cache = $cache;
+ $this->_headers = $headers;
+ $this->_grammar = $grammar;
+ $this->setEncoder($encoder);
+ $this->_headers->defineOrdering(array('Content-Type', 'Content-Transfer-Encoding'));
+
+ // This array specifies that, when the entire MIME document contains
+ // $compoundLevel, then for each child within $level, if its Content-Type
+ // is $contentType then it should be treated as if it's level is
+ // $neededLevel instead. I tried to write that unambiguously! :-\
+ // Data Structure:
+ // array (
+ // $compoundLevel => array(
+ // $level => array(
+ // $contentType => $neededLevel
+ // )
+ // )
+ // )
+
+ $this->_compoundLevelFilters = array(
+ (self::LEVEL_ALTERNATIVE + self::LEVEL_RELATED) => array(
+ self::LEVEL_ALTERNATIVE => array(
+ 'text/plain' => self::LEVEL_ALTERNATIVE,
+ 'text/html' => self::LEVEL_RELATED,
+ ),
+ ),
+ );
+
+ $this->_id = $this->getRandomId();
+ }
+
+ /**
+ * Generate a new Content-ID or Message-ID for this MIME entity.
+ *
+ * @return string
+ */
+ public function generateId()
+ {
+ $this->setId($this->getRandomId());
+
+ return $this->_id;
+ }
+
+ /**
+ * Get the {@link Swift_Mime_HeaderSet} for this entity.
+ *
+ * @return Swift_Mime_HeaderSet
+ */
+ public function getHeaders()
+ {
+ return $this->_headers;
+ }
+
+ /**
+ * Get the nesting level of this entity.
+ *
+ * @see LEVEL_TOP, LEVEL_MIXED, LEVEL_RELATED, LEVEL_ALTERNATIVE
+ *
+ * @return int
+ */
+ public function getNestingLevel()
+ {
+ return $this->_nestingLevel;
+ }
+
+ /**
+ * Get the Content-type of this entity.
+ *
+ * @return string
+ */
+ public function getContentType()
+ {
+ return $this->_getHeaderFieldModel('Content-Type');
+ }
+
+ /**
+ * Set the Content-type of this entity.
+ *
+ * @param string $type
+ *
+ * @return Swift_Mime_SimpleMimeEntity
+ */
+ public function setContentType($type)
+ {
+ $this->_setContentTypeInHeaders($type);
+ // Keep track of the value so that if the content-type changes automatically
+ // due to added child entities, it can be restored if they are later removed
+ $this->_userContentType = $type;
+
+ return $this;
+ }
+
+ /**
+ * Get the CID of this entity.
+ *
+ * The CID will only be present in headers if a Content-ID header is present.
+ *
+ * @return string
+ */
+ public function getId()
+ {
+ $tmp = (array) $this->_getHeaderFieldModel($this->_getIdField());
+
+ return $this->_headers->has($this->_getIdField()) ? current($tmp) : $this->_id;
+ }
+
+ /**
+ * Set the CID of this entity.
+ *
+ * @param string $id
+ *
+ * @return Swift_Mime_SimpleMimeEntity
+ */
+ public function setId($id)
+ {
+ if (!$this->_setHeaderFieldModel($this->_getIdField(), $id)) {
+ $this->_headers->addIdHeader($this->_getIdField(), $id);
+ }
+ $this->_id = $id;
+
+ return $this;
+ }
+
+ /**
+ * Get the description of this entity.
+ *
+ * This value comes from the Content-Description header if set.
+ *
+ * @return string
+ */
+ public function getDescription()
+ {
+ return $this->_getHeaderFieldModel('Content-Description');
+ }
+
+ /**
+ * Set the description of this entity.
+ *
+ * This method sets a value in the Content-ID header.
+ *
+ * @param string $description
+ *
+ * @return Swift_Mime_SimpleMimeEntity
+ */
+ public function setDescription($description)
+ {
+ if (!$this->_setHeaderFieldModel('Content-Description', $description)) {
+ $this->_headers->addTextHeader('Content-Description', $description);
+ }
+
+ return $this;
+ }
+
+ /**
+ * Get the maximum line length of the body of this entity.
+ *
+ * @return int
+ */
+ public function getMaxLineLength()
+ {
+ return $this->_maxLineLength;
+ }
+
+ /**
+ * Set the maximum line length of lines in this body.
+ *
+ * Though not enforced by the library, lines should not exceed 1000 chars.
+ *
+ * @param int $length
+ *
+ * @return Swift_Mime_SimpleMimeEntity
+ */
+ public function setMaxLineLength($length)
+ {
+ $this->_maxLineLength = $length;
+
+ return $this;
+ }
+
+ /**
+ * Get all children added to this entity.
+ *
+ * @return array of Swift_Mime_Entity
+ */
+ public function getChildren()
+ {
+ return $this->_children;
+ }
+
+ /**
+ * Set all children of this entity.
+ *
+ * @param array $children Swift_Mime_Entity instances
+ * @param int $compoundLevel For internal use only
+ *
+ * @return Swift_Mime_SimpleMimeEntity
+ */
+ public function setChildren(array $children, $compoundLevel = null)
+ {
+ // TODO: Try to refactor this logic
+
+ $compoundLevel = isset($compoundLevel)
+ ? $compoundLevel
+ : $this->_getCompoundLevel($children)
+ ;
+
+ $immediateChildren = array();
+ $grandchildren = array();
+ $newContentType = $this->_userContentType;
+
+ foreach ($children as $child) {
+ $level = $this->_getNeededChildLevel($child, $compoundLevel);
+ if (empty($immediateChildren)) {
+ //first iteration
+ $immediateChildren = array($child);
+ } else {
+ $nextLevel = $this->_getNeededChildLevel($immediateChildren[0], $compoundLevel);
+ if ($nextLevel == $level) {
+ $immediateChildren[] = $child;
+ } elseif ($level < $nextLevel) {
+ // Re-assign immediateChildren to grandchildren
+ $grandchildren = array_merge($grandchildren, $immediateChildren);
+ // Set new children
+ $immediateChildren = array($child);
+ } else {
+ $grandchildren[] = $child;
+ }
+ }
+ }
+
+ if (!empty($immediateChildren)) {
+ $lowestLevel = $this->_getNeededChildLevel($immediateChildren[0], $compoundLevel);
+
+ // Determine which composite media type is needed to accommodate the
+ // immediate children
+ foreach ($this->_compositeRanges as $mediaType => $range) {
+ if ($lowestLevel > $range[0]
+ && $lowestLevel <= $range[1]) {
+ $newContentType = $mediaType;
+ break;
+ }
+ }
+
+ // Put any grandchildren in a subpart
+ if (!empty($grandchildren)) {
+ $subentity = $this->_createChild();
+ $subentity->_setNestingLevel($lowestLevel);
+ $subentity->setChildren($grandchildren, $compoundLevel);
+ array_unshift($immediateChildren, $subentity);
+ }
+ }
+
+ $this->_immediateChildren = $immediateChildren;
+ $this->_children = $children;
+ $this->_setContentTypeInHeaders($newContentType);
+ $this->_fixHeaders();
+ $this->_sortChildren();
+
+ return $this;
+ }
+
+ /**
+ * Get the body of this entity as a string.
+ *
+ * @return string
+ */
+ public function getBody()
+ {
+ return ($this->_body instanceof Swift_OutputByteStream)
+ ? $this->_readStream($this->_body)
+ : $this->_body;
+ }
+
+ /**
+ * Set the body of this entity, either as a string, or as an instance of
+ * {@link Swift_OutputByteStream}.
+ *
+ * @param mixed $body
+ * @param string $contentType optional
+ *
+ * @return Swift_Mime_SimpleMimeEntity
+ */
+ public function setBody($body, $contentType = null)
+ {
+ if ($body !== $this->_body) {
+ $this->_clearCache();
+ }
+
+ $this->_body = $body;
+ if (isset($contentType)) {
+ $this->setContentType($contentType);
+ }
+
+ return $this;
+ }
+
+ /**
+ * Get the encoder used for the body of this entity.
+ *
+ * @return Swift_Mime_ContentEncoder
+ */
+ public function getEncoder()
+ {
+ return $this->_encoder;
+ }
+
+ /**
+ * Set the encoder used for the body of this entity.
+ *
+ * @param Swift_Mime_ContentEncoder $encoder
+ *
+ * @return Swift_Mime_SimpleMimeEntity
+ */
+ public function setEncoder(Swift_Mime_ContentEncoder $encoder)
+ {
+ if ($encoder !== $this->_encoder) {
+ $this->_clearCache();
+ }
+
+ $this->_encoder = $encoder;
+ $this->_setEncoding($encoder->getName());
+ $this->_notifyEncoderChanged($encoder);
+
+ return $this;
+ }
+
+ /**
+ * Get the boundary used to separate children in this entity.
+ *
+ * @return string
+ */
+ public function getBoundary()
+ {
+ if (!isset($this->_boundary)) {
+ $this->_boundary = '_=_swift_v4_'.time().'_'.md5(getmypid().mt_rand().uniqid('', true)).'_=_';
+ }
+
+ return $this->_boundary;
+ }
+
+ /**
+ * Set the boundary used to separate children in this entity.
+ *
+ * @param string $boundary
+ *
+ * @return Swift_Mime_SimpleMimeEntity
+ *
+ * @throws Swift_RfcComplianceException
+ */
+ public function setBoundary($boundary)
+ {
+ $this->_assertValidBoundary($boundary);
+ $this->_boundary = $boundary;
+
+ return $this;
+ }
+
+ /**
+ * Receive notification that the charset of this entity, or a parent entity
+ * has changed.
+ *
+ * @param string $charset
+ */
+ public function charsetChanged($charset)
+ {
+ $this->_notifyCharsetChanged($charset);
+ }
+
+ /**
+ * Receive notification that the encoder of this entity or a parent entity
+ * has changed.
+ *
+ * @param Swift_Mime_ContentEncoder $encoder
+ */
+ public function encoderChanged(Swift_Mime_ContentEncoder $encoder)
+ {
+ $this->_notifyEncoderChanged($encoder);
+ }
+
+ /**
+ * Get this entire entity as a string.
+ *
+ * @return string
+ */
+ public function toString()
+ {
+ $string = $this->_headers->toString();
+ $string .= $this->_bodyToString();
+
+ return $string;
+ }
+
+ /**
+ * Get this entire entity as a string.
+ *
+ * @return string
+ */
+ protected function _bodyToString()
+ {
+ $string = '';
+
+ if (isset($this->_body) && empty($this->_immediateChildren)) {
+ if ($this->_cache->hasKey($this->_cacheKey, 'body')) {
+ $body = $this->_cache->getString($this->_cacheKey, 'body');
+ } else {
+ $body = "\r\n".$this->_encoder->encodeString($this->getBody(), 0,
+ $this->getMaxLineLength()
+ );
+ $this->_cache->setString($this->_cacheKey, 'body', $body,
+ Swift_KeyCache::MODE_WRITE
+ );
+ }
+ $string .= $body;
+ }
+
+ if (!empty($this->_immediateChildren)) {
+ foreach ($this->_immediateChildren as $child) {
+ $string .= "\r\n\r\n--".$this->getBoundary()."\r\n";
+ $string .= $child->toString();
+ }
+ $string .= "\r\n\r\n--".$this->getBoundary()."--\r\n";
+ }
+
+ return $string;
+ }
+
+ /**
+ * Returns a string representation of this object.
+ *
+ * @see toString()
+ *
+ * @return string
+ */
+ public function __toString()
+ {
+ return $this->toString();
+ }
+
+ /**
+ * Write this entire entity to a {@see Swift_InputByteStream}.
+ *
+ * @param Swift_InputByteStream
+ */
+ public function toByteStream(Swift_InputByteStream $is)
+ {
+ $is->write($this->_headers->toString());
+ $is->commit();
+
+ $this->_bodyToByteStream($is);
+ }
+
+ /**
+ * Write this entire entity to a {@link Swift_InputByteStream}.
+ *
+ * @param Swift_InputByteStream
+ */
+ protected function _bodyToByteStream(Swift_InputByteStream $is)
+ {
+ if (empty($this->_immediateChildren)) {
+ if (isset($this->_body)) {
+ if ($this->_cache->hasKey($this->_cacheKey, 'body')) {
+ $this->_cache->exportToByteStream($this->_cacheKey, 'body', $is);
+ } else {
+ $cacheIs = $this->_cache->getInputByteStream($this->_cacheKey, 'body');
+ if ($cacheIs) {
+ $is->bind($cacheIs);
+ }
+
+ $is->write("\r\n");
+
+ if ($this->_body instanceof Swift_OutputByteStream) {
+ $this->_body->setReadPointer(0);
+
+ $this->_encoder->encodeByteStream($this->_body, $is, 0, $this->getMaxLineLength());
+ } else {
+ $is->write($this->_encoder->encodeString($this->getBody(), 0, $this->getMaxLineLength()));
+ }
+
+ if ($cacheIs) {
+ $is->unbind($cacheIs);
+ }
+ }
+ }
+ }
+
+ if (!empty($this->_immediateChildren)) {
+ foreach ($this->_immediateChildren as $child) {
+ $is->write("\r\n\r\n--".$this->getBoundary()."\r\n");
+ $child->toByteStream($is);
+ }
+ $is->write("\r\n\r\n--".$this->getBoundary()."--\r\n");
+ }
+ }
+
+ /**
+ * Get the name of the header that provides the ID of this entity
+ */
+ protected function _getIdField()
+ {
+ return 'Content-ID';
+ }
+
+ /**
+ * Get the model data (usually an array or a string) for $field.
+ */
+ protected function _getHeaderFieldModel($field)
+ {
+ if ($this->_headers->has($field)) {
+ return $this->_headers->get($field)->getFieldBodyModel();
+ }
+ }
+
+ /**
+ * Set the model data for $field.
+ */
+ protected function _setHeaderFieldModel($field, $model)
+ {
+ if ($this->_headers->has($field)) {
+ $this->_headers->get($field)->setFieldBodyModel($model);
+
+ return true;
+ } else {
+ return false;
+ }
+ }
+
+ /**
+ * Get the parameter value of $parameter on $field header.
+ */
+ protected function _getHeaderParameter($field, $parameter)
+ {
+ if ($this->_headers->has($field)) {
+ return $this->_headers->get($field)->getParameter($parameter);
+ }
+ }
+
+ /**
+ * Set the parameter value of $parameter on $field header.
+ */
+ protected function _setHeaderParameter($field, $parameter, $value)
+ {
+ if ($this->_headers->has($field)) {
+ $this->_headers->get($field)->setParameter($parameter, $value);
+
+ return true;
+ } else {
+ return false;
+ }
+ }
+
+ /**
+ * Re-evaluate what content type and encoding should be used on this entity.
+ */
+ protected function _fixHeaders()
+ {
+ if (count($this->_immediateChildren)) {
+ $this->_setHeaderParameter('Content-Type', 'boundary',
+ $this->getBoundary()
+ );
+ $this->_headers->remove('Content-Transfer-Encoding');
+ } else {
+ $this->_setHeaderParameter('Content-Type', 'boundary', null);
+ $this->_setEncoding($this->_encoder->getName());
+ }
+ }
+
+ /**
+ * Get the KeyCache used in this entity.
+ *
+ * @return Swift_KeyCache
+ */
+ protected function _getCache()
+ {
+ return $this->_cache;
+ }
+
+ /**
+ * Get the grammar used for validation.
+ *
+ * @return Swift_Mime_Grammar
+ */
+ protected function _getGrammar()
+ {
+ return $this->_grammar;
+ }
+
+ /**
+ * Empty the KeyCache for this entity.
+ */
+ protected function _clearCache()
+ {
+ $this->_cache->clearKey($this->_cacheKey, 'body');
+ }
+
+ /**
+ * Returns a random Content-ID or Message-ID.
+ *
+ * @return string
+ */
+ protected function getRandomId()
+ {
+ $idLeft = md5(getmypid().'.'.time().'.'.uniqid(mt_rand(), true));
+ $idRight = !empty($_SERVER['SERVER_NAME']) ? $_SERVER['SERVER_NAME'] : 'swift.generated';
+ $id = $idLeft.'@'.$idRight;
+
+ try {
+ $this->_assertValidId($id);
+ } catch (Swift_RfcComplianceException $e) {
+ $id = $idLeft.'@swift.generated';
+ }
+
+ return $id;
+ }
+
+ private function _readStream(Swift_OutputByteStream $os)
+ {
+ $string = '';
+ while (false !== $bytes = $os->read(8192)) {
+ $string .= $bytes;
+ }
+
+ return $string;
+ }
+
+ private function _setEncoding($encoding)
+ {
+ if (!$this->_setHeaderFieldModel('Content-Transfer-Encoding', $encoding)) {
+ $this->_headers->addTextHeader('Content-Transfer-Encoding', $encoding);
+ }
+ }
+
+ private function _assertValidBoundary($boundary)
+ {
+ if (!preg_match(
+ '/^[a-z0-9\'\(\)\+_\-,\.\/:=\?\ ]{0,69}[a-z0-9\'\(\)\+_\-,\.\/:=\?]$/Di',
+ $boundary)) {
+ throw new Swift_RfcComplianceException('Mime boundary set is not RFC 2046 compliant.');
+ }
+ }
+
+ private function _setContentTypeInHeaders($type)
+ {
+ if (!$this->_setHeaderFieldModel('Content-Type', $type)) {
+ $this->_headers->addParameterizedHeader('Content-Type', $type);
+ }
+ }
+
+ private function _setNestingLevel($level)
+ {
+ $this->_nestingLevel = $level;
+ }
+
+ private function _getCompoundLevel($children)
+ {
+ $level = 0;
+ foreach ($children as $child) {
+ $level |= $child->getNestingLevel();
+ }
+
+ return $level;
+ }
+
+ private function _getNeededChildLevel($child, $compoundLevel)
+ {
+ $filter = array();
+ foreach ($this->_compoundLevelFilters as $bitmask => $rules) {
+ if (($compoundLevel & $bitmask) === $bitmask) {
+ $filter = $rules + $filter;
+ }
+ }
+
+ $realLevel = $child->getNestingLevel();
+ $lowercaseType = strtolower($child->getContentType());
+
+ if (isset($filter[$realLevel])
+ && isset($filter[$realLevel][$lowercaseType])) {
+ return $filter[$realLevel][$lowercaseType];
+ } else {
+ return $realLevel;
+ }
+ }
+
+ private function _createChild()
+ {
+ return new self($this->_headers->newInstance(),
+ $this->_encoder, $this->_cache, $this->_grammar);
+ }
+
+ private function _notifyEncoderChanged(Swift_Mime_ContentEncoder $encoder)
+ {
+ foreach ($this->_immediateChildren as $child) {
+ $child->encoderChanged($encoder);
+ }
+ }
+
+ private function _notifyCharsetChanged($charset)
+ {
+ $this->_encoder->charsetChanged($charset);
+ $this->_headers->charsetChanged($charset);
+ foreach ($this->_immediateChildren as $child) {
+ $child->charsetChanged($charset);
+ }
+ }
+
+ private function _sortChildren()
+ {
+ $shouldSort = false;
+ foreach ($this->_immediateChildren as $child) {
+ // NOTE: This include alternative parts moved into a related part
+ if ($child->getNestingLevel() == self::LEVEL_ALTERNATIVE) {
+ $shouldSort = true;
+ break;
+ }
+ }
+
+ // Sort in order of preference, if there is one
+ if ($shouldSort) {
+ usort($this->_immediateChildren, array($this, '_childSortAlgorithm'));
+ }
+ }
+
+ private function _childSortAlgorithm($a, $b)
+ {
+ $typePrefs = array();
+ $types = array(
+ strtolower($a->getContentType()),
+ strtolower($b->getContentType()),
+ );
+ foreach ($types as $type) {
+ $typePrefs[] = (array_key_exists($type, $this->_alternativePartOrder))
+ ? $this->_alternativePartOrder[$type]
+ : (max($this->_alternativePartOrder) + 1);
+ }
+
+ return ($typePrefs[0] >= $typePrefs[1]) ? 1 : -1;
+ }
+
+ // -- Destructor
+
+ /**
+ * Empties it's own contents from the cache.
+ */
+ public function __destruct()
+ {
+ $this->_cache->clearAll($this->_cacheKey);
+ }
+
+ /**
+ * Throws an Exception if the id passed does not comply with RFC 2822.
+ *
+ * @param string $id
+ *
+ * @throws Swift_RfcComplianceException
+ */
+ private function _assertValidId($id)
+ {
+ if (!preg_match(
+ '/^'.$this->_grammar->getDefinition('id-left').'@'.
+ $this->_grammar->getDefinition('id-right').'$/D',
+ $id
+ )) {
+ throw new Swift_RfcComplianceException(
+ 'Invalid ID given <'.$id.'>'
+ );
+ }
+ }
+
+ /**
+ * Make a deep copy of object
+ */
+ public function __clone()
+ {
+ $this->_headers = clone $this->_headers;
+ $this->_encoder = clone $this->_encoder;
+ $this->_cacheKey = uniqid();
+ $this->generateId();
+ $children = array();
+ foreach ($this->_children as $pos => $child) {
+ $children[$pos] = clone $child;
+ }
+ $this->setChildren($children);
+ }
+}
diff --git a/vendor/swiftmailer/swiftmailer/lib/classes/Swift/MimePart.php b/vendor/swiftmailer/swiftmailer/lib/classes/Swift/MimePart.php
new file mode 100644
index 00000000..5702d1c1
--- /dev/null
+++ b/vendor/swiftmailer/swiftmailer/lib/classes/Swift/MimePart.php
@@ -0,0 +1,59 @@
+createDependenciesFor('mime.part')
+ );
+
+ if (!isset($charset)) {
+ $charset = Swift_DependencyContainer::getInstance()
+ ->lookup('properties.charset');
+ }
+ $this->setBody($body);
+ $this->setCharset($charset);
+ if ($contentType) {
+ $this->setContentType($contentType);
+ }
+ }
+
+ /**
+ * Create a new MimePart.
+ *
+ * @param string $body
+ * @param string $contentType
+ * @param string $charset
+ *
+ * @return Swift_Mime_MimePart
+ */
+ public static function newInstance($body = null, $contentType = null, $charset = null)
+ {
+ return new self($body, $contentType, $charset);
+ }
+}
diff --git a/vendor/swiftmailer/swiftmailer/lib/classes/Swift/NullTransport.php b/vendor/swiftmailer/swiftmailer/lib/classes/Swift/NullTransport.php
new file mode 100644
index 00000000..726d83ca
--- /dev/null
+++ b/vendor/swiftmailer/swiftmailer/lib/classes/Swift/NullTransport.php
@@ -0,0 +1,39 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+/**
+ * Pretends messages have been sent, but just ignores them.
+ *
+ * @author Fabien Potencier
+ */
+class Swift_NullTransport extends Swift_Transport_NullTransport
+{
+ /**
+ * Create a new NullTransport.
+ */
+ public function __construct()
+ {
+ call_user_func_array(
+ array($this, 'Swift_Transport_NullTransport::__construct'),
+ Swift_DependencyContainer::getInstance()
+ ->createDependenciesFor('transport.null')
+ );
+ }
+
+ /**
+ * Create a new NullTransport instance.
+ *
+ * @return Swift_NullTransport
+ */
+ public static function newInstance()
+ {
+ return new self();
+ }
+}
diff --git a/vendor/swiftmailer/swiftmailer/lib/classes/Swift/OutputByteStream.php b/vendor/swiftmailer/swiftmailer/lib/classes/Swift/OutputByteStream.php
new file mode 100644
index 00000000..0c2783f0
--- /dev/null
+++ b/vendor/swiftmailer/swiftmailer/lib/classes/Swift/OutputByteStream.php
@@ -0,0 +1,46 @@
+setThreshold($threshold);
+ $this->setSleepTime($sleep);
+ $this->_sleeper = $sleeper;
+ }
+
+ /**
+ * Set the number of emails to send before restarting.
+ *
+ * @param int $threshold
+ */
+ public function setThreshold($threshold)
+ {
+ $this->_threshold = $threshold;
+ }
+
+ /**
+ * Get the number of emails to send before restarting.
+ *
+ * @return int
+ */
+ public function getThreshold()
+ {
+ return $this->_threshold;
+ }
+
+ /**
+ * Set the number of seconds to sleep for during a restart.
+ *
+ * @param int $sleep time
+ */
+ public function setSleepTime($sleep)
+ {
+ $this->_sleep = $sleep;
+ }
+
+ /**
+ * Get the number of seconds to sleep for during a restart.
+ *
+ * @return int
+ */
+ public function getSleepTime()
+ {
+ return $this->_sleep;
+ }
+
+ /**
+ * Invoked immediately before the Message is sent.
+ *
+ * @param Swift_Events_SendEvent $evt
+ */
+ public function beforeSendPerformed(Swift_Events_SendEvent $evt)
+ {
+ }
+
+ /**
+ * Invoked immediately after the Message is sent.
+ *
+ * @param Swift_Events_SendEvent $evt
+ */
+ public function sendPerformed(Swift_Events_SendEvent $evt)
+ {
+ ++$this->_counter;
+ if ($this->_counter >= $this->_threshold) {
+ $transport = $evt->getTransport();
+ $transport->stop();
+ if ($this->_sleep) {
+ $this->sleep($this->_sleep);
+ }
+ $transport->start();
+ $this->_counter = 0;
+ }
+ }
+
+ /**
+ * Sleep for $seconds.
+ *
+ * @param int $seconds
+ */
+ public function sleep($seconds)
+ {
+ if (isset($this->_sleeper)) {
+ $this->_sleeper->sleep($seconds);
+ } else {
+ sleep($seconds);
+ }
+ }
+}
diff --git a/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Plugins/BandwidthMonitorPlugin.php b/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Plugins/BandwidthMonitorPlugin.php
new file mode 100644
index 00000000..af1701a0
--- /dev/null
+++ b/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Plugins/BandwidthMonitorPlugin.php
@@ -0,0 +1,164 @@
+getMessage();
+ $message->toByteStream($this);
+ }
+
+ /**
+ * Invoked immediately following a command being sent.
+ *
+ * @param Swift_Events_CommandEvent $evt
+ */
+ public function commandSent(Swift_Events_CommandEvent $evt)
+ {
+ $command = $evt->getCommand();
+ $this->_out += strlen($command);
+ }
+
+ /**
+ * Invoked immediately following a response coming back.
+ *
+ * @param Swift_Events_ResponseEvent $evt
+ */
+ public function responseReceived(Swift_Events_ResponseEvent $evt)
+ {
+ $response = $evt->getResponse();
+ $this->_in += strlen($response);
+ }
+
+ /**
+ * Called when a message is sent so that the outgoing counter can be increased.
+ *
+ * @param string $bytes
+ */
+ public function write($bytes)
+ {
+ $this->_out += strlen($bytes);
+ foreach ($this->_mirrors as $stream) {
+ $stream->write($bytes);
+ }
+ }
+
+ /**
+ * Not used.
+ */
+ public function commit()
+ {
+ }
+
+ /**
+ * Attach $is to this stream.
+ *
+ * The stream acts as an observer, receiving all data that is written.
+ * All {@link write()} and {@link flushBuffers()} operations will be mirrored.
+ *
+ * @param Swift_InputByteStream $is
+ */
+ public function bind(Swift_InputByteStream $is)
+ {
+ $this->_mirrors[] = $is;
+ }
+
+ /**
+ * Remove an already bound stream.
+ *
+ * If $is is not bound, no errors will be raised.
+ * If the stream currently has any buffered data it will be written to $is
+ * before unbinding occurs.
+ *
+ * @param Swift_InputByteStream $is
+ */
+ public function unbind(Swift_InputByteStream $is)
+ {
+ foreach ($this->_mirrors as $k => $stream) {
+ if ($is === $stream) {
+ unset($this->_mirrors[$k]);
+ }
+ }
+ }
+
+ /**
+ * Not used.
+ */
+ public function flushBuffers()
+ {
+ foreach ($this->_mirrors as $stream) {
+ $stream->flushBuffers();
+ }
+ }
+
+ /**
+ * Get the total number of bytes sent to the server.
+ *
+ * @return int
+ */
+ public function getBytesOut()
+ {
+ return $this->_out;
+ }
+
+ /**
+ * Get the total number of bytes received from the server.
+ *
+ * @return int
+ */
+ public function getBytesIn()
+ {
+ return $this->_in;
+ }
+
+ /**
+ * Reset the internal counters to zero.
+ */
+ public function reset()
+ {
+ $this->_out = 0;
+ $this->_in = 0;
+ }
+}
diff --git a/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Plugins/Decorator/Replacements.php b/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Plugins/Decorator/Replacements.php
new file mode 100644
index 00000000..86184339
--- /dev/null
+++ b/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Plugins/Decorator/Replacements.php
@@ -0,0 +1,31 @@
+
+ * $replacements = array(
+ * "address1@domain.tld" => array("{a}" => "b", "{c}" => "d"),
+ * "address2@domain.tld" => array("{a}" => "x", "{c}" => "y")
+ * )
+ *
+ *
+ * When using an instance of {@link Swift_Plugins_Decorator_Replacements},
+ * the object should return just the array of replacements for the address
+ * given to {@link Swift_Plugins_Decorator_Replacements::getReplacementsFor()}.
+ *
+ * @param mixed $replacements Array or Swift_Plugins_Decorator_Replacements
+ */
+ public function __construct($replacements)
+ {
+ $this->setReplacements($replacements);
+ }
+
+ /**
+ * Sets replacements.
+ *
+ * @param mixed $replacements Array or Swift_Plugins_Decorator_Replacements
+ *
+ * @see __construct()
+ */
+ public function setReplacements($replacements)
+ {
+ if (!($replacements instanceof Swift_Plugins_Decorator_Replacements)) {
+ $this->_replacements = (array) $replacements;
+ } else {
+ $this->_replacements = $replacements;
+ }
+ }
+
+ /**
+ * Invoked immediately before the Message is sent.
+ *
+ * @param Swift_Events_SendEvent $evt
+ */
+ public function beforeSendPerformed(Swift_Events_SendEvent $evt)
+ {
+ $message = $evt->getMessage();
+ $this->_restoreMessage($message);
+ $to = array_keys($message->getTo());
+ $address = array_shift($to);
+ if ($replacements = $this->getReplacementsFor($address)) {
+ $body = $message->getBody();
+ $search = array_keys($replacements);
+ $replace = array_values($replacements);
+ $bodyReplaced = str_replace(
+ $search, $replace, $body
+ );
+ if ($body != $bodyReplaced) {
+ $this->_originalBody = $body;
+ $message->setBody($bodyReplaced);
+ }
+
+ foreach ($message->getHeaders()->getAll() as $header) {
+ $body = $header->getFieldBodyModel();
+ $count = 0;
+ if (is_array($body)) {
+ $bodyReplaced = array();
+ foreach ($body as $key => $value) {
+ $count1 = 0;
+ $count2 = 0;
+ $key = is_string($key) ? str_replace($search, $replace, $key, $count1) : $key;
+ $value = is_string($value) ? str_replace($search, $replace, $value, $count2) : $value;
+ $bodyReplaced[$key] = $value;
+
+ if (!$count && ($count1 || $count2)) {
+ $count = 1;
+ }
+ }
+ } else {
+ $bodyReplaced = str_replace($search, $replace, $body, $count);
+ }
+
+ if ($count) {
+ $this->_originalHeaders[$header->getFieldName()] = $body;
+ $header->setFieldBodyModel($bodyReplaced);
+ }
+ }
+
+ $children = (array) $message->getChildren();
+ foreach ($children as $child) {
+ list($type, ) = sscanf($child->getContentType(), '%[^/]/%s');
+ if ('text' == $type) {
+ $body = $child->getBody();
+ $bodyReplaced = str_replace(
+ $search, $replace, $body
+ );
+ if ($body != $bodyReplaced) {
+ $child->setBody($bodyReplaced);
+ $this->_originalChildBodies[$child->getId()] = $body;
+ }
+ }
+ }
+ $this->_lastMessage = $message;
+ }
+ }
+
+ /**
+ * Find a map of replacements for the address.
+ *
+ * If this plugin was provided with a delegate instance of
+ * {@link Swift_Plugins_Decorator_Replacements} then the call will be
+ * delegated to it. Otherwise, it will attempt to find the replacements
+ * from the array provided in the constructor.
+ *
+ * If no replacements can be found, an empty value (NULL) is returned.
+ *
+ * @param string $address
+ *
+ * @return array
+ */
+ public function getReplacementsFor($address)
+ {
+ if ($this->_replacements instanceof Swift_Plugins_Decorator_Replacements) {
+ return $this->_replacements->getReplacementsFor($address);
+ } else {
+ return isset($this->_replacements[$address])
+ ? $this->_replacements[$address]
+ : null
+ ;
+ }
+ }
+
+ /**
+ * Invoked immediately after the Message is sent.
+ *
+ * @param Swift_Events_SendEvent $evt
+ */
+ public function sendPerformed(Swift_Events_SendEvent $evt)
+ {
+ $this->_restoreMessage($evt->getMessage());
+ }
+
+ /** Restore a changed message back to its original state */
+ private function _restoreMessage(Swift_Mime_Message $message)
+ {
+ if ($this->_lastMessage === $message) {
+ if (isset($this->_originalBody)) {
+ $message->setBody($this->_originalBody);
+ $this->_originalBody = null;
+ }
+ if (!empty($this->_originalHeaders)) {
+ foreach ($message->getHeaders()->getAll() as $header) {
+ if (array_key_exists($header->getFieldName(), $this->_originalHeaders)) {
+ $header->setFieldBodyModel($this->_originalHeaders[$header->getFieldName()]);
+ }
+ }
+ $this->_originalHeaders = array();
+ }
+ if (!empty($this->_originalChildBodies)) {
+ $children = (array) $message->getChildren();
+ foreach ($children as $child) {
+ $id = $child->getId();
+ if (array_key_exists($id, $this->_originalChildBodies)) {
+ $child->setBody($this->_originalChildBodies[$id]);
+ }
+ }
+ $this->_originalChildBodies = array();
+ }
+ $this->_lastMessage = null;
+ }
+ }
+}
diff --git a/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Plugins/ImpersonatePlugin.php b/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Plugins/ImpersonatePlugin.php
new file mode 100644
index 00000000..5bd0bbda
--- /dev/null
+++ b/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Plugins/ImpersonatePlugin.php
@@ -0,0 +1,68 @@
+_sender = $sender;
+ }
+
+ /**
+ * Invoked immediately before the Message is sent.
+ *
+ * @param Swift_Events_SendEvent $evt
+ */
+ public function beforeSendPerformed(Swift_Events_SendEvent $evt)
+ {
+ $message = $evt->getMessage();
+ $headers = $message->getHeaders();
+
+ // save current recipients
+ $headers->addPathHeader('X-Swift-Return-Path', $message->getReturnPath());
+
+ // replace them with the one to send to
+ $message->setReturnPath($this->_sender);
+ }
+
+ /**
+ * Invoked immediately after the Message is sent.
+ *
+ * @param Swift_Events_SendEvent $evt
+ */
+ public function sendPerformed(Swift_Events_SendEvent $evt)
+ {
+ $message = $evt->getMessage();
+
+ // restore original headers
+ $headers = $message->getHeaders();
+
+ if ($headers->has('X-Swift-Return-Path')) {
+ $message->setReturnPath($headers->get('X-Swift-Return-Path')->getAddress());
+ $headers->removeAll('X-Swift-Return-Path');
+ }
+ }
+}
diff --git a/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Plugins/Logger.php b/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Plugins/Logger.php
new file mode 100644
index 00000000..915e7206
--- /dev/null
+++ b/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Plugins/Logger.php
@@ -0,0 +1,36 @@
+_logger = $logger;
+ }
+
+ /**
+ * Add a log entry.
+ *
+ * @param string $entry
+ */
+ public function add($entry)
+ {
+ $this->_logger->add($entry);
+ }
+
+ /**
+ * Clear the log contents.
+ */
+ public function clear()
+ {
+ $this->_logger->clear();
+ }
+
+ /**
+ * Get this log as a string.
+ *
+ * @return string
+ */
+ public function dump()
+ {
+ return $this->_logger->dump();
+ }
+
+ /**
+ * Invoked immediately following a command being sent.
+ *
+ * @param Swift_Events_CommandEvent $evt
+ */
+ public function commandSent(Swift_Events_CommandEvent $evt)
+ {
+ $command = $evt->getCommand();
+ $this->_logger->add(sprintf(">> %s", $command));
+ }
+
+ /**
+ * Invoked immediately following a response coming back.
+ *
+ * @param Swift_Events_ResponseEvent $evt
+ */
+ public function responseReceived(Swift_Events_ResponseEvent $evt)
+ {
+ $response = $evt->getResponse();
+ $this->_logger->add(sprintf("<< %s", $response));
+ }
+
+ /**
+ * Invoked just before a Transport is started.
+ *
+ * @param Swift_Events_TransportChangeEvent $evt
+ */
+ public function beforeTransportStarted(Swift_Events_TransportChangeEvent $evt)
+ {
+ $transportName = get_class($evt->getSource());
+ $this->_logger->add(sprintf("++ Starting %s", $transportName));
+ }
+
+ /**
+ * Invoked immediately after the Transport is started.
+ *
+ * @param Swift_Events_TransportChangeEvent $evt
+ */
+ public function transportStarted(Swift_Events_TransportChangeEvent $evt)
+ {
+ $transportName = get_class($evt->getSource());
+ $this->_logger->add(sprintf("++ %s started", $transportName));
+ }
+
+ /**
+ * Invoked just before a Transport is stopped.
+ *
+ * @param Swift_Events_TransportChangeEvent $evt
+ */
+ public function beforeTransportStopped(Swift_Events_TransportChangeEvent $evt)
+ {
+ $transportName = get_class($evt->getSource());
+ $this->_logger->add(sprintf("++ Stopping %s", $transportName));
+ }
+
+ /**
+ * Invoked immediately after the Transport is stopped.
+ *
+ * @param Swift_Events_TransportChangeEvent $evt
+ */
+ public function transportStopped(Swift_Events_TransportChangeEvent $evt)
+ {
+ $transportName = get_class($evt->getSource());
+ $this->_logger->add(sprintf("++ %s stopped", $transportName));
+ }
+
+ /**
+ * Invoked as a TransportException is thrown in the Transport system.
+ *
+ * @param Swift_Events_TransportExceptionEvent $evt
+ */
+ public function exceptionThrown(Swift_Events_TransportExceptionEvent $evt)
+ {
+ $e = $evt->getException();
+ $message = $e->getMessage();
+ $this->_logger->add(sprintf("!! %s", $message));
+ $message .= PHP_EOL;
+ $message .= 'Log data:'.PHP_EOL;
+ $message .= $this->_logger->dump();
+ $evt->cancelBubble();
+ throw new Swift_TransportException($message);
+ }
+}
diff --git a/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Plugins/Loggers/ArrayLogger.php b/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Plugins/Loggers/ArrayLogger.php
new file mode 100644
index 00000000..f1739e8e
--- /dev/null
+++ b/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Plugins/Loggers/ArrayLogger.php
@@ -0,0 +1,72 @@
+_size = $size;
+ }
+
+ /**
+ * Add a log entry.
+ *
+ * @param string $entry
+ */
+ public function add($entry)
+ {
+ $this->_log[] = $entry;
+ while (count($this->_log) > $this->_size) {
+ array_shift($this->_log);
+ }
+ }
+
+ /**
+ * Clear the log contents.
+ */
+ public function clear()
+ {
+ $this->_log = array();
+ }
+
+ /**
+ * Get this log as a string.
+ *
+ * @return string
+ */
+ public function dump()
+ {
+ return implode(PHP_EOL, $this->_log);
+ }
+}
diff --git a/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Plugins/Loggers/EchoLogger.php b/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Plugins/Loggers/EchoLogger.php
new file mode 100644
index 00000000..e8b6c18a
--- /dev/null
+++ b/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Plugins/Loggers/EchoLogger.php
@@ -0,0 +1,58 @@
+_isHtml = $isHtml;
+ }
+
+ /**
+ * Add a log entry.
+ *
+ * @param string $entry
+ */
+ public function add($entry)
+ {
+ if ($this->_isHtml) {
+ printf('%s%s%s', htmlspecialchars($entry, ENT_QUOTES), ' ', PHP_EOL);
+ } else {
+ printf('%s%s', $entry, PHP_EOL);
+ }
+ }
+
+ /**
+ * Not implemented.
+ */
+ public function clear()
+ {
+ }
+
+ /**
+ * Not implemented.
+ */
+ public function dump()
+ {
+ }
+}
diff --git a/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Plugins/MessageLogger.php b/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Plugins/MessageLogger.php
new file mode 100644
index 00000000..a02ad98e
--- /dev/null
+++ b/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Plugins/MessageLogger.php
@@ -0,0 +1,75 @@
+messages = array();
+ }
+
+ /**
+ * Get the message list
+ *
+ * @return array
+ */
+ public function getMessages()
+ {
+ return $this->messages;
+ }
+
+ /**
+ * Get the message count
+ *
+ * @return int count
+ */
+ public function countMessages()
+ {
+ return count($this->messages);
+ }
+
+ /**
+ * Empty the message list
+ *
+ */
+ public function clear()
+ {
+ $this->messages = array();
+ }
+
+ /**
+ * Invoked immediately before the Message is sent.
+ *
+ * @param Swift_Events_SendEvent $evt
+ */
+ public function beforeSendPerformed(Swift_Events_SendEvent $evt)
+ {
+ $this->messages[] = clone $evt->getMessage();
+ }
+
+ /**
+ * Invoked immediately after the Message is sent.
+ *
+ * @param Swift_Events_SendEvent $evt
+ */
+ public function sendPerformed(Swift_Events_SendEvent $evt)
+ {
+ }
+}
diff --git a/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Plugins/Pop/Pop3Connection.php b/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Plugins/Pop/Pop3Connection.php
new file mode 100644
index 00000000..1e18016a
--- /dev/null
+++ b/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Plugins/Pop/Pop3Connection.php
@@ -0,0 +1,31 @@
+_host = $host;
+ $this->_port = $port;
+ $this->_crypto = $crypto;
+ }
+
+ /**
+ * Create a new PopBeforeSmtpPlugin for $host and $port.
+ *
+ * @param string $host
+ * @param int $port
+ * @param string $crypto as "tls" or "ssl"
+ *
+ * @return Swift_Plugins_PopBeforeSmtpPlugin
+ */
+ public static function newInstance($host, $port = 110, $crypto = null)
+ {
+ return new self($host, $port, $crypto);
+ }
+
+ /**
+ * Set a Pop3Connection to delegate to instead of connecting directly.
+ *
+ * @param Swift_Plugins_Pop_Pop3Connection $connection
+ *
+ * @return Swift_Plugins_PopBeforeSmtpPlugin
+ */
+ public function setConnection(Swift_Plugins_Pop_Pop3Connection $connection)
+ {
+ $this->_connection = $connection;
+
+ return $this;
+ }
+
+ /**
+ * Bind this plugin to a specific SMTP transport instance.
+ *
+ * @param Swift_Transport
+ */
+ public function bindSmtp(Swift_Transport $smtp)
+ {
+ $this->_transport = $smtp;
+ }
+
+ /**
+ * Set the connection timeout in seconds (default 10).
+ *
+ * @param int $timeout
+ *
+ * @return Swift_Plugins_PopBeforeSmtpPlugin
+ */
+ public function setTimeout($timeout)
+ {
+ $this->_timeout = (int) $timeout;
+
+ return $this;
+ }
+
+ /**
+ * Set the username to use when connecting (if needed).
+ *
+ * @param string $username
+ *
+ * @return Swift_Plugins_PopBeforeSmtpPlugin
+ */
+ public function setUsername($username)
+ {
+ $this->_username = $username;
+
+ return $this;
+ }
+
+ /**
+ * Set the password to use when connecting (if needed).
+ *
+ * @param string $password
+ *
+ * @return Swift_Plugins_PopBeforeSmtpPlugin
+ */
+ public function setPassword($password)
+ {
+ $this->_password = $password;
+
+ return $this;
+ }
+
+ /**
+ * Connect to the POP3 host and authenticate.
+ *
+ * @throws Swift_Plugins_Pop_Pop3Exception if connection fails
+ */
+ public function connect()
+ {
+ if (isset($this->_connection)) {
+ $this->_connection->connect();
+ } else {
+ if (!isset($this->_socket)) {
+ if (!$socket = fsockopen(
+ $this->_getHostString(), $this->_port, $errno, $errstr, $this->_timeout)) {
+ throw new Swift_Plugins_Pop_Pop3Exception(
+ sprintf('Failed to connect to POP3 host [%s]: %s', $this->_host, $errstr)
+ );
+ }
+ $this->_socket = $socket;
+
+ if (false === $greeting = fgets($this->_socket)) {
+ throw new Swift_Plugins_Pop_Pop3Exception(
+ sprintf('Failed to connect to POP3 host [%s]', trim($greeting))
+ );
+ }
+
+ $this->_assertOk($greeting);
+
+ if ($this->_username) {
+ $this->_command(sprintf("USER %s\r\n", $this->_username));
+ $this->_command(sprintf("PASS %s\r\n", $this->_password));
+ }
+ }
+ }
+ }
+
+ /**
+ * Disconnect from the POP3 host.
+ */
+ public function disconnect()
+ {
+ if (isset($this->_connection)) {
+ $this->_connection->disconnect();
+ } else {
+ $this->_command("QUIT\r\n");
+ if (!fclose($this->_socket)) {
+ throw new Swift_Plugins_Pop_Pop3Exception(
+ sprintf('POP3 host [%s] connection could not be stopped', $this->_host)
+ );
+ }
+ $this->_socket = null;
+ }
+ }
+
+ /**
+ * Invoked just before a Transport is started.
+ *
+ * @param Swift_Events_TransportChangeEvent $evt
+ */
+ public function beforeTransportStarted(Swift_Events_TransportChangeEvent $evt)
+ {
+ if (isset($this->_transport)) {
+ if ($this->_transport !== $evt->getTransport()) {
+ return;
+ }
+ }
+
+ $this->connect();
+ $this->disconnect();
+ }
+
+ /**
+ * Not used.
+ */
+ public function transportStarted(Swift_Events_TransportChangeEvent $evt)
+ {
+ }
+
+ /**
+ * Not used.
+ */
+ public function beforeTransportStopped(Swift_Events_TransportChangeEvent $evt)
+ {
+ }
+
+ /**
+ * Not used.
+ */
+ public function transportStopped(Swift_Events_TransportChangeEvent $evt)
+ {
+ }
+
+ private function _command($command)
+ {
+ if (!fwrite($this->_socket, $command)) {
+ throw new Swift_Plugins_Pop_Pop3Exception(
+ sprintf('Failed to write command [%s] to POP3 host', trim($command))
+ );
+ }
+
+ if (false === $response = fgets($this->_socket)) {
+ throw new Swift_Plugins_Pop_Pop3Exception(
+ sprintf('Failed to read from POP3 host after command [%s]', trim($command))
+ );
+ }
+
+ $this->_assertOk($response);
+
+ return $response;
+ }
+
+ private function _assertOk($response)
+ {
+ if (substr($response, 0, 3) != '+OK') {
+ throw new Swift_Plugins_Pop_Pop3Exception(
+ sprintf('POP3 command failed [%s]', trim($response))
+ );
+ }
+ }
+
+ private function _getHostString()
+ {
+ $host = $this->_host;
+ switch (strtolower($this->_crypto)) {
+ case 'ssl':
+ $host = 'ssl://'.$host;
+ break;
+
+ case 'tls':
+ $host = 'tls://'.$host;
+ break;
+ }
+
+ return $host;
+ }
+}
diff --git a/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Plugins/RedirectingPlugin.php b/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Plugins/RedirectingPlugin.php
new file mode 100644
index 00000000..cc86134c
--- /dev/null
+++ b/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Plugins/RedirectingPlugin.php
@@ -0,0 +1,211 @@
+_recipient = $recipient;
+ $this->_whitelist = $whitelist;
+ }
+
+ /**
+ * Set the recipient of all messages.
+ *
+ * @param mixed $recipient
+ */
+ public function setRecipient($recipient)
+ {
+ $this->_recipient = $recipient;
+ }
+
+ /**
+ * Get the recipient of all messages.
+ *
+ * @return mixed
+ */
+ public function getRecipient()
+ {
+ return $this->_recipient;
+ }
+
+ /**
+ * Set a list of regular expressions to whitelist certain recipients
+ *
+ * @param array $whitelist
+ */
+ public function setWhitelist(array $whitelist)
+ {
+ $this->_whitelist = $whitelist;
+ }
+
+ /**
+ * Get the whitelist
+ *
+ * @return array
+ */
+ public function getWhitelist()
+ {
+ return $this->_whitelist;
+ }
+
+ /**
+ * Invoked immediately before the Message is sent.
+ *
+ * @param Swift_Events_SendEvent $evt
+ */
+ public function beforeSendPerformed(Swift_Events_SendEvent $evt)
+ {
+ $message = $evt->getMessage();
+ $headers = $message->getHeaders();
+
+ // conditionally save current recipients
+
+ if ($headers->has('to')) {
+ $headers->addMailboxHeader('X-Swift-To', $message->getTo());
+ }
+
+ if ($headers->has('cc')) {
+ $headers->addMailboxHeader('X-Swift-Cc', $message->getCc());
+ }
+
+ if ($headers->has('bcc')) {
+ $headers->addMailboxHeader('X-Swift-Bcc', $message->getBcc());
+ }
+
+ // Filter remaining headers against whitelist
+ $this->_filterHeaderSet($headers, 'To');
+ $this->_filterHeaderSet($headers, 'Cc');
+ $this->_filterHeaderSet($headers, 'Bcc');
+
+ // Add each hard coded recipient
+ $to = $message->getTo();
+ if (null === $to) {
+ $to = array();
+ }
+
+ foreach ( (array) $this->_recipient as $recipient) {
+ if (!array_key_exists($recipient, $to)) {
+ $message->addTo($recipient);
+ }
+ }
+ }
+
+ /**
+ * Filter header set against a whitelist of regular expressions
+ *
+ * @param Swift_Mime_HeaderSet $headerSet
+ * @param string $type
+ */
+ private function _filterHeaderSet(Swift_Mime_HeaderSet $headerSet, $type)
+ {
+ foreach ($headerSet->getAll($type) as $headers) {
+ $headers->setNameAddresses($this->_filterNameAddresses($headers->getNameAddresses()));
+ }
+ }
+
+ /**
+ * Filtered list of addresses => name pairs
+ *
+ * @param array $recipients
+ * @return array
+ */
+ private function _filterNameAddresses(array $recipients)
+ {
+ $filtered = array();
+
+ foreach ($recipients as $address => $name) {
+ if ($this->_isWhitelisted($address)) {
+ $filtered[$address] = $name;
+ }
+ }
+
+ return $filtered;
+ }
+
+ /**
+ * Matches address against whitelist of regular expressions
+ *
+ * @param $recipient
+ * @return bool
+ */
+ protected function _isWhitelisted($recipient)
+ {
+ if (in_array($recipient, (array) $this->_recipient)) {
+ return true;
+ }
+
+ foreach ($this->_whitelist as $pattern) {
+ if (preg_match($pattern, $recipient)) {
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+ /**
+ * Invoked immediately after the Message is sent.
+ *
+ * @param Swift_Events_SendEvent $evt
+ */
+ public function sendPerformed(Swift_Events_SendEvent $evt)
+ {
+ $this->_restoreMessage($evt->getMessage());
+ }
+
+ private function _restoreMessage(Swift_Mime_Message $message)
+ {
+ // restore original headers
+ $headers = $message->getHeaders();
+
+ if ($headers->has('X-Swift-To')) {
+ $message->setTo($headers->get('X-Swift-To')->getNameAddresses());
+ $headers->removeAll('X-Swift-To');
+ } else {
+ $message->setTo(null);
+ }
+
+ if ($headers->has('X-Swift-Cc')) {
+ $message->setCc($headers->get('X-Swift-Cc')->getNameAddresses());
+ $headers->removeAll('X-Swift-Cc');
+ }
+
+ if ($headers->has('X-Swift-Bcc')) {
+ $message->setBcc($headers->get('X-Swift-Bcc')->getNameAddresses());
+ $headers->removeAll('X-Swift-Bcc');
+ }
+ }
+}
diff --git a/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Plugins/Reporter.php b/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Plugins/Reporter.php
new file mode 100644
index 00000000..294b547d
--- /dev/null
+++ b/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Plugins/Reporter.php
@@ -0,0 +1,32 @@
+_reporter = $reporter;
+ }
+
+ /**
+ * Not used.
+ */
+ public function beforeSendPerformed(Swift_Events_SendEvent $evt)
+ {
+ }
+
+ /**
+ * Invoked immediately after the Message is sent.
+ *
+ * @param Swift_Events_SendEvent $evt
+ */
+ public function sendPerformed(Swift_Events_SendEvent $evt)
+ {
+ $message = $evt->getMessage();
+ $failures = array_flip($evt->getFailedRecipients());
+ foreach ((array) $message->getTo() as $address => $null) {
+ $this->_reporter->notify(
+ $message, $address, (array_key_exists($address, $failures)
+ ? Swift_Plugins_Reporter::RESULT_FAIL
+ : Swift_Plugins_Reporter::RESULT_PASS)
+ );
+ }
+ foreach ((array) $message->getCc() as $address => $null) {
+ $this->_reporter->notify(
+ $message, $address, (array_key_exists($address, $failures)
+ ? Swift_Plugins_Reporter::RESULT_FAIL
+ : Swift_Plugins_Reporter::RESULT_PASS)
+ );
+ }
+ foreach ((array) $message->getBcc() as $address => $null) {
+ $this->_reporter->notify(
+ $message, $address, (array_key_exists($address, $failures)
+ ? Swift_Plugins_Reporter::RESULT_FAIL
+ : Swift_Plugins_Reporter::RESULT_PASS)
+ );
+ }
+ }
+}
diff --git a/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Plugins/Reporters/HitReporter.php b/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Plugins/Reporters/HitReporter.php
new file mode 100644
index 00000000..ea60f51d
--- /dev/null
+++ b/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Plugins/Reporters/HitReporter.php
@@ -0,0 +1,59 @@
+_failures_cache[$address])) {
+ $this->_failures[] = $address;
+ $this->_failures_cache[$address] = true;
+ }
+ }
+
+ /**
+ * Get an array of addresses for which delivery failed.
+ *
+ * @return array
+ */
+ public function getFailedRecipients()
+ {
+ return $this->_failures;
+ }
+
+ /**
+ * Clear the buffer (empty the list).
+ */
+ public function clear()
+ {
+ $this->_failures = $this->_failures_cache = array();
+ }
+}
diff --git a/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Plugins/Reporters/HtmlReporter.php b/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Plugins/Reporters/HtmlReporter.php
new file mode 100644
index 00000000..817e32f5
--- /dev/null
+++ b/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Plugins/Reporters/HtmlReporter.php
@@ -0,0 +1,39 @@
+".PHP_EOL;
+ echo "PASS ".$address.PHP_EOL;
+ echo "".PHP_EOL;
+ flush();
+ } else {
+ echo "
".PHP_EOL;
+ flush();
+ }
+ }
+}
diff --git a/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Plugins/Sleeper.php b/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Plugins/Sleeper.php
new file mode 100644
index 00000000..38727052
--- /dev/null
+++ b/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Plugins/Sleeper.php
@@ -0,0 +1,24 @@
+_rate = $rate;
+ $this->_mode = $mode;
+ $this->_sleeper = $sleeper;
+ $this->_timer = $timer;
+ }
+
+ /**
+ * Invoked immediately before the Message is sent.
+ *
+ * @param Swift_Events_SendEvent $evt
+ */
+ public function beforeSendPerformed(Swift_Events_SendEvent $evt)
+ {
+ $time = $this->getTimestamp();
+ if (!isset($this->_start)) {
+ $this->_start = $time;
+ }
+ $duration = $time - $this->_start;
+
+ switch ($this->_mode) {
+ case self::BYTES_PER_MINUTE :
+ $sleep = $this->_throttleBytesPerMinute($duration);
+ break;
+ case self::MESSAGES_PER_SECOND :
+ $sleep = $this->_throttleMessagesPerSecond($duration);
+ break;
+ case self::MESSAGES_PER_MINUTE :
+ $sleep = $this->_throttleMessagesPerMinute($duration);
+ break;
+ default :
+ $sleep = 0;
+ break;
+ }
+
+ if ($sleep > 0) {
+ $this->sleep($sleep);
+ }
+ }
+
+ /**
+ * Invoked when a Message is sent.
+ *
+ * @param Swift_Events_SendEvent $evt
+ */
+ public function sendPerformed(Swift_Events_SendEvent $evt)
+ {
+ parent::sendPerformed($evt);
+ ++$this->_messages;
+ }
+
+ /**
+ * Sleep for $seconds.
+ *
+ * @param int $seconds
+ */
+ public function sleep($seconds)
+ {
+ if (isset($this->_sleeper)) {
+ $this->_sleeper->sleep($seconds);
+ } else {
+ sleep($seconds);
+ }
+ }
+
+ /**
+ * Get the current UNIX timestamp.
+ *
+ * @return int
+ */
+ public function getTimestamp()
+ {
+ if (isset($this->_timer)) {
+ return $this->_timer->getTimestamp();
+ } else {
+ return time();
+ }
+ }
+
+ /**
+ * Get a number of seconds to sleep for.
+ *
+ * @param int $timePassed
+ *
+ * @return int
+ */
+ private function _throttleBytesPerMinute($timePassed)
+ {
+ $expectedDuration = $this->getBytesOut() / ($this->_rate / 60);
+
+ return (int) ceil($expectedDuration - $timePassed);
+ }
+
+ /**
+ * Get a number of seconds to sleep for.
+ *
+ * @param int $timePassed
+ *
+ * @return int
+ */
+ private function _throttleMessagesPerSecond($timePassed)
+ {
+ $expectedDuration = $this->_messages / ($this->_rate);
+
+ return (int) ceil($expectedDuration - $timePassed);
+ }
+
+ /**
+ * Get a number of seconds to sleep for.
+ *
+ * @param int $timePassed
+ *
+ * @return int
+ */
+ private function _throttleMessagesPerMinute($timePassed)
+ {
+ $expectedDuration = $this->_messages / ($this->_rate / 60);
+
+ return (int) ceil($expectedDuration - $timePassed);
+ }
+}
diff --git a/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Plugins/Timer.php b/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Plugins/Timer.php
new file mode 100644
index 00000000..a05e3181
--- /dev/null
+++ b/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Plugins/Timer.php
@@ -0,0 +1,24 @@
+register('properties.charset')->asValue($charset);
+
+ return $this;
+ }
+
+ /**
+ * Set the directory where temporary files can be saved.
+ *
+ * @param string $dir
+ *
+ * @return Swift_Preferences
+ */
+ public function setTempDir($dir)
+ {
+ Swift_DependencyContainer::getInstance()
+ ->register('tempdir')->asValue($dir);
+
+ return $this;
+ }
+
+ /**
+ * Set the type of cache to use (i.e. "disk" or "array").
+ *
+ * @param string $type
+ *
+ * @return Swift_Preferences
+ */
+ public function setCacheType($type)
+ {
+ Swift_DependencyContainer::getInstance()
+ ->register('cache')->asAliasOf(sprintf('cache.%s', $type));
+
+ return $this;
+ }
+
+ /**
+ * Set the QuotedPrintable dot escaper preference.
+ *
+ * @param bool $dotEscape
+ *
+ * @return Swift_Preferences
+ */
+ public function setQPDotEscape($dotEscape)
+ {
+ $dotEscape = !empty($dotEscape);
+ Swift_DependencyContainer::getInstance()
+ ->register('mime.qpcontentencoder')
+ ->asNewInstanceOf('Swift_Mime_ContentEncoder_QpContentEncoder')
+ ->withDependencies(array('mime.charstream', 'mime.bytecanonicalizer'))
+ ->addConstructorValue($dotEscape);
+
+ return $this;
+ }
+}
diff --git a/vendor/swiftmailer/swiftmailer/lib/classes/Swift/ReplacementFilterFactory.php b/vendor/swiftmailer/swiftmailer/lib/classes/Swift/ReplacementFilterFactory.php
new file mode 100644
index 00000000..ca9e4f60
--- /dev/null
+++ b/vendor/swiftmailer/swiftmailer/lib/classes/Swift/ReplacementFilterFactory.php
@@ -0,0 +1,27 @@
+createDependenciesFor('transport.sendmail')
+ );
+
+ $this->setCommand($command);
+ }
+
+ /**
+ * Create a new SendmailTransport instance.
+ *
+ * @param string $command
+ *
+ * @return Swift_SendmailTransport
+ */
+ public static function newInstance($command = '/usr/sbin/sendmail -bs')
+ {
+ return new self($command);
+ }
+}
diff --git a/vendor/swiftmailer/swiftmailer/lib/classes/Swift/SignedMessage.php b/vendor/swiftmailer/swiftmailer/lib/classes/Swift/SignedMessage.php
new file mode 100644
index 00000000..66e1c68c
--- /dev/null
+++ b/vendor/swiftmailer/swiftmailer/lib/classes/Swift/SignedMessage.php
@@ -0,0 +1,22 @@
+
+ * @deprecated
+ */
+class Swift_SignedMessage extends Swift_Message
+{
+}
diff --git a/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Signer.php b/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Signer.php
new file mode 100644
index 00000000..7448179f
--- /dev/null
+++ b/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Signer.php
@@ -0,0 +1,20 @@
+
+ */
+interface Swift_Signer
+{
+ public function reset();
+}
diff --git a/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Signers/BodySigner.php b/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Signers/BodySigner.php
new file mode 100644
index 00000000..93dc8ac7
--- /dev/null
+++ b/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Signers/BodySigner.php
@@ -0,0 +1,33 @@
+
+ */
+interface Swift_Signers_BodySigner extends Swift_Signer
+{
+ /**
+ * Change the Swift_Signed_Message to apply the singing.
+ *
+ * @param Swift_Message $message
+ *
+ * @return Swift_Signers_BodySigner
+ */
+ public function signMessage(Swift_Message $message);
+
+ /**
+ * Return the list of header a signer might tamper
+ *
+ * @return array
+ */
+ public function getAlteredHeaders();
+}
diff --git a/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Signers/DKIMSigner.php b/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Signers/DKIMSigner.php
new file mode 100644
index 00000000..220c3ac9
--- /dev/null
+++ b/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Signers/DKIMSigner.php
@@ -0,0 +1,688 @@
+
+ */
+class Swift_Signers_DKIMSigner implements Swift_Signers_HeaderSigner
+{
+ /**
+ * PrivateKey
+ *
+ * @var string
+ */
+ protected $_privateKey;
+
+ /**
+ * DomainName
+ *
+ * @var string
+ */
+ protected $_domainName;
+
+ /**
+ * Selector
+ *
+ * @var string
+ */
+ protected $_selector;
+
+ /**
+ * Hash algorithm used
+ *
+ * @var string
+ */
+ protected $_hashAlgorithm = 'rsa-sha1';
+
+ /**
+ * Body canon method
+ *
+ * @var string
+ */
+ protected $_bodyCanon = 'simple';
+
+ /**
+ * Header canon method
+ *
+ * @var string
+ */
+ protected $_headerCanon = 'simple';
+
+ /**
+ * Headers not being signed
+ *
+ * @var array
+ */
+ protected $_ignoredHeaders = array();
+
+ /**
+ * Signer identity
+ *
+ * @var unknown_type
+ */
+ protected $_signerIdentity;
+
+ /**
+ * BodyLength
+ *
+ * @var int
+ */
+ protected $_bodyLen = 0;
+
+ /**
+ * Maximum signedLen
+ *
+ * @var int
+ */
+ protected $_maxLen = PHP_INT_MAX;
+
+ /**
+ * Embbed bodyLen in signature
+ *
+ * @var bool
+ */
+ protected $_showLen = false;
+
+ /**
+ * When the signature has been applied (true means time()), false means not embedded
+ *
+ * @var mixed
+ */
+ protected $_signatureTimestamp = true;
+
+ /**
+ * When will the signature expires false means not embedded, if sigTimestamp is auto
+ * Expiration is relative, otherwhise it's absolute
+ *
+ * @var int
+ */
+ protected $_signatureExpiration = false;
+
+ /**
+ * Must we embed signed headers?
+ *
+ * @var bool
+ */
+ protected $_debugHeaders = false;
+
+ // work variables
+ /**
+ * Headers used to generate hash
+ *
+ * @var array
+ */
+ protected $_signedHeaders = array();
+
+ /**
+ * If debugHeaders is set store debugDatas here
+ *
+ * @var string
+ */
+ private $_debugHeadersData = '';
+
+ /**
+ * Stores the bodyHash
+ *
+ * @var string
+ */
+ private $_bodyHash = '';
+
+ /**
+ * Stores the signature header
+ *
+ * @var Swift_Mime_Headers_ParameterizedHeader
+ */
+ protected $_dkimHeader;
+
+ /**
+ * Hash Handler
+ *
+ * @var hash_ressource
+ */
+ private $_headerHashHandler;
+
+ private $_bodyHashHandler;
+
+ private $_headerHash;
+
+ private $_headerCanonData = '';
+
+ private $_bodyCanonEmptyCounter = 0;
+
+ private $_bodyCanonIgnoreStart = 2;
+
+ private $_bodyCanonSpace = false;
+
+ private $_bodyCanonLastChar = null;
+
+ private $_bodyCanonLine = '';
+
+ private $_bound = array();
+
+ /**
+ * Constructor
+ *
+ * @param string $privateKey
+ * @param string $domainName
+ * @param string $selector
+ */
+ public function __construct($privateKey, $domainName, $selector)
+ {
+ $this->_privateKey = $privateKey;
+ $this->_domainName = $domainName;
+ $this->_signerIdentity = '@'.$domainName;
+ $this->_selector = $selector;
+ }
+
+ /**
+ * Instanciate DKIMSigner
+ *
+ * @param string $privateKey
+ * @param string $domainName
+ * @param string $selector
+ * @return Swift_Signers_DKIMSigner
+ */
+ public static function newInstance($privateKey, $domainName, $selector)
+ {
+ return new static($privateKey, $domainName, $selector);
+ }
+
+ /**
+ * Reset the Signer
+ * @see Swift_Signer::reset()
+ */
+ public function reset()
+ {
+ $this->_headerHash = null;
+ $this->_signedHeaders = array();
+ $this->_headerHashHandler = null;
+ $this->_bodyHash = null;
+ $this->_bodyHashHandler = null;
+ $this->_bodyCanonIgnoreStart = 2;
+ $this->_bodyCanonEmptyCounter = 0;
+ $this->_bodyCanonLastChar = null;
+ $this->_bodyCanonSpace = false;
+ }
+
+ /**
+ * Writes $bytes to the end of the stream.
+ *
+ * Writing may not happen immediately if the stream chooses to buffer. If
+ * you want to write these bytes with immediate effect, call {@link commit()}
+ * after calling write().
+ *
+ * This method returns the sequence ID of the write (i.e. 1 for first, 2 for
+ * second, etc etc).
+ *
+ * @param string $bytes
+ * @return int
+ * @throws Swift_IoException
+ */
+ public function write($bytes)
+ {
+ $this->_canonicalizeBody($bytes);
+ foreach ($this->_bound as $is) {
+ $is->write($bytes);
+ }
+ }
+
+ /**
+ * For any bytes that are currently buffered inside the stream, force them
+ * off the buffer.
+ *
+ * @throws Swift_IoException
+ */
+ public function commit()
+ {
+ // Nothing to do
+ return;
+ }
+
+ /**
+ * Attach $is to this stream.
+ * The stream acts as an observer, receiving all data that is written.
+ * All {@link write()} and {@link flushBuffers()} operations will be mirrored.
+ *
+ * @param Swift_InputByteStream $is
+ */
+ public function bind(Swift_InputByteStream $is)
+ {
+ // Don't have to mirror anything
+ $this->_bound[] = $is;
+
+ return;
+ }
+
+ /**
+ * Remove an already bound stream.
+ * If $is is not bound, no errors will be raised.
+ * If the stream currently has any buffered data it will be written to $is
+ * before unbinding occurs.
+ *
+ * @param Swift_InputByteStream $is
+ */
+ public function unbind(Swift_InputByteStream $is)
+ {
+ // Don't have to mirror anything
+ foreach ($this->_bound as $k => $stream) {
+ if ($stream === $is) {
+ unset($this->_bound[$k]);
+
+ return;
+ }
+ }
+
+ return;
+ }
+
+ /**
+ * Flush the contents of the stream (empty it) and set the internal pointer
+ * to the beginning.
+ *
+ * @throws Swift_IoException
+ */
+ public function flushBuffers()
+ {
+ $this->reset();
+ }
+
+ /**
+ * Set hash_algorithm, must be one of rsa-sha256 | rsa-sha1 defaults to rsa-sha256
+ *
+ * @param string $hash
+ * @return Swift_Signers_DKIMSigner
+ */
+ public function setHashAlgorithm($hash)
+ {
+ // Unable to sign with rsa-sha256
+ if ($hash == 'rsa-sha1') {
+ $this->_hashAlgorithm = 'rsa-sha1';
+ } else {
+ $this->_hashAlgorithm = 'rsa-sha256';
+ }
+
+ return $this;
+ }
+
+ /**
+ * Set the body canonicalization algorithm
+ *
+ * @param string $canon
+ * @return Swift_Signers_DKIMSigner
+ */
+ public function setBodyCanon($canon)
+ {
+ if ($canon == 'relaxed') {
+ $this->_bodyCanon = 'relaxed';
+ } else {
+ $this->_bodyCanon = 'simple';
+ }
+
+ return $this;
+ }
+
+ /**
+ * Set the header canonicalization algorithm
+ *
+ * @param string $canon
+ * @return Swift_Signers_DKIMSigner
+ */
+ public function setHeaderCanon($canon)
+ {
+ if ($canon == 'relaxed') {
+ $this->_headerCanon = 'relaxed';
+ } else {
+ $this->_headerCanon = 'simple';
+ }
+
+ return $this;
+ }
+
+ /**
+ * Set the signer identity
+ *
+ * @param string $identity
+ * @return Swift_Signers_DKIMSigner
+ */
+ public function setSignerIdentity($identity)
+ {
+ $this->_signerIdentity = $identity;
+
+ return $this;
+ }
+
+ /**
+ * Set the length of the body to sign
+ *
+ * @param mixed $len (bool or int)
+ * @return Swift_Signers_DKIMSigner
+ */
+ public function setBodySignedLen($len)
+ {
+ if ($len === true) {
+ $this->_showLen = true;
+ $this->_maxLen = PHP_INT_MAX;
+ } elseif ($len === false) {
+ $this->showLen = false;
+ $this->_maxLen = PHP_INT_MAX;
+ } else {
+ $this->_showLen = true;
+ $this->_maxLen = (int) $len;
+ }
+
+ return $this;
+ }
+
+ /**
+ * Set the signature timestamp
+ *
+ * @param timestamp $time
+ * @return Swift_Signers_DKIMSigner
+ */
+ public function setSignatureTimestamp($time)
+ {
+ $this->_signatureTimestamp = $time;
+
+ return $this;
+ }
+
+ /**
+ * Set the signature expiration timestamp
+ *
+ * @param timestamp $time
+ * @return Swift_Signers_DKIMSigner
+ */
+ public function setSignatureExpiration($time)
+ {
+ $this->_signatureExpiration = $time;
+
+ return $this;
+ }
+
+ /**
+ * Enable / disable the DebugHeaders
+ *
+ * @param bool $debug
+ * @return Swift_Signers_DKIMSigner
+ */
+ public function setDebugHeaders($debug)
+ {
+ $this->_debugHeaders = (bool) $debug;
+
+ return $this;
+ }
+
+ /**
+ * Start Body
+ *
+ */
+ public function startBody()
+ {
+ // Init
+ switch ($this->_hashAlgorithm) {
+ case 'rsa-sha256' :
+ $this->_bodyHashHandler = hash_init('sha256');
+ break;
+ case 'rsa-sha1' :
+ $this->_bodyHashHandler = hash_init('sha1');
+ break;
+ }
+ $this->_bodyCanonLine = '';
+ }
+
+ /**
+ * End Body
+ *
+ */
+ public function endBody()
+ {
+ $this->_endOfBody();
+ }
+
+ /**
+ * Returns the list of Headers Tampered by this plugin
+ *
+ * @return array
+ */
+ public function getAlteredHeaders()
+ {
+ if ($this->_debugHeaders) {
+ return array('DKIM-Signature', 'X-DebugHash');
+ } else {
+ return array('DKIM-Signature');
+ }
+ }
+
+ /**
+ * Adds an ignored Header
+ *
+ * @param string $header_name
+ * @return Swift_Signers_DKIMSigner
+ */
+ public function ignoreHeader($header_name)
+ {
+ $this->_ignoredHeaders[strtolower($header_name)] = true;
+
+ return $this;
+ }
+
+ /**
+ * Set the headers to sign
+ *
+ * @param Swift_Mime_HeaderSet $headers
+ * @return Swift_Signers_DKIMSigner
+ */
+ public function setHeaders(Swift_Mime_HeaderSet $headers)
+ {
+ $this->_headerCanonData = '';
+ // Loop through Headers
+ $listHeaders = $headers->listAll();
+ foreach ($listHeaders as $hName) {
+ // Check if we need to ignore Header
+ if (! isset($this->_ignoredHeaders[strtolower($hName)])) {
+ if ($headers->has($hName)) {
+ $tmp = $headers->getAll($hName);
+ foreach ($tmp as $header) {
+ if ($header->getFieldBody() != '') {
+ $this->_addHeader($header->toString());
+ $this->_signedHeaders[] = $header->getFieldName();
+ }
+ }
+ }
+ }
+ }
+
+ return $this;
+ }
+
+ /**
+ * Add the signature to the given Headers
+ *
+ * @param Swift_Mime_HeaderSet $headers
+ * @return Swift_Signers_DKIMSigner
+ */
+ public function addSignature(Swift_Mime_HeaderSet $headers)
+ {
+ // Prepare the DKIM-Signature
+ $params = array('v' => '1', 'a' => $this->_hashAlgorithm, 'bh' => base64_encode($this->_bodyHash), 'd' => $this->_domainName, 'h' => implode(': ', $this->_signedHeaders), 'i' => $this->_signerIdentity, 's' => $this->_selector);
+ if ($this->_bodyCanon != 'simple') {
+ $params['c'] = $this->_headerCanon.'/'.$this->_bodyCanon;
+ } elseif ($this->_headerCanon != 'simple') {
+ $params['c'] = $this->_headerCanon;
+ }
+ if ($this->_showLen) {
+ $params['l'] = $this->_bodyLen;
+ }
+ if ($this->_signatureTimestamp === true) {
+ $params['t'] = time();
+ if ($this->_signatureExpiration !== false) {
+ $params['x'] = $params['t'] + $this->_signatureExpiration;
+ }
+ } else {
+ if ($this->_signatureTimestamp !== false) {
+ $params['t'] = $this->_signatureTimestamp;
+ }
+ if ($this->_signatureExpiration !== false) {
+ $params['x'] = $this->_signatureExpiration;
+ }
+ }
+ if ($this->_debugHeaders) {
+ $params['z'] = implode('|', $this->_debugHeadersData);
+ }
+ $string = '';
+ foreach ($params as $k => $v) {
+ $string .= $k.'='.$v.'; ';
+ }
+ $string = trim($string);
+ $headers->addTextHeader('DKIM-Signature', $string);
+ // Add the last DKIM-Signature
+ $tmp = $headers->getAll('DKIM-Signature');
+ $this->_dkimHeader = end($tmp);
+ $this->_addHeader(trim($this->_dkimHeader->toString())."\r\n b=", true);
+ $this->_endOfHeaders();
+ if ($this->_debugHeaders) {
+ $headers->addTextHeader('X-DebugHash', base64_encode($this->_headerHash));
+ }
+ $this->_dkimHeader->setValue($string." b=".trim(chunk_split(base64_encode($this->_getEncryptedHash()), 73, " ")));
+
+ return $this;
+ }
+
+ /* Private helpers */
+
+ protected function _addHeader($header, $is_sig = false)
+ {
+ switch ($this->_headerCanon) {
+ case 'relaxed' :
+ // Prepare Header and cascade
+ $exploded = explode(':', $header, 2);
+ $name = strtolower(trim($exploded[0]));
+ $value = str_replace("\r\n", "", $exploded[1]);
+ $value = preg_replace("/[ \t][ \t]+/", " ", $value);
+ $header = $name.":".trim($value).($is_sig ? '' : "\r\n");
+ case 'simple' :
+ // Nothing to do
+ }
+ $this->_addToHeaderHash($header);
+ }
+
+ protected function _endOfHeaders()
+ {
+ //$this->_headerHash=hash_final($this->_headerHashHandler, true);
+ }
+
+ protected function _canonicalizeBody($string)
+ {
+ $len = strlen($string);
+ $canon = '';
+ $method = ($this->_bodyCanon == "relaxed");
+ for ($i = 0; $i < $len; ++$i) {
+ if ($this->_bodyCanonIgnoreStart > 0) {
+ --$this->_bodyCanonIgnoreStart;
+ continue;
+ }
+ switch ($string[$i]) {
+ case "\r" :
+ $this->_bodyCanonLastChar = "\r";
+ break;
+ case "\n" :
+ if ($this->_bodyCanonLastChar == "\r") {
+ if ($method) {
+ $this->_bodyCanonSpace = false;
+ }
+ if ($this->_bodyCanonLine == '') {
+ ++$this->_bodyCanonEmptyCounter;
+ } else {
+ $this->_bodyCanonLine = '';
+ $canon .= "\r\n";
+ }
+ } else {
+ // Wooops Error
+ // todo handle it but should never happen
+ }
+ break;
+ case " " :
+ case "\t" :
+ if ($method) {
+ $this->_bodyCanonSpace = true;
+ break;
+ }
+ default :
+ if ($this->_bodyCanonEmptyCounter > 0) {
+ $canon .= str_repeat("\r\n", $this->_bodyCanonEmptyCounter);
+ $this->_bodyCanonEmptyCounter = 0;
+ }
+ if ($this->_bodyCanonSpace) {
+ $this->_bodyCanonLine .= ' ';
+ $canon .= ' ';
+ $this->_bodyCanonSpace = false;
+ }
+ $this->_bodyCanonLine .= $string[$i];
+ $canon .= $string[$i];
+ }
+ }
+ $this->_addToBodyHash($canon);
+ }
+
+ protected function _endOfBody()
+ {
+ // Add trailing Line return if last line is non empty
+ if (strlen($this->_bodyCanonLine) > 0) {
+ $this->_addToBodyHash("\r\n");
+ }
+ $this->_bodyHash = hash_final($this->_bodyHashHandler, true);
+ }
+
+ private function _addToBodyHash($string)
+ {
+ $len = strlen($string);
+ if ($len > ($new_len = ($this->_maxLen - $this->_bodyLen))) {
+ $string = substr($string, 0, $new_len);
+ $len = $new_len;
+ }
+ hash_update($this->_bodyHashHandler, $string);
+ $this->_bodyLen += $len;
+ }
+
+ private function _addToHeaderHash($header)
+ {
+ if ($this->_debugHeaders) {
+ $this->_debugHeadersData[] = trim($header);
+ }
+ $this->_headerCanonData .= $header;
+ }
+
+ /**
+ * @throws Swift_SwiftException
+ * @return string
+ */
+ private function _getEncryptedHash()
+ {
+ $signature = '';
+ switch ($this->_hashAlgorithm) {
+ case 'rsa-sha1':
+ $algorithm = OPENSSL_ALGO_SHA1;
+ break;
+ case 'rsa-sha256':
+ $algorithm = OPENSSL_ALGO_SHA256;
+ break;
+ }
+ $pkeyId = openssl_get_privatekey($this->_privateKey);
+ if (!$pkeyId) {
+ throw new Swift_SwiftException('Unable to load DKIM Private Key ['.openssl_error_string().']');
+ }
+ if (openssl_sign($this->_headerCanonData, $signature, $pkeyId, $algorithm)) {
+ return $signature;
+ }
+ throw new Swift_SwiftException('Unable to sign DKIM Hash ['.openssl_error_string().']');
+ }
+}
diff --git a/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Signers/DomainKeySigner.php b/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Signers/DomainKeySigner.php
new file mode 100644
index 00000000..b52ffdf4
--- /dev/null
+++ b/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Signers/DomainKeySigner.php
@@ -0,0 +1,512 @@
+
+ */
+class Swift_Signers_DomainKeySigner implements Swift_Signers_HeaderSigner
+{
+ /**
+ * PrivateKey
+ *
+ * @var string
+ */
+ protected $_privateKey;
+
+ /**
+ * DomainName
+ *
+ * @var string
+ */
+ protected $_domainName;
+
+ /**
+ * Selector
+ *
+ * @var string
+ */
+ protected $_selector;
+
+ /**
+ * Hash algorithm used
+ *
+ * @var string
+ */
+ protected $_hashAlgorithm = 'rsa-sha1';
+
+ /**
+ * Canonisation method
+ *
+ * @var string
+ */
+ protected $_canon = 'simple';
+
+ /**
+ * Headers not being signed
+ *
+ * @var array
+ */
+ protected $_ignoredHeaders = array();
+
+ /**
+ * Signer identity
+ *
+ * @var string
+ */
+ protected $_signerIdentity;
+
+ /**
+ * Must we embed signed headers?
+ *
+ * @var bool
+ */
+ protected $_debugHeaders = false;
+
+ // work variables
+ /**
+ * Headers used to generate hash
+ *
+ * @var array
+ */
+ private $_signedHeaders = array();
+
+ /**
+ * Stores the signature header
+ *
+ * @var Swift_Mime_Headers_ParameterizedHeader
+ */
+ protected $_domainKeyHeader;
+
+ /**
+ * Hash Handler
+ *
+ * @var resource|null
+ */
+ private $_hashHandler;
+
+ private $_hash;
+
+ private $_canonData = '';
+
+ private $_bodyCanonEmptyCounter = 0;
+
+ private $_bodyCanonIgnoreStart = 2;
+
+ private $_bodyCanonSpace = false;
+
+ private $_bodyCanonLastChar = null;
+
+ private $_bodyCanonLine = '';
+
+ private $_bound = array();
+
+ /**
+ * Constructor
+ *
+ * @param string $privateKey
+ * @param string $domainName
+ * @param string $selector
+ */
+ public function __construct($privateKey, $domainName, $selector)
+ {
+ $this->_privateKey = $privateKey;
+ $this->_domainName = $domainName;
+ $this->_signerIdentity = '@'.$domainName;
+ $this->_selector = $selector;
+ }
+
+ /**
+ * Instanciate DomainKeySigner
+ *
+ * @param string $privateKey
+ * @param string $domainName
+ * @param string $selector
+ * @return Swift_Signers_DomainKeySigner
+ */
+ public static function newInstance($privateKey, $domainName, $selector)
+ {
+ return new static($privateKey, $domainName, $selector);
+ }
+
+ /**
+ * Resets internal states
+ *
+ * @return Swift_Signers_DomainKeysSigner
+ */
+ public function reset()
+ {
+ $this->_hash = null;
+ $this->_hashHandler = null;
+ $this->_bodyCanonIgnoreStart = 2;
+ $this->_bodyCanonEmptyCounter = 0;
+ $this->_bodyCanonLastChar = null;
+ $this->_bodyCanonSpace = false;
+
+ return $this;
+ }
+
+ /**
+ * Writes $bytes to the end of the stream.
+ *
+ * Writing may not happen immediately if the stream chooses to buffer. If
+ * you want to write these bytes with immediate effect, call {@link commit()}
+ * after calling write().
+ *
+ * This method returns the sequence ID of the write (i.e. 1 for first, 2 for
+ * second, etc etc).
+ *
+ * @param string $bytes
+ * @return int
+ * @throws Swift_IoException
+ * @return Swift_Signers_DomainKeysSigner
+ */
+ public function write($bytes)
+ {
+ $this->_canonicalizeBody($bytes);
+ foreach ($this->_bound as $is) {
+ $is->write($bytes);
+ }
+
+ return $this;
+ }
+
+ /**
+ * For any bytes that are currently buffered inside the stream, force them
+ * off the buffer.
+ *
+ * @throws Swift_IoException
+ * @return Swift_Signers_DomainKeysSigner
+ */
+ public function commit()
+ {
+ // Nothing to do
+ return $this;
+ }
+
+ /**
+ * Attach $is to this stream.
+ * The stream acts as an observer, receiving all data that is written.
+ * All {@link write()} and {@link flushBuffers()} operations will be mirrored.
+ *
+ * @param Swift_InputByteStream $is
+ * @return Swift_Signers_DomainKeysSigner
+ */
+ public function bind(Swift_InputByteStream $is)
+ {
+ // Don't have to mirror anything
+ $this->_bound[] = $is;
+
+ return $this;
+ }
+
+ /**
+ * Remove an already bound stream.
+ * If $is is not bound, no errors will be raised.
+ * If the stream currently has any buffered data it will be written to $is
+ * before unbinding occurs.
+ *
+ * @param Swift_InputByteStream $is
+ * @return Swift_Signers_DomainKeysSigner
+ */
+ public function unbind(Swift_InputByteStream $is)
+ {
+ // Don't have to mirror anything
+ foreach ($this->_bound as $k => $stream) {
+ if ($stream === $is) {
+ unset($this->_bound[$k]);
+
+ return;
+ }
+ }
+
+ return $this;
+ }
+
+ /**
+ * Flush the contents of the stream (empty it) and set the internal pointer
+ * to the beginning.
+ *
+ * @throws Swift_IoException
+ * @return Swift_Signers_DomainKeysSigner
+ */
+ public function flushBuffers()
+ {
+ $this->reset();
+
+ return $this;
+ }
+
+ /**
+ * Set hash_algorithm, must be one of rsa-sha256 | rsa-sha1 defaults to rsa-sha256
+ *
+ * @param string $hash
+ * @return Swift_Signers_DomainKeysSigner
+ */
+ public function setHashAlgorithm($hash)
+ {
+ $this->_hashAlgorithm = 'rsa-sha1';
+
+ return $this;
+ }
+
+ /**
+ * Set the canonicalization algorithm
+ *
+ * @param string $canon simple | nofws defaults to simple
+ * @return Swift_Signers_DomainKeysSigner
+ */
+ public function setCanon($canon)
+ {
+ if ($canon == 'nofws') {
+ $this->_canon = 'nofws';
+ } else {
+ $this->_canon = 'simple';
+ }
+
+ return $this;
+ }
+
+ /**
+ * Set the signer identity
+ *
+ * @param string $identity
+ * @return Swift_Signers_DomainKeySigner
+ */
+ public function setSignerIdentity($identity)
+ {
+ $this->_signerIdentity = $identity;
+
+ return $this;
+ }
+
+ /**
+ * Enable / disable the DebugHeaders
+ *
+ * @param bool $debug
+ * @return Swift_Signers_DomainKeySigner
+ */
+ public function setDebugHeaders($debug)
+ {
+ $this->_debugHeaders = (bool) $debug;
+
+ return $this;
+ }
+
+ /**
+ * Start Body
+ *
+ */
+ public function startBody()
+ {
+ }
+
+ /**
+ * End Body
+ *
+ */
+ public function endBody()
+ {
+ $this->_endOfBody();
+ }
+
+ /**
+ * Returns the list of Headers Tampered by this plugin
+ *
+ * @return array
+ */
+ public function getAlteredHeaders()
+ {
+ if ($this->_debugHeaders) {
+ return array('DomainKey-Signature', 'X-DebugHash');
+ } else {
+ return array('DomainKey-Signature');
+ }
+ }
+
+ /**
+ * Adds an ignored Header
+ *
+ * @param string $header_name
+ * @return Swift_Signers_DomainKeySigner
+ */
+ public function ignoreHeader($header_name)
+ {
+ $this->_ignoredHeaders[strtolower($header_name)] = true;
+
+ return $this;
+ }
+
+ /**
+ * Set the headers to sign
+ *
+ * @param Swift_Mime_HeaderSet $headers
+ * @return Swift_Signers_DomainKeySigner
+ */
+ public function setHeaders(Swift_Mime_HeaderSet $headers)
+ {
+ $this->_startHash();
+ $this->_canonData = '';
+ // Loop through Headers
+ $listHeaders = $headers->listAll();
+ foreach ($listHeaders as $hName) {
+ // Check if we need to ignore Header
+ if (! isset($this->_ignoredHeaders[strtolower($hName)])) {
+ if ($headers->has($hName)) {
+ $tmp = $headers->getAll($hName);
+ foreach ($tmp as $header) {
+ if ($header->getFieldBody() != '') {
+ $this->_addHeader($header->toString());
+ $this->_signedHeaders[] = $header->getFieldName();
+ }
+ }
+ }
+ }
+ }
+ $this->_endOfHeaders();
+
+ return $this;
+ }
+
+ /**
+ * Add the signature to the given Headers
+ *
+ * @param Swift_Mime_HeaderSet $headers
+ * @return Swift_Signers_DomainKeySigner
+ */
+ public function addSignature(Swift_Mime_HeaderSet $headers)
+ {
+ // Prepare the DomainKey-Signature Header
+ $params = array('a' => $this->_hashAlgorithm, 'b' => chunk_split(base64_encode($this->_getEncryptedHash()), 73, " "), 'c' => $this->_canon, 'd' => $this->_domainName, 'h' => implode(': ', $this->_signedHeaders), 'q' => 'dns', 's' => $this->_selector);
+ $string = '';
+ foreach ($params as $k => $v) {
+ $string .= $k.'='.$v.'; ';
+ }
+ $string = trim($string);
+ $headers->addTextHeader('DomainKey-Signature', $string);
+
+ return $this;
+ }
+
+ /* Private helpers */
+
+ protected function _addHeader($header)
+ {
+ switch ($this->_canon) {
+ case 'nofws' :
+ // Prepare Header and cascade
+ $exploded = explode(':', $header, 2);
+ $name = strtolower(trim($exploded[0]));
+ $value = str_replace("\r\n", "", $exploded[1]);
+ $value = preg_replace("/[ \t][ \t]+/", " ", $value);
+ $header = $name.":".trim($value)."\r\n";
+ case 'simple' :
+ // Nothing to do
+ }
+ $this->_addToHash($header);
+ }
+
+ protected function _endOfHeaders()
+ {
+ $this->_bodyCanonEmptyCounter = 1;
+ }
+
+ protected function _canonicalizeBody($string)
+ {
+ $len = strlen($string);
+ $canon = '';
+ $nofws = ($this->_canon == "nofws");
+ for ($i = 0; $i < $len; ++$i) {
+ if ($this->_bodyCanonIgnoreStart > 0) {
+ --$this->_bodyCanonIgnoreStart;
+ continue;
+ }
+ switch ($string[$i]) {
+ case "\r" :
+ $this->_bodyCanonLastChar = "\r";
+ break;
+ case "\n" :
+ if ($this->_bodyCanonLastChar == "\r") {
+ if ($nofws) {
+ $this->_bodyCanonSpace = false;
+ }
+ if ($this->_bodyCanonLine == '') {
+ ++$this->_bodyCanonEmptyCounter;
+ } else {
+ $this->_bodyCanonLine = '';
+ $canon .= "\r\n";
+ }
+ } else {
+ // Wooops Error
+ throw new Swift_SwiftException('Invalid new line sequence in mail found \n without preceding \r');
+ }
+ break;
+ case " " :
+ case "\t" :
+ case "\x09": //HTAB
+ if ($nofws) {
+ $this->_bodyCanonSpace = true;
+ break;
+ }
+ default :
+ if ($this->_bodyCanonEmptyCounter > 0) {
+ $canon .= str_repeat("\r\n", $this->_bodyCanonEmptyCounter);
+ $this->_bodyCanonEmptyCounter = 0;
+ }
+ $this->_bodyCanonLine .= $string[$i];
+ $canon .= $string[$i];
+ }
+ }
+ $this->_addToHash($canon);
+ }
+
+ protected function _endOfBody()
+ {
+ if (strlen($this->_bodyCanonLine) > 0) {
+ $this->_addToHash("\r\n");
+ }
+ $this->_hash = hash_final($this->_hashHandler, true);
+ }
+
+ private function _addToHash($string)
+ {
+ $this->_canonData .= $string;
+ hash_update($this->_hashHandler, $string);
+ }
+
+ private function _startHash()
+ {
+ // Init
+ switch ($this->_hashAlgorithm) {
+ case 'rsa-sha1' :
+ $this->_hashHandler = hash_init('sha1');
+ break;
+ }
+ $this->_canonLine = '';
+ }
+
+ /**
+ * @throws Swift_SwiftException
+ * @return string
+ */
+ private function _getEncryptedHash()
+ {
+ $signature = '';
+ $pkeyId = openssl_get_privatekey($this->_privateKey);
+ if (!$pkeyId) {
+ throw new Swift_SwiftException('Unable to load DomainKey Private Key ['.openssl_error_string().']');
+ }
+ if (openssl_sign($this->_canonData, $signature, $pkeyId, OPENSSL_ALGO_SHA1)) {
+ return $signature;
+ }
+ throw new Swift_SwiftException('Unable to sign DomainKey Hash ['.openssl_error_string().']');
+ }
+}
diff --git a/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Signers/HeaderSigner.php b/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Signers/HeaderSigner.php
new file mode 100644
index 00000000..67c79413
--- /dev/null
+++ b/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Signers/HeaderSigner.php
@@ -0,0 +1,65 @@
+
+ */
+interface Swift_Signers_HeaderSigner extends Swift_Signer, Swift_InputByteStream
+{
+ /**
+ * Exclude an header from the signed headers
+ *
+ * @param string $header_name
+ *
+ * @return Swift_Signers_HeaderSigner
+ */
+ public function ignoreHeader($header_name);
+
+ /**
+ * Prepare the Signer to get a new Body
+ *
+ * @return Swift_Signers_HeaderSigner
+ */
+ public function startBody();
+
+ /**
+ * Give the signal that the body has finished streaming
+ *
+ * @return Swift_Signers_HeaderSigner
+ */
+ public function endBody();
+
+ /**
+ * Give the headers already given
+ *
+ * @param Swift_Mime_SimpleHeaderSet $headers
+ *
+ * @return Swift_Signers_HeaderSigner
+ */
+ public function setHeaders(Swift_Mime_HeaderSet $headers);
+
+ /**
+ * Add the header(s) to the headerSet
+ *
+ * @param Swift_Mime_HeaderSet $headers
+ *
+ * @return Swift_Signers_HeaderSigner
+ */
+ public function addSignature(Swift_Mime_HeaderSet $headers);
+
+ /**
+ * Return the list of header a signer might tamper
+ *
+ * @return array
+ */
+ public function getAlteredHeaders();
+}
diff --git a/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Signers/OpenDKIMSigner.php b/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Signers/OpenDKIMSigner.php
new file mode 100644
index 00000000..b9738f42
--- /dev/null
+++ b/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Signers/OpenDKIMSigner.php
@@ -0,0 +1,186 @@
+
+ */
+class Swift_Signers_OpenDKIMSigner extends Swift_Signers_DKIMSigner
+{
+ private $_peclLoaded = false;
+
+ private $_dkimHandler = null;
+
+ private $dropFirstLF = true;
+
+ const CANON_RELAXED = 1;
+ const CANON_SIMPLE = 2;
+ const SIG_RSA_SHA1 = 3;
+ const SIG_RSA_SHA256 = 4;
+
+ public function __construct($privateKey, $domainName, $selector)
+ {
+ if (extension_loaded('opendkim')) {
+ $this->_peclLoaded = true;
+ } else {
+ throw new Swift_SwiftException('php-opendkim extension not found');
+ }
+ parent::__construct($privateKey, $domainName, $selector);
+ }
+
+ public static function newInstance($privateKey, $domainName, $selector)
+ {
+ return new static($privateKey, $domainName, $selector);
+ }
+
+ public function addSignature(Swift_Mime_HeaderSet $headers)
+ {
+ $header = new Swift_Mime_Headers_OpenDKIMHeader('DKIM-Signature');
+ $headerVal = $this->_dkimHandler->getSignatureHeader();
+ if (!$headerVal) {
+ throw new Swift_SwiftException('OpenDKIM Error: '.$this->_dkimHandler->getError());
+ }
+ $header->setValue($headerVal);
+ $headers->set($header);
+
+ return $this;
+ }
+
+ public function setHeaders(Swift_Mime_HeaderSet $headers)
+ {
+ $bodyLen = $this->_bodyLen;
+ if (is_bool($bodyLen)) {
+ $bodyLen = - 1;
+ }
+ $hash = ($this->_hashAlgorithm == 'rsa-sha1') ? OpenDKIMSign::ALG_RSASHA1 : OpenDKIMSign::ALG_RSASHA256;
+ $bodyCanon = ($this->_bodyCanon == 'simple') ? OpenDKIMSign::CANON_SIMPLE : OpenDKIMSign::CANON_RELAXED;
+ $headerCanon = ($this->_headerCanon == 'simple') ? OpenDKIMSign::CANON_SIMPLE : OpenDKIMSign::CANON_RELAXED;
+ $this->_dkimHandler = new OpenDKIMSign($this->_privateKey, $this->_selector, $this->_domainName, $headerCanon, $bodyCanon, $hash, $bodyLen);
+ // Hardcode signature Margin for now
+ $this->_dkimHandler->setMargin(78);
+
+ if (!is_numeric($this->_signatureTimestamp)) {
+ OpenDKIM::setOption(OpenDKIM::OPTS_FIXEDTIME, time());
+ } else {
+ if (!OpenDKIM::setOption(OpenDKIM::OPTS_FIXEDTIME, $this->_signatureTimestamp)) {
+ throw new Swift_SwiftException('Unable to force signature timestamp ['.openssl_error_string().']');
+ }
+ }
+ if (isset($this->_signerIdentity)) {
+ $this->_dkimHandler->setSigner($this->_signerIdentity);
+ }
+ $listHeaders = $headers->listAll();
+ foreach ($listHeaders as $hName) {
+ // Check if we need to ignore Header
+ if (! isset($this->_ignoredHeaders[strtolower($hName)])) {
+ $tmp = $headers->getAll($hName);
+ if ($headers->has($hName)) {
+ foreach ($tmp as $header) {
+ if ($header->getFieldBody() != '') {
+ $htosign = $header->toString();
+ $this->_dkimHandler->header($htosign);
+ $this->_signedHeaders[] = $header->getFieldName();
+ }
+ }
+ }
+ }
+ }
+
+ return $this;
+ }
+
+ public function startBody()
+ {
+ if (! $this->_peclLoaded) {
+ return parent::startBody();
+ }
+ $this->dropFirstLF = true;
+ $this->_dkimHandler->eoh();
+
+ return $this;
+ }
+
+ public function endBody()
+ {
+ if (! $this->_peclLoaded) {
+ return parent::endBody();
+ }
+ $this->_dkimHandler->eom();
+
+ return $this;
+ }
+
+ public function reset()
+ {
+ $this->_dkimHandler = null;
+ parent::reset();
+
+ return $this;
+ }
+
+ /**
+ * Set the signature timestamp
+ *
+ * @param timestamp $time
+ * @return Swift_Signers_DKIMSigner
+ */
+ public function setSignatureTimestamp($time)
+ {
+ $this->_signatureTimestamp = $time;
+
+ return $this;
+ }
+
+ /**
+ * Set the signature expiration timestamp
+ *
+ * @param timestamp $time
+ * @return Swift_Signers_DKIMSigner
+ */
+ public function setSignatureExpiration($time)
+ {
+ $this->_signatureExpiration = $time;
+
+ return $this;
+ }
+
+ /**
+ * Enable / disable the DebugHeaders
+ *
+ * @param bool $debug
+ * @return Swift_Signers_DKIMSigner
+ */
+ public function setDebugHeaders($debug)
+ {
+ $this->_debugHeaders = (bool) $debug;
+
+ return $this;
+ }
+
+ // Protected
+
+ protected function _canonicalizeBody($string)
+ {
+ if (! $this->_peclLoaded) {
+ return parent::_canonicalizeBody($string);
+ }
+ if (false && $this->dropFirstLF === true) {
+ if ($string[0] == "\r" && $string[1] == "\n") {
+ $string = substr($string, 2);
+ }
+ }
+ $this->dropFirstLF = false;
+ if (strlen($string)) {
+ $this->_dkimHandler->body($string);
+ }
+ }
+}
diff --git a/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Signers/SMimeSigner.php b/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Signers/SMimeSigner.php
new file mode 100644
index 00000000..42e294c6
--- /dev/null
+++ b/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Signers/SMimeSigner.php
@@ -0,0 +1,427 @@
+
+ */
+class Swift_Signers_SMimeSigner implements Swift_Signers_BodySigner
+{
+ protected $signCertificate;
+ protected $signPrivateKey;
+ protected $encryptCert;
+ protected $signThenEncrypt = true;
+ protected $signLevel;
+ protected $encryptLevel;
+ protected $signOptions;
+ protected $encryptOptions;
+ protected $encryptCipher;
+
+ /**
+ * @var Swift_StreamFilters_StringReplacementFilterFactory
+ */
+ protected $replacementFactory;
+
+ /**
+ * @var Swift_Mime_HeaderFactory
+ */
+ protected $headerFactory;
+
+ /**
+ * Constructor.
+ *
+ * @param string $certificate
+ * @param string $privateKey
+ * @param string $encryptCertificate
+ */
+ public function __construct($signCertificate = null, $signPrivateKey = null, $encryptCertificate = null)
+ {
+ if (null !== $signPrivateKey) {
+ $this->setSignCertificate($signCertificate, $signPrivateKey);
+ }
+
+ if (null !== $encryptCertificate) {
+ $this->setEncryptCertificate($encryptCertificate);
+ }
+
+ $this->replacementFactory = Swift_DependencyContainer::getInstance()
+ ->lookup('transport.replacementfactory');
+
+ $this->signOptions = PKCS7_DETACHED;
+
+ // Supported since php5.4
+ if (defined('OPENSSL_CIPHER_AES_128_CBC')) {
+ $this->encryptCipher = OPENSSL_CIPHER_AES_128_CBC;
+ } else {
+ $this->encryptCipher = OPENSSL_CIPHER_RC2_128;
+ }
+ }
+
+ /**
+ * Returns an new Swift_Signers_SMimeSigner instance.
+ *
+ * @param string $certificate
+ * @param string $privateKey
+ *
+ * @return Swift_Signers_SMimeSigner
+ */
+ public static function newInstance($certificate = null, $privateKey = null)
+ {
+ return new self($certificate, $privateKey);
+ }
+
+ /**
+ * Set the certificate location to use for signing.
+ *
+ * @link http://www.php.net/manual/en/openssl.pkcs7.flags.php
+ *
+ * @param string $certificate
+ * @param string|array $privateKey If the key needs an passphrase use array('file-location', 'passphrase') instead
+ * @param int $signOptions Bitwise operator options for openssl_pkcs7_sign()
+ *
+ * @return Swift_Signers_SMimeSigner
+ */
+ public function setSignCertificate($certificate, $privateKey = null, $signOptions = PKCS7_DETACHED)
+ {
+ $this->signCertificate = 'file://'.str_replace('\\', '/', realpath($certificate));
+
+ if (null !== $privateKey) {
+ if (is_array($privateKey)) {
+ $this->signPrivateKey = $privateKey;
+ $this->signPrivateKey[0] = 'file://'.str_replace('\\', '/', realpath($privateKey[0]));
+ } else {
+ $this->signPrivateKey = 'file://'.str_replace('\\', '/', realpath($privateKey));
+ }
+ }
+
+ $this->signOptions = $signOptions;
+
+ return $this;
+ }
+
+ /**
+ * Set the certificate location to use for encryption.
+ *
+ * @link http://www.php.net/manual/en/openssl.pkcs7.flags.php
+ * @link http://nl3.php.net/manual/en/openssl.ciphers.php
+ *
+ * @param string|array $recipientCerts Either an single X.509 certificate, or an assoc array of X.509 certificates.
+ * @param int $cipher
+ *
+ * @return Swift_Signers_SMimeSigner
+ */
+ public function setEncryptCertificate($recipientCerts, $cipher = null)
+ {
+ if (is_array($recipientCerts)) {
+ $this->encryptCert = array();
+
+ foreach ($recipientCerts as $cert) {
+ $this->encryptCert[] = 'file://'.str_replace('\\', '/', realpath($cert));
+ }
+ } else {
+ $this->encryptCert = 'file://'.str_replace('\\', '/', realpath($recipientCerts));
+ }
+
+ if (null !== $cipher) {
+ $this->encryptCipher = $cipher;
+ }
+
+ return $this;
+ }
+
+ /**
+ * @return string
+ */
+ public function getSignCertificate()
+ {
+ return $this->signCertificate;
+ }
+
+ /**
+ * @return string
+ */
+ public function getSignPrivateKey()
+ {
+ return $this->signPrivateKey;
+ }
+
+ /**
+ * Set perform signing before encryption.
+ *
+ * The default is to first sign the message and then encrypt.
+ * But some older mail clients, namely Microsoft Outlook 2000 will work when the message first encrypted.
+ * As this goes against the official specs, its recommended to only use 'encryption -> signing' when specifically targeting these 'broken' clients.
+ *
+ * @param string $signThenEncrypt
+ *
+ * @return Swift_Signers_SMimeSigner
+ */
+ public function setSignThenEncrypt($signThenEncrypt = true)
+ {
+ $this->signThenEncrypt = $signThenEncrypt;
+
+ return $this;
+ }
+
+ /**
+ * @return bool
+ */
+ public function isSignThenEncrypt()
+ {
+ return $this->signThenEncrypt;
+ }
+
+ /**
+ * Resets internal states.
+ *
+ * @return Swift_Signers_SMimeSigner
+ */
+ public function reset()
+ {
+ return $this;
+ }
+
+ /**
+ * Change the Swift_Message to apply the signing.
+ *
+ * @param Swift_Message $message
+ *
+ * @return Swift_Signers_SMimeSigner
+ */
+ public function signMessage(Swift_Message $message)
+ {
+ if (null === $this->signCertificate && null === $this->encryptCert) {
+ return $this;
+ }
+
+ // Store the message using ByteStream to a file{1}
+ // Remove all Children
+ // Sign file{1}, parse the new MIME headers and set them on the primary MimeEntity
+ // Set the singed-body as the new body (without boundary)
+
+ $messageStream = new Swift_ByteStream_TemporaryFileByteStream();
+ $this->toSMimeByteStream($messageStream, $message);
+ $message->setEncoder(Swift_DependencyContainer::getInstance()->lookup('mime.rawcontentencoder'));
+
+ $message->setChildren(array());
+ $this->streamToMime($messageStream, $message);
+ }
+
+ /**
+ * Return the list of header a signer might tamper.
+ *
+ * @return array
+ */
+ public function getAlteredHeaders()
+ {
+ return array('Content-Type', 'Content-Transfer-Encoding', 'Content-Disposition');
+ }
+
+ /**
+ * @param Swift_InputByteStream $inputStream
+ * @param Swift_Message $mimeEntity
+ */
+ protected function toSMimeByteStream(Swift_InputByteStream $inputStream, Swift_Message $message)
+ {
+ $mimeEntity = $this->createMessage($message);
+ $messageStream = new Swift_ByteStream_TemporaryFileByteStream();
+
+ $mimeEntity->toByteStream($messageStream);
+ $messageStream->commit();
+
+ if (null !== $this->signCertificate && null !== $this->encryptCert) {
+ $temporaryStream = new Swift_ByteStream_TemporaryFileByteStream();
+
+ if ($this->signThenEncrypt) {
+ $this->messageStreamToSignedByteStream($messageStream, $temporaryStream);
+ $this->messageStreamToEncryptedByteStream($temporaryStream, $inputStream);
+ } else {
+ $this->messageStreamToEncryptedByteStream($messageStream, $temporaryStream);
+ $this->messageStreamToSignedByteStream($temporaryStream, $inputStream);
+ }
+ } elseif ($this->signCertificate !== null) {
+ $this->messageStreamToSignedByteStream($messageStream, $inputStream);
+ } else {
+ $this->messageStreamToEncryptedByteStream($messageStream, $inputStream);
+ }
+ }
+
+ /**
+ * @param Swift_Message $message
+ *
+ * @return Swift_Message
+ */
+ protected function createMessage(Swift_Message $message)
+ {
+ $mimeEntity = new Swift_Message('', $message->getBody(), $message->getContentType(), $message->getCharset());
+ $mimeEntity->setChildren($message->getChildren());
+
+ $messageHeaders = $mimeEntity->getHeaders();
+ $messageHeaders->remove('Message-ID');
+ $messageHeaders->remove('Date');
+ $messageHeaders->remove('Subject');
+ $messageHeaders->remove('MIME-Version');
+ $messageHeaders->remove('To');
+ $messageHeaders->remove('From');
+
+ return $mimeEntity;
+ }
+
+ /**
+ * @param Swift_FileStream $outputStream
+ * @param Swift_InputByteStream $inputStream
+ *
+ * @throws Swift_IoException
+ */
+ protected function messageStreamToSignedByteStream(Swift_FileStream $outputStream, Swift_InputByteStream $inputStream)
+ {
+ $signedMessageStream = new Swift_ByteStream_TemporaryFileByteStream();
+
+ if (!openssl_pkcs7_sign($outputStream->getPath(), $signedMessageStream->getPath(), $this->signCertificate, $this->signPrivateKey, array(), $this->signOptions)) {
+ throw new Swift_IoException(sprintf('Failed to sign S/Mime message. Error: "%s".', openssl_error_string()));
+ }
+
+ $this->copyFromOpenSSLOutput($signedMessageStream, $inputStream);
+ }
+
+ /**
+ * @param Swift_FileStream $outputStream
+ * @param Swift_InputByteStream $is
+ *
+ * @throws Swift_IoException
+ */
+ protected function messageStreamToEncryptedByteStream(Swift_FileStream $outputStream, Swift_InputByteStream $is)
+ {
+ $encryptedMessageStream = new Swift_ByteStream_TemporaryFileByteStream();
+
+ if (!openssl_pkcs7_encrypt($outputStream->getPath(), $encryptedMessageStream->getPath(), $this->encryptCert, array(), 0, $this->encryptCipher)) {
+ throw new Swift_IoException(sprintf('Failed to encrypt S/Mime message. Error: "%s".', openssl_error_string()));
+ }
+
+ $this->copyFromOpenSSLOutput($encryptedMessageStream, $is);
+ }
+
+ /**
+ * @param Swift_OutputByteStream $fromStream
+ * @param Swift_InputByteStream $toStream
+ */
+ protected function copyFromOpenSSLOutput(Swift_OutputByteStream $fromStream, Swift_InputByteStream $toStream)
+ {
+ $bufferLength = 4096;
+ $filteredStream = new Swift_ByteStream_TemporaryFileByteStream();
+ $filteredStream->addFilter($this->replacementFactory->createFilter("\r\n", "\n"), 'CRLF to LF');
+ $filteredStream->addFilter($this->replacementFactory->createFilter("\n", "\r\n"), 'LF to CRLF');
+
+ while (false !== ($buffer = $fromStream->read($bufferLength))) {
+ $filteredStream->write($buffer);
+ }
+
+ $filteredStream->flushBuffers();
+
+ while (false !== ($buffer = $filteredStream->read($bufferLength))) {
+ $toStream->write($buffer);
+ }
+
+ $toStream->commit();
+ }
+
+ /**
+ * Merges an OutputByteStream to Swift_Message.
+ *
+ * @param Swift_OutputByteStream $fromStream
+ * @param Swift_Message $message
+ */
+ protected function streamToMime(Swift_OutputByteStream $fromStream, Swift_Message $message)
+ {
+ $bufferLength = 78;
+ $headerData = '';
+
+ $fromStream->setReadPointer(0);
+
+ while (($buffer = $fromStream->read($bufferLength)) !== false) {
+ $headerData .= $buffer;
+
+ if (false !== strpos($buffer, "\r\n\r\n")) {
+ break;
+ }
+ }
+
+ $headersPosEnd = strpos($headerData, "\r\n\r\n");
+ $headerData = trim($headerData);
+ $headerData = substr($headerData, 0, $headersPosEnd);
+ $headerLines = explode("\r\n", $headerData);
+ unset($headerData);
+
+ $headers = array();
+ $currentHeaderName = '';
+
+ foreach ($headerLines as $headerLine) {
+ // Line separated
+ if (ctype_space($headerLines[0]) || false === strpos($headerLine, ':')) {
+ $headers[$currentHeaderName] .= ' '.trim($headerLine);
+ continue;
+ }
+
+ $header = explode(':', $headerLine, 2);
+ $currentHeaderName = strtolower($header[0]);
+ $headers[$currentHeaderName] = trim($header[1]);
+ }
+
+ $messageStream = new Swift_ByteStream_TemporaryFileByteStream();
+ $messageStream->addFilter($this->replacementFactory->createFilter("\r\n", "\n"), 'CRLF to LF');
+ $messageStream->addFilter($this->replacementFactory->createFilter("\n", "\r\n"), 'LF to CRLF');
+
+ $messageHeaders = $message->getHeaders();
+
+ // No need to check for 'application/pkcs7-mime', as this is always base64
+ if ('multipart/signed;' === substr($headers['content-type'], 0, 17)) {
+ if (!preg_match('/boundary=("[^"]+"|(?:[^\s]+|$))/is', $headers['content-type'], $contentTypeData)) {
+ throw new Swift_SwiftException('Failed to find Boundary parameter');
+ }
+
+ $boundary = trim($contentTypeData['1'], '"');
+ $boundaryLen = strlen($boundary);
+
+ // Skip the header and CRLF CRLF
+ $fromStream->setReadPointer($headersPosEnd + 4);
+
+ while (false !== ($buffer = $fromStream->read($bufferLength))) {
+ $messageStream->write($buffer);
+ }
+
+ $messageStream->commit();
+
+ $messageHeaders->remove('Content-Transfer-Encoding');
+ $message->setContentType($headers['content-type']);
+ $message->setBoundary($boundary);
+ $message->setBody($messageStream);
+ } else {
+ $fromStream->setReadPointer($headersPosEnd + 4);
+
+ if (null === $this->headerFactory) {
+ $this->headerFactory = Swift_DependencyContainer::getInstance()->lookup('mime.headerfactory');
+ }
+
+ $message->setContentType($headers['content-type']);
+ $messageHeaders->set($this->headerFactory->createTextHeader('Content-Transfer-Encoding', $headers['content-transfer-encoding']));
+ $messageHeaders->set($this->headerFactory->createTextHeader('Content-Disposition', $headers['content-disposition']));
+
+ while (false !== ($buffer = $fromStream->read($bufferLength))) {
+ $messageStream->write($buffer);
+ }
+
+ $messageStream->commit();
+ $message->setBody($messageStream);
+ }
+ }
+}
diff --git a/vendor/swiftmailer/swiftmailer/lib/classes/Swift/SmtpTransport.php b/vendor/swiftmailer/swiftmailer/lib/classes/Swift/SmtpTransport.php
new file mode 100644
index 00000000..5d4945e1
--- /dev/null
+++ b/vendor/swiftmailer/swiftmailer/lib/classes/Swift/SmtpTransport.php
@@ -0,0 +1,57 @@
+createDependenciesFor('transport.smtp')
+ );
+
+ $this->setHost($host);
+ $this->setPort($port);
+ $this->setEncryption($security);
+ }
+
+ /**
+ * Create a new SmtpTransport instance.
+ *
+ * @param string $host
+ * @param int $port
+ * @param string $security
+ *
+ * @return Swift_SmtpTransport
+ */
+ public static function newInstance($host = 'localhost', $port = 25, $security = null)
+ {
+ return new self($host, $port, $security);
+ }
+}
diff --git a/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Spool.php b/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Spool.php
new file mode 100644
index 00000000..afae5fac
--- /dev/null
+++ b/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Spool.php
@@ -0,0 +1,53 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+/**
+ * Interface for spools.
+ *
+ * @author Fabien Potencier
+ */
+interface Swift_Spool
+{
+ /**
+ * Starts this Spool mechanism.
+ */
+ public function start();
+
+ /**
+ * Stops this Spool mechanism.
+ */
+ public function stop();
+
+ /**
+ * Tests if this Spool mechanism has started.
+ *
+ * @return bool
+ */
+ public function isStarted();
+
+ /**
+ * Queues a message.
+ *
+ * @param Swift_Mime_Message $message The message to store
+ *
+ * @return bool Whether the operation has succeeded
+ */
+ public function queueMessage(Swift_Mime_Message $message);
+
+ /**
+ * Sends messages using the given transport instance.
+ *
+ * @param Swift_Transport $transport A transport instance
+ * @param string[] $failedRecipients An array of failures by-reference
+ *
+ * @return int The number of sent emails
+ */
+ public function flushQueue(Swift_Transport $transport, &$failedRecipients = null);
+}
diff --git a/vendor/swiftmailer/swiftmailer/lib/classes/Swift/SpoolTransport.php b/vendor/swiftmailer/swiftmailer/lib/classes/Swift/SpoolTransport.php
new file mode 100644
index 00000000..9351c40d
--- /dev/null
+++ b/vendor/swiftmailer/swiftmailer/lib/classes/Swift/SpoolTransport.php
@@ -0,0 +1,47 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+/**
+ * Stores Messages in a queue.
+ *
+ * @author Fabien Potencier
+ */
+class Swift_SpoolTransport extends Swift_Transport_SpoolTransport
+{
+ /**
+ * Create a new SpoolTransport.
+ *
+ * @param Swift_Spool $spool
+ */
+ public function __construct(Swift_Spool $spool)
+ {
+ $arguments = Swift_DependencyContainer::getInstance()
+ ->createDependenciesFor('transport.spool');
+
+ $arguments[] = $spool;
+
+ call_user_func_array(
+ array($this, 'Swift_Transport_SpoolTransport::__construct'),
+ $arguments
+ );
+ }
+
+ /**
+ * Create a new SpoolTransport instance.
+ *
+ * @param Swift_Spool $spool
+ *
+ * @return Swift_SpoolTransport
+ */
+ public static function newInstance(Swift_Spool $spool)
+ {
+ return new self($spool);
+ }
+}
diff --git a/vendor/swiftmailer/swiftmailer/lib/classes/Swift/StreamFilter.php b/vendor/swiftmailer/swiftmailer/lib/classes/Swift/StreamFilter.php
new file mode 100644
index 00000000..1c3fd3a5
--- /dev/null
+++ b/vendor/swiftmailer/swiftmailer/lib/classes/Swift/StreamFilter.php
@@ -0,0 +1,35 @@
+_search = $search;
+ $this->_index = array();
+ $this->_tree = array();
+ $this->_replace = array();
+ $this->_repSize = array();
+
+ $tree = null;
+ $i = null;
+ $last_size = $size = 0;
+ foreach ($search as $i => $search_element) {
+ if ($tree !== null) {
+ $tree[-1] = min (count($replace) - 1, $i - 1);
+ $tree[-2] = $last_size;
+ }
+ $tree = &$this->_tree;
+ if (is_array ($search_element)) {
+ foreach ($search_element as $k => $char) {
+ $this->_index[$char] = true;
+ if (!isset($tree[$char])) {
+ $tree[$char] = array();
+ }
+ $tree = &$tree[$char];
+ }
+ $last_size = $k+1;
+ $size = max($size, $last_size);
+ } else {
+ $last_size = 1;
+ if (!isset($tree[$search_element])) {
+ $tree[$search_element] = array();
+ }
+ $tree = &$tree[$search_element];
+ $size = max($last_size, $size);
+ $this->_index[$search_element] = true;
+ }
+ }
+ if ($i !== null) {
+ $tree[-1] = min (count ($replace) - 1, $i);
+ $tree[-2] = $last_size;
+ $this->_treeMaxLen = $size;
+ }
+ foreach ($replace as $rep) {
+ if (!is_array($rep)) {
+ $rep = array ($rep);
+ }
+ $this->_replace[] = $rep;
+ }
+ for ($i = count($this->_replace) - 1; $i >= 0; --$i) {
+ $this->_replace[$i] = $rep = $this->filter($this->_replace[$i], $i);
+ $this->_repSize[$i] = count($rep);
+ }
+ }
+
+ /**
+ * Returns true if based on the buffer passed more bytes should be buffered.
+ *
+ * @param array $buffer
+ *
+ * @return bool
+ */
+ public function shouldBuffer($buffer)
+ {
+ $endOfBuffer = end($buffer);
+
+ return isset ($this->_index[$endOfBuffer]);
+ }
+
+ /**
+ * Perform the actual replacements on $buffer and return the result.
+ *
+ * @param array $buffer
+ * @param int $_minReplaces
+ *
+ * @return array
+ */
+ public function filter($buffer, $_minReplaces = -1)
+ {
+ if ($this->_treeMaxLen == 0) {
+ return $buffer;
+ }
+
+ $newBuffer = array();
+ $buf_size = count($buffer);
+ for ($i = 0; $i < $buf_size; ++$i) {
+ $search_pos = $this->_tree;
+ $last_found = PHP_INT_MAX;
+ // We try to find if the next byte is part of a search pattern
+ for ($j = 0; $j <= $this->_treeMaxLen; ++$j) {
+ // We have a new byte for a search pattern
+ if (isset ($buffer [$p = $i + $j]) && isset($search_pos[$buffer[$p]])) {
+ $search_pos = $search_pos[$buffer[$p]];
+ // We have a complete pattern, save, in case we don't find a better match later
+ if (isset($search_pos[- 1]) && $search_pos[-1] < $last_found
+ && $search_pos[-1] > $_minReplaces) {
+ $last_found = $search_pos[-1];
+ $last_size = $search_pos[-2];
+ }
+ }
+ // We got a complete pattern
+ elseif ($last_found !== PHP_INT_MAX) {
+ // Adding replacement datas to output buffer
+ $rep_size = $this->_repSize[$last_found];
+ for ($j = 0; $j < $rep_size; ++$j) {
+ $newBuffer[] = $this->_replace[$last_found][$j];
+ }
+ // We Move cursor forward
+ $i += $last_size - 1;
+ // Edge Case, last position in buffer
+ if ($i >= $buf_size) {
+ $newBuffer[] = $buffer[$i];
+ }
+
+ // We start the next loop
+ continue 2;
+ } else {
+ // this byte is not in a pattern and we haven't found another pattern
+ break;
+ }
+ }
+ // Normal byte, move it to output buffer
+ $newBuffer[] = $buffer[$i];
+ }
+
+ return $newBuffer;
+ }
+}
diff --git a/vendor/swiftmailer/swiftmailer/lib/classes/Swift/StreamFilters/StringReplacementFilter.php b/vendor/swiftmailer/swiftmailer/lib/classes/Swift/StreamFilters/StringReplacementFilter.php
new file mode 100644
index 00000000..e6b9e7b8
--- /dev/null
+++ b/vendor/swiftmailer/swiftmailer/lib/classes/Swift/StreamFilters/StringReplacementFilter.php
@@ -0,0 +1,66 @@
+_search = $search;
+ $this->_replace = $replace;
+ }
+
+ /**
+ * Returns true if based on the buffer passed more bytes should be buffered.
+ *
+ * @param string $buffer
+ *
+ * @return bool
+ */
+ public function shouldBuffer($buffer)
+ {
+ $endOfBuffer = substr($buffer, -1);
+ foreach ((array) $this->_search as $needle) {
+ if (false !== strpos($needle, $endOfBuffer)) {
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+ /**
+ * Perform the actual replacements on $buffer and return the result.
+ *
+ * @param string $buffer
+ *
+ * @return string
+ */
+ public function filter($buffer)
+ {
+ return str_replace($this->_search, $this->_replace, $buffer);
+ }
+}
diff --git a/vendor/swiftmailer/swiftmailer/lib/classes/Swift/StreamFilters/StringReplacementFilterFactory.php b/vendor/swiftmailer/swiftmailer/lib/classes/Swift/StreamFilters/StringReplacementFilterFactory.php
new file mode 100644
index 00000000..4b12cfff
--- /dev/null
+++ b/vendor/swiftmailer/swiftmailer/lib/classes/Swift/StreamFilters/StringReplacementFilterFactory.php
@@ -0,0 +1,45 @@
+_filters[$search][$replace])) {
+ if (!isset($this->_filters[$search])) {
+ $this->_filters[$search] = array();
+ }
+
+ if (!isset($this->_filters[$search][$replace])) {
+ $this->_filters[$search][$replace] = array();
+ }
+
+ $this->_filters[$search][$replace] = new Swift_StreamFilters_StringReplacementFilter($search, $replace);
+ }
+
+ return $this->_filters[$search][$replace];
+ }
+}
diff --git a/vendor/swiftmailer/swiftmailer/lib/classes/Swift/SwiftException.php b/vendor/swiftmailer/swiftmailer/lib/classes/Swift/SwiftException.php
new file mode 100644
index 00000000..22ee3eb4
--- /dev/null
+++ b/vendor/swiftmailer/swiftmailer/lib/classes/Swift/SwiftException.php
@@ -0,0 +1,27 @@
+_eventDispatcher = $dispatcher;
+ $this->_buffer = $buf;
+ $this->_lookupHostname();
+ }
+
+ /**
+ * Set the name of the local domain which Swift will identify itself as.
+ *
+ * This should be a fully-qualified domain name and should be truly the domain
+ * you're using.
+ *
+ * If your server doesn't have a domain name, use the IP in square
+ * brackets (i.e. [127.0.0.1]).
+ *
+ * @param string $domain
+ *
+ * @return Swift_Transport_AbstractSmtpTransport
+ */
+ public function setLocalDomain($domain)
+ {
+ $this->_domain = $domain;
+
+ return $this;
+ }
+
+ /**
+ * Get the name of the domain Swift will identify as.
+ *
+ * @return string
+ */
+ public function getLocalDomain()
+ {
+ return $this->_domain;
+ }
+
+ /**
+ * Sets the source IP.
+ *
+ * @param string $source
+ */
+ public function setSourceIp($source)
+ {
+ $this->_sourceIp = $source;
+ }
+
+ /**
+ * Returns the IP used to connect to the destination
+ *
+ * @return string
+ */
+ public function getSourceIp()
+ {
+ return $this->_sourceIp;
+ }
+
+ /**
+ * Start the SMTP connection.
+ */
+ public function start()
+ {
+ if (!$this->_started) {
+ if ($evt = $this->_eventDispatcher->createTransportChangeEvent($this)) {
+ $this->_eventDispatcher->dispatchEvent($evt, 'beforeTransportStarted');
+ if ($evt->bubbleCancelled()) {
+ return;
+ }
+ }
+
+ try {
+ $this->_buffer->initialize($this->_getBufferParams());
+ } catch (Swift_TransportException $e) {
+ $this->_throwException($e);
+ }
+ $this->_readGreeting();
+ $this->_doHeloCommand();
+
+ if ($evt) {
+ $this->_eventDispatcher->dispatchEvent($evt, 'transportStarted');
+ }
+
+ $this->_started = true;
+ }
+ }
+
+ /**
+ * Test if an SMTP connection has been established.
+ *
+ * @return bool
+ */
+ public function isStarted()
+ {
+ return $this->_started;
+ }
+
+ /**
+ * Send the given Message.
+ *
+ * Recipient/sender data will be retrieved from the Message API.
+ * The return value is the number of recipients who were accepted for delivery.
+ *
+ * @param Swift_Mime_Message $message
+ * @param string[] $failedRecipients An array of failures by-reference
+ *
+ * @return int
+ */
+ public function send(Swift_Mime_Message $message, &$failedRecipients = null)
+ {
+ $sent = 0;
+ $failedRecipients = (array) $failedRecipients;
+
+ if ($evt = $this->_eventDispatcher->createSendEvent($this, $message)) {
+ $this->_eventDispatcher->dispatchEvent($evt, 'beforeSendPerformed');
+ if ($evt->bubbleCancelled()) {
+ return 0;
+ }
+ }
+
+ if (!$reversePath = $this->_getReversePath($message)) {
+ throw new Swift_TransportException(
+ 'Cannot send message without a sender address'
+ );
+ }
+
+ $to = (array) $message->getTo();
+ $cc = (array) $message->getCc();
+ $tos = array_merge($to, $cc);
+ $bcc = (array) $message->getBcc();
+
+ $message->setBcc(array());
+
+ try {
+ $sent += $this->_sendTo($message, $reversePath, $tos, $failedRecipients);
+ $sent += $this->_sendBcc($message, $reversePath, $bcc, $failedRecipients);
+ } catch (Exception $e) {
+ $message->setBcc($bcc);
+ throw $e;
+ }
+
+ $message->setBcc($bcc);
+
+ if ($evt) {
+ if ($sent == count($to) + count($cc) + count($bcc)) {
+ $evt->setResult(Swift_Events_SendEvent::RESULT_SUCCESS);
+ } elseif ($sent > 0) {
+ $evt->setResult(Swift_Events_SendEvent::RESULT_TENTATIVE);
+ } else {
+ $evt->setResult(Swift_Events_SendEvent::RESULT_FAILED);
+ }
+ $evt->setFailedRecipients($failedRecipients);
+ $this->_eventDispatcher->dispatchEvent($evt, 'sendPerformed');
+ }
+
+ $message->generateId(); //Make sure a new Message ID is used
+
+ return $sent;
+ }
+
+ /**
+ * Stop the SMTP connection.
+ */
+ public function stop()
+ {
+ if ($this->_started) {
+ if ($evt = $this->_eventDispatcher->createTransportChangeEvent($this)) {
+ $this->_eventDispatcher->dispatchEvent($evt, 'beforeTransportStopped');
+ if ($evt->bubbleCancelled()) {
+ return;
+ }
+ }
+
+ try {
+ $this->executeCommand("QUIT\r\n", array(221));
+ } catch (Swift_TransportException $e) {
+ }
+
+ try {
+ $this->_buffer->terminate();
+
+ if ($evt) {
+ $this->_eventDispatcher->dispatchEvent($evt, 'transportStopped');
+ }
+ } catch (Swift_TransportException $e) {
+ $this->_throwException($e);
+ }
+ }
+ $this->_started = false;
+ }
+
+ /**
+ * Register a plugin.
+ *
+ * @param Swift_Events_EventListener $plugin
+ */
+ public function registerPlugin(Swift_Events_EventListener $plugin)
+ {
+ $this->_eventDispatcher->bindEventListener($plugin);
+ }
+
+ /**
+ * Reset the current mail transaction.
+ */
+ public function reset()
+ {
+ $this->executeCommand("RSET\r\n", array(250));
+ }
+
+ /**
+ * Get the IoBuffer where read/writes are occurring.
+ *
+ * @return Swift_Transport_IoBuffer
+ */
+ public function getBuffer()
+ {
+ return $this->_buffer;
+ }
+
+ /**
+ * Run a command against the buffer, expecting the given response codes.
+ *
+ * If no response codes are given, the response will not be validated.
+ * If codes are given, an exception will be thrown on an invalid response.
+ *
+ * @param string $command
+ * @param int[] $codes
+ * @param string[] $failures An array of failures by-reference
+ *
+ * @return string
+ */
+ public function executeCommand($command, $codes = array(), &$failures = null)
+ {
+ $failures = (array) $failures;
+ $seq = $this->_buffer->write($command);
+ $response = $this->_getFullResponse($seq);
+ if ($evt = $this->_eventDispatcher->createCommandEvent($this, $command, $codes)) {
+ $this->_eventDispatcher->dispatchEvent($evt, 'commandSent');
+ }
+ $this->_assertResponseCode($response, $codes);
+
+ return $response;
+ }
+
+ /** Read the opening SMTP greeting */
+ protected function _readGreeting()
+ {
+ $this->_assertResponseCode($this->_getFullResponse(0), array(220));
+ }
+
+ /** Send the HELO welcome */
+ protected function _doHeloCommand()
+ {
+ $this->executeCommand(
+ sprintf("HELO %s\r\n", $this->_domain), array(250)
+ );
+ }
+
+ /** Send the MAIL FROM command */
+ protected function _doMailFromCommand($address)
+ {
+ $this->executeCommand(
+ sprintf("MAIL FROM: <%s>\r\n", $address), array(250)
+ );
+ }
+
+ /** Send the RCPT TO command */
+ protected function _doRcptToCommand($address)
+ {
+ $this->executeCommand(
+ sprintf("RCPT TO: <%s>\r\n", $address), array(250, 251, 252)
+ );
+ }
+
+ /** Send the DATA command */
+ protected function _doDataCommand()
+ {
+ $this->executeCommand("DATA\r\n", array(354));
+ }
+
+ /** Stream the contents of the message over the buffer */
+ protected function _streamMessage(Swift_Mime_Message $message)
+ {
+ $this->_buffer->setWriteTranslations(array("\r\n." => "\r\n.."));
+ try {
+ $message->toByteStream($this->_buffer);
+ $this->_buffer->flushBuffers();
+ } catch (Swift_TransportException $e) {
+ $this->_throwException($e);
+ }
+ $this->_buffer->setWriteTranslations(array());
+ $this->executeCommand("\r\n.\r\n", array(250));
+ }
+
+ /** Determine the best-use reverse path for this message */
+ protected function _getReversePath(Swift_Mime_Message $message)
+ {
+ $return = $message->getReturnPath();
+ $sender = $message->getSender();
+ $from = $message->getFrom();
+ $path = null;
+ if (!empty($return)) {
+ $path = $return;
+ } elseif (!empty($sender)) {
+ // Don't use array_keys
+ reset($sender); // Reset Pointer to first pos
+ $path = key($sender); // Get key
+ } elseif (!empty($from)) {
+ reset($from); // Reset Pointer to first pos
+ $path = key($from); // Get key
+ }
+
+ return $path;
+ }
+
+ /** Throw a TransportException, first sending it to any listeners */
+ protected function _throwException(Swift_TransportException $e)
+ {
+ if ($evt = $this->_eventDispatcher->createTransportExceptionEvent($this, $e)) {
+ $this->_eventDispatcher->dispatchEvent($evt, 'exceptionThrown');
+ if (!$evt->bubbleCancelled()) {
+ throw $e;
+ }
+ } else {
+ throw $e;
+ }
+ }
+
+ /** Throws an Exception if a response code is incorrect */
+ protected function _assertResponseCode($response, $wanted)
+ {
+ list($code) = sscanf($response, '%3d');
+ $valid = (empty($wanted) || in_array($code, $wanted));
+
+ if ($evt = $this->_eventDispatcher->createResponseEvent($this, $response,
+ $valid)) {
+ $this->_eventDispatcher->dispatchEvent($evt, 'responseReceived');
+ }
+
+ if (!$valid) {
+ $this->_throwException(
+ new Swift_TransportException(
+ 'Expected response code '.implode('/', $wanted).' but got code '.
+ '"'.$code.'", with message "'.$response.'"',
+ $code)
+ );
+ }
+ }
+
+ /** Get an entire multi-line response using its sequence number */
+ protected function _getFullResponse($seq)
+ {
+ $response = '';
+ try {
+ do {
+ $line = $this->_buffer->readLine($seq);
+ $response .= $line;
+ } while (null !== $line && false !== $line && ' ' != $line{3});
+ } catch (Swift_TransportException $e) {
+ $this->_throwException($e);
+ } catch (Swift_IoException $e) {
+ $this->_throwException(
+ new Swift_TransportException(
+ $e->getMessage())
+ );
+ }
+
+ return $response;
+ }
+
+ /** Send an email to the given recipients from the given reverse path */
+ private function _doMailTransaction($message, $reversePath, array $recipients, array &$failedRecipients)
+ {
+ $sent = 0;
+ $this->_doMailFromCommand($reversePath);
+ foreach ($recipients as $forwardPath) {
+ try {
+ $this->_doRcptToCommand($forwardPath);
+ $sent++;
+ } catch (Swift_TransportException $e) {
+ $failedRecipients[] = $forwardPath;
+ }
+ }
+
+ if ($sent != 0) {
+ $this->_doDataCommand();
+ $this->_streamMessage($message);
+ } else {
+ $this->reset();
+ }
+
+ return $sent;
+ }
+
+ /** Send a message to the given To: recipients */
+ private function _sendTo(Swift_Mime_Message $message, $reversePath, array $to, array &$failedRecipients)
+ {
+ if (empty($to)) {
+ return 0;
+ }
+
+ return $this->_doMailTransaction($message, $reversePath, array_keys($to),
+ $failedRecipients);
+ }
+
+ /** Send a message to all Bcc: recipients */
+ private function _sendBcc(Swift_Mime_Message $message, $reversePath, array $bcc, array &$failedRecipients)
+ {
+ $sent = 0;
+ foreach ($bcc as $forwardPath => $name) {
+ $message->setBcc(array($forwardPath => $name));
+ $sent += $this->_doMailTransaction(
+ $message, $reversePath, array($forwardPath), $failedRecipients
+ );
+ }
+
+ return $sent;
+ }
+
+ /** Try to determine the hostname of the server this is run on */
+ private function _lookupHostname()
+ {
+ if (!empty($_SERVER['SERVER_NAME'])
+ && $this->_isFqdn($_SERVER['SERVER_NAME'])) {
+ $this->_domain = $_SERVER['SERVER_NAME'];
+ } elseif (!empty($_SERVER['SERVER_ADDR'])) {
+ $this->_domain = sprintf('[%s]', $_SERVER['SERVER_ADDR']);
+ }
+ }
+
+ /** Determine is the $hostname is a fully-qualified name */
+ private function _isFqdn($hostname)
+ {
+ // We could do a really thorough check, but there's really no point
+ if (false !== $dotPos = strpos($hostname, '.')) {
+ return ($dotPos > 0) && ($dotPos != strlen($hostname) - 1);
+ } else {
+ return false;
+ }
+ }
+
+ /**
+ * Destructor.
+ */
+ public function __destruct()
+ {
+ $this->stop();
+ }
+}
diff --git a/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Transport/Esmtp/Auth/CramMd5Authenticator.php b/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Transport/Esmtp/Auth/CramMd5Authenticator.php
new file mode 100644
index 00000000..4774e032
--- /dev/null
+++ b/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Transport/Esmtp/Auth/CramMd5Authenticator.php
@@ -0,0 +1,81 @@
+executeCommand("AUTH CRAM-MD5\r\n", array(334));
+ $challenge = base64_decode(substr($challenge, 4));
+ $message = base64_encode(
+ $username.' '.$this->_getResponse($password, $challenge)
+ );
+ $agent->executeCommand(sprintf("%s\r\n", $message), array(235));
+
+ return true;
+ } catch (Swift_TransportException $e) {
+ $agent->executeCommand("RSET\r\n", array(250));
+
+ return false;
+ }
+ }
+
+ /**
+ * Generate a CRAM-MD5 response from a server challenge.
+ *
+ * @param string $secret
+ * @param string $challenge
+ *
+ * @return string
+ */
+ private function _getResponse($secret, $challenge)
+ {
+ if (strlen($secret) > 64) {
+ $secret = pack('H32', md5($secret));
+ }
+
+ if (strlen($secret) < 64) {
+ $secret = str_pad($secret, 64, chr(0));
+ }
+
+ $k_ipad = substr($secret, 0, 64) ^ str_repeat(chr(0x36), 64);
+ $k_opad = substr($secret, 0, 64) ^ str_repeat(chr(0x5C), 64);
+
+ $inner = pack('H32', md5($k_ipad.$challenge));
+ $digest = md5($k_opad.$inner);
+
+ return $digest;
+ }
+}
diff --git a/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Transport/Esmtp/Auth/LoginAuthenticator.php b/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Transport/Esmtp/Auth/LoginAuthenticator.php
new file mode 100644
index 00000000..ebb35520
--- /dev/null
+++ b/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Transport/Esmtp/Auth/LoginAuthenticator.php
@@ -0,0 +1,51 @@
+executeCommand("AUTH LOGIN\r\n", array(334));
+ $agent->executeCommand(sprintf("%s\r\n", base64_encode($username)), array(334));
+ $agent->executeCommand(sprintf("%s\r\n", base64_encode($password)), array(235));
+
+ return true;
+ } catch (Swift_TransportException $e) {
+ $agent->executeCommand("RSET\r\n", array(250));
+
+ return false;
+ }
+ }
+}
diff --git a/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Transport/Esmtp/Auth/NTLMAuthenticator.php b/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Transport/Esmtp/Auth/NTLMAuthenticator.php
new file mode 100644
index 00000000..2c02bd2c
--- /dev/null
+++ b/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Transport/Esmtp/Auth/NTLMAuthenticator.php
@@ -0,0 +1,700 @@
+
+ */
+class Swift_Transport_Esmtp_Auth_NTLMAuthenticator implements Swift_Transport_Esmtp_Authenticator
+{
+ const NTLMSIG = "NTLMSSP\x00";
+ const DESCONST = "KGS!@#$%";
+
+ /**
+ * Get the name of the AUTH mechanism this Authenticator handles.
+ *
+ * @return string
+ */
+ public function getAuthKeyword()
+ {
+ return 'NTLM';
+ }
+
+ /**
+ * Try to authenticate the user with $username and $password.
+ *
+ * @param Swift_Transport_SmtpAgent $agent
+ * @param string $username
+ * @param string $password
+ *
+ * @return bool
+ */
+ public function authenticate(Swift_Transport_SmtpAgent $agent, $username, $password)
+ {
+ if (!function_exists('mcrypt_module_open')) {
+ throw new LogicException('The mcrypt functions need to be enabled to use the NTLM authenticator.');
+ }
+
+ if (!function_exists('openssl_random_pseudo_bytes')) {
+ throw new LogicException('The OpenSSL extension must be enabled to use the NTLM authenticator.');
+ }
+
+ if (!function_exists('bcmul')) {
+ throw new LogicException('The BCMatch functions must be enabled to use the NTLM authenticator.');
+ }
+
+ try {
+ // execute AUTH command and filter out the code at the beginning
+ // AUTH NTLM xxxx
+ $response = base64_decode(substr(trim($this->sendMessage1($agent)), 4));
+
+ // extra parameters for our unit cases
+ $timestamp = func_num_args() > 3 ? func_get_arg(3) : $this->getCorrectTimestamp(bcmul(microtime(true), "1000"));
+ $client = func_num_args() > 4 ? func_get_arg(4) : $this->getRandomBytes(8);
+
+ // Message 3 response
+ $this->sendMessage3($response, $username, $password, $timestamp, $client, $agent);
+
+ return true;
+ } catch (Swift_TransportException $e) {
+ $agent->executeCommand("RSET\r\n", array(250));
+
+ return false;
+ }
+ }
+
+ protected function si2bin($si, $bits = 32)
+ {
+ $bin = null;
+ if ($si >= -pow(2, $bits - 1) && ($si <= pow(2, $bits - 1))) {
+ // positive or zero
+ if ($si >= 0) {
+ $bin = base_convert($si, 10, 2);
+ // pad to $bits bit
+ $bin_length = strlen($bin);
+ if ($bin_length < $bits) {
+ $bin = str_repeat("0", $bits - $bin_length).$bin;
+ }
+ } else {
+ // negative
+ $si = -$si - pow(2, $bits);
+ $bin = base_convert($si, 10, 2);
+ $bin_length = strlen($bin);
+ if ($bin_length > $bits) {
+ $bin = str_repeat("1", $bits - $bin_length).$bin;
+ }
+ }
+ }
+
+ return $bin;
+ }
+
+ /**
+ * Send our auth message and returns the response
+ *
+ * @param Swift_Transport_SmtpAgent $agent
+ * @return string SMTP Response
+ */
+ protected function sendMessage1(Swift_Transport_SmtpAgent $agent)
+ {
+ $message = $this->createMessage1();
+
+ return $agent->executeCommand(sprintf("AUTH %s %s\r\n", $this->getAuthKeyword(), base64_encode($message)), array(334));
+ }
+
+ /**
+ * Fetch all details of our response (message 2)
+ *
+ * @param string $response
+ * @return array our response parsed
+ */
+ protected function parseMessage2($response)
+ {
+ $responseHex = bin2hex($response);
+ $length = floor(hexdec(substr($responseHex, 28, 4)) / 256) * 2;
+ $offset = floor(hexdec(substr($responseHex, 32, 4)) / 256) * 2;
+ $challenge = $this->hex2bin(substr($responseHex, 48, 16));
+ $context = $this->hex2bin(substr($responseHex, 64, 16));
+ $targetInfoH = $this->hex2bin(substr($responseHex, 80, 16));
+ $targetName = $this->hex2bin(substr($responseHex, $offset, $length));
+ $offset = floor(hexdec(substr($responseHex, 88, 4)) / 256) * 2;
+ $targetInfoBlock = substr($responseHex, $offset);
+ list($domainName, $serverName, $DNSDomainName, $DNSServerName, $terminatorByte) = $this->readSubBlock($targetInfoBlock);
+
+ return array(
+ $challenge,
+ $context,
+ $targetInfoH,
+ $targetName,
+ $domainName,
+ $serverName,
+ $DNSDomainName,
+ $DNSServerName,
+ $this->hex2bin($targetInfoBlock),
+ $terminatorByte,
+ );
+ }
+
+ /**
+ * Read the blob information in from message2
+ *
+ * @param $block
+ * @return array
+ */
+ protected function readSubBlock($block)
+ {
+ // remove terminatorByte cause it's always the same
+ $block = substr($block, 0, -8);
+
+ $length = strlen($block);
+ $offset = 0;
+ $data = array();
+ while ($offset < $length) {
+ $blockLength = hexdec(substr(substr($block, $offset, 8), -4)) / 256;
+ $offset += 8;
+ $data[] = $this->hex2bin(substr($block, $offset, $blockLength * 2));
+ $offset += $blockLength * 2;
+ }
+
+ if (count($data) == 3) {
+ $data[] = $data[2];
+ $data[2] = '';
+ }
+
+ $data[] = $this->createByte('00');
+
+ return $data;
+ }
+
+ /**
+ * Send our final message with all our data
+ *
+ * @param string $response Message 1 response (message 2)
+ * @param string $username
+ * @param string $password
+ * @param string $timestamp
+ * @param string $client
+ * @param Swift_Transport_SmtpAgent $agent
+ * @param bool $v2 Use version2 of the protocol
+ * @return string
+ */
+ protected function sendMessage3($response, $username, $password, $timestamp, $client, Swift_Transport_SmtpAgent $agent, $v2 = true)
+ {
+ list($domain, $username) = $this->getDomainAndUsername($username);
+ //$challenge, $context, $targetInfoH, $targetName, $domainName, $workstation, $DNSDomainName, $DNSServerName, $blob, $ter
+ list($challenge, , , , , $workstation, , , $blob) = $this->parseMessage2($response);
+
+ if (!$v2) {
+ // LMv1
+ $lmResponse = $this->createLMPassword($password, $challenge);
+ // NTLMv1
+ $ntlmResponse = $this->createNTLMPassword($password, $challenge);
+ } else {
+ // LMv2
+ $lmResponse = $this->createLMv2Password($password, $username, $domain, $challenge, $client);
+ // NTLMv2
+ $ntlmResponse = $this->createNTLMv2Hash($password, $username, $domain, $challenge, $blob, $timestamp, $client);
+ }
+
+ $message = $this->createMessage3($domain, $username, $workstation, $lmResponse, $ntlmResponse);
+
+ return $agent->executeCommand(sprintf("%s\r\n", base64_encode($message)), array(235));
+ }
+
+ /**
+ * Create our message 1
+ *
+ * @return string
+ */
+ protected function createMessage1()
+ {
+ return self::NTLMSIG
+ .$this->createByte('01') // Message 1
+.$this->createByte('0702'); // Flags
+ }
+
+ /**
+ * Create our message 3
+ *
+ * @param string $domain
+ * @param string $username
+ * @param string $workstation
+ * @param string $lmResponse
+ * @param string $ntlmResponse
+ * @return string
+ */
+ protected function createMessage3($domain, $username, $workstation, $lmResponse, $ntlmResponse)
+ {
+ // Create security buffers
+ $domainSec = $this->createSecurityBuffer($domain, 64);
+ $domainInfo = $this->readSecurityBuffer(bin2hex($domainSec));
+ $userSec = $this->createSecurityBuffer($username, ($domainInfo[0] + $domainInfo[1]) / 2);
+ $userInfo = $this->readSecurityBuffer(bin2hex($userSec));
+ $workSec = $this->createSecurityBuffer($workstation, ($userInfo[0] + $userInfo[1]) / 2);
+ $workInfo = $this->readSecurityBuffer(bin2hex($workSec));
+ $lmSec = $this->createSecurityBuffer($lmResponse, ($workInfo[0] + $workInfo[1]) / 2, true);
+ $lmInfo = $this->readSecurityBuffer(bin2hex($lmSec));
+ $ntlmSec = $this->createSecurityBuffer($ntlmResponse, ($lmInfo[0] + $lmInfo[1]) / 2, true);
+
+ return self::NTLMSIG
+ .$this->createByte('03') // TYPE 3 message
+.$lmSec // LM response header
+.$ntlmSec // NTLM response header
+.$domainSec // Domain header
+.$userSec // User header
+.$workSec // Workstation header
+.$this->createByte("000000009a", 8) // session key header (empty)
+.$this->createByte('01020000') // FLAGS
+.$this->convertTo16bit($domain) // domain name
+.$this->convertTo16bit($username) // username
+.$this->convertTo16bit($workstation) // workstation
+.$lmResponse
+ .$ntlmResponse;
+ }
+
+ /**
+ * @param string $timestamp Epoch timestamp in microseconds
+ * @param string $client Random bytes
+ * @param string $targetInfo
+ * @return string
+ */
+ protected function createBlob($timestamp, $client, $targetInfo)
+ {
+ return $this->createByte('0101')
+ .$this->createByte('00')
+ .$timestamp
+ .$client
+ .$this->createByte('00')
+ .$targetInfo
+ .$this->createByte('00');
+ }
+
+ /**
+ * Get domain and username from our username
+ *
+ * @example DOMAIN\username
+ *
+ * @param string $name
+ * @return array
+ */
+ protected function getDomainAndUsername($name)
+ {
+ if (strpos($name, '\\') !== false) {
+ return explode('\\', $name);
+ }
+
+ list($user, $domain) = explode('@', $name);
+
+ return array($domain, $user);
+ }
+
+ /**
+ * Create LMv1 response
+ *
+ * @param string $password
+ * @param string $challenge
+ * @return string
+ */
+ protected function createLMPassword($password, $challenge)
+ {
+ // FIRST PART
+ $password = $this->createByte(strtoupper($password), 14, false);
+ list($key1, $key2) = str_split($password, 7);
+
+ $desKey1 = $this->createDesKey($key1);
+ $desKey2 = $this->createDesKey($key2);
+
+ $constantDecrypt = $this->createByte($this->desEncrypt(self::DESCONST, $desKey1).$this->desEncrypt(self::DESCONST, $desKey2), 21, false);
+
+ // SECOND PART
+ list($key1, $key2, $key3) = str_split($constantDecrypt, 7);
+
+ $desKey1 = $this->createDesKey($key1);
+ $desKey2 = $this->createDesKey($key2);
+ $desKey3 = $this->createDesKey($key3);
+
+ return $this->desEncrypt($challenge, $desKey1).$this->desEncrypt($challenge, $desKey2).$this->desEncrypt($challenge, $desKey3);
+ }
+
+ /**
+ * Create NTLMv1 response
+ *
+ * @param string $password
+ * @param string $challenge
+ * @return string
+ */
+ protected function createNTLMPassword($password, $challenge)
+ {
+ // FIRST PART
+ $ntlmHash = $this->createByte($this->md4Encrypt($password), 21, false);
+ list($key1, $key2, $key3) = str_split($ntlmHash, 7);
+
+ $desKey1 = $this->createDesKey($key1);
+ $desKey2 = $this->createDesKey($key2);
+ $desKey3 = $this->createDesKey($key3);
+
+ return $this->desEncrypt($challenge, $desKey1).$this->desEncrypt($challenge, $desKey2).$this->desEncrypt($challenge, $desKey3);
+ }
+
+ /**
+ * Convert a normal timestamp to a tenth of a microtime epoch time
+ *
+ * @param string $time
+ * @return string
+ */
+ protected function getCorrectTimestamp($time)
+ {
+ // Get our timestamp (tricky!)
+ bcscale(0);
+
+ $time = number_format($time, 0, '.', ''); // save microtime to string
+ $time = bcadd($time, "11644473600000"); // add epoch time
+ $time = bcmul($time, 10000); // tenths of a microsecond.
+
+ $binary = $this->si2bin($time, 64); // create 64 bit binary string
+ $timestamp = "";
+ for ($i = 0; $i < 8; $i++) {
+ $timestamp .= chr(bindec(substr($binary, -(($i + 1) * 8), 8)));
+ }
+
+ return $timestamp;
+ }
+
+ /**
+ * Create LMv2 response
+ *
+ * @param string $password
+ * @param string $username
+ * @param string $domain
+ * @param string $challenge NTLM Challenge
+ * @param string $client Random string
+ * @return string
+ */
+ protected function createLMv2Password($password, $username, $domain, $challenge, $client)
+ {
+ $lmPass = '00'; // by default 00
+ // if $password > 15 than we can't use this method
+ if (strlen($password) <= 15) {
+ $ntlmHash = $this->md4Encrypt($password);
+ $ntml2Hash = $this->md5Encrypt($ntlmHash, $this->convertTo16bit(strtoupper($username).$domain));
+
+ $lmPass = bin2hex($this->md5Encrypt($ntml2Hash, $challenge.$client).$client);
+ }
+
+ return $this->createByte($lmPass, 24);
+ }
+
+ /**
+ * Create NTLMv2 response
+ *
+ * @param string $password
+ * @param string $username
+ * @param string $domain
+ * @param string $challenge Hex values
+ * @param string $targetInfo Hex values
+ * @param string $timestamp
+ * @param string $client Random bytes
+ * @return string
+ * @see http://davenport.sourceforge.net/ntlm.html#theNtlmResponse
+ */
+ protected function createNTLMv2Hash($password, $username, $domain, $challenge, $targetInfo, $timestamp, $client)
+ {
+ $ntlmHash = $this->md4Encrypt($password);
+ $ntml2Hash = $this->md5Encrypt($ntlmHash, $this->convertTo16bit(strtoupper($username).$domain));
+
+ // create blob
+ $blob = $this->createBlob($timestamp, $client, $targetInfo);
+
+ $ntlmv2Response = $this->md5Encrypt($ntml2Hash, $challenge.$blob);
+
+ return $ntlmv2Response.$blob;
+ }
+
+ protected function createDesKey($key)
+ {
+ $material = array(bin2hex($key[0]));
+ $len = strlen($key);
+ for ($i = 1; $i < $len; $i++) {
+ list($high, $low) = str_split(bin2hex($key[$i]));
+ $v = $this->castToByte(ord($key[$i - 1]) << (7 + 1 - $i) | $this->uRShift(hexdec(dechex(hexdec($high) & 0xf).dechex(hexdec($low) & 0xf)), $i));
+ $material[] = str_pad(substr(dechex($v), -2), 2, '0', STR_PAD_LEFT); // cast to byte
+ }
+ $material[] = str_pad(substr(dechex($this->castToByte(ord($key[6]) << 1)), -2), 2, '0');
+
+ // odd parity
+ foreach ($material as $k => $v) {
+ $b = $this->castToByte(hexdec($v));
+ $needsParity = (($this->uRShift($b, 7) ^ $this->uRShift($b, 6) ^ $this->uRShift($b, 5)
+ ^ $this->uRShift($b, 4) ^ $this->uRShift($b, 3) ^ $this->uRShift($b, 2)
+ ^ $this->uRShift($b, 1)) & 0x01) == 0;
+
+ list($high, $low) = str_split($v);
+ if ($needsParity) {
+ $material[$k] = dechex(hexdec($high) | 0x0).dechex(hexdec($low) | 0x1);
+ } else {
+ $material[$k] = dechex(hexdec($high) & 0xf).dechex(hexdec($low) & 0xe);
+ }
+ }
+
+ return $this->hex2bin(implode('', $material));
+ }
+
+ /** HELPER FUNCTIONS */
+ /**
+ * Create our security buffer depending on length and offset
+ *
+ * @param string $value Value we want to put in
+ * @param int $offset start of value
+ * @param bool $is16 Do we 16bit string or not?
+ * @return string
+ */
+ protected function createSecurityBuffer($value, $offset, $is16 = false)
+ {
+ $length = strlen(bin2hex($value));
+ $length = $is16 ? $length / 2 : $length;
+ $length = $this->createByte(str_pad(dechex($length), 2, '0', STR_PAD_LEFT), 2);
+
+ return $length.$length.$this->createByte(dechex($offset), 4);
+ }
+
+ /**
+ * Read our security buffer to fetch length and offset of our value
+ *
+ * @param string $value Securitybuffer in hex
+ * @return array array with length and offset
+ */
+ protected function readSecurityBuffer($value)
+ {
+ $length = floor(hexdec(substr($value, 0, 4)) / 256) * 2;
+ $offset = floor(hexdec(substr($value, 8, 4)) / 256) * 2;
+
+ return array($length, $offset);
+ }
+
+ /**
+ * Cast to byte java equivalent to (byte)
+ *
+ * @param int $v
+ * @return int
+ */
+ protected function castToByte($v)
+ {
+ return (($v + 128) % 256) - 128;
+ }
+
+ /**
+ * Java unsigned right bitwise
+ * $a >>> $b
+ *
+ * @param int $a
+ * @param int $b
+ * @return int
+ */
+ protected function uRShift($a, $b)
+ {
+ if ($b == 0) {
+ return $a;
+ }
+
+ return ($a >> $b) & ~(1 << (8 * PHP_INT_SIZE - 1) >> ($b - 1));
+ }
+
+ /**
+ * Right padding with 0 to certain length
+ *
+ * @param string $input
+ * @param int $bytes Length of bytes
+ * @param bool $isHex Did we provided hex value
+ * @return string
+ */
+ protected function createByte($input, $bytes = 4, $isHex = true)
+ {
+ if ($isHex) {
+ $byte = $this->hex2bin(str_pad($input, $bytes * 2, '00'));
+ } else {
+ $byte = str_pad($input, $bytes, "\x00");
+ }
+
+ return $byte;
+ }
+
+ /**
+ * Create random bytes
+ *
+ * @param $length
+ * @return string
+ */
+ protected function getRandomBytes($length)
+ {
+ $bytes = openssl_random_pseudo_bytes($length, $strong);
+
+ if (false !== $bytes && true === $strong) {
+ return $bytes;
+ }
+
+ throw new RuntimeException('OpenSSL did not produce a secure random number.');
+ }
+
+ /** ENCRYPTION ALGORITHMS */
+ /**
+ * DES Encryption
+ *
+ * @param string $value
+ * @param string $key
+ * @return string
+ */
+ protected function desEncrypt($value, $key)
+ {
+ $cipher = mcrypt_module_open(MCRYPT_DES, '', 'ecb', '');
+ mcrypt_generic_init($cipher, $key, mcrypt_create_iv(mcrypt_enc_get_iv_size($cipher), MCRYPT_DEV_RANDOM));
+
+ return mcrypt_generic($cipher, $value);
+ }
+
+ /**
+ * MD5 Encryption
+ *
+ * @param string $key Encryption key
+ * @param string $msg Message to encrypt
+ * @return string
+ */
+ protected function md5Encrypt($key, $msg)
+ {
+ $blocksize = 64;
+ if (strlen($key) > $blocksize) {
+ $key = pack('H*', md5($key));
+ }
+
+ $key = str_pad($key, $blocksize, "\0");
+ $ipadk = $key ^ str_repeat("\x36", $blocksize);
+ $opadk = $key ^ str_repeat("\x5c", $blocksize);
+
+ return pack('H*', md5($opadk.pack('H*', md5($ipadk.$msg))));
+ }
+
+ /**
+ * MD4 Encryption
+ *
+ * @param string $input
+ * @return string
+ * @see http://php.net/manual/en/ref.hash.php
+ */
+ protected function md4Encrypt($input)
+ {
+ $input = $this->convertTo16bit($input);
+
+ return function_exists('hash') ? $this->hex2bin(hash('md4', $input)) : mhash(MHASH_MD4, $input);
+ }
+
+ /**
+ * Convert UTF-8 to UTF-16
+ *
+ * @param string $input
+ * @return string
+ */
+ protected function convertTo16bit($input)
+ {
+ return iconv('UTF-8', 'UTF-16LE', $input);
+ }
+
+ /**
+ * Hex2bin replacement for < PHP 5.4
+ * @param string $hex
+ * @return string Binary
+ */
+ protected function hex2bin($hex)
+ {
+ if (function_exists('hex2bin')) {
+ return hex2bin($hex);
+ } else {
+ return pack('H*', $hex);
+ }
+ }
+
+ /**
+ * @param string $message
+ */
+ protected function debug($message)
+ {
+ $message = bin2hex($message);
+ $messageId = substr($message, 16, 8);
+ echo substr($message, 0, 16)." NTLMSSP Signature \n";
+ echo $messageId." Type Indicator \n";
+
+ if ($messageId == "02000000") {
+ $map = array(
+ 'Challenge',
+ 'Context',
+ 'Target Information Security Buffer',
+ 'Target Name Data',
+ 'NetBIOS Domain Name',
+ 'NetBIOS Server Name',
+ 'DNS Domain Name',
+ 'DNS Server Name',
+ 'BLOB',
+ 'Target Information Terminator',
+ );
+
+ $data = $this->parseMessage2($this->hex2bin($message));
+
+ foreach ($map as $key => $value) {
+ echo bin2hex($data[$key]).' - '.$data[$key].' ||| '.$value." \n";
+ }
+ } elseif ($messageId == "03000000") {
+ $i = 0;
+ $data[$i++] = substr($message, 24, 16);
+ list($lmLength, $lmOffset) = $this->readSecurityBuffer($data[$i - 1]);
+
+ $data[$i++] = substr($message, 40, 16);
+ list($ntmlLength, $ntmlOffset) = $this->readSecurityBuffer($data[$i - 1]);
+
+ $data[$i++] = substr($message, 56, 16);
+ list($targetLength, $targetOffset) = $this->readSecurityBuffer($data[$i - 1]);
+
+ $data[$i++] = substr($message, 72, 16);
+ list($userLength, $userOffset) = $this->readSecurityBuffer($data[$i - 1]);
+
+ $data[$i++] = substr($message, 88, 16);
+ list($workLength, $workOffset) = $this->readSecurityBuffer($data[$i - 1]);
+
+ $data[$i++] = substr($message, 104, 16);
+ $data[$i++] = substr($message, 120, 8);
+ $data[$i++] = substr($message, $targetOffset, $targetLength);
+ $data[$i++] = substr($message, $userOffset, $userLength);
+ $data[$i++] = substr($message, $workOffset, $workLength);
+ $data[$i++] = substr($message, $lmOffset, $lmLength);
+ $data[$i] = substr($message, $ntmlOffset, $ntmlLength);
+
+ $map = array(
+ 'LM Response Security Buffer',
+ 'NTLM Response Security Buffer',
+ 'Target Name Security Buffer',
+ 'User Name Security Buffer',
+ 'Workstation Name Security Buffer',
+ 'Session Key Security Buffer',
+ 'Flags',
+ 'Target Name Data',
+ 'User Name Data',
+ 'Workstation Name Data',
+ 'LM Response Data',
+ 'NTLM Response Data',
+ );
+
+ foreach ($map as $key => $value) {
+ echo $data[$key].' - '.$this->hex2bin($data[$key]).' ||| '.$value." \n";
+ }
+ }
+
+ echo "
";
+ }
+}
diff --git a/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Transport/Esmtp/Auth/PlainAuthenticator.php b/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Transport/Esmtp/Auth/PlainAuthenticator.php
new file mode 100644
index 00000000..98f6d181
--- /dev/null
+++ b/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Transport/Esmtp/Auth/PlainAuthenticator.php
@@ -0,0 +1,50 @@
+executeCommand(sprintf("AUTH PLAIN %s\r\n", $message), array(235));
+
+ return true;
+ } catch (Swift_TransportException $e) {
+ $agent->executeCommand("RSET\r\n", array(250));
+
+ return false;
+ }
+ }
+}
diff --git a/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Transport/Esmtp/Auth/XOAuth2Authenticator.php b/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Transport/Esmtp/Auth/XOAuth2Authenticator.php
new file mode 100644
index 00000000..80c00b98
--- /dev/null
+++ b/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Transport/Esmtp/Auth/XOAuth2Authenticator.php
@@ -0,0 +1,69 @@
+
+ * $transport = Swift_SmtpTransport::newInstance('smtp.gmail.com', 587, 'tls')
+ * ->setAuthMode('XOAUTH2')
+ * ->setUsername('YOUR_EMAIL_ADDRESS')
+ * ->setPassword('YOUR_ACCESS_TOKEN');
+ *
+ *
+ * @author xu.li
+ * @see https://developers.google.com/google-apps/gmail/xoauth2_protocol
+ */
+class Swift_Transport_Esmtp_Auth_XOAuth2Authenticator implements Swift_Transport_Esmtp_Authenticator
+{
+ /**
+ * Get the name of the AUTH mechanism this Authenticator handles.
+ *
+ * @return string
+ */
+ public function getAuthKeyword()
+ {
+ return 'XOAUTH2';
+ }
+
+ /**
+ * Try to authenticate the user with $email and $token.
+ *
+ * @param Swift_Transport_SmtpAgent $agent
+ * @param string $email
+ * @param string $token
+ *
+ * @return bool
+ */
+ public function authenticate(Swift_Transport_SmtpAgent $agent, $email, $token)
+ {
+ try {
+ $param = $this->constructXOAuth2Params($email, $token);
+ $agent->executeCommand("AUTH XOAUTH2 ".$param."\r\n", array(235));
+
+ return true;
+ } catch (Swift_TransportException $e) {
+ $agent->executeCommand("RSET\r\n", array(250));
+
+ return false;
+ }
+ }
+
+ /**
+ * Construct the auth parameter
+ *
+ * @see https://developers.google.com/google-apps/gmail/xoauth2_protocol#the_sasl_xoauth2_mechanism
+ */
+ protected function constructXOAuth2Params($email, $token)
+ {
+ return base64_encode("user=$email\1auth=Bearer $token\1\1");
+ }
+}
diff --git a/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Transport/Esmtp/AuthHandler.php b/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Transport/Esmtp/AuthHandler.php
new file mode 100644
index 00000000..6b83194c
--- /dev/null
+++ b/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Transport/Esmtp/AuthHandler.php
@@ -0,0 +1,263 @@
+setAuthenticators($authenticators);
+ }
+
+ /**
+ * Set the Authenticators which can process a login request.
+ *
+ * @param Swift_Transport_Esmtp_Authenticator[] $authenticators
+ */
+ public function setAuthenticators(array $authenticators)
+ {
+ $this->_authenticators = $authenticators;
+ }
+
+ /**
+ * Get the Authenticators which can process a login request.
+ *
+ * @return Swift_Transport_Esmtp_Authenticator[]
+ */
+ public function getAuthenticators()
+ {
+ return $this->_authenticators;
+ }
+
+ /**
+ * Set the username to authenticate with.
+ *
+ * @param string $username
+ */
+ public function setUsername($username)
+ {
+ $this->_username = $username;
+ }
+
+ /**
+ * Get the username to authenticate with.
+ *
+ * @return string
+ */
+ public function getUsername()
+ {
+ return $this->_username;
+ }
+
+ /**
+ * Set the password to authenticate with.
+ *
+ * @param string $password
+ */
+ public function setPassword($password)
+ {
+ $this->_password = $password;
+ }
+
+ /**
+ * Get the password to authenticate with.
+ *
+ * @return string
+ */
+ public function getPassword()
+ {
+ return $this->_password;
+ }
+
+ /**
+ * Set the auth mode to use to authenticate.
+ *
+ * @param string $mode
+ */
+ public function setAuthMode($mode)
+ {
+ $this->_auth_mode = $mode;
+ }
+
+ /**
+ * Get the auth mode to use to authenticate.
+ *
+ * @return string
+ */
+ public function getAuthMode()
+ {
+ return $this->_auth_mode;
+ }
+
+ /**
+ * Get the name of the ESMTP extension this handles.
+ *
+ * @return bool
+ */
+ public function getHandledKeyword()
+ {
+ return 'AUTH';
+ }
+
+ /**
+ * Set the parameters which the EHLO greeting indicated.
+ *
+ * @param string[] $parameters
+ */
+ public function setKeywordParams(array $parameters)
+ {
+ $this->_esmtpParams = $parameters;
+ }
+
+ /**
+ * Runs immediately after a EHLO has been issued.
+ *
+ * @param Swift_Transport_SmtpAgent $agent to read/write
+ */
+ public function afterEhlo(Swift_Transport_SmtpAgent $agent)
+ {
+ if ($this->_username) {
+ $count = 0;
+ foreach ($this->_getAuthenticatorsForAgent() as $authenticator) {
+ if (in_array(strtolower($authenticator->getAuthKeyword()),
+ array_map('strtolower', $this->_esmtpParams))) {
+ $count++;
+ if ($authenticator->authenticate($agent, $this->_username, $this->_password)) {
+ return;
+ }
+ }
+ }
+ throw new Swift_TransportException(
+ 'Failed to authenticate on SMTP server with username "'.
+ $this->_username.'" using '.$count.' possible authenticators'
+ );
+ }
+ }
+
+ /**
+ * Not used.
+ */
+ public function getMailParams()
+ {
+ return array();
+ }
+
+ /**
+ * Not used.
+ */
+ public function getRcptParams()
+ {
+ return array();
+ }
+
+ /**
+ * Not used.
+ */
+ public function onCommand(Swift_Transport_SmtpAgent $agent, $command, $codes = array(), &$failedRecipients = null, &$stop = false)
+ {
+ }
+
+ /**
+ * Returns +1, -1 or 0 according to the rules for usort().
+ *
+ * This method is called to ensure extensions can be execute in an appropriate order.
+ *
+ * @param string $esmtpKeyword to compare with
+ *
+ * @return int
+ */
+ public function getPriorityOver($esmtpKeyword)
+ {
+ return 0;
+ }
+
+ /**
+ * Returns an array of method names which are exposed to the Esmtp class.
+ *
+ * @return string[]
+ */
+ public function exposeMixinMethods()
+ {
+ return array('setUsername', 'getUsername', 'setPassword', 'getPassword', 'setAuthMode', 'getAuthMode');
+ }
+
+ /**
+ * Not used.
+ */
+ public function resetState()
+ {
+ }
+
+ /**
+ * Returns the authenticator list for the given agent.
+ *
+ * @param Swift_Transport_SmtpAgent $agent
+ *
+ * @return array
+ */
+ protected function _getAuthenticatorsForAgent()
+ {
+ if (!$mode = strtolower($this->_auth_mode)) {
+ return $this->_authenticators;
+ }
+
+ foreach ($this->_authenticators as $authenticator) {
+ if (strtolower($authenticator->getAuthKeyword()) == $mode) {
+ return array($authenticator);
+ }
+ }
+
+ throw new Swift_TransportException('Auth mode '.$mode.' is invalid');
+ }
+}
diff --git a/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Transport/Esmtp/Authenticator.php b/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Transport/Esmtp/Authenticator.php
new file mode 100644
index 00000000..9078003a
--- /dev/null
+++ b/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Transport/Esmtp/Authenticator.php
@@ -0,0 +1,35 @@
+.
+ *
+ * @return string[]
+ */
+ public function getMailParams();
+
+ /**
+ * Get params which are appended to RCPT TO:<>.
+ *
+ * @return string[]
+ */
+ public function getRcptParams();
+
+ /**
+ * Runs when a command is due to be sent.
+ *
+ * @param Swift_Transport_SmtpAgent $agent to read/write
+ * @param string $command to send
+ * @param int[] $codes expected in response
+ * @param string[] $failedRecipients to collect failures
+ * @param bool $stop to be set true by-reference if the command is now sent
+ */
+ public function onCommand(Swift_Transport_SmtpAgent $agent, $command, $codes = array(), &$failedRecipients = null, &$stop = false);
+
+ /**
+ * Returns +1, -1 or 0 according to the rules for usort().
+ *
+ * This method is called to ensure extensions can be execute in an appropriate order.
+ *
+ * @param string $esmtpKeyword to compare with
+ *
+ * @return int
+ */
+ public function getPriorityOver($esmtpKeyword);
+
+ /**
+ * Returns an array of method names which are exposed to the Esmtp class.
+ *
+ * @return string[]
+ */
+ public function exposeMixinMethods();
+
+ /**
+ * Tells this handler to clear any buffers and reset its state.
+ */
+ public function resetState();
+}
diff --git a/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Transport/EsmtpTransport.php b/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Transport/EsmtpTransport.php
new file mode 100644
index 00000000..e860a8ef
--- /dev/null
+++ b/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Transport/EsmtpTransport.php
@@ -0,0 +1,386 @@
+ 'tcp',
+ 'host' => 'localhost',
+ 'port' => 25,
+ 'timeout' => 30,
+ 'blocking' => 1,
+ 'tls' => false,
+ 'type' => Swift_Transport_IoBuffer::TYPE_SOCKET,
+ );
+
+ /**
+ * Creates a new EsmtpTransport using the given I/O buffer.
+ *
+ * @param Swift_Transport_IoBuffer $buf
+ * @param Swift_Transport_EsmtpHandler[] $extensionHandlers
+ * @param Swift_Events_EventDispatcher $dispatcher
+ */
+ public function __construct(Swift_Transport_IoBuffer $buf, array $extensionHandlers, Swift_Events_EventDispatcher $dispatcher)
+ {
+ parent::__construct($buf, $dispatcher);
+ $this->setExtensionHandlers($extensionHandlers);
+ }
+
+ /**
+ * Set the host to connect to.
+ *
+ * @param string $host
+ *
+ * @return Swift_Transport_EsmtpTransport
+ */
+ public function setHost($host)
+ {
+ $this->_params['host'] = $host;
+
+ return $this;
+ }
+
+ /**
+ * Get the host to connect to.
+ *
+ * @return string
+ */
+ public function getHost()
+ {
+ return $this->_params['host'];
+ }
+
+ /**
+ * Set the port to connect to.
+ *
+ * @param int $port
+ *
+ * @return Swift_Transport_EsmtpTransport
+ */
+ public function setPort($port)
+ {
+ $this->_params['port'] = (int) $port;
+
+ return $this;
+ }
+
+ /**
+ * Get the port to connect to.
+ *
+ * @return int
+ */
+ public function getPort()
+ {
+ return $this->_params['port'];
+ }
+
+ /**
+ * Set the connection timeout.
+ *
+ * @param int $timeout seconds
+ *
+ * @return Swift_Transport_EsmtpTransport
+ */
+ public function setTimeout($timeout)
+ {
+ $this->_params['timeout'] = (int) $timeout;
+ $this->_buffer->setParam('timeout', (int) $timeout);
+
+ return $this;
+ }
+
+ /**
+ * Get the connection timeout.
+ *
+ * @return int
+ */
+ public function getTimeout()
+ {
+ return $this->_params['timeout'];
+ }
+
+ /**
+ * Set the encryption type (tls or ssl)
+ *
+ * @param string $encryption
+ *
+ * @return Swift_Transport_EsmtpTransport
+ */
+ public function setEncryption($encryption)
+ {
+ if ('tls' == $encryption) {
+ $this->_params['protocol'] = 'tcp';
+ $this->_params['tls'] = true;
+ } else {
+ $this->_params['protocol'] = $encryption;
+ $this->_params['tls'] = false;
+ }
+
+ return $this;
+ }
+
+ /**
+ * Get the encryption type.
+ *
+ * @return string
+ */
+ public function getEncryption()
+ {
+ return $this->_params['tls'] ? 'tls' : $this->_params['protocol'];
+ }
+
+ /**
+ * Sets the source IP.
+ *
+ * @param string $source
+ *
+ * @return Swift_Transport_EsmtpTransport
+ */
+ public function setSourceIp($source)
+ {
+ $this->_params['sourceIp'] = $source;
+
+ return $this;
+ }
+
+ /**
+ * Returns the IP used to connect to the destination.
+ *
+ * @return string
+ */
+ public function getSourceIp()
+ {
+ return $this->_params['sourceIp'];
+ }
+
+ /**
+ * Set ESMTP extension handlers.
+ *
+ * @param Swift_Transport_EsmtpHandler[] $handlers
+ *
+ * @return Swift_Transport_EsmtpTransport
+ */
+ public function setExtensionHandlers(array $handlers)
+ {
+ $assoc = array();
+ foreach ($handlers as $handler) {
+ $assoc[$handler->getHandledKeyword()] = $handler;
+ }
+ uasort($assoc, array($this, '_sortHandlers'));
+ $this->_handlers = $assoc;
+ $this->_setHandlerParams();
+
+ return $this;
+ }
+
+ /**
+ * Get ESMTP extension handlers.
+ *
+ * @return Swift_Transport_EsmtpHandler[]
+ */
+ public function getExtensionHandlers()
+ {
+ return array_values($this->_handlers);
+ }
+
+ /**
+ * Run a command against the buffer, expecting the given response codes.
+ *
+ * If no response codes are given, the response will not be validated.
+ * If codes are given, an exception will be thrown on an invalid response.
+ *
+ * @param string $command
+ * @param int[] $codes
+ * @param string[] $failures An array of failures by-reference
+ *
+ * @return string
+ */
+ public function executeCommand($command, $codes = array(), &$failures = null)
+ {
+ $failures = (array) $failures;
+ $stopSignal = false;
+ $response = null;
+ foreach ($this->_getActiveHandlers() as $handler) {
+ $response = $handler->onCommand(
+ $this, $command, $codes, $failures, $stopSignal
+ );
+ if ($stopSignal) {
+ return $response;
+ }
+ }
+
+ return parent::executeCommand($command, $codes, $failures);
+ }
+
+ // -- Mixin invocation code
+
+ /** Mixin handling method for ESMTP handlers */
+ public function __call($method, $args)
+ {
+ foreach ($this->_handlers as $handler) {
+ if (in_array(strtolower($method),
+ array_map('strtolower', (array) $handler->exposeMixinMethods())
+ )) {
+ $return = call_user_func_array(array($handler, $method), $args);
+ // Allow fluid method calls
+ if (is_null($return) && substr($method, 0, 3) == 'set') {
+ return $this;
+ } else {
+ return $return;
+ }
+ }
+ }
+ trigger_error('Call to undefined method '.$method, E_USER_ERROR);
+ }
+
+ /** Get the params to initialize the buffer */
+ protected function _getBufferParams()
+ {
+ return $this->_params;
+ }
+
+ /** Overridden to perform EHLO instead */
+ protected function _doHeloCommand()
+ {
+ try {
+ $response = $this->executeCommand(
+ sprintf("EHLO %s\r\n", $this->_domain), array(250)
+ );
+ } catch (Swift_TransportException $e) {
+ return parent::_doHeloCommand();
+ }
+
+ if ($this->_params['tls']) {
+ try {
+ $this->executeCommand("STARTTLS\r\n", array(220));
+
+ if (!$this->_buffer->startTLS()) {
+ throw new Swift_TransportException('Unable to connect with TLS encryption');
+ }
+
+ try {
+ $response = $this->executeCommand(
+ sprintf("EHLO %s\r\n", $this->_domain), array(250)
+ );
+ } catch (Swift_TransportException $e) {
+ return parent::_doHeloCommand();
+ }
+ } catch (Swift_TransportException $e) {
+ $this->_throwException($e);
+ }
+ }
+
+ $this->_capabilities = $this->_getCapabilities($response);
+ $this->_setHandlerParams();
+ foreach ($this->_getActiveHandlers() as $handler) {
+ $handler->afterEhlo($this);
+ }
+ }
+
+ /** Overridden to add Extension support */
+ protected function _doMailFromCommand($address)
+ {
+ $handlers = $this->_getActiveHandlers();
+ $params = array();
+ foreach ($handlers as $handler) {
+ $params = array_merge($params, (array) $handler->getMailParams());
+ }
+ $paramStr = !empty($params) ? ' '.implode(' ', $params) : '';
+ $this->executeCommand(
+ sprintf("MAIL FROM: <%s>%s\r\n", $address, $paramStr), array(250)
+ );
+ }
+
+ /** Overridden to add Extension support */
+ protected function _doRcptToCommand($address)
+ {
+ $handlers = $this->_getActiveHandlers();
+ $params = array();
+ foreach ($handlers as $handler) {
+ $params = array_merge($params, (array) $handler->getRcptParams());
+ }
+ $paramStr = !empty($params) ? ' '.implode(' ', $params) : '';
+ $this->executeCommand(
+ sprintf("RCPT TO: <%s>%s\r\n", $address, $paramStr), array(250, 251, 252)
+ );
+ }
+
+ /** Determine ESMTP capabilities by function group */
+ private function _getCapabilities($ehloResponse)
+ {
+ $capabilities = array();
+ $ehloResponse = trim($ehloResponse);
+ $lines = explode("\r\n", $ehloResponse);
+ array_shift($lines);
+ foreach ($lines as $line) {
+ if (preg_match('/^[0-9]{3}[ -]([A-Z0-9-]+)((?:[ =].*)?)$/Di', $line, $matches)) {
+ $keyword = strtoupper($matches[1]);
+ $paramStr = strtoupper(ltrim($matches[2], ' ='));
+ $params = !empty($paramStr) ? explode(' ', $paramStr) : array();
+ $capabilities[$keyword] = $params;
+ }
+ }
+
+ return $capabilities;
+ }
+
+ /** Set parameters which are used by each extension handler */
+ private function _setHandlerParams()
+ {
+ foreach ($this->_handlers as $keyword => $handler) {
+ if (array_key_exists($keyword, $this->_capabilities)) {
+ $handler->setKeywordParams($this->_capabilities[$keyword]);
+ }
+ }
+ }
+
+ /** Get ESMTP handlers which are currently ok to use */
+ private function _getActiveHandlers()
+ {
+ $handlers = array();
+ foreach ($this->_handlers as $keyword => $handler) {
+ if (array_key_exists($keyword, $this->_capabilities)) {
+ $handlers[] = $handler;
+ }
+ }
+
+ return $handlers;
+ }
+
+ /** Custom sort for extension handler ordering */
+ private function _sortHandlers($a, $b)
+ {
+ return $a->getPriorityOver($b->getHandledKeyword());
+ }
+}
diff --git a/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Transport/FailoverTransport.php b/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Transport/FailoverTransport.php
new file mode 100644
index 00000000..eafde009
--- /dev/null
+++ b/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Transport/FailoverTransport.php
@@ -0,0 +1,85 @@
+_transports);
+ $sent = 0;
+
+ for ($i = 0; $i < $maxTransports
+ && $transport = $this->_getNextTransport(); ++$i) {
+ try {
+ if (!$transport->isStarted()) {
+ $transport->start();
+ }
+
+ return $transport->send($message, $failedRecipients);
+ } catch (Swift_TransportException $e) {
+ $this->_killCurrentTransport();
+ }
+ }
+
+ if (count($this->_transports) == 0) {
+ throw new Swift_TransportException(
+ 'All Transports in FailoverTransport failed, or no Transports available'
+ );
+ }
+
+ return $sent;
+ }
+
+ protected function _getNextTransport()
+ {
+ if (!isset($this->_currentTransport)) {
+ $this->_currentTransport = parent::_getNextTransport();
+ }
+
+ return $this->_currentTransport;
+ }
+
+ protected function _killCurrentTransport()
+ {
+ $this->_currentTransport = null;
+ parent::_killCurrentTransport();
+ }
+}
diff --git a/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Transport/IoBuffer.php b/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Transport/IoBuffer.php
new file mode 100644
index 00000000..71b3f1e5
--- /dev/null
+++ b/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Transport/IoBuffer.php
@@ -0,0 +1,67 @@
+_transports = $transports;
+ $this->_deadTransports = array();
+ }
+
+ /**
+ * Get $transports to delegate to.
+ *
+ * @return Swift_Transport[]
+ */
+ public function getTransports()
+ {
+ return array_merge($this->_transports, $this->_deadTransports);
+ }
+
+ /**
+ * Test if this Transport mechanism has started.
+ *
+ * @return bool
+ */
+ public function isStarted()
+ {
+ return count($this->_transports) > 0;
+ }
+
+ /**
+ * Start this Transport mechanism.
+ */
+ public function start()
+ {
+ $this->_transports = array_merge($this->_transports, $this->_deadTransports);
+ }
+
+ /**
+ * Stop this Transport mechanism.
+ */
+ public function stop()
+ {
+ foreach ($this->_transports as $transport) {
+ $transport->stop();
+ }
+ }
+
+ /**
+ * Send the given Message.
+ *
+ * Recipient/sender data will be retrieved from the Message API.
+ * The return value is the number of recipients who were accepted for delivery.
+ *
+ * @param Swift_Mime_Message $message
+ * @param string[] $failedRecipients An array of failures by-reference
+ *
+ * @return int
+ */
+ public function send(Swift_Mime_Message $message, &$failedRecipients = null)
+ {
+ $maxTransports = count($this->_transports);
+ $sent = 0;
+
+ for ($i = 0; $i < $maxTransports
+ && $transport = $this->_getNextTransport(); ++$i) {
+ try {
+ if (!$transport->isStarted()) {
+ $transport->start();
+ }
+ if ($sent = $transport->send($message, $failedRecipients)) {
+ break;
+ }
+ } catch (Swift_TransportException $e) {
+ $this->_killCurrentTransport();
+ }
+ }
+
+ if (count($this->_transports) == 0) {
+ throw new Swift_TransportException(
+ 'All Transports in LoadBalancedTransport failed, or no Transports available'
+ );
+ }
+
+ return $sent;
+ }
+
+ /**
+ * Register a plugin.
+ *
+ * @param Swift_Events_EventListener $plugin
+ */
+ public function registerPlugin(Swift_Events_EventListener $plugin)
+ {
+ foreach ($this->_transports as $transport) {
+ $transport->registerPlugin($plugin);
+ }
+ }
+
+ /**
+ * Rotates the transport list around and returns the first instance.
+ *
+ * @return Swift_Transport
+ */
+ protected function _getNextTransport()
+ {
+ if ($next = array_shift($this->_transports)) {
+ $this->_transports[] = $next;
+ }
+
+ return $next;
+ }
+
+ /**
+ * Tag the currently used (top of stack) transport as dead/useless.
+ */
+ protected function _killCurrentTransport()
+ {
+ if ($transport = array_pop($this->_transports)) {
+ try {
+ $transport->stop();
+ } catch (Exception $e) {
+ }
+ $this->_deadTransports[] = $transport;
+ }
+ }
+}
diff --git a/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Transport/MailInvoker.php b/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Transport/MailInvoker.php
new file mode 100644
index 00000000..77489ced
--- /dev/null
+++ b/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Transport/MailInvoker.php
@@ -0,0 +1,32 @@
+_invoker = $invoker;
+ $this->_eventDispatcher = $eventDispatcher;
+ }
+
+ /**
+ * Not used.
+ */
+ public function isStarted()
+ {
+ return false;
+ }
+
+ /**
+ * Not used.
+ */
+ public function start()
+ {
+ }
+
+ /**
+ * Not used.
+ */
+ public function stop()
+ {
+ }
+
+ /**
+ * Set the additional parameters used on the mail() function.
+ *
+ * This string is formatted for sprintf() where %s is the sender address.
+ *
+ * @param string $params
+ *
+ * @return Swift_Transport_MailTransport
+ */
+ public function setExtraParams($params)
+ {
+ $this->_extraParams = $params;
+
+ return $this;
+ }
+
+ /**
+ * Get the additional parameters used on the mail() function.
+ *
+ * This string is formatted for sprintf() where %s is the sender address.
+ *
+ * @return string
+ */
+ public function getExtraParams()
+ {
+ return $this->_extraParams;
+ }
+
+ /**
+ * Send the given Message.
+ *
+ * Recipient/sender data will be retrieved from the Message API.
+ * The return value is the number of recipients who were accepted for delivery.
+ *
+ * @param Swift_Mime_Message $message
+ * @param string[] $failedRecipients An array of failures by-reference
+ *
+ * @return int
+ */
+ public function send(Swift_Mime_Message $message, &$failedRecipients = null)
+ {
+ $failedRecipients = (array) $failedRecipients;
+
+ if ($evt = $this->_eventDispatcher->createSendEvent($this, $message)) {
+ $this->_eventDispatcher->dispatchEvent($evt, 'beforeSendPerformed');
+ if ($evt->bubbleCancelled()) {
+ return 0;
+ }
+ }
+
+ $count = (
+ count((array) $message->getTo())
+ + count((array) $message->getCc())
+ + count((array) $message->getBcc())
+ );
+
+ $toHeader = $message->getHeaders()->get('To');
+ $subjectHeader = $message->getHeaders()->get('Subject');
+
+ if (!$toHeader) {
+ throw new Swift_TransportException(
+ 'Cannot send message without a recipient'
+ );
+ }
+ $to = $toHeader->getFieldBody();
+ $subject = $subjectHeader ? $subjectHeader->getFieldBody() : '';
+
+ $reversePath = $this->_getReversePath($message);
+
+ // Remove headers that would otherwise be duplicated
+ $message->getHeaders()->remove('To');
+ $message->getHeaders()->remove('Subject');
+
+ $messageStr = $message->toString();
+
+ $message->getHeaders()->set($toHeader);
+ $message->getHeaders()->set($subjectHeader);
+
+ // Separate headers from body
+ if (false !== $endHeaders = strpos($messageStr, "\r\n\r\n")) {
+ $headers = substr($messageStr, 0, $endHeaders)."\r\n"; //Keep last EOL
+ $body = substr($messageStr, $endHeaders + 4);
+ } else {
+ $headers = $messageStr."\r\n";
+ $body = '';
+ }
+
+ unset($messageStr);
+
+ if ("\r\n" != PHP_EOL) {
+ // Non-windows (not using SMTP)
+ $headers = str_replace("\r\n", PHP_EOL, $headers);
+ $body = str_replace("\r\n", PHP_EOL, $body);
+ } else {
+ // Windows, using SMTP
+ $headers = str_replace("\r\n.", "\r\n..", $headers);
+ $body = str_replace("\r\n.", "\r\n..", $body);
+ }
+
+ if ($this->_invoker->mail($to, $subject, $body, $headers,
+ sprintf($this->_extraParams, $reversePath))) {
+ if ($evt) {
+ $evt->setResult(Swift_Events_SendEvent::RESULT_SUCCESS);
+ $evt->setFailedRecipients($failedRecipients);
+ $this->_eventDispatcher->dispatchEvent($evt, 'sendPerformed');
+ }
+ } else {
+ $failedRecipients = array_merge(
+ $failedRecipients,
+ array_keys((array) $message->getTo()),
+ array_keys((array) $message->getCc()),
+ array_keys((array) $message->getBcc())
+ );
+
+ if ($evt) {
+ $evt->setResult(Swift_Events_SendEvent::RESULT_FAILED);
+ $evt->setFailedRecipients($failedRecipients);
+ $this->_eventDispatcher->dispatchEvent($evt, 'sendPerformed');
+ }
+
+ $message->generateId();
+
+ $count = 0;
+ }
+
+ return $count;
+ }
+
+ /**
+ * Register a plugin.
+ *
+ * @param Swift_Events_EventListener $plugin
+ */
+ public function registerPlugin(Swift_Events_EventListener $plugin)
+ {
+ $this->_eventDispatcher->bindEventListener($plugin);
+ }
+
+ /** Determine the best-use reverse path for this message */
+ private function _getReversePath(Swift_Mime_Message $message)
+ {
+ $return = $message->getReturnPath();
+ $sender = $message->getSender();
+ $from = $message->getFrom();
+ $path = null;
+ if (!empty($return)) {
+ $path = $return;
+ } elseif (!empty($sender)) {
+ $keys = array_keys($sender);
+ $path = array_shift($keys);
+ } elseif (!empty($from)) {
+ $keys = array_keys($from);
+ $path = array_shift($keys);
+ }
+
+ return $path;
+ }
+}
diff --git a/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Transport/NullTransport.php b/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Transport/NullTransport.php
new file mode 100644
index 00000000..f87cfbf3
--- /dev/null
+++ b/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Transport/NullTransport.php
@@ -0,0 +1,93 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+/**
+ * Pretends messages have been sent, but just ignores them.
+ *
+ * @author Fabien Potencier
+ */
+class Swift_Transport_NullTransport implements Swift_Transport
+{
+ /** The event dispatcher from the plugin API */
+ private $_eventDispatcher;
+
+ /**
+ * Constructor.
+ */
+ public function __construct(Swift_Events_EventDispatcher $eventDispatcher)
+ {
+ $this->_eventDispatcher = $eventDispatcher;
+ }
+
+ /**
+ * Tests if this Transport mechanism has started.
+ *
+ * @return bool
+ */
+ public function isStarted()
+ {
+ return true;
+ }
+
+ /**
+ * Starts this Transport mechanism.
+ */
+ public function start()
+ {
+ }
+
+ /**
+ * Stops this Transport mechanism.
+ */
+ public function stop()
+ {
+ }
+
+ /**
+ * Sends the given message.
+ *
+ * @param Swift_Mime_Message $message
+ * @param string[] $failedRecipients An array of failures by-reference
+ *
+ * @return int The number of sent emails
+ */
+ public function send(Swift_Mime_Message $message, &$failedRecipients = null)
+ {
+ if ($evt = $this->_eventDispatcher->createSendEvent($this, $message)) {
+ $this->_eventDispatcher->dispatchEvent($evt, 'beforeSendPerformed');
+ if ($evt->bubbleCancelled()) {
+ return 0;
+ }
+ }
+
+ if ($evt) {
+ $evt->setResult(Swift_Events_SendEvent::RESULT_SUCCESS);
+ $this->_eventDispatcher->dispatchEvent($evt, 'sendPerformed');
+ }
+
+ $count = (
+ count((array) $message->getTo())
+ + count((array) $message->getCc())
+ + count((array) $message->getBcc())
+ );
+
+ return $count;
+ }
+
+ /**
+ * Register a plugin.
+ *
+ * @param Swift_Events_EventListener $plugin
+ */
+ public function registerPlugin(Swift_Events_EventListener $plugin)
+ {
+ $this->_eventDispatcher->bindEventListener($plugin);
+ }
+}
diff --git a/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Transport/SendmailTransport.php b/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Transport/SendmailTransport.php
new file mode 100644
index 00000000..c508cb13
--- /dev/null
+++ b/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Transport/SendmailTransport.php
@@ -0,0 +1,159 @@
+ 30,
+ 'blocking' => 1,
+ 'command' => '/usr/sbin/sendmail -bs',
+ 'type' => Swift_Transport_IoBuffer::TYPE_PROCESS,
+ );
+
+ /**
+ * Create a new SendmailTransport with $buf for I/O.
+ *
+ * @param Swift_Transport_IoBuffer $buf
+ * @param Swift_Events_EventDispatcher $dispatcher
+ */
+ public function __construct(Swift_Transport_IoBuffer $buf, Swift_Events_EventDispatcher $dispatcher)
+ {
+ parent::__construct($buf, $dispatcher);
+ }
+
+ /**
+ * Start the standalone SMTP session if running in -bs mode.
+ */
+ public function start()
+ {
+ if (false !== strpos($this->getCommand(), ' -bs')) {
+ parent::start();
+ }
+ }
+
+ /**
+ * Set the command to invoke.
+ *
+ * If using -t mode you are strongly advised to include -oi or -i in the flags.
+ * For example: /usr/sbin/sendmail -oi -t
+ * Swift will append a -f flag if one is not present.
+ *
+ * The recommended mode is "-bs" since it is interactive and failure notifications
+ * are hence possible.
+ *
+ * @param string $command
+ *
+ * @return Swift_Transport_SendmailTransport
+ */
+ public function setCommand($command)
+ {
+ $this->_params['command'] = $command;
+
+ return $this;
+ }
+
+ /**
+ * Get the sendmail command which will be invoked.
+ *
+ * @return string
+ */
+ public function getCommand()
+ {
+ return $this->_params['command'];
+ }
+
+ /**
+ * Send the given Message.
+ *
+ * Recipient/sender data will be retrieved from the Message API.
+ *
+ * The return value is the number of recipients who were accepted for delivery.
+ * NOTE: If using 'sendmail -t' you will not be aware of any failures until
+ * they bounce (i.e. send() will always return 100% success).
+ *
+ * @param Swift_Mime_Message $message
+ * @param string[] $failedRecipients An array of failures by-reference
+ *
+ * @return int
+ */
+ public function send(Swift_Mime_Message $message, &$failedRecipients = null)
+ {
+ $failedRecipients = (array) $failedRecipients;
+ $command = $this->getCommand();
+ $buffer = $this->getBuffer();
+
+ if (false !== strpos($command, ' -t')) {
+ if ($evt = $this->_eventDispatcher->createSendEvent($this, $message)) {
+ $this->_eventDispatcher->dispatchEvent($evt, 'beforeSendPerformed');
+ if ($evt->bubbleCancelled()) {
+ return 0;
+ }
+ }
+
+ if (false === strpos($command, ' -f')) {
+ $command .= ' -f'.escapeshellarg($this->_getReversePath($message));
+ }
+
+ $buffer->initialize(array_merge($this->_params, array('command' => $command)));
+
+ if (false === strpos($command, ' -i') && false === strpos($command, ' -oi')) {
+ $buffer->setWriteTranslations(array("\r\n" => "\n", "\n." => "\n.."));
+ } else {
+ $buffer->setWriteTranslations(array("\r\n" => "\n"));
+ }
+
+ $count = count((array) $message->getTo())
+ + count((array) $message->getCc())
+ + count((array) $message->getBcc())
+ ;
+ $message->toByteStream($buffer);
+ $buffer->flushBuffers();
+ $buffer->setWriteTranslations(array());
+ $buffer->terminate();
+
+ if ($evt) {
+ $evt->setResult(Swift_Events_SendEvent::RESULT_SUCCESS);
+ $evt->setFailedRecipients($failedRecipients);
+ $this->_eventDispatcher->dispatchEvent($evt, 'sendPerformed');
+ }
+
+ $message->generateId();
+ } elseif (false !== strpos($command, ' -bs')) {
+ $count = parent::send($message, $failedRecipients);
+ } else {
+ $this->_throwException(new Swift_TransportException(
+ 'Unsupported sendmail command flags ['.$command.']. '.
+ 'Must be one of "-bs" or "-t" but can include additional flags.'
+ ));
+ }
+
+ return $count;
+ }
+
+ /** Get the params to initialize the buffer */
+ protected function _getBufferParams()
+ {
+ return $this->_params;
+ }
+}
diff --git a/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Transport/SimpleMailInvoker.php b/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Transport/SimpleMailInvoker.php
new file mode 100644
index 00000000..21e629a6
--- /dev/null
+++ b/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Transport/SimpleMailInvoker.php
@@ -0,0 +1,39 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+/**
+ * Stores Messages in a queue.
+ *
+ * @author Fabien Potencier
+ */
+class Swift_Transport_SpoolTransport implements Swift_Transport
+{
+ /** The spool instance */
+ private $_spool;
+
+ /** The event dispatcher from the plugin API */
+ private $_eventDispatcher;
+
+ /**
+ * Constructor.
+ */
+ public function __construct(Swift_Events_EventDispatcher $eventDispatcher, Swift_Spool $spool = null)
+ {
+ $this->_eventDispatcher = $eventDispatcher;
+ $this->_spool = $spool;
+ }
+
+ /**
+ * Sets the spool object.
+ *
+ * @param Swift_Spool $spool
+ *
+ * @return Swift_Transport_SpoolTransport
+ */
+ public function setSpool(Swift_Spool $spool)
+ {
+ $this->_spool = $spool;
+
+ return $this;
+ }
+
+ /**
+ * Get the spool object.
+ *
+ * @return Swift_Spool
+ */
+ public function getSpool()
+ {
+ return $this->_spool;
+ }
+
+ /**
+ * Tests if this Transport mechanism has started.
+ *
+ * @return bool
+ */
+ public function isStarted()
+ {
+ return true;
+ }
+
+ /**
+ * Starts this Transport mechanism.
+ */
+ public function start()
+ {
+ }
+
+ /**
+ * Stops this Transport mechanism.
+ */
+ public function stop()
+ {
+ }
+
+ /**
+ * Sends the given message.
+ *
+ * @param Swift_Mime_Message $message
+ * @param string[] $failedRecipients An array of failures by-reference
+ *
+ * @return int The number of sent e-mail's
+ */
+ public function send(Swift_Mime_Message $message, &$failedRecipients = null)
+ {
+ if ($evt = $this->_eventDispatcher->createSendEvent($this, $message)) {
+ $this->_eventDispatcher->dispatchEvent($evt, 'beforeSendPerformed');
+ if ($evt->bubbleCancelled()) {
+ return 0;
+ }
+ }
+
+ $success = $this->_spool->queueMessage($message);
+
+ if ($evt) {
+ $evt->setResult($success ? Swift_Events_SendEvent::RESULT_SUCCESS : Swift_Events_SendEvent::RESULT_FAILED);
+ $this->_eventDispatcher->dispatchEvent($evt, 'sendPerformed');
+ }
+
+ return 1;
+ }
+
+ /**
+ * Register a plugin.
+ *
+ * @param Swift_Events_EventListener $plugin
+ */
+ public function registerPlugin(Swift_Events_EventListener $plugin)
+ {
+ $this->_eventDispatcher->bindEventListener($plugin);
+ }
+}
diff --git a/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Transport/StreamBuffer.php b/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Transport/StreamBuffer.php
new file mode 100644
index 00000000..53e2ffa8
--- /dev/null
+++ b/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Transport/StreamBuffer.php
@@ -0,0 +1,321 @@
+_replacementFactory = $replacementFactory;
+ }
+
+ /**
+ * Perform any initialization needed, using the given $params.
+ *
+ * Parameters will vary depending upon the type of IoBuffer used.
+ *
+ * @param array $params
+ */
+ public function initialize(array $params)
+ {
+ $this->_params = $params;
+ switch ($params['type']) {
+ case self::TYPE_PROCESS:
+ $this->_establishProcessConnection();
+ break;
+ case self::TYPE_SOCKET:
+ default:
+ $this->_establishSocketConnection();
+ break;
+ }
+ }
+
+ /**
+ * Set an individual param on the buffer (e.g. switching to SSL).
+ *
+ * @param string $param
+ * @param mixed $value
+ */
+ public function setParam($param, $value)
+ {
+ if (isset($this->_stream)) {
+ switch ($param) {
+ case 'timeout':
+ if ($this->_stream) {
+ stream_set_timeout($this->_stream, $value);
+ }
+ break;
+
+ case 'blocking':
+ if ($this->_stream) {
+ stream_set_blocking($this->_stream, 1);
+ }
+
+ }
+ }
+ $this->_params[$param] = $value;
+ }
+
+ public function startTLS()
+ {
+ return stream_socket_enable_crypto($this->_stream, true, STREAM_CRYPTO_METHOD_TLS_CLIENT);
+ }
+
+ /**
+ * Perform any shutdown logic needed.
+ */
+ public function terminate()
+ {
+ if (isset($this->_stream)) {
+ switch ($this->_params['type']) {
+ case self::TYPE_PROCESS:
+ fclose($this->_in);
+ fclose($this->_out);
+ proc_close($this->_stream);
+ break;
+ case self::TYPE_SOCKET:
+ default:
+ fclose($this->_stream);
+ break;
+ }
+ }
+ $this->_stream = null;
+ $this->_out = null;
+ $this->_in = null;
+ }
+
+ /**
+ * Set an array of string replacements which should be made on data written
+ * to the buffer.
+ *
+ * This could replace LF with CRLF for example.
+ *
+ * @param string[] $replacements
+ */
+ public function setWriteTranslations(array $replacements)
+ {
+ foreach ($this->_translations as $search => $replace) {
+ if (!isset($replacements[$search])) {
+ $this->removeFilter($search);
+ unset($this->_translations[$search]);
+ }
+ }
+
+ foreach ($replacements as $search => $replace) {
+ if (!isset($this->_translations[$search])) {
+ $this->addFilter(
+ $this->_replacementFactory->createFilter($search, $replace), $search
+ );
+ $this->_translations[$search] = true;
+ }
+ }
+ }
+
+ /**
+ * Get a line of output (including any CRLF).
+ *
+ * The $sequence number comes from any writes and may or may not be used
+ * depending upon the implementation.
+ *
+ * @param int $sequence of last write to scan from
+ *
+ * @return string
+ *
+ * @throws Swift_IoException
+ */
+ public function readLine($sequence)
+ {
+ if (isset($this->_out) && !feof($this->_out)) {
+ $line = fgets($this->_out);
+ if (strlen($line) == 0) {
+ $metas = stream_get_meta_data($this->_out);
+ if ($metas['timed_out']) {
+ throw new Swift_IoException(
+ 'Connection to '.
+ $this->_getReadConnectionDescription().
+ ' Timed Out'
+ );
+ }
+ }
+
+ return $line;
+ }
+ }
+
+ /**
+ * Reads $length bytes from the stream into a string and moves the pointer
+ * through the stream by $length.
+ *
+ * If less bytes exist than are requested the remaining bytes are given instead.
+ * If no bytes are remaining at all, boolean false is returned.
+ *
+ * @param int $length
+ *
+ * @return string|bool
+ *
+ * @throws Swift_IoException
+ */
+ public function read($length)
+ {
+ if (isset($this->_out) && !feof($this->_out)) {
+ $ret = fread($this->_out, $length);
+ if (strlen($ret) == 0) {
+ $metas = stream_get_meta_data($this->_out);
+ if ($metas['timed_out']) {
+ throw new Swift_IoException(
+ 'Connection to '.
+ $this->_getReadConnectionDescription().
+ ' Timed Out'
+ );
+ }
+ }
+
+ return $ret;
+ }
+ }
+
+ /** Not implemented */
+ public function setReadPointer($byteOffset)
+ {
+ }
+
+ /** Flush the stream contents */
+ protected function _flush()
+ {
+ if (isset($this->_in)) {
+ fflush($this->_in);
+ }
+ }
+
+ /** Write this bytes to the stream */
+ protected function _commit($bytes)
+ {
+ if (isset($this->_in)) {
+ $bytesToWrite = strlen($bytes);
+ $totalBytesWritten = 0;
+
+ while ($totalBytesWritten < $bytesToWrite) {
+ $bytesWritten = fwrite($this->_in, substr($bytes, $totalBytesWritten));
+ if (false === $bytesWritten || 0 === $bytesWritten) {
+ break;
+ }
+
+ $totalBytesWritten += $bytesWritten;
+ }
+
+ if ($totalBytesWritten > 0) {
+ return ++$this->_sequence;
+ }
+ }
+ }
+
+ /**
+ * Establishes a connection to a remote server.
+ */
+ private function _establishSocketConnection()
+ {
+ $host = $this->_params['host'];
+ if (!empty($this->_params['protocol'])) {
+ $host = $this->_params['protocol'].'://'.$host;
+ }
+ $timeout = 15;
+ if (!empty($this->_params['timeout'])) {
+ $timeout = $this->_params['timeout'];
+ }
+ $options = array();
+ if (!empty($this->_params['sourceIp'])) {
+ $options['socket']['bindto'] = $this->_params['sourceIp'].':0';
+ }
+ $this->_stream = @stream_socket_client($host.':'.$this->_params['port'], $errno, $errstr, $timeout, STREAM_CLIENT_CONNECT, stream_context_create($options));
+ if (false === $this->_stream) {
+ throw new Swift_TransportException(
+ 'Connection could not be established with host '.$this->_params['host'].
+ ' ['.$errstr.' #'.$errno.']'
+ );
+ }
+ if (!empty($this->_params['blocking'])) {
+ stream_set_blocking($this->_stream, 1);
+ } else {
+ stream_set_blocking($this->_stream, 0);
+ }
+ stream_set_timeout($this->_stream, $timeout);
+ $this->_in = & $this->_stream;
+ $this->_out = & $this->_stream;
+ }
+
+ /**
+ * Opens a process for input/output.
+ */
+ private function _establishProcessConnection()
+ {
+ $command = $this->_params['command'];
+ $descriptorSpec = array(
+ 0 => array('pipe', 'r'),
+ 1 => array('pipe', 'w'),
+ 2 => array('pipe', 'w'),
+ );
+ $this->_stream = proc_open($command, $descriptorSpec, $pipes);
+ stream_set_blocking($pipes[2], 0);
+ if ($err = stream_get_contents($pipes[2])) {
+ throw new Swift_TransportException(
+ 'Process could not be started ['.$err.']'
+ );
+ }
+ $this->_in = & $pipes[0];
+ $this->_out = & $pipes[1];
+ }
+
+ private function _getReadConnectionDescription()
+ {
+ switch ($this->_params['type']) {
+ case self::TYPE_PROCESS:
+ return 'Process '.$this->_params['command'];
+ break;
+
+ case self::TYPE_SOCKET:
+ default:
+ $host = $this->_params['host'];
+ if (!empty($this->_params['protocol'])) {
+ $host = $this->_params['protocol'].'://'.$host;
+ }
+ $host .= ':'.$this->_params['port'];
+
+ return $host;
+ break;
+ }
+ }
+}
diff --git a/vendor/swiftmailer/swiftmailer/lib/classes/Swift/TransportException.php b/vendor/swiftmailer/swiftmailer/lib/classes/Swift/TransportException.php
new file mode 100644
index 00000000..bdcd23bb
--- /dev/null
+++ b/vendor/swiftmailer/swiftmailer/lib/classes/Swift/TransportException.php
@@ -0,0 +1,27 @@
+
+ */
+class Swift_Validate
+{
+ /**
+ * Grammar Object
+ *
+ * @var Swift_Mime_Grammar
+ */
+ private static $grammar = null;
+
+ /**
+ * Checks if an e-mail address matches the current grammars.
+ *
+ * @param string $email
+ *
+ * @return bool
+ */
+ public static function email($email)
+ {
+ if (self::$grammar === null) {
+ self::$grammar = Swift_DependencyContainer::getInstance()
+ ->lookup('mime.grammar');
+ }
+
+ return (bool) preg_match(
+ '/^'.self::$grammar->getDefinition('addr-spec').'$/D',
+ $email
+ );
+ }
+}
diff --git a/vendor/swiftmailer/swiftmailer/lib/dependency_maps/cache_deps.php b/vendor/swiftmailer/swiftmailer/lib/dependency_maps/cache_deps.php
new file mode 100644
index 00000000..6023448e
--- /dev/null
+++ b/vendor/swiftmailer/swiftmailer/lib/dependency_maps/cache_deps.php
@@ -0,0 +1,23 @@
+register('cache')
+ ->asAliasOf('cache.array')
+
+ ->register('tempdir')
+ ->asValue('/tmp')
+
+ ->register('cache.null')
+ ->asSharedInstanceOf('Swift_KeyCache_NullKeyCache')
+
+ ->register('cache.array')
+ ->asSharedInstanceOf('Swift_KeyCache_ArrayKeyCache')
+ ->withDependencies(array('cache.inputstream'))
+
+ ->register('cache.disk')
+ ->asSharedInstanceOf('Swift_KeyCache_DiskKeyCache')
+ ->withDependencies(array('cache.inputstream', 'tempdir'))
+
+ ->register('cache.inputstream')
+ ->asNewInstanceOf('Swift_KeyCache_SimpleKeyCacheInputStream')
+;
diff --git a/vendor/swiftmailer/swiftmailer/lib/dependency_maps/message_deps.php b/vendor/swiftmailer/swiftmailer/lib/dependency_maps/message_deps.php
new file mode 100644
index 00000000..64d69d21
--- /dev/null
+++ b/vendor/swiftmailer/swiftmailer/lib/dependency_maps/message_deps.php
@@ -0,0 +1,9 @@
+register('message.message')
+ ->asNewInstanceOf('Swift_Message')
+
+ ->register('message.mimepart')
+ ->asNewInstanceOf('Swift_MimePart')
+;
diff --git a/vendor/swiftmailer/swiftmailer/lib/dependency_maps/mime_deps.php b/vendor/swiftmailer/swiftmailer/lib/dependency_maps/mime_deps.php
new file mode 100644
index 00000000..04f394b3
--- /dev/null
+++ b/vendor/swiftmailer/swiftmailer/lib/dependency_maps/mime_deps.php
@@ -0,0 +1,123 @@
+register('properties.charset')
+ ->asValue('utf-8')
+
+ ->register('mime.grammar')
+ ->asSharedInstanceOf('Swift_Mime_Grammar')
+
+ ->register('mime.message')
+ ->asNewInstanceOf('Swift_Mime_SimpleMessage')
+ ->withDependencies(array(
+ 'mime.headerset',
+ 'mime.qpcontentencoder',
+ 'cache',
+ 'mime.grammar',
+ 'properties.charset',
+ ))
+
+ ->register('mime.part')
+ ->asNewInstanceOf('Swift_Mime_MimePart')
+ ->withDependencies(array(
+ 'mime.headerset',
+ 'mime.qpcontentencoder',
+ 'cache',
+ 'mime.grammar',
+ 'properties.charset',
+ ))
+
+ ->register('mime.attachment')
+ ->asNewInstanceOf('Swift_Mime_Attachment')
+ ->withDependencies(array(
+ 'mime.headerset',
+ 'mime.base64contentencoder',
+ 'cache',
+ 'mime.grammar',
+ ))
+ ->addConstructorValue($swift_mime_types)
+
+ ->register('mime.embeddedfile')
+ ->asNewInstanceOf('Swift_Mime_EmbeddedFile')
+ ->withDependencies(array(
+ 'mime.headerset',
+ 'mime.base64contentencoder',
+ 'cache',
+ 'mime.grammar',
+ ))
+ ->addConstructorValue($swift_mime_types)
+
+ ->register('mime.headerfactory')
+ ->asNewInstanceOf('Swift_Mime_SimpleHeaderFactory')
+ ->withDependencies(array(
+ 'mime.qpheaderencoder',
+ 'mime.rfc2231encoder',
+ 'mime.grammar',
+ 'properties.charset',
+ ))
+
+ ->register('mime.headerset')
+ ->asNewInstanceOf('Swift_Mime_SimpleHeaderSet')
+ ->withDependencies(array('mime.headerfactory', 'properties.charset'))
+
+ ->register('mime.qpheaderencoder')
+ ->asNewInstanceOf('Swift_Mime_HeaderEncoder_QpHeaderEncoder')
+ ->withDependencies(array('mime.charstream'))
+
+ ->register('mime.base64headerencoder')
+ ->asNewInstanceOf('Swift_Mime_HeaderEncoder_Base64HeaderEncoder')
+ ->withDependencies(array('mime.charstream'))
+
+ ->register('mime.charstream')
+ ->asNewInstanceOf('Swift_CharacterStream_NgCharacterStream')
+ ->withDependencies(array('mime.characterreaderfactory', 'properties.charset'))
+
+ ->register('mime.bytecanonicalizer')
+ ->asSharedInstanceOf('Swift_StreamFilters_ByteArrayReplacementFilter')
+ ->addConstructorValue(array(array(0x0D, 0x0A), array(0x0D), array(0x0A)))
+ ->addConstructorValue(array(array(0x0A), array(0x0A), array(0x0D, 0x0A)))
+
+ ->register('mime.characterreaderfactory')
+ ->asSharedInstanceOf('Swift_CharacterReaderFactory_SimpleCharacterReaderFactory')
+
+ ->register('mime.safeqpcontentencoder')
+ ->asNewInstanceOf('Swift_Mime_ContentEncoder_QpContentEncoder')
+ ->withDependencies(array('mime.charstream', 'mime.bytecanonicalizer'))
+
+ ->register('mime.rawcontentencoder')
+ ->asNewInstanceOf('Swift_Mime_ContentEncoder_RawContentEncoder')
+
+ ->register('mime.nativeqpcontentencoder')
+ ->withDependencies(array('properties.charset'))
+ ->asNewInstanceOf('Swift_Mime_ContentEncoder_NativeQpContentEncoder')
+
+ ->register('mime.qpcontentencoderproxy')
+ ->asNewInstanceOf('Swift_Mime_ContentEncoder_QpContentEncoderProxy')
+ ->withDependencies(array('mime.safeqpcontentencoder', 'mime.nativeqpcontentencoder', 'properties.charset'))
+
+ ->register('mime.7bitcontentencoder')
+ ->asNewInstanceOf('Swift_Mime_ContentEncoder_PlainContentEncoder')
+ ->addConstructorValue('7bit')
+ ->addConstructorValue(true)
+
+ ->register('mime.8bitcontentencoder')
+ ->asNewInstanceOf('Swift_Mime_ContentEncoder_PlainContentEncoder')
+ ->addConstructorValue('8bit')
+ ->addConstructorValue(true)
+
+ ->register('mime.base64contentencoder')
+ ->asSharedInstanceOf('Swift_Mime_ContentEncoder_Base64ContentEncoder')
+
+ ->register('mime.rfc2231encoder')
+ ->asNewInstanceOf('Swift_Encoder_Rfc2231Encoder')
+ ->withDependencies(array('mime.charstream'))
+
+ // As of PHP 5.4.7, the quoted_printable_encode() function behaves correctly.
+ // see https://github.com/php/php-src/commit/18bb426587d62f93c54c40bf8535eb8416603629
+ ->register('mime.qpcontentencoder')
+ ->asAliasOf(version_compare(phpversion(), '5.4.7', '>=') ? 'mime.qpcontentencoderproxy' : 'mime.safeqpcontentencoder')
+;
+
+unset($swift_mime_types);
diff --git a/vendor/swiftmailer/swiftmailer/lib/dependency_maps/transport_deps.php b/vendor/swiftmailer/swiftmailer/lib/dependency_maps/transport_deps.php
new file mode 100644
index 00000000..77e432cf
--- /dev/null
+++ b/vendor/swiftmailer/swiftmailer/lib/dependency_maps/transport_deps.php
@@ -0,0 +1,76 @@
+register('transport.smtp')
+ ->asNewInstanceOf('Swift_Transport_EsmtpTransport')
+ ->withDependencies(array(
+ 'transport.buffer',
+ array('transport.authhandler'),
+ 'transport.eventdispatcher',
+ ))
+
+ ->register('transport.sendmail')
+ ->asNewInstanceOf('Swift_Transport_SendmailTransport')
+ ->withDependencies(array(
+ 'transport.buffer',
+ 'transport.eventdispatcher',
+ ))
+
+ ->register('transport.mail')
+ ->asNewInstanceOf('Swift_Transport_MailTransport')
+ ->withDependencies(array('transport.mailinvoker', 'transport.eventdispatcher'))
+
+ ->register('transport.loadbalanced')
+ ->asNewInstanceOf('Swift_Transport_LoadBalancedTransport')
+
+ ->register('transport.failover')
+ ->asNewInstanceOf('Swift_Transport_FailoverTransport')
+
+ ->register('transport.spool')
+ ->asNewInstanceOf('Swift_Transport_SpoolTransport')
+ ->withDependencies(array('transport.eventdispatcher'))
+
+ ->register('transport.null')
+ ->asNewInstanceOf('Swift_Transport_NullTransport')
+ ->withDependencies(array('transport.eventdispatcher'))
+
+ ->register('transport.mailinvoker')
+ ->asSharedInstanceOf('Swift_Transport_SimpleMailInvoker')
+
+ ->register('transport.buffer')
+ ->asNewInstanceOf('Swift_Transport_StreamBuffer')
+ ->withDependencies(array('transport.replacementfactory'))
+
+ ->register('transport.authhandler')
+ ->asNewInstanceOf('Swift_Transport_Esmtp_AuthHandler')
+ ->withDependencies(array(
+ array(
+ 'transport.crammd5auth',
+ 'transport.loginauth',
+ 'transport.plainauth',
+ 'transport.ntlmauth',
+ 'transport.xoauth2auth',
+ ),
+ ))
+
+ ->register('transport.crammd5auth')
+ ->asNewInstanceOf('Swift_Transport_Esmtp_Auth_CramMd5Authenticator')
+
+ ->register('transport.loginauth')
+ ->asNewInstanceOf('Swift_Transport_Esmtp_Auth_LoginAuthenticator')
+
+ ->register('transport.plainauth')
+ ->asNewInstanceOf('Swift_Transport_Esmtp_Auth_PlainAuthenticator')
+
+ ->register('transport.xoauth2auth')
+ ->asNewInstanceOf('Swift_Transport_Esmtp_Auth_XOAuth2Authenticator')
+
+ ->register('transport.ntlmauth')
+ ->asNewInstanceOf('Swift_Transport_Esmtp_Auth_NTLMAuthenticator')
+
+ ->register('transport.eventdispatcher')
+ ->asNewInstanceOf('Swift_Events_SimpleEventDispatcher')
+
+ ->register('transport.replacementfactory')
+ ->asSharedInstanceOf('Swift_StreamFilters_StringReplacementFilterFactory')
+;
diff --git a/vendor/swiftmailer/swiftmailer/lib/mime_types.php b/vendor/swiftmailer/swiftmailer/lib/mime_types.php
new file mode 100644
index 00000000..2d7b98dc
--- /dev/null
+++ b/vendor/swiftmailer/swiftmailer/lib/mime_types.php
@@ -0,0 +1,1007 @@
+ 'text/vnd.in3d.3dml',
+ '3ds' => 'image/x-3ds',
+ '3g2' => 'video/3gpp2',
+ '3gp' => 'video/3gpp',
+ '7z' => 'application/x-7z-compressed',
+ 'aab' => 'application/x-authorware-bin',
+ 'aac' => 'audio/x-aac',
+ 'aam' => 'application/x-authorware-map',
+ 'aas' => 'application/x-authorware-seg',
+ 'abw' => 'application/x-abiword',
+ 'ac' => 'application/pkix-attr-cert',
+ 'acc' => 'application/vnd.americandynamics.acc',
+ 'ace' => 'application/x-ace-compressed',
+ 'acu' => 'application/vnd.acucobol',
+ 'acutc' => 'application/vnd.acucorp',
+ 'adp' => 'audio/adpcm',
+ 'aep' => 'application/vnd.audiograph',
+ 'afm' => 'application/x-font-type1',
+ 'afp' => 'application/vnd.ibm.modcap',
+ 'ahead' => 'application/vnd.ahead.space',
+ 'ai' => 'application/postscript',
+ 'aif' => 'audio/x-aiff',
+ 'aifc' => 'audio/x-aiff',
+ 'aiff' => 'audio/x-aiff',
+ 'air' => 'application/vnd.adobe.air-application-installer-package+zip',
+ 'ait' => 'application/vnd.dvb.ait',
+ 'ami' => 'application/vnd.amiga.ami',
+ 'apk' => 'application/vnd.android.package-archive',
+ 'appcache' => 'text/cache-manifest',
+ 'apr' => 'application/vnd.lotus-approach',
+ 'aps' => 'application/postscript',
+ 'arc' => 'application/x-freearc',
+ 'asc' => 'application/pgp-signature',
+ 'asf' => 'video/x-ms-asf',
+ 'asm' => 'text/x-asm',
+ 'aso' => 'application/vnd.accpac.simply.aso',
+ 'asx' => 'video/x-ms-asf',
+ 'atc' => 'application/vnd.acucorp',
+ 'atom' => 'application/atom+xml',
+ 'atomcat' => 'application/atomcat+xml',
+ 'atomsvc' => 'application/atomsvc+xml',
+ 'atx' => 'application/vnd.antix.game-component',
+ 'au' => 'audio/basic',
+ 'avi' => 'video/x-msvideo',
+ 'aw' => 'application/applixware',
+ 'azf' => 'application/vnd.airzip.filesecure.azf',
+ 'azs' => 'application/vnd.airzip.filesecure.azs',
+ 'azw' => 'application/vnd.amazon.ebook',
+ 'bat' => 'application/x-msdownload',
+ 'bcpio' => 'application/x-bcpio',
+ 'bdf' => 'application/x-font-bdf',
+ 'bdm' => 'application/vnd.syncml.dm+wbxml',
+ 'bed' => 'application/vnd.realvnc.bed',
+ 'bh2' => 'application/vnd.fujitsu.oasysprs',
+ 'bin' => 'application/octet-stream',
+ 'blb' => 'application/x-blorb',
+ 'blorb' => 'application/x-blorb',
+ 'bmi' => 'application/vnd.bmi',
+ 'bmp' => 'image/bmp',
+ 'book' => 'application/vnd.framemaker',
+ 'box' => 'application/vnd.previewsystems.box',
+ 'boz' => 'application/x-bzip2',
+ 'bpk' => 'application/octet-stream',
+ 'btif' => 'image/prs.btif',
+ 'bz' => 'application/x-bzip',
+ 'bz2' => 'application/x-bzip2',
+ 'c' => 'text/x-c',
+ 'c11amc' => 'application/vnd.cluetrust.cartomobile-config',
+ 'c11amz' => 'application/vnd.cluetrust.cartomobile-config-pkg',
+ 'c4d' => 'application/vnd.clonk.c4group',
+ 'c4f' => 'application/vnd.clonk.c4group',
+ 'c4g' => 'application/vnd.clonk.c4group',
+ 'c4p' => 'application/vnd.clonk.c4group',
+ 'c4u' => 'application/vnd.clonk.c4group',
+ 'cab' => 'application/vnd.ms-cab-compressed',
+ 'caf' => 'audio/x-caf',
+ 'cap' => 'application/vnd.tcpdump.pcap',
+ 'car' => 'application/vnd.curl.car',
+ 'cat' => 'application/vnd.ms-pki.seccat',
+ 'cb7' => 'application/x-cbr',
+ 'cba' => 'application/x-cbr',
+ 'cbr' => 'application/x-cbr',
+ 'cbt' => 'application/x-cbr',
+ 'cbz' => 'application/x-cbr',
+ 'cc' => 'text/x-c',
+ 'cct' => 'application/x-director',
+ 'ccxml' => 'application/ccxml+xml',
+ 'cdbcmsg' => 'application/vnd.contact.cmsg',
+ 'cdf' => 'application/x-netcdf',
+ 'cdkey' => 'application/vnd.mediastation.cdkey',
+ 'cdmia' => 'application/cdmi-capability',
+ 'cdmic' => 'application/cdmi-container',
+ 'cdmid' => 'application/cdmi-domain',
+ 'cdmio' => 'application/cdmi-object',
+ 'cdmiq' => 'application/cdmi-queue',
+ 'cdx' => 'chemical/x-cdx',
+ 'cdxml' => 'application/vnd.chemdraw+xml',
+ 'cdy' => 'application/vnd.cinderella',
+ 'cer' => 'application/pkix-cert',
+ 'cfs' => 'application/x-cfs-compressed',
+ 'cgm' => 'image/cgm',
+ 'chat' => 'application/x-chat',
+ 'chm' => 'application/vnd.ms-htmlhelp',
+ 'chrt' => 'application/vnd.kde.kchart',
+ 'cif' => 'chemical/x-cif',
+ 'cii' => 'application/vnd.anser-web-certificate-issue-initiation',
+ 'cil' => 'application/vnd.ms-artgalry',
+ 'cla' => 'application/vnd.claymore',
+ 'class' => 'application/java-vm',
+ 'clkk' => 'application/vnd.crick.clicker.keyboard',
+ 'clkp' => 'application/vnd.crick.clicker.palette',
+ 'clkt' => 'application/vnd.crick.clicker.template',
+ 'clkw' => 'application/vnd.crick.clicker.wordbank',
+ 'clkx' => 'application/vnd.crick.clicker',
+ 'clp' => 'application/x-msclip',
+ 'cmc' => 'application/vnd.cosmocaller',
+ 'cmdf' => 'chemical/x-cmdf',
+ 'cml' => 'chemical/x-cml',
+ 'cmp' => 'application/vnd.yellowriver-custom-menu',
+ 'cmx' => 'image/x-cmx',
+ 'cod' => 'application/vnd.rim.cod',
+ 'com' => 'application/x-msdownload',
+ 'conf' => 'text/plain',
+ 'cpio' => 'application/x-cpio',
+ 'cpp' => 'text/x-c',
+ 'cpt' => 'application/mac-compactpro',
+ 'crd' => 'application/x-mscardfile',
+ 'crl' => 'application/pkix-crl',
+ 'crt' => 'application/x-x509-ca-cert',
+ 'csh' => 'application/x-csh',
+ 'csml' => 'chemical/x-csml',
+ 'csp' => 'application/vnd.commonspace',
+ 'css' => 'text/css',
+ 'cst' => 'application/x-director',
+ 'csv' => 'text/csv',
+ 'cu' => 'application/cu-seeme',
+ 'curl' => 'text/vnd.curl',
+ 'cww' => 'application/prs.cww',
+ 'cxt' => 'application/x-director',
+ 'cxx' => 'text/x-c',
+ 'dae' => 'model/vnd.collada+xml',
+ 'daf' => 'application/vnd.mobius.daf',
+ 'dart' => 'application/vnd.dart',
+ 'dataless' => 'application/vnd.fdsn.seed',
+ 'davmount' => 'application/davmount+xml',
+ 'dbk' => 'application/docbook+xml',
+ 'dcr' => 'application/x-director',
+ 'dcurl' => 'text/vnd.curl.dcurl',
+ 'dd2' => 'application/vnd.oma.dd2+xml',
+ 'ddd' => 'application/vnd.fujixerox.ddd',
+ 'deb' => 'application/x-debian-package',
+ 'def' => 'text/plain',
+ 'deploy' => 'application/octet-stream',
+ 'der' => 'application/x-x509-ca-cert',
+ 'dfac' => 'application/vnd.dreamfactory',
+ 'dgc' => 'application/x-dgc-compressed',
+ 'dic' => 'text/x-c',
+ 'dir' => 'application/x-director',
+ 'dis' => 'application/vnd.mobius.dis',
+ 'dist' => 'application/octet-stream',
+ 'distz' => 'application/octet-stream',
+ 'djv' => 'image/vnd.djvu',
+ 'djvu' => 'image/vnd.djvu',
+ 'dll' => 'application/x-msdownload',
+ 'dmg' => 'application/x-apple-diskimage',
+ 'dmp' => 'application/vnd.tcpdump.pcap',
+ 'dms' => 'application/octet-stream',
+ 'dna' => 'application/vnd.dna',
+ 'doc' => 'application/msword',
+ 'docm' => 'application/vnd.ms-word.document.macroenabled.12',
+ 'docx' => 'application/vnd.openxmlformats-officedocument.wordprocessingml.document',
+ 'dot' => 'application/msword',
+ 'dotm' => 'application/vnd.ms-word.template.macroenabled.12',
+ 'dotx' => 'application/vnd.openxmlformats-officedocument.wordprocessingml.template',
+ 'dp' => 'application/vnd.osgi.dp',
+ 'dpg' => 'application/vnd.dpgraph',
+ 'dra' => 'audio/vnd.dra',
+ 'dsc' => 'text/prs.lines.tag',
+ 'dssc' => 'application/dssc+der',
+ 'dtb' => 'application/x-dtbook+xml',
+ 'dtd' => 'application/xml-dtd',
+ 'dts' => 'audio/vnd.dts',
+ 'dtshd' => 'audio/vnd.dts.hd',
+ 'dump' => 'application/octet-stream',
+ 'dvb' => 'video/vnd.dvb.file',
+ 'dvi' => 'application/x-dvi',
+ 'dwf' => 'model/vnd.dwf',
+ 'dwg' => 'image/vnd.dwg',
+ 'dxf' => 'image/vnd.dxf',
+ 'dxp' => 'application/vnd.spotfire.dxp',
+ 'dxr' => 'application/x-director',
+ 'ecelp4800' => 'audio/vnd.nuera.ecelp4800',
+ 'ecelp7470' => 'audio/vnd.nuera.ecelp7470',
+ 'ecelp9600' => 'audio/vnd.nuera.ecelp9600',
+ 'ecma' => 'application/ecmascript',
+ 'edm' => 'application/vnd.novadigm.edm',
+ 'edx' => 'application/vnd.novadigm.edx',
+ 'efif' => 'application/vnd.picsel',
+ 'ei6' => 'application/vnd.pg.osasli',
+ 'elc' => 'application/octet-stream',
+ 'emf' => 'application/x-msmetafile',
+ 'eml' => 'message/rfc822',
+ 'emma' => 'application/emma+xml',
+ 'emz' => 'application/x-msmetafile',
+ 'eol' => 'audio/vnd.digital-winds',
+ 'eot' => 'application/vnd.ms-fontobject',
+ 'eps' => 'application/postscript',
+ 'epub' => 'application/epub+zip',
+ 'es3' => 'application/vnd.eszigno3+xml',
+ 'esa' => 'application/vnd.osgi.subsystem',
+ 'esf' => 'application/vnd.epson.esf',
+ 'et3' => 'application/vnd.eszigno3+xml',
+ 'etx' => 'text/x-setext',
+ 'eva' => 'application/x-eva',
+ 'evy' => 'application/x-envoy',
+ 'exe' => 'application/x-msdownload',
+ 'exi' => 'application/exi',
+ 'ext' => 'application/vnd.novadigm.ext',
+ 'ez' => 'application/andrew-inset',
+ 'ez2' => 'application/vnd.ezpix-album',
+ 'ez3' => 'application/vnd.ezpix-package',
+ 'f' => 'text/x-fortran',
+ 'f4v' => 'video/x-f4v',
+ 'f77' => 'text/x-fortran',
+ 'f90' => 'text/x-fortran',
+ 'fbs' => 'image/vnd.fastbidsheet',
+ 'fcdt' => 'application/vnd.adobe.formscentral.fcdt',
+ 'fcs' => 'application/vnd.isac.fcs',
+ 'fdf' => 'application/vnd.fdf',
+ 'fe_launch' => 'application/vnd.denovo.fcselayout-link',
+ 'fg5' => 'application/vnd.fujitsu.oasysgp',
+ 'fgd' => 'application/x-director',
+ 'fh' => 'image/x-freehand',
+ 'fh4' => 'image/x-freehand',
+ 'fh5' => 'image/x-freehand',
+ 'fh7' => 'image/x-freehand',
+ 'fhc' => 'image/x-freehand',
+ 'fig' => 'application/x-xfig',
+ 'flac' => 'audio/x-flac',
+ 'fli' => 'video/x-fli',
+ 'flo' => 'application/vnd.micrografx.flo',
+ 'flv' => 'video/x-flv',
+ 'flw' => 'application/vnd.kde.kivio',
+ 'flx' => 'text/vnd.fmi.flexstor',
+ 'fly' => 'text/vnd.fly',
+ 'fm' => 'application/vnd.framemaker',
+ 'fnc' => 'application/vnd.frogans.fnc',
+ 'for' => 'text/x-fortran',
+ 'fpx' => 'image/vnd.fpx',
+ 'frame' => 'application/vnd.framemaker',
+ 'fsc' => 'application/vnd.fsc.weblaunch',
+ 'fst' => 'image/vnd.fst',
+ 'ftc' => 'application/vnd.fluxtime.clip',
+ 'fti' => 'application/vnd.anser-web-funds-transfer-initiation',
+ 'fvt' => 'video/vnd.fvt',
+ 'fxp' => 'application/vnd.adobe.fxp',
+ 'fxpl' => 'application/vnd.adobe.fxp',
+ 'fzs' => 'application/vnd.fuzzysheet',
+ 'g2w' => 'application/vnd.geoplan',
+ 'g3' => 'image/g3fax',
+ 'g3w' => 'application/vnd.geospace',
+ 'gac' => 'application/vnd.groove-account',
+ 'gam' => 'application/x-tads',
+ 'gbr' => 'application/rpki-ghostbusters',
+ 'gca' => 'application/x-gca-compressed',
+ 'gdl' => 'model/vnd.gdl',
+ 'geo' => 'application/vnd.dynageo',
+ 'gex' => 'application/vnd.geometry-explorer',
+ 'ggb' => 'application/vnd.geogebra.file',
+ 'ggt' => 'application/vnd.geogebra.tool',
+ 'ghf' => 'application/vnd.groove-help',
+ 'gif' => 'image/gif',
+ 'gim' => 'application/vnd.groove-identity-message',
+ 'gml' => 'application/gml+xml',
+ 'gmx' => 'application/vnd.gmx',
+ 'gnumeric' => 'application/x-gnumeric',
+ 'gph' => 'application/vnd.flographit',
+ 'gpx' => 'application/gpx+xml',
+ 'gqf' => 'application/vnd.grafeq',
+ 'gqs' => 'application/vnd.grafeq',
+ 'gram' => 'application/srgs',
+ 'gramps' => 'application/x-gramps-xml',
+ 'gre' => 'application/vnd.geometry-explorer',
+ 'grv' => 'application/vnd.groove-injector',
+ 'grxml' => 'application/srgs+xml',
+ 'gsf' => 'application/x-font-ghostscript',
+ 'gtar' => 'application/x-gtar',
+ 'gtm' => 'application/vnd.groove-tool-message',
+ 'gtw' => 'model/vnd.gtw',
+ 'gv' => 'text/vnd.graphviz',
+ 'gxf' => 'application/gxf',
+ 'gxt' => 'application/vnd.geonext',
+ 'gz' => 'application/x-gzip',
+ 'h' => 'text/x-c',
+ 'h261' => 'video/h261',
+ 'h263' => 'video/h263',
+ 'h264' => 'video/h264',
+ 'hal' => 'application/vnd.hal+xml',
+ 'hbci' => 'application/vnd.hbci',
+ 'hdf' => 'application/x-hdf',
+ 'hh' => 'text/x-c',
+ 'hlp' => 'application/winhlp',
+ 'hpgl' => 'application/vnd.hp-hpgl',
+ 'hpid' => 'application/vnd.hp-hpid',
+ 'hps' => 'application/vnd.hp-hps',
+ 'hqx' => 'application/mac-binhex40',
+ 'htke' => 'application/vnd.kenameaapp',
+ 'htm' => 'text/html',
+ 'html' => 'text/html',
+ 'hvd' => 'application/vnd.yamaha.hv-dic',
+ 'hvp' => 'application/vnd.yamaha.hv-voice',
+ 'hvs' => 'application/vnd.yamaha.hv-script',
+ 'i2g' => 'application/vnd.intergeo',
+ 'icc' => 'application/vnd.iccprofile',
+ 'ice' => 'x-conference/x-cooltalk',
+ 'icm' => 'application/vnd.iccprofile',
+ 'ico' => 'image/x-icon',
+ 'ics' => 'text/calendar',
+ 'ief' => 'image/ief',
+ 'ifb' => 'text/calendar',
+ 'ifm' => 'application/vnd.shana.informed.formdata',
+ 'iges' => 'model/iges',
+ 'igl' => 'application/vnd.igloader',
+ 'igm' => 'application/vnd.insors.igm',
+ 'igs' => 'model/iges',
+ 'igx' => 'application/vnd.micrografx.igx',
+ 'iif' => 'application/vnd.shana.informed.interchange',
+ 'imp' => 'application/vnd.accpac.simply.imp',
+ 'ims' => 'application/vnd.ms-ims',
+ 'in' => 'text/plain',
+ 'ink' => 'application/inkml+xml',
+ 'inkml' => 'application/inkml+xml',
+ 'install' => 'application/x-install-instructions',
+ 'iota' => 'application/vnd.astraea-software.iota',
+ 'ipfix' => 'application/ipfix',
+ 'ipk' => 'application/vnd.shana.informed.package',
+ 'irm' => 'application/vnd.ibm.rights-management',
+ 'irp' => 'application/vnd.irepository.package+xml',
+ 'iso' => 'application/x-iso9660-image',
+ 'itp' => 'application/vnd.shana.informed.formtemplate',
+ 'ivp' => 'application/vnd.immervision-ivp',
+ 'ivu' => 'application/vnd.immervision-ivu',
+ 'jad' => 'text/vnd.sun.j2me.app-descriptor',
+ 'jam' => 'application/vnd.jam',
+ 'jar' => 'application/java-archive',
+ 'java' => 'text/x-java-source',
+ 'jisp' => 'application/vnd.jisp',
+ 'jlt' => 'application/vnd.hp-jlyt',
+ 'jnlp' => 'application/x-java-jnlp-file',
+ 'joda' => 'application/vnd.joost.joda-archive',
+ 'jpe' => 'image/jpeg',
+ 'jpeg' => 'image/jpeg',
+ 'jpg' => 'image/jpeg',
+ 'jpgm' => 'video/jpm',
+ 'jpgv' => 'video/jpeg',
+ 'jpm' => 'video/jpm',
+ 'js' => 'application/javascript',
+ 'json' => 'application/json',
+ 'jsonml' => 'application/jsonml+json',
+ 'kar' => 'audio/midi',
+ 'karbon' => 'application/vnd.kde.karbon',
+ 'kfo' => 'application/vnd.kde.kformula',
+ 'kia' => 'application/vnd.kidspiration',
+ 'kml' => 'application/vnd.google-earth.kml+xml',
+ 'kmz' => 'application/vnd.google-earth.kmz',
+ 'kne' => 'application/vnd.kinar',
+ 'knp' => 'application/vnd.kinar',
+ 'kon' => 'application/vnd.kde.kontour',
+ 'kpr' => 'application/vnd.kde.kpresenter',
+ 'kpt' => 'application/vnd.kde.kpresenter',
+ 'kpxx' => 'application/vnd.ds-keypoint',
+ 'ksp' => 'application/vnd.kde.kspread',
+ 'ktr' => 'application/vnd.kahootz',
+ 'ktx' => 'image/ktx',
+ 'ktz' => 'application/vnd.kahootz',
+ 'kwd' => 'application/vnd.kde.kword',
+ 'kwt' => 'application/vnd.kde.kword',
+ 'lasxml' => 'application/vnd.las.las+xml',
+ 'latex' => 'application/x-latex',
+ 'lbd' => 'application/vnd.llamagraphics.life-balance.desktop',
+ 'lbe' => 'application/vnd.llamagraphics.life-balance.exchange+xml',
+ 'les' => 'application/vnd.hhe.lesson-player',
+ 'lha' => 'application/x-lzh-compressed',
+ 'link66' => 'application/vnd.route66.link66+xml',
+ 'list' => 'text/plain',
+ 'list3820' => 'application/vnd.ibm.modcap',
+ 'listafp' => 'application/vnd.ibm.modcap',
+ 'lnk' => 'application/x-ms-shortcut',
+ 'log' => 'text/plain',
+ 'lostxml' => 'application/lost+xml',
+ 'lrf' => 'application/octet-stream',
+ 'lrm' => 'application/vnd.ms-lrm',
+ 'ltf' => 'application/vnd.frogans.ltf',
+ 'lvp' => 'audio/vnd.lucent.voice',
+ 'lwp' => 'application/vnd.lotus-wordpro',
+ 'lzh' => 'application/x-lzh-compressed',
+ 'm13' => 'application/x-msmediaview',
+ 'm14' => 'application/x-msmediaview',
+ 'm1v' => 'video/mpeg',
+ 'm21' => 'application/mp21',
+ 'm2a' => 'audio/mpeg',
+ 'm2v' => 'video/mpeg',
+ 'm3a' => 'audio/mpeg',
+ 'm3u' => 'audio/x-mpegurl',
+ 'm3u8' => 'application/vnd.apple.mpegurl',
+ 'm4a' => 'audio/mp4',
+ 'm4u' => 'video/vnd.mpegurl',
+ 'm4v' => 'video/x-m4v',
+ 'ma' => 'application/mathematica',
+ 'mads' => 'application/mads+xml',
+ 'mag' => 'application/vnd.ecowin.chart',
+ 'maker' => 'application/vnd.framemaker',
+ 'man' => 'text/troff',
+ 'mar' => 'application/octet-stream',
+ 'mathml' => 'application/mathml+xml',
+ 'mb' => 'application/mathematica',
+ 'mbk' => 'application/vnd.mobius.mbk',
+ 'mbox' => 'application/mbox',
+ 'mc1' => 'application/vnd.medcalcdata',
+ 'mcd' => 'application/vnd.mcd',
+ 'mcurl' => 'text/vnd.curl.mcurl',
+ 'mdb' => 'application/x-msaccess',
+ 'mdi' => 'image/vnd.ms-modi',
+ 'me' => 'text/troff',
+ 'mesh' => 'model/mesh',
+ 'meta4' => 'application/metalink4+xml',
+ 'metalink' => 'application/metalink+xml',
+ 'mets' => 'application/mets+xml',
+ 'mfm' => 'application/vnd.mfmp',
+ 'mft' => 'application/rpki-manifest',
+ 'mgp' => 'application/vnd.osgeo.mapguide.package',
+ 'mgz' => 'application/vnd.proteus.magazine',
+ 'mid' => 'audio/midi',
+ 'midi' => 'audio/midi',
+ 'mie' => 'application/x-mie',
+ 'mif' => 'application/vnd.mif',
+ 'mime' => 'message/rfc822',
+ 'mj2' => 'video/mj2',
+ 'mjp2' => 'video/mj2',
+ 'mk3d' => 'video/x-matroska',
+ 'mka' => 'audio/x-matroska',
+ 'mks' => 'video/x-matroska',
+ 'mkv' => 'video/x-matroska',
+ 'mlp' => 'application/vnd.dolby.mlp',
+ 'mmd' => 'application/vnd.chipnuts.karaoke-mmd',
+ 'mmf' => 'application/vnd.smaf',
+ 'mmr' => 'image/vnd.fujixerox.edmics-mmr',
+ 'mng' => 'video/x-mng',
+ 'mny' => 'application/x-msmoney',
+ 'mobi' => 'application/x-mobipocket-ebook',
+ 'mods' => 'application/mods+xml',
+ 'mov' => 'video/quicktime',
+ 'movie' => 'video/x-sgi-movie',
+ 'mp2' => 'audio/mpeg',
+ 'mp21' => 'application/mp21',
+ 'mp2a' => 'audio/mpeg',
+ 'mp3' => 'audio/mpeg',
+ 'mp4' => 'video/mp4',
+ 'mp4a' => 'audio/mp4',
+ 'mp4s' => 'application/mp4',
+ 'mp4v' => 'video/mp4',
+ 'mpc' => 'application/vnd.mophun.certificate',
+ 'mpe' => 'video/mpeg',
+ 'mpeg' => 'video/mpeg',
+ 'mpg' => 'video/mpeg',
+ 'mpg4' => 'video/mp4',
+ 'mpga' => 'audio/mpeg',
+ 'mpkg' => 'application/vnd.apple.installer+xml',
+ 'mpm' => 'application/vnd.blueice.multipass',
+ 'mpn' => 'application/vnd.mophun.application',
+ 'mpp' => 'application/vnd.ms-project',
+ 'mpt' => 'application/vnd.ms-project',
+ 'mpy' => 'application/vnd.ibm.minipay',
+ 'mqy' => 'application/vnd.mobius.mqy',
+ 'mrc' => 'application/marc',
+ 'mrcx' => 'application/marcxml+xml',
+ 'ms' => 'text/troff',
+ 'mscml' => 'application/mediaservercontrol+xml',
+ 'mseed' => 'application/vnd.fdsn.mseed',
+ 'mseq' => 'application/vnd.mseq',
+ 'msf' => 'application/vnd.epson.msf',
+ 'msh' => 'model/mesh',
+ 'msi' => 'application/x-msdownload',
+ 'msl' => 'application/vnd.mobius.msl',
+ 'msty' => 'application/vnd.muvee.style',
+ 'mts' => 'model/vnd.mts',
+ 'mus' => 'application/vnd.musician',
+ 'musicxml' => 'application/vnd.recordare.musicxml+xml',
+ 'mvb' => 'application/x-msmediaview',
+ 'mwf' => 'application/vnd.mfer',
+ 'mxf' => 'application/mxf',
+ 'mxl' => 'application/vnd.recordare.musicxml',
+ 'mxml' => 'application/xv+xml',
+ 'mxs' => 'application/vnd.triscape.mxs',
+ 'mxu' => 'video/vnd.mpegurl',
+ 'n-gage' => 'application/vnd.nokia.n-gage.symbian.install',
+ 'n3' => 'text/n3',
+ 'nb' => 'application/mathematica',
+ 'nbp' => 'application/vnd.wolfram.player',
+ 'nc' => 'application/x-netcdf',
+ 'ncx' => 'application/x-dtbncx+xml',
+ 'nfo' => 'text/x-nfo',
+ 'ngdat' => 'application/vnd.nokia.n-gage.data',
+ 'nitf' => 'application/vnd.nitf',
+ 'nlu' => 'application/vnd.neurolanguage.nlu',
+ 'nml' => 'application/vnd.enliven',
+ 'nnd' => 'application/vnd.noblenet-directory',
+ 'nns' => 'application/vnd.noblenet-sealer',
+ 'nnw' => 'application/vnd.noblenet-web',
+ 'npx' => 'image/vnd.net-fpx',
+ 'nsc' => 'application/x-conference',
+ 'nsf' => 'application/vnd.lotus-notes',
+ 'ntf' => 'application/vnd.nitf',
+ 'nzb' => 'application/x-nzb',
+ 'oa2' => 'application/vnd.fujitsu.oasys2',
+ 'oa3' => 'application/vnd.fujitsu.oasys3',
+ 'oas' => 'application/vnd.fujitsu.oasys',
+ 'obd' => 'application/x-msbinder',
+ 'obj' => 'application/x-tgif',
+ 'oda' => 'application/oda',
+ 'odb' => 'application/vnd.oasis.opendocument.database',
+ 'odc' => 'application/vnd.oasis.opendocument.chart',
+ 'odf' => 'application/vnd.oasis.opendocument.formula',
+ 'odft' => 'application/vnd.oasis.opendocument.formula-template',
+ 'odg' => 'application/vnd.oasis.opendocument.graphics',
+ 'odi' => 'application/vnd.oasis.opendocument.image',
+ 'odm' => 'application/vnd.oasis.opendocument.text-master',
+ 'odp' => 'application/vnd.oasis.opendocument.presentation',
+ 'ods' => 'application/vnd.oasis.opendocument.spreadsheet',
+ 'odt' => 'application/vnd.oasis.opendocument.text',
+ 'oga' => 'audio/ogg',
+ 'ogg' => 'audio/ogg',
+ 'ogv' => 'video/ogg',
+ 'ogx' => 'application/ogg',
+ 'omdoc' => 'application/omdoc+xml',
+ 'onepkg' => 'application/onenote',
+ 'onetmp' => 'application/onenote',
+ 'onetoc' => 'application/onenote',
+ 'onetoc2' => 'application/onenote',
+ 'opf' => 'application/oebps-package+xml',
+ 'opml' => 'text/x-opml',
+ 'oprc' => 'application/vnd.palm',
+ 'org' => 'application/vnd.lotus-organizer',
+ 'osf' => 'application/vnd.yamaha.openscoreformat',
+ 'osfpvg' => 'application/vnd.yamaha.openscoreformat.osfpvg+xml',
+ 'otc' => 'application/vnd.oasis.opendocument.chart-template',
+ 'otf' => 'application/x-font-otf',
+ 'otg' => 'application/vnd.oasis.opendocument.graphics-template',
+ 'oth' => 'application/vnd.oasis.opendocument.text-web',
+ 'oti' => 'application/vnd.oasis.opendocument.image-template',
+ 'otp' => 'application/vnd.oasis.opendocument.presentation-template',
+ 'ots' => 'application/vnd.oasis.opendocument.spreadsheet-template',
+ 'ott' => 'application/vnd.oasis.opendocument.text-template',
+ 'oxps' => 'application/oxps',
+ 'oxt' => 'application/vnd.openofficeorg.extension',
+ 'p' => 'text/x-pascal',
+ 'p10' => 'application/pkcs10',
+ 'p12' => 'application/x-pkcs12',
+ 'p7b' => 'application/x-pkcs7-certificates',
+ 'p7c' => 'application/pkcs7-mime',
+ 'p7m' => 'application/pkcs7-mime',
+ 'p7r' => 'application/x-pkcs7-certreqresp',
+ 'p7s' => 'application/pkcs7-signature',
+ 'p8' => 'application/pkcs8',
+ 'pas' => 'text/x-pascal',
+ 'paw' => 'application/vnd.pawaafile',
+ 'pbd' => 'application/vnd.powerbuilder6',
+ 'pbm' => 'image/x-portable-bitmap',
+ 'pcap' => 'application/vnd.tcpdump.pcap',
+ 'pcf' => 'application/x-font-pcf',
+ 'pcl' => 'application/vnd.hp-pcl',
+ 'pclxl' => 'application/vnd.hp-pclxl',
+ 'pct' => 'image/x-pict',
+ 'pcurl' => 'application/vnd.curl.pcurl',
+ 'pcx' => 'image/x-pcx',
+ 'pdb' => 'application/vnd.palm',
+ 'pdf' => 'application/pdf',
+ 'pfa' => 'application/x-font-type1',
+ 'pfb' => 'application/x-font-type1',
+ 'pfm' => 'application/x-font-type1',
+ 'pfr' => 'application/font-tdpfr',
+ 'pfx' => 'application/x-pkcs12',
+ 'pgm' => 'image/x-portable-graymap',
+ 'pgn' => 'application/x-chess-pgn',
+ 'pgp' => 'application/pgp-encrypted',
+ 'php' => 'application/x-php',
+ 'php3' => 'application/x-php',
+ 'php4' => 'application/x-php',
+ 'php5' => 'application/x-php',
+ 'pic' => 'image/x-pict',
+ 'pkg' => 'application/octet-stream',
+ 'pki' => 'application/pkixcmp',
+ 'pkipath' => 'application/pkix-pkipath',
+ 'plb' => 'application/vnd.3gpp.pic-bw-large',
+ 'plc' => 'application/vnd.mobius.plc',
+ 'plf' => 'application/vnd.pocketlearn',
+ 'pls' => 'application/pls+xml',
+ 'pml' => 'application/vnd.ctc-posml',
+ 'png' => 'image/png',
+ 'pnm' => 'image/x-portable-anymap',
+ 'portpkg' => 'application/vnd.macports.portpkg',
+ 'pot' => 'application/vnd.ms-powerpoint',
+ 'potm' => 'application/vnd.ms-powerpoint.template.macroenabled.12',
+ 'potx' => 'application/vnd.openxmlformats-officedocument.presentationml.template',
+ 'ppam' => 'application/vnd.ms-powerpoint.addin.macroenabled.12',
+ 'ppd' => 'application/vnd.cups-ppd',
+ 'ppm' => 'image/x-portable-pixmap',
+ 'pps' => 'application/vnd.ms-powerpoint',
+ 'ppsm' => 'application/vnd.ms-powerpoint.slideshow.macroenabled.12',
+ 'ppsx' => 'application/vnd.openxmlformats-officedocument.presentationml.slideshow',
+ 'ppt' => 'application/vnd.ms-powerpoint',
+ 'pptm' => 'application/vnd.ms-powerpoint.presentation.macroenabled.12',
+ 'pptx' => 'application/vnd.openxmlformats-officedocument.presentationml.presentation',
+ 'pqa' => 'application/vnd.palm',
+ 'prc' => 'application/x-mobipocket-ebook',
+ 'pre' => 'application/vnd.lotus-freelance',
+ 'prf' => 'application/pics-rules',
+ 'ps' => 'application/postscript',
+ 'psb' => 'application/vnd.3gpp.pic-bw-small',
+ 'psd' => 'image/vnd.adobe.photoshop',
+ 'psf' => 'application/x-font-linux-psf',
+ 'pskcxml' => 'application/pskc+xml',
+ 'ptid' => 'application/vnd.pvi.ptid1',
+ 'pub' => 'application/x-mspublisher',
+ 'pvb' => 'application/vnd.3gpp.pic-bw-var',
+ 'pwn' => 'application/vnd.3m.post-it-notes',
+ 'pya' => 'audio/vnd.ms-playready.media.pya',
+ 'pyv' => 'video/vnd.ms-playready.media.pyv',
+ 'qam' => 'application/vnd.epson.quickanime',
+ 'qbo' => 'application/vnd.intu.qbo',
+ 'qfx' => 'application/vnd.intu.qfx',
+ 'qps' => 'application/vnd.publishare-delta-tree',
+ 'qt' => 'video/quicktime',
+ 'qwd' => 'application/vnd.quark.quarkxpress',
+ 'qwt' => 'application/vnd.quark.quarkxpress',
+ 'qxb' => 'application/vnd.quark.quarkxpress',
+ 'qxd' => 'application/vnd.quark.quarkxpress',
+ 'qxl' => 'application/vnd.quark.quarkxpress',
+ 'qxt' => 'application/vnd.quark.quarkxpress',
+ 'ra' => 'audio/x-pn-realaudio',
+ 'ram' => 'audio/x-pn-realaudio',
+ 'rar' => 'application/x-rar-compressed',
+ 'ras' => 'image/x-cmu-raster',
+ 'rcprofile' => 'application/vnd.ipunplugged.rcprofile',
+ 'rdf' => 'application/rdf+xml',
+ 'rdz' => 'application/vnd.data-vision.rdz',
+ 'rep' => 'application/vnd.businessobjects',
+ 'res' => 'application/x-dtbresource+xml',
+ 'rgb' => 'image/x-rgb',
+ 'rif' => 'application/reginfo+xml',
+ 'rip' => 'audio/vnd.rip',
+ 'ris' => 'application/x-research-info-systems',
+ 'rl' => 'application/resource-lists+xml',
+ 'rlc' => 'image/vnd.fujixerox.edmics-rlc',
+ 'rld' => 'application/resource-lists-diff+xml',
+ 'rm' => 'application/vnd.rn-realmedia',
+ 'rmi' => 'audio/midi',
+ 'rmp' => 'audio/x-pn-realaudio-plugin',
+ 'rms' => 'application/vnd.jcp.javame.midlet-rms',
+ 'rmvb' => 'application/vnd.rn-realmedia-vbr',
+ 'rnc' => 'application/relax-ng-compact-syntax',
+ 'roa' => 'application/rpki-roa',
+ 'roff' => 'text/troff',
+ 'rp9' => 'application/vnd.cloanto.rp9',
+ 'rpss' => 'application/vnd.nokia.radio-presets',
+ 'rpst' => 'application/vnd.nokia.radio-preset',
+ 'rq' => 'application/sparql-query',
+ 'rs' => 'application/rls-services+xml',
+ 'rsd' => 'application/rsd+xml',
+ 'rss' => 'application/rss+xml',
+ 'rtf' => 'application/rtf',
+ 'rtx' => 'text/richtext',
+ 's' => 'text/x-asm',
+ 's3m' => 'audio/s3m',
+ 'saf' => 'application/vnd.yamaha.smaf-audio',
+ 'sbml' => 'application/sbml+xml',
+ 'sc' => 'application/vnd.ibm.secure-container',
+ 'scd' => 'application/x-msschedule',
+ 'scm' => 'application/vnd.lotus-screencam',
+ 'scq' => 'application/scvp-cv-request',
+ 'scs' => 'application/scvp-cv-response',
+ 'scurl' => 'text/vnd.curl.scurl',
+ 'sda' => 'application/vnd.stardivision.draw',
+ 'sdc' => 'application/vnd.stardivision.calc',
+ 'sdd' => 'application/vnd.stardivision.impress',
+ 'sdkd' => 'application/vnd.solent.sdkm+xml',
+ 'sdkm' => 'application/vnd.solent.sdkm+xml',
+ 'sdp' => 'application/sdp',
+ 'sdw' => 'application/vnd.stardivision.writer',
+ 'see' => 'application/vnd.seemail',
+ 'seed' => 'application/vnd.fdsn.seed',
+ 'sema' => 'application/vnd.sema',
+ 'semd' => 'application/vnd.semd',
+ 'semf' => 'application/vnd.semf',
+ 'ser' => 'application/java-serialized-object',
+ 'setpay' => 'application/set-payment-initiation',
+ 'setreg' => 'application/set-registration-initiation',
+ 'sfd-hdstx' => 'application/vnd.hydrostatix.sof-data',
+ 'sfs' => 'application/vnd.spotfire.sfs',
+ 'sfv' => 'text/x-sfv',
+ 'sgi' => 'image/sgi',
+ 'sgl' => 'application/vnd.stardivision.writer-global',
+ 'sgm' => 'text/sgml',
+ 'sgml' => 'text/sgml',
+ 'sh' => 'application/x-sh',
+ 'shar' => 'application/x-shar',
+ 'shf' => 'application/shf+xml',
+ 'sid' => 'image/x-mrsid-image',
+ 'sig' => 'application/pgp-signature',
+ 'sil' => 'audio/silk',
+ 'silo' => 'model/mesh',
+ 'sis' => 'application/vnd.symbian.install',
+ 'sisx' => 'application/vnd.symbian.install',
+ 'sit' => 'application/x-stuffit',
+ 'sitx' => 'application/x-stuffitx',
+ 'skd' => 'application/vnd.koan',
+ 'skm' => 'application/vnd.koan',
+ 'skp' => 'application/vnd.koan',
+ 'skt' => 'application/vnd.koan',
+ 'sldm' => 'application/vnd.ms-powerpoint.slide.macroenabled.12',
+ 'sldx' => 'application/vnd.openxmlformats-officedocument.presentationml.slide',
+ 'slt' => 'application/vnd.epson.salt',
+ 'sm' => 'application/vnd.stepmania.stepchart',
+ 'smf' => 'application/vnd.stardivision.math',
+ 'smi' => 'application/smil+xml',
+ 'smil' => 'application/smil+xml',
+ 'smv' => 'video/x-smv',
+ 'smzip' => 'application/vnd.stepmania.package',
+ 'snd' => 'audio/basic',
+ 'snf' => 'application/x-font-snf',
+ 'so' => 'application/octet-stream',
+ 'spc' => 'application/x-pkcs7-certificates',
+ 'spf' => 'application/vnd.yamaha.smaf-phrase',
+ 'spl' => 'application/x-futuresplash',
+ 'spot' => 'text/vnd.in3d.spot',
+ 'spp' => 'application/scvp-vp-response',
+ 'spq' => 'application/scvp-vp-request',
+ 'spx' => 'audio/ogg',
+ 'sql' => 'application/x-sql',
+ 'src' => 'application/x-wais-source',
+ 'srt' => 'application/x-subrip',
+ 'sru' => 'application/sru+xml',
+ 'srx' => 'application/sparql-results+xml',
+ 'ssdl' => 'application/ssdl+xml',
+ 'sse' => 'application/vnd.kodak-descriptor',
+ 'ssf' => 'application/vnd.epson.ssf',
+ 'ssml' => 'application/ssml+xml',
+ 'st' => 'application/vnd.sailingtracker.track',
+ 'stc' => 'application/vnd.sun.xml.calc.template',
+ 'std' => 'application/vnd.sun.xml.draw.template',
+ 'stf' => 'application/vnd.wt.stf',
+ 'sti' => 'application/vnd.sun.xml.impress.template',
+ 'stk' => 'application/hyperstudio',
+ 'stl' => 'application/vnd.ms-pki.stl',
+ 'str' => 'application/vnd.pg.format',
+ 'stw' => 'application/vnd.sun.xml.writer.template',
+ 'sub' => 'text/vnd.dvb.subtitle',
+ 'sus' => 'application/vnd.sus-calendar',
+ 'susp' => 'application/vnd.sus-calendar',
+ 'sv4cpio' => 'application/x-sv4cpio',
+ 'sv4crc' => 'application/x-sv4crc',
+ 'svc' => 'application/vnd.dvb.service',
+ 'svd' => 'application/vnd.svd',
+ 'svg' => 'image/svg+xml',
+ 'svgz' => 'image/svg+xml',
+ 'swa' => 'application/x-director',
+ 'swf' => 'application/x-shockwave-flash',
+ 'swi' => 'application/vnd.aristanetworks.swi',
+ 'sxc' => 'application/vnd.sun.xml.calc',
+ 'sxd' => 'application/vnd.sun.xml.draw',
+ 'sxg' => 'application/vnd.sun.xml.writer.global',
+ 'sxi' => 'application/vnd.sun.xml.impress',
+ 'sxm' => 'application/vnd.sun.xml.math',
+ 'sxw' => 'application/vnd.sun.xml.writer',
+ 't' => 'text/troff',
+ 't3' => 'application/x-t3vm-image',
+ 'taglet' => 'application/vnd.mynfc',
+ 'tao' => 'application/vnd.tao.intent-module-archive',
+ 'tar' => 'application/x-tar',
+ 'tcap' => 'application/vnd.3gpp2.tcap',
+ 'tcl' => 'application/x-tcl',
+ 'teacher' => 'application/vnd.smart.teacher',
+ 'tei' => 'application/tei+xml',
+ 'teicorpus' => 'application/tei+xml',
+ 'tex' => 'application/x-tex',
+ 'texi' => 'application/x-texinfo',
+ 'texinfo' => 'application/x-texinfo',
+ 'text' => 'text/plain',
+ 'tfi' => 'application/thraud+xml',
+ 'tfm' => 'application/x-tex-tfm',
+ 'tga' => 'image/x-tga',
+ 'thmx' => 'application/vnd.ms-officetheme',
+ 'tif' => 'image/tiff',
+ 'tiff' => 'image/tiff',
+ 'tmo' => 'application/vnd.tmobile-livetv',
+ 'torrent' => 'application/x-bittorrent',
+ 'tpl' => 'application/vnd.groove-tool-template',
+ 'tpt' => 'application/vnd.trid.tpt',
+ 'tr' => 'text/troff',
+ 'tra' => 'application/vnd.trueapp',
+ 'trm' => 'application/x-msterminal',
+ 'tsd' => 'application/timestamped-data',
+ 'tsv' => 'text/tab-separated-values',
+ 'ttc' => 'application/x-font-ttf',
+ 'ttf' => 'application/x-font-ttf',
+ 'ttl' => 'text/turtle',
+ 'twd' => 'application/vnd.simtech-mindmapper',
+ 'twds' => 'application/vnd.simtech-mindmapper',
+ 'txd' => 'application/vnd.genomatix.tuxedo',
+ 'txf' => 'application/vnd.mobius.txf',
+ 'txt' => 'text/plain',
+ 'u32' => 'application/x-authorware-bin',
+ 'udeb' => 'application/x-debian-package',
+ 'ufd' => 'application/vnd.ufdl',
+ 'ufdl' => 'application/vnd.ufdl',
+ 'ulx' => 'application/x-glulx',
+ 'umj' => 'application/vnd.umajin',
+ 'unityweb' => 'application/vnd.unity',
+ 'uoml' => 'application/vnd.uoml+xml',
+ 'uri' => 'text/uri-list',
+ 'uris' => 'text/uri-list',
+ 'urls' => 'text/uri-list',
+ 'ustar' => 'application/x-ustar',
+ 'utz' => 'application/vnd.uiq.theme',
+ 'uu' => 'text/x-uuencode',
+ 'uva' => 'audio/vnd.dece.audio',
+ 'uvd' => 'application/vnd.dece.data',
+ 'uvf' => 'application/vnd.dece.data',
+ 'uvg' => 'image/vnd.dece.graphic',
+ 'uvh' => 'video/vnd.dece.hd',
+ 'uvi' => 'image/vnd.dece.graphic',
+ 'uvm' => 'video/vnd.dece.mobile',
+ 'uvp' => 'video/vnd.dece.pd',
+ 'uvs' => 'video/vnd.dece.sd',
+ 'uvt' => 'application/vnd.dece.ttml+xml',
+ 'uvu' => 'video/vnd.uvvu.mp4',
+ 'uvv' => 'video/vnd.dece.video',
+ 'uvva' => 'audio/vnd.dece.audio',
+ 'uvvd' => 'application/vnd.dece.data',
+ 'uvvf' => 'application/vnd.dece.data',
+ 'uvvg' => 'image/vnd.dece.graphic',
+ 'uvvh' => 'video/vnd.dece.hd',
+ 'uvvi' => 'image/vnd.dece.graphic',
+ 'uvvm' => 'video/vnd.dece.mobile',
+ 'uvvp' => 'video/vnd.dece.pd',
+ 'uvvs' => 'video/vnd.dece.sd',
+ 'uvvt' => 'application/vnd.dece.ttml+xml',
+ 'uvvu' => 'video/vnd.uvvu.mp4',
+ 'uvvv' => 'video/vnd.dece.video',
+ 'uvvx' => 'application/vnd.dece.unspecified',
+ 'uvvz' => 'application/vnd.dece.zip',
+ 'uvx' => 'application/vnd.dece.unspecified',
+ 'uvz' => 'application/vnd.dece.zip',
+ 'vcard' => 'text/vcard',
+ 'vcd' => 'application/x-cdlink',
+ 'vcf' => 'text/x-vcard',
+ 'vcg' => 'application/vnd.groove-vcard',
+ 'vcs' => 'text/x-vcalendar',
+ 'vcx' => 'application/vnd.vcx',
+ 'vis' => 'application/vnd.visionary',
+ 'viv' => 'video/vnd.vivo',
+ 'vob' => 'video/x-ms-vob',
+ 'vor' => 'application/vnd.stardivision.writer',
+ 'vox' => 'application/x-authorware-bin',
+ 'vrml' => 'model/vrml',
+ 'vsd' => 'application/vnd.visio',
+ 'vsf' => 'application/vnd.vsf',
+ 'vss' => 'application/vnd.visio',
+ 'vst' => 'application/vnd.visio',
+ 'vsw' => 'application/vnd.visio',
+ 'vtu' => 'model/vnd.vtu',
+ 'vxml' => 'application/voicexml+xml',
+ 'w3d' => 'application/x-director',
+ 'wad' => 'application/x-doom',
+ 'wav' => 'audio/x-wav',
+ 'wax' => 'audio/x-ms-wax',
+ 'wbmp' => 'image/vnd.wap.wbmp',
+ 'wbs' => 'application/vnd.criticaltools.wbs+xml',
+ 'wbxml' => 'application/vnd.wap.wbxml',
+ 'wcm' => 'application/vnd.ms-works',
+ 'wdb' => 'application/vnd.ms-works',
+ 'wdp' => 'image/vnd.ms-photo',
+ 'weba' => 'audio/webm',
+ 'webm' => 'video/webm',
+ 'webp' => 'image/webp',
+ 'wg' => 'application/vnd.pmi.widget',
+ 'wgt' => 'application/widget',
+ 'wks' => 'application/vnd.ms-works',
+ 'wm' => 'video/x-ms-wm',
+ 'wma' => 'audio/x-ms-wma',
+ 'wmd' => 'application/x-ms-wmd',
+ 'wmf' => 'application/x-msmetafile',
+ 'wml' => 'text/vnd.wap.wml',
+ 'wmlc' => 'application/vnd.wap.wmlc',
+ 'wmls' => 'text/vnd.wap.wmlscript',
+ 'wmlsc' => 'application/vnd.wap.wmlscriptc',
+ 'wmv' => 'video/x-ms-wmv',
+ 'wmx' => 'video/x-ms-wmx',
+ 'wmz' => 'application/x-msmetafile',
+ 'woff' => 'application/font-woff',
+ 'wpd' => 'application/vnd.wordperfect',
+ 'wpl' => 'application/vnd.ms-wpl',
+ 'wps' => 'application/vnd.ms-works',
+ 'wqd' => 'application/vnd.wqd',
+ 'wri' => 'application/x-mswrite',
+ 'wrl' => 'model/vrml',
+ 'wsdl' => 'application/wsdl+xml',
+ 'wspolicy' => 'application/wspolicy+xml',
+ 'wtb' => 'application/vnd.webturbo',
+ 'wvx' => 'video/x-ms-wvx',
+ 'x32' => 'application/x-authorware-bin',
+ 'x3d' => 'model/x3d+xml',
+ 'x3db' => 'model/x3d+binary',
+ 'x3dbz' => 'model/x3d+binary',
+ 'x3dv' => 'model/x3d+vrml',
+ 'x3dvz' => 'model/x3d+vrml',
+ 'x3dz' => 'model/x3d+xml',
+ 'xaml' => 'application/xaml+xml',
+ 'xap' => 'application/x-silverlight-app',
+ 'xar' => 'application/vnd.xara',
+ 'xbap' => 'application/x-ms-xbap',
+ 'xbd' => 'application/vnd.fujixerox.docuworks.binder',
+ 'xbm' => 'image/x-xbitmap',
+ 'xdf' => 'application/xcap-diff+xml',
+ 'xdm' => 'application/vnd.syncml.dm+xml',
+ 'xdp' => 'application/vnd.adobe.xdp+xml',
+ 'xdssc' => 'application/dssc+xml',
+ 'xdw' => 'application/vnd.fujixerox.docuworks',
+ 'xenc' => 'application/xenc+xml',
+ 'xer' => 'application/patch-ops-error+xml',
+ 'xfdf' => 'application/vnd.adobe.xfdf',
+ 'xfdl' => 'application/vnd.xfdl',
+ 'xht' => 'application/xhtml+xml',
+ 'xhtml' => 'application/xhtml+xml',
+ 'xhvml' => 'application/xv+xml',
+ 'xif' => 'image/vnd.xiff',
+ 'xla' => 'application/vnd.ms-excel',
+ 'xlam' => 'application/vnd.ms-excel.addin.macroenabled.12',
+ 'xlc' => 'application/vnd.ms-excel',
+ 'xlf' => 'application/x-xliff+xml',
+ 'xlm' => 'application/vnd.ms-excel',
+ 'xls' => 'application/vnd.ms-excel',
+ 'xlsb' => 'application/vnd.ms-excel.sheet.binary.macroenabled.12',
+ 'xlsm' => 'application/vnd.ms-excel.sheet.macroenabled.12',
+ 'xlsx' => 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
+ 'xlt' => 'application/vnd.ms-excel',
+ 'xltm' => 'application/vnd.ms-excel.template.macroenabled.12',
+ 'xltx' => 'application/vnd.openxmlformats-officedocument.spreadsheetml.template',
+ 'xlw' => 'application/vnd.ms-excel',
+ 'xm' => 'audio/xm',
+ 'xml' => 'application/xml',
+ 'xo' => 'application/vnd.olpc-sugar',
+ 'xop' => 'application/xop+xml',
+ 'xpi' => 'application/x-xpinstall',
+ 'xpl' => 'application/xproc+xml',
+ 'xpm' => 'image/x-xpixmap',
+ 'xpr' => 'application/vnd.is-xpr',
+ 'xps' => 'application/vnd.ms-xpsdocument',
+ 'xpw' => 'application/vnd.intercon.formnet',
+ 'xpx' => 'application/vnd.intercon.formnet',
+ 'xsl' => 'application/xml',
+ 'xslt' => 'application/xslt+xml',
+ 'xsm' => 'application/vnd.syncml+xml',
+ 'xspf' => 'application/xspf+xml',
+ 'xul' => 'application/vnd.mozilla.xul+xml',
+ 'xvm' => 'application/xv+xml',
+ 'xvml' => 'application/xv+xml',
+ 'xwd' => 'image/x-xwindowdump',
+ 'xyz' => 'chemical/x-xyz',
+ 'xz' => 'application/x-xz',
+ 'yang' => 'application/yang',
+ 'yin' => 'application/yin+xml',
+ 'z1' => 'application/x-zmachine',
+ 'z2' => 'application/x-zmachine',
+ 'z3' => 'application/x-zmachine',
+ 'z4' => 'application/x-zmachine',
+ 'z5' => 'application/x-zmachine',
+ 'z6' => 'application/x-zmachine',
+ 'z7' => 'application/x-zmachine',
+ 'z8' => 'application/x-zmachine',
+ 'zaz' => 'application/vnd.zzazz.deck+xml',
+ 'zip' => 'application/zip',
+ 'zir' => 'application/vnd.zul',
+ 'zirz' => 'application/vnd.zul',
+ 'zmm' => 'application/vnd.handheld-entertainment+xml',
+ '123' => 'application/vnd.lotus-1-2-3',
+);
diff --git a/vendor/swiftmailer/swiftmailer/lib/preferences.php b/vendor/swiftmailer/swiftmailer/lib/preferences.php
new file mode 100644
index 00000000..e5195014
--- /dev/null
+++ b/vendor/swiftmailer/swiftmailer/lib/preferences.php
@@ -0,0 +1,25 @@
+setCharset('utf-8');
+
+// Without these lines the default caching mechanism is "array" but this uses a lot of memory.
+// If possible, use a disk cache to enable attaching large attachments etc.
+// You can override the default temporary directory by setting the TMPDIR environment variable.
+if (@is_writable($tmpDir = sys_get_temp_dir())) {
+ $preferences->setTempDir($tmpDir)->setCacheType('disk');
+}
+
+// this should only be done when Swiftmailer won't use the native QP content encoder
+// see mime_deps.php
+if (version_compare(phpversion(), '5.4.7', '<')) {
+ $preferences->setQPDotEscape(false);
+}
diff --git a/vendor/swiftmailer/swiftmailer/lib/swift_init.php b/vendor/swiftmailer/swiftmailer/lib/swift_init.php
new file mode 100644
index 00000000..5c4bae4f
--- /dev/null
+++ b/vendor/swiftmailer/swiftmailer/lib/swift_init.php
@@ -0,0 +1,28 @@
+ 'application/x-php',
+ 'php3' => 'application/x-php',
+ 'php4' => 'application/x-php',
+ 'php5' => 'application/x-php',
+ 'zip' => 'application/zip',
+ 'gif' => 'image/gif',
+ 'png' => 'image/png',
+ 'css' => 'text/css',
+ 'js' => 'text/javascript',
+ 'txt' => 'text/plain',
+ 'xml' => 'text/xml',
+ 'aif' => 'audio/x-aiff',
+ 'aiff' => 'audio/x-aiff',
+ 'avi' => 'video/avi',
+ 'bmp' => 'image/bmp',
+ 'bz2' => 'application/x-bz2',
+ 'csv' => 'text/csv',
+ 'dmg' => 'application/x-apple-diskimage',
+ 'doc' => 'application/msword',
+ 'docx' => 'application/vnd.openxmlformats-officedocument.wordprocessingml.document',
+ 'eml' => 'message/rfc822',
+ 'aps' => 'application/postscript',
+ 'exe' => 'application/x-ms-dos-executable',
+ 'flv' => 'video/x-flv',
+ 'gz' => 'application/x-gzip',
+ 'hqx' => 'application/stuffit',
+ 'htm' => 'text/html',
+ 'html' => 'text/html',
+ 'jar' => 'application/x-java-archive',
+ 'jpeg' => 'image/jpeg',
+ 'jpg' => 'image/jpeg',
+ 'm3u' => 'audio/x-mpegurl',
+ 'm4a' => 'audio/mp4',
+ 'mdb' => 'application/x-msaccess',
+ 'mid' => 'audio/midi',
+ 'midi' => 'audio/midi',
+ 'mov' => 'video/quicktime',
+ 'mp3' => 'audio/mpeg',
+ 'mp4' => 'video/mp4',
+ 'mpeg' => 'video/mpeg',
+ 'mpg' => 'video/mpeg',
+ 'odg' => 'vnd.oasis.opendocument.graphics',
+ 'odp' => 'vnd.oasis.opendocument.presentation',
+ 'odt' => 'vnd.oasis.opendocument.text',
+ 'ods' => 'vnd.oasis.opendocument.spreadsheet',
+ 'ogg' => 'audio/ogg',
+ 'pdf' => 'application/pdf',
+ 'ppt' => 'application/vnd.ms-powerpoint',
+ 'pptx' => 'application/vnd.openxmlformats-officedocument.presentationml.presentation',
+ 'ps' => 'application/postscript',
+ 'rar' => 'application/x-rar-compressed',
+ 'rtf' => 'application/rtf',
+ 'tar' => 'application/x-tar',
+ 'sit' => 'application/x-stuffit',
+ 'svg' => 'image/svg+xml',
+ 'tif' => 'image/tiff',
+ 'tiff' => 'image/tiff',
+ 'ttf' => 'application/x-font-truetype',
+ 'vcf' => 'text/x-vcard',
+ 'wav' => 'audio/wav',
+ 'wma' => 'audio/x-ms-wma',
+ 'wmv' => 'audio/x-ms-wmv',
+ 'xls' => 'application/excel',
+ 'xlsx' => 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
+ 'xml' => 'application/xml',
+ );
+
+ // wrap array for generating file
+ foreach ($valid_mime_types_preset as $extension => $mime_type) {
+ // generate array for mimetype to extension resolver (only first match)
+ $valid_mime_types[$extension] = "'{$extension}' => '{$mime_type}'";
+ }
+
+ // collect extensions
+ $valid_extensions = array();
+
+ // all extensions from second match
+ foreach ($matches[2] as $i => $extensions) {
+ // explode multiple extensions from string
+ $extensions = explode(" ", strtolower($extensions));
+
+ // force array for foreach
+ if (!is_array($extensions)) {
+ $extensions = array($extensions);
+ }
+
+ foreach ($extensions as $extension) {
+ // get mime type
+ $mime_type = $matches[1][$i];
+
+ // check if string length lower than 10
+ if (strlen($extension) < 10) {
+ // add extension
+ $valid_extensions[] = $extension;
+
+ if (!isset($valid_mime_types[$mime_type])) {
+ // generate array for mimetype to extension resolver (only first match)
+ $valid_mime_types[$extension] = "'{$extension}' => '{$mime_type}'";
+ }
+ }
+ }
+ }
+ }
+
+ $xml = simplexml_load_string($mime_xml);
+
+ foreach ($xml as $node) {
+ // check if there is no pattern
+ if (!isset($node->glob["pattern"])) {
+ continue;
+ }
+
+ // get all matching extensions from match
+ foreach ((array) $node->glob["pattern"] as $extension) {
+ // skip none glob extensions
+ if (strpos($extension, '.') === FALSE) {
+ continue;
+ }
+
+ // remove get only last part
+ $extension = explode('.', strtolower($extension));
+ $extension = end($extension);
+
+ // maximum length in database column
+ if (strlen($extension) <= 9) {
+ $valid_extensions[] = $extension;
+ }
+ }
+
+ if (isset($node->glob["pattern"][0])) {
+ // mime type
+ $mime_type = strtolower((string) $node["type"]);
+
+ // get first extension
+ $extension = strtolower(trim($node->glob["ddpattern"][0], '*.'));
+
+ // skip none glob extensions and check if string length between 1 and 10
+ if (strpos($extension, '.') !== FALSE || strlen($extension) < 1 || strlen($extension) > 9) {
+ continue;
+ }
+
+ // check if string length lower than 10
+ if (!isset($valid_mime_types[$mime_type])) {
+ // generate array for mimetype to extension resolver (only first match)
+ $valid_mime_types[$extension] = "'{$extension}' => '{$mime_type}'";
+ }
+ }
+ }
+
+ // full list of valid extensions only
+ $valid_mime_types = array_unique($valid_mime_types);
+ ksort($valid_mime_types);
+
+ // combine mime types and extensions array
+ $output = "$preamble\$swift_mime_types = array(\n ".implode($valid_mime_types, ",\n ")."\n);";
+
+ // write mime_types.php config file
+ @file_put_contents('./mime_types.php', $output);
+}
+
+generateUpToDateMimeArray();
diff --git a/vendor/swiftmailer/swiftmailer/notes/APPS b/vendor/swiftmailer/swiftmailer/notes/APPS
new file mode 100644
index 00000000..b06b4cc0
--- /dev/null
+++ b/vendor/swiftmailer/swiftmailer/notes/APPS
@@ -0,0 +1,15 @@
+Applications I need to test with
+---------------------------------
+
+Standalone (can read .eml files):
+---------------------------------
+Microsoft Entourage (can assume same as outlook)
+Mozilla Thunderbird
+Apple Mail
+
+Web-based:
+----------
+Hotmail
+Gmail
+Yahoo!
+Mail2Web
diff --git a/vendor/swiftmailer/swiftmailer/notes/CHARSETS b/vendor/swiftmailer/swiftmailer/notes/CHARSETS
new file mode 100644
index 00000000..6a97a89c
--- /dev/null
+++ b/vendor/swiftmailer/swiftmailer/notes/CHARSETS
@@ -0,0 +1,46 @@
+Following is a list of character sets along with their widths:
+--------------------------------------------------------------
+
+1 Octet 8bit:
+-------------
+Windows 125* (CP125*)
+CP*
+ANSI
+ISO-8859-* (IEC-8859-*)
+Macintosh (Mac OS Roman)
+KOI8-U (potentially KOI*8-*)
+KOI8-R
+MIK
+Cork (T1)
+ISCII
+VISCII
+
+
+1 Octet 7bit:
+-------------
+US-ASCII
+K0I7
+
+2 octets 16 bit:
+----------------
+UCS-2
+UTF-16* (UTF-16BE etc)
+
+4-octets 32 bit:
+----------------
+UCS-4
+UTF-32
+
+Variable-width:
+----------------------------
+Big5 - http://en.wikipedia.org/wiki/Big5 (1-2 bytes: 00-7f=1, 81-fe=2)
+HKSCS - http://en.wikipedia.org/wiki/HKSCS (a big5 variant, but some variants use 10646)
+ISO-10646 (IEC-10646) - http://en.wikipedia.org/wiki/ISO_10646 (unicode)
+UTF-8 (1-5 bytes)
+ISO-2022 (IEC-2022) - http://en.wikipedia.org/wiki/ISO_2022
+Shift-JIS - http://en.wikipedia.org/wiki/Shift-JIS
+
+A good resource:
+----------------
+http://en.wikipedia.org/wiki/Character_encoding#Simple_character_sets
+
diff --git a/vendor/swiftmailer/swiftmailer/notes/message.xml b/vendor/swiftmailer/swiftmailer/notes/message.xml
new file mode 100644
index 00000000..1183ecaa
--- /dev/null
+++ b/vendor/swiftmailer/swiftmailer/notes/message.xml
@@ -0,0 +1,22 @@
+
+
+ Some test message
+ chris@w3style.co.uk
+ mark@swiftmailer.org
+ chris.corbyn@sitepoint.com
+ text/plain
+
+ Here's a recipe for beef stifado
+
+
+ text/html
+
+ This is the other part
+
+
+
+ application/pdf
+ stifado.pdf
+ /path/to/stifado.pdf
+
+
diff --git a/vendor/swiftmailer/swiftmailer/notes/rfc/rfc0821.txt b/vendor/swiftmailer/swiftmailer/notes/rfc/rfc0821.txt
new file mode 100644
index 00000000..d877b72c
--- /dev/null
+++ b/vendor/swiftmailer/swiftmailer/notes/rfc/rfc0821.txt
@@ -0,0 +1,4050 @@
+
+
+
+ RFC 821
+
+
+
+
+
+ SIMPLE MAIL TRANSFER PROTOCOL
+
+
+
+ Jonathan B. Postel
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ August 1982
+
+
+
+ Information Sciences Institute
+ University of Southern California
+ 4676 Admiralty Way
+ Marina del Rey, California 90291
+
+ (213) 822-1511
+
+
+
+
+RFC 821 August 1982
+ Simple Mail Transfer Protocol
+
+
+
+ TABLE OF CONTENTS
+
+ 1. INTRODUCTION .................................................. 1
+
+ 2. THE SMTP MODEL ................................................ 2
+
+ 3. THE SMTP PROCEDURE ............................................ 4
+
+ 3.1. Mail ..................................................... 4
+ 3.2. Forwarding ............................................... 7
+ 3.3. Verifying and Expanding .................................. 8
+ 3.4. Sending and Mailing ..................................... 11
+ 3.5. Opening and Closing ..................................... 13
+ 3.6. Relaying ................................................ 14
+ 3.7. Domains ................................................. 17
+ 3.8. Changing Roles .......................................... 18
+
+ 4. THE SMTP SPECIFICATIONS ...................................... 19
+
+ 4.1. SMTP Commands ........................................... 19
+ 4.1.1. Command Semantics ..................................... 19
+ 4.1.2. Command Syntax ........................................ 27
+ 4.2. SMTP Replies ............................................ 34
+ 4.2.1. Reply Codes by Function Group ......................... 35
+ 4.2.2. Reply Codes in Numeric Order .......................... 36
+ 4.3. Sequencing of Commands and Replies ...................... 37
+ 4.4. State Diagrams .......................................... 39
+ 4.5. Details ................................................. 41
+ 4.5.1. Minimum Implementation ................................ 41
+ 4.5.2. Transparency .......................................... 41
+ 4.5.3. Sizes ................................................. 42
+
+ APPENDIX A: TCP ................................................. 44
+ APPENDIX B: NCP ................................................. 45
+ APPENDIX C: NITS ................................................ 46
+ APPENDIX D: X.25 ................................................ 47
+ APPENDIX E: Theory of Reply Codes ............................... 48
+ APPENDIX F: Scenarios ........................................... 51
+
+ GLOSSARY ......................................................... 64
+
+ REFERENCES ....................................................... 67
+
+
+
+
+Network Working Group J. Postel
+Request for Comments: DRAFT ISI
+Replaces: RFC 788, 780, 772 August 1982
+
+ SIMPLE MAIL TRANSFER PROTOCOL
+
+
+1. INTRODUCTION
+
+ The objective of Simple Mail Transfer Protocol (SMTP) is to transfer
+ mail reliably and efficiently.
+
+ SMTP is independent of the particular transmission subsystem and
+ requires only a reliable ordered data stream channel. Appendices A,
+ B, C, and D describe the use of SMTP with various transport services.
+ A Glossary provides the definitions of terms as used in this
+ document.
+
+ An important feature of SMTP is its capability to relay mail across
+ transport service environments. A transport service provides an
+ interprocess communication environment (IPCE). An IPCE may cover one
+ network, several networks, or a subset of a network. It is important
+ to realize that transport systems (or IPCEs) are not one-to-one with
+ networks. A process can communicate directly with another process
+ through any mutually known IPCE. Mail is an application or use of
+ interprocess communication. Mail can be communicated between
+ processes in different IPCEs by relaying through a process connected
+ to two (or more) IPCEs. More specifically, mail can be relayed
+ between hosts on different transport systems by a host on both
+ transport systems.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Postel [Page 1]
+
+
+
+August 1982 RFC 821
+Simple Mail Transfer Protocol
+
+
+
+2. THE SMTP MODEL
+
+ The SMTP design is based on the following model of communication: as
+ the result of a user mail request, the sender-SMTP establishes a
+ two-way transmission channel to a receiver-SMTP. The receiver-SMTP
+ may be either the ultimate destination or an intermediate. SMTP
+ commands are generated by the sender-SMTP and sent to the
+ receiver-SMTP. SMTP replies are sent from the receiver-SMTP to the
+ sender-SMTP in response to the commands.
+
+ Once the transmission channel is established, the SMTP-sender sends a
+ MAIL command indicating the sender of the mail. If the SMTP-receiver
+ can accept mail it responds with an OK reply. The SMTP-sender then
+ sends a RCPT command identifying a recipient of the mail. If the
+ SMTP-receiver can accept mail for that recipient it responds with an
+ OK reply; if not, it responds with a reply rejecting that recipient
+ (but not the whole mail transaction). The SMTP-sender and
+ SMTP-receiver may negotiate several recipients. When the recipients
+ have been negotiated the SMTP-sender sends the mail data, terminating
+ with a special sequence. If the SMTP-receiver successfully processes
+ the mail data it responds with an OK reply. The dialog is purposely
+ lock-step, one-at-a-time.
+
+ -------------------------------------------------------------
+
+
+ +----------+ +----------+
+ +------+ | | | |
+ | User |<-->| | SMTP | |
+ +------+ | Sender- |Commands/Replies| Receiver-|
+ +------+ | SMTP |<-------------->| SMTP | +------+
+ | File |<-->| | and Mail | |<-->| File |
+ |System| | | | | |System|
+ +------+ +----------+ +----------+ +------+
+
+
+ Sender-SMTP Receiver-SMTP
+
+ Model for SMTP Use
+
+ Figure 1
+
+ -------------------------------------------------------------
+
+ The SMTP provides mechanisms for the transmission of mail; directly
+ from the sending user's host to the receiving user's host when the
+
+
+
+[Page 2] Postel
+
+
+
+RFC 821 August 1982
+ Simple Mail Transfer Protocol
+
+
+
+ two host are connected to the same transport service, or via one or
+ more relay SMTP-servers when the source and destination hosts are not
+ connected to the same transport service.
+
+ To be able to provide the relay capability the SMTP-server must be
+ supplied with the name of the ultimate destination host as well as
+ the destination mailbox name.
+
+ The argument to the MAIL command is a reverse-path, which specifies
+ who the mail is from. The argument to the RCPT command is a
+ forward-path, which specifies who the mail is to. The forward-path
+ is a source route, while the reverse-path is a return route (which
+ may be used to return a message to the sender when an error occurs
+ with a relayed message).
+
+ When the same message is sent to multiple recipients the SMTP
+ encourages the transmission of only one copy of the data for all the
+ recipients at the same destination host.
+
+ The mail commands and replies have a rigid syntax. Replies also have
+ a numeric code. In the following, examples appear which use actual
+ commands and replies. The complete lists of commands and replies
+ appears in Section 4 on specifications.
+
+ Commands and replies are not case sensitive. That is, a command or
+ reply word may be upper case, lower case, or any mixture of upper and
+ lower case. Note that this is not true of mailbox user names. For
+ some hosts the user name is case sensitive, and SMTP implementations
+ must take case to preserve the case of user names as they appear in
+ mailbox arguments. Host names are not case sensitive.
+
+ Commands and replies are composed of characters from the ASCII
+ character set [1]. When the transport service provides an 8-bit byte
+ (octet) transmission channel, each 7-bit character is transmitted
+ right justified in an octet with the high order bit cleared to zero.
+
+ When specifying the general form of a command or reply, an argument
+ (or special symbol) will be denoted by a meta-linguistic variable (or
+ constant), for example, "" or "". Here the
+ angle brackets indicate these are meta-linguistic variables.
+ However, some arguments use the angle brackets literally. For
+ example, an actual reverse-path is enclosed in angle brackets, i.e.,
+ "" is an instance of (the
+ angle brackets are actually transmitted in the command or reply).
+
+
+
+
+
+Postel [Page 3]
+
+
+
+August 1982 RFC 821
+Simple Mail Transfer Protocol
+
+
+
+3. THE SMTP PROCEDURES
+
+ This section presents the procedures used in SMTP in several parts.
+ First comes the basic mail procedure defined as a mail transaction.
+ Following this are descriptions of forwarding mail, verifying mailbox
+ names and expanding mailing lists, sending to terminals instead of or
+ in combination with mailboxes, and the opening and closing exchanges.
+ At the end of this section are comments on relaying, a note on mail
+ domains, and a discussion of changing roles. Throughout this section
+ are examples of partial command and reply sequences, several complete
+ scenarios are presented in Appendix F.
+
+ 3.1. MAIL
+
+ There are three steps to SMTP mail transactions. The transaction
+ is started with a MAIL command which gives the sender
+ identification. A series of one or more RCPT commands follows
+ giving the receiver information. Then a DATA command gives the
+ mail data. And finally, the end of mail data indicator confirms
+ the transaction.
+
+ The first step in the procedure is the MAIL command. The
+ contains the source mailbox.
+
+ MAIL FROM:
+
+ This command tells the SMTP-receiver that a new mail
+ transaction is starting and to reset all its state tables and
+ buffers, including any recipients or mail data. It gives the
+ reverse-path which can be used to report errors. If accepted,
+ the receiver-SMTP returns a 250 OK reply.
+
+ The can contain more than just a mailbox. The
+ is a reverse source routing list of hosts and
+ source mailbox. The first host in the should be
+ the host sending this command.
+
+ The second step in the procedure is the RCPT command.
+
+ RCPT TO:
+
+ This command gives a forward-path identifying one recipient.
+ If accepted, the receiver-SMTP returns a 250 OK reply, and
+ stores the forward-path. If the recipient is unknown the
+ receiver-SMTP returns a 550 Failure reply. This second step of
+ the procedure can be repeated any number of times.
+
+
+
+[Page 4] Postel
+
+
+
+RFC 821 August 1982
+ Simple Mail Transfer Protocol
+
+
+
+ The can contain more than just a mailbox. The
+ is a source routing list of hosts and the
+ destination mailbox. The first host in the
+ should be the host receiving this command.
+
+ The third step in the procedure is the DATA command.
+
+ DATA
+
+ If accepted, the receiver-SMTP returns a 354 Intermediate reply
+ and considers all succeeding lines to be the message text.
+ When the end of text is received and stored the SMTP-receiver
+ sends a 250 OK reply.
+
+ Since the mail data is sent on the transmission channel the end
+ of the mail data must be indicated so that the command and
+ reply dialog can be resumed. SMTP indicates the end of the
+ mail data by sending a line containing only a period. A
+ transparency procedure is used to prevent this from interfering
+ with the user's text (see Section 4.5.2).
+
+ Please note that the mail data includes the memo header
+ items such as Date, Subject, To, Cc, From [2].
+
+ The end of mail data indicator also confirms the mail
+ transaction and tells the receiver-SMTP to now process the
+ stored recipients and mail data. If accepted, the
+ receiver-SMTP returns a 250 OK reply. The DATA command should
+ fail only if the mail transaction was incomplete (for example,
+ no recipients), or if resources are not available.
+
+ The above procedure is an example of a mail transaction. These
+ commands must be used only in the order discussed above.
+ Example 1 (below) illustrates the use of these commands in a mail
+ transaction.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Postel [Page 5]
+
+
+
+August 1982 RFC 821
+Simple Mail Transfer Protocol
+
+
+
+ -------------------------------------------------------------
+
+ Example of the SMTP Procedure
+
+ This SMTP example shows mail sent by Smith at host Alpha.ARPA,
+ to Jones, Green, and Brown at host Beta.ARPA. Here we assume
+ that host Alpha contacts host Beta directly.
+
+ S: MAIL FROM:
+ R: 250 OK
+
+ S: RCPT TO:
+ R: 250 OK
+
+ S: RCPT TO:
+ R: 550 No such user here
+
+ S: RCPT TO:
+ R: 250 OK
+
+ S: DATA
+ R: 354 Start mail input; end with .
+ S: Blah blah blah...
+ S: ...etc. etc. etc.
+ S: .
+ R: 250 OK
+
+ The mail has now been accepted for Jones and Brown. Green did
+ not have a mailbox at host Beta.
+
+ Example 1
+
+ -------------------------------------------------------------
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+[Page 6] Postel
+
+
+
+RFC 821 August 1982
+ Simple Mail Transfer Protocol
+
+
+
+ 3.2. FORWARDING
+
+ There are some cases where the destination information in the
+ is incorrect, but the receiver-SMTP knows the
+ correct destination. In such cases, one of the following replies
+ should be used to allow the sender to contact the correct
+ destination.
+
+ 251 User not local; will forward to
+
+ This reply indicates that the receiver-SMTP knows the user's
+ mailbox is on another host and indicates the correct
+ forward-path to use in the future. Note that either the
+ host or user or both may be different. The receiver takes
+ responsibility for delivering the message.
+
+ 551 User not local; please try
+
+ This reply indicates that the receiver-SMTP knows the user's
+ mailbox is on another host and indicates the correct
+ forward-path to use. Note that either the host or user or
+ both may be different. The receiver refuses to accept mail
+ for this user, and the sender must either redirect the mail
+ according to the information provided or return an error
+ response to the originating user.
+
+ Example 2 illustrates the use of these responses.
+
+ -------------------------------------------------------------
+
+ Example of Forwarding
+
+ Either
+
+ S: RCPT TO:
+ R: 251 User not local; will forward to
+
+ Or
+
+ S: RCPT TO:
+ R: 551 User not local; please try
+
+ Example 2
+
+ -------------------------------------------------------------
+
+
+
+
+Postel [Page 7]
+
+
+
+August 1982 RFC 821
+Simple Mail Transfer Protocol
+
+
+
+ 3.3. VERIFYING AND EXPANDING
+
+ SMTP provides as additional features, commands to verify a user
+ name or expand a mailing list. This is done with the VRFY and
+ EXPN commands, which have character string arguments. For the
+ VRFY command, the string is a user name, and the response may
+ include the full name of the user and must include the mailbox of
+ the user. For the EXPN command, the string identifies a mailing
+ list, and the multiline response may include the full name of the
+ users and must give the mailboxes on the mailing list.
+
+ "User name" is a fuzzy term and used purposely. If a host
+ implements the VRFY or EXPN commands then at least local mailboxes
+ must be recognized as "user names". If a host chooses to
+ recognize other strings as "user names" that is allowed.
+
+ In some hosts the distinction between a mailing list and an alias
+ for a single mailbox is a bit fuzzy, since a common data structure
+ may hold both types of entries, and it is possible to have mailing
+ lists of one mailbox. If a request is made to verify a mailing
+ list a positive response can be given if on receipt of a message
+ so addressed it will be delivered to everyone on the list,
+ otherwise an error should be reported (e.g., "550 That is a
+ mailing list, not a user"). If a request is made to expand a user
+ name a positive response can be formed by returning a list
+ containing one name, or an error can be reported (e.g., "550 That
+ is a user name, not a mailing list").
+
+ In the case of a multiline reply (normal for EXPN) exactly one
+ mailbox is to be specified on each line of the reply. In the case
+ of an ambiguous request, for example, "VRFY Smith", where there
+ are two Smith's the response must be "553 User ambiguous".
+
+ The case of verifying a user name is straightforward as shown in
+ example 3.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+[Page 8] Postel
+
+
+
+RFC 821 August 1982
+ Simple Mail Transfer Protocol
+
+
+
+ -------------------------------------------------------------
+
+ Example of Verifying a User Name
+
+ Either
+
+ S: VRFY Smith
+ R: 250 Fred Smith
+
+ Or
+
+ S: VRFY Smith
+ R: 251 User not local; will forward to
+
+ Or
+
+ S: VRFY Jones
+ R: 550 String does not match anything.
+
+ Or
+
+ S: VRFY Jones
+ R: 551 User not local; please try
+
+ Or
+
+ S: VRFY Gourzenkyinplatz
+ R: 553 User ambiguous.
+
+ Example 3
+
+ -------------------------------------------------------------
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Postel [Page 9]
+
+
+
+August 1982 RFC 821
+Simple Mail Transfer Protocol
+
+
+
+ The case of expanding a mailbox list requires a multiline reply as
+ shown in example 4.
+
+ -------------------------------------------------------------
+
+ Example of Expanding a Mailing List
+
+ Either
+
+ S: EXPN Example-People
+ R: 250-Jon Postel
+ R: 250-Fred Fonebone
+ R: 250-Sam Q. Smith
+ R: 250-Quincy Smith <@USC-ISIF.ARPA:Q-Smith@ISI-VAXA.ARPA>
+ R: 250-
+ R: 250
+
+ Or
+
+ S: EXPN Executive-Washroom-List
+ R: 550 Access Denied to You.
+
+ Example 4
+
+ -------------------------------------------------------------
+
+ The character string arguments of the VRFY and EXPN commands
+ cannot be further restricted due to the variety of implementations
+ of the user name and mailbox list concepts. On some systems it
+ may be appropriate for the argument of the EXPN command to be a
+ file name for a file containing a mailing list, but again there is
+ a variety of file naming conventions in the Internet.
+
+ The VRFY and EXPN commands are not included in the minimum
+ implementation (Section 4.5.1), and are not required to work
+ across relays when they are implemented.
+
+
+
+
+
+
+
+
+
+
+
+
+
+[Page 10] Postel
+
+
+
+RFC 821 August 1982
+ Simple Mail Transfer Protocol
+
+
+
+ 3.4. SENDING AND MAILING
+
+ The main purpose of SMTP is to deliver messages to user's
+ mailboxes. A very similar service provided by some hosts is to
+ deliver messages to user's terminals (provided the user is active
+ on the host). The delivery to the user's mailbox is called
+ "mailing", the delivery to the user's terminal is called
+ "sending". Because in many hosts the implementation of sending is
+ nearly identical to the implementation of mailing these two
+ functions are combined in SMTP. However the sending commands are
+ not included in the required minimum implementation
+ (Section 4.5.1). Users should have the ability to control the
+ writing of messages on their terminals. Most hosts permit the
+ users to accept or refuse such messages.
+
+ The following three command are defined to support the sending
+ options. These are used in the mail transaction instead of the
+ MAIL command and inform the receiver-SMTP of the special semantics
+ of this transaction:
+
+ SEND FROM:
+
+ The SEND command requires that the mail data be delivered to
+ the user's terminal. If the user is not active (or not
+ accepting terminal messages) on the host a 450 reply may
+ returned to a RCPT command. The mail transaction is
+ successful if the message is delivered the terminal.
+
+ SOML FROM:
+
+ The Send Or MaiL command requires that the mail data be
+ delivered to the user's terminal if the user is active (and
+ accepting terminal messages) on the host. If the user is
+ not active (or not accepting terminal messages) then the
+ mail data is entered into the user's mailbox. The mail
+ transaction is successful if the message is delivered either
+ to the terminal or the mailbox.
+
+ SAML FROM:
+
+ The Send And MaiL command requires that the mail data be
+ delivered to the user's terminal if the user is active (and
+ accepting terminal messages) on the host. In any case the
+ mail data is entered into the user's mailbox. The mail
+ transaction is successful if the message is delivered the
+ mailbox.
+
+
+
+Postel [Page 11]
+
+
+
+August 1982 RFC 821
+Simple Mail Transfer Protocol
+
+
+
+ The same reply codes that are used for the MAIL commands are used
+ for these commands.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+[Page 12] Postel
+
+
+
+RFC 821 August 1982
+ Simple Mail Transfer Protocol
+
+
+
+ 3.5. OPENING AND CLOSING
+
+ At the time the transmission channel is opened there is an
+ exchange to ensure that the hosts are communicating with the hosts
+ they think they are.
+
+ The following two commands are used in transmission channel
+ opening and closing:
+
+ HELO
+
+ QUIT
+
+ In the HELO command the host sending the command identifies
+ itself; the command may be interpreted as saying "Hello, I am
+ ".
+
+ -------------------------------------------------------------
+
+ Example of Connection Opening
+
+ R: 220 BBN-UNIX.ARPA Simple Mail Transfer Service Ready
+ S: HELO USC-ISIF.ARPA
+ R: 250 BBN-UNIX.ARPA
+
+ Example 5
+
+ -------------------------------------------------------------
+
+ -------------------------------------------------------------
+
+ Example of Connection Closing
+
+ S: QUIT
+ R: 221 BBN-UNIX.ARPA Service closing transmission channel
+
+ Example 6
+
+ -------------------------------------------------------------
+
+
+
+
+
+
+
+
+
+
+Postel [Page 13]
+
+
+
+August 1982 RFC 821
+Simple Mail Transfer Protocol
+
+
+
+ 3.6. RELAYING
+
+ The forward-path may be a source route of the form
+ "@ONE,@TWO:JOE@THREE", where ONE, TWO, and THREE are hosts. This
+ form is used to emphasize the distinction between an address and a
+ route. The mailbox is an absolute address, and the route is
+ information about how to get there. The two concepts should not
+ be confused.
+
+ Conceptually the elements of the forward-path are moved to the
+ reverse-path as the message is relayed from one server-SMTP to
+ another. The reverse-path is a reverse source route, (i.e., a
+ source route from the current location of the message to the
+ originator of the message). When a server-SMTP deletes its
+ identifier from the forward-path and inserts it into the
+ reverse-path, it must use the name it is known by in the
+ environment it is sending into, not the environment the mail came
+ from, in case the server-SMTP is known by different names in
+ different environments.
+
+ If when the message arrives at an SMTP the first element of the
+ forward-path is not the identifier of that SMTP the element is not
+ deleted from the forward-path and is used to determine the next
+ SMTP to send the message to. In any case, the SMTP adds its own
+ identifier to the reverse-path.
+
+ Using source routing the receiver-SMTP receives mail to be relayed
+ to another server-SMTP The receiver-SMTP may accept or reject the
+ task of relaying the mail in the same way it accepts or rejects
+ mail for a local user. The receiver-SMTP transforms the command
+ arguments by moving its own identifier from the forward-path to
+ the beginning of the reverse-path. The receiver-SMTP then becomes
+ a sender-SMTP, establishes a transmission channel to the next SMTP
+ in the forward-path, and sends it the mail.
+
+ The first host in the reverse-path should be the host sending the
+ SMTP commands, and the first host in the forward-path should be
+ the host receiving the SMTP commands.
+
+ Notice that the forward-path and reverse-path appear in the SMTP
+ commands and replies, but not necessarily in the message. That
+ is, there is no need for these paths and especially this syntax to
+ appear in the "To:" , "From:", "CC:", etc. fields of the message
+ header.
+
+ If a server-SMTP has accepted the task of relaying the mail and
+
+
+
+[Page 14] Postel
+
+
+
+RFC 821 August 1982
+ Simple Mail Transfer Protocol
+
+
+
+ later finds that the forward-path is incorrect or that the mail
+ cannot be delivered for whatever reason, then it must construct an
+ "undeliverable mail" notification message and send it to the
+ originator of the undeliverable mail (as indicated by the
+ reverse-path).
+
+ This notification message must be from the server-SMTP at this
+ host. Of course, server-SMTPs should not send notification
+ messages about problems with notification messages. One way to
+ prevent loops in error reporting is to specify a null reverse-path
+ in the MAIL command of a notification message. When such a
+ message is relayed it is permissible to leave the reverse-path
+ null. A MAIL command with a null reverse-path appears as follows:
+
+ MAIL FROM:<>
+
+ An undeliverable mail notification message is shown in example 7.
+ This notification is in response to a message originated by JOE at
+ HOSTW and sent via HOSTX to HOSTY with instructions to relay it on
+ to HOSTZ. What we see in the example is the transaction between
+ HOSTY and HOSTX, which is the first step in the return of the
+ notification message.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Postel [Page 15]
+
+
+
+August 1982 RFC 821
+Simple Mail Transfer Protocol
+
+
+
+ -------------------------------------------------------------
+
+ Example Undeliverable Mail Notification Message
+
+ S: MAIL FROM:<>
+ R: 250 ok
+ S: RCPT TO:<@HOSTX.ARPA:JOE@HOSTW.ARPA>
+ R: 250 ok
+ S: DATA
+ R: 354 send the mail data, end with .
+ S: Date: 23 Oct 81 11:22:33
+ S: From: SMTP@HOSTY.ARPA
+ S: To: JOE@HOSTW.ARPA
+ S: Subject: Mail System Problem
+ S:
+ S: Sorry JOE, your message to SAM@HOSTZ.ARPA lost.
+ S: HOSTZ.ARPA said this:
+ S: "550 No Such User"
+ S: .
+ R: 250 ok
+
+ Example 7
+
+ -------------------------------------------------------------
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+[Page 16] Postel
+
+
+
+RFC 821 August 1982
+ Simple Mail Transfer Protocol
+
+
+
+ 3.7. DOMAINS
+
+ Domains are a recently introduced concept in the ARPA Internet
+ mail system. The use of domains changes the address space from a
+ flat global space of simple character string host names to a
+ hierarchically structured rooted tree of global addresses. The
+ host name is replaced by a domain and host designator which is a
+ sequence of domain element strings separated by periods with the
+ understanding that the domain elements are ordered from the most
+ specific to the most general.
+
+ For example, "USC-ISIF.ARPA", "Fred.Cambridge.UK", and
+ "PC7.LCS.MIT.ARPA" might be host-and-domain identifiers.
+
+ Whenever domain names are used in SMTP only the official names are
+ used, the use of nicknames or aliases is not allowed.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Postel [Page 17]
+
+
+
+August 1982 RFC 821
+Simple Mail Transfer Protocol
+
+
+
+ 3.8. CHANGING ROLES
+
+ The TURN command may be used to reverse the roles of the two
+ programs communicating over the transmission channel.
+
+ If program-A is currently the sender-SMTP and it sends the TURN
+ command and receives an ok reply (250) then program-A becomes the
+ receiver-SMTP.
+
+ If program-B is currently the receiver-SMTP and it receives the
+ TURN command and sends an ok reply (250) then program-B becomes
+ the sender-SMTP.
+
+ To refuse to change roles the receiver sends the 502 reply.
+
+ Please note that this command is optional. It would not normally
+ be used in situations where the transmission channel is TCP.
+ However, when the cost of establishing the transmission channel is
+ high, this command may be quite useful. For example, this command
+ may be useful in supporting be mail exchange using the public
+ switched telephone system as a transmission channel, especially if
+ some hosts poll other hosts for mail exchanges.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+[Page 18] Postel
+
+
+
+RFC 821 August 1982
+ Simple Mail Transfer Protocol
+
+
+
+4. THE SMTP SPECIFICATIONS
+
+ 4.1. SMTP COMMANDS
+
+ 4.1.1. COMMAND SEMANTICS
+
+ The SMTP commands define the mail transfer or the mail system
+ function requested by the user. SMTP commands are character
+ strings terminated by . The command codes themselves are
+ alphabetic characters terminated by if parameters follow
+ and otherwise. The syntax of mailboxes must conform to
+ receiver site conventions. The SMTP commands are discussed
+ below. The SMTP replies are discussed in the Section 4.2.
+
+ A mail transaction involves several data objects which are
+ communicated as arguments to different commands. The
+ reverse-path is the argument of the MAIL command, the
+ forward-path is the argument of the RCPT command, and the mail
+ data is the argument of the DATA command. These arguments or
+ data objects must be transmitted and held pending the
+ confirmation communicated by the end of mail data indication
+ which finalizes the transaction. The model for this is that
+ distinct buffers are provided to hold the types of data
+ objects, that is, there is a reverse-path buffer, a
+ forward-path buffer, and a mail data buffer. Specific commands
+ cause information to be appended to a specific buffer, or cause
+ one or more buffers to be cleared.
+
+ HELLO (HELO)
+
+ This command is used to identify the sender-SMTP to the
+ receiver-SMTP. The argument field contains the host name of
+ the sender-SMTP.
+
+ The receiver-SMTP identifies itself to the sender-SMTP in
+ the connection greeting reply, and in the response to this
+ command.
+
+ This command and an OK reply to it confirm that both the
+ sender-SMTP and the receiver-SMTP are in the initial state,
+ that is, there is no transaction in progress and all state
+ tables and buffers are cleared.
+
+
+
+
+
+
+
+Postel [Page 19]
+
+
+
+August 1982 RFC 821
+Simple Mail Transfer Protocol
+
+
+
+ MAIL (MAIL)
+
+ This command is used to initiate a mail transaction in which
+ the mail data is delivered to one or more mailboxes. The
+ argument field contains a reverse-path.
+
+ The reverse-path consists of an optional list of hosts and
+ the sender mailbox. When the list of hosts is present, it
+ is a "reverse" source route and indicates that the mail was
+ relayed through each host on the list (the first host in the
+ list was the most recent relay). This list is used as a
+ source route to return non-delivery notices to the sender.
+ As each relay host adds itself to the beginning of the list,
+ it must use its name as known in the IPCE to which it is
+ relaying the mail rather than the IPCE from which the mail
+ came (if they are different). In some types of error
+ reporting messages (for example, undeliverable mail
+ notifications) the reverse-path may be null (see Example 7).
+
+ This command clears the reverse-path buffer, the
+ forward-path buffer, and the mail data buffer; and inserts
+ the reverse-path information from this command into the
+ reverse-path buffer.
+
+ RECIPIENT (RCPT)
+
+ This command is used to identify an individual recipient of
+ the mail data; multiple recipients are specified by multiple
+ use of this command.
+
+ The forward-path consists of an optional list of hosts and a
+ required destination mailbox. When the list of hosts is
+ present, it is a source route and indicates that the mail
+ must be relayed to the next host on the list. If the
+ receiver-SMTP does not implement the relay function it may
+ user the same reply it would for an unknown local user
+ (550).
+
+ When mail is relayed, the relay host must remove itself from
+ the beginning forward-path and put itself at the beginning
+ of the reverse-path. When mail reaches its ultimate
+ destination (the forward-path contains only a destination
+ mailbox), the receiver-SMTP inserts it into the destination
+ mailbox in accordance with its host mail conventions.
+
+
+
+
+
+[Page 20] Postel
+
+
+
+RFC 821 August 1982
+ Simple Mail Transfer Protocol
+
+
+
+ For example, mail received at relay host A with arguments
+
+ FROM:
+ TO:<@HOSTA.ARPA,@HOSTB.ARPA:USERC@HOSTD.ARPA>
+
+ will be relayed on to host B with arguments
+
+ FROM:<@HOSTA.ARPA:USERX@HOSTY.ARPA>
+ TO:<@HOSTB.ARPA:USERC@HOSTD.ARPA>.
+
+ This command causes its forward-path argument to be appended
+ to the forward-path buffer.
+
+ DATA (DATA)
+
+ The receiver treats the lines following the command as mail
+ data from the sender. This command causes the mail data
+ from this command to be appended to the mail data buffer.
+ The mail data may contain any of the 128 ASCII character
+ codes.
+
+ The mail data is terminated by a line containing only a
+ period, that is the character sequence "." (see
+ Section 4.5.2 on Transparency). This is the end of mail
+ data indication.
+
+ The end of mail data indication requires that the receiver
+ must now process the stored mail transaction information.
+ This processing consumes the information in the reverse-path
+ buffer, the forward-path buffer, and the mail data buffer,
+ and on the completion of this command these buffers are
+ cleared. If the processing is successful the receiver must
+ send an OK reply. If the processing fails completely the
+ receiver must send a failure reply.
+
+ When the receiver-SMTP accepts a message either for relaying
+ or for final delivery it inserts at the beginning of the
+ mail data a time stamp line. The time stamp line indicates
+ the identity of the host that sent the message, and the
+ identity of the host that received the message (and is
+ inserting this time stamp), and the date and time the
+ message was received. Relayed messages will have multiple
+ time stamp lines.
+
+ When the receiver-SMTP makes the "final delivery" of a
+ message it inserts at the beginning of the mail data a
+
+
+
+Postel [Page 21]
+
+
+
+August 1982 RFC 821
+Simple Mail Transfer Protocol
+
+
+
+ return path line. The return path line preserves the
+ information in the from the MAIL command.
+ Here, final delivery means the message leaves the SMTP
+ world. Normally, this would mean it has been delivered to
+ the destination user, but in some cases it may be further
+ processed and transmitted by another mail system.
+
+ It is possible for the mailbox in the return path be
+ different from the actual sender's mailbox, for example,
+ if error responses are to be delivered a special error
+ handling mailbox rather than the message senders.
+
+ The preceding two paragraphs imply that the final mail data
+ will begin with a return path line, followed by one or more
+ time stamp lines. These lines will be followed by the mail
+ data header and body [2]. See Example 8.
+
+ Special mention is needed of the response and further action
+ required when the processing following the end of mail data
+ indication is partially successful. This could arise if
+ after accepting several recipients and the mail data, the
+ receiver-SMTP finds that the mail data can be successfully
+ delivered to some of the recipients, but it cannot be to
+ others (for example, due to mailbox space allocation
+ problems). In such a situation, the response to the DATA
+ command must be an OK reply. But, the receiver-SMTP must
+ compose and send an "undeliverable mail" notification
+ message to the originator of the message. Either a single
+ notification which lists all of the recipients that failed
+ to get the message, or separate notification messages must
+ be sent for each failed recipient (see Example 7). All
+ undeliverable mail notification messages are sent using the
+ MAIL command (even if they result from processing a SEND,
+ SOML, or SAML command).
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+[Page 22] Postel
+
+
+
+RFC 821 August 1982
+ Simple Mail Transfer Protocol
+
+
+
+ -------------------------------------------------------------
+
+ Example of Return Path and Received Time Stamps
+
+ Return-Path: <@GHI.ARPA,@DEF.ARPA,@ABC.ARPA:JOE@ABC.ARPA>
+ Received: from GHI.ARPA by JKL.ARPA ; 27 Oct 81 15:27:39 PST
+ Received: from DEF.ARPA by GHI.ARPA ; 27 Oct 81 15:15:13 PST
+ Received: from ABC.ARPA by DEF.ARPA ; 27 Oct 81 15:01:59 PST
+ Date: 27 Oct 81 15:01:01 PST
+ From: JOE@ABC.ARPA
+ Subject: Improved Mailing System Installed
+ To: SAM@JKL.ARPA
+
+ This is to inform you that ...
+
+ Example 8
+
+ -------------------------------------------------------------
+
+ SEND (SEND)
+
+ This command is used to initiate a mail transaction in which
+ the mail data is delivered to one or more terminals. The
+ argument field contains a reverse-path. This command is
+ successful if the message is delivered to a terminal.
+
+ The reverse-path consists of an optional list of hosts and
+ the sender mailbox. When the list of hosts is present, it
+ is a "reverse" source route and indicates that the mail was
+ relayed through each host on the list (the first host in the
+ list was the most recent relay). This list is used as a
+ source route to return non-delivery notices to the sender.
+ As each relay host adds itself to the beginning of the list,
+ it must use its name as known in the IPCE to which it is
+ relaying the mail rather than the IPCE from which the mail
+ came (if they are different).
+
+ This command clears the reverse-path buffer, the
+ forward-path buffer, and the mail data buffer; and inserts
+ the reverse-path information from this command into the
+ reverse-path buffer.
+
+ SEND OR MAIL (SOML)
+
+ This command is used to initiate a mail transaction in which
+ the mail data is delivered to one or more terminals or
+
+
+
+Postel [Page 23]
+
+
+
+August 1982 RFC 821
+Simple Mail Transfer Protocol
+
+
+
+ mailboxes. For each recipient the mail data is delivered to
+ the recipient's terminal if the recipient is active on the
+ host (and accepting terminal messages), otherwise to the
+ recipient's mailbox. The argument field contains a
+ reverse-path. This command is successful if the message is
+ delivered to a terminal or the mailbox.
+
+ The reverse-path consists of an optional list of hosts and
+ the sender mailbox. When the list of hosts is present, it
+ is a "reverse" source route and indicates that the mail was
+ relayed through each host on the list (the first host in the
+ list was the most recent relay). This list is used as a
+ source route to return non-delivery notices to the sender.
+ As each relay host adds itself to the beginning of the list,
+ it must use its name as known in the IPCE to which it is
+ relaying the mail rather than the IPCE from which the mail
+ came (if they are different).
+
+ This command clears the reverse-path buffer, the
+ forward-path buffer, and the mail data buffer; and inserts
+ the reverse-path information from this command into the
+ reverse-path buffer.
+
+ SEND AND MAIL (SAML)
+
+ This command is used to initiate a mail transaction in which
+ the mail data is delivered to one or more terminals and
+ mailboxes. For each recipient the mail data is delivered to
+ the recipient's terminal if the recipient is active on the
+ host (and accepting terminal messages), and for all
+ recipients to the recipient's mailbox. The argument field
+ contains a reverse-path. This command is successful if the
+ message is delivered to the mailbox.
+
+ The reverse-path consists of an optional list of hosts and
+ the sender mailbox. When the list of hosts is present, it
+ is a "reverse" source route and indicates that the mail was
+ relayed through each host on the list (the first host in the
+ list was the most recent relay). This list is used as a
+ source route to return non-delivery notices to the sender.
+ As each relay host adds itself to the beginning of the list,
+ it must use its name as known in the IPCE to which it is
+ relaying the mail rather than the IPCE from which the mail
+ came (if they are different).
+
+ This command clears the reverse-path buffer, the
+
+
+
+[Page 24] Postel
+
+
+
+RFC 821 August 1982
+ Simple Mail Transfer Protocol
+
+
+
+ forward-path buffer, and the mail data buffer; and inserts
+ the reverse-path information from this command into the
+ reverse-path buffer.
+
+ RESET (RSET)
+
+ This command specifies that the current mail transaction is
+ to be aborted. Any stored sender, recipients, and mail data
+ must be discarded, and all buffers and state tables cleared.
+ The receiver must send an OK reply.
+
+ VERIFY (VRFY)
+
+ This command asks the receiver to confirm that the argument
+ identifies a user. If it is a user name, the full name of
+ the user (if known) and the fully specified mailbox are
+ returned.
+
+ This command has no effect on any of the reverse-path
+ buffer, the forward-path buffer, or the mail data buffer.
+
+ EXPAND (EXPN)
+
+ This command asks the receiver to confirm that the argument
+ identifies a mailing list, and if so, to return the
+ membership of that list. The full name of the users (if
+ known) and the fully specified mailboxes are returned in a
+ multiline reply.
+
+ This command has no effect on any of the reverse-path
+ buffer, the forward-path buffer, or the mail data buffer.
+
+ HELP (HELP)
+
+ This command causes the receiver to send helpful information
+ to the sender of the HELP command. The command may take an
+ argument (e.g., any command name) and return more specific
+ information as a response.
+
+ This command has no effect on any of the reverse-path
+ buffer, the forward-path buffer, or the mail data buffer.
+
+
+
+
+
+
+
+
+Postel [Page 25]
+
+
+
+August 1982 RFC 821
+Simple Mail Transfer Protocol
+
+
+
+ NOOP (NOOP)
+
+ This command does not affect any parameters or previously
+ entered commands. It specifies no action other than that
+ the receiver send an OK reply.
+
+ This command has no effect on any of the reverse-path
+ buffer, the forward-path buffer, or the mail data buffer.
+
+ QUIT (QUIT)
+
+ This command specifies that the receiver must send an OK
+ reply, and then close the transmission channel.
+
+ The receiver should not close the transmission channel until
+ it receives and replies to a QUIT command (even if there was
+ an error). The sender should not close the transmission
+ channel until it send a QUIT command and receives the reply
+ (even if there was an error response to a previous command).
+ If the connection is closed prematurely the receiver should
+ act as if a RSET command had been received (canceling any
+ pending transaction, but not undoing any previously
+ completed transaction), the sender should act as if the
+ command or transaction in progress had received a temporary
+ error (4xx).
+
+ TURN (TURN)
+
+ This command specifies that the receiver must either (1)
+ send an OK reply and then take on the role of the
+ sender-SMTP, or (2) send a refusal reply and retain the role
+ of the receiver-SMTP.
+
+ If program-A is currently the sender-SMTP and it sends the
+ TURN command and receives an OK reply (250) then program-A
+ becomes the receiver-SMTP. Program-A is then in the initial
+ state as if the transmission channel just opened, and it
+ then sends the 220 service ready greeting.
+
+ If program-B is currently the receiver-SMTP and it receives
+ the TURN command and sends an OK reply (250) then program-B
+ becomes the sender-SMTP. Program-B is then in the initial
+ state as if the transmission channel just opened, and it
+ then expects to receive the 220 service ready greeting.
+
+ To refuse to change roles the receiver sends the 502 reply.
+
+
+
+[Page 26] Postel
+
+
+
+RFC 821 August 1982
+ Simple Mail Transfer Protocol
+
+
+
+ There are restrictions on the order in which these command may
+ be used.
+
+ The first command in a session must be the HELO command.
+ The HELO command may be used later in a session as well. If
+ the HELO command argument is not acceptable a 501 failure
+ reply must be returned and the receiver-SMTP must stay in
+ the same state.
+
+ The NOOP, HELP, EXPN, and VRFY commands can be used at any
+ time during a session.
+
+ The MAIL, SEND, SOML, or SAML commands begin a mail
+ transaction. Once started a mail transaction consists of
+ one of the transaction beginning commands, one or more RCPT
+ commands, and a DATA command, in that order. A mail
+ transaction may be aborted by the RSET command. There may
+ be zero or more transactions in a session.
+
+ If the transaction beginning command argument is not
+ acceptable a 501 failure reply must be returned and the
+ receiver-SMTP must stay in the same state. If the commands
+ in a transaction are out of order a 503 failure reply must
+ be returned and the receiver-SMTP must stay in the same
+ state.
+
+ The last command in a session must be the QUIT command. The
+ QUIT command can not be used at any other time in a session.
+
+ 4.1.2. COMMAND SYNTAX
+
+ The commands consist of a command code followed by an argument
+ field. Command codes are four alphabetic characters. Upper
+ and lower case alphabetic characters are to be treated
+ identically. Thus, any of the following may represent the mail
+ command:
+
+ MAIL Mail mail MaIl mAIl
+
+ This also applies to any symbols representing parameter values,
+ such as "TO" or "to" for the forward-path. Command codes and
+ the argument fields are separated by one or more spaces.
+ However, within the reverse-path and forward-path arguments
+ case is important. In particular, in some hosts the user
+ "smith" is different from the user "Smith".
+
+
+
+
+Postel [Page 27]
+
+
+
+August 1982 RFC 821
+Simple Mail Transfer Protocol
+
+
+
+ The argument field consists of a variable length character
+ string ending with the character sequence . The receiver
+ is to take no action until this sequence is received.
+
+ Square brackets denote an optional argument field. If the
+ option is not taken, the appropriate default is implied.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+[Page 28] Postel
+
+
+
+RFC 821 August 1982
+ Simple Mail Transfer Protocol
+
+
+
+ The following are the SMTP commands:
+
+ HELO
+
+ MAIL FROM:
+
+ RCPT TO:
+
+ DATA
+
+ RSET
+
+ SEND FROM:
+
+ SOML FROM:
+
+ SAML FROM:
+
+ VRFY
+
+ EXPN
+
+ HELP []
+
+ NOOP
+
+ QUIT
+
+ TURN
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Postel [Page 29]
+
+
+
+August 1982 RFC 821
+Simple Mail Transfer Protocol
+
+
+
+ The syntax of the above argument fields (using BNF notation
+ where applicable) is given below. The "..." notation indicates
+ that a field may be repeated one or more times.
+
+ ::=
+
+ ::=
+
+ ::= "<" [ ":" ] ">"
+
+ ::= | ","
+
+ ::= "@"
+
+ ::= | "."
+
+ ::= | "#" | "[" "]"
+
+ ::= "@"
+
+ ::= |
+
+ ::=
+
+ ::= |
+
+ ::= |
+
+ ::= | | "-"
+
+ ::= | "."
+
+ ::= |
+
+ ::= """ """
+
+ ::= "\" | "\" | |
+
+ ::= | "\"
+
+ ::= "." "." "."
+
+ ::= |
+
+ ::=
+
+
+
+
+[Page 30] Postel
+
+
+
+RFC 821 August 1982
+ Simple Mail Transfer Protocol
+
+
+
+ ::= the carriage return character (ASCII code 13)
+
+ ::= the line feed character (ASCII code 10)
+
+ ::= the space character (ASCII code 32)
+
+ ::= one, two, or three digits representing a decimal
+ integer value in the range 0 through 255
+
+ ::= any one of the 52 alphabetic characters A through Z
+ in upper case and a through z in lower case
+
+ ::= any one of the 128 ASCII characters, but not any
+ or
+
+ ::= any one of the ten digits 0 through 9
+
+ ::= any one of the 128 ASCII characters except ,
+ , quote ("), or backslash (\)
+
+ ::= any one of the 128 ASCII characters (no exceptions)
+
+ ::= "<" | ">" | "(" | ")" | "[" | "]" | "\" | "."
+ | "," | ";" | ":" | "@" """ | the control
+ characters (ASCII codes 0 through 31 inclusive and
+ 127)
+
+ Note that the backslash, "\", is a quote character, which is
+ used to indicate that the next character is to be used
+ literally (instead of its normal interpretation). For example,
+ "Joe\,Smith" could be used to indicate a single nine character
+ user field with comma being the fourth character of the field.
+
+ Hosts are generally known by names which are translated to
+ addresses in each host. Note that the name elements of domains
+ are the official names -- no use of nicknames or aliases is
+ allowed.
+
+ Sometimes a host is not known to the translation function and
+ communication is blocked. To bypass this barrier two numeric
+ forms are also allowed for host "names". One form is a decimal
+ integer prefixed by a pound sign, "#", which indicates the
+ number is the address of the host. Another form is four small
+ decimal integers separated by dots and enclosed by brackets,
+ e.g., "[123.255.37.2]", which indicates a 32-bit ARPA Internet
+ Address in four 8-bit fields.
+
+
+
+Postel [Page 31]
+
+
+
+August 1982 RFC 821
+Simple Mail Transfer Protocol
+
+
+
+ The time stamp line and the return path line are formally
+ defined as follows:
+
+ ::= "Return-Path:"
+
+ ::= "Received:"
+
+ ::= ";"
+
+
+ ::= "FROM"
+
+ ::= "BY"
+
+ ::= [] [] [] []
+
+ ::= "VIA"
+
+ ::= "WITH"